diff -u --recursive --new-file v2.1.66/linux/CREDITS linux/CREDITS --- v2.1.66/linux/CREDITS Wed Nov 26 16:24:00 1997 +++ linux/CREDITS Sat Nov 29 10:33:18 1997 @@ -25,6 +25,14 @@ S: CH-1015 Lausanne S: Switzerland +N: Tim Alpaerts +E: tim_alpaerts@toyota-motor-europe.com +D: 802.2 class II logical link control layer, +D: the humble start of an opening towards the IBM SNA protocols +S: Klaproosstraat 72 c 10 +S: B-2610 Wilrijk-Antwerpen +S: Belgium + N: H. Peter Anvin E: hpa@zytor.com W: http://www.zytor.com/~hpa/ @@ -144,11 +152,11 @@ N: Philip Blundell E: Philip.Blundell@pobox.com -D: Device driver hacking (especially EtherExpress16/3C505 net cards) +D: Device driver hacking D: Some Linux/ARM stuff D: Co-architect of the parallel port sharing system -S: 201 Gilbert Road -S: Cambridge, UK. CB4 3PA +S: Nexus Electronics Ltd +S: 10 St Barnabas Road, Cambridge, UK. CB1 2BY N: Thomas Bogendoerfer E: tsbogend@alpha.franken.de @@ -359,6 +367,11 @@ S: 47807 Krefeld S: Germany +N: Tom Dyas +E: tdyas@eden.rutgers.edu +D: minor hacks and some sparc port stuff +S: New Jersey, USA + N: Drew Eckhardt E: drew@PoohSticks.ORG D: SCSI code @@ -505,6 +518,15 @@ S: N.S.W., 2121 S: Australia +N: Richard E. Gooch +E: rgooch@atnf.csiro.au +D: parent process death signal to children +D: prctl() syscall +S: CSIRO Australia Telescope National Facility +S: P.O. Box 76, Epping +S: N.S.W., 2121 +S: Australia + N: Dmitry S. Gorodchanin E: begemot@bgm.rosprint.net D: RISCom/8 driver, misc kernel fixes. @@ -606,9 +628,12 @@ S: Germany N: Richard Henderson -E: richard@gnu.ai.mit.edu E: rth@cygnus.com +E: richard@gnu.org D: Alpha/ELF, gcc, binutils, and glibc +S: 5450 Mayme #25 +S: San Jose, California 95129 +S: USA N: Sebastian Hetze E: she@lunetix.de @@ -798,6 +823,13 @@ E: rfkoenig@immd4.informatik.uni-erlangen.de D: The Linux Support Team Erlangen +N: Andi Kleen +E: ak@muc.de +D: network hacker, syncookies +S: Schwalbenstr. 96 +S: 85551 Ottobrunn +S: Germany + N: Willy Konynenberg E: willy@xos.nl W: http://www.xos.nl/ @@ -850,6 +882,13 @@ D: Author of the dialog utility, foundation D: for Menuconfig's lxdialog. +N: Tom Lees +E: tom@lpsg.demon.co.uk +W: http://www.lpsg.demon.co.uk/ +P: 1024/87D4D065 2A 66 86 9D 02 4D A6 1E B8 A2 17 9D 4F 9B 89 D6 +D: Original author and current maintainer of +D: PnP code. + N: David van Leeuwen E: david@tm.tno.nl D: Philips/LMS cm206 cdrom driver, generic cdrom driver @@ -950,6 +989,7 @@ N: Pavel Machek E: pavel@atrey.karlin.mff.cuni.cz D: Softcursor for vga, hypertech cdrom support, vcsa bugfix +D: Network block device S: Volkova 1131 S: 198 00 Praha 9 S: Czech Republic @@ -980,12 +1020,12 @@ S: Canada B3J 3C8 N: Martin Mares -E: mj@k332.feld.cvut.cz +E: mj@atrey.karlin.mff.cuni.cz W: http://atrey.karlin.mff.cuni.cz/~mj/ D: BIOS video mode handling code -D: Miscellaneous kernel fixes and hacks D: MOXA C-218 serial board driver -D: BOOTP support +D: Network autoconfiguration +D: Random kernel hacking S: Kankovskeho 1241 S: 182 00 Praha 8 S: Czech Republic @@ -1182,6 +1222,15 @@ E: orc@pell.chi.il.us D: improved memory detection code. +N: Vojtech Pavlik +E: vojtech@atrey.karlin.mff.cuni.cz +D: Joystick driver +D: arcnet-hardware readme +D: Minor ARCnet hacking +S: Ucitelska 1576 +S: Prague 8 +S: 182 00 Czech Republic + N: Barak A. Pearlmutter E: bap@cs.unm.edu W: http://www.cs.unm.edu/~bap/ @@ -1209,6 +1258,11 @@ S: Tula 300000 S: Russia +N: Kirk Petersen +E: kirk@speakeasy.org +W: http://www.speakeasy.org/~kirk/ +D: modularized BSD Unix domain sockets + N: Kai Petzke E: wpp@marie.physik.tu-berlin.de W: http://physik.tu-berlin.de/~wpp @@ -1660,8 +1714,8 @@ S: Germany N: Marco van Wieringen -E: mvw@mercury.mcs.nl.mugnet.org -D: Author of acct and quota +E: mvw@planets.elm.net +D: Author of process accounting and diskquota S: Breeburgsingel 12 S: 2135 CN Hoofddorp S: The Netherlands @@ -1700,6 +1754,7 @@ E: dwmw2@cam.ac.uk D: Extensive ARCnet rewrite D: ARCnet COM20020, COM90xx IO-MAP drivers +D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31) S: Robinson College, Grange Road S: Cambridge. CB3 9AN S: England diff -u --recursive --new-file v2.1.66/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.66/linux/Documentation/Configure.help Wed Nov 26 16:24:01 1997 +++ linux/Documentation/Configure.help Sat Nov 29 10:33:18 1997 @@ -148,6 +148,15 @@ nothing to do with the loopback device used for network connections from the machine to itself. Most users will answer N here. +Network Block Device support +CONFIG_BLK_DEV_NBD + Saying Y here will allow computer to serve as client for network + block device - it will be able to use block devices exported by + servers (mount filesystems on them etc.). It also allows you to run + a block-device in userland (making server and client physicaly the same + computer, communicating using loopback). Normal users say N + here. Read Documentation/nbd.txt. + Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support CONFIG_BLK_DEV_IDE This will use the full-featured IDE driver to control up to four IDE @@ -522,7 +531,30 @@ kernel, you should consider updating your networking tools too because changes in the kernel and the tools often go hand in hand; see http://www.inka.de/sites/lina/linux/NetTools/index_en.html for - details. + details. + +Packet socket +CONFIG_PACKET + Packet protocol is used by applications directly communicating + to network devices f.e. tcpdump. You want that they worked, + so that choose Y. If you run kerneld, option M is the best solution. + +Kernel/User netlink socket +CONFIG_NETLINK + This protocol family is used for bi-directional communication + between kernel and user level daemons. This option is unlikely to + be useful for common workstation, but if you configure router or + firewall, do not hesitate: press Y. + +Routing messages +CONFIG_RTNETLINK + One of netlink protocols used by kernel routing engine. + You will need it to use advanced routing features. + +Netlink device emulation +CONFIG_NETLINK_DEV + It is backward compatibility option, choose Y for now. + This option will be removed soon. Network aliasing CONFIG_NET_ALIAS @@ -741,9 +773,10 @@ PCI bridge optimization (experimental) CONFIG_PCI_OPTIMIZE - This can improve access times for some hardware devices under - certain BIOSes if your computer uses a PCI bus system. This is - recommended; say Y. + This can improve access times for some hardware devices if you have + a really broken BIOS and your computer uses a PCI bus system. Set to Y + if you think it might help, but try turning it off if you experience + any problems with the PCI bus. MCA support CONFIG_MCA @@ -882,11 +915,11 @@ you have use for it. If you don't know what to answer at this point, say Y. -Processor type +Processor family CONFIG_M386 This is the processor type of your CPU. This information is used for optimizing purposes. In order to compile a kernel that can run on - all Intel CPU types (albeit not optimally fast), you can specify + all x86 CPU types (albeit not optimally fast), you can specify "386" here. If you specify one of "486" or "Pentium" or "PPro", then the kernel will run on all of these CPUs: 486 and Pentium (=586) and Pentium Pro (=686). In rare cases, it can make sense to @@ -963,6 +996,72 @@ when requested. If this option is enabled the kernel will probe to see what devices are connected at boot time. +Plug and Play subsystem (EXPERIMENTAL) +CONFIG_PNP_DRV + This enables support for the new Plug-and-Play (or PnP) Linux + subsystems. This support is required for PnP ISA support, and for PnP + Legacy support. User-mode utilities for this support may be found at + http://www.lpsg.demon.co.uk/pnp-linux.html. + +PnP resource management +CONFIG_KERNEL_PNP_RESOURCE + This option will cause the new PnP generic resource management + routines to be used instead of the old routines request_xxx and + free_xxx. Emulation routines are put in place to support the old + calling style. This code support masks for IO decoding (required for + Plug and Play devices). There is no need to enable this option unless + you want to - these features will still be used where they are needed. + However, enabling it will reduce your kernel size slightly, and also + allow you to test this code more extensively. + +Support for boot-loaded PnP configuration (RECOMMENDED) +CONFIG_PNP_BLDCONFIG + This will enable support for preloading data about the configuration + of any Plug-and-Play devices in the system into the kernel at boot + time, which means that any devices required at boot can be configured + at this time manually. Say Y unless you have a reason not to. + +PnP ISA support +CONFIG_PNP_ISA + This option is required to allow the Linux PnP subsystem to handle + Plug and Play ISA devices. This includes full support for PnP ISA, + including the I/O range check feature. + +PnP ISA backwards-compatiblity support +CONFIG_PNP_ISA_COMPAT + This option will enable partial backwards compatibility with drivers + written using older versions (up to the last 0.2.x) of the PnP driver + written by Tom Lees . + +PnP Legacy device support +CONFIG_PNP_LEGACY + Before PnP ISA was standardized, several "jumperless", or + "soft-configurable" boards were finding there way onto the market. + These cards used somewhat proprietary mechanisms for configuring + IRQs, DMAs, IO addresses, and memory ranges. These devices (mainly + network cards, but also some sound card) can be configured as any + other PnP device can by enabling this option, if appropriate drivers + for these devices are available. + +PnP sysctl support (RECOMMENDED) +CONFIG_PNP_SYSCTL + This option enables support for the user-mode interface to the + kernel-mode PnP systems. It requires that you enable CONFIG_SYSCTL. + The only reason you might want to switch this off is if you aren't + going to use user-mode utilities to configure PnP, and you want to + save a couple of kilobytes of kernel space. Answer Y unless you know + what you are doing. User-mode utilities and a library for accessing + this interface may be found at + http://www.lpsg.demon.co.uk/pnp-linux.html. + +PnP auto-configures all devices on startup +CONFIG_PNP_BOOTINIT + This option will allow the PnP subsystem to automatically configure + all the PnP devices it finds upon system startup (or at least + attempt to). This is useful if you have older driver which do not use + the Linux-PnP system to configure PnP devices, and which you need + configured by PnP in order to use. + Enable loadable module support CONFIG_MODULES Kernel modules are small pieces of compiled code which can be @@ -1039,9 +1138,7 @@ IP: multicasting CONFIG_IP_MULTICAST This is code for addressing several networked computers at once, - enlarging your kernel by about 2 kB. If you are using gated, the - daemon that updates your computer's routing tables, you will need to - have this option compiled in. You also need multicasting if you + enlarging your kernel by about 2 kB. You need multicasting if you intend to participate in the MBONE, a high bandwidth network on top of the internet which carries audio and video broadcasts. More information about the MBONE is on the WWW at @@ -1112,6 +1209,39 @@ recorded, you need the tool ipfwadm (available via ftp (user: anonymous) from ftp.xos.nl/pub/linux/ipfwadm/). +IP: kernel level autoconfiguration +CONFIG_IP_PNP + This enables automatic configuration of IP addresses of devices and + of the routing table during kernel boot, based on either information + supplied at the kernel command line or by BOOTP or RARP protocols. + You need to say Y only for diskless machines requiring network access + to boot (see CONFIG_ROOT_NFS for more information about root volume + mounted via NFS), because all other machines configure the network in + their startup scripts. + +BOOTP support +CONFIG_IP_PNP_BOOTP + If you want your Linux box to mount its whole root filesystem from + some other computer over the net via NFS and you want the IP address + of your computer to be discovered automatically at boot time using + the BOOTP protocol (a special protocol designed for doing this job), + say Y here. In case the boot ROM of your network card was designed + for booting Linux and does BOOTP itself, providing all necessary + information on the kernel command line, you can say N here. If + unsure, say Y. Note that in case you want to use BOOTP, a BOOTP + server must be operating on your network. Read + Documentation/nfsroot.txt for details. + +RARP support +CONFIG_IP_PNP_RARP + If you want your Linux box to mount its whole root filesystem from + some other computer over the net via NFS and you want the IP address + of your computer to be discovered automatically at boot time using + the RARP protocol (an older protocol which is being obsoleted by + BOOTP and DHCP), say Y here. Note that in case you want to use RARP, + a RARP server must be operating on your network. Read + Documentation/nfsroot.txt for details. + IP: tunneling CONFIG_NET_IPIP Tunneling means encapsulating data of one protocol type within @@ -1128,7 +1258,22 @@ one encapsulator called tunnel.o and one decapsulator called ipip.o. You can read details in drivers/net/README.tunnel. Most people won't need this and can say N. - + +IP: GRE tunnels over IP +CONFIG_NET_IPGRE + Another kind of tunneling protocol - "Generic Routing Encapsulation". + It allows to tunnel any networking protocol over existing IPv4 + infrastructure. At the moment only IPv4 and IPv6 are supported. + It is useful, if another endpoint is Cisco router: it likes + GRE much more than IPIP and, particularly, allows multicasts + redistribution over GRE tunnels. + +IP: broadcast GRE over IP +CONFIG_NET_IPGRE_BROADCAST + One application of GRE/IP, allowing to construct broadcast LAN, + looking like ethernet network, distributed over the Internet. + It requires, that your domain supported multicast routing. + IP: firewall packet logging CONFIG_IP_FIREWALL_VERBOSE This gives you information about what your firewall did with @@ -1220,6 +1365,21 @@ drivers/net/README.multicast. If you haven't heard about it, you don't need it. +IP: PIM-SM version 1 support +CONFIG_IP_PIMSM_V1 + Kernel side support for Sparse Mode PIM version 1. This multicast + routing protocol is used widely due to Cisco supports it. + You need special software to use it (pimd-v1). Press N, if + you do not want to use PIM-SM v1. Note, that Dense Mode PIM + need not this option. + +IP: PIM-SM version 2 support +CONFIG_IP_PIMSM_V2 + Kernel side support for Sparse Mode PIM version 2. You need + experimental routing daemon supporting it (pimd or gated-5). + This protocol is not used widely, so that press Y, if you + do not want play with it. + PC/TCP compatibility mode CONFIG_INET_PCTCP If you have been having difficulties telneting to your Linux machine @@ -1320,6 +1480,13 @@ a second or satellite links this option will make no difference to performance. +BSD Unix domain sockets +CONFIG_UNIX + Y if you want BSD Unix domain sockets. Unless you are working on an + embedded system or somthing, you probably want to say Y. If you try + building this as a module and you are running kerneld, you need to make + sure and add 'alias net-pf-1 unix' to your /etc/conf.module file. + The IPv6 protocol CONFIG_IPV6 This is experimental support for the next version of the Internet @@ -1338,6 +1505,20 @@ be called ipv6.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. It's safe to say N for now. +IPv6: enable EUI-64 token format +CONFIG_IPV6_EUI64 + 6bone is moving to new aggregatable address format and new link local + address assignment (EUI-64). Say Y, if your site already upgraded, or + started upgrade. + +IPv6: disable provider based addresses +CONFIG_IPV6_NO_PB + Linux tries to operate correctly, when site is moved to EUI-64 + only partially. Unfortunately, these two formats ("provider based" + and "aggregatable") are incompatible. Say Y, if your site finished + upgrade, and/or you encountered some problems caused by presense of + two link-local addresses on an interface. + The IPX protocol CONFIG_IPX This is support for the Novell networking protocol, IPX, commonly @@ -2675,6 +2856,18 @@ with many transceiver designs and the fact that the TCM3105 (if used) is operated widely outside its specifications. +Soundcard modem support for 2666 baud AFSK modulation +CONFIG_SOUNDMODEM_AFSK2666 + This option enables the soundmodem driver 2666 baud AFSK modem. + This modem is experimental, and not compatible to anything + else I know of. + +Soundcard modem support for 4800 baud 8PSK modulation +CONFIG_SOUNDMODEM_PSK4800 + This option enables the soundmodem driver 4800 baud 8PSK modem. + This modem is experimental, and not compatible to anything + else I know of. + Soundcard modem support for 4800 baud HAPN-1 modulation CONFIG_SOUNDMODEM_HAPN4800 This option enables the soundmodem driver 4800 baud HAPN-1 @@ -4465,29 +4658,6 @@ module, say M here and read Documentation/modules.txt. If unsure, say N. -BOOTP support -CONFIG_RNFS_BOOTP - If you want your Linux box to mount its whole root filesystem from - some other computer over the net via NFS and you want the IP address - of your computer to be discovered automatically at boot time using - the BOOTP protocol (a special protocol designed for doing this job), - say Y here. In case the boot ROM of your network card was designed - for booting Linux and does BOOTP itself, providing all necessary - information on the kernel command line, you can say N here. If - unsure, say Y. Note that in case you want to use BOOTP, a BOOTP - server must be operating on your network. Read - Documentation/nfsroot.txt for details. - -RARP support -CONFIG_RNFS_RARP - If you want your Linux box to mount its whole root filesystem from - some other computer over the net via NFS and you want the IP address - of your computer to be discovered automatically at boot time using - the RARP protocol (an older protocol which is being obsoleted by - BOOTP and DHCP), say Y here. Note that in case you want to use RARP, - a RARP server must be operating on your network. Read - Documentation/nfsroot.txt for details. - ISO9660 cdrom filesystem support CONFIG_ISO9660_FS This is the standard filesystem used on CDROMs. It was previously @@ -5492,38 +5662,18 @@ PC joystick support CONFIG_JOYSTICK - If you have a joystick, you can say Y here. If you then create a - character special file under /dev with major number 15 and minor - number 0 or 1 (for the two joystick ports) using mknod ("man - mknod"), you can read the status of the buttons and the x and y - coordinates from that file. More information, an example program and - a calibration program are contained in the joystick package which is - available via ftp (user: anonymous) in - sunsite.unc.edu/pub/Linux/kernel/patches/console/. 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 joystick.o. If you want to compile it as a module, say M - here and read Documentation/modules.txt. - -Radio support -CONFIG_MISC_RADIO - If you have a radio card (you will probably know if you do!), then - you will want to say "y" here and make a character device file - (usually /dev/radio) with major number 10 and minor 152 using mknod - ("man mknod"). And then, don't forget to pick up some useful tools - to use said device (you _might_ find something at ftp.lmh.ox.ac.uk: - /users/weejock/linux/radio/, but I haven't written anything too - useful yet...) - -AIMSlab RadioTrack card -CONFIG_RADIO_RTRACK - Choose "y" here if you have one of these, and then fill in the port - address below. - -RadioTrack i/o port -CONFIG_RADIO_RTRACK_PORT - Enter either 0x30f or 0x20f here. The card default is 0x30f, if you - haven't changed the jumper setting on the card. + If you have a PC compatible analog or digital joystick, you can + say Y here. If you then create a character special file under /dev + with major number 15 and minor number 0 or 1 (for the two joystick + ports) using mknod ("man mknod"), you can read the status of the + buttons and the x and y coordinates from that file. More + information, an example program and a calibration program are + contained in the joystick package which is available at: + ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console + 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 joystick.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. ARC console time CONFIG_RTC_ARC @@ -5767,9 +5917,9 @@ flush the disks, reboot the system immediately or dump some status information). This is accomplished by pressing various keys while holding SysRq (Alt+PrintScreen). As you are expected to be a kernel - hacker to use this, the simple rule about learning what the keys + hacker to use this, the simple rule about learning what do the keys mean is "Use the source, Luke!" -- read drivers/char/sysrq.c. - Don't say Y unless you really know what this hack does. + Don't say Y unless you really know what does this hack do. ISDN subsystem CONFIG_ISDN @@ -5979,6 +6129,124 @@ removed from the running kernel whenever you want), say M and read Documentation/modules.txt. If unsure, say Y. +Support for Cyrix processors +CONFIG_CYRIX + This enables recognition of Cyrix processors. Without it + /proc/cpuinfo will list your processor as an unknown model + of Cyrix. With it it will list the correct details. It should + be safe to say Y here regardless of what processor you are + actually using. If this option is not enabled none of the + Cyrix feature options are available. + +Enable suspend on halt power saving feature +CONFIG_CYRIX_SUSP_HLT + Suspend on halt causes the processor to enter a low power state + when the "hlt" instruction is executed. This is disabled at + power up and many BIOSs leave it that way. You probably want it + enabled since it dramatically reduces the operating temperature + of the processor. In a few rare cases there may be problems + with some bus master DMA cards if this is enabled. + +No I/O recovery delays +CONFIG_CYRIX_FAST_IO + Historically programmers used "jmp $+2" instructions to create + delays between I/O instructions. The branch prediction of 5x86 + and higher processors renders this ineffective and so a selectable + delay is implemented for I/O instructions in the processor. Linux + uses dummy I/O instructions where necessary rather than jumps + and so the extra processor imposed delay should not be necessary. + Enabling this option removes this delay. + +5x86 performance features +CONFIG_CYRIX_5X86 + The Cyrix 5x86 has several performance feature which are enabled + using on-chip registers. This code attempts to ensure that the + useful features are set to suit Linux. Read Documentation/CPU/Cyrix + before enabling this. + WARNING: If this is enabled you may find that the only way to + reboot is to power cycle the machine. Even a hard reboot seems + to fail on some systems. + +6x86 performance features +CONFIG_CYRIX_6X86 + The Cyrix 6x86 has several performance feature which are enabled + using on-chip registers. Most are normally enabled by the BIOS + however this code ensures that all the useful ones are set to + suit Linux. Read Documentation/CPU/Cyrix before enabling this. + +Avoid unnecessary locked cycles +CONFIG_CYRIX_6X86_NOLOCK + Enabling this option causes the 6x86 not to use locked bus cycles + except for page table access and interrupt acknowledge cycles. + This allows the data used by descriptor tables, xchg instructions + and instructions preceeded by the LOCK prefix to be cached leading + to improved performance. Enabling this option has no effect if + an SMP kernel is being built - SMP requires locked cycles to + guarantee processor synchronization. + +Allocate L1 cache lines on write misses +CONFIG_CYRIX_6X86_WTALLOC + If this is enabled L1 cache write misses will cause a cache line + to be allocated. This may result in increased performance. On the + other hand it may cause excessive trashing of the L1 cache when + copying or zeroing pages. In general you _probably_ win... + +Branch Target Buffer features +CONFIG_CYRIX_6X86_BTB + The Cyrix 6x86 has branch prediction logic which is normally + only set to handle short branches (as in small loops and ifs). + This code attempts on configure the branch prediction logic + appropriately. Read Documentation/CPU/Cyrix before enabling this. + +Variable sized paging mechanism (VSPM) +CONFIG_CYRIX_6X86_VSPM + Variable sized paging mechanism (VSPM) is a feature of the Cyrix + 6x86 family of processors that allows large regions of memory + to be mapped in one go, significantly reducing the amount of work + the MMU has to do compared with traditional paging. However VSPM + is known to be buggy in many 6x86 chip revisions. Please read + Documentation/CPU/Cyrix before enabling this. + WARNING: If this is enabled you may find that the only way to + reboot is to power cycle the machine. Even a hard reboot seems + to fail on some systems. + +Allocate L1 cache lines on write misses +CONFIG_AMD_K5_WTALLOC + If this is enabled L1 cache write misses will cause a cache line + to be allocated. This may result in increased performance. On the + other hand it may cause excessive trashing of the L1 cache when + copying or zeroing pages. In general you _probably_ win... + +Allocate L1 cache lines on write misses +CONFIG_AMD_K6_WTALLOC + If this is enabled L1 cache write misses will cause a cache line + to be allocated. This may result in increased performance. On the + other hand it may cause excessive trashing of the L1 cache when + copying or zeroing pages. In general you _probably_ win... + +Use write cacheability detection +CONFIG_AMD_K6_WTALLOC_WCDE + Write cacheability detection requires the system logic to assert + the cache enable bus signal during a write cycle. Some chipsets + do this and some do not. Some, such as Triton, do but not at + the appropriate point during the write cycle. Cacheability + detection is not normally useful unless you have memory mapped + devices which exist outside the 640k-1M range but within your + actual memory. (There is another option that disables write + allocate for the 15M-16M range commonly used by older VLB + video cards). You probably do not want to enable this. + +No write allocate between 15MB-16MB +CONFIG_AMD_K6_WTALLOC_WAE15M + There were a small number of cards, mainly VESA Local Bus + video cards, that were memory mapped to the 15M-16M address + range. If you have such a card you do not want write allocate + to delay or reorder writes to this space so you must enable + this option. Other memory mapped cards are either outside the + systems memory space or are in the 640k-1M range which is + not subject to write allocate so this option is not normally + required. + # m68k-specific kernel options # Documented by Chris Lawrence et al. @@ -6214,6 +6482,11 @@ 1260 accelerator, and the optional SCSI module, say Y. Otherwise, say N. +Fastlane SCSI support +CONFIG_FASTLANE_SCSI + If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use one + in the near future, say Y to this question. Otherwise, say N. + Atari native SCSI support CONFIG_ATARI_SCSI If you have an Atari with built-in NCR5380 SCSI controller (TT, @@ -6333,6 +6606,33 @@ whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +Radio support +CONFIG_MISC_RADIO + If you have a radio card (you will probably know if you do!), then + you will want to say "y" here and make a character device file + (usually /dev/radio) with major number 10 and minor 152 using mknod + ("man mknod"). And then, don't forget to pick up some useful tools + to use said device (you _might_ find something at ftp.lmh.ox.ac.uk: + /users/weejock/linux/radio/, but I haven't written anything too + useful yet...) + +AIMSlab RadioTrack card +CONFIG_RADIO_RTRACK + Choose "y" here if you have one of these, and then fill in the port + address below. + +RadioTrack i/o port +CONFIG_RADIO_RTRACK_PORT + Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. + +Atari SCC serial DMA support +CONFIG_ATARI_SCC_DMA + This enables DMA support for receiving data on channel A of the SCC. If + you have a TT you may say Y here and read drivers/char/atari_SCC.README. + All other users should say N here, because only the TT has SCC-DMA, even + if your machine keeps claiming so at boot time. + Atari MIDI serial support CONFIG_ATARI_MIDI If you want to use your Atari's MIDI port in Linux, say Y. @@ -6462,6 +6762,17 @@ Power Macintoshes and clones with ethernet built-in on the motherboard will usually use a MACE (Medium Access Control for Ethernet) interface. Say Y to include support for the MACE chip. + +Video For Linux +CONFIG_VIDEO_DEV + Support for audio/video capture and overlay devices. The exact capabilities + of each device vary. User tools for this are available from + ftp://ftp.uk.linux.org/pub/linux/video4linux + +BT848 Video For Linux +CONFIG_VIDEO_BT848 + Support for BT848 based frame grabber/overlay boards. This includes the + Miro, Hauppauge and STB boards. # need an empty line after last entry, for sed script in Configure. diff -u --recursive --new-file v2.1.66/linux/Documentation/VGA-softcursor.txt linux/Documentation/VGA-softcursor.txt --- v2.1.66/linux/Documentation/VGA-softcursor.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/VGA-softcursor.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,34 @@ +Software cursor for VGA by Pavel Machek +======================= & Martin Mares + + Linux now has some ability to manipulate cursor appearance. Normally, you +can set the size of hardware cursor (and also work-around some ugly bugs in +those miserable Trident cards -- see #define TRIDENT_GLITCH in drivers/char/ +vga.c). In case you enable "Software generated cursor" in the system +configuration, you can play few new tricks: you can make your cursor look +like a non-blinking red block, make it inverse background of the character +it's over or to highlight that character and still choose whether the +original hardware cursor should remain visible or not. And maybe other +things I have never thought of. + + The cursor appearance is controlled by a "[?1;2;3c" escape sequence +where 1, 2 and 3 are parameters described below. If you omit any of them, +they will default to zeroes. + + Parameter #1 specifies cursor size (0=default, 1=invisible, 2=underline, ..., +8=full block) + 16 if you want the software cursor to be applied + 32 if you +want to always change the background color + 64 if you dislike background same +as foreground. (Highlights are ignored for the last two flags.) + + The second parameter selects character attribute bits you want to change +(by simple XOR'ing them with the value of this parameter). On standard VGA, +the high 4 bits specify background and the low 4 the foreground. In both +groups, low 3 bits set color (as in normal color codes used by the console) +and the most significant one turns on highlight (or sometimes blinking -- it +depends on the configuration of your VGA). + + And the third parameter consists of character attribute bits you want +to set. Bit setting takes place before bit toggling, so you can simply +clear a bit by including it in both the set mask and the toggle mask. + + diff -u --recursive --new-file v2.1.66/linux/Documentation/cyrix.txt linux/Documentation/cyrix.txt --- v2.1.66/linux/Documentation/cyrix.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/cyrix.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,201 @@ + Cyrix Processor Support + ----------------------- + +Processor Recognition +--------------------- + +Cyrix processors prior to the 6x86MX power up in a default mode +designed to avoid compatibility problems with software that +makes assumptions about processor capabilities based solely on +the apparent family of processor. Unless special handling is +provided Cyrix chips will be identified as some unknown model +of 486. + + The Cyrix processor recognition kernel build option compiles +in code that enables the CPUID instruction on Cyrix processors +and that uses the Cyrix specific DEVID feature to identify the +particular type of Cyrix chip present. + + The 6x86MX and later processors have CPUID enabled by default +however special handling is still required to read the specific +processor type using DEVID since the CPUID information gives +family 6, model 0 - i.e. an A step PPro. + + The combination of CPUID and DEVID allows all current Cyrix +processors to be recognised and listed correctly in /proc/cpuinfo. +This includes Cx486, 5x86, 6x86, Gx86 (aka MediaGx) and 6x86MX. + + Processor recognition is required for all other Cyrix specific +options. + + +Suspend on Halt Power Saving +---------------------------- + +The suspend on halt power saving feature allows the processor to +enter a low power mode when the "hlt" instruction is executed. This +results in dramatically reduced operating temperatures if you do +not spend long periods of time running processor intensive tasks. +Cyrix processors allow this feature to be enabled an disabled +through their configuration registers. The default state on reset +is disabled and many (most?) BIOSs leave it disabled hence a +kernel configuration option is provided that adds code to explicitly +enabled suspend on halt when Linux boots. + + However there appear to be a few rare cases in which the +combination of suspend on halt and some bus master DMA cards can +cause the system to lock up. If this appears to happen you may +need to leave suspend on halt in its default state. (Note that +an option to _disable_ suspend on halt is not provided. If your +BIOS enables it you have to live with it) + + +5x86 Performance Features +------------------------- + +The 5x86 contains a performance control register that allows +several performance enhancing features to be turned on. Unfortunately +many of these features do not appear to work correctly. The 5x86 +performance features kernel build option will attempt to set +the performance control register appropriately but it is +impossible to guarantee that even these conservative settings +will work on all chips. + + WARNING: If this is enabled you may find that the only way to +reboot is to power cycle the machine. Even a hard reboot seems +to fail on some systems. + + +6x86 Performance Features +------------------------- + +Like the 5x86 the 6x86 has several Cyrix specific performance +features. Normally a 6x86 aware BIOS will set these to reasonable, +if not fully optimal, settings. The 6x86 performance features +kernel build option mostly just fine tunes them. + + +6x86 Branch Prediction +---------------------- + +The 6x86 uses speculative execution coupled with several levels +of branch prediction to maximise processing speed. While the +default power up state is reasonable the branch prediction logic +is configurable and there may be some benefit in fine tuning it. + + Unfortunately Cyrix offer no documentation on how to configure +branch prediction and IBM have only partial documentation available. +Further detail and speculation is available from the 6x86opt package +by Mikael Johansson . + + The initial power up state of the 6x86 configures the branch +prediction logic to handle short branches. The 6x86 branch target +buffer features kernel build option enables code that enables +handling of long branches as well. It is not clear if this will +benefit in your particular case or not. + + +6x86 Variable Sized Paging Mechanism +------------------------------------ + +The variable sized paging mechanism (VSPM) is a feature of the Cyrix +6x86 family of processors that allows large regions of memory +to be mapped using a single MMU entry rather than many individual +page sized entries. This significantly reduces the overhead in +accessing such regions. It is also ideally suited to use for the +linear mapping of physical memory to kernel memory used by Linux. + + The Cyrix documenation offers only a brief paragraph of explanation. +Unfortunately the observed behaviour of VSPM suggests that even +this little information is not entirely correct. Worse still, no one +at Cyrix is able to answer questions concerning VSPM. Given that +every revision of 6x86 has *different* VSPM bugs this is not entirely +surprising! Work arounds are in place for the known bugs in step 1, +revisions 4, 5 and 6 chips. Revision 7 is also believed to work. + + WARNING: There appears to be no way to disable a VSPM entry once +it has been created short of a hard reset (which may mean a power +cycle). Failure to clear the VSPM entries means that programs that +use virtual memory layouts different from Linux will crash unexpectedly +after Linux has been running. This includes Windows NT/95, programs +that use DOS extenders etc. + + By experiment: + + * VSPM pages must be power of two sizes. A single 24MB page fails. + This is not entirely surprising but the documentation could give + the impression that VSPM supports arbitrary sizes. + + * Documentation suggests there are 8 VSPM slots (3 bit index) but + tests show the upper four slots mirror the lower four. + + * VSPM entries appear to override traditional page table entries + so we must not overlap the start of the vmalloc region. + + The following only apply to 1 rev 6 and lower chips. 1 rev 7 and + above do not appear to have these problems. + + * With a 16MB page followed by an 8MB page I always get a write + fault on the last 4k of the 8MB page. With 8MB plus 4MB I can't + even boot. + If we have such a memory size we map the first power of two + with a VSPM entry and use traditional paging for the rest. + + * Do not try and create a mapping with dirty and accessed flags + clear - a step 1 rev 5 chip will crash. + + * The valid bit in a VSPM entry is non-functional. There is no way + to invalidate a VSPM entry once it has been written. + + * Attempting to replace a VSPM entry with one that maps a zero + sized region from 0 to 0 crashes the CPU. + + +What more could be done +----------------------- + + Disabling write allocate while we do page copies/clears will +avoid unnecessary cache trashing. However it will also reduce +the apparent memory bandwidth for the operation so it runs +slower (with write allocate the write to memory becomes delayed +and happens asynchronously). Rumour has it that disabling +write allocate for such operations is generally good on an +Intel chip. Disabling and re-enabling write allocate on a +Cyrix would take and extra 60-65 clock cycles each. + + The 6x86 allows Address regions to be set up and en/disabling +certain features for these regions. In order to optimize, we could +analyse the setup done (or not done) by the BIOS and optimize it. +However, it is worth noting that the BIOS probably has more +hardware specific details coded in it than we could ever determine +by any form of probing so if it sets something up in a particular +way the motherboard designers may have had very good reasons for +doing it. Trying to play fast and loose may not be such a good +idea for the general case. + + * Setting up regions fo the main memory: RCE, WWO, WL(?), WG + + * Setting up VGA text (0x000a0000) and graphics memory (PCI: + e.g. 0xe0000000) to RCD, WG + + * Setting up BIOS regions to RCD or RCE, WT + + * Not touching SMM space (ARR3) + + * Disabling WG for Memory Mapped IO + +(RCE/D = Region cache enable/disable, WWO = Weak Write Ordering, +WL = Weak Locking, WG = Write Gathering, WT = Write Through.) + + +Where to get information +------------------------ + + There is a databook in PDF format (6X-DBOOK.PDF), which can be down- +loaded from Cyrix' WWW server, which contains a description of the +Configuration Registers CCR0 - CCR5, the Device Identification Registers +DIR0 + DIR1 and the Address Region ARRx and Region Control +RCRx registers and an incomplete description of the VSPM mechanism. +More about CPU detection, VSPM and more undocumented features can be +found on the Pentium Compiler Group homepage (http://www.goof.com/pcg) +and by following the links found in the docs. diff -u --recursive --new-file v2.1.66/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.1.66/linux/Documentation/devices.tex Wed Nov 26 16:24:01 1997 +++ linux/Documentation/devices.tex Sat Nov 29 10:33:18 1997 @@ -4,7 +4,7 @@ % pages to print... :-) If you're actually putting this in print, you % may wish to change these. % -% $Id: devices.tex,v 1.3 1997/11/10 01:29:35 hpa Exp $ +% $Id: devices.tex,v 1.28 1997/11/12 23:59:41 davem Exp $ % \oddsidemargin=0in \textwidth=6.5in diff -u --recursive --new-file v2.1.66/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.1.66/linux/Documentation/ioctl-number.txt Wed Sep 3 20:52:41 1997 +++ linux/Documentation/ioctl-number.txt Sat Nov 29 10:33:18 1997 @@ -91,6 +91,7 @@ 'c' all linux/comstats.h 'f' all linux/ext2_fs.h +'j' 00-3F linux/joystick.h 'k' all asm-sparc/kbio.h, asm-sparc64/kbio.h 'l' 00-3F linux/tcfs_fs.h in development: @@ -125,3 +126,4 @@ 0xA3 90-9F DoubleTalk driver in development: +0xAB 00-06 Network block device diff -u --recursive --new-file v2.1.66/linux/Documentation/joystick.txt linux/Documentation/joystick.txt --- v2.1.66/linux/Documentation/joystick.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/joystick.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,200 @@ + PC Joystick driver v1.0.6 beta + (c) 1997 Vojtech Pavlik +---------------------------------------------------------------------------- + +1. Intro +~~~~~~~~ + The PC Joystick driver for Linux provides support for analog (variable +resistor based) and digital (switch based) joysticks connected via the PC +game port. It can support up to 2 joysticks. + + Because the joystick driver is still in its beta stage I'm very interested +in any problems you encounter while using it. Bug reports and success +stories are also welcome. + +2. Usage +~~~~~~~~ + If you enable the joystick driver in the kernel configuration, all +connected joystick should be found automatically. If that doesn't work, you +can pass the joystick driver the following kernel command line arguments: + +js=0xXX,0xYY + + Where XX and YY are bit masks for the two joysticks, with the bits +representing: + +Bit | Explanation +----------------- + 0 | Axis 0 + 1 | Axis 1 + 2 | Axis 2 + 3 | Axis 3 + 4 | Button 0 + 5 | Button 1 + 6 | Button 2 + 7 | Button 3 + + These bitmasks are ANDed with what's found by the driver and the result is +used. + + Another method of using the driver is loading it as a module. For that, +select `M' for this driver in the kernel configuration and insert the +module: + +insmod js.o js=0xXX,0xYY + + To enable the user space programs to read the joystick device, you have to +create the device files using mknod (man mknod for more info): + +mknod /dev/js0 c 15 0 +mknod /dev/js1 c 15 1 + +3. Calibration +~~~~~~~~~~~~~~ + As of version 1.0 the calibration routines used in the joystick driver are +worth using. The idea of calibration is that you have to calibrate the +joystick only once, and then set the calibration at boot-time, thus removing +the need of re-calibrating it in each program that uses it. + + For calibration, use the jscal program, contained in the joystick package +which is available at: + +ftp://atrey.karlin.mff.cuni.cz/pub/local/vojtech/joystick/joystick-1.0.6.tar.gz + +And soon also at: + +ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/joystick-1.0.6.tar.gz + +4. Programming Interface +~~~~~~~~~~~~~~~~~~~~~~~~ + The 1.0 driver uses a new, event based approach to the joystick driver. +Instead of the user program polling for the joystick values, the joystick +driver now reports only any changes of its state. See joystick.h and +jstest.c included in the joystick package for more information. The joystick +device can be used in either blocking or nonblocking mode and supports +select() calls. + + For backward compatibility the old interface is still included, but will +be dropped in the future. + +5. Credits +~~~~~~~~~~ + Thanks to the following authors that contributed to the joystick driver +development: + + 0.1-0.5 Arthur C. Smith + 0.5 Eyal Lebedinsky + 0.6 Jeff Tranter + 0.7 Carlos Puchol + 0.7.1-0.8 Matt Rhoten + 0.7.3 Dan Fandrich + 0.7.3 Sverker Wilberg + 0.8 Hal Maney + 0.8 Bernd Schmidt + 0.9 Alan Cox + 0.9.0-1.0.6 Vojtech Pavlik + +6. Change Log +~~~~~~~~~~~~~ + The current (1.0.x) version was originally based on the 0.7.3 version of +the joystick driver, which caused some inconsistencies in version numbering. +The following log documents all changes done to the driver by various +contributors: + +Version 0.1 Original version + Works but lacks multi-joystick support +Version 0.2 Added multi-joystick support (minor 0 and 1) + Added delay between measuring joystick axis + Added scaling ioctl +Version 0.3 Modified scaling to use ints to prevent kernel + panics 8-) +Version 0.4 Linux 0.99.6 and fixed race condition in js_read. + After looking at a schematic of a joystick card + it became apparent that any write to the joystick + port started ALL the joystick one shots. If the + one that we are reading is short enough and the + first one to be read, the second one will return + bad data if it's one shot has not expired when + the joystick port is written for the second time. + Thus solves the mystery delay problem in 0.2! +Version 0.5 Upgraded the driver to the 0.99.9 kernel, added + joystick support to the make config options, + updated the driver to return the buttons as + positive logic, and read both axis at once + and added some new ioctls. +Version 0.6 Made necessary changes to work with 0.99.15 + kernel (and hopefully 1.0). Also did some + cleanup: indented code, fixed some typos, wrote + man page, etc ... +Version 0.7 Support for modules +Version 0.7.1 Fix bug in reading button state of js1 + Add include so module compiles under recent kernels +Version 0.7.3 Include directives changed for joystick.h + Separated out joystick detection/counting, cleanup + Fix for detection of 3-axis joysticks + Better detection announcement + Added I/O port registration, cleaned up code +Version 0.8 New read loop + Cleaned up #includes to allow #include of joystick.h with + gcc -Wall and from g++ + Made js_init fail if it finds zero joysticks + General source/comment cleanup + Use of MOD_(INC|DEC)_USE_COUNT + Changes to compile correctly under 1.3 in kernel or as module +Version 0.9 Ported to 2.1.x + Reformatted to resemble Linux coding standard + Removed semaphore bug (we can dump the lot I think) + Fixed xntp timer adjust during joystick timer0 bug + Changed variable names to lower case. Kept binary compatibility. + Better ioctl names. Kept binary compatibility. + Removed 'save_busy'. Just set busy to 1. +Version 0.9.0 Based on 0.7.3 + New read function that allows two axes have same value + New joystick calibration code + Real support for 3-axis joysticks + CPU speed independent timeouts + Reads may happen even for unwhole record size => cat /dev/js0 works + Correct error for lseek + /dev/js? can be read simultaneously by several processes +Version 0.9.1 IOCTLs now obey general Linux IOCTL rules ('j' letter assigned) + Use of verify_area result codes + Fuzz correction added + Semaphore and many cli()'s removed + Fix for TurboFire joysticks - read buttons always + Fix for broken joysticks - return with -ENODEV only if joystick + completely disconnected + Fix in read function to allow zero results + Broken line correction added for broken joysticks (eg. JB-500) + Timeouts back separated for easier setting + Some fixes and cleanups in read function +Version 0.9.2 Fixed a typo causing nothing to be working +Version 1.0.0 Event approach started +Version 1.0.1 Complete rewrite + Compiles but doesn't work +Version 1.0.2 Works, many bugs fixed, more yet to come +Version 1.0.3 Tail cutting logic changes & fixes + Fix in js_do_bh - no more zero values for axes + Lost event changest & fixes +Version 1.0.4 Kernel command line & module configuration support + Better cli()/sti() handling + Linux 2.1.25 select => poll changes +Version 1.0.5 Fixes in calibration routines + Better jscal +Version 1.0.6 Backward compatibility with old js driver added + Init value after recalibration bug fixed + Using KERN_* printk() codes + Finally leaving ALPHA and going beta + Cosmetic changes + +7. To do +~~~~~~~~ + Sooner or later I'll get to these: + + Backport & create patches for 2.0 + Try using Pentium timers for better precision + Create patches for most common programs using joystick + Support for cards with hw calibration (Gravis Ultrasound, QuickShot) + Support for multiport cards (QuickShot 4-joy board) + Support for multiaxis, multibutton joysticks (Gravis Firebird) + Support for MS digital joystick + diff -u --recursive --new-file v2.1.66/linux/Documentation/m68k/00-INDEX linux/Documentation/m68k/00-INDEX --- v2.1.66/linux/Documentation/m68k/00-INDEX Tue May 13 22:41:00 1997 +++ linux/Documentation/m68k/00-INDEX Sat Nov 29 10:33:18 1997 @@ -1,7 +1,5 @@ 00-INDEX - this file -amiboot.txt - - info and options for the Linux/m68k Amiga bootstrap (Amiboot) framebuffer.txt - info about the Linux/m68k frame buffer device kernel-options.txt diff -u --recursive --new-file v2.1.66/linux/Documentation/m68k/amiboot.txt linux/Documentation/m68k/amiboot.txt --- v2.1.66/linux/Documentation/m68k/amiboot.txt Mon Jul 7 08:18:53 1997 +++ linux/Documentation/m68k/amiboot.txt Wed Dec 31 16:00:00 1969 @@ -1,282 +0,0 @@ - - Linux/m68k Amiga Bootstrap version 5.6 - -------------------------------------- - -Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) -Last revised: June 12, 1997 - - -0. Introduction ---------------- - -Amiboot is used to boot Linux/m68k on Amiga from the CLI/Shell. - -Before you try to boot Linux/m68k for the first time, please read the FAQ - - http://www.clark.net/pub/lawrencc/linux/faq/faq.html - -and the Installation Guide - - http://www.informatik.uni-oldenburg.de/~amigo/inst.html - -first. Although the Installation Guide is getting a bit outdated, it's still a -good starting point. - -Amiboot 5.6 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo -interface versions 1.x and 2.x). Please use an older version for older kernels. - - -1. Running Amiboot ------------------- - -The Amiboot invocation syntax looks like - - amiboot [options] [kernel command line] - -Basic options: - - --help Display the usage information - - --kernel file Use kernel image `file' (default is `vmlinux') - - --ramdisk file Use ramdisk image `file' - -Advanced options: - - --debug Enable debug mode - - --baud speed Set the serial port speed (default is 9600 bps) - - --memfile file Use memory file `file' - - --keep-video Don't reset the video mode - - --model id Set the Amiga model to `id' - - --processor cfm Set the processor type to `cfm' - -The kernel command line contains the options you want to pass to the kernel and -to init, the process that's started first by Linux. Please read -linux/Documentation/m68k/kernel-options.txt for more information. - -Normally you only use the --kernel option to specify the file that contains the -Linux/m68k kernel image, and --ramdisk if you want to boot from a ramdisk file, -i.e. a file containing a complete file system, instead of from a hard disk -partition. - -Note that both the kernel image and the ramdisk image can be compressed with -gzip. Amiboot knows how to deal with gzipped kernel images, and the kernel -recognizes gzipped ramdisk images. - -Example: - - amiboot -k vmlinux-2.1.13 root=/dev/hda3 video=font:PEARL8x8 - -Amiboot will boot the kernel image `vmlinux-2.1.13' and will pass -`root=/dev/hda3 video=font:PEARL8x8' to the kernel. - - -The other options are more advanced. Don't use them unless you really have to -and you know what you're doing. - -The --baud option allows you to specify the serial port speed for initial boot -information and initial kernel messages. Note: this option does not work with -kernels with bootinfo interface versions prior to 2.0. - -The --memfile option is used to specify the blocks of memory that will be used -by Linux. - -The --keep-video option is necessary if you want to retain the current graphics -mode (on a graphics board) under Linux. Currently this is only useful if you -have a CyberVision 64 graphics board. - -Finally, --model and --processor allow you to specify your Amiga model and -processor type if they are detected incorrectly, and --debug dumps some -information which simplifies debugging. - - -2. The memory file ------------------- - -If you have some non-AutoConfig memory you want to use under Linux, or if you -want to disable some parts of your memory (e.g. Zorro II RAM on '040 based -systems), you have to use a memory file and the --memfile option. This file -contains information about the memory chunks you want to use under Linux. The -format for the file is: - - chipramsize - [0xfastchunkaddr fastchunksize] - [0xfastchunkaddr fastchunksize] - ... - -For example, if you don't want Linux to use your 2nd meg of chipram, you would -create a file that contains only: - - 1048576 - -If you had 1M of chip ram, 2M of 16 bit FAST ram at address 0x200000 and 16M of -32 bit FAST ram at address 0x80000000, and you didn't want Linux to use the -slow 16 bit FAST ram, you'd create a file that looks like: - - 1048576 - 0x80000000 16777216 - -The memory file can also be used to specify in which block of memory the kernel -will be put. Normally Amiboot will put the kernel in the first block of Fast -RAM it will find. If you use a memory file, it will put the kernel in the first -block of fast RAM you specify. - - -3. Amiga models ---------------- - -If Amiboot incorrectly detects the model of your Amiga, you can force it to -detect any model you want using the --model option. `id' must be one of the -numbers as defined in linux/include/asm-m68k/amigahw.h (AMI_*). Currently the -following models are known: - - Model ID - ----- -- - Amiga 500 1 - Amiga 500+ 2 - Amiga 600 3 - Amiga 1000 4 - Amiga 1200 5 - Amiga 2000 6 - Amiga 2500 7 - Amiga 3000 8 - Amiga 3000T 9 - Amiga 3000+ 10 - Amiga 4000 11 - Amiga 4000T 12 - CDTV 13 - CD32 14 - Draco 15 - -Note that Amiboot can't distinguish among Amiga models that are very similar to -each other (e.g. A500/A1000/A2000/A2500 and A3000/A3000T). Of course this is -harmless and there's no real need to use --model in that case. - -Please send me the output of amiboot used with the --debug option if your Amiga -model is detected incorrectly. - - -4. Processor types ------------------- - -If your processor is detected incorrectly, you can override this using the -`--processor cfm' option. `cfm' must be a three-digit number with - - - `c' the CPU (Central Processing Unit) type, - - 'f' the FPU (Floating Point Unit) type, - - 'm' the MMU (Memory Management Unit) type, - -from the table below: - - value | CPU | FPU | MMU - -------+-------+-------+------- - 0 | - | - | - - 1 | 68020 | 68881 | 68851 - 2 | 68030 | 68882 | 68030 - 3 | 68040 | 68040 | 68040 - 4 | 68060 | 68060 | 68060 - -e.g. `444' if you have a 68060 and `303' if you have a 68LC040. - -Note that normally you don't have to use this option. It's only needed for some -combinations of an old Kickstart ROM and a new processor (e.g. a 68060). - - -5. Abbreviations ----------------- - -All options also have a shorthand: - - --help -h - --kernel -k - --ramdisk -r - --debug -d - --baud -b - --memfile -m - --keep-video -v - --model -t - --processor -p - - -6. Miscellaneous ----------------- - -Some expansion boards keep on generating interrupts once they were initialized -under AmigaOS. This can cause an interrupt deadlock while booting Linux. The -following boards are recognized and disabled: - - o Helfrich Rainbow 3 Graphics Board - o Helfrich Piccolo Graphics Board - o Helfrich SD64 Graphics Board - o Village Tronic Ariadne Ethernet Board - o Hydra Systems Amiganet Ethernet Board - -The following boards are known to cause problems but we don't have a disable -routine for them yet: - - o Commodore A2060 Arcnet Card - o Ameristar A560 Arcnet Card - -If you write a routine to disable an expansion board, please let me know. - - -7. Troubleshooting ------------------- - - - Amiboot says - - This bootstrap is too old/new for this kernel - - This means that you're using a version of Amiboot that's not compatible - with the kernel you want to boot. - - Solution: use the correct Amiboot, or use another kernel. - - - Amiboot says - - Warning: too many AutoConfig devices. Ignoring device at 0x???????? - - or - - Warning: too many memory blocks. Ignoring block of ???K at 0x???????? - - This means that you have more AutoConfig devices or memory chunks than - Amiboot supports. Note that you can still boot Linux/m68k, but that the - additional devices or memory blocks can't be used. - - Solution: increase the ZORRO_NUM_AUTO (for AutoConfig devices) or - NUM_MEMINFO (for memory chunks) values in the kernel sources - (linux/include/asm-m68k/zorro.h and linux/include/asm-m68k/setup.h) and - recompile both Amiboot and the kernel. - - - If all you get is a grey screen, or if Linux/m68k suddenly locks up during - booting, try the following things: - - o Boot with the Startup-Sequence disabled, run SetPatch and try again. - - o If that doesn't work, remove any expansion devices and retry. - - o Check the detected Amiga model and processor type. - - o Look at the characters that are dumped to the serial port during - booting. - - -8. Amiga-Lilo -------------- - -Once you have a stable Linux/m68k installation, you may want to try Amiga-Lilo. -Amiga-Lilo allows you to boot Linux/m68k without the overhead of booting -AmigaOS first, and it provides you with a boot menu. - - -9. Credits ----------- - -This readme was written by Geert Uytterhoeven. A lot of information was taken -from the ANNOUNCE-* files by Hamish Macdonald. diff -u --recursive --new-file v2.1.66/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt --- v2.1.66/linux/Documentation/m68k/kernel-options.txt Tue May 13 22:41:00 1997 +++ linux/Documentation/m68k/kernel-options.txt Sat Nov 29 10:33:18 1997 @@ -3,8 +3,8 @@ Command Line Options for Linux/m68k =================================== -Date: Sep 14, 1996 -Linux/m68k version: 2.0.20 +Date: Oct 6, 1997 +Linux/m68k version: 2.0.21 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek) Update: jds@kom.auc.dk (Jes Sorensen) @@ -312,9 +312,11 @@ 4.1) video= -------------- -Syntax: video= +Syntax: video=: -The is a comma-separated list of the sub-options listed +The parameter specifies the name of the frame buffer, +eg. most atari users will want to specify `atafb' here. The + is a comma-separated list of the sub-options listed below. NB: Please notice that this option was renamed from `atavideo' to @@ -322,6 +324,9 @@ might need to update your boot-scripts if upgrading to 2.0.x from an 1.2.13ply kernel. +NBB: The behavior of video= was changed in 2.1.57 so the recommended +option is to specify the name of the frame buffer. + 4.1.1) Video Mode ----------------- @@ -420,7 +425,7 @@ Syntax: external:;;;;[;[;\ - [;[;]]]] + [;[;[;]]]]] [I had to break this line...] @@ -496,6 +501,14 @@ "vga" (which is also the default) and "mv300" (SANG MV300) are implemented. + Parameter is required for ProMST or ET4000 cards where +the physical linelength differs from the visible length. With ProMST, +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, +panning or blanking. + 4.1.8) eclock: -------------- @@ -645,7 +658,13 @@ 5.1) video= ----------- -Syntax: video= +Syntax: video=: + +The parameter specifies the name of the frame buffer, valid +options are `amifb', `cyberfb', `retz3' and `clgen', provided that the +respective frame buffer devices have been compiled into the kernel (or +compiled as loadable modules). The behavior of the option was +changed in 2.1.57 so it is now recommended to specify this option. The is a comma-separated list of the sub-options listed below. This option is organized similar to the Atari version of the diff -u --recursive --new-file v2.1.66/linux/Documentation/modules.txt linux/Documentation/modules.txt --- v2.1.66/linux/Documentation/modules.txt Tue Jan 14 02:59:10 1997 +++ linux/Documentation/modules.txt Sat Nov 29 10:33:18 1997 @@ -3,15 +3,12 @@ the internals of module, but mostly a sample of how to compile and use modules. -Note: You should ensure that the modules-X.Y.Z.tar.gz you are using +Note: You should ensure that the modutils-X.Y.Z.tar.gz you are using is the most up to date one for this kernel. The "X.Y.Z" will reflect the kernel version at the time of the release of the modules package. Some older modules packages aren't aware of some of the newer modular -features that the kernel now supports. (If you are unsure, you can -usually find out what the current release of the modules-X.Y.Z.tar.gz -package is by looking up the URL listed for "Bjorn Ekwall" in the -file ./linux/CREDITS) - +features that the kernel now supports. The current required version +is listed in the file linux/Documentation/Changes. In the beginning... ------------------- diff -u --recursive --new-file v2.1.66/linux/Documentation/nbd.txt linux/Documentation/nbd.txt --- v2.1.66/linux/Documentation/nbd.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/nbd.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,57 @@ + Network Block Device (TCP version) + + Note: Network Block Device is now experimental, which approximately + means, that it works on my computer, and it worked on one of school + computers. + + What is it: With this think compiled in kernel, linux can use remote + server as one of its block devices. So every time client computer + wants to read /dev/nd0, it will send request over TCP to server, which + will reply with data readed. This can be used for stations with + low-disk space (or even disklesses - if you boot from floppy) to + borrow disk space from other computer. Unlike NFS, it is possible to + put any filesystem on it etc. It is impossible to use NBD as root + filesystem, since it requires user-level program to start. It also + allows you to run block-device in user land (making server and client + physicaly same computer, communicating using loopback). + + Current state: It currently works. Network block device looks like + being pretty stable. I originaly thought that it is impossible to swap + over TCP. It turned out not to be true - swapping over TCP now works + and seems to be deadlock-free, but it requires heavy patches into + Linux's network layer. + + Devices: Network block device uses major 43, minors 0..n (where n is + configurable in nbd.h). Create these files by mknod when needed. After + that, your ls -l /dev/ should look like: + +brw-rw-rw- 1 root root 43, 0 Apr 11 00:28 nd0 +brw-rw-rw- 1 root root 43, 1 Apr 11 00:28 nd1 +... + + Protocol: Userland program passes file handle with connected TCP + socket to actuall kernel driver. This way, kernel does not have to + care about connecting etc. Protocol is rather simple: If driver is + asked to read from block device, it sends packet of following form + "request" (all data are in network byte order): + + __u32 magic; must be equal to 0x12560953 + __u32 from; position in bytes to read from / write at + __u32 len; number of bytes to be read / written + __u64 handle; handle of operation + __u32 type; 0 = read + 1 = write + ... in case of write operation, this is + immediately followed len bytes of data + + When operation is completed, server responds with packet of following + structure "reply": + + __u32 magic; must be equal to + __u64 handle; handle copyied from request + __u32 error; 0 = operation completed successfully, + else error code + ... in case of read operation with no error, + this is immediately followed len bytes of data + + For more information, look at http://atrey.karlin.mff.cuni.cz/~pavel. diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/DLINK.txt linux/Documentation/networking/DLINK.txt --- v2.1.66/linux/Documentation/networking/DLINK.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/DLINK.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,205 @@ +Released 1994-06-13 + + + CONTENTS: + + 1. Introduction. + 2. License. + 3. Files in this release. + 4. Installation. + 5. Problems and tuning. + 6. Using the drivers with earlier releases. + 7. Acknowledgments. + + + 1. INTRODUCTION. + + This is a set of Ethernet drivers for the D-Link DE-600/DE-620 + 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. + + I have used these drivers for NFS, ftp, telnet and X-clients on + remote machines. Transmissions with ftp seems to work as + good as can be expected (i.e. > 80k bytes/sec) from a + parallel port...:-) Receive speeds will be about 60-80% of this. + Depending on your machine, somewhat higher speeds can be achieved. + + All comments/fixes to Bjorn Ekwall (bj0rn@blox.se). + + + 2. LICENSE. + + 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. + + 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. + + + 3. FILES IN THIS RELEASE. + + README.DLINK This file. + de600.c The Source (,may it be with You :-) for the DE-600 + de620.c ditto for the DE-620 + 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: + linux/drivers/net/Makefile + linux/drivers/net/CONFIG + linux/drivers/net/MODULES + linux/drivers/net/Space.c + linux/config.in + Apply the patch by: + "cd /usr/src; patch -p0 < linux/drivers/net/dlink-patches" + The old source, "linux/drivers/net/d_link.c", can be removed. + + + 4. INSTALLATION. + + o Get the latest net binaries, according to current net.wisdom. + + o Read the NET-2 and Ethernet HOWTO's and modify your setup. + + o If your parallel port has a strange address or irq, + modify "linux/drivers/net/CONFIG" accordingly, or adjust + the parameters in the "tuning" section in the sources. + + If you are going to use the drivers a loadable modules, do _not_ + enable them while doing "make config", but instead make sure that + the drivers are included in "linux/drivers/net/MODULES". + + If you are _not_ going to use the driver(s) as loadable modules, + but instead have them included in the kernel, remember to enable + the drivers while doing "make config". + + o To include networking and DE600/DE620 support in your kernel: + # cd /linux + (as modules:) + # make config (answer yes on CONFIG_NET and CONFIG_INET) + (else included in the kernel:) + # make config (answer yes on CONFIG _NET, _INET and _DE600 or _DE620) + # make clean + # make depend + # make zImage (or whatever magic you usually do) + + o I use lilo to boot multiple kernels, so that I at least + can have one working kernel :-). If you do too, append + these lines to /etc/lilo/config: + + image = /linux/zImage + label = newlinux + root = /dev/hda2 (or whatever YOU have...) + + # /etc/lilo/install + + o Do "sync" and reboot the new kernel with a D-Link + DE-600/DE-620 pocket adapter connected. + + o The adapter can be configured with ifconfig eth? + where the actual number is decided by the kernel + when the drivers are initialized. + + + 5. "PROBLEMS" AND TUNING, + + o If you see error messages from the driver, and if the traffic + stops on the adapter, try to do "ifconfig" and "route" once + more, just as in "rc.inet1". This should take care of most + problems, including effects from power loss, or adapters that + aren't connected to the printer port in some way or another. + You can somewhat change the behaviour by enabling/disabling + the macro SHUTDOWN_WHEN_LOST in the "tuning" section. + For the DE-600 there is another macro, CHECK_LOST_DE600, + that you might want to read about in the "tuning" section. + + o Some machines have trouble handling the parallel port and + the adapter at high speed. If you experience problems: + + DE-600: + - The adapter is not recognized at boot, i.e. an Ethernet + address of 00:80:c8:... is not shown, try to add another + "; SLOW_DOWN_IO" + at DE600_SLOW_DOWN in the "tuning" section. As a last resort, + uncomment: "#define REALLY_SLOW_IO" (see for hints). + + - You experience "timeout" messages: first try to add another + "; SLOW_DOWN_IO" + at DE600_SLOW_DOWN in the "tuning" section, _then_ try to + increase the value (original value: 5) at + "if (tickssofar < 5)" near line 422. + + DE-620: + - Your parallel port might be "sluggish". To cater for + this, there are the macros LOWSPEED and READ_DELAY/WRITE_DELAY + in the "tuning" section. Your first step should be to enable + LOWSPEED, and after that you can "tune" the XXX_DELAY values. + + o If the adapter _is_ recognized at boot but you get messages + about "Network Unreachable", then the problem is probably + _not_ with the driver. Check your net configuration instead + (ifconfig and route) in "rc.inet1". + + o There is some rudimentary support for debugging, look at + the source. Use "-DDE600_DEBUG=3" or "-DDE620_DEBUG=3" + when compiling, or include it in "linux/drivers/net/CONFIG". + IF YOU HAVE PROBLEMS YOU CAN'T SOLVE: PLEASE COMPILE THE DRIVER + WITH DEBUGGING ENABLED, AND SEND ME THE RESULTING OUTPUT! + + + 6. USING THE DRIVERS WITH EARLIER RELEASES. + + The later v1.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 + all releases on-line. + Known needed changes to date: + - release patchfile: some patches will fail, but they should + be easy to apply "by hand", since they are trivial. + (Space.c: d_link_init() is now called de600_probe()) + - de600.c: change "mark_bh(NET_BH)" to "mark_bh(INET_BH)". + - de620.c: (maybe) change the code around "netif_rx(skb);" to be + similar to the code around "dev_rint(...)" in de600.c + + + 7. ACKNOWLEDGMENTS. + + These drivers wouldn't have been done without the base + (and support) from Ross Biro , + and D-Link Systems Inc. The driver relies upon GPL-ed + source from D-Link Systems Inc. and from Russel Nelson at + Crynwr Software . + + Additional input also from: + Donald Becker , Alan Cox + and Fred N. van Kempen + + DE-600 alpha release primary victim^H^H^H^H^H^Htester: + - Erik Proper . + Good input also from several users, most notably + - Mark Burton . + + DE-620 alpha release victims^H^H^H^H^H^H^Htesters: + - J. Joshua Kopper + - Olav Kvittem + - Germano Caronni + - Jeremy Fitzhardinge + + + Happy hacking! + + Bjorn Ekwall == bj0rn@blox.se diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/PLIP.txt linux/Documentation/networking/PLIP.txt --- v2.1.66/linux/Documentation/networking/PLIP.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/PLIP.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,162 @@ +PLIP: The Parallel Line Internet Protocol Device + +Donald Becker (becker@super.org) +I.D.A. Supercomputing Research Center, Bowie MD 20715 + +At some point T. Thorn will probably contribute text, +Tommy Thorn (tthorn@daimi.aau.dk) + +PLIP Introduction +----------------- + +This document describes the parallel port packet pusher for Net/LGX. +This device interface allows a point-to-point connection between two +parallel ports to appear as a IP network interface. + +What is PLIP? +============= + +PLIP is Parallel Line IP, that is, the transportation of IP packages +over a parallel port. In the case of a PC, the obvious choice is the +printer port. PLIP is a non-standard, but [can use] uses the standard +LapLink null-printer cable [can also work in turbo mode, with a PLIP +cable]. [The protocol used to pack IP packages, is a simple one +initiated by Crynwr.] + +Advantages of PLIP +================== + +It's cheap, it's available everywhere, and it's easy. + +The PLIP cable is all that's needed to connect two Linux boxes, and it +can be build for very few bucks. + +Connecting two Linux boxes takes only a seconds decision and a few +minutes work, no need to search for a [supported] netcard. This might +even be especially important in the case of notebooks, where netcard +are not easily available. + +Not requiring a netcard also means that apart from connecting the +cables, everything else is software configuration [which in principle +could be made very easy.] + +Disadvantages of PLIP +===================== + +Doesn't work over a modem, like SLIP and PPP. Limited range, 15 m. +Can only be used to connect three (?) Linux boxes. Doesn't connect to +an exiting ethernet. Isn't standard (not even de facto standard, like +SLIP). + +Performance +========== + +PLIP easily outperforms ethernet cards....(ups, I was dreaming, but +it *is* getting late. EOB) + +PLIP hardware interconnection +----------------------------- + +PLIP uses several different data transfer methods. The first (and the +only one implemented in the early version of the code) uses a standard +printer "null" cable to transfers data four bits at a time using +data bit outputs connected to status bit inputs. + +The second data transfer method relies on both machines having +bi-directional parallel ports, rather than output-only ``printer'' +ports. This allows byte-wide transfers and avoids reconstructing +nibbles into bytes, leading to much faster transfers. + +Parallel Transfer Mode 0 Cable +============================== + +The cable for the first transfer mode is a standard +printer "null" cable which transfers data four bits at a time using +data bit outputs of the first port (machine T) connected to the +status bit inputs of the second port (machine R). There are five +status inputs, and they are used as four data inputs and a clock (data +strobe) input, arranged so that the data input bits appear as contiguous +bits with standard status register implementation. + +A cable that implements this protocol is available commercially as a +"Null Printer" or "Turbo Laplink" cable. It can be constructed with +two DB-25 male connectors symmetrically connected as follows: + + STROBE output 1* + D0->ERROR 2 - 15 15 - 2 + D1->SLCT 3 - 13 13 - 3 + D2->PAPOUT 4 - 12 12 - 4 + D3->ACK 5 - 10 10 - 5 + D4->BUSY 6 - 11 11 - 6 + D5,D6,D7 are 7*, 8*, 9* + AUTOFD output 14* + INIT output 16* + SLCTIN 17 - 17 + extra grounds are 18*,19*,20*,21*,22*,23*,24* + GROUND 25 - 25 +* Do not connect these pins on either end + +If the cable you are using has a metallic shield it should be +connected to the metallic DB-25 shell at one end only. + +Parallel Transfer Mode 1 +======================== + +The second data transfer method relies on both machines having +bi-directional parallel ports, rather than output-only ``printer'' +ports. This allows byte-wide transfers, and avoids reconstructing +nibbles into bytes. This cable should not be used on unidirectional +``printer'' (as opposed to ``parallel'') ports or when the machine +isn't configured for PLIP, as it will result in output driver +conflicts and the (unlikely) possibility of damage. + +The cable for this transfer mode should be constructed as follows: + + STROBE->BUSY 1 - 11 + D0->D0 2 - 2 + D1->D1 3 - 3 + D2->D2 4 - 4 + D3->D3 5 - 5 + D4->D4 6 - 6 + D5->D5 7 - 7 + D6->D6 8 - 8 + D7->D7 9 - 9 + INIT -> ACK 16 - 10 + AUTOFD->PAPOUT 14 - 12 + SLCT->SLCTIN 13 - 17 + GND->ERROR 18 - 15 + extra grounds are 19*,20*,21*,22*,23*,24* + GROUND 25 - 25 +* Do not connect these pins on either end + +Once again, if the cable you are using has a metallic shield it should +be connected to the metallic DB-25 shell at one end only. + +PLIP Mode 0 transfer protocol +============================= + +The PLIP driver is compatible with the "Crynwr" parallel port transfer +standard in Mode 0. That standard specifies the following protocol: + + send header nibble '8' + count-low octet + count-high octet + ... data octets + checksum octet + +Each octet is sent as + + >4)&0x0F)> + +To start a transfer the transmitting machine outputs a nibble 0x08. +The raises the ACK line, triggering an interrupt in the receiving +machine. The receiving machine disables + +Restated: + +(OUT is bit 0-4, OUT.j is bit j from OUT. IN likewise) +Send_Byte: + OUT := low nibble, OUT.4 := 1 + WAIT FOR IN.4 = 1 + OUT := high nibble, OUT.4 := 0 + WAIT FOR IN.4 = 0 diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/README.cops linux/Documentation/networking/README.cops --- v2.1.66/linux/Documentation/networking/README.cops Thu Jun 26 12:33:36 1997 +++ linux/Documentation/networking/README.cops Wed Dec 31 16:00:00 1969 @@ -1,39 +0,0 @@ -README for the COPS LocalTalk Linux driver (cops.c). - By Jay Schulist - -This driver compiles well against 2.1.29 - 2.1.41. - -Building the driver from the cops-0.0*.tar.gz file. -1. Untar the cops-0.0*.tar.gz it will make a directory called cops. -2. Copy the cops-kernel.diff to /usr/src/ and then type patch -p0 < cops-kernel.diff -3. In the cops driver directory type make install. It will copy the driver to - the linux/drivers/net directory. -4. When you configure your kernel select Y or M for COPS LocalTalk PC support. - Also make sure you have choosen Appletalk support. -5. Compile like usual and you should bet set. - -This driver has 2 modes and they are: Dayna mode and Tangent mode. -Each mode corresponds with the type of card. It has been found -that there are 2 main types of cards and all other cards are -the same and just have different names or only have minor differences -such as more IO ports. As this driver is tested it will -become more clear on exactly what cards are supported. The driver -defaults to using Dayna mode. To change the drivers mode if you build -a driver with dual support use board_type=1 or board_type=2 for -dayna and tangent in the insmod. - -Operation/loading of the driver. -Use modprobe like this: /sbin/modprobe cops.o (IO #) (IRQ #) -If you do not specify any options the driver will try and use the IO = 0x240, -IRQ = 5. As of right now I would only use IRQ 5 for the card, if autoprobing. - -Use ifconfig like this: /sbin/ifconfig lt0 127.0.0.34 up - -You will need to configure atalkd with something like the following to make -it work with the cops.c driver. - -dummy -seed -phase 2 -net 2000 -addr 2000.10 -zone "1033" -lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033" -- Or - -eth0 -seed -phase 2 -net 3000 -addr 3000.20 -zone "1033" -lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033" diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/cops.txt linux/Documentation/networking/cops.txt --- v2.1.66/linux/Documentation/networking/cops.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/cops.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,63 @@ +Text File for the COPS LocalTalk Linux driver (cops.c). + By Jay Schulist + +This driver has teo modes and they are: Dayna mode and Tangent mode. +Each mode corresponds with the type of card. It has been found +that there are 2 main types of cards and all other cards are +the same and just have different names or only have minor differences +such as more IO ports. As this driver is tested it will +become more clear on exactly what cards are supported. + +Right now these cards are known to work with the COPS driver. The +LT-200 cards work in a somewhat more limited capacity than the +DL200 cards, which work very well and are in use by many people. + +TANGENT driver mode: + Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200 +DAYNA driver mode: + Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, + Farallon PhoneNET PC III, Farallon PhoneNET PC II +Other cards possibly supported mode unkown though: + Dayna DL2000 (Full length) + +The COPS driver defaults to using Dayna mode. To change the drivers +mode if you build a driver with a dual support use board_type=1 or +board_type=2 for Dayna or Tangent with insmod. + +** Operation/loading of the driver. +Use modprobe like this: /sbin/modprobe cops.o (IO #) (IRQ #) +If you do not specify any options the driver will try and use the IO = 0x240, +IRQ = 5. As of right now I would only use IRQ 5 for the card, if autoprobing. + +To load multiple COPS driver Localtalk cards you can do one of the following. + +insmod cops io=0x240 irq=5 +insmod -o cops2 cops io=0x260 irq=3 + +Or in lilo.conf put something like this: + append="ether=5,0x240,lt0 ether=3,0x260,lt1" + +Then bring up the interface with ifconfig. It will look something like this: +lt0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-F7-00-00-00-00-00-00-00-00 + inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0 + UP BROADCAST RUNNING NOARP MULTICAST MTU:600 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 coll:0 + +** Netatalk Configuration +You will need to configure atalkd with something like the following to make +it work with the cops.c driver. + +* For single LTalk card use. +dummy -seed -phase 2 -net 2000 -addr 2000.10 -zone "1033" +lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033" + +* For multiple cards, Ethernet and Localtalk. +eth0 -seed -phase 2 -net 3000 -addr 3000.20 -zone "1033" +lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033" + +* For multiple LocalTalk cards, and an Ethernet card. +* Order seems to matters here, Ethernet last. +lt0 -seed -phase 1 -net 1000 -addr 1000.10 -zone "LocalTalk1" +lt1 -seed -phase 1 -net 2000 -addr 2000.20 -zone "LocalTalk2" +eth0 -seed -phase 2 -net 3000 -addr 3000.30 -zone "EtherTalk" diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/de4x5.txt linux/Documentation/networking/de4x5.txt --- v2.1.66/linux/Documentation/networking/de4x5.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/de4x5.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,143 @@ + Originally, this driver was written for the Digital Equipment + Corporation series of EtherWORKS ethernet cards: + + DE425 TP/COAX EISA + DE434 TP PCI + DE435 TP/COAX/AUI PCI + DE450 TP/COAX/AUI PCI + DE500 10/100 PCI Fasternet + + but it will now attempt to support all cards which conform to the + Digital Semiconductor SROM Specification. The driver currently + recognises the following chips: + + DC21040 (no SROM) + DC21041[A] + DC21140[A] + DC21142 + DC21143 + + So far the driver is known to work with the following cards: + + KINGSTON + Linksys + ZNYX342 + SMC8432 + SMC9332 (w/new SROM) + ZNYX31[45] + ZNYX346 10/100 4 port (can act as a 10/100 bridge!) + + The driver has been tested on a relatively busy network using the DE425, + DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred + 16M of data to a DECstation 5000/200 as follows: + + TCP UDP + TX RX TX RX + DE425 1030k 997k 1170k 1128k + DE434 1063k 995k 1170k 1125k + DE435 1063k 995k 1170k 1125k + DE500 1063k 998k 1170k 1125k in 10Mb/s mode + + All values are typical (in kBytes/sec) from a sample of 4 for each + measurement. Their error is +/-20k on a quiet (private) network and also + depend on what load the CPU has. + + ========================================================================= + + The ability to load this driver as a loadable module has been included + and used extensively during the driver development (to save those long + reboot sequences). Loadable module support under PCI and EISA has been + achieved by letting the driver autoprobe as if it were compiled into the + kernel. Do make sure you're not sharing interrupts with anything that + cannot accommodate interrupt sharing! + + To utilise this ability, you have to do 8 things: + + 0) have a copy of the loadable modules code installed on your system. + 1) copy de4x5.c from the /linux/drivers/net directory to your favourite + temporary directory. + 2) for fixed autoprobes (not recommended), edit the source code near + line 5537 to reflect the I/O address you're using, or assign these when + loading by: + + insmod de4x5 io=0xghh where g = bus number + hh = device number + + NB: autoprobing for modules is now supported by default. You may just + use: + + insmod de4x5 + + to load all available boards. For a specific board, still use + the 'io=?' above. + 3) compile de4x5.c, but include -DMODULE in the command line to ensure + that the correct bits are compiled (see end of source code). + 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a + kernel with the de4x5 configuration turned off and reboot. + 5) insmod de4x5 [io=0xghh] + 6) run the net startup bits for your new eth?? interface(s) manually + (usually /etc/rc.inet[12] at boot time). + 7) enjoy! + + To unload a module, turn off the associated interface(s) + 'ifconfig eth?? down' then 'rmmod de4x5'. + + Automedia detection is included so that in principal you can disconnect + from, e.g. TP, reconnect to BNC and things will still work (after a + pause whilst the driver figures out where its media went). My tests + using ping showed that it appears to work.... + + By default, the driver will now autodetect any DECchip based card. + Should you have a need to restrict the driver to DIGITAL only cards, you + can compile with a DEC_ONLY define, or if loading as a module, use the + 'dec_only=1' parameter. + + The SMC9332 card has a non-compliant SROM which needs fixing - I have + patched this driver to detect it because the SROM format used complies + to a previous DEC-STD format. + + I have removed the buffer copies needed for receive on Intels. I cannot + remove them for Alphas since the Tulip hardware only does longword + aligned DMA transfers and the Alphas get alignment traps with non + longword aligned data copies (which makes them really slow). No comment. + + I have added SROM decoding routines to make this driver work with any + card that supports the Digital Semiconductor SROM spec. This will help + all cards running the dc2114x series chips in particular. Cards using + the dc2104x chips should run correctly with the basic driver. I'm in + debt to for the testing and feedback that helped get + this feature working. So far we have tested KINGSTON, SMC8432, SMC9332 + (with the latest SROM complying with the SROM spec V3: their first was + broken), ZNYX342 and LinkSys. ZYNX314 (dual 21041 MAC) and ZNYX 315 + (quad 21041 MAC) cards also appear to work despite their incorrectly + wired IRQs. + + I have added a temporary fix for interrupt problems when some SCSI cards + share the same interrupt as the DECchip based cards. The problem occurs + because the SCSI card wants to grab the interrupt as a fast interrupt + (runs the service routine with interrupts turned off) vs. this card + which really needs to run the service routine with interrupts turned on. + This driver will now add the interrupt service routine as a fast + interrupt if it is bounced from the slow interrupt. THIS IS NOT A + RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time + until people sort out their compatibility issues and the kernel + interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST + INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not + run on the same interrupt. PCMCIA/CardBus is another can of worms... + + Finally, I think I have really fixed the module loading problem with + more than one DECchip based card. As a side effect, I don't mess with + the device structure any more which means that if more than 1 card in + 2.0.x is installed (4 in 2.1.x), the user will have to edit + linux/drivers/net/Space.c to make room for them. Hence, module loading + is the preferred way to use this driver, since it doesn't have this + limitation. + + Where SROM media detection is used and full duplex is specified in the + SROM, the feature is ignored unless de4x5_full_duplex is set at compile + time OR during a module load (insmod de4x5 de4x5_full_duplex=1). This + is because there is no way to automatically detect full duplex links + except through autonegotiation. When I include the autonegotiation + feature in the SROM autoconf code, this detection will occur + automatically. + diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/dgrs.txt linux/Documentation/networking/dgrs.txt --- v2.1.66/linux/Documentation/networking/dgrs.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/dgrs.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,52 @@ + The Digi Intl. 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 +switches and a NIC combined into a single board. This driver can +be compiled into the kernel statically or as a loadable module. + +There is also a companion management tool, called "xrightswitch". +The management tool lets you watch the performance graphically, +as well as set the SNMP agent IP and IPX addresses, IEEE Spanning +Tree, and Aging time. These can also be set from the command line +when the driver is loaded. The driver command line options are: + + debug=NNN Debug printing level + dma=0/1 Disable/Enable DMA on PCI card + spantree=0/1 Disable/Enable IEEE spanning tree + hashexpire=NNN Change address aging time (default 300 seconds) + ipaddr=A,B,C,D Set SNMP agent IP address i.e. 199,86,8,221 + iptrap=A,B,C,D Set SNMP agent IP trap address i.e. 199,86,8,221 + ipxnet=NNN Set SNMP agent IPX network number + nicmode=0/1 Disable/Enable multiple NIC mode + +There is also a tool for setting up input and output packet filters +on each port, called "dgrsfilt". + +Both the management tool and the filtering tool are available +separately from the following FTP site: + + ftp://ftp.dgii.com/drivers/rightswitch/linux/ + +When nicmode=1, the board and driver operate as 4 or 6 individual +NIC ports (eth0...eth5) instead of as a switch. All switching +functions are disabled. In the future, the board firmware may include +a routing cache when in this mode. + +Copyright 1995-1996 Digi International Inc. + +This software may be used and distributed according to the terms +of the GNU General Public License, incorporated herein by reference. + +For information on purchasing a RightSwitch SE-4 or SE-6 +board, please contact Digi's sales department at 1-612-912-3444 +or 1-800-DIGIBRD. Outside the U.S., please check our Web page at: + + http://www.dgii.com + +for sales offices worldwide. Tech support is also available through +the channels listed on the Web site, although as long as I am +employed on networking products at Digi I will be happy to provide +any bug fixes that may be needed. + +-Rick Richardson, rick@dgii.com diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/eql.txt linux/Documentation/networking/eql.txt --- v2.1.66/linux/Documentation/networking/eql.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/eql.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,528 @@ + EQL Driver: Serial IP Load Balancing HOWTO + Simon "Guru Aleph-Null" Janes, simon@ncm.com + v1.1, February 27, 1995 + + This is the manual for the EQL device driver. EQL is a software device + that lets you load-balance IP serial links (SLIP or uncompressed PPP) + to increase your bandwidth. It will not reduce your latency (i.e. ping + times) except in the case where you already have lots of traffic on + your link, in which it will help them out. This driver has been tested + with the 1.1.75 kernel, and is known to have patched cleanly with + 1.1.86. Some testing with 1.1.92 has been done with the v1.1 patch + which was only created to patch cleanly in the very latest kernel + source trees. (Yes, it worked fine.) + + 1. Introduction + + Which is worse? A huge fee for a 56K leased line or two phone lines? + Its probably the former. If you find yourself craving more bandwidth, + and have a ISP that is flexible, it is now possible to bind modems + together to work as one point-to-point link to increase your + bandwidth. All without having to have a special black box on either + side. + + + The eql driver has only been tested with the Livingston PortMaster-2e + terminal server. I do not know if other terminal servers support load- + balancing, but I do know that the PortMaster does it, and does it + almost as well as the eql driver seems to do it (-- Unfortunately, in + my testing so far, the Livingston PortMaster 2e's load-balancing is a + good 1 to 2 KB/s slower than the test machine working with a 28.8 Kbps + and 14.4 Kbps connection. However, I am not sure that it really is + the PortMaster, or if it's Linux's TCP drivers. I'm told that Linux's + TCP implementation is pretty fast though.--) + + + I suggest to ISP's out there that it would probably be fair to charge + a load-balancing client 75% of the cost of the second line and 50% of + the cost of the third line etc... + + + Hey, we can all dream you know... + + + 2. Kernel Configuration + + Here I describe the general steps of getting a kernel up and working + with the eql driver. From patching, building, to installing. + + + 2.1. Patching The Kernel + + If you do not have or cannot get a copy of the kernel with the eql + driver folded into it, get your copy of the driver from + ftp://slaughter.ncm.com/pub/Linux/LOAD_BALANCING/eql-1.1.tar.gz. + Unpack this archive someplace obvious like /usr/local/src/. It will + create the following files: + + + + ______________________________________________________________________ + -rw-r--r-- guru/ncm 198 Jan 19 18:53 1995 eql-1.1/NO-WARRANTY + -rw-r--r-- guru/ncm 30620 Feb 27 21:40 1995 eql-1.1/eql-1.1.patch + -rwxr-xr-x guru/ncm 16111 Jan 12 22:29 1995 eql-1.1/eql_enslave + -rw-r--r-- guru/ncm 2195 Jan 10 21:48 1995 eql-1.1/eql_enslave.c + ______________________________________________________________________ + + Unpack a recent kernel (something after 1.1.92) Someplace convenient + like say /usr/src/linux-1.1.92.eql. Use symbolic links to point + /usr/src/linux to this development directory. + + + Apply the patch by running the commands: + + + ______________________________________________________________________ + cd /usr/src + patch + ". Here are some example enslavings: + + + + ______________________________________________________________________ + eql_enslave eql sl0 28800 + eql_enslave eql ppp0 14400 + eql_enslave eql sl1 57600 + ______________________________________________________________________ + + + + + + When you want to free a device from its life of slavery, you can + either down the device with ifconfig (eql will automatically bury the + dead slave and remove it from its queue) or use eql_emancipate to free + it. (-- Or just ifconfig it down, and the eql driver will take it out + for you.--) + + + + ______________________________________________________________________ + eql_emancipate eql sl0 + eql_emancipate eql ppp0 + eql_emancipate eql sl1 + ______________________________________________________________________ + + + + + + 3.3. DSLIP Configuration for the eql Device + + The general idea is to bring up and keep up as many SLIP connections + as you need, automatically. + + + 3.3.1. /etc/slip/runslip.conf + + Here is an example runslip.conf: + + + + + + + + + + + + + + + + ______________________________________________________________________ + name sl-line-1 + enabled + baud 38400 + mtu 576 + ducmd -e /etc/slip/dialout/cua2-288.xp -t 9 + command eql_enslave eql $interface 28800 + address 198.67.33.239 + line /dev/cua2 + + name sl-line-2 + enabled + baud 38400 + mtu 576 + ducmd -e /etc/slip/dialout/cua3-288.xp -t 9 + command eql_enslave eql $interface 28800 + address 198.67.33.239 + line /dev/cua3 + ______________________________________________________________________ + + + + + + 3.4. Using PPP and the eql Device + + I have not yet done any load-balancing testing for PPP devices, mainly + because I don't have a PPP-connection manager like SLIP has with + DSLIP. I did find a good tip from LinuxNET:Billy for PPP performance: + make sure you have asyncmap set to something so that control + characters are not escaped. + + + I tried to fix up a PPP script/system for redialing lost PPP + connections for use with the eql driver the weekend of Feb 25-26 '95 + (Hereafter known as the 8-hour PPP Hate Festival). Perhaps later this + year. + + + 4. About the Slave Scheduler Algorithm + + The slave scheduler probably could be replaced with a dozen other + things and push traffic much faster. The formula in the current set + up of the driver was tuned to handle slaves with wildly different + bits-per-second "priorities". + + + All testing I have done was with two 28.8 V.FC modems, one connecting + at 28800 bps or slower, and the other connecting at 14400 bps all the + time. + + + One version of the scheduler was able to push 5.3 K/s through the + 28800 and 14400 connections, but when the priorities on the links were + very wide apart (57600 vs. 14400) The "faster" modem received all + traffic and the "slower" modem starved. + + + 5. Tester's Reports + + Some people have experimented with the eql device with newer kernels + kernels (than 1.1.75). I have since updated the driver to patch + cleanly in newer kernels because of the removal of the old "slave- + balancing" driver config option. + + + o icee from LinuxNET patched 1.1.86 without any rejects and was able + to boot the kernel and enslave a couple of ISDN PPP links. + + 5.1. Randolph Bentson's Test Report + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bentson@grieg.seaslug.org Wed Feb 8 19:08:09 1995 + Date: Tue, 7 Feb 95 22:57 PST + From: Randolph Bentson + To: guru@ncm.com + Subject: EQL driver tests + + + I have been checking out your eql driver. (Nice work, that!) + Although you may already done this performance testing, here + are some data I've discovered. + + Randolph Bentson + bentson@grieg.seaslug.org + + --------------------------------------------------------- + + + A pseudo-device driver, EQL, written by Simon Janes, can be used + to bundle multiple SLIP connections into what appears to be a + single connection. This allows one to improve dial-up network + connectivity gradually, without having to buy expensive DSU/CSU + hardware and services. + + I have done some testing of this software, with two goals in + mind: first, to ensure it actually works as described and + second, as a method of exercising my device driver. + + The following performance measurements were derived from a set + of SLIP connections run between two Linux systems (1.1.84) using + a 486DX2/66 with a Cyclom-8Ys and a 486SLC/40 with a Cyclom-16Y. + (Ports 0,1,2,3 were used. A later configuration will distribute + port selection across the different Cirrus chips on the boards.) + Once a link was established, I timed a binary ftp transfer of + 289284 bytes of data. If there were no overhead (packet headers, + inter-character and inter-packet delays, etc.) the transfers + would take the following times: + + bits/sec seconds + 345600 8.3 + 234600 12.3 + 172800 16.7 + 153600 18.8 + 76800 37.6 + 57600 50.2 + 38400 75.3 + 28800 100.4 + 19200 150.6 + 9600 301.3 + + A single line running at the lower speeds and with large packets + comes to within 2% of this. Performance is limited for the higher + speeds (as predicted by the Cirrus databook) to an aggregate of + about 160 kbits/sec. The next round of testing will distribute + the load across two or more Cirrus chips. + + The good news is that one gets nearly the full advantage of the + second, third, and fourth line's bandwidth. (The bad news is + that the connection establishment seemed fragile for the higher + speeds. Once established, the connection seemed robust enough.) + + #lines speed mtu seconds theory actual %of + kbit/sec duration speed speed max + 3 115200 900 _ 345600 + 3 115200 400 18.1 345600 159825 46 + 2 115200 900 _ 230400 + 2 115200 600 18.1 230400 159825 69 + 2 115200 400 19.3 230400 149888 65 + 4 57600 900 _ 234600 + 4 57600 600 _ 234600 + 4 57600 400 _ 234600 + 3 57600 600 20.9 172800 138413 80 + 3 57600 900 21.2 172800 136455 78 + 3 115200 600 21.7 345600 133311 38 + 3 57600 400 22.5 172800 128571 74 + 4 38400 900 25.2 153600 114795 74 + 4 38400 600 26.4 153600 109577 71 + 4 38400 400 27.3 153600 105965 68 + 2 57600 900 29.1 115200 99410.3 86 + 1 115200 900 30.7 115200 94229.3 81 + 2 57600 600 30.2 115200 95789.4 83 + 3 38400 900 30.3 115200 95473.3 82 + 3 38400 600 31.2 115200 92719.2 80 + 1 115200 600 31.3 115200 92423 80 + 2 57600 400 32.3 115200 89561.6 77 + 1 115200 400 32.8 115200 88196.3 76 + 3 38400 400 33.5 115200 86353.4 74 + 2 38400 900 43.7 76800 66197.7 86 + 2 38400 600 44 76800 65746.4 85 + 2 38400 400 47.2 76800 61289 79 + 4 19200 900 50.8 76800 56945.7 74 + 4 19200 400 53.2 76800 54376.7 70 + 4 19200 600 53.7 76800 53870.4 70 + 1 57600 900 54.6 57600 52982.4 91 + 1 57600 600 56.2 57600 51474 89 + 3 19200 900 60.5 57600 47815.5 83 + 1 57600 400 60.2 57600 48053.8 83 + 3 19200 600 62 57600 46658.7 81 + 3 19200 400 64.7 57600 44711.6 77 + 1 38400 900 79.4 38400 36433.8 94 + 1 38400 600 82.4 38400 35107.3 91 + 2 19200 900 84.4 38400 34275.4 89 + 1 38400 400 86.8 38400 33327.6 86 + 2 19200 600 87.6 38400 33023.3 85 + 2 19200 400 91.2 38400 31719.7 82 + 4 9600 900 94.7 38400 30547.4 79 + 4 9600 400 106 38400 27290.9 71 + 4 9600 600 110 38400 26298.5 68 + 3 9600 900 118 28800 24515.6 85 + 3 9600 600 120 28800 24107 83 + 3 9600 400 131 28800 22082.7 76 + 1 19200 900 155 19200 18663.5 97 + 1 19200 600 161 19200 17968 93 + 1 19200 400 170 19200 17016.7 88 + 2 9600 600 176 19200 16436.6 85 + 2 9600 900 180 19200 16071.3 83 + 2 9600 400 181 19200 15982.5 83 + 1 9600 900 305 9600 9484.72 98 + 1 9600 600 314 9600 9212.87 95 + 1 9600 400 332 9600 8713.37 90 + + + + + + 5.2. Anthony Healy's Report + + + + + + + + Date: Mon, 13 Feb 1995 16:17:29 +1100 (EST) + From: Antony Healey + To: Simon Janes + Subject: Re: Load Balancing + + Hi Simon, + I've installed your patch and it works great. I have trialed + it over twin SL/IP lines, just over null modems, but I was + able to data at over 48Kb/s [ISDN link -Simon]. I managed a + transfer of upto 7.5 Kbyte/s on one go, but averaged around + 6.4 Kbyte/s, which I think is pretty cool. :) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/ethertap.txt linux/Documentation/networking/ethertap.txt --- v2.1.66/linux/Documentation/networking/ethertap.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/ethertap.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,88 @@ +Documentation on setup and use of EtherTap. + +Contact Jay Schulist if you +have questions or need futher assistance. + +Introduction +============ + +Ethertap provides packet reception and transmission for user +space programs. It can be viewed as a simple ethernet device, +which instead of recieving packets from a network wire, it recieves +them from user space. + +Ethertap can be used for anything from Appletalk to IPX to even +building bridging tunnels. It also has many other general purpose +uses. + +Ethertap also can do ARP for you. Although this is not enabled per +default. + +SetUp +===== + +First you will have to enable Ethertap in the kernel configuration. +Then you will need to create any number of ethertap device files, +/dev/tap0->/dev/tap15. This is done by the following command. + +mknod /dev/tap* c 36 16 ( 17 18 19 20 for tap1,2,3,4...) + +** Replace * with the proper tap device number you need. ** + +Now with your kernel that has ethertap enabled, you will need +to ifconfig /dev/tap* 192.168.1.1 (replace 192.168.1.1 with the +proper IP number for your situation.) + +If you want your Ethertap device to ARP for you would ifconfig +the interface like this: ifconfig tap* 192.168.1.1 arp + +Remember that the you need to have a corresponding /dev/tap* file +for each tap* device you need to ifconfig. + +Now Ethertap should be ready to use. + +Diagram of how Ethertap works. (Courtesy of Alan Cox) +==================================================== + +This is for a tunnel, but you should be able to +get the general idea. + + 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 + + +[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> macs + +The routing on our box would be + + ifconfig eth0 1.2.3.5 netmask 255.255.255.0 up + route add default gw 1.2.3.4 + ifconfig tap0 2.0.0.1 netmask 255.255.255.0 up arp + (route add 2.0.0.0 netmask 255.255.255.0) + +C code for a Simple program using an EtherTap device +==================================================== + +This code is just excepts from a real program, so some parts are missing +but the important stuff is below. + +void main (void) +{ + int TapDevice, eth_pkt_len = 0; + unsigned char full_pkt_len[MAX_PKT_LEN]; + + TapDevice = open("/dev/tap0", O_RDWR); + if(TapDevice < 0) + { + perror("Error opening device"); + exit(1); + } + + write(TapDevice, full_packet, eth_pkt_len); + + close(TapDevice); + + return; +} diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/ewrk3.txt linux/Documentation/networking/ewrk3.txt --- v2.1.66/linux/Documentation/networking/ewrk3.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/ewrk3.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,45 @@ +The EtherWORKS 3 driver in this distribution is designed to work with all +kernels > 1.1.33 (approx) and includes tools in the 'ewrk3tools' +subdirectory to allow set up of the card, similar to the MSDOS +'NICSETUP.EXE' tools provided on the DOS drivers disk (type 'make' in that +subdirectory to make the tools). + +The supported cards are DE203, DE204 and DE205. All other cards are NOT +supported - refer to 'depca.c' for running the LANCE based network cards and +'de4x5.c' for the DIGITAL Semiconductor PCI chip based adapters from +Digital. + +The ability to load this driver as a loadable module has been included and +used extensively during the driver development (to save those long reboot +sequences). To utilise this ability, you have to do 8 things: + + 0) have a copy of the loadable modules code installed on your system. + 1) copy ewrk3.c from the /linux/drivers/net directory to your favourite + temporary directory. + 2) edit the source code near line 1898 to reflect the I/O address and + IRQ you're using. + 3) compile ewrk3.c, but include -DMODULE in the command line to ensure + that the correct bits are compiled (see end of source code). + 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a + kernel with the ewrk3 configuration turned off and reboot. + 5) insmod ewrk3.o + [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y] + 6) run the net startup bits for your new eth?? interface manually + (usually /etc/rc.inet[12] at boot time). + 7) enjoy! + + Note that autoprobing is not allowed in loadable modules - the system is + already up and running and you're messing with interrupts. + + To unload a module, turn off the associated interface + 'ifconfig eth?? down' then 'rmmod ewrk3'. + +The performance we've achieved so far has been measured through the 'ttcp' +tool at 975kB/s. This measures the total tcp stack performance which +includes the card, so don't expect to get much nearer the 1.25MB/s +theoretical ethernet rate. + + +Enjoy! + +Dave diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.1.66/linux/Documentation/networking/ip-sysctl.txt Thu Sep 4 17:07:29 1997 +++ linux/Documentation/networking/ip-sysctl.txt Sat Nov 29 10:33:18 1997 @@ -143,10 +143,22 @@ tcp_max_syn_backlog - INTEGER Undocumented (work in progress) +ip_local_port_range - 2 INTEGERS + Defines the local port range that is used by TCP and UDP to + choose the local port. The first number is the first, the + second the last local port number. For high-usage systems + change this to 32768-61000. + +icmp_echo_ignore_all - BOOLEAN +icmp_echo_ignore_broadcasts - BOOLEAN + If either is set to true, then the kernel will ignore either all + ICMP ECHO requests sent to it or just those to broadcast/multicast + addresses, respectively. + Alexey Kuznetsov. kuznet@ms2.inr.ac.ru Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.3 1997/08/22 19:22:00 freitag Exp $ +$Id: ip-sysctl.txt,v 1.5 1997/10/17 03:58:23 tdyas Exp $ diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/ltpc.txt linux/Documentation/networking/ltpc.txt --- v2.1.66/linux/Documentation/networking/ltpc.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/ltpc.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,98 @@ +This is the ALPHA version of the ltpc driver. + +In order to use it, you will need at least version 1.3.3 of the +netatalk package, and the Apple or Farallon Localtalk PC card. +There are a number of different Localtalk cards for the PC; this +driver applies only to the one with the 65c02 processor chip on it. + +To include it in the kernel, select the CONFIG_LTPC switch in the +configuration dialog; at this time (kernel 2.1.23) compiling it as +a module will not work. + +Before starting up the netatalk demons (perhaps in rc.local), you +need to add a line such as: + +/sbin/ifconfig ltalk0 127.0.0.42 + + +The driver will autoprobe, and you should see a message like: +"LocalTalk card found at 240, IR9, DMA1." +at bootup. + +The appropriate netatalk configuration depends on whether you are +attached to a network that includes appletalk routers or not. If, +like me, you are simply connecting to your home Macintoshes and +printers, you need to set up netatalk to "seed". The way I do this +is to have the lines + +dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033" +ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033" + +in my atalkd.conf. What is going on here is that I need to fool +netatalk into thinking that there are two appletalk interfaces +present -- otherwise it refuses to seed. This is a hack, and a +more permanent solution would be to alter the netatalk code. +Note that the dummy driver needs to accept multicasts also -- earlier +versions of dummy.c may need to be patched. + + +If you are attached to an extended appletalk network, with routers on +it, then you don't need to fool around with this -- the appropriate +line in atalkd.conf is + +ltalk0 -phase 1 + +-------------------------------------- + +Card Configuration: + +The interrupts and so forth are configured via the dipswitch 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 + polled mode. Because the card was developed in the XT era, the + original documentation refers to IRQ2. Since you'll be running + this on an AT (or later) class machine, that really means IRQ9. + + SW1 IRQ 4 + SW2 IRQ 3 + SW3 IRQ 9 (2 in original card documentation only applies to XT) + + + DMA -- choose DMA 1 or 3, and set both corresponding switches. + + SW4 DMA 3 + SW5 DMA 1 + SW6 DMA 3 + SW7 DMA 1 + + + I/O address -- choose one. + + SW8 220 / 240 + +-------------------------------------- + +IP: + Many people are interested in this driver in order to use IP +when Localtalk, but no Ethernet, is available. While the code to do +this is not strictly speaking part of this driver, an experimental +version is available which seems to work under kernel 2.0.xx. It is +not yet functional in the 2.1.xx kernels. + +-------------------------------------- + +BUGS: + +2.0.xx: + +2.1.xx: The module support doesn't work yet. + +______________________________________ + +THANKS: + Thanks to Alan Cox for helpful discussions early on in this +work, and to Denis Hainsworth for doing the bleeding-edge testing. + +-- Bradford Johnson + diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/multicast.txt linux/Documentation/networking/multicast.txt --- v2.1.66/linux/Documentation/networking/multicast.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/multicast.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,57 @@ +Behaviour of cards under Multicast. This is how they currently +behave not what the hardware can do. In particular all the 8390 based +cards don't use the onboard hash filter, and the lance driver doesn't +use its filter, even though the code for loading it is in the DEC +lance based driver. + +The following multicast requirements are needed +----------------------------------------------- +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 + + +Board Multicast AllMulti Promisc Filter +------------------------------------------------------------------------ +3c501 YES YES YES Software +3c503 YES YES YES Hardware +3c505 YES NO YES Hardware +3c507 NO NO NO N/A +3c509 YES YES YES Software +3c59x YES YES YES Software +ac3200 YES YES YES Hardware +apricot YES PROMISC YES Hardware +arcnet NO NO NO N/A +at1700 PROMISC PROMISC YES Software +atp PROMISC PROMISC YES Software +cs89x0 YES YES YES Software +de4x5 YES YES YES Hardware +de600 NO NO NO N/A +de620 PROMISC PROMISC YES Software +depca YES PROMISC YES Hardware +e2100 YES YES YES Hardware +eepro YES PROMISC YES Hardware +eexpress NO NO NO N/A +ewrk3 YES PROMISC YES Hardware +hp-plus YES YES YES Hardware +hp YES YES YES Hardware +hp100 YES YES YES Hardware +ibmtr NO NO NO N/A +lance YES YES YES Software(#) +ne YES YES YES Hardware +ni52 <------------------ Buggy ------------------> +ni65 YES YES YES Software(#) +seeq NO NO NO N/A +sk_g16 NO NO YES N/A +smc-ultra YES YES YES Hardware +sunlance YES YES YES Hardware +tulip YES YES YES Hardware +wavelan YES PROMISC YES Hardware +wd YES YES YES Hardware +znet YES YES YES Software + + +PROMISC = This multicasts mode is in fact promiscuous mode. Avoid using +cards who go PROMISC on any multicast in a multicast kernel. +(#) = Hardware multicast support is not used yet. diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/pt.txt linux/Documentation/networking/pt.txt --- v2.1.66/linux/Documentation/networking/pt.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/pt.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,58 @@ +This is the README for the Gracilis Packetwin device driver, version 0.5 +ALPHA for Linux 1.3.43. + +These files will allow you to talk to the PackeTwin (now know as PT) and +connect through it just like a pair of TNC's. To do this you will also +require the AX.25 code in the kernel enabled. + +There are four files in this archive; this readme, a patch file, a .c file +and finally a .h file. The two program files need to be put into the +drivers/net directory in the Linux source tree, for me this is the +directory /usr/src/linux/drivers/net. The patch file needs to be patched in +at the top of the Linux source tree (/usr/src/linux in my case). + +You will most probably have to edit the pt.c file to suit your own setup, +this should just involve changing some of the defines at the top of the file. +Please note that if you run an external modem you must specify a speed of 0. + +The program is currently setup to run a 4800 baud external modem on port A +and a Kantronics DE-9600 daughter board on port B so if you have this (or +something similar) then you're right. + +To compile in the driver, put the files in the correct place and patch in +the diff. You will have to re-configure the kernel again before you +recompile it. + +The driver is not real good at the moment for finding the card. You can +'help' it by changing the order of the potential addresses in the structure +found in the pt_init() function so the address of where the card is is put +first. + +After compiling, you have to get them going, they are pretty well like any +other net device and just need ifconfig to get them going. +As an example, here is my /etc/rc.net +-------------------------- + +# +# Configure the PackeTwin, port A. +/sbin/ifconfig pt0a 44.136.8.87 hw ax25 vk2xlz mtu 512 +/sbin/ifconfig pt0a 44.136.8.87 broadcast 44.136.8.255 netmask 255.255.255.0 +/sbin/route add -net 44.136.8.0 netmask 255.255.255.0 dev pt0a +/sbin/route add -net 44.0.0.0 netmask 255.0.0.0 gw 44.136.8.68 dev pt0a +/sbin/route add -net 138.25.16.0 netmask 255.255.240.0 dev pt0a +/sbin/route add -host 44.136.8.255 dev pt0a +# +# Configure the PackeTwin, port B. +/sbin/ifconfig pt0b 44.136.8.87 hw ax25 vk2xlz-1 mtu 512 +/sbin/ifconfig pt0b 44.136.8.87 broadcast 44.255.255.255 netmask 255.0.0.0 +/sbin/route add -host 44.136.8.216 dev pt0b +/sbin/route add -host 44.136.8.95 dev pt0b +/sbin/route add -host 44.255.255.255 dev pt0b + +This version of the driver comes under the GNU GPL. If you have one on my +previous (non-GPL) versions of the driver, please update to this one. + +I hope that this all works well for you. I would be pleased to hear how +many people use the driver and if it does its job. + + - Craig vk2xlz diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/scc.txt linux/Documentation/networking/scc.txt --- v2.1.66/linux/Documentation/networking/scc.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/scc.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,23 @@ + +You will find subset of the documentation in + + linux/Documentation/networking/z8530drv.txt + +To use this driver you MUST have the full package from: + +Internet: +========= + +1. db0bm.automation.fh-aachen.de/incoming/dl1bke/z8530drv-utils-3.0.tar.gz + +2. ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz + If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz + +and various mirrors (i.e. nic.switch.ch) + +The package includes the utilities necessary to initialize and +control the driver. + +Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org + AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU + Internet: jreuter@lykos.oche.de diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/smc9.txt linux/Documentation/networking/smc9.txt --- v2.1.66/linux/Documentation/networking/smc9.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/smc9.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,42 @@ + +SMC 9xxxx Driver +Revision 0.12 +3/5/96 +Copyright 1996 Erik Stahlman +Released under terms of the GNU public license. + +This file contains the instructions and caveats for my SMC9xxx driver. You +should not be using the driver without reading this file. + +Things to note about installation: + + 1. The driver should work on all kernels from 1.2.13 until 1.3.71. + (A kernel patch is supplied for 1.3.71 ) + + 2. If you include this into the kernel, you might need to change some + options, such as for forcing IRQ. + + + 3. To compile as a module, run 'make' . + Make will give you the appropriate options for various kernel support. + + 4. Loading the driver as a module : + + use: insmod smc9194.o + optional parameters: + io=xxxx : your base address + irq=xx : your irq + ifport=x : 0 for whatever is default + 1 for twisted pair + 2 for AUI ( or BNC on some cards ) + +How to obtain the latest version? + +FTP: + ftp://fenris.campus.vt.edu/smc9/smc9-12.tar.gz + ftp://sfbox.vt.edu/filebox/F/fenris/smc9/smc9-12.tar.gz + + +Contacting me: + erik@mail.vt.edu + diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/wanpipe.txt linux/Documentation/networking/wanpipe.txt --- v2.1.66/linux/Documentation/networking/wanpipe.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/wanpipe.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,148 @@ +------------------------------------------------------------------------------ +WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router +------------------------------------------------------------------------------ +Release 3.1.0 +January 30, 1997 +Author: Gene Kozin +Copyright (c) 1995-1997 Sangoma Technologies Inc. +------------------------------------------------------------------------------ + +INTRODUCTION + +WANPIPE(tm) is a family of intelligent muliprotocol WAN communication adapters +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 variety of synchronous communications protocols, +including frame relay, PPP, X.25, SDLC, etc. + +WANPIPE driver together with Linux WAN Router module allows you to build +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 WAN Tools +package to be able to use Linux WAN Router and WANPIPE driver. The package +is available via the Internet from Sangoma Technologies' anonymous FTP server: + + ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz + +For technical questions and/or comments please e-mail to genek@compuserve.com. +For general inquiries please contact Sangoma Technologies Inc. by + + Hotline: 1-800-388-2475 (USA and Canada, toll free) + Phone: (905) 474-1990 + Fax: (905) 474-9223 + E-mail: dm@sangoma.com (David Mandelstam) + WWW: http://www.sangoma.com + + + +COPYRIGHT AND LICENSING INFORMATION + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; 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. + +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. + + + +NEW IN THIS RELEASE + + o Implemented as WAN Link Driver compliant with Linux WAN Router interface + o Added support for X.25 protocol + o Miscellaneous bug fixes and performance improvements + + + +FILE LIST + +drivers/net: + README.wanpipe This file + sdladrv.c SDLA support module source code + wpmain.c WANPIPE driver module main source code + wpx.c WANPIPE driver module X.25 source code + wpf.c WANPIPE driver module frame relay source code + wpp.c WANPIPE driver module PPP source code + 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 + +include/linux: + wanpipe.h WANPIPE API definitions + sdladrv.h SDLA support module API definitions + sdlasfm.h SDLA firmware module definitions + + + +REVISION HISTORY + +3.1.0 January 30, 1997 + + o Implemented IOCTL for executing adapter commands. + o Fixed a bug in frame relay code causing driver configured as a FR + switch to be stuck in WAN_DISCONNECTED mode. + +3.0.0 December 31, 1996 + + o Uses Linux WAN Router interface + o Added support for X.25 routing + o Miscellaneous bug fixes and performance improvements + +2.4.1 December 18, 1996 + + o Added support for LMI and Q.933 frame relay link management + +2.3.0 October 17, 1996 + + o All shell scripts use meta-configuration file + o Miscellaneous bug fixes + +2.2.0 July 16, 1996 + + o Compatible with Linux 2.0 + o Added uninstall script + o User's Manual is available in HTML format + +2.1.0 June 20, 1996 + + o Added support for synchronous PPP + o Added support for S503 adapter + o Added API for executing adapter commands + o Fixed a re-entrancy problem in frame relaty driver + o Changed interface between SDLA driver and protocol support modules + o Updated frame relay firmware + +2.0.0 May 1, 1996 + + o Added interactive installation and configuration scripts + o Added System V-style start-up script + o Added dynamic memory window address selection in SDLA driver + o Miscellaneous bug fixes in SDLA driver + o Updated S508 frame relay firmware + o Changed SFM file format + +1.0.0 February 12, 1996 + + o Final release + o Added support for Linux 1.3 + o Updated S508 frame relay firmware + +0.9.0 December 21, 1995 + + o Added SNAP encapsulation for routed frames + o Added support for the frame relay switch emulation mode + o Added support for S508 adapter + o Added capability to autodetect adapter type + o Miscellaneous bug fixes in SDLA and frame relay drivers + +0.1.0 October 12, 1995 + + o Initial version + +>>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + diff -u --recursive --new-file v2.1.66/linux/Documentation/networking/wavelan.txt linux/Documentation/networking/wavelan.txt --- v2.1.66/linux/Documentation/networking/wavelan.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/wavelan.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,33 @@ +Sun Jul 2 01:38:33 EST 1995 + +1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390. + The version of the card that I use (NCR) supports four I/O addresses (selectable + via a pair of DIP switches). If you want the driver to autoprobe a different + subset of the four valid addresses then you will need to edit + .../drivers/net/wavelan.c (near line 714) and change the initialisation of the + `iobase[]' array. Normally, I use a LILO configuration file directive to + obviate the need for autoprobing entirely, a course of action I heartily + recommend. + +2. By default, the driver uses the Network ID (NWID) stored in the card's Parameter + Storage Area (PSA). However, the PSA NWID can be overridden by a value passed + explicitly as the third numeric argument to LILO's "ether=" directive, either + at the LILO prompt at boot time or within LILO's configuration file. + For example, the following line from such a LILO configuration file would + auto-configure the IRQ value, set the I/O base to 0x390 and set the NWID to + 0x4321, all on a WaveLAN card labelled "eth0": + + .. + append ="ether=0,0x390,0x4321,eth0" + .. + +3. The driver uses the IRQ stored in the card's PSA. + To change this you will need to use the configuration/setup software that + accompanies each WaveLAN device. Yes, the driver should use the value passed + in via LILO and it will, just as soon as I can work out why that part of the + code doesn't work :-(. + +4. If you encounter any problems send me some email. + +Good luck, +Bruce Janson (bruce@cs.usyd.edu.au) diff -u --recursive --new-file v2.1.66/linux/Documentation/nfsroot.txt linux/Documentation/nfsroot.txt --- v2.1.66/linux/Documentation/nfsroot.txt Mon May 6 02:26:01 1996 +++ linux/Documentation/nfsroot.txt Sat Nov 29 10:33:18 1997 @@ -2,6 +2,7 @@ ============================================== Written 1996 by Gero Kuhlmann +Updated 1997 by Martin Mares @@ -47,12 +48,12 @@ nfsroot=[:][,] - If the nfsroot parameter is NOT give on the command line, the default + If the `nfsroot' parameter is NOT given on the command line, the default "/tftpboot/%s" will be used. Specifies the IP address of the NFS server. If this field is not given, the default address as determined by the - nfsaddrs variable (see below) is used. One use of this + `ip' variable (see below) is used. One use of this parameter is for example to allow using different servers for RARP and NFS. Usually you can leave this blank. @@ -76,10 +77,16 @@ flags = hard, nointr, noposix, cto, ac -nfsaddrs=:::::: +ip=:::::: - If this parameter is missing on the kernel command line, all fields are - assumed to be empty, and the below mentioned defaults apply. In general + This parameter tells the kernel how to configure IP addresses of devices + and also how to set up the IP routing table. It was originally called `nfsaddrs', + but now the boot-time IP configuration works independently on NFS, so it + was renamed to `ip' and the old name remained as an alias for compatibility + reasons. + + If this parameter is missing from the kernel command line, all fields are + assumed to be empty, and the defaults mentioned below apply. In general this means that the kernel tries to configure everything using both RARP and BOOTP (depending on what has been enabled during kernel confi- guration, and if both what protocol answer got in first). @@ -95,7 +102,7 @@ replies from the specified server are accepted. To use different RARP and NFS server, specify your RARP server here (or leave it blank), and specify your NFS server in - the nfsroot parameter (see above). If this entry is blank + the `nfsroot' parameter (see above). If this entry is blank the address of the server is used which answered the RARP or BOOTP request. @@ -105,29 +112,26 @@ value has been received by BOOTP. Netmask for local network interface. If this is empty, - the netmask is derived from the client IP address, un- - less a value has been received by BOOTP. + the netmask is derived from the client IP address assuming + classful addressing, unless overriden in BOOTP reply. Name of the client. If empty, the client IP address is used in ASCII-notation, or the value received by BOOTP. Name of network device to use. If this is empty, all - devices are used for RARP requests, and the first one - found for BOOTP. For NFS the device is used on which - either RARP or BOOTP replies have been received. If - you only have one device you can safely leave this blank. + devices are used for RARP and BOOTP requests, and the + first one we receive a reply on is configured. If you have + only one device, you can safely leave this blank. Method to use for autoconfiguration. If this is either - 'rarp' or 'bootp' the specified protocol is being used. + 'rarp' or 'bootp', the specified protocol is used. If the value is 'both' or empty, both protocols are used so far as they have been enabled during kernel configura- - tion. 'none' means no autoconfiguration. In this case you - have to specify all necessary values in the fields before. + tion. 'off' means no autoconfiguration. - The parameter can appear alone as the value to the nfsaddrs + The parameter can appear alone as the value to the `ip' parameter (without all the ':' characters before) in which case auto- - configuration is used. However, the 'none' value is not available in - that case. + configuration is used. @@ -196,9 +200,11 @@ 4.) Credits ------- - The nfsroot code in the kernel has been written by me, Gero Kuhlmann - , with the BOOTP code and a couple of bug fixes - contributed by Martin Mares . In order to write - the initial version of nfsroot I would like to thank Jens-Uwe Mager - for his help. + The nfsroot code in the kernel and the RARP support have been written + by Gero Kuhlmann . + + The rest of the IP layer autoconfiguration code has been written + by Martin Mares . + In order to write the initial version of nfsroot I would like to thank + Jens-Uwe Mager for his help. diff -u --recursive --new-file v2.1.66/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.1.66/linux/Documentation/parport.txt Tue Sep 23 16:48:46 1997 +++ linux/Documentation/parport.txt Sat Nov 29 10:33:18 1997 @@ -53,11 +53,9 @@ parport0: Printer, BJC-210 (Canon) -Additionally, if you use kerneld, you can add to /etc/conf.modules the -following lines, to have the probe happen automatically: +(If you are using kerneld and have configured parport_probe as a +module, this will just happen.) - post-install parport modprobe parport_probe - pre-remove parport modprobe -r parport_probe Parport, but not as modules =========================== @@ -71,6 +69,31 @@ You can have many `parport=...' statements, one for each port you want to add. Adding `parport=0' to the kernel command-line will disable parport support entirely. + +Files in /proc +============== + +If you have configured the /proc filesystem into your kernel, you will +see a new directory entry: /proc/parport. In there will be a +directory entry for each parallel port for which parport is +configured. In each of those directories are three files describing +that parallel port. For example: + +File: Contents: + +/proc/parport/0/devices A list of the device drivers using + that port. A "+" will appear by the + name of the device currently using the + port (it might not appear against any). + +/proc/parport/0/hardware Parallel port's base address, IRQ line + and DMA channel. + +/proc/parport/0/irq The IRQ that parport is using for that + port (as above). This is in a + separate file to allow you to alter it + by writing a new value in (IRQ number + or "none"). Device drivers ============== diff -u --recursive --new-file v2.1.66/linux/Documentation/powerpc/00-INDEX linux/Documentation/powerpc/00-INDEX --- v2.1.66/linux/Documentation/powerpc/00-INDEX Thu Sep 4 17:07:29 1997 +++ linux/Documentation/powerpc/00-INDEX Sat Nov 29 10:33:18 1997 @@ -7,3 +7,5 @@ - this file ppc_htab.txt - info about the Linux/PPC /proc/ppc_htab entry +sound.txt + - info on sound support under Linux/PPC diff -u --recursive --new-file v2.1.66/linux/Documentation/powerpc/ppc_htab.txt linux/Documentation/powerpc/ppc_htab.txt --- v2.1.66/linux/Documentation/powerpc/ppc_htab.txt Thu Sep 4 17:07:29 1997 +++ linux/Documentation/powerpc/ppc_htab.txt Sat Nov 29 10:33:18 1997 @@ -1,25 +1,47 @@ Information about /proc/ppc_htab ===================================================================== +This document and the related code was written by me (Cort Dougan), please +email me (cort@cs.nmt.edu) if you have questions, comments or corrections. + This entry in the proc directory is readable by all users but only writable by root. +The ppc_htab interface is a user level way of accessing the +performance monitoring registers as well as providing information +about the PTE hash table. 1. Reading Reading this file will give you information about the memory management hash table that serves as an extended tlb for page translation on the - powerpc. + powerpc. It will also give you information about performance measurement + specific to the cpu that you are using. - Explaination of the fields: + Explanation of the 604 Performance Monitoring Fields: + MMCR0 - the current value of the MMCR0 register + PMC1 + PMC2 - the value of the performance counters and a + description of what events they are counting + which are based on MMCR0 bit settings. + Explanation of the PTE Hash Table fields: Size - hash table size in Kb. Buckets - number of buckets in the table. - Addess - the virtual kernel address of the hash table base. + Address - the virtual kernel address of the hash table base. Entries - the number of ptes that can be stored in the hash table. User/Kernel - how many pte's are in use by the kernel or user at that time. Overflows - How many of the entries are in their secondary hash location. Percent full - ratio of free pte entries to in use entries. + Reloads - Count of how many hash table misses have occurred + that were fixed with a reload from the linux tables. + Should always be 0 on 603 based machines. + Non-error Misses - Count of how many hash table misses have occurred + that were completed with the creation of a pte in the linux + tables with a call to do_page_fault(). + Error Misses - Number of misses due to errors such as bad address + and permission violations. This includes kernel access of + bad user addresses that are fixed up by the trap handler. Note that calculation of the data displayed from /proc/ppc_htab takes a long time and spends a great deal of time in the kernel. It would @@ -30,21 +52,70 @@ 2. Writing - Writing to ppc_htab is not yet allowed. + Writing to the ppc_htab allows you to change the characteristics of + the powerpc PTE hash table and setup performance monitoring. + + Resizing the PTE hash table is not enabled right now due to many + complications with moving the hash table, rehashing the entries + and many many SMP issues that would have to be dealt with. Write options to ppc_htab: - To set the size of the hash table to 64Kb: - echo 'size 64' > /dev/ppc_htab + echo 'size 64' > /proc/ppc_htab The size must be a multiple of 64 and must be greater than or equal to 64. + - To turn off performance monitoring: + + echo 'off' > /proc/ppc_htab + + - To reset the counters without changing what they're counting: + + echo 'reset' > /proc/ppc_htab + + Note that counting will continue after the reset if it is enabled. + + - To count only events in user mode or only in kernel mode: + + echo 'user' > /proc/ppc_htab + ...or... + echo 'kernel' > /proc/ppc_htab + + Note that these two options are exclusive of one another and the + lack of either of these options counts user and kernel. + Using 'reset' and 'off' reset these flags. + + - The 604 has 2 performance counters which can each count events from + a specific set of events. These sets are disjoint so it is not + possible to count _any_ combination of 2 events. One event can + be counted by PMC1 and one by PMC2. + + To start counting a particular event use: + + echo 'event' > /proc/ppc_htab + and choose from these events: + PMC1 + ---- + 'ic miss' - instruction cache misses + 'dtlb' - data tlb misses (not hash table misses) + PMC2 + ---- + 'dc miss' - data cache misses + 'itlb' - instruction tlb misses (not hash table misses) + 'load miss time' - cycles to complete a load miss +3. Bugs + Doing a 'less' or 'more' on ppc_htab results in a segmentation violation. + I'm not sure of the cause but in the mean time 'cat' works adequately for + reading the file. + The PMC1 and PMC2 counters can overflow and give no indication of that + in /proc/ppc_htab. diff -u --recursive --new-file v2.1.66/linux/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt --- v2.1.66/linux/Documentation/powerpc/sound.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/powerpc/sound.txt Sat Nov 29 10:33:18 1997 @@ -0,0 +1,57 @@ + Information about PowerPC Sound support +===================================================================== + +Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +comments or corrections. + +This just covers sound on the PReP systems for now, and later will +contain information on the PowerMac's. + +Sound has been tested and is working with the PowerStack and IBM Power +Series onboard sound systems which are based on the cs4231(2) chip. +The sound options when doing the make config are a bit different from the +default, though. + +The I/O base, irq and dma lines that you enter during the make config +are ignored and are set when booting according to the machine type. +This is so that one binary can be used for Motorola and IBM machines +which use different values and isn't allowed by the driver, so things are +hacked together in such a way as to allow this information to be set +automatically on boot. + +1. PowerStack + + Enable support for "Crystal CS4232 based (PnP) cards". Although the + options you set are ignored and determined automatically on boot these + are included for information only: + + (830) CS4232 audio I/O base 530, 604, E80 or F40 + (10) CS4232 audio IRQ 5, 7, 9, 11, 12 or 15 + (6) CS4232 audio DMA 0, 1 or 3 + (7) CS4232 second (duplex) DMA 0, 1 or 3 + + This will allow simultaneous record and playback, as 2 different dma + channels are used. + + Midi is not supported since the cs4232 driver doesn't support midi yet. + +2. IBM machines + + I've only tested sound on the Power Personal Series of IBM workstations + so if you try it on others please let me know the result. + + Enable support for "Crystal CS4232 based (PnP) cards". Although the + options you set are ignored and determined automatically on boot these + are included for information only: + + (530) CS4232 audio I/O base 530, 604, E80 or F40 + (5) CS4232 audio IRQ 5, 7, 9, 11, 12 or 15 + (1) CS4232 audio DMA 0, 1 or 3 + (7) CS4232 second (duplex) DMA 0, 1 or 3 + (330) CS4232 MIDI I/O base 330, 370, 3B0 or 3F0 + (9) CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15 + + This setup does _NOT_ allow for recording yet. + + Midi is not supported since the cs4232 driver doesn't support midi yet. + diff -u --recursive --new-file v2.1.66/linux/Documentation/svga.txt linux/Documentation/svga.txt --- v2.1.66/linux/Documentation/svga.txt Thu May 15 16:48:01 1997 +++ linux/Documentation/svga.txt Sat Nov 29 10:33:18 1997 @@ -7,10 +7,7 @@ This small document describes the "Video Mode Selection" feature which allows to use various special video modes supported by the video BIOS. Due to usage of the BIOS, the selection is limited to the boot time (before the -kernel decompression starts and works only on 80X86 machines. - - IF YOU USE THIS FEATURE, I'LL BE MUCH PLEASED IF YOU SEND ME A MAIL -DESCRIBING YOUR EXPERIENCE WITH IT. BUG REPORTS ARE ALSO WELCOME. +kernel decompression starts) and works only on 80X86 machines. The video mode to be used is selected by a kernel parameter which can be specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..." diff -u --recursive --new-file v2.1.66/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.66/linux/MAINTAINERS Wed Nov 26 16:24:01 1997 +++ linux/MAINTAINERS Sat Nov 29 10:33:18 1997 @@ -70,6 +70,12 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +DISKQUOTA: +P: Marco van Wieringen +M: mvw@planets.elm.net +L: linux-kernel@vger.rutgers.edu +S: Maintained + 3C501 NETWORK DRIVER P: Alan Cox M: net-patches@lxorguk.ukuu.org.uk @@ -85,13 +91,13 @@ ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell -M: pjb27@cam.ac.uk +M: Philip.Blundell@pobox.com L: linux-net@vger.rutgers.edu S: Maintained 3C505 NETWORK DRIVER P: Philip Blundell -M: phil@tazenda.demon.co.uk +M: Philip.Blundell@pobox.com L: linux-net@vger.rutgers.edu S: Maintained @@ -167,6 +173,13 @@ L: linux-hams@vger.rutgers.edu S: Maintained +BAYCOM/HDLCDRV/SOUNDMODEM DRIVERS FOR AX.25 +P: Thomas Sailer +M: sailer@ife.ee.ethz.ch +L: linux-hams@vger.rutgers.edu +W: http://www.ife.ee.ethz.ch/~sailer/ham/ham.html +S: Maintained + BUSLOGIC SCSI DRIVER P: Leonard N. Zubkoff M: Leonard N. Zubkoff @@ -270,7 +283,7 @@ P: Jes Sorensen M: Jes.Sorensen@cern.ch W: http://www.clark.net/pub/lawrencc/linux/index.html -L: linux-m68k@phil.uni-sb.de +L: linux-m68k@lists.linux-m68k.org S: Maintained MODULE SUPPORT [GENERAL], KERNELD @@ -466,6 +479,14 @@ W: http://www.cage.curtin.edu.au/~campbell/parbus/ S: Maintained +PNP SUPPORT +P: Tom Lees +M: tom@lpsg.demon.co.uk +L: pnp-list@lpsg.demon.co.uk +L: pnp-list@redhat.com (maybe) +W: http://www.lpsg.demon.co.uk/pnp-linux.html +S: Maintained + LINUX FOR POWERPC (PREP) P: Cort Dougan M: cort@cs.nmt.edu @@ -499,6 +520,16 @@ P: H. Peter Anvin M: hpa@zytor.com L: linux-kernel@vger.rutgers.edu +S: Maintained + +JOYSTICK DRIVER +P: Vojtech Pavlik +M: vojtech@atrey.karlin.mff.cuni.cz +S: Maintained + +NETWORK BLOCK DEVICE +P: Pavel Machek +M: pavel@atrey.karlin.mff.cuni.cz S: Maintained REST: diff -u --recursive --new-file v2.1.66/linux/Makefile linux/Makefile --- v2.1.66/linux/Makefile Wed Nov 26 16:24:01 1997 +++ linux/Makefile Wed Nov 26 16:20:57 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 66 +SUBLEVEL = 67 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.66/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.66/linux/arch/i386/defconfig Wed Nov 26 16:24:01 1997 +++ linux/arch/i386/defconfig Sat Nov 29 10:50:11 1997 @@ -248,6 +248,9 @@ # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_PMS is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set # CONFIG_MISC_RADIO is not set diff -u --recursive --new-file v2.1.66/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.66/linux/arch/i386/kernel/i386_ksyms.c Mon Oct 20 10:36:52 1997 +++ linux/arch/i386/kernel/i386_ksyms.c Sat Nov 29 10:33:18 1997 @@ -15,6 +15,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -42,6 +43,11 @@ EXPORT_SYMBOL(__intel_bh_counter); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); +/* Delay loops */ +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__delay); +EXPORT_SYMBOL(__const_udelay); + #ifdef __SMP__ EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */ diff -u --recursive --new-file v2.1.66/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.1.66/linux/arch/i386/lib/Makefile Sun Jan 26 02:07:05 1997 +++ linux/arch/i386/lib/Makefile Sat Nov 29 10:33:18 1997 @@ -11,6 +11,6 @@ endif L_TARGET = lib.a -L_OBJS = checksum.o semaphore.o locks.o +L_OBJS = checksum.o semaphore.o locks.o delay.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.66/linux/arch/i386/lib/delay.c linux/arch/i386/lib/delay.c --- v2.1.66/linux/arch/i386/lib/delay.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/delay.c Sat Nov 29 10:33:18 1997 @@ -0,0 +1,45 @@ +/* + * Precise Delay Loops for i386 + * + * Copyright (C) 1993 Linus Torvalds + * Copyright (C) 1997 Martin Mares + * + * The __delay function must _NOT_ be inlined as its execution time + * depends wildly on alignment on many x86 processors. + */ + +#include +#include + +#ifdef __SMP__ +#include +#endif + +#ifdef __SMP__ +#define __udelay_val cpu_data[smp_processor_id()].udelay_val +#else +#define __udelay_val loops_per_sec +#endif + +void __delay(unsigned long loops) +{ + __asm__ __volatile__( + "1:\tdecl %0\n\tjns 1b" + :/* no outputs */ + :"a" (loops) + :"ax"); +} + +inline void __const_udelay(unsigned long xloops) +{ + __asm__("mull %0" + :"=d" (xloops) + :"a" (xloops),"0" (__udelay_val) + :"ax"); + __delay(xloops); +} + +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */ +} diff -u --recursive --new-file v2.1.66/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.1.66/linux/drivers/block/Config.in Wed Nov 12 13:34:25 1997 +++ linux/drivers/block/Config.in Sat Nov 29 10:33:18 1997 @@ -49,6 +49,7 @@ comment 'Additional Block Devices' tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +#tristate 'Network block device support' CONFIG_BLK_DEV_NBD bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR diff -u --recursive --new-file v2.1.66/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.1.66/linux/drivers/block/Makefile Wed Nov 12 13:34:25 1997 +++ linux/drivers/block/Makefile Sat Nov 29 10:33:18 1997 @@ -218,4 +218,12 @@ endif +ifeq ($(CONFIG_BLK_DEV_NBD),y) +L_OBJS += nbd.o +else + ifeq ($(CONFIG_BLK_DEV_NBD),m) + M_OBJS += nbd.o + endif +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.66/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.1.66/linux/drivers/block/nbd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/nbd.c Sat Nov 29 10:33:18 1997 @@ -0,0 +1,435 @@ +/* + * Network block device - make block devices work over TCP + * + * Note that you can not swap over this thing, yet. Seems to work but + * deadlocks sometimes - you can not swap over TCP in general. + * + * Copyright 1997 Pavel Machek + * + * (part of code stolen from loop.c) + * + * 97-3-25 compiled 0-th version, not yet tested it + * (it did not work, BTW) (later that day) HEY! it works! + * (bit later) hmm, not that much... 2:00am next day: + * yes, it works, but it gives something like 50kB/sec + * 97-4-01 complete rewrite to make it possible for many requests at + * once to be processed + * 97-4-11 Making protocol independent of endianity etc. + * 97-9-13 Cosmetic changes + * + * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall + * why not: would need verify_area and friends, would share yet another + * structure with userland + */ + +#define PARANOIA +#include +#define MAJOR_NR NBD_MAJOR +#include + +#include + +#include +#include +#include + +#include +#include + +static int nbd_blksizes[MAX_NBD] = {1024, 1024,}; +static int nbd_sizes[MAX_NBD] = {0x7fffffff, 0x7fffffff,}; + +static struct nbd_device nbd_dev[MAX_NBD]; + +#define DEBUG( s ) +/* #define DEBUG( s ) printk( s ) + */ + +#ifdef PARANOIA +static int requests_in; +static int requests_out; +#endif + +static int nbd_open(struct inode *inode, struct file *file) +{ + int dev; + + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev); + if (dev >= MAX_NBD) + return -ENODEV; + nbd_dev[dev].refcnt++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Send or receive packet. + */ +static +int nbd_xmit(int send, struct socket *sock, char *buf, int size) +{ + unsigned long oldfs; + int result; + struct msghdr msg; + struct iovec iov; + + oldfs = get_fs(); + set_fs(get_ds()); + do { + int save; + + iov.iov_base = buf; + iov.iov_len = size; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_namelen = 0; + msg.msg_flags = 0; + + save = current->blocked; + current->blocked = ~0UL; + if (send) + result = sock_sendmsg(sock, &msg, size); + else + result = sock_recvmsg(sock, &msg, size, 0); + current->blocked = save; + if (result <= 0) { +#ifdef PARANOIA + printk(KERN_ERR "NBD: %s - sock=%d at buf=%d, size=%d returned %d.\n", + send ? "send" : "receive", (int) sock, (int) buf, size, result); +#endif + break; + } + size -= result; + buf += result; + } while (size > 0); + set_fs(oldfs); + return result; +} + +#define FAIL( s ) { printk( KERN_ERR "NBD: " s "(result %d)\n", result ); goto error_out; } + +void nbd_send_req(struct socket *sock, struct request *req) +{ + int result; + struct nbd_request request; + + DEBUG("NBD: sending control, "); + request.magic = htonl(NBD_REQUEST_MAGIC); + request.type = htonl(req->cmd); + request.from = htonl(req->sector * 512); + request.len = htonl(req->current_nr_sectors << 9); + memcpy(request.handle, &req, sizeof(req)); + + result = nbd_xmit(1, sock, (char *) &request, sizeof(request)); + if (result <= 0) + FAIL("Sendmsg failed for control."); + + if (req->cmd == WRITE) { + DEBUG("data, "); + result = nbd_xmit(1, sock, req->buffer, req->current_nr_sectors << 9); + if (result <= 0) + FAIL("Send data failed."); + } + return; + + error_out: + req->errors++; +} + +#define HARDFAIL( s ) { printk( KERN_ERR "NBD: " s "(result %d)\n", result ); lo->harderror = result; return NULL; } +struct request * /* NULL returned = something went wrong, inform userspace */ + nbd_read_stat(struct nbd_device *lo) +{ + int result; + struct nbd_reply reply; + struct request *xreq, *req; + + DEBUG("reading control, "); + reply.magic = 0; + result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply)); + req = lo->tail; + if (result <= 0) + HARDFAIL("Recv control failed."); + memcpy(&xreq, reply.handle, sizeof(xreq)); + + if (xreq != req) + FAIL("Unexpected handle received.\n"); + + DEBUG("ok, "); + if (ntohl(reply.magic) != NBD_REPLY_MAGIC) + HARDFAIL("Not enough magic."); + if (ntohl(reply.error)) + FAIL("Other side returned error."); + if (req->cmd == READ) { + DEBUG("data, "); + result = nbd_xmit(0, lo->sock, req->buffer, req->current_nr_sectors << 9); + if (result <= 0) + HARDFAIL("Recv data failed."); + } + DEBUG("done.\n"); + return req; + +/* Can we get here? Yes, if other side returns error */ + error_out: + req->errors++; + return req; +} + +void nbd_do_it(struct nbd_device *lo) +{ + struct request *req; + + while (1) { + req = nbd_read_stat(lo); + if (!req) + return; +#ifdef PARANOIA + if (req != lo->tail) { + printk(KERN_ALERT "NBD: I have problem...\n"); + } + if (lo != &nbd_dev[MINOR(req->rq_dev)]) { + printk(KERN_ALERT "NBD: request corrupted!\n"); + continue; + } + if (lo->magic != LO_MAGIC) { + printk(KERN_ALERT "NBD: nbd_dev[] corrupted: Not enough magic\n"); + return; + } +#endif + nbd_end_request(req); + if (lo->tail == lo->head) { +#ifdef PARANOIA + if (lo->tail->next) + printk(KERN_ERR "NBD: I did not expect this\n"); +#endif + lo->head = NULL; + } + lo->tail = lo->tail->next; + } +} + +void nbd_clear_que(struct nbd_device *lo) +{ + struct request *req; + + while (1) { + req = lo->tail; + if (!req) + return; +#ifdef PARANOIA + if (lo != &nbd_dev[MINOR(req->rq_dev)]) { + printk(KERN_ALERT "NBD: request corrupted when clearing!\n"); + continue; + } + if (lo->magic != LO_MAGIC) { + printk(KERN_ERR "NBD: nbd_dev[] corrupted: Not enough magic when clearing!\n"); + return; + } +#endif + req->errors++; + nbd_end_request(req); + if (lo->tail == lo->head) { +#ifdef PARANOIA + if (lo->tail->next) + printk(KERN_ERR "NBD: I did not assume this\n"); +#endif + lo->head = NULL; + } + lo->tail = lo->tail->next; + } +} + +/* + * We always wait for result of write, for now. It would be nice to make it optional + * in future + * if ((req->cmd == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) + * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } + */ + +#undef FAIL +#define FAIL( s ) { printk( KERN_ERR "NBD, minor %d: " s "\n", dev ); goto error_out; } + +static void do_nbd_request(void) +{ + struct request *req; + int dev; + struct nbd_device *lo; + + while (CURRENT) { + req = CURRENT; + dev = MINOR(req->rq_dev); +#ifdef PARANOIA + if (dev >= MAX_NBD) + FAIL("Minor too big."); /* Probably can not happen */ +#endif + lo = &nbd_dev[dev]; + if (!lo->file) + FAIL("Request when not-ready."); + if ((req->cmd == WRITE) && (lo->flags && NBD_READ_ONLY)) + FAIL("Write on read-only"); +#ifdef PARANOIA + if (lo->magic != LO_MAGIC) + FAIL("nbd[] is not magical!"); + requests_in++; +#endif + req->errors = 0; + + nbd_send_req(lo->sock, req); /* Why does this block? */ + CURRENT = CURRENT->next; + req->next = NULL; + if (lo->head == NULL) { + lo->head = req; + lo->tail = req; + } else { + lo->head->next = req; + lo->head = req; + } + continue; + + error_out: + req->errors++; + nbd_end_request(req); + CURRENT = CURRENT->next; + } + return; +} + +static int nbd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct nbd_device *lo; + int dev; + + if (!suser()) + return -EPERM; + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev); + if (dev >= MAX_NBD) + return -ENODEV; + lo = &nbd_dev[dev]; + switch (cmd) { + case NBD_CLEAR_SOCK: + if (lo->head || lo->tail) { + printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n"); + return -EBUSY; + } + if (!lo->file) + return -EINVAL; + lo->file->f_count--; + lo->file = NULL; + lo->sock = NULL; + return 0; + case NBD_SET_SOCK: + file = current->files->fd[arg]; + inode = file->f_dentry->d_inode; + file->f_count++; + lo->sock = &inode->u.socket_i; + lo->file = file; + return 0; + case NBD_SET_BLKSIZE: + if ((arg & 511) || (arg > PAGE_SIZE)) + return -EINVAL; + nbd_blksizes[dev] = arg; + return 0; + case NBD_SET_SIZE: + nbd_sizes[dev] = arg; + return 0; + case NBD_DO_IT: + if (!lo->file) + return -EINVAL; + nbd_do_it(lo); + return lo->harderror; + case NBD_CLEAR_QUE: + nbd_clear_que(lo); + return 0; +#ifdef PARANOIA + case NBD_PRINT_DEBUG: + printk(KERN_INFO "NBD device %d: head = %x, tail = %x. Global: in %d, out %d\n", + dev, (int) lo->head, (int) lo->tail, requests_in, requests_out); + return 0; +#endif + } + return -EINVAL; +} + +static int nbd_release(struct inode *inode, struct file *file) +{ + struct nbd_device *lo; + int dev; + + if (!inode) + return -ENODEV; + dev = MINOR(inode->i_rdev); + if (dev >= MAX_NBD) + return -ENODEV; + fsync_dev(inode->i_rdev); + lo = &nbd_dev[dev]; + if (lo->refcnt <= 0) + printk(KERN_ALERT "nbd_release: refcount(%d) <= 0\n", lo->refcnt); + lo->refcnt--; + MOD_DEC_USE_COUNT; + return 0; +} + +static struct file_operations nbd_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + nbd_ioctl, /* ioctl */ + NULL, /* mmap */ + nbd_open, /* open */ + nbd_release /* release */ +}; + +/* + * And here should be modules and kernel interface + * (Just smiley confuses emacs :-) + */ + +#ifdef MODULE +#define nbd_init init_module +#endif + +int nbd_init(void) +{ + int i; + + if (register_blkdev(MAJOR_NR, "nbd", &nbd_fops)) { + printk("Unable to get major number %d for NBD\n", + MAJOR_NR); + return -EIO; + } +#ifdef MODULE + printk("nbd: registered device at major %d\n", MAJOR_NR); +#endif + blksize_size[MAJOR_NR] = nbd_blksizes; + blk_size[MAJOR_NR] = nbd_sizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + for (i = 0; i < MAX_NBD; i++) { + nbd_dev[i].refcnt = 0; + nbd_dev[i].file = NULL; + nbd_dev[i].magic = LO_MAGIC; + nbd_dev[i].flags = 0; + } + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + if (unregister_blkdev(MAJOR_NR, "nbd") != 0) + printk("nbd: cleanup_module failed\n"); + else + printk("nbd: module cleaned up.\n"); +} +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.1.66/linux/drivers/block/xd.c Tue May 13 22:41:05 1997 +++ linux/drivers/block/xd.c Sat Nov 29 10:33:18 1997 @@ -20,6 +20,13 @@ * * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu * + * Revised: 13/09/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl + * Fixed some problems with disk initialization and module initiation. + * Added support for manual geometry setting (except Seagate controllers) + * in form: + * xd_geo=,,[,,,] + * Recovered DMA access. Abridged messages. Added support for DTC5051CX & + * WD1002-27X controllers. Added alternate jumper geometry setting. */ #include @@ -28,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +50,13 @@ #include "xd.h" +#define XD_DONT_USE_DMA 0 /* Initial value. may be overriden using + "nodma" module option */ +#define XD_INIT_DISK_DELAY 3 /* 30 ms delay during disk initialization */ + +/* Above may need to be increased if a problem with the 2nd drive detection + (ST11M controller) or resetting a controler (WD) appears */ + XD_INFO xd_info[XD_MAXDRIVES]; /* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS @@ -68,27 +83,47 @@ NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */ -static XD_SIGNATURE xd_sigs[] = { +#include +/* coppied from floppy.c */ +static inline int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} +#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size)) +#define xd_dma_mem_free(addr, size) free_pages(addr, __get_order(size)) +static char *xd_dma_buffer = 0; + +static XD_SIGNATURE xd_sigs[] __initdata = { { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */ + { 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */ { 0x000B,"CRD18A Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */ { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, pat@it.com.au */ - { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */ - { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */ - { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */ + { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Dig. 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */ + { 0x0008,"07/15/86(C) Copyright 1986 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. 1002-27X" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */ + { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Dig. 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */ + { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */ { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */ { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */ { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */ { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */ }; -static unsigned int xd_bases[] = +static unsigned int xd_bases[] __initdata = { 0xC8000, 0xCA000, 0xCC000, 0xCE000, 0xD0000, 0xD8000, 0xE0000 }; -static struct hd_struct xd[XD_MAXDRIVES << 6]; +static struct hd_struct xd_struct[XD_MAXDRIVES << 6]; static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES] = { 0, 0 }; static int xd_blocksizes[XD_MAXDRIVES << 6]; static struct gendisk xd_gendisk = { @@ -102,7 +137,7 @@ #else xd_geninit, /* init function */ #endif - xd, /* hd struct */ + xd_struct, /* hd struct */ xd_sizes, /* block sizes */ 0, /* number */ (void *) xd_info, /* internal */ @@ -122,15 +157,26 @@ }; static struct wait_queue *xd_wait_int = NULL, *xd_wait_open = NULL; static u_char xd_valid[XD_MAXDRIVES] = { 0,0 }; -static u_char xd_drives = 0, xd_irq = 0, xd_dma = 0, xd_maxsectors; -static u_char xd_override = 0, xd_type = 0; -static u_short xd_iobase = 0; +static u_char xd_drives = 0, xd_irq = 5, xd_dma = 3, xd_maxsectors; +static u_char xd_override __initdata = 0, xd_type = 0; +static u_short xd_iobase = 0x320; +static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0,0,0,0,0,0 }; + +static volatile int xdc_busy = 0; +static struct wait_queue *xdc_wait = NULL; + +typedef void (*timeout_fn)(unsigned long); +static struct timer_list xd_timer = { NULL, NULL, 0, 0, (timeout_fn) xd_wakeup }, + xd_watchdog_int = { NULL, NULL, 0, 0, (timeout_fn) xd_watchdog }; + +static volatile u_char xd_error; +static int nodma = XD_DONT_USE_DMA; /* xd_init: register the block device number and set up pointer tables */ __initfunc(int xd_init (void)) { if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) { - printk("xd_init: unable to get major number %d\n",MAJOR_NR); + printk("xd: Unable to get major number %d\n",MAJOR_NR); return -1; } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; @@ -172,27 +218,29 @@ if (xd_detect(&controller,&address)) { - printk("xd_geninit: detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address); + printk("Detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address); if (controller) xd_sigs[controller].init_controller(address); xd_drives = xd_initdrives(xd_sigs[controller].init_drive); - printk("xd_geninit: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma); + printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma); for (i = 0; i < xd_drives; i++) - printk("xd_geninit: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors); + printk(" xd%c: CHS=%d/%d/%d\n",'a'+i,xd_info[i].cylinders,xd_info[i].heads,xd_info[i].sectors); + } + if (xd_drives) { if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT harddisk", NULL)) { if (request_dma(xd_dma,"xd")) { - printk("xd_geninit: unable to get DMA%d\n",xd_dma); + printk("xd: unable to get DMA%d\n",xd_dma); free_irq(xd_irq, NULL); } } else - printk("xd_geninit: unable to get IRQ%d\n",xd_irq); + printk("xd: unable to get IRQ%d\n",xd_irq); } for (i = 0; i < xd_drives; i++) { - xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors; + xd_struct[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors; xd_valid[i] = 1; } @@ -211,6 +259,10 @@ while (!xd_valid[dev]) sleep_on(&xd_wait_open); +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif /* MODULE */ + xd_access[dev]++; return (0); @@ -226,13 +278,15 @@ int code; sti(); + if (xdc_busy) + return; while (code = 0, CURRENT) { INIT_REQUEST; /* do some checking on the request structure */ if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors - <= xd[MINOR(CURRENT->rq_dev)].nr_sects) { - block = CURRENT->sector + xd[MINOR(CURRENT->rq_dev)].start_sect; + <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) { + block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect; count = CURRENT->nr_sectors; switch (CURRENT->cmd) { @@ -242,7 +296,8 @@ code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count); break; default: - printk("do_xd_request: unknown request\n"); break; + printk("do_xd_request: unknown request\n"); + break; } } end_request(code); /* wrap up, 0 = fail, 1 = success */ @@ -262,15 +317,14 @@ switch (cmd) { case HDIO_GETGEO: { + struct hd_geometry g; struct hd_geometry *geometry = (struct hd_geometry *) arg; if (!geometry) return -EINVAL; - if(put_user(xd_info[dev].heads, (char *) &geometry->heads) - || put_user(xd_info[dev].sectors, (char *) &geometry->sectors) - || put_user(xd_info[dev].cylinders, (short *) &geometry->cylinders) - || put_user(xd[MINOR(inode->i_rdev)].start_sect, - (unsigned long *) &geometry->start)) - return -EFAULT; - return 0; + g.heads = xd_info[dev].heads; + g.sectors = xd_info[dev].sectors; + g.cylinders = xd_info[dev].cylinders; + g.start = xd_struct[MINOR(inode->i_rdev)].start_sect; + return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case BLKRASET: if(!suser()) return -EACCES; @@ -279,8 +333,7 @@ return 0; case BLKGETSIZE: if (!arg) return -EINVAL; - put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg); - return 0; + return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg); case BLKFLSBUF: /* Return devices size */ if(!suser()) return -EACCES; fsync_dev(inode->i_rdev); @@ -303,6 +356,11 @@ if (target < xd_drives) { sync_dev(inode->i_rdev); xd_access[target]--; + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif /* MODULE */ + } return 0; } @@ -326,8 +384,11 @@ for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { int minor = (start | partition); kdev_t devp = MKDEV(MAJOR_NR, minor); + struct super_block * sb = get_super(devp); + sync_dev(devp); - invalidate_inodes(devp); + if (sb) + invalidate_inodes(sb); invalidate_buffers(devp); xd_gendisk.part[minor].start_sect = 0; xd_gendisk.part[minor].nr_sects = 0; @@ -347,13 +408,17 @@ { u_char cmdblk[6],sense[4]; u_short track,cylinder; - u_char head,sector,control,mode,temp; + u_char head,sector,control,mode = PIO_MODE,temp; + char **real_buffer; + register int i; #ifdef DEBUG_READWRITE printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count); #endif /* DEBUG_READWRITE */ control = xd_info[drive].control; + if (!xd_dma_buffer) + xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); while (count) { temp = count < xd_maxsectors ? count : xd_maxsectors; @@ -366,27 +431,47 @@ printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp); #endif /* DEBUG_READWRITE */ - mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200); + if (xd_dma_buffer) { + mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200); + real_buffer = &xd_dma_buffer; + for (i=0; i < (temp * 0x200); i++) + xd_dma_buffer[i] = buffer[i]; + } + else + real_buffer = &buffer; + xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control); - switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) { + switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) { case 1: - printk("xd_readwrite: timeout, recalibrating drive\n"); + printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write")); xd_recalibrate(drive); return (0); case 2: - switch ((sense[0] & 0x30) >> 4) { - case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break; - case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break; - case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break; - case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break; + if (sense[0] & 0x30) { + printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing")); + switch ((sense[0] & 0x30) >> 4) { + case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F); + break; + case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F); + break; + case 2: printk("command error, code = 0x%X",sense[0] & 0x0F); + break; + case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F); + break; + } } if (sense[0] & 0x80) - printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F); + printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F); + /* reported drive number = (sense[1] & 0xE0) >> 5 */ else printk(" - no valid disk address\n"); return (0); } + if (xd_dma_buffer) + for (i=0; i < (temp * 0x200); i++) + buffer[i] = xd_dma_buffer[i]; + count -= temp, buffer += temp * 0x200, block += temp; } return (1); @@ -399,7 +484,7 @@ xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0); if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) - printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n"); + printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive); } /* xd_interrupt_handler: interrupt service routine */ @@ -413,31 +498,27 @@ wake_up(&xd_wait_int); /* and wake up sleeping processes */ } else - printk("xd_interrupt_handler: unexpected interrupt\n"); + printk("xd: unexpected interrupt\n"); } -/* xd_dma: set up the DMA controller for a data transfer */ +/* xd_setup_dma: set up the DMA controller for a data transfer */ static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count) { - if (buffer < ((u_char *) 0x1000000 - count)) { /* transfer to address < 16M? */ - if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) { + if (nodma) + return (PIO_MODE); + if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) { #ifdef DEBUG_OTHER - printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n"); + printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n"); #endif /* DEBUG_OTHER */ - return (PIO_MODE); - } - disable_dma(xd_dma); - clear_dma_ff(xd_dma); - set_dma_mode(xd_dma,mode); - set_dma_addr(xd_dma,(u_int) buffer); - set_dma_count(xd_dma,count); - - return (DMA_MODE); /* use DMA and INT */ + return (PIO_MODE); } -#ifdef DEBUG_OTHER - printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n"); -#endif /* DEBUG_OTHER */ - return (PIO_MODE); + disable_dma(xd_dma); + clear_dma_ff(xd_dma); + set_dma_mode(xd_dma,mode); + set_dma_addr(xd_dma,(u_int) buffer); + set_dma_count(xd_dma,count); + + return (DMA_MODE); /* use DMA and INT */ } /* xd_build: put stuff into an array in a format suitable for the controller */ @@ -453,15 +534,53 @@ return (cmdblk); } +/* xd_wakeup is called from timer interrupt */ +static void xd_wakeup (void) +{ + wake_up(&xdc_wait); +} + +/* xd_wakeup is called from timer interrupt */ +static void xd_watchdog (void) +{ + xd_error = 1; + wake_up(&xd_wait_int); +} + /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */ static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout) { u_long expiry = jiffies + timeout; + int success; - while (((inb(port) & mask) != flags) && (jiffies < expiry)) - ; - - return (jiffies >= expiry); + xdc_busy = 1; + while ((success = ((inb(port) & mask) != flags)) && (jiffies < expiry)) { + xd_timer.expires = jiffies; + cli(); + add_timer(&xd_timer); + sleep_on(&xdc_wait); + del_timer(&xd_timer); + sti(); + } + xdc_busy = 0; + return (success); +} + +static inline u_int xd_wait_for_IRQ (void) +{ + xd_watchdog_int.expires = jiffies + 8 * HZ; + add_timer(&xd_watchdog_int); + enable_dma(xd_dma); + sleep_on(&xd_wait_int); + del_timer(&xd_watchdog_int); + xdc_busy = 0; + disable_dma(xd_dma); + if (xd_error) { + printk("xd: missed IRQ - command aborted\n"); + xd_error = 0; + return (1); + } + return (0); } /* xd_command: handle all data transfers necessary for a single command */ @@ -478,24 +597,23 @@ if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout)) return (1); - + while (!complete) { if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout)) return (1); + switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) { case 0: if (mode == DMA_MODE) { - enable_dma(xd_dma); - sleep_on(&xd_wait_int); - disable_dma(xd_dma); + if (xd_wait_for_IRQ()) + return (1); } else outb(outdata ? *outdata++ : 0,XD_DATA); break; case STAT_INPUT: if (mode == DMA_MODE) { - enable_dma(xd_dma); - sleep_on(&xd_wait_int); - disable_dma(xd_dma); + if (xd_wait_for_IRQ()) + return (1); } else if (indata) *indata++ = inb(XD_DATA); @@ -518,7 +636,7 @@ if (csb & CSB_ERROR) { /* read sense data if error */ xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0); if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT)) - printk("xd_command: warning! sense command failed!\n"); + printk("xd: warning! sense command failed!\n"); } #ifdef DEBUG_COMMAND @@ -535,28 +653,92 @@ for (i = 0; i < XD_MAXDRIVES; i++) { xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0); if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) { + xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; + add_timer(&xd_timer); + sleep_on(&xdc_wait); + init_drive(count); count++; + + xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; + add_timer(&xd_timer); + sleep_on(&xdc_wait); } } return (count); } +__initfunc(static void xd_manual_geo_set (u_char drive)) +{ + xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]); + xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]); + xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]); +} + __initfunc(static void xd_dtc_init_controller (unsigned int address)) { switch (address) { - case 0xC8000: xd_iobase = 0x320; break; + case 0x00000: + case 0xC8000: break; /*initial: 0x320 */ case 0xCA000: xd_iobase = 0x324; break; + case 0xD0000: /*5150CX*/ + case 0xD8000: break; /*5150CX*/ default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address); - xd_iobase = 0x320; break; + break; } - xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */ - xd_dma = 3; xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */ outb(0,XD_RESET); /* reset the controller */ } + +__initfunc(static void xd_dtc5150cx_init_drive (u_char drive)) +{ + /* values from controller's BIOS - BIOS chip may be removed */ + static u_short geometry_table[][4] = { + {0x200,8,0x200,0x100}, + {0x267,2,0x267,0x267}, + {0x264,4,0x264,0x80}, + {0x132,4,0x132,0x0}, + {0x132,2,0x80, 0x132}, + {0x177,8,0x177,0x0}, + {0x132,8,0x84, 0x0}, + {}, /* not used */ + {0x132,6,0x80, 0x100}, + {0x200,6,0x100,0x100}, + {0x264,2,0x264,0x80}, + {0x280,4,0x280,0x100}, + {0x2B9,3,0x2B9,0x2B9}, + {0x2B9,5,0x2B9,0x2B9}, + {0x280,6,0x280,0x100}, + {0x132,4,0x132,0x0}}; + u_char n; + + n = inb(XD_JUMPER); + n = (drive ? n : (n >> 2)) & 0x33; + n = (n | (n >> 2)) & 0x0F; + if (xd_geo[3*drive]) + xd_manual_geo_set(drive); + else + if (n != 7) { + xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */ + xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */ + xd_info[drive].sectors = 17; /* sectors */ +#if 0 + xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */ + xd_info[drive].precomp = geometry_table[n][3] /* write precomp */ + xd_info[drive].ecc = 0x0B; /* ecc length */ +#endif /* 0 */ + } + else { + printk("xd%c: undetermined drive geometry\n",'a'+drive); + return; + } + xd_info[drive].control = 5; /* control byte */ + xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B); + xd_recalibrate(drive); +} + __initfunc(static void xd_dtc_init_drive (u_char drive)) { u_char cmdblk[6],buf[64]; @@ -566,6 +748,8 @@ xd_info[drive].heads = buf[0x0A]; /* heads */ xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ + if (xd_geo[3*drive]) + xd_manual_geo_set(drive); #if 0 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */ xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */ @@ -576,65 +760,128 @@ xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]); xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7); if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) - printk("xd_dtc_init_drive: error setting step rate for drive %d\n",drive); + printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive); } else - printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive); + printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive); } __initfunc(static void xd_wd_init_controller (unsigned int address)) { switch (address) { - case 0xC8000: xd_iobase = 0x320; break; + case 0x00000: + case 0xC8000: break; /*initial: 0x320 */ case 0xCA000: xd_iobase = 0x324; break; case 0xCC000: xd_iobase = 0x328; break; case 0xCE000: xd_iobase = 0x32C; break; - case 0xD0000: xd_iobase = 0x328; break; - case 0xD8000: xd_iobase = 0x32C; break; + case 0xD0000: xd_iobase = 0x328; break; /* ? */ + case 0xD8000: xd_iobase = 0x32C; break; /* ? */ default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address); - xd_iobase = 0x320; break; + break; } - xd_irq = 5; /* don't know how to auto-detect this yet */ - xd_dma = 3; xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */ - /* outb(0,XD_RESET); */ /* reset the controller */ + outb(0,XD_RESET); /* reset the controller */ + + xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; + add_timer(&xd_timer); + sleep_on(&xdc_wait); } __initfunc(static void xd_wd_init_drive (u_char drive)) { - u_char cmdblk[6],buf[0x200]; + /* values from controller's BIOS - BIOS may be disabled */ + static u_short geometry_table[][4] = { + {0x264,4,0x1C2,0x1C2}, /* common part */ + {0x132,4,0x099,0x0}, + {0x267,2,0x1C2,0x1C2}, + {0x267,4,0x1C2,0x1C2}, + + {0x334,6,0x335,0x335}, /* 1004 series RLL */ + {0x30E,4,0x30F,0x3DC}, + {0x30E,2,0x30F,0x30F}, + {0x267,4,0x268,0x268}, + + {0x3D5,5,0x3D6,0x3D6}, /* 1002 series RLL */ + {0x3DB,7,0x3DC,0x3DC}, + {0x264,4,0x265,0x265}, + {0x267,4,0x268,0x268}}; + u_char cmdblk[6],buf[0x200]; + u_char n = 0,rll,jumper_state,use_jumper_geo; + u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6'); + + jumper_state = ~(inb(0x322)); + if (jumper_state & 0x40) + xd_irq = 9; + rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0; xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0); if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { xd_info[drive].heads = buf[0x1AF]; /* heads */ xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ + if (xd_geo[3*drive]) + xd_manual_geo_set(drive); #if 0 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */ xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */ xd_info[drive].ecc = buf[0x1B4]; /* ecc length */ #endif /* 0 */ xd_info[drive].control = buf[0x1B5]; /* control byte */ - - xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]); + use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders); + if (xd_geo[3*drive]) { + xd_manual_geo_set(drive); + xd_info[drive].control = rll ? 7 : 5; + } + else if (use_jumper_geo) { + n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll; + xd_info[drive].cylinders = geometry_table[n][0]; + xd_info[drive].heads = (u_char)(geometry_table[n][1]); + xd_info[drive].control = rll ? 7 : 5; +#if 0 + xd_info[drive].rwrite = geometry_table[n][2]; + xd_info[drive].wprecomp = geometry_table[n][3]; + xd_info[drive].ecc = 0x0B; +#endif /* 0 */ + } + if (!wd_1002) + if (use_jumper_geo) + xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders, + geometry_table[n][2],geometry_table[n][3],0x0B); + else + xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders, + ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]); + /* 1002 based RLL controler requests converted adressing, but reports physical + (physical 26 sec., logical 17 sec.) + 1004 based ???? */ + if (rll & wd_1002) { + if ((xd_info[drive].cylinders *= 26, + xd_info[drive].cylinders /= 17) > 1023) + xd_info[drive].cylinders = 1023; /* 1024 ? */ +#if 0 + xd_info[drive].rwrite *= 26; + xd_info[drive].rwrite /= 17; + xd_info[drive].wprecomp *= 26 + xd_info[drive].wprecomp /= 17; +#endif /* 0 */ + } } else - printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive); + printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive); + } __initfunc(static void xd_seagate_init_controller (unsigned int address)) { switch (address) { - case 0xC8000: xd_iobase = 0x320; break; + case 0x00000: + case 0xC8000: break; /*initial: 0x320 */ case 0xD0000: xd_iobase = 0x324; break; case 0xD8000: xd_iobase = 0x328; break; case 0xE0000: xd_iobase = 0x32C; break; default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address); - xd_iobase = 0x320; break; + break; } - xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */ - xd_dma = 3; xd_maxsectors = 0x40; outb(0,XD_RESET); /* reset the controller */ @@ -652,23 +899,22 @@ xd_info[drive].control = 0; /* control byte */ } else - printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive); + printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive); } /* Omti support courtesy Dirk Melchers */ __initfunc(static void xd_omti_init_controller (unsigned int address)) { switch (address) { - case 0xC8000: xd_iobase = 0x320; break; + case 0x00000: + case 0xC8000: break; /*initial: 0x320 */ case 0xD0000: xd_iobase = 0x324; break; case 0xD8000: xd_iobase = 0x328; break; case 0xE0000: xd_iobase = 0x32C; break; default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address); - xd_iobase = 0x320; break; + break; } - xd_irq = 5; /* the IRQ and DMA channel are fixed on the Omti controllers */ - xd_dma = 3; xd_maxsectors = 0x40; outb(0,XD_RESET); /* reset the controller */ @@ -690,36 +936,63 @@ u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 }; u_char cmdblk[6],i; - for (i = 0; i < 3; i++) { - while (min[i] != max[i] - 1) { - test[i] = (min[i] + max[i]) / 2; - xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0); - if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) - min[i] = test[i]; - else - max[i] = test[i]; + if (xd_geo[3*drive]) + xd_manual_geo_set(drive); + else { + for (i = 0; i < 3; i++) { + while (min[i] != max[i] - 1) { + test[i] = (min[i] + max[i]) / 2; + xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0); + if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) + min[i] = test[i]; + else + max[i] = test[i]; + } + test[i] = min[i]; } - test[i] = min[i]; + xd_info[drive].heads = (u_char) min[0] + 1; + xd_info[drive].cylinders = (u_short) min[1] + 1; + xd_info[drive].sectors = (u_char) min[2] + 1; } - xd_info[drive].heads = (u_char) min[0] + 1; - xd_info[drive].cylinders = (u_short) min[1] + 1; - xd_info[drive].sectors = (u_char) min[2] + 1; xd_info[drive].control = 0; } -/* xd_setup: initialise from command line parameters */ +/* xd_setup: initialise controler from command line parameters */ __initfunc(void xd_setup (char *command,int *integers)) { - xd_override = 1; - - xd_type = integers[1]; - xd_irq = integers[2]; - xd_iobase = integers[3]; - xd_dma = integers[4]; - + switch (integers[0]) { + case 4: if (integers[4] < 0) + nodma = 1; + else if (integers[4] < 8) + xd_dma = integers[4]; + case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC)) + xd_iobase = integers[3]; + case 2: if ((integers[2] > 0) && (integers[2] < 16)) + xd_irq = integers[2]; + case 1: xd_override = 1; + if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0])))) + xd_type = integers[1]; + case 0: break; + default:printk("xd: too many parameters for xd\n"); + } xd_maxsectors = 0x01; } +#ifndef MODULE +/* xd_manual_geo_init: initialise drive geometry from command line parameters + (used only for WD drives) */ +__initfunc(void xd_manual_geo_init (char *command,int *integers)) +{ + int i; + if (integers[0]%3 != 0) { + printk("xd: incorrect number of parameters for xd_geo\n"); + return; + } + for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++) + xd_geo[i] = integers[i+1]; +} +#endif /* MODULE */ + /* xd_setparam: set the drive characteristics */ __initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)) { @@ -736,18 +1009,37 @@ cmdblk[13] = ecc; if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) - printk("xd_setparam: error setting characteristics for drive %d\n",drive); + printk("xd: error setting characteristics for xd%c\n", 'a'+drive); } #ifdef MODULE +static int xd[5] = { -1,-1,-1,-1, }; + +MODULE_PARM(xd, "1-4i"); +MODULE_PARM(xd_geo, "3-6i"); +MODULE_PARM(nodma, "i"); + int init_module(void) { + int i,count = 0; int error = xd_init(); if (!error) { printk(KERN_INFO "XD: Loaded as a module.\n"); + for (i = 4; i > 0; i--) + if(((xd[i] = xd[i-1]) >= 0) && !count) + count = i; + if((xd[0] = count)); + xd_setup(NULL, xd); xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 }); + if (!xd_drives) { + /* no drives detected - unload module */ + unregister_blkdev(MAJOR_NR, "xd"); + return (-1); + } + for (i = 0; i < xd_drives; i++) + resetup_one_dev(&xd_gendisk, i); } return error; @@ -756,8 +1048,12 @@ void cleanup_module(void) { unregister_blkdev(MAJOR_NR, "xd"); - free_irq(xd_irq, NULL); - free_dma(xd_dma); + if (xd_drives) { + free_irq(xd_irq, NULL); + free_dma(xd_dma); + if (xd_dma_buffer) + xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); + } } #endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/block/xd.h linux/drivers/block/xd.h --- v2.1.66/linux/drivers/block/xd.h Sun Apr 13 10:18:20 1997 +++ linux/drivers/block/xd.h Sat Nov 29 10:33:18 1997 @@ -35,7 +35,7 @@ #define CMD_SEEK 0x0B /* seek */ /* Controller specific commands */ -#define CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X only?) */ +#define CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X & CX only?) */ #define CMD_DTCGETECC 0x0D /* get ecc error length (DTC 5150X only?) */ #define CMD_DTCREADBUF 0x0E /* read sector buffer (DTC 5150X only?) */ #define CMD_DTCWRITEBUF 0x0F /* write sector buffer (DTC 5150X only?) */ @@ -85,8 +85,6 @@ u_char control; } XD_INFO; -#define HDIO_GETGEO 0x0301 /* get drive geometry */ - /* this structure is returned to the HDIO_GETGEO ioctl */ typedef struct { __u8 heads; @@ -105,6 +103,9 @@ } XD_SIGNATURE; void xd_setup (char *command,int *integers); +#ifndef MODULE +void xd_manual_geo_init (char *command,int *integers); +#endif /* MODULE */ static u_char xd_detect (u_char *controller, unsigned int *address); static u_char xd_initdrives (void (*init_drive)(u_char drive)); static void xd_geninit (struct gendisk *); @@ -120,11 +121,14 @@ static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs); static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count); static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control); +static void xd_wakeup (void); +static void xd_watchdog (void); static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout); static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout); /* card specific setup and geometry gathering code */ static void xd_dtc_init_controller (unsigned int address); +static void xd_dtc5150cx_init_drive (u_char drive); static void xd_dtc_init_drive (u_char drive); static void xd_wd_init_controller (unsigned int address); static void xd_wd_init_drive (u_char drive); diff -u --recursive --new-file v2.1.66/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.66/linux/drivers/char/Config.in Wed Nov 26 16:24:01 1997 +++ linux/drivers/char/Config.in Sat Nov 29 10:33:19 1997 @@ -99,9 +99,13 @@ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT fi bool 'Enhanced Real Time Clock Support' CONFIG_RTC -if [ "$CONFIG_PPC" = "y" ]; then +if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi +tristate 'Video For Linux' CONFIG_VIDEO_DEV +dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV +#dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV +dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV tristate '/dev/nvram support' CONFIG_NVRAM tristate 'PC joystick support' CONFIG_JOYSTICK bool 'Radio Device Support' CONFIG_MISC_RADIO diff -u --recursive --new-file v2.1.66/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.66/linux/drivers/char/Makefile Wed Nov 26 16:24:01 1997 +++ linux/drivers/char/Makefile Sat Nov 29 10:33:19 1997 @@ -273,11 +273,47 @@ ifeq ($(CONFIG_NVRAM),y) M = y -L_OBJS += nvram.o + ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),) + L_OBJS += nvram.o + endif else ifeq ($(CONFIG_NVRAM),m) MM = m + ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),) M_OBJS += nvram.o + endif + endif +endif + +ifeq ($(CONFIG_VIDEO_DEV),y) +LX_OBJS += videodev.o +else + ifeq ($(CONFIG_VIDEO_DEV),m) + MX_OBJS += videodev.o + endif +endif + +ifeq ($(CONFIG_VIDEO_BT848),y) +L_OBJS += bttv.o +else + ifeq ($(CONFIG_VIDEO_BT848),m) + M_OBJS += bttv.o + endif +endif + +ifeq ($(CONFIG_VIDEO_BWQCAM),y) +L_OBJS += bw-qcam.o +else + ifeq ($(CONFIG_VIDEO_BWQCAM),m) + M_OBJS += bw-qcam.o + endif +endif + +ifeq ($(CONFIG_VIDEO_PMS),y) +L_OBJS += pms.o +else + ifeq ($(CONFIG_VIDEO_PMS),m) + M_OBJS += pms.o endif endif diff -u --recursive --new-file v2.1.66/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.1.66/linux/drivers/char/acquirewdt.c Sun Sep 7 13:10:42 1997 +++ linux/drivers/char/acquirewdt.c Sat Nov 29 10:33:19 1997 @@ -62,7 +62,7 @@ inb_p(WDT_START); } -static long acq_write(struct inode *inode, struct file *file, const char *buf, unsigned long count) +static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { if(count) { @@ -72,7 +72,7 @@ return 0; } -static long acq_read(struct inode *inode, struct file *file, char *buf, unsigned long count) +static ssize_t acq_read(struct file *file, char *buf, size_t count, loff_t *ppos) { return -EINVAL; } diff -u --recursive --new-file v2.1.66/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v2.1.66/linux/drivers/char/apm_bios.c Wed Sep 24 20:05:46 1997 +++ linux/drivers/char/apm_bios.c Sat Nov 29 10:33:19 1997 @@ -63,8 +63,8 @@ #include #include -#include +#include #include #include #include @@ -307,7 +307,7 @@ static int do_open(struct inode *, struct file *); static int do_release(struct inode *, struct file *); -static long do_read(struct inode *, struct file *, char *, unsigned long); +static ssize_t do_read(struct file *, char *, size_t , loff_t *); static unsigned int do_poll(struct file *, poll_table *); static int do_ioctl(struct inode *, struct file *, u_int, u_long); @@ -812,8 +812,7 @@ return 0; } -static long do_read(struct inode *inode, struct file *fp, - char *buf, unsigned long count) +static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) { struct apm_bios_struct * as; int i; diff -u --recursive --new-file v2.1.66/linux/drivers/char/bt848.h linux/drivers/char/bt848.h --- v2.1.66/linux/drivers/char/bt848.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/bt848.h Sat Nov 29 10:33:19 1997 @@ -0,0 +1,319 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif + +#define RISCMEM_LEN 131040 + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1<<12) +#define BT848_RISC_BYTE1 (1<<13) +#define BT848_RISC_BYTE2 (1<<14) +#define BT848_RISC_BYTE3 (1<<15) +#define BT848_RISC_BYTE_ALL (0x0f<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1<<27) + +#define BT848_RISC_WRITE (0x01<<28) +#define BT848_RISC_SKIP (0x02<<28) +#define BT848_RISC_WRITEC (0x05<<28) +#define BT848_RISC_JUMP (0x07<<28) +#define BT848_RISC_SYNC (0x08<<28) + +#define BT848_RISC_WRITE123 (0x09<<28) +#define BT848_RISC_SKIP123 (0x0a<<28) +#define BT848_RISC_WRITE1S23 (0x0b<<28) + +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.66/linux/drivers/char/bttv.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/bttv.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,2005 @@ +/* + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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. + + Modified to put the RISC code writer in the kernel and to fit a + common (and I hope safe) kernel interface. When we have an X extension + all will now be really sweet. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bttv.h" +#include "tuner.h" + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ + +static unsigned int remap=0; +static unsigned int vidmem=0; +static unsigned int tuner=0; /* Default tuner */ + +static int find_vga(void); +static void bt848_set_risc_jmps(struct bttv *btv); + +/* Anybody who uses more than four? */ +#define BTTV_MAX 4 + +static int bttv_num; +static struct bttv bttvs[BTTV_MAX]; + +#define I2C_TIMING (0x7<<4) +#define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA) + +#define AUDIO_MUTE_DELAY 10000 +#define FREQ_CHANGE_DELAY 20000 +#define EEPROM_WRITE_DELAY 20000 + + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +/* convert virtual user memory address to physical address */ +/* (virt_to_phys only works for kmalloced kernel memory) */ + +static inline ulong uvirt_to_phys(ulong adr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + +/* printk("adr: 0x%08x\n",adr);*/ + pgd = pgd_offset(current->mm, adr); +/* printk("pgd: 0x%08x\n",pgd);*/ + if (pgd_none(*pgd)) + return 0; + pmd = pmd_offset(pgd, adr); +/* printk("pmd: 0x%08x\n",pmd); */ + if (pmd_none(*pmd)) + return 0; + ptep = pte_offset(pmd, adr&(~PGDIR_MASK)); + pte = *ptep; + if(pte_present(pte)) + return (pte_page(pte)|(adr&(PAGE_SIZE-1))); + return 0; +} + +/* convert virtual kernel memory address to physical address */ +/* (virt_to_phys only works for kmalloced kernel memory) */ + +static inline ulong kvirt_to_phys(ulong adr) +{ + return uvirt_to_phys(VMALLOC_VMADDR(adr)); +} + +static inline ulong kvirt_to_bus(ulong adr) +{ + return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); +} + + +/*****************/ +/* I2C functions */ +/*****************/ + +static int I2CRead(struct bttv *btv, int addr) +{ + u32 i; + u32 stat; + + /* clear status bit ; BT848_INT_RACK is ro */ + btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); + + btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C); + + for (i=0x7fffffff; i; i--) + { + stat=btread(BT848_INT_STAT); + if (stat & BT848_INT_I2CDONE) + break; + } + + if (!i) + return -1; + if (!(stat & BT848_INT_RACK)) + return -2; + + i=(btread(BT848_I2C)>>8)&0xff; + return i; +} + +/* set both to write both bytes, reset it to write only b1 */ + +static int I2CWrite(struct bttv *btv, unchar addr, unchar b1, + unchar b2, int both) +{ + u32 i; + u32 data; + u32 stat; + + /* clear status bit; BT848_INT_RACK is ro */ + btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); + + data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | I2C_COMMAND; + if (both) + { + data|=((b2 & 0xff) << 8); + data|=BT848_I2C_W3B; + } + + btwrite(data, BT848_I2C); + + for (i=0x7fffffff; i; i--) + { + stat=btread(BT848_INT_STAT); + if (stat & BT848_INT_I2CDONE) + break; + } + + if (!i) + return -1; + if (!(stat & BT848_INT_RACK)) + return -2; + + return 0; +} + +static void readee(struct bttv *btv, unchar *eedata) +{ + int i, k; + + if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) + { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + + for (i=0; i<256; i++) + { + k=I2CRead(btv, 0xa1); + if (k<0) + { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + eedata[i]=k; + } +} + +static void writeee(struct bttv *btv, unchar *eedata) +{ + int i; + + for (i=0; i<256; i++) + { + if (I2CWrite(btv, 0xa0, i, eedata[i], 1)<0) + { + printk(KERN_WARNING "bttv: writeee error (%d)\n", i); + break; + } + udelay(EEPROM_WRITE_DELAY); + } +} + +/* + * Tuner, internal, external and mute + */ + +static unchar audiomuxs[][4] = +{ + { 0x00, 0x00, 0x00, 0x00}, /* unknown */ + { 0x02, 0x00, 0x00, 0x0a}, /* MIRO */ + { 0x00, 0x02, 0x03, 0x04}, /* Hauppauge */ + { 0x04, 0x02, 0x03, 0x01}, /* STB */ + { 0x01, 0x02, 0x03, 0x04}, /* Intel??? */ + { 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000??? */ +}; + +static void audio(struct bttv *btv, int mode) +{ + btwrite(0x0f, BT848_GPIO_OUT_EN); + btwrite(0x00, BT848_GPIO_REG_INP); + + switch (mode) + { + case AUDIO_UNMUTE: + btv->audio&=~AUDIO_MUTE; + mode=btv->audio; + break; + case AUDIO_OFF: + mode=AUDIO_OFF; + break; + case AUDIO_ON: + mode=btv->audio; + break; + default: + btv->audio&=AUDIO_MUTE; + btv->audio|=mode; + break; + } + if ((btv->audio&AUDIO_MUTE) || !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) + mode=AUDIO_OFF; + btaor(audiomuxs[btv->type][mode] , ~0x0f, BT848_GPIO_DATA); +} + + +extern inline void bt848_dma(struct bttv *btv, uint state) +{ + if (state) + btor(3, BT848_GPIO_DMA_CTL); + else + btand(~3, BT848_GPIO_DMA_CTL); +} + + +static void bt848_cap(struct bttv *btv, uint state) +{ + if (state) + { + btv->cap|=3; + bt848_set_risc_jmps(btv); + } + else + { + btv->cap&=~3; + bt848_set_risc_jmps(btv); + } +} + +static void bt848_muxsel(struct bttv *btv, uint input) +{ + input&=3; + + /* This seems to get rid of some synchronization problems */ + btand(~(3<<5), BT848_IFORM); + udelay(10000); + + if (input==3) + { + btor(BT848_CONTROL_COMP, BT848_E_CONTROL); + btor(BT848_CONTROL_COMP, BT848_O_CONTROL); + } + else + { + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + } + if (input==2) + input=3; + btaor(((input+2)&3)<<5, ~(3<<5), BT848_IFORM); + audio(btv, input ? AUDIO_EXTERN : AUDIO_TUNER); +} + + +#define VBIBUF_SIZE 65536 + +static void make_vbitab(struct bttv *btv) +{ + int i; + dword *po=(dword *) btv->vbi_odd; + dword *pe=(dword *) btv->vbi_even; + + DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd)); + DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even)); + DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); + + *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0; + for (i=0; i<16; i++) + { + *(po++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL|(13<<20); + *(po++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048); + } + *(po++)=BT848_RISC_JUMP; + *(po++)=virt_to_bus(btv->risc_jmp+4); + + *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0; + for (i=16; i<32; i++) + { + *(pe++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL; + *(pe++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048); + } + *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16); + *(pe++)=virt_to_bus(btv->risc_jmp+10); +} + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the BT848 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.brooktree.com - nicely done those folks. + */ + +static void bt848_set_size(struct bttv *btv) +{ + u16 vscale, hscale; + u32 xsf, sr; + u16 hdelay, vdelay; + u16 hactive, vactive; + u16 inter; + u8 crop; + + /* + * No window , no try... + */ + + if (!btv->win.width) + return; + if (!btv->win.height) + return; + + inter=(btv->win.interlace&1)^1; + + switch (btv->win.bpp) + { + /* + * RGB8 seems to be a 9x5x5 GRB color cube starting at color 16 + * Why the h... can't they even mention this in the datasheet??? + */ + case 1: + btwrite(BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT); + btand(~0x10, BT848_CAP_CTL); // Dithering looks much better in this mode + break; + case 2: + btwrite(BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT); + btor(0x10, BT848_CAP_CTL); + break; + case 3: + btwrite(BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT); + btor(0x10, BT848_CAP_CTL); + break; + case 4: + btwrite(BT848_COLOR_FMT_RGB32, BT848_COLOR_FMT); + btor(0x10, BT848_CAP_CTL); + break; + } + + /* + * Set things up according to the final picture width. + */ + + hactive=btv->win.width; + if (hactive < 193) + { + btwrite (2, BT848_E_VTC); + btwrite (2, BT848_O_VTC); + } + else if (hactive < 385) + { + btwrite (1, BT848_E_VTC); + btwrite (1, BT848_O_VTC); + } + else + { + btwrite (0, BT848_E_VTC); + btwrite (0, BT848_O_VTC); + } + + /* + * Ok are we doing Never The Same Color or PAL ? + */ + + if (btv->win.norm==1) + { + btv->win.cropwidth=640; + btv->win.cropheight=480; + btwrite(0x68, BT848_ADELAY); + btwrite(0x5d, BT848_BDELAY); + btaor(BT848_IFORM_NTSC, ~7, BT848_IFORM); + btaor(BT848_IFORM_XT0, ~0x18, BT848_IFORM); + xsf = (btv->win.width*365625UL)/300000UL; + hscale = ((910UL*4096UL)/xsf-4096); + vdelay=btv->win.cropy+0x16; + hdelay=((hactive*135)/754+btv->win.cropx)&0x3fe; + } + else + { + btv->win.cropwidth=768; + btv->win.cropheight=576; + if (btv->win.norm==0) + { + btwrite(0x7f, BT848_ADELAY); + btwrite(0x72, BT848_BDELAY); + btaor(BT848_IFORM_PAL_BDGHI, ~BT848_IFORM_NORM, BT848_IFORM); + } + else + { + btwrite(0x7f, BT848_ADELAY); + btwrite(0x00, BT848_BDELAY); + btaor(BT848_IFORM_SECAM, ~BT848_IFORM_NORM, BT848_IFORM); + } + btaor(BT848_IFORM_XT1, ~0x18, BT848_IFORM); + xsf = (btv->win.width*36875UL)/30000UL; + hscale = ((1135UL*4096UL)/xsf-4096); + vdelay=btv->win.cropy+0x20; + hdelay=((hactive*186)/922+btv->win.cropx)&0x3fe; + } + sr=((btv->win.cropheight>>inter)*512)/btv->win.height-512; + vscale=(0x10000UL-sr)&0x1fff; + vactive=btv->win.cropheight; + +#if 0 + printk("bttv: hscale=0x%04x, ",hscale); + printk("bttv: vscale=0x%04x\n",vscale); + + printk("bttv: hdelay =0x%04x\n",hdelay); + printk("bttv: hactive=0x%04x\n",hactive); + printk("bttv: vdelay =0x%04x\n",vdelay); + printk("bttv: vactive=0x%04x\n",vactive); +#endif + + /* + * Interlace is set elsewhere according to the final image + * size we desire + */ + + if (btv->win.interlace) + { + btor(BT848_VSCALE_INT, BT848_E_VSCALE_HI); + btor(BT848_VSCALE_INT, BT848_O_VSCALE_HI); + } + else + { + btand(~BT848_VSCALE_INT, BT848_E_VSCALE_HI); + btand(~BT848_VSCALE_INT, BT848_O_VSCALE_HI); + } + + /* + * Load her up + */ + + btwrite(hscale>>8, BT848_E_HSCALE_HI); + btwrite(hscale>>8, BT848_O_HSCALE_HI); + btwrite(hscale&0xff, BT848_E_HSCALE_LO); + btwrite(hscale&0xff, BT848_O_HSCALE_LO); + + btwrite((vscale>>8)|(btread(BT848_E_VSCALE_HI)&0xe0), BT848_E_VSCALE_HI); + btwrite((vscale>>8)|(btread(BT848_O_VSCALE_HI)&0xe0), BT848_O_VSCALE_HI); + btwrite(vscale&0xff, BT848_E_VSCALE_LO); + btwrite(vscale&0xff, BT848_O_VSCALE_LO); + + btwrite(hactive&0xff, BT848_E_HACTIVE_LO); + btwrite(hactive&0xff, BT848_O_HACTIVE_LO); + btwrite(hdelay&0xff, BT848_E_HDELAY_LO); + btwrite(hdelay&0xff, BT848_O_HDELAY_LO); + + btwrite(vactive&0xff, BT848_E_VACTIVE_LO); + btwrite(vactive&0xff, BT848_O_VACTIVE_LO); + btwrite(vdelay&0xff, BT848_E_VDELAY_LO); + btwrite(vdelay&0xff, BT848_O_VDELAY_LO); + + crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| + ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); + btwrite(crop, BT848_E_CROP); + btwrite(crop, BT848_O_CROP); +} + + +/* + * The floats in the tuner struct are computed at compile time + * by gcc and cast back to integers. Thus we don't violate the + * "no float in kernel" rule. + */ + +static struct tunertype tuners[] = { + {"Temic PAL", TEMIC, PAL, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2}, + {"Philips PAL_I", Philips, PAL_I, + 16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00}, + {"Philips NTSC", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0}, + {"Philips SECAM", Philips, SECAM, + 16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0}, + {"NoTuner", NoTuner, NOTUNER, + 0 ,0 ,0x00,0x00,0x00,0x00,0x00}, + {"Philips PAL", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0}, + {"Temic NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2}, + {"TEMIC PAL_I", TEMIC, PAL_I, + 0 ,0 ,0x00,0x00,0x00,0x00,0xc2}, +}; + +/* + * Set TSA5522 synthesizer frequency in 1/16 Mhz steps + */ + +static void set_freq(struct bttv *btv, ushort freq) +{ + u8 config; + u16 div; + struct tunertype *tun=&tuners[btv->tuner]; + int oldAudio = btv->audio; + + audio(btv, AUDIO_MUTE); + udelay(AUDIO_MUTE_DELAY); + if (freq < tun->thresh1) + config = tun->VHF_L; + else if (freq < tun->thresh2) + config = tun->VHF_H; + else + config = tun->UHF; + + div=freq+623; /* div=((freq+16*38.9));*/ + + div&=0x7fff; + if (I2CWrite(btv, btv->tuneradr, (div>>8)&0x7f, div&0xff, 1)<0) + return; + I2CWrite(btv, btv->tuneradr, tun->config, config, 1); + if (!(oldAudio & AUDIO_MUTE)) + { + udelay(FREQ_CHANGE_DELAY); + audio(btv, AUDIO_UNMUTE); + } +} + +static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock) +{ + struct bttv *btv= (struct bttv *)v; + int q,todo; + + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + +/* btv->vbip=0; */ + cli(); + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + sti(); + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + interruptible_sleep_on(&btv->vbiq); + sti(); + if(current->signal & ~current->blocked) + { + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +/* + * Open a bttv card. Right now the flags stuff is just playing + */ + +static int bttv_open(struct video_device *dev, int flags) +{ + struct bttv *btv = (struct bttv *)dev; + int users, i; + + switch (flags) + { + case 0: + if (btv->user) + return -EBUSY; + btv->user++; + audio(btv, AUDIO_UNMUTE); + for (i=users=0; ivbip=VBIBUF_SIZE; + btv->cap|=0x0c; + bt848_set_risc_jmps(btv); + break; + } + MOD_INC_USE_COUNT; + return 0; +} + +static void bttv_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)dev; + + btv->user--; + audio(btv, AUDIO_MUTE); + btv->cap&=~3; +#if 0 /* FIXME */ + if(minor&0x20) + { + btv->cap&=~0x0c; + } +#endif + bt848_set_risc_jmps(btv); + + MOD_DEC_USE_COUNT; +} + +/***********************************/ +/* ioctls and supporting functions */ +/***********************************/ + +extern inline void bt848_bright(struct bttv *btv, uint bright) +{ + btwrite(bright&0xff, BT848_BRIGHT); +} + +extern inline void bt848_hue(struct bttv *btv, uint hue) +{ + btwrite(hue&0xff, BT848_HUE); +} + +extern inline void bt848_contrast(struct bttv *btv, uint cont) +{ + unsigned int conthi; + + conthi=(cont>>6)&4; + btwrite(cont&0xff, BT848_CONTRAST_LO); + btaor(conthi, ~4, BT848_E_CONTROL); + btaor(conthi, ~4, BT848_O_CONTROL); +} + +extern inline void bt848_sat_u(struct bttv *btv, ulong data) +{ + u32 datahi; + + datahi=(data>>7)&2; + btwrite(data&0xff, BT848_SAT_U_LO); + btaor(datahi, ~2, BT848_E_CONTROL); + btaor(datahi, ~2, BT848_O_CONTROL); +} + +static inline void bt848_sat_v(struct bttv *btv, ulong data) +{ + u32 datahi; + + datahi=(data>>8)&1; + btwrite(data&0xff, BT848_SAT_V_LO); + btaor(datahi, ~1, BT848_E_CONTROL); + btaor(datahi, ~1, BT848_O_CONTROL); +} + +/* + * Cliprect -> risc table. + * + * FIXME: This is generating wrong code when we have some kinds of + * rectangle lists. I don't currently understand why. + */ + +static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count) +{ + int i; + u32 yy, y, x, dx, ox; + u32 *rmem, *rmem2; + struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2; + u32 *rp, rpo=0, rpe=0, p, bpsl; + u32 *rpp; + u32 mask; + int interlace; + int depth; + + rmem=(u32 *)btv->risc_odd; + rmem2=(u32 *)btv->risc_even; + depth=btv->win.bpp; + + /* create y-sorted list */ + + first.next=NULL; + for (i=0; inext) && (vp[i].y > cur->next->y)) + cur=nx; + cur->next=&(vp[i]); + vp[i].next=nx; + } + first2.next=NULL; + + rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem[rpo++]=0; + + rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem2[rpe++]=0; + + + /* + * 32bit depth frame buffers need extra flags setting + */ + + if (depth==4) + mask=BT848_RISC_BYTE3; + else + mask=0; + + bpsl=btv->win.width*btv->win.bpp; + p=btv->win.vidadr+btv->win.x*btv->win.bpp+ + btv->win.y*btv->win.bpl; + + interlace=btv->win.interlace; + + /* + * Loop through all lines + */ + + for (yy=0; yy<(btv->win.height<<(1^interlace)); yy++) + { + y=yy>>(1^interlace); + + /* + * Even or odd frame generation. We have to + * write the RISC instructions to the right stream. + */ + + if(!(y&1)) + { + rp=&rpo; + rpp=rmem; + } + else + { + rp=&rpe; + rpp=rmem2; + } + + + /* + * first2 is the header of a list of "active" rectangles. We add + * rectangles as we hit their top and remove them as they fall off + * the bottom + */ + + /* remove rects with y2 > y */ + if ((cur=first2.next)) + { + prev=&first2; + do + { + if (cur->y+cur->height < y) + prev->next=cur->next; + else + prev=cur; + } + while ((cur=cur->next)); + } + + /* add rect to second (x-sorted) list if rect.y == y */ + if ((cur=first.next)) + { + while ((cur) && (cur->y == y)) + { + first.next=cur->next; + cur2=&first2; + while ((nx2=cur2->next) && (cur->x > cur2->next->x)) + cur2=nx2; + cur2->next=cur; + cur->next=nx2; + cur=first.next; + } + } + + + /* + * Begin writing the RISC script + */ + + dx=x=0; + + /* + * Starting at x position 0 on a new scan line + * write to location p, don't yet write the number + * of pixels for the instruction + */ + + rpp[(*rp)++]=BT848_RISC_WRITE|BT848_RISC_SOL; + rpp[(*rp)++]=p; + + /* + * For each rectangle we have in the "active" list - sorted left to + * right.. + */ + + for (cur2=first2.next; cur2; cur2=cur2->next) + { + /* + * If we are to the left of the first drawing area + */ + + if (x+dx < cur2->x) + { + /* Bytes pending ? */ + if (dx) + { + /* For a delta away from the start we need to write a SKIP */ + if (x) + rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth); + else + /* Rewrite the start of line WRITE to a SKIP */ + rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth); + /* Move X to the next point (drawing start) */ + x=x+dx; + } + /* Ok how far are we from the start of the next rectangle ? */ + dx=cur2->x-x; + /* dx is now the size of data to write */ + + /* If this isnt the left edge generate a "write continue" */ + if (x) + rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|mask; + else + /* Fill in the byte count on the initial WRITE */ + rpp[(*rp)-2]|=(dx*depth)|mask; + /* Move to the start of the rectangle */ + x=cur2->x; + /* x is our left dx is byte size of hole */ + dx=cur2->width+1; + } + else + /* Already in a clip zone.. set dx */ + if (x+dx < cur2->x+cur2->width) + dx=cur2->x+cur2->width-x+1; + } + /* now treat the rest of the line */ + ox=x; + if (dx) + { + /* Complete the SKIP to eat to the end of the gap */ + if (x) + rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth); + else + /* Rewrite to SKIP start to this point */ + rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth); + x=x+dx; + } + + /* + * Not at the right hand edge ? + */ + + if ((dx=btv->win.width-x)!=0) + { + /* Write to edge of display */ + if (x) + rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|BT848_RISC_EOL|mask; + else + /* Entire frame is a write - patch first order */ + rpp[(*rp)-2]|=(dx*depth)|BT848_RISC_EOL|mask; + } + else + { + /* End of line if needed */ + if (ox) + rpp[(*rp)-1]|=BT848_RISC_EOL|mask; + else + { + /* Skip the line : write a SKIP + start/end of line marks */ + (*rp)--; + rpp[(*rp)-1]=BT848_RISC_SKIP|(btv->win.width*depth)| + BT848_RISC_EOL|BT848_RISC_SOL; + } + } + /* + * Move the video render pointer on a line + */ + if (interlace||(y&1)) + p+=btv->win.bpl; + } + + /* + * Attach the interframe jumps + */ + + rmem[rpo++]=BT848_RISC_JUMP; + rmem[rpo++]=btv->bus_vbi_even; + + rmem2[rpe++]=BT848_RISC_JUMP; + rmem2[rpe++]=btv->bus_vbi_odd; +} + +/* + * Helper for adding clips. + */ + +static void new_risc_clip(struct video_window *vw, struct video_clip *vcp, int x, int y, int w, int h) +{ + vcp[vw->clipcount].x=x; + vcp[vw->clipcount].y=y; + vcp[vw->clipcount].width=w; + vcp[vw->clipcount].height=h; + vw->clipcount++; +} + +/* + * ioctl routine + */ + +static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + unsigned char eedata[256]; +/* unsigned long data;*/ +/* static ushort creg;*/ + struct bttv *btv=(struct bttv *)dev; + static int lastchan=0; + + switch (cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->video_dev.name); + b.type = VID_TYPE_CAPTURE| + VID_TYPE_TUNER| + VID_TYPE_TELETEXT| + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + b.channels = 4; /* tv , input, svhs */ + b.audios = 4; /* tv, input, svhs */ + b.maxwidth = 768; + b.maxheight = 576; + b.minwidth = 32; + b.minheight = 32; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags=VIDEO_VC_AUDIO; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; + switch(v.channel) + { + case 0: + strcpy(v.name,"Television"); + v.flags|=VIDEO_VC_TUNER; + v.type=VIDEO_TYPE_TV; + v.tuners=1; + break; + case 1: + strcpy(v.name,"Composite1"); + break; + case 2: + strcpy(v.name,"Composite2"); + break; + case 3: + strcpy(v.name,"SVHS"); + break; + default: + return -EINVAL; + } + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* + * Each channel has 1 tuner + */ + case VIDIOCSCHAN: + { + int v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + bt848_muxsel(btv, v); + lastchan=v; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||lastchan) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Television"); + v.rangelow=0; + v.rangehigh=0xFFFFFFFF; + v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC; + v.mode = btv->win.norm; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* We have but tuner 0 */ + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only channel 0 has a tuner */ + if(v.tuner!=0 || lastchan) + return -EINVAL; + if(v.mode!=VIDEO_MODE_PAL||v.mode!=VIDEO_MODE_NTSC) + return -EOPNOTSUPP; + btv->win.norm = v.mode; + bt848_set_size(btv); + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=btv->picture; + if(btv->win.bpp==8) + p.palette=VIDEO_PALETTE_HI240; + if(btv->win.bpp==16) + p.palette=VIDEO_PALETTE_RGB565; + if(btv->win.bpp==24) + p.palette=VIDEO_PALETTE_RGB24; + if(btv->win.bpp==32) + p.palette=VIDEO_PALETTE_RGB32; + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + if(copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + /* We want -128 to 127 we get 0-65535 */ + bt848_bright(btv, (p.brightness>>8)-128); + /* 0-511 for the colour */ + bt848_sat_u(btv, p.colour>>7); + bt848_sat_v(btv, ((p.colour>>7)*201L)/237); + /* -128 to 127 */ + bt848_hue(btv, (p.hue>>8)-128); + /* 0-511 */ + bt848_contrast(btv, p.contrast>>7); + btv->picture=p; + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp; + int on; + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + if(vw.flags) + return -EINVAL; + + btv->win.x=vw.x; + btv->win.y=vw.y; + btv->win.width=vw.width; + btv->win.height=vw.height; + + if(btv->win.height>btv->win.cropheight/2) + btv->win.interlace=1; + else + btv->win.interlace=0; + + on=(btv->cap&3)?1:0; + + bt848_cap(btv,0); + bt848_set_size(btv); + + if(vw.clipcount>256) + return -EDOM; /* Too many! */ + + /* + * Do any clips. + */ + + vcp=vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); + if(vcp==NULL) + return -ENOMEM; + if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) + return -EFAULT; + /* + * Impose display clips + */ + if(btv->win.x<0) + new_risc_clip(&vw, vcp, 0, 0, -btv->win.x, btv->win.height-1); + if(btv->win.y<0) + new_risc_clip(&vw, vcp, 0, 0, btv->win.width-1,-btv->win.y); + if(btv->win.x+btv->win.width> btv->win.swidth) + new_risc_clip(&vw, vcp, btv->win.swidth-btv->win.x, 0, btv->win.width-1, btv->win.height-1); + if(btv->win.y+btv->win.height > btv->win.sheight) + new_risc_clip(&vw, vcp, 0, btv->win.sheight-btv->win.y, btv->win.width-1, btv->win.height-1); + /* + * Question: Do we need to walk the clip list + * and saw off any clips outside the window + * frame or will write_risc_tab do the right + * thing ? + */ + write_risc_data(btv,vcp, vw.clipcount); + vfree(vcp); + if(on) + bt848_cap(btv,1); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + /* Oh for a COBOL move corresponding .. */ + vw.x=btv->win.x; + vw.y=btv->win.y; + vw.width=btv->win.width; + vw.height=btv->win.height; + vw.chromakey=0; + vw.flags=0; + if(btv->win.interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + if(copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(btv->win.vidadr==0 || btv->win.width==0 || btv->win.height==0) + return -EINVAL; + if(v==0) + { + bt848_cap(btv,0); + } + else + { + bt848_cap(btv,1); + } + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + v.base=(void *)btv->win.vidadr; + v.height=btv->win.sheight; + v.width=btv->win.swidth; + v.depth=btv->win.bpp*8; + v.bytesperline=btv->win.bpl; + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; + + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if(!suser()) + return -EPERM; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v.depth!=8 && v.depth!=16 && v.depth!=24 && v.depth!=32) + return -EINVAL; + btv->win.vidadr=(int)v.base; + btv->win.sheight=v.height; + btv->win.swidth=v.width; + btv->win.bpp=v.depth/8; + btv->win.bpl=v.bytesperline; + + DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); + bt848_set_size(btv); + return 0; + } + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + return 0; + } + case VIDIOCGFREQ: + { + unsigned long v=btv->win.freq; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: + { + unsigned long v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + btv->win.freq=v; + set_freq(btv, btv->win.freq); + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio vp; + vp=btv->audio_dev; + vp.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); + vp.flags|=VIDEO_AUDIO_MUTABLE; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v,arg, sizeof(v))) + return -EFAULT; + if(v.flags&VIDEO_AUDIO_MUTE) + audio(btv, AUDIO_MUTE); + if(v.audio<0||v.audio>2) + return -EINVAL; + bt848_muxsel(btv,v.audio); + if(!(v.flags&VIDEO_AUDIO_MUTE)) + audio(btv, AUDIO_UNMUTE); + btv->audio_dev=v; + return 0; + } + + case BTTV_WRITEEE: + if(copy_from_user((void *) eedata, (void *) arg, 256)) + return -EFAULT; + writeee(btv, eedata); + break; + + case BTTV_READEE: + readee(btv, eedata); + if(copy_to_user((void *) arg, (void *) eedata, 256)) + return -EFAULT; + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int bttv_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device bttv_template= +{ + "UNSET", + VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT, + VID_HARDWARE_BT848, + bttv_open, + bttv_close, + bttv_read, + bttv_write, + bttv_ioctl, + NULL, /* no mmap yet */ + bttv_init_done, + NULL, + 0, + 0 +}; + +struct vidbases +{ + ushort vendor, device; + char *name; + uint badr; +}; + +static struct vidbases vbs[] = { + { PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, + "Matrox Millennium", PCI_BASE_ADDRESS_1}, + { PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1}, + { PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX, + "ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128, + "Number Nine Imagine 128", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, + "DEC DC21030", PCI_BASE_ADDRESS_0}, +}; + + +/* DEC TGA offsets stolen from XFree-3.2 */ + +static uint dec_offsets[4] = { + 0x200000, + 0x804000, + 0, + 0x1004000 +}; + +#define NR_CARDS (sizeof(vbs)/sizeof(struct vidbases)) + +/* Scan for PCI display adapter + if more than one card is present the last one is used for now */ + +static int find_vga(void) +{ + unsigned int devfn, class, vendev; + ushort vendor, device, badr; + int found=0, bus=0, i, tga_type; + unsigned int vidadr=0; + + + for (devfn = 0; devfn < 0xff; devfn++) + { + if (PCI_FUNC(devfn) != 0) + continue; + pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendev); + if (vendev == 0xffffffff || vendev == 0x00000000) + continue; + pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &device); + pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class); + class = class >> 16; +/* if (class == PCI_CLASS_DISPLAY_VGA) {*/ + if ((class>>8) == PCI_BASE_CLASS_DISPLAY || + /* Number 9 GXE64Pro needs this */ + class == PCI_CLASS_NOT_DEFINED_VGA) + { + badr=0; + printk(KERN_INFO "bttv: PCI display adapter: "); + for (i=0; i> 12) & 0x0f; + if (tga_type != 0 && tga_type != 1 && tga_type != 3) + { + printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type); + found--; + } + vidadr+=dec_offsets[tga_type]; + } + + DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr)); + DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn)); + found++; + } + } + + if (vidmem) + { + vidadr=vidmem<<20; + printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr); + found=1; + } + for (i=0; i switch it off */ + if(!(b & TRITON_BUS_CONCURRENCY)) + { + printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n"); + b |= TRITON_BUS_CONCURRENCY; + } + + /* still freezes on other boards -> switch off even more */ + if(b & TRITON_PEER_CONCURRENCY) + { + printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n"); + b &= ~TRITON_PEER_CONCURRENCY; + } + if(!(b & TRITON_STREAMING)) + { + printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n"); + b |= TRITON_STREAMING; + } + + if (b!=bo) + { + pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); + printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b); + } + } + } +} + +static void init_tda9850(struct bttv *btv) +{ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0, 1); +} + +/* Figure out card and tuner type */ + +static void idcard(struct bttv *btv) +{ + int i; + + btwrite(0, BT848_GPIO_OUT_EN); + DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA))); + + btv->type=BTTV_MIRO; + btv->tuner=tuner; + + if (I2CRead(btv, I2C_HAUPEE)>=0) + btv->type=BTTV_HAUPPAUGE; + else if (I2CRead(btv, I2C_STBEE)>=0) + btv->type=BTTV_STB; + + for (i=0xc0; i<0xd0; i+=2) + { + if (I2CRead(btv, i)>=0) + { + btv->tuneradr=i; + break; + } + } + + btv->dbx = I2CRead(btv, I2C_TDA9850) ? 0 : 1; + + if (btv->dbx) + init_tda9850(btv); + + /* How do I detect the tuner type for other cards but Miro ??? */ + printk(KERN_INFO "bttv: model: "); + switch (btv->type) + { + case BTTV_MIRO: + btv->tuner=((btread(BT848_GPIO_DATA)>>10)-1)&7; + printk("MIRO"); + strcpy(btv->video_dev.name,"BT848(Miro)"); + break; + case BTTV_HAUPPAUGE: + printk("HAUPPAUGE"); + strcpy(btv->video_dev.name,"BT848(Hauppauge)"); + break; + case BTTV_STB: + printk("STB"); + strcpy(btv->video_dev.name,"BT848(STB)"); + break; + case BTTV_INTEL: + printk("Intel"); + strcpy(btv->video_dev.name,"BT848(Intel)"); + break; + case BTTV_DIAMOND: + printk("Diamond"); + strcpy(btv->video_dev.name,"BT848(Diamond)"); + break; + } + printk(" (%s @ 0x%02x)\n", tuners[btv->tuner].name, btv->tuneradr); + audio(btv, AUDIO_MUTE); +} + + +static void bt848_set_risc_jmps(struct bttv *btv) +{ + int flags=btv->cap; + + btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE; + btv->risc_jmp[1]=0; + + btv->risc_jmp[2]=BT848_RISC_JUMP; + if (flags&8) + btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd); + else + btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4); + + btv->risc_jmp[4]=BT848_RISC_JUMP; + if (flags&2) + btv->risc_jmp[5]=virt_to_bus(btv->risc_odd); + else + btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6); + + btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO; + btv->risc_jmp[7]=0; + + btv->risc_jmp[8]=BT848_RISC_JUMP; + if (flags&4) + btv->risc_jmp[9]=virt_to_bus(btv->vbi_even); + else + btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10); + + btv->risc_jmp[10]=BT848_RISC_JUMP; + if (flags&1) + btv->risc_jmp[11]=virt_to_bus(btv->risc_even); + else + btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp); + + btaor(flags, ~0x0f, BT848_CAP_CTL); + if (flags&0x0f) + bt848_dma(btv, 3); + else + bt848_dma(btv, 0); +} + + +static int init_bt848(struct bttv *btv) +{ + /* reset the bt848 */ + btwrite(0,BT848_SRESET); + btv->user=0; + + DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem)); + + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ + + btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ + btv->win.interlace=1; + btv->win.x=0; + btv->win.y=0; + btv->win.width=768; /* 640 */ + btv->win.height=576; /* 480 */ + btv->win.cropwidth=768; /* 640 */ + btv->win.cropheight=576; /* 480 */ + btv->win.cropx=0; + btv->win.cropy=0; + btv->win.bpp=2; + btv->win.bpl=1024*btv->win.bpp; + btv->win.swidth=1024; + btv->win.sheight=768; + btv->cap=0; + + if (!(btv->risc_odd=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_jmp =(dword *) kmalloc(1024, GFP_KERNEL))) + return -1; + btv->vbi_odd=btv->risc_jmp+12; + btv->vbi_even=btv->vbi_odd+256; + btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp); + btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); + + btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); + btv->vbibuf=(unchar *) vmalloc(VBIBUF_SIZE); + if (!btv->vbibuf) + return -1; + + bt848_muxsel(btv, 1); + bt848_set_size(btv); + +/* btwrite(0, BT848_TDEC); */ + btwrite(0x10, BT848_COLOR_CTL); + btwrite(0x00, BT848_CAP_CTL); + + btwrite(0x0ff, BT848_VBI_PACK_SIZE); + btwrite(1, BT848_VBI_PACK_DEL); + + btwrite(0xfc, BT848_GPIO_DMA_CTL); + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI, + BT848_IFORM); + + bt848_bright(btv, 0x10); + btwrite(0xd8, BT848_CONTRAST_LO); + + btwrite(0x60, BT848_E_VSCALE_HI); + btwrite(0x60, BT848_O_VSCALE_HI); + btwrite(/*BT848_ADC_SYNC_T|*/ + BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC); + + btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + btwrite(0x00, BT848_E_SCLOOP); + btwrite(0x00, BT848_O_SCLOOP); + + btwrite(0xffffffUL,BT848_INT_STAT); +/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|BT848_INT_FDSR| + BT848_INT_FTRGT|BT848_INT_FBUS|*/ + btwrite(BT848_INT_ETBF| + BT848_INT_SCERR| + BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| + BT848_INT_FMTCHG|BT848_INT_HLOCK, + BT848_INT_MASK); + +/* make_risctab(btv); */ + make_vbitab(btv); + bt848_set_risc_jmps(btv); + + /* + * Now add the template and register the device unit. + */ + + memcpy(&btv->video_dev,&bttv_template,sizeof(bttv_template)); + idcard(btv); + if(video_register_device(&btv->video_dev)<0) + return -1; + return 0; +} + + +static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,astat; + u32 dstat; + int count; + struct bttv *btv; + + btv=(struct bttv *)dev_id; + count=0; + while (1) + { + /* get/clear interrupt status bits */ + stat=btread(BT848_INT_STAT); + astat=stat&btread(BT848_INT_MASK); + if (!astat) + return; + btwrite(astat,BT848_INT_STAT); + IDEBUG(printk ("bttv: astat %08x\n",astat)); + IDEBUG(printk ("bttv: stat %08x\n",stat)); + + /* get device status bits */ + dstat=btread(BT848_DSTATUS); + + if (astat&BT848_INT_FMTCHG) + { + IDEBUG(printk ("bttv: IRQ_FMTCHG\n")); +/* btv->win.norm&=(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ + } + if (astat&BT848_INT_VPRES) + { + IDEBUG(printk ("bttv: IRQ_VPRES\n")); + } + if (astat&BT848_INT_VSYNC) + { + IDEBUG(printk ("bttv: IRQ_VSYNC\n")); + } + if (astat&BT848_INT_SCERR) { + IDEBUG(printk ("bttv: IRQ_SCERR\n")); + bt848_dma(btv, 0); + bt848_dma(btv, 1); + wake_up_interruptible(&btv->vbiq); + wake_up_interruptible(&btv->capq); + } + if (astat&BT848_INT_RISCI) + { + IDEBUG(printk ("bttv: IRQ_RISCI\n")); + /* printk ("bttv: IRQ_RISCI%d\n",stat>>28); */ + if (stat&(1<<28)) + { + btv->vbip=0; + wake_up_interruptible(&btv->vbiq); + } + if (stat&(2<<28)) + { + bt848_set_risc_jmps(btv); + wake_up_interruptible(&btv->capq); + break; + } + } + if (astat&BT848_INT_OCERR) + { + IDEBUG(printk ("bttv: IRQ_OCERR\n")); + } + if (astat&BT848_INT_PABORT) + { + IDEBUG(printk ("bttv: IRQ_PABORT\n")); + } + if (astat&BT848_INT_RIPERR) + { + IDEBUG(printk ("bttv: IRQ_RIPERR\n")); + } + if (astat&BT848_INT_PPERR) + { + IDEBUG(printk ("bttv: IRQ_PPERR\n")); + } + if (astat&BT848_INT_FDSR) + { + IDEBUG(printk ("bttv: IRQ_FDSR\n")); + } + if (astat&BT848_INT_FTRGT) + { + IDEBUG(printk ("bttv: IRQ_FTRGT\n")); + } + if (astat&BT848_INT_FBUS) + { + IDEBUG(printk ("bttv: IRQ_FBUS\n")); + } + if (astat&BT848_INT_HLOCK) + { + if (dstat&BT848_DSTATUS_HLOC) + audio(btv, AUDIO_ON); + else + audio(btv, AUDIO_OFF); + } + + if (astat&BT848_INT_I2CDONE) + { + } + + count++; + if (count > 10) + printk (KERN_WARNING "bttv: irq loop %d\n", count); + if (count > 20) + { + btwrite(0, BT848_INT_MASK); + printk(KERN_ERR "bttv: IRQ lockup, cleared int mask\n"); + } + } +} + + +/* + * Scan for a Bt848 card, request the irq and map the io memory + */ + +static int find_bt848(void) +{ + short pci_index; + unsigned char command, latency; + int result; + unsigned char bus, devfn; + struct bttv *btv; + + bttv_num=0; + + if (!pcibios_present()) + { + DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessable!\n")); + return 0; + } + + for (pci_index = 0; + !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, + pci_index, &bus, &devfn); + ++pci_index) + { + btv=&bttvs[bttv_num]; + btv->bus=bus; + btv->devfn=devfn; + btv->bt848_mem=NULL; + btv->vbibuf=NULL; + btv->risc_jmp=NULL; + btv->vbi_odd=NULL; + btv->vbi_even=NULL; + btv->vbiq=NULL; + btv->capq=NULL; + btv->vbip=VBIBUF_SIZE; + + pcibios_read_config_byte(btv->bus, btv->devfn, + PCI_INTERRUPT_LINE, &btv->irq); + pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, + &btv->bt848_adr); + + if (remap&&(!bttv_num)) + { + remap<<=20; + remap&=PCI_BASE_ADDRESS_MEM_MASK; + printk(KERN_INFO "Remapping to : 0x%08x.\n", remap); + remap|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK); + pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, + remap); + pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, + &btv->bt848_adr); + } + + btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION, + &btv->revision); + printk(KERN_INFO "bttv: Brooktree Bt848 (rev %d) ",btv->revision); + printk("bus: %d, devfn: %d, ", + btv->bus, btv->devfn); + printk("irq: %d, ",btv->irq); + printk("memory: 0x%08x.\n", btv->bt848_adr); + + btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); + + result = request_irq(btv->irq, bttv_irq, + SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); + if (result==-EINVAL) + { + printk(KERN_ERR "bttv: Bad irq number or handler\n"); + return -EINVAL; + } + if (result==-EBUSY) + { + printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->irq); + return result; + } + if (result < 0) + return result; + + /* Enable bus-mastering */ + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command); + command|=PCI_COMMAND_MASTER; + pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command); + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command); + if (!(command&PCI_COMMAND_MASTER)) + { + printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n"); + return -1; + } + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER, + &latency); + if (!latency) + { + latency=32; + pcibios_write_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER, + latency); + } + DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency)); + bttv_num++; + } + if(bttv_num) + printk(KERN_INFO "bttv: %d Bt848 card(s) found.\n", bttv_num); + return bttv_num; +} + +static void release_bttv(void) +{ + u8 command; + int i; + struct bttv *btv; + + for (i=0;ibus, btv->devfn, PCI_COMMAND, &command); + command|=PCI_COMMAND_MASTER; + pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command); + + /* unmap and free memory */ + if (btv->risc_odd) + kfree((void *) btv->risc_odd); + + if (btv->risc_even) + kfree((void *) btv->risc_even); + + DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp)); + if (btv->risc_jmp) + kfree((void *) btv->risc_jmp); + + DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf)); + if (btv->vbibuf) + vfree((void *) btv->vbibuf); + free_irq(btv->irq,btv); + DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem)); + if (btv->bt848_mem) + iounmap(btv->bt848_mem); + video_unregister_device(&btv->video_dev); + } +} + + +#ifdef MODULE + +int init_module(void) +{ +#else +int init_bttv_cards(struct video_init *unused) +{ +#endif + int i; + + handle_chipset(); + if (find_bt848()<0) + return -EIO; + + for (i=0; i +#include + +#include "bt848.h" + +typedef unsigned int dword; + +struct riscprog { + uint length; + dword *busadr; + dword *prog; +}; + +/* values that can be set by user programs */ + +struct bttv_window { + int x, y; + ushort width, height; + ushort bpp, bpl; + ushort swidth, sheight; + short cropx, cropy; + ushort cropwidth, cropheight; + int vidadr; + ushort freq; + int norm; + int interlace; + int color_fmt; +}; + +/* private data that can only be read (or set indirectly) by user program */ + +struct bttv { + struct video_device video_dev; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + u_char bus; /* PCI bus the Bt848 is on */ + u_char devfn; + u_char revision; + u_char irq; /* IRQ used by Bt848 card */ + uint bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + u_char *bt848_mem; /* pointer to mapped IO memory */ + ulong busriscmem; + dword *riscmem; + + u_char *vbibuf; + struct bttv_window win; + int type; /* card type */ + int audio; /* audio mode */ + int user; + int tuner; + int tuneradr; + int dbx; + + dword *risc_jmp; + dword *vbi_odd; + dword *vbi_even; + dword bus_vbi_even; + dword bus_vbi_odd; + struct wait_queue *vbiq; + struct wait_queue *capq; + int vbip; + + dword *risc_odd; + dword *risc_even; + int cap; +}; + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BTTV in the Makefile.*/ +#ifdef _ALPHA_BTTV +#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) +#define btread(adr) readl(btv->bt848_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) +#define btread(adr) readl(btv->bt848_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +/* bttv ioctls */ +#define BTTV_WRITE_BTREG 0x00 +#define BTTV_READ_BTREG 0x01 +#define BTTV_SET_BTREG 0x02 +#define BTTV_SETRISC 0x03 +#define BTTV_SETWTW 0x04 +#define BTTV_GETWTW 0x05 +#define BTTV_DMA 0x06 +#define BTTV_CAP_OFF 0x07 +#define BTTV_CAP_ON 0x08 +#define BTTV_GETBTTV 0x09 +#define BTTV_SETFREQ 0x0a +#define BTTV_SETCHAN 0x0b +#define BTTV_INPUT 0x0c +#define BTTV_READEE 0x0d +#define BTTV_WRITEEE 0x0e +#define BTTV_BRIGHT 0x0f +#define BTTV_HUE 0x10 +#define BTTV_COLOR 0x11 +#define BTTV_CONTRAST 0x12 +#define BTTV_SET_FFREQ 0x13 +#define BTTV_MUTE 0x14 + +#define BTTV_GRAB 0x20 +#define BTTV_TESTM 0x20 + + +#define BTTV_UNKNOWN 0x00 +#define BTTV_MIRO 0x01 +#define BTTV_HAUPPAUGE 0x02 +#define BTTV_STB 0x03 +#define BTTV_INTEL 0x04 +#define BTTV_DIAMOND 0x05 + +#define AUDIO_TUNER 0x00 +#define AUDIO_EXTERN 0x01 +#define AUDIO_INTERN 0x02 +#define AUDIO_OFF 0x03 +#define AUDIO_ON 0x04 +#define AUDIO_MUTE 0x80 +#define AUDIO_UNMUTE 0x81 + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/char/joystick.c linux/drivers/char/joystick.c --- v2.1.66/linux/drivers/char/joystick.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/char/joystick.c Sat Nov 29 10:33:19 1997 @@ -1,380 +1,837 @@ /* + * $Id: joystick.c,v 1.2 1997/10/31 19:11:48 mj Exp $ + * + * Copyright (C) 1997 Vojtech Pavlik + */ - linux/drivers/char/joystick.c - Copyright (C) 1992, 1993 Arthur C. Smith - Joystick driver for Linux running on an IBM compatible computer. - -VERSION INFO: -01/08/93 ACS 0.1: Works but needs multi-joystick support -01/13/93 ACS 0.2: Added multi-joystick support (minor 0 and 1) - Added delay between measuring joystick axis - Added scaling ioctl -02/16/93 ACS 0.3: Modified scaling to use ints to prevent kernel - panics 8-) -02/28/93 ACS 0.4: Linux99.6 and fixed race condition in js_read. - After looking at a schematic of a joystick card - it became apparent that any write to the joystick - port started ALL the joystick one shots. If the - one that we are reading is short enough and the - first one to be read, the second one will return - bad data if it's one shot has not expired when - the joystick port is written for the second time. - Thus solves the mystery delay problem in 0.2! -05/05/93 ACS/Eyal 0.5: Upgraded the driver to the 99.9 kernel, added - joystick support to the make config options, - updated the driver to return the buttons as - positive logic, and read both axis at once - (thanks Eyal!), and added some new ioctls. -02/12/94 Jeff Tranter 0.6: Made necessary changes to work with 0.99pl15 - kernel (and hopefully 1.0). Also did some - cleanup: indented code, fixed some typos, wrote - man page, etc... -05/17/95 Dan Fandrich 0.7.3: Added I/O port registration, cleaned up code -04/03/96 Matt Rhoten 0.8: many minor changes: - new read loop from Hal Maney - cleaned up #includes to allow #include of - joystick.h with gcc -Wall and from g++ - made js_init fail if it finds zero joysticks - general source/comment cleanup - use of MOD_(INC|DEC)_USE_COUNT - changes from Bernd Schmidt - to compile correctly under 1.3 in kernel or as module -06/30/97 Alan Cox 0.9: Ported to 2.1.x - Reformatted to resemble Linux coding standard - Removed semaphore bug (we can dump the lot I think) - Fixed xntp timer adjust during joystick timer0 bug - Changed variable names to lower case. Kept binary - compatibility. - Better ioctl names. Kept binary compatibility. - Removed 'save_busy'. Just set busy to 1. -11/03/97 Brian Gerst 0.9.1: Fixed bug which caused driver to always time out - but never report a timeout (broken while loop). - Fixed js_read for new VFS code. -*/ +/* + * This is joystick driver for Linux. It supports up to two analog joysticks + * on a PC compatible machine. See Documentation/joystick.txt for changelog + * and credits. + */ +#include +#include #include -#include +#include +#include #include +#include +#include +#include +#include #include -#include +#include + #include +#include #include +#include -static struct js_config js_data[JS_MAX]; /* misc data */ -static int js_exist; /* which joysticks' axis exist? */ -static int js_read_semaphore; /* to prevent two processes from trying - to read different joysticks at the - same time */ +#define PIT_HZ 1193180L /* PIT clock is 1.19318 MHz */ -/* - * get_timer0(): - * returns the current value of timer 0. This is a 16 bit counter that starts - * at LATCH and counts down to 0 +#define JS_MAXTIME PIT_HZ/250 /* timeout for read (4 ms) */ + +#define JS_BUTTON_PERIOD HZ/50 /* button valid time (20 ms) */ +#define JS_AXIS_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */ +#define JS_AXIS_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */ + +#define JS_FIFO_SIZE 16 /* number of FIFO entries */ +#define JS_BUFF_SIZE 32 /* output buffer size */ +#define JS_RETRIES 4 /* number of retries */ +#define JS_DEF_PREC 8 /* initial precision for all axes */ + +#define JS_NUM 2 /* number of joysticks */ + +#define JS_AXES 0x0f /* bit mask for all axes */ +#define JS_BUTTONS 0xf0 /* bit mask for all buttons */ + +#define PIT_MODE 0x43 /* timer mode port */ +#define PIT_DATA 0x40 /* timer 0 data port */ +#define JS_PORT 0x201 /* joystick port */ + +#define JS_TRIGGER 0xff /* triggers one-shots */ +#define PIT_READ_TIMER 0x00 /* to read timer 0 */ + +#define DELTA(X,Y,Z) ((X)-(Y)+(((X)>=(Y))?0:Z)) /* cyclic delta */ +#define DELTA_T(X,Y) DELTA((X),(Y),(PIT_HZ/HZ)) /* for time measurement */ +#define DELTA_TX(X,Y,Z) DELTA_T((X),((Y)&0xFF)|(((Z)&0xFF)<<8)) +#define ROT(A,B,C) ((((A)<(C))&&(((B)>(A))&&((B)<(C))))||(((A)>(C))&&(((B)>(A))||((B)<(C))))) +#define GOF(X) (((X)==JS_BUFF_SIZE-1)?0:(X)+1) +#define GOFF(X) (((X)==JS_FIFO_SIZE-1)?0:(X)+1) +#define GOB(X) ((X)?(X)-1:JS_BUFF_SIZE-1) + +struct js_data { + int ahead; + int bhead; + int tail; + struct js_event buff[JS_BUFF_SIZE]; + struct js_list *list; + struct wait_queue *wait; + unsigned int exist; +}; + +struct js_axis { + int value; + struct js_corr corr; +}; + +struct js_list { + struct js_list *next; /* next-in-list pointer */ + unsigned long time; /* when the device was open */ + int tail; /* a tail for js_buff */ + char startup; +}; + +struct js_fifo { + unsigned long time; + unsigned long event; +}; + +static struct js_data jsd[JS_NUM]; /* joystick data */ +static struct timer_list js_timer; /* joystick timer */ + +static unsigned char js_fifo_head = 0; /* head of the fifo */ +static unsigned char js_fifo_tail = JS_FIFO_SIZE - 1; /* tail of the fifo */ +static struct js_fifo js_fifo[JS_FIFO_SIZE]; /* the fifo */ + +static unsigned char js_last_buttons = 0; /* last read button state */ +static unsigned long js_axis_time = 0; /* last read axis time */ +static unsigned long js_mark_time = 0; + +static unsigned char js_axes_exist; /* all axes that exist */ +static unsigned char js_buttons_exist; /* all buttons that exist */ + +static struct js_axis js_axis[4]; +static unsigned int js_buttons = 0; + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_SUPPORTED_DEVICE("js"); +MODULE_PARM(js, "0-1b"); + +static char js[] = {0, 0}; + +/* + * get_pit() returns the immediate state of PIT0. Must be run + * with interrupts disabled. */ - -extern inline int get_timer0(void) + +static inline int get_pit(void) { - unsigned long flags; - int t0, t1; + int t, flags; + save_flags(flags); cli(); - outb (0, PIT_MODE); - t0 = (int) inb (PIT_COUNTER_0); - t1 = ((int) inb (PIT_COUNTER_0) << 8) + t0; + outb(PIT_READ_TIMER, PIT_MODE); + t = inb(PIT_DATA); + t |= (int) inb(PIT_DATA) << 8; restore_flags(flags); - return (t1); + return t; } /* - * find_axes(): - * - * returns which axes are hooked up, in a bitfield. 2^n is set if - * axis n is hooked up, for 0 <= n < 4. - * - * REVIEW: should update this to handle eight-axis (four-stick) game port - * cards. anyone have one of these to test on? mattrh 3/23/96 + * count_bits() counts set bits in a byte. */ - -extern inline int find_axes(void) + +static int count_bits(unsigned char c) { - int j; - outb (0xff, JS_PORT); /* trigger oneshots */ - /* and see what happens */ - for (j = JS_DEF_TIMEOUT; (0x0f & inb (JS_PORT)) && j; j--); - /* do nothing; wait for the timeout */ - js_exist = inb (JS_PORT) & 0x0f; /* get joystick status byte */ - js_exist = (~js_exist) & 0x0f; -/* printk("find_axes: js_exist is %d (0x%04X)\n", js_exist, js_exist);*/ - return js_exist; + int i, t = 0; + for (i = 0; i < 8; i++) + if (c & (1 << i)) t++; + return t; } -static int js_ioctl (struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg) +/* + * js_correct() performs correction of raw joystick data. + */ + +static int js_correct(int value, struct js_corr *corr) { - unsigned int minor = MINOR (inode->i_rdev); - if (minor >= JS_MAX) - return -ENODEV; - - if ((((inb (JS_PORT) & 0x0f) >> (minor << 1)) & 0x03) == 0x03) /*js minor exists?*/ - return -ENODEV; - switch (cmd) - { - - case JSIOCSCAL: /*from struct *arg to js_data[minor]*/ - if(copy_from_user(&js_data[minor].js_corr, - (void *)arg, sizeof(struct js_status))) - return -EFAULT; - break; - case JSIOCGCAL: /*to struct *arg from js_data[minor]*/ - if(copy_to_user((void *) arg, &js_data[minor].js_corr, - sizeof(struct js_status))) - return -EFAULT; - break; - case JSIOCSTIMEOUT: - if(copy_from_user(&js_data[minor].js_timeout, - (void *)arg, sizeof(js_data[0].js_timeout))) - return -EFAULT; - break; - case JSIOCGTIMEOUT: - if(copy_to_user((void *)arg, &js_data[minor].js_timeout, - sizeof(js_data[0].js_timeout))) - return -EFAULT; - break; - case JSIOCSTIMELIMIT: - if(copy_from_user(&js_data[minor].js_timelimit, - (void *)arg, sizeof(js_data[0].js_timelimit))) - return -EFAULT; - break; - case JSIOCGTIMELIMIT: - if(copy_to_user((void *)arg, &js_data[minor].js_timelimit, - sizeof(js_data[0].js_timelimit))) - return -EFAULT; - break; - case JSIOCGCONFIG: - if(copy_to_user((void *)arg, &js_data[minor], - sizeof(struct js_config))) - return -EFAULT; - break; - case JSIOCSCONFIG: - if(copy_from_user(&js_data[minor], (void *)arg, - sizeof(struct js_config))) - return -EFAULT; - /* Must be busy to do this ioctl! */ - js_data[minor].busy = 1; - break; - default: - return -EINVAL; + int t; + + if (corr->type == JS_CORR_NONE) return value; + t = value > corr->coef[0] ? (value < corr->coef[1] ? corr->coef[0] : value - corr->coef[1] + corr->coef[0]) : value; + if (t == corr->coef[0]) return 32768; + + switch (corr->type) { + case JS_CORR_BROKEN: + t = t < corr->coef[0] ? ((corr->coef[2] * t) >> 14) + corr->coef[3] : + ((corr->coef[4] * t) >> 14) + corr->coef[5]; + break; + default: + return 0; } - return 0; + + if (t < 0) return 0; + if (t > 65535) return 65535; + + return t; } /* - * js_open(): - * device open routine. increments module usage count, initializes - * data for that joystick. - * - * returns: 0 or - * -ENODEV: asked for joystick other than #0 or #1 - * -ENODEV: asked for joystick on axis where there is none - * -EBUSY: attempt to open joystick already open - */ - -static int js_open (struct inode *inode, struct file *file) -{ - unsigned int minor = MINOR (inode->i_rdev); - int j; - - if (minor >= JS_MAX) - return -ENODEV; /*check for joysticks*/ - - for (j = JS_DEF_TIMEOUT; (js_exist & inb (JS_PORT)) && j; j--); - cli(); /*block js_read while js_exist is being modified*/ - /*js minor exists?*/ - if ((((js_exist = inb (JS_PORT)) >> (minor << 1)) & 0x03) == 0x03) { - js_exist = (~js_exist) & 0x0f; - sti(); - return -ENODEV; + * js_compare() compares two close axis values and decides + * whether they are "same". + */ + +static int js_compare(int x, int y, int prec) +{ + return (x < y + prec) && (y < x + prec); +} + +/* + * js_probe() probes for joysticks + */ + +inline int js_probe(void) +{ + int t; + + outb(JS_TRIGGER, JS_PORT); + t = get_pit(); + while (DELTA_T(t, get_pit()) < JS_MAXTIME); + t = inb(JS_PORT); + + if (js[0] || js[1]) { + jsd[0].exist = js[0] & ~(t & JS_AXES); + jsd[1].exist = js[1] & ~(t & JS_AXES); + } else + switch (t & JS_AXES) { + case 0x0c: jsd[0].exist = 0x33; jsd[1].exist = 0x00; break; /* joystick 0 connected */ + case 0x03: jsd[0].exist = 0x00; jsd[1].exist = 0xcc; break; /* joystick 1 connected */ + case 0x04: jsd[0].exist = 0xfb; jsd[1].exist = 0x00; break; /* 3-axis joystick connected */ + case 0x00: jsd[0].exist = 0x33; jsd[1].exist = 0xcc; break; /* joysticks 0 and 1 connected */ + default: jsd[0].exist = 0x00; jsd[1].exist = 0x00; return -1; /* no joysticks */ } - js_exist = (~js_exist) & 0x0f; - sti(); - if (js_data[minor].busy) - return -EBUSY; - js_data[minor].busy = JS_TRUE; - js_data[minor].js_corr.x = JS_DEF_CORR; /*default scale*/ - js_data[minor].js_corr.y = JS_DEF_CORR; - js_data[minor].js_timeout = JS_DEF_TIMEOUT; - js_data[minor].js_timelimit = JS_DEF_TIMELIMIT; - js_data[minor].js_expiretime = jiffies; + js_axes_exist = (jsd[0].exist | jsd[1].exist) & JS_AXES; + js_buttons_exist = (jsd[0].exist | jsd[1].exist) & JS_BUTTONS; - MOD_INC_USE_COUNT; return 0; } -static int js_release (struct inode *inode, struct file *file) +/* + * js_do_timer() controls the action by adding entries to the event + * fifo each time a button changes its state or axis valid time + * expires. + */ + +static void js_do_timer(unsigned long data) { - unsigned int minor = MINOR (inode->i_rdev); - inode->i_atime = CURRENT_TIME; - js_data[minor].busy = JS_FALSE; - MOD_DEC_USE_COUNT; - return 0; + int t = ~inb(JS_PORT) & js_buttons_exist; + if ((js_last_buttons != t) && (js_fifo_head != js_fifo_tail)) { + js_fifo[js_fifo_head].event = js_last_buttons = t; + js_fifo[js_fifo_head].time = jiffies; + js_fifo_head++; + if (js_fifo_head == JS_FIFO_SIZE) js_fifo_head = 0; + if (!js_mark_time) { + js_mark_time = jiffies; + mark_bh(JS_BH); + } + } + else + if ((jiffies > js_axis_time + JS_AXIS_MAX_PERIOD) && !js_mark_time) { + js_mark_time = jiffies; + mark_bh(JS_BH); + } + js_timer.expires = jiffies + JS_BUTTON_PERIOD; + add_timer(&js_timer); } /* - * js_read() reads the buttons x, and y axis from both joysticks if a - * given interval has expired since the last read or is equal to - * -1l. The buttons are in port 0x201 in the high nibble. The axis are - * read by writing to 0x201 and then measuring the time it takes the - * one shots to clear. + * js_do_bh() does the main processing and adds events to output buffers. + */ + +static void js_do_bh(void) +{ + + int i, j, k; + unsigned int t; + + if (jiffies > js_axis_time + JS_AXIS_MIN_PERIOD) { + + unsigned int old_axis[4]; + unsigned int t_low, t_high; + unsigned int flags, joy_state; + unsigned int t1l, t1h, jsm; + unsigned char jss; + unsigned char again; + unsigned char retries = 0; + + for (i = 0; i < 4; i++) + old_axis[i] = js_axis[i].value; + + do { + i = 0; + again = 0; + t_low = 0; + t_high = 0; + joy_state = JS_AXES; + +/* + * Measure the axes. */ -static ssize_t js_read (struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - int j, chk, jsmask; - int t0, t_x0, t_y0, t_x1, t_y1; - unsigned int minor; - int buttons; - struct inode *inode=file->f_dentry->d_inode; + save_flags(flags); + cli(); /* no interrupts */ + outb(JS_TRIGGER, JS_PORT); /* trigger one-shots */ + outb(PIT_READ_TIMER, PIT_MODE); /* read timer */ + t = (t1l = inb(PIT_DATA)) | + (t1h = inb(PIT_DATA)) << 8; + restore_flags(flags); + + do { + jss = inb(JS_PORT); + if ((jss ^ joy_state) & js_axes_exist) { + t_low = (t_low << 8) | t1l; + t_high = (t_high << 8) | t1h; + joy_state = (joy_state << 8) | jss; + i++; + } + + cli(); + outb(PIT_READ_TIMER, PIT_MODE); + t1l = inb(PIT_DATA); + t1h = inb(PIT_DATA); + restore_flags(flags); + + } while ((jss & js_axes_exist) && (DELTA_TX(t, t1l, t1h) < JS_MAXTIME)); + +/* + * Process the gathered axis data in joy_state. + */ + + joy_state ^= ((joy_state >> 8) | 0xff000000L); /* More magic */ + + for (; i > 0; i--) { + for (j = 0; j < 4; j++) + if (joy_state & js_axes_exist & (1 << j)) { + jsm = js_correct(DELTA_TX(t, t_low, t_high), &js_axis[j].corr); + if (!js_compare(jsm, js_axis[j].value, js_axis[j].corr.prec)) { + if (jsm < js_axis[j].value || !retries) + js_axis[j].value = jsm; + again = 1; + } + } + joy_state = joy_state >> 8; + t_low = t_low >> 8; + t_high = t_high >> 8; + } + + } while (retries++ < JS_RETRIES && again); + +/* + * Check if joystick lost. + */ + + for (i = 0; i < JS_NUM; i++) { + + if (jsd[i].exist && ((jss & jsd[i].exist & JS_AXES) == (jsd[i].exist & JS_AXES))) { + printk(KERN_WARNING "js%d: joystick lost.\n", i); + js_buttons_exist &= ~jsd[i].exist; + js_axes_exist &= ~jsd[i].exist; + jsd[i].exist = 0; + wake_up_interruptible(&jsd[i].wait); + } + + if ((jss & jsd[i].exist & JS_AXES)) { + printk(KERN_WARNING "js%d: joystick broken. Check cables.\n", i); + } + + } + +/* + * Put changed axes into output buffer. + */ + + if (retries > 1) + for (i = 0; i < JS_NUM; i++) + if (jsd[i].list) { + k = 0; + for (j = 0; j < 4; j++) + if ((1 << j) & jsd[i].exist) { + if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec)) { + jsd[i].buff[jsd[i].ahead].time = js_mark_time; + jsd[i].buff[jsd[i].ahead].type = JS_EVENT_AXIS; + jsd[i].buff[jsd[i].ahead].number = k; + jsd[i].buff[jsd[i].ahead].value = js_axis[j].value; + jsd[i].ahead++; + if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0; + } + k++; + } + } + js_axis_time = jiffies; + } + js_mark_time = 0; + +/* + * And now process the button fifo. + */ + + while (js_fifo_head != (t = GOFF(js_fifo_tail))) { + for (i = 0; i < JS_NUM; i++) + if (jsd[i].list) { + k = 0; + for (j = 4; j < 8; j++) + if ((1 << j) & jsd[i].exist) { + if ((1 << j) & (js_buttons ^ js_fifo[t].event)) { + jsd[i].buff[jsd[i].ahead].time = js_fifo[t].time; + jsd[i].buff[jsd[i].ahead].type = JS_EVENT_BUTTON; + jsd[i].buff[jsd[i].ahead].number = k; + jsd[i].buff[jsd[i].ahead].value = (js_fifo[t].event >> j) & 1; + jsd[i].ahead++; + if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0; + } + k++; + } + } + js_buttons = js_fifo[js_fifo_tail = t].event; + } + +/* + * Sync ahead with bhead and cut too long tails. + */ - if (count != JS_RETURN) + for (i = 0; i < JS_NUM; i++) + if (jsd[i].list) + if (jsd[i].bhead != jsd[i].ahead) { + if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) { + struct js_list *curl; + curl = jsd[i].list; + while (curl) { + if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) { + curl->tail = jsd[i].ahead; + curl->startup = jsd[i].exist; + } + curl = curl->next; + } + jsd[i].tail = jsd[i].ahead; + } + jsd[i].bhead = jsd[i].ahead; + wake_up_interruptible(&jsd[i].wait); + } + +} + +/* + * js_lseek() just returns with error. + */ + +static loff_t js_lseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* + * js_read() copies one or more entries from jsd[].buff to user + * space. + */ + +static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct wait_queue wait = { current, NULL }; + struct js_list *curl = file->private_data; + struct js_event *buff = (void *) buf; + unsigned long blocks = count / sizeof(struct js_event); + unsigned long i = 0, j; + int t, u = curl->tail; + int retval = 0; + +/* + * Check user data. + */ + + if (MAJOR(file->f_dentry->d_inode->i_rdev) != JOYSTICK_MAJOR) return -EINVAL; - minor = MINOR (inode->i_rdev); - inode->i_atime = CURRENT_TIME; - if (jiffies >= js_data[minor].js_expiretime) - { - j = js_data[minor].js_timeout; - for (; (js_exist & inb (JS_PORT)) && j; j--); - if (j == 0) - return -ENODEV; /*no joystick here*/ - /*Make sure no other proc is using port*/ - - cli(); - js_read_semaphore++; - sti(); - - buttons = ~(inb (JS_PORT) >> 4); - js_data[0].js_save.buttons = buttons & 0x03; - js_data[1].js_save.buttons = (buttons >> 2) & 0x03; - j = js_data[minor].js_timeout; - jsmask = 0; - - cli(); /*no interrupts!*/ - outb (0xff, JS_PORT); /*trigger one-shots*/ - /*get init timestamp*/ - t_x0 = t_y0 = t_x1 = t_y1 = t0 = get_timer0 (); - /*wait for an axis' bit to clear or timeout*/ - do { - chk = (inb (JS_PORT) & js_exist) | jsmask; - if (!(chk & JS_X_0)) { - t_x0 = get_timer0(); - jsmask |= JS_X_0; + if (file->f_pos < 0) + return -EINVAL; + if (!blocks) + return -EINVAL; + if (!curl) + return -EINVAL; + + if (minor > JS_NUM) + return -ENODEV; + if (!jsd[minor].exist) + return -ENODEV; + +/* + * Handle (non)blocking i/o. + */ + + if (count != sizeof(struct JS_DATA_TYPE)) { + + if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) { + add_wait_queue(&jsd[minor].wait, &wait); + current->state = TASK_INTERRUPTIBLE; + while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + schedule(); + if (!jsd[minor].exist) { + retval = -ENODEV; + break; + } } - if (!(chk & JS_Y_0)) { - t_y0 = get_timer0(); - jsmask |= JS_Y_0; + current->state = TASK_RUNNING; + remove_wait_queue(&jsd[minor].wait, &wait); + } + + if (retval) return retval; + +/* + * Do the i/o. + */ + + if (curl->startup) { + struct js_event tmpevent; + + t = 0; + for (j = 0; j < 4 && (i < blocks) && !retval; j++) + if (jsd[minor].exist & (1 << j)) { + if (curl->startup & (1 << j)) { + tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT; + tmpevent.number = t; + tmpevent.value = js_axis[j].value; + if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event))) + retval = -EFAULT; + if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time)) + retval = -EFAULT; + curl->startup &= ~(1 << j); + i++; + } + t++; } - if (!(chk & JS_X_1)) { - t_x1 = get_timer0(); - jsmask |= JS_X_1; + + t = 0; + for (j = 4; j < 8 && (i < blocks) && !retval; j++) + if (jsd[minor].exist & (1 << j)) { + if (curl->startup & (1 << j)) { + tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT; + tmpevent.number = t; + tmpevent.value = (js_buttons >> j) & 1; + if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event))) + retval = -EFAULT; + if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time)) + retval = -EFAULT; + curl->startup &= ~(1 << j); + i++; + } + t++; } - if (!(chk & JS_Y_1)) { - t_y1 = get_timer0(); - jsmask |= JS_Y_1; + } + + + while ((jsd[minor].ahead != (t = GOF(curl->tail))) && (i < blocks) && !retval) { + if (copy_to_user(&buff[i], &jsd[minor].buff[t], sizeof(struct js_event))) + retval = -EFAULT; + if (put_user((__u32)((jsd[minor].buff[t].time - curl->time) * (1000/HZ)), &buff[i].time)) + retval = -EFAULT; + curl->tail = t; + i++; + } + + } + + else + +/* + * Handle version 0.x compatibility. + */ + + { + struct JS_DATA_TYPE *bufo = (void *) buf; + int buttons = 0; + + while (~jsd[minor].exist & (1<x, &js_axis[i].value, sizeof(int)); + + i++; + while (~jsd[minor].exist & (1<y, &js_axis[i].value, sizeof(int)); + + i = 0; + for (j = 4; j < 8; j++) + if ((1 << j) & jsd[minor].exist) + buttons |= (!!(js_last_buttons & (1 << j))) << (i++); + copy_to_user(&bufo->buttons, &buttons, sizeof(int)); + + curl->tail = GOB(jsd[minor].ahead); + retval = sizeof(struct JS_DATA_TYPE); + } + +/* + * Check main tail and move it. + */ + + if (u == jsd[minor].tail) { + t = curl->tail; + curl = jsd[minor].list; + while (curl && curl->tail != jsd[minor].tail) { + if (ROT(jsd[minor].ahead, t, curl->tail) || + (jsd[minor].ahead == curl->tail)) t = curl->tail; + curl = curl->next; + } + if (!curl) jsd[minor].tail = t; + } + + return retval ? retval : i*sizeof(struct js_event); +} + +/* + * js_poll() does select() support. + */ + +static unsigned int js_poll(struct file *file, poll_table *wait) +{ + struct js_list *curl; + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + curl = file->private_data; + + poll_wait(&jsd[minor].wait, wait); + if (GOF(curl->tail) != jsd[minor].ahead) + return POLLIN | POLLRDNORM; + return 0; +} + +/* + * js_ioctl handles misc ioctl calls. + */ + +static int js_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + unsigned int minor = MINOR(inode->i_rdev); + int i, j; + + if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) + return -EINVAL; + if (minor > JS_NUM) + return -ENODEV; + if (!jsd[minor].exist) + return -ENODEV; + + switch (cmd) { + case JSIOCGVERSION: + if(put_user(JS_VERSION, (__u32 *) arg)) return -EFAULT; + break; + case JSIOCGAXES: + if(put_user(count_bits(jsd[minor].exist & JS_AXES), (__u8 *) arg)) return -EFAULT; + break; + case JSIOCGBUTTONS: + if(put_user(count_bits(jsd[minor].exist & JS_BUTTONS), (__u8 *) arg)) return -EFAULT; + break; + case JSIOCSCORR: + j = 0; + for (i = 0; i < 4; i++) + if ((1 << i) & jsd[minor].exist) { + if (copy_from_user(&js_axis[i].corr, (void *) arg + j * sizeof(struct js_corr), + sizeof(struct js_corr))) return -EFAULT; + j++; + } + js_axis_time = 0; + break; + case JSIOCGCORR: + j = 0; + for (i = 0; i < 4; i++) + if ((1 << i) & jsd[minor].exist) { + if (copy_to_user((void *) arg + j * sizeof(struct js_corr), &js_axis[i].corr, + sizeof(struct js_corr))) return -EFAULT; + j++; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * js_open() performs necessary initialization and adds + * an entry to the linked list. + */ + +static int js_open(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct js_list *curl; + int t; + + if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) + return -EINVAL; + if (minor > JS_NUM) + return -ENODEV; + if (!jsd[minor].exist) { + js_probe(); + if (jsd[minor].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n", + minor, count_bits(jsd[minor].exist & JS_AXES), JS_PORT); + else return -ENODEV; + } + + MOD_INC_USE_COUNT; + + if (!jsd[0].list && !jsd[1].list) { + js_timer.expires = jiffies + JS_BUTTON_PERIOD; + add_timer(&js_timer); + } + + curl = jsd[minor].list; + jsd[minor].list = kmalloc(sizeof(struct js_list), GFP_KERNEL); + jsd[minor].list->next = curl; + jsd[minor].list->startup = jsd[minor].exist; + jsd[minor].list->tail = t = GOB(jsd[minor].ahead); + jsd[minor].list->time = jiffies; + + file->private_data = jsd[minor].list; + + return 0; +} + +/* + * js_release() removes an entry from list and deallocates memory + * used by it. + */ + +static int js_release(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct js_list **curp, *curl; + int t; + + curp = &jsd[minor].list; + curl = file->private_data; + + while (*curp && (*curp != curl)) curp = &((*curp)->next); + *curp = (*curp)->next; + + if (jsd[minor].list) { + if (curl->tail == jsd[minor].tail) { + curl = jsd[minor].list; + t = curl->tail; + while (curl && curl->tail != jsd[minor].tail) { + if (ROT(jsd[minor].ahead, t, curl->tail) || + (jsd[minor].ahead == curl->tail)) t = curl->tail; + curl = curl->next; } - } while (--j && jsmask != js_exist); - sti(); /* allow interrupts */ + if (!curl) jsd[minor].tail = t; + } + } - js_read_semaphore = 0; /* allow other reads to progress */ - if (j == 0) - return -ENODEV; /*read timed out*/ - js_data[0].js_expiretime = jiffies + - js_data[0].js_timelimit; /*update data*/ - js_data[1].js_expiretime = jiffies + - js_data[1].js_timelimit; - js_data[0].js_save.x = DELTA_TIME (t0, t_x0) >> - js_data[0].js_corr.x; - js_data[0].js_save.y = DELTA_TIME (t0, t_y0) >> - js_data[0].js_corr.y; - js_data[1].js_save.x = DELTA_TIME (t0, t_x1) >> - js_data[1].js_corr.x; - js_data[1].js_save.y = DELTA_TIME (t0, t_y1) >> - js_data[1].js_corr.y; - } - - if(copy_to_user(buf, &js_data[minor].js_save, JS_RETURN)) - return -EFAULT; - return JS_RETURN; + kfree(file->private_data); + if (!jsd[0].list && !jsd[1].list) del_timer(&js_timer); + + MOD_DEC_USE_COUNT; + return 0; } +/* + * The operations structure. + */ static struct file_operations js_fops = { - NULL, /* js_lseek*/ + js_lseek, /* js_lseek */ js_read, /* js_read */ - NULL, /* js_write*/ - NULL, /* js_readaddr*/ - NULL, /* js_select */ - js_ioctl, /* js_ioctl*/ + NULL, /* js_write */ + NULL, /* js_readdir */ + js_poll, /* js_poll */ + js_ioctl, /* js_ioctl */ NULL, /* js_mmap */ - js_open, /* js_open*/ - js_release, /* js_release*/ - NULL /* js_fsync */ + js_open, /* js_open */ + js_release, /* js_release */ + NULL /* js_sync */ }; -#ifdef MODULE +/* + * js_setup() parses kernel command line parametres. + */ -#define joystick_init init_module +#ifndef MODULE +__initfunc(void js_setup(char *str, int *ints)) -void cleanup_module (void) { - if (unregister_chrdev (JOYSTICK_MAJOR, "joystick")) - printk ("joystick: cleanup_module failed\n"); - release_region(JS_PORT, 1); + js[0] = ((ints[0] > 0) ? ints[1] : 0 ); + js[1] = ((ints[0] > 1) ? ints[2] : 0 ); } +#endif -#endif /* MODULE */ +/* + * js_init() registres the driver and calls the probe function. + * also initializes some crucial variables. + */ -int joystick_init(void) +#ifdef MODULE +int init_module(void) +#else +__initfunc(int js_init(void)) +#endif { - int js_num; - int js_count; + int i; if (check_region(JS_PORT, 1)) { - printk("js_init: port already in use\n"); + printk(KERN_ERR "js: port %#x already in use\n", JS_PORT); return -EBUSY; } - js_num = find_axes(); - js_count = !!(js_num & 0x3) + !!(js_num & 0xC); - - - if (js_count == 0) - { - printk("No joysticks found.\n"); + if (js_probe() < 0) { + printk(KERN_INFO "js: no joysticks found\n"); return -ENODEV; - /* if the user boots the machine, which runs insmod, and THEN - decides to hook up the joystick, well, then we do the wrong - thing. But it's a good idea to avoid giving out a false sense - of security by letting the module load otherwise. */ } - if (register_chrdev (JOYSTICK_MAJOR, "joystick", &js_fops)) { - printk ("Unable to get major=%d for joystick\n", - JOYSTICK_MAJOR); + if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) { + printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR); return -EBUSY; } - request_region(JS_PORT, 1, "joystick"); + + for (i = 0; i < JS_NUM; i++) { + if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n", + i, count_bits(jsd[i].exist & JS_AXES), JS_PORT); + jsd[i].ahead = jsd[i].bhead = 0; + jsd[i].tail = JS_BUFF_SIZE - 1; + jsd[i].list = NULL; + jsd[i].wait = NULL; + memset(jsd[i].buff, 0, JS_BUFF_SIZE * sizeof(struct js_event)); + } + + for (i = 0; i < 4; i++) { + js_axis[i].corr.type = JS_CORR_NONE; + js_axis[i].corr.prec = JS_DEF_PREC; + } + + request_region(JS_PORT, 1, "js"); + init_bh(JS_BH, &js_do_bh); + enable_bh(JS_BH); + init_timer(&js_timer); + js_timer.function = js_do_timer; - for (js_num = 0; js_num < JS_MAX; js_num++) - js_data[js_num].busy = JS_FALSE; - js_read_semaphore = 0; - - printk (KERN_INFO "Found %d joystick%c.\n", - js_count, - (js_num == 1) ? ' ' : 's'); return 0; } +/* + * cleanup_module() handles module removal. + */ + +#ifdef MODULE +void cleanup_module(void) +{ + if (MOD_IN_USE) + printk(KERN_NOTICE "js: device busy, remove delayed\n"); + else { + del_timer(&js_timer); + disable_bh(JS_BH); + if (unregister_chrdev(JOYSTICK_MAJOR, "js")) + printk(KERN_ERR "js: module cleanup failed\n"); + release_region(JS_PORT, 1); + } +} +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.66/linux/drivers/char/misc.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/char/misc.c Sat Nov 29 10:33:19 1997 @@ -116,7 +116,7 @@ return -ENODEV; } - if ((file->f_op = c->fops)) + if ((file->f_op = c->fops) && file->f_op->open) return file->f_op->open(inode,file); else return -ENODEV; diff -u --recursive --new-file v2.1.66/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.1.66/linux/drivers/char/pc110pad.c Tue Sep 23 16:48:47 1997 +++ linux/drivers/char/pc110pad.c Sat Nov 29 10:33:19 1997 @@ -13,6 +13,7 @@ * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation * 0.2 1997-06-03 Robin O'Leary - tap gesture * 0.3 1997-06-27 Alan Cox - 2.1 commit + * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes */ #include @@ -532,7 +533,7 @@ /* * writes are disallowed */ -static long write_pad(struct inode * inode, struct file * file, const char * buffer, unsigned long count) +static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos) { return -EINVAL; } @@ -553,7 +554,7 @@ /* * Read pad data. Currently never blocks. */ -static long read_pad(struct inode * inode, struct file * file, char * buffer, unsigned long count) +static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos) { int r; diff -u --recursive --new-file v2.1.66/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.1.66/linux/drivers/char/pcwd.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/char/pcwd.c Sat Nov 29 10:33:19 1997 @@ -29,7 +29,6 @@ * 961118 Changed some verbiage on some of the output, tidied up * code bits, and added compatibility to 2.1.x. * 970912 Enabled board on open and disable on close. - * 971107 Took account of recent VFS changes (broke read). */ #include @@ -223,7 +222,7 @@ } static int pcwd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { int i, cdat, rv; static struct watchdog_info ident= @@ -360,12 +359,8 @@ return 0; } -static ssize_t pcwd_write(struct file *file, const char *buf, size_t len, - loff_t *ppos) +static long pcwd_write(struct inode *inode, struct file *file, const char *buf, unsigned long len) { - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; if (len) { pcwd_send_heartbeat(); @@ -386,15 +381,11 @@ return(0); } -static ssize_t pcwd_read(struct file *file, char *buf, size_t count, - loff_t *ppos) +static ssize_t pcwd_read(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned short c = inb(current_readport); unsigned char cp; - /* Can't seek (pread) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; switch(MINOR(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: @@ -497,16 +488,11 @@ pcwd_read, /* Read */ pcwd_write, /* Write */ NULL, /* Readdir */ - NULL, /* Poll */ + NULL, /* Select */ pcwd_ioctl, /* IOctl */ NULL, /* MMAP */ pcwd_open, /* Open */ - pcwd_close, /* Release */ - NULL, /* Fsync */ - NULL, /* Fasync */ - NULL, /* CheckMediaChange */ - NULL, /* Revalidate */ - NULL, /* Lock */ + pcwd_close /* Close */ }; static struct miscdevice pcwd_miscdev = { diff -u --recursive --new-file v2.1.66/linux/drivers/char/pms.c linux/drivers/char/pms.c --- v2.1.66/linux/drivers/char/pms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/pms.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,1069 @@ +/* + * Media Vision Pro Movie Studio + * or + * "all you need is an I2C bus some RAM and a prayer" + * + * This draws heavily on code + * + * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994 + * Kiefernring 15 + * 14478 Potsdam, Germany + * + * Most of this code is directly derived from his userspace driver. + * His driver works so send any reports to alan@cymru.net unless the + * userspace driver also doesnt work for you... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MOTOROLA 1 +#define PHILIPS2 2 +#define PHILIPS1 3 +#define MVVMEMORYWIDTH 0x40 /* 512 bytes */ + +struct pms_device +{ + struct video_device v; + struct video_picture picture; + int height; + int width; +}; + +struct i2c_info +{ + u8 slave; + u8 sub; + u8 data; + u8 hits; +}; + +static int i2c_count = 0; +static struct i2c_info i2cinfo[64]; + +static int decoder = PHILIPS2; +static int standard = 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */ + +/* + * I/O ports and Shared Memory + */ + +static int io_port = 0x250; +static int data_port = 0x251; +static int mem_base = 0xC8000; + + + +extern __inline__ void mvv_write(u8 index, u8 value) +{ + outw(index|(value<<8), io_port); +} + +extern __inline__ u8 mvv_read(u8 index) +{ + outb(index, io_port); + return inb(data_port); +} + +extern int i2c_stat(u8 slave) +{ + int counter; + int i; + + outb(0x28, io_port); + + counter=0; + while((inb(data_port)&0x01)==0) + if(counter++==256) + break; + + while((inb(data_port)&0x01)!=0) + if(counter++==256) + break; + + outb(slave, io_port); + + counter=0; + while((inb(data_port)&0x01)==0) + if(counter++==256) + break; + + while((inb(data_port)&0x01)!=0) + if(counter++==256) + break; + + for(i=0;i<12;i++) + { + char st=inb(data_port); + if((st&2)!=0) + return -1; + if((st&1)==0) + break; + } + outb(0x29, io_port); + return inb(data_port); +} + +int i2c_write(u16 slave, u16 sub, u16 data) +{ + int skip=0; + int count; + int i; + + for(i=0;i255) + break; + while((inb(data_port)&1)!=0) + if(count>255) + break; + + count=inb(data_port); + + if(count&2) + return -1; + return count; +} + +int i2c_read(int slave, int sub) +{ + int i=0; + for(i=0;i32) + { + deciden/=2; + decinum=(decinum+1)/2; + } + if(deciden==32) + deciden--; + pms_vert(deciden,decinum); +} + +static void pms_horzdeci(short decinum, short deciden) +{ + if(decinum<=512) + { + if(decinum%5==0) + { + decinum/=5; + deciden/=5; + } + } + else + { + decinum=512; + deciden=640; /* 768 would be ideal */ + } + + while(decinum%2==0 && deciden%2==0) + { + decinum/=2; + deciden/=2; + } + while(deciden>32) + { + deciden/=2; + decinum=(decinum+1)/2; + } + if(deciden==32) + deciden--; + + mvv_write(0x24, 0x80|deciden); + mvv_write(0x25, deciden); +} + +static void pms_resolution(short width, short height) +{ + int fg_height; + + fg_height=height; + if(fg_height>280) + fg_height=280; + + mvv_write(0x18, fg_height); + mvv_write(0x19, fg_height>>8); + + if(standard==1) + { + mvv_write(0x1A, 0xFC); + mvv_write(0x1B, 0x00); + if(height>width) + pms_vertdeci(240,240); + else + pms_vertdeci(fg_height,240); + } + else + { + mvv_write(0x1A, 0x1A); + mvv_write(0x1B, 0x01); + if(fg_height>256) + pms_vertdeci(270,270); + else + pms_vertdeci(fg_height, 270); + } + mvv_write(0x12,0); + mvv_write(0x13, MVVMEMORYWIDTH); + mvv_write(0x42, 0x00); + mvv_write(0x43, 0x00); + mvv_write(0x44, MVVMEMORYWIDTH); + + mvv_write(0x22, width+8); + mvv_write(0x23, (width+8)>> 8); + + if(standard==1) + pms_horzdeci(width,640); + else + pms_horzdeci(width+8, 768); + + mvv_write(0x30, mvv_read(0x30)&0xFE); + mvv_write(0x08, mvv_read(0x08)|0x01); + mvv_write(0x01, mvv_read(0x01)&0xFD); + mvv_write(0x32, 0x00); + mvv_write(0x33, MVVMEMORYWIDTH); +} + +static void pms_vstart(short start) +{ + mvv_write(0x16, start); + mvv_write(0x17, (start>>8)&0x01); +} + +/* + * Set Input + */ + +static void pms_vcrinput(short input) +{ + if(decoder==PHILIPS2) + i2c_andor(0x8A,0x0D,0x7F,(input&1)<<7); + else if(decoder==PHILIPS1) + i2c_andor(0x42,0x0D,0x7F,(input&1)<<7); +} + + +static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count) +{ + char dump[16]; + int y; + int ww= dev->width, wh= dev->height; + int dinc, zz; + int dw=2*ww, loops; + unsigned char r8; + int len=0; + + short *dst=(short *)buf; + short *src=(short *)bus_to_virt((void *)mem_base); + + if(wh>256) + { + dinc=2*ww; + zz=wh/2; + loops=2; + } + else + { + dinc=ww; + zz=wh; + loops=1; + } + + + r8=0x5; + if(rgb555) + r8|=0x20; + +field_cap: + + mvv_write(0x08, r8); /* Capture mode, Enable DRAM, PC enable */ + + for(y=0;ydw) /* But only as many as needed */ + n=dw; + memcpy(dump, src, 16); /* Junk */ + if(n) + copy_to_user(dst, src, n); /* Data */ + dst+=dinc; + *src=0; /* Synchronization */ + } + + if(--loops>0) + { + mvv_write(0x14, mvv_read(0x14)|0xC0); /* Other frame */ + dst=(short *)buf+ww; + goto field_cap; + } + + /* + * Set back to capture even frames + */ + + if(wh>256) + mvv_write(0x14, (mvv_read(0x14)|0x80)&~0x40); + return len; +} + + +/* + * Video4linux interfacing + */ + +static int pms_open(struct video_device *dev, int flags) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void pms_close(struct video_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +static int pms_init_done(struct video_device *dev) +{ + return 0; +} + +static long pms_write(struct video_device *v, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static int pms_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct pms_device *pd=(struct pms_device *)dev; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, "Mediavision PMS"); + b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES; + b.channels = 4; + b.audios = 0; + b.maxwidth = 640; + b.maxheight = 480; + b.minwidth = 16; + b.minheight = 16; + if(copy_to_user(arg, &b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.channel<0 || v.channel>3) + return -EINVAL; + v.flags=0; + v.tuners=1; + /* Good question.. its composite or SVHS so.. */ + v.type = VIDEO_TYPE_CAMERA; + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSCHAN: + { + int v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v<0 && v>3) + return -EINVAL; + pms_videosource(v&1); + pms_vcrinput(v>>1); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + strcpy(v.name, "Format"); + v.rangelow=0; + v.rangehigh=0; + v.flags= VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + switch(standard) + { + case 0: + v.mode = VIDEO_MODE_AUTO; + break; + case 1: + v.mode = VIDEO_MODE_NTSC; + break; + case 2: + v.mode = VIDEO_MODE_PAL; + break; + case 3: + v.mode = VIDEO_MODE_SECAM; + break; + } + if(copy_to_user(arg,&v,sizeof(v))!=0) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + switch(v.mode) + { + case VIDEO_MODE_AUTO: + pms_framerate(25); + pms_secamcross(0); + pms_format(0); + break; + case VIDEO_MODE_NTSC: + pms_framerate(30); + pms_secamcross(0); + pms_format(1); + break; + case VIDEO_MODE_PAL: + pms_framerate(25); + pms_secamcross(0); + pms_format(2); + break; + case VIDEO_MODE_SECAM: + pms_framerate(25); + pms_secamcross(1); + pms_format(2); + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=pd->picture; + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + if(copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + if(!((p.palette==VIDEO_PALETTE_RGB565 && p.depth==16) + ||(p.palette==VIDEO_PALETTE_RGB555 && p.depth==15))) + return -EINVAL; + pd->picture=p; + + /* + * Now load the card. + */ + + pms_brightness(p.brightness); + pms_hue(p.hue); + pms_colour(p.colour); + pms_contrast(p.contrast); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + if(copy_from_user(&vw, arg,sizeof(vw))) + return -EFAULT; + if(vw.flags) + return -EINVAL; + if(vw.clipcount) + return -EINVAL; + if(vw.height<16||vw.height>480) + return -EINVAL; + if(vw.width<16||vw.width>640) + return -EINVAL; + pd->width=vw.width; + pd->height=vw.height; + pms_resolution(pd->width, pd->height); + /* Ok we figured out what to use from our wide choice */ + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + vw.x=0; + vw.y=0; + vw.width=pd->width; + vw.height=pd->height; + vw.chromakey=0; + vw.flags=0; + if(copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + return -EINVAL; + case VIDIOCGFBUF: + return -EINVAL; + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCKEY: + return 0; + case VIDIOCGFREQ: + return -EINVAL; + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + return -EINVAL; + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static long pms_read(struct video_device *v, char *buf, unsigned long count, int noblock) +{ + struct pms_device *pd=(struct pms_device *)v; + int len; + + /* FIXME: semaphore this */ + len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count); + return len; +} + + +struct video_device pms_template= +{ + "Mediavision PMS", + VID_TYPE_CAPTURE, + VID_HARDWARE_PMS, + pms_open, + pms_close, + pms_read, + pms_write, + pms_ioctl, + NULL, + pms_init_done, + NULL, + 0, + 0 +}; + +struct pms_device pms_device; + + +/* + * Probe for and initialise the Mediavision PMS + */ + +static int init_mediavision(void) +{ + int id; + int idec, decst; + int i; + + unsigned char i2c_defs[]={ + 0x4C,0x30,0x00,0xE8, + 0xB6,0xE2,0x00,0x00, + 0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x78,0x98, + 0x00,0x00,0x00,0x00, + 0x34,0x0A,0xF4,0xCE, + 0xE4 + }; + + if(check_region(0x9A01,1)) + { + printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n"); + return -EBUSY; + } + if(check_region(io_port,3)) + { + printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port); + return -EBUSY; + } + outb(0xB8, 0x9A01); /* Unlock */ + outb(io_port>>4, 0x9A01); /* Set IO port */ + + + id=mvv_read(3); + decst=i2c_stat(0x43); + + if(decst!=-1) + idec=2; + else if(i2c_stat(0xb9)!=-1) + idec=3; + else if(i2c_stat(0x8b)!=-1) + idec=1; + else + idec=0; + + if(idec==0) + return -ENODEV; + + /* + * Ok we have a PMS of some sort + */ + + request_region(io_port,3, "Mediavision PMS"); + request_region(0x9A01, 1, "Mediavision PMS config"); + + mvv_write(0x04, mem_base>>12); /* Set the memory area */ + + /* Ok now load the defaults */ + + for(i=0;i<0x19;i++) + { + if(i2c_defs[i]==0xFF) + i2c_andor(0x8A, i, 0x07,0x00); + else + i2c_write(0x8A, i, i2c_defs[i]); + } + + i2c_write(0xB8,0x00,0x12); + i2c_write(0xB8,0x04,0x00); + i2c_write(0xB8,0x07,0x00); + i2c_write(0xB8,0x08,0x00); + i2c_write(0xB8,0x09,0xFF); + i2c_write(0xB8,0x0A,0x00); + i2c_write(0xB8,0x0B,0x10); + i2c_write(0xB8,0x10,0x03); + + mvv_write(0x01, 0x00); + mvv_write(0x05, 0xA0); + mvv_write(0x08, 0x25); + mvv_write(0x09, 0x00); + mvv_write(0x0A, 0x20|MVVMEMORYWIDTH); + + mvv_write(0x10, 0x02); + mvv_write(0x1E, 0x0C); + mvv_write(0x1F, 0x03); + mvv_write(0x26, 0x06); + + mvv_write(0x2B, 0x00); + mvv_write(0x2C, 0x20); + mvv_write(0x2D, 0x00); + mvv_write(0x2F, 0x70); + mvv_write(0x32, 0x00); + mvv_write(0x33, MVVMEMORYWIDTH); + mvv_write(0x34, 0x00); + mvv_write(0x35, 0x00); + mvv_write(0x3A, 0x80); + mvv_write(0x3B, 0x10); + mvv_write(0x20, 0x00); + mvv_write(0x21, 0x00); + mvv_write(0x30, 0x22); + return 0; +} + +static void shutdown_mediavision(void) +{ + release_region(io_port,3); + release_region(0x9A01, 1); +} + +/* + * Module stuff + */ + +#ifdef MODULE + +int init_module(void) +{ + printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.01\n"); + if(init_mediavision()) + { + printk(KERN_INFO "Board not found.\n"); + return -ENODEV; + } + memcpy(&pms_device, &pms_template, sizeof(pms_template)); + pms_device.height=240; + pms_device.width=320; + pms_resolution(320,240); + return video_register_device((struct video_device *)&pms_device); +} + +void cleanup_module(void) +{ + shutdown_mediavision(); + video_unregister_device((struct video_device *)&pms_device); +} + +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.1.66/linux/drivers/char/softdog.c Mon Jun 16 16:35:55 1997 +++ linux/drivers/char/softdog.c Sat Nov 29 10:33:19 1997 @@ -113,7 +113,7 @@ return; } -static long softdog_write(struct inode *inode, struct file *file, const char *data, unsigned long len) +static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) { /* * Refresh the timer. diff -u --recursive --new-file v2.1.66/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.1.66/linux/drivers/char/tpqic02.c Tue Sep 23 16:48:47 1997 +++ linux/drivers/char/tpqic02.c Sat Nov 29 10:33:19 1997 @@ -1750,11 +1750,10 @@ * request would return the EOF flag for the previous file. */ -static long qic02_tape_read(struct inode * inode, struct file * filp, - char * buf, unsigned long count) +static ssize_t qic02_tape_read(struct file * filp, char * buf, size_t count, loff_t *ppos) { int err; - kdev_t dev = inode->i_rdev; + kdev_t dev = filp->f_dentry->d_inode->i_rdev; unsigned short flags = filp->f_flags; unsigned long bytes_todo, bytes_done, total_bytes_done = 0; int stat; @@ -1925,7 +1924,7 @@ { status_bytes_rd = YES; buf += bytes_done; - filp->f_pos += bytes_done; + *ppos += bytes_done; total_bytes_done += bytes_done; count -= bytes_done; } @@ -1964,11 +1963,11 @@ * tape device again. The driver will detect an exception status in (No Cartridge) * and force a rewind. After that tar may continue writing. */ -static long qic02_tape_write(struct inode * inode, struct file * filp, - const char * buf, unsigned long count) +static ssize_t qic02_tape_write( struct file * filp, const char * buf, + size_t count, loff_t *ppos) { int err; - kdev_t dev = inode->i_rdev; + kdev_t dev = filp->f_dentry->d_inode->i_rdev; unsigned short flags = filp->f_flags; unsigned long bytes_todo, bytes_done, total_bytes_done = 0; @@ -2120,7 +2119,7 @@ { status_bytes_wr = YES; buf += bytes_done; - filp->f_pos += bytes_done; + *ppos += bytes_done; total_bytes_done += bytes_done; count -= bytes_done; } diff -u --recursive --new-file v2.1.66/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.66/linux/drivers/char/tty_io.c Wed Nov 26 16:24:02 1997 +++ linux/drivers/char/tty_io.c Sat Nov 29 10:06:22 1997 @@ -1140,27 +1140,9 @@ } /* - * Make sure that the tty's task queue isn't activated. If it - * is, take it out of the linked list. The tqueue isn't used by - * pty's, so skip the test for them. + * Make sure that the tty's task queue isn't activated. */ - if (tty->driver.type != TTY_DRIVER_TYPE_PTY) { - spin_lock_irq(&tqueue_lock); - if (tty->flip.tqueue.sync) { - struct tq_struct *tq, *prev; - - for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { - if (tq == &tty->flip.tqueue) { - if (prev) - prev->next = tq->next; - else - tq_timer = tq->next; - break; - } - } - } - spin_unlock_irq(&tqueue_lock); - } + run_task_queue(&tq_timer); /* * The release_mem function takes care of the details of clearing diff -u --recursive --new-file v2.1.66/linux/drivers/char/tuner.h linux/drivers/char/tuner.h --- v2.1.66/linux/drivers/char/tuner.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/tuner.h Sat Nov 29 10:33:19 1997 @@ -0,0 +1,59 @@ +/* + tuner.h - definition for different tuners + + Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) + minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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. +*/ + +#ifndef _TUNER_H +#define _TUNER_H + +#define TUNER_TEMIC_PAL 0 /* Miro Gpio Coding -1 */ +#define TUNER_PHILIPS_PAL_I 1 +#define TUNER_PHILIPS_NTSC 2 +#define TUNER_PHILIPS_SECAM 3 +#define TUNER_ABSENT 4 +#define TUNER_PHILIPS_PAL 5 +#define TUNER_TEMIC_NTSC 6 +#define TUNER_TEMIC_PAL_I 7 + +#define NOTUNER 0 +#define PAL 1 +#define PAL_I 2 +#define NTSC 3 +#define SECAM 4 + +#define NoTuner 0 +#define Philips 1 +#define TEMIC 2 +#define Sony 3 + +struct tunertype { + char *name; + unchar Vendor; + unchar Type; + + ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */ + ushort thresh2; + unchar VHF_L; + unchar VHF_H; + unchar UHF; + unchar config; + unchar I2C; +}; +#endif + diff -u --recursive --new-file v2.1.66/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.1.66/linux/drivers/char/videodev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/videodev.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,264 @@ +/* + * Video capture interface for Linux + * + * A generic video device interface for the LINUX operating system + * using a set of device structures/vectors for low level operations. + * + * 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: Alan Cox, + * + * Fixes: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define VIDEO_NUM_DEVICES 256 + +/* + * Active devices + */ + +static struct video_device *video_device[VIDEO_NUM_DEVICES]; + +/* + * Initialiser list + */ + +struct video_init +{ + char *name; + int (*init)(struct video_init *); +}; + +extern int init_bttv_cards(struct video_init *); + +static struct video_init video_init_list[]={ +#ifdef CONFIG_VIDEO_BT848 + {"bttv", init_bttv_cards}, +#endif +#ifdef CONFIG_VIDEO_BWQCAM + {"bttv", init_bw_qcams}, +#endif +#ifdef CONFIG_VIDEO_PMS + {"bttv", init_pms_cards}, +#endif + {"end", NULL} +}; + + +/* + * Read will do some smarts later on. Buffer pin etc. + */ + +static ssize_t video_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int err; + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); +} + +/* + * Write for now does nothing. No reason it shouldnt do overlay setting + * for some boards I guess.. + */ + +static ssize_t video_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + int err; + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); +} + +/* + * Open a video device. + */ + +static int video_open(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + int err; + struct video_device *vfl; + + if(minor>=VIDEO_NUM_DEVICES) + return -ENODEV; + + vfl=video_device[minor]; + if(vfl==NULL) + return -ENODEV; + if(vfl->busy) + return -EBUSY; + vfl->busy=1; /* In case vfl->open sleeps */ + + if(vfl->open) + { + err=vfl->open(vfl,0); /* Tell the device it is open */ + if(err) + { + vfl->busy=0; + return err; + } + } + return 0; +} + +/* + * Last close of a video for Linux device + */ + +static int video_release(struct inode *inode, struct file *file) +{ + struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + if(vfl->close) + vfl->close(vfl); + vfl->busy=0; + return 0; +} + +/* + * Question: Should we be able to capture and then seek around the + * image ? + */ + +static long long video_lseek(struct file * file, + long long offset, int origin) +{ + return -ESPIPE; +} + + +static int video_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + int err=vfl->ioctl(vfl, cmd, (void *)arg); + + if(err!=-ENOIOCTLCMD) + return err; + + switch(cmd) + { + default: + return -EINVAL; + } +} + +/* + * We need to do MMAP support + */ + +/* + * Video For Linux device drivers request registration here. + */ + +int video_register_device(struct video_device *vfd) +{ + int i=0; + int base=0; + int err; + + for(i=base;iminor=i; + /* The init call may sleep so we book the slot out + then call */ + MOD_INC_USE_COUNT; + err=vfd->initialize(vfd); + if(err<0) + { + video_device[i]=NULL; + MOD_DEC_USE_COUNT; + return err; + } + return 0; + } + } + return -ENFILE; +} + +/* + * Unregister an unused video for linux device + */ + +void video_unregister_device(struct video_device *vfd) +{ + if(video_device[vfd->minor]!=vfd) + panic("vfd: bad unregister"); + video_device[vfd->minor]=NULL; + MOD_DEC_USE_COUNT; +} + + +static struct file_operations video_fops= +{ + video_lseek, + video_read, + video_write, + NULL, /* readdir */ + NULL, /* poll */ + video_ioctl, + NULL, /* mmap */ + video_open, + video_release +}; + +/* + * Initialise video for linux + */ + +int videodev_init(void) +{ + struct video_init *vfli = video_init_list; + + printk(KERN_INFO "Linux video capture interface: v0.01 ALPHA\n"); + if(register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops)) + { + printk("video_dev: unable to get major %d\n", VIDEO_MAJOR); + return -EIO; + } + + /* + * Init kernel installed video drivers + */ + + while(vfli->init!=NULL) + { + vfli->init(vfli); + vfli++; + } + return 0; +} + + +int init_module(void) +{ + return videodev_init(); +} + +void cleanup_module(void) +{ + unregister_chrdev(VIDEO_MAJOR, "video_capture"); +} + +EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(video_unregister_device); diff -u --recursive --new-file v2.1.66/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.1.66/linux/drivers/char/wdt.c Tue Sep 23 16:48:47 1997 +++ linux/drivers/char/wdt.c Sat Nov 29 10:33:19 1997 @@ -169,7 +169,7 @@ outb_p(0, WDT_DC); } -static long wdt_write(struct inode *inode, struct file *file, const char *buf, unsigned long count) +static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { if(count) { @@ -183,13 +183,13 @@ * Read reports the temperature in farenheit */ -static long wdt_read(struct inode *inode, struct file *file, char *buf, unsigned long count) +static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr) { unsigned short c=inb_p(WDT_RT); unsigned char cp; int err; - switch(MINOR(inode->i_rdev)) + switch(MINOR(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: err=verify_area(VERIFY_WRITE, buf, 1); diff -u --recursive --new-file v2.1.66/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.66/linux/drivers/net/Config.in Tue Sep 23 16:48:48 1997 +++ linux/drivers/net/Config.in Sat Nov 29 10:33:19 1997 @@ -140,9 +140,9 @@ fi fi -if [ ! "$CONFIG_PARPORT" = "n" ]; then - dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT -fi +#if [ ! "$CONFIG_PARPORT" = "n" ]; then +# dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT +#fi tristate 'PPP (point-to-point) support' CONFIG_PPP if [ ! "$CONFIG_PPP" = "n" ]; then @@ -181,7 +181,7 @@ bool 'HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS fi fi - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP +# tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN fi diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.DLINK linux/drivers/net/README.DLINK --- v2.1.66/linux/drivers/net/README.DLINK Wed Aug 10 09:26:00 1994 +++ linux/drivers/net/README.DLINK Wed Dec 31 16:00:00 1969 @@ -1,205 +0,0 @@ -Released 1994-06-13 - - - CONTENTS: - - 1. Introduction. - 2. License. - 3. Files in this release. - 4. Installation. - 5. Problems and tuning. - 6. Using the drivers with earlier releases. - 7. Acknowledgments. - - - 1. INTRODUCTION. - - This is a set of Ethernet drivers for the D-Link DE-600/DE-620 - 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. - - I have used these drivers for NFS, ftp, telnet and X-clients on - remote machines. Transmissions with ftp seems to work as - good as can be expected (i.e. > 80k bytes/sec) from a - parallel port...:-) Receive speeds will be about 60-80% of this. - Depending on your machine, somewhat higher speeds can be achieved. - - All comments/fixes to Bjorn Ekwall (bj0rn@blox.se). - - - 2. LICENSE. - - 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. - - 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. - - - 3. FILES IN THIS RELEASE. - - README.DLINK This file. - de600.c The Source (,may it be with You :-) for the DE-600 - de620.c ditto for the DE-620 - 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: - linux/drivers/net/Makefile - linux/drivers/net/CONFIG - linux/drivers/net/MODULES - linux/drivers/net/Space.c - linux/config.in - Apply the patch by: - "cd /usr/src; patch -p0 < linux/drivers/net/dlink-patches" - The old source, "linux/drivers/net/d_link.c", can be removed. - - - 4. INSTALLATION. - - o Get the latest net binaries, according to current net.wisdom. - - o Read the NET-2 and Ethernet HOWTO's and modify your setup. - - o If your parallel port has a strange address or irq, - modify "linux/drivers/net/CONFIG" accordingly, or adjust - the parameters in the "tuning" section in the sources. - - If you are going to use the drivers a loadable modules, do _not_ - enable them while doing "make config", but instead make sure that - the drivers are included in "linux/drivers/net/MODULES". - - If you are _not_ going to use the driver(s) as loadable modules, - but instead have them included in the kernel, remember to enable - the drivers while doing "make config". - - o To include networking and DE600/DE620 support in your kernel: - # cd /linux - (as modules:) - # make config (answer yes on CONFIG_NET and CONFIG_INET) - (else included in the kernel:) - # make config (answer yes on CONFIG _NET, _INET and _DE600 or _DE620) - # make clean - # make depend - # make zImage (or whatever magic you usually do) - - o I use lilo to boot multiple kernels, so that I at least - can have one working kernel :-). If you do too, append - these lines to /etc/lilo/config: - - image = /linux/zImage - label = newlinux - root = /dev/hda2 (or whatever YOU have...) - - # /etc/lilo/install - - o Do "sync" and reboot the new kernel with a D-Link - DE-600/DE-620 pocket adapter connected. - - o The adapter can be configured with ifconfig eth? - where the actual number is decided by the kernel - when the drivers are initialized. - - - 5. "PROBLEMS" AND TUNING, - - o If you see error messages from the driver, and if the traffic - stops on the adapter, try to do "ifconfig" and "route" once - more, just as in "rc.inet1". This should take care of most - problems, including effects from power loss, or adapters that - aren't connected to the printer port in some way or another. - You can somewhat change the behaviour by enabling/disabling - the macro SHUTDOWN_WHEN_LOST in the "tuning" section. - For the DE-600 there is another macro, CHECK_LOST_DE600, - that you might want to read about in the "tuning" section. - - o Some machines have trouble handling the parallel port and - the adapter at high speed. If you experience problems: - - DE-600: - - The adapter is not recognized at boot, i.e. an Ethernet - address of 00:80:c8:... is not shown, try to add another - "; SLOW_DOWN_IO" - at DE600_SLOW_DOWN in the "tuning" section. As a last resort, - uncomment: "#define REALLY_SLOW_IO" (see for hints). - - - You experience "timeout" messages: first try to add another - "; SLOW_DOWN_IO" - at DE600_SLOW_DOWN in the "tuning" section, _then_ try to - increase the value (original value: 5) at - "if (tickssofar < 5)" near line 422. - - DE-620: - - Your parallel port might be "sluggish". To cater for - this, there are the macros LOWSPEED and READ_DELAY/WRITE_DELAY - in the "tuning" section. Your first step should be to enable - LOWSPEED, and after that you can "tune" the XXX_DELAY values. - - o If the adapter _is_ recognized at boot but you get messages - about "Network Unreachable", then the problem is probably - _not_ with the driver. Check your net configuration instead - (ifconfig and route) in "rc.inet1". - - o There is some rudimentary support for debugging, look at - the source. Use "-DDE600_DEBUG=3" or "-DDE620_DEBUG=3" - when compiling, or include it in "linux/drivers/net/CONFIG". - IF YOU HAVE PROBLEMS YOU CAN'T SOLVE: PLEASE COMPILE THE DRIVER - WITH DEBUGGING ENABLED, AND SEND ME THE RESULTING OUTPUT! - - - 6. USING THE DRIVERS WITH EARLIER RELEASES. - - The later v1.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 - all releases on-line. - Known needed changes to date: - - release patchfile: some patches will fail, but they should - be easy to apply "by hand", since they are trivial. - (Space.c: d_link_init() is now called de600_probe()) - - de600.c: change "mark_bh(NET_BH)" to "mark_bh(INET_BH)". - - de620.c: (maybe) change the code around "netif_rx(skb);" to be - similar to the code around "dev_rint(...)" in de600.c - - - 7. ACKNOWLEDGMENTS. - - These drivers wouldn't have been done without the base - (and support) from Ross Biro , - and D-Link Systems Inc. The driver relies upon GPL-ed - source from D-Link Systems Inc. and from Russel Nelson at - Crynwr Software . - - Additional input also from: - Donald Becker , Alan Cox - and Fred N. van Kempen - - DE-600 alpha release primary victim^H^H^H^H^H^Htester: - - Erik Proper . - Good input also from several users, most notably - - Mark Burton . - - DE-620 alpha release victims^H^H^H^H^H^H^Htesters: - - J. Joshua Kopper - - Olav Kvittem - - Germano Caronni - - Jeremy Fitzhardinge - - - Happy hacking! - - Bjorn Ekwall == bj0rn@blox.se diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.de4x5 linux/drivers/net/README.de4x5 --- v2.1.66/linux/drivers/net/README.de4x5 Mon Nov 17 18:47:21 1997 +++ linux/drivers/net/README.de4x5 Wed Dec 31 16:00:00 1969 @@ -1,143 +0,0 @@ - Originally, this driver was written for the Digital Equipment - Corporation series of EtherWORKS ethernet cards: - - DE425 TP/COAX EISA - DE434 TP PCI - DE435 TP/COAX/AUI PCI - DE450 TP/COAX/AUI PCI - DE500 10/100 PCI Fasternet - - but it will now attempt to support all cards which conform to the - Digital Semiconductor SROM Specification. The driver currently - recognises the following chips: - - DC21040 (no SROM) - DC21041[A] - DC21140[A] - DC21142 - DC21143 - - So far the driver is known to work with the following cards: - - KINGSTON - Linksys - ZNYX342 - SMC8432 - SMC9332 (w/new SROM) - ZNYX31[45] - ZNYX346 10/100 4 port (can act as a 10/100 bridge!) - - The driver has been tested on a relatively busy network using the DE425, - DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred - 16M of data to a DECstation 5000/200 as follows: - - TCP UDP - TX RX TX RX - DE425 1030k 997k 1170k 1128k - DE434 1063k 995k 1170k 1125k - DE435 1063k 995k 1170k 1125k - DE500 1063k 998k 1170k 1125k in 10Mb/s mode - - All values are typical (in kBytes/sec) from a sample of 4 for each - measurement. Their error is +/-20k on a quiet (private) network and also - depend on what load the CPU has. - - ========================================================================= - - The ability to load this driver as a loadable module has been included - and used extensively during the driver development (to save those long - reboot sequences). Loadable module support under PCI and EISA has been - achieved by letting the driver autoprobe as if it were compiled into the - kernel. Do make sure you're not sharing interrupts with anything that - cannot accommodate interrupt sharing! - - To utilise this ability, you have to do 8 things: - - 0) have a copy of the loadable modules code installed on your system. - 1) copy de4x5.c from the /linux/drivers/net directory to your favourite - temporary directory. - 2) for fixed autoprobes (not recommended), edit the source code near - line 5537 to reflect the I/O address you're using, or assign these when - loading by: - - insmod de4x5 io=0xghh where g = bus number - hh = device number - - NB: autoprobing for modules is now supported by default. You may just - use: - - insmod de4x5 - - to load all available boards. For a specific board, still use - the 'io=?' above. - 3) compile de4x5.c, but include -DMODULE in the command line to ensure - that the correct bits are compiled (see end of source code). - 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a - kernel with the de4x5 configuration turned off and reboot. - 5) insmod de4x5 [io=0xghh] - 6) run the net startup bits for your new eth?? interface(s) manually - (usually /etc/rc.inet[12] at boot time). - 7) enjoy! - - To unload a module, turn off the associated interface(s) - 'ifconfig eth?? down' then 'rmmod de4x5'. - - Automedia detection is included so that in principal you can disconnect - from, e.g. TP, reconnect to BNC and things will still work (after a - pause whilst the driver figures out where its media went). My tests - using ping showed that it appears to work.... - - By default, the driver will now autodetect any DECchip based card. - Should you have a need to restrict the driver to DIGITAL only cards, you - can compile with a DEC_ONLY define, or if loading as a module, use the - 'dec_only=1' parameter. - - The SMC9332 card has a non-compliant SROM which needs fixing - I have - patched this driver to detect it because the SROM format used complies - to a previous DEC-STD format. - - I have removed the buffer copies needed for receive on Intels. I cannot - remove them for Alphas since the Tulip hardware only does longword - aligned DMA transfers and the Alphas get alignment traps with non - longword aligned data copies (which makes them really slow). No comment. - - I have added SROM decoding routines to make this driver work with any - card that supports the Digital Semiconductor SROM spec. This will help - all cards running the dc2114x series chips in particular. Cards using - the dc2104x chips should run correctly with the basic driver. I'm in - debt to for the testing and feedback that helped get - this feature working. So far we have tested KINGSTON, SMC8432, SMC9332 - (with the latest SROM complying with the SROM spec V3: their first was - broken), ZNYX342 and LinkSys. ZYNX314 (dual 21041 MAC) and ZNYX 315 - (quad 21041 MAC) cards also appear to work despite their incorrectly - wired IRQs. - - I have added a temporary fix for interrupt problems when some SCSI cards - share the same interrupt as the DECchip based cards. The problem occurs - because the SCSI card wants to grab the interrupt as a fast interrupt - (runs the service routine with interrupts turned off) vs. this card - which really needs to run the service routine with interrupts turned on. - This driver will now add the interrupt service routine as a fast - interrupt if it is bounced from the slow interrupt. THIS IS NOT A - RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time - until people sort out their compatibility issues and the kernel - interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST - INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not - run on the same interrupt. PCMCIA/CardBus is another can of worms... - - Finally, I think I have really fixed the module loading problem with - more than one DECchip based card. As a side effect, I don't mess with - the device structure any more which means that if more than 1 card in - 2.0.x is installed (4 in 2.1.x), the user will have to edit - linux/drivers/net/Space.c to make room for them. Hence, module loading - is the preferred way to use this driver, since it doesn't have this - limitation. - - Where SROM media detection is used and full duplex is specified in the - SROM, the feature is ignored unless de4x5_full_duplex is set at compile - time OR during a module load (insmod de4x5 de4x5_full_duplex=1). This - is because there is no way to automatically detect full duplex links - except through autonegotiation. When I include the autonegotiation - feature in the SROM autoconf code, this detection will occur - automatically. - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.dgrs linux/drivers/net/README.dgrs --- v2.1.66/linux/drivers/net/README.dgrs Sat Dec 21 07:23:20 1996 +++ linux/drivers/net/README.dgrs Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ - The Digi Intl. 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 -switches and a NIC combined into a single board. This driver can -be compiled into the kernel statically or as a loadable module. - -There is also a companion management tool, called "xrightswitch". -The management tool lets you watch the performance graphically, -as well as set the SNMP agent IP and IPX addresses, IEEE Spanning -Tree, and Aging time. These can also be set from the command line -when the driver is loaded. The driver command line options are: - - debug=NNN Debug printing level - dma=0/1 Disable/Enable DMA on PCI card - spantree=0/1 Disable/Enable IEEE spanning tree - hashexpire=NNN Change address aging time (default 300 seconds) - ipaddr=A,B,C,D Set SNMP agent IP address i.e. 199,86,8,221 - iptrap=A,B,C,D Set SNMP agent IP trap address i.e. 199,86,8,221 - ipxnet=NNN Set SNMP agent IPX network number - nicmode=0/1 Disable/Enable multiple NIC mode - -There is also a tool for setting up input and output packet filters -on each port, called "dgrsfilt". - -Both the management tool and the filtering tool are available -separately from the following FTP site: - - ftp://ftp.dgii.com/drivers/rightswitch/linux/ - -When nicmode=1, the board and driver operate as 4 or 6 individual -NIC ports (eth0...eth5) instead of as a switch. All switching -functions are disabled. In the future, the board firmware may include -a routing cache when in this mode. - -Copyright 1995-1996 Digi International Inc. - -This software may be used and distributed according to the terms -of the GNU General Public License, incorporated herein by reference. - -For information on purchasing a RightSwitch SE-4 or SE-6 -board, please contact Digi's sales department at 1-612-912-3444 -or 1-800-DIGIBRD. Outside the U.S., please check our Web page at: - - http://www.dgii.com - -for sales offices worldwide. Tech support is also available through -the channels listed on the Web site, although as long as I am -employed on networking products at Digi I will be happy to provide -any bug fixes that may be needed. - --Rick Richardson, rick@dgii.com diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.eql linux/drivers/net/README.eql --- v2.1.66/linux/drivers/net/README.eql Mon May 6 02:26:07 1996 +++ linux/drivers/net/README.eql Wed Dec 31 16:00:00 1969 @@ -1,528 +0,0 @@ - EQL Driver: Serial IP Load Balancing HOWTO - Simon "Guru Aleph-Null" Janes, simon@ncm.com - v1.1, February 27, 1995 - - This is the manual for the EQL device driver. EQL is a software device - that lets you load-balance IP serial links (SLIP or uncompressed PPP) - to increase your bandwidth. It will not reduce your latency (i.e. ping - times) except in the case where you already have lots of traffic on - your link, in which it will help them out. This driver has been tested - with the 1.1.75 kernel, and is known to have patched cleanly with - 1.1.86. Some testing with 1.1.92 has been done with the v1.1 patch - which was only created to patch cleanly in the very latest kernel - source trees. (Yes, it worked fine.) - - 1. Introduction - - Which is worse? A huge fee for a 56K leased line or two phone lines? - Its probably the former. If you find yourself craving more bandwidth, - and have a ISP that is flexible, it is now possible to bind modems - together to work as one point-to-point link to increase your - bandwidth. All without having to have a special black box on either - side. - - - The eql driver has only been tested with the Livingston PortMaster-2e - terminal server. I do not know if other terminal servers support load- - balancing, but I do know that the PortMaster does it, and does it - almost as well as the eql driver seems to do it (-- Unfortunately, in - my testing so far, the Livingston PortMaster 2e's load-balancing is a - good 1 to 2 KB/s slower than the test machine working with a 28.8 Kbps - and 14.4 Kbps connection. However, I am not sure that it really is - the PortMaster, or if it's Linux's TCP drivers. I'm told that Linux's - TCP implementation is pretty fast though.--) - - - I suggest to ISP's out there that it would probably be fair to charge - a load-balancing client 75% of the cost of the second line and 50% of - the cost of the third line etc... - - - Hey, we can all dream you know... - - - 2. Kernel Configuration - - Here I describe the general steps of getting a kernel up and working - with the eql driver. From patching, building, to installing. - - - 2.1. Patching The Kernel - - If you do not have or cannot get a copy of the kernel with the eql - driver folded into it, get your copy of the driver from - ftp://slaughter.ncm.com/pub/Linux/LOAD_BALANCING/eql-1.1.tar.gz. - Unpack this archive someplace obvious like /usr/local/src/. It will - create the following files: - - - - ______________________________________________________________________ - -rw-r--r-- guru/ncm 198 Jan 19 18:53 1995 eql-1.1/NO-WARRANTY - -rw-r--r-- guru/ncm 30620 Feb 27 21:40 1995 eql-1.1/eql-1.1.patch - -rwxr-xr-x guru/ncm 16111 Jan 12 22:29 1995 eql-1.1/eql_enslave - -rw-r--r-- guru/ncm 2195 Jan 10 21:48 1995 eql-1.1/eql_enslave.c - ______________________________________________________________________ - - Unpack a recent kernel (something after 1.1.92) Someplace convenient - like say /usr/src/linux-1.1.92.eql. Use symbolic links to point - /usr/src/linux to this development directory. - - - Apply the patch by running the commands: - - - ______________________________________________________________________ - cd /usr/src - patch - ". Here are some example enslavings: - - - - ______________________________________________________________________ - eql_enslave eql sl0 28800 - eql_enslave eql ppp0 14400 - eql_enslave eql sl1 57600 - ______________________________________________________________________ - - - - - - When you want to free a device from its life of slavery, you can - either down the device with ifconfig (eql will automatically bury the - dead slave and remove it from its queue) or use eql_emancipate to free - it. (-- Or just ifconfig it down, and the eql driver will take it out - for you.--) - - - - ______________________________________________________________________ - eql_emancipate eql sl0 - eql_emancipate eql ppp0 - eql_emancipate eql sl1 - ______________________________________________________________________ - - - - - - 3.3. DSLIP Configuration for the eql Device - - The general idea is to bring up and keep up as many SLIP connections - as you need, automatically. - - - 3.3.1. /etc/slip/runslip.conf - - Here is an example runslip.conf: - - - - - - - - - - - - - - - - ______________________________________________________________________ - name sl-line-1 - enabled - baud 38400 - mtu 576 - ducmd -e /etc/slip/dialout/cua2-288.xp -t 9 - command eql_enslave eql $interface 28800 - address 198.67.33.239 - line /dev/cua2 - - name sl-line-2 - enabled - baud 38400 - mtu 576 - ducmd -e /etc/slip/dialout/cua3-288.xp -t 9 - command eql_enslave eql $interface 28800 - address 198.67.33.239 - line /dev/cua3 - ______________________________________________________________________ - - - - - - 3.4. Using PPP and the eql Device - - I have not yet done any load-balancing testing for PPP devices, mainly - because I don't have a PPP-connection manager like SLIP has with - DSLIP. I did find a good tip from LinuxNET:Billy for PPP performance: - make sure you have asyncmap set to something so that control - characters are not escaped. - - - I tried to fix up a PPP script/system for redialing lost PPP - connections for use with the eql driver the weekend of Feb 25-26 '95 - (Hereafter known as the 8-hour PPP Hate Festival). Perhaps later this - year. - - - 4. About the Slave Scheduler Algorithm - - The slave scheduler probably could be replaced with a dozen other - things and push traffic much faster. The formula in the current set - up of the driver was tuned to handle slaves with wildly different - bits-per-second "priorities". - - - All testing I have done was with two 28.8 V.FC modems, one connecting - at 28800 bps or slower, and the other connecting at 14400 bps all the - time. - - - One version of the scheduler was able to push 5.3 K/s through the - 28800 and 14400 connections, but when the priorities on the links were - very wide apart (57600 vs. 14400) The "faster" modem received all - traffic and the "slower" modem starved. - - - 5. Tester's Reports - - Some people have experimented with the eql device with newer kernels - kernels (than 1.1.75). I have since updated the driver to patch - cleanly in newer kernels because of the removal of the old "slave- - balancing" driver config option. - - - o icee from LinuxNET patched 1.1.86 without any rejects and was able - to boot the kernel and enslave a couple of ISDN PPP links. - - 5.1. Randolph Bentson's Test Report - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From bentson@grieg.seaslug.org Wed Feb 8 19:08:09 1995 - Date: Tue, 7 Feb 95 22:57 PST - From: Randolph Bentson - To: guru@ncm.com - Subject: EQL driver tests - - - I have been checking out your eql driver. (Nice work, that!) - Although you may already done this performance testing, here - are some data I've discovered. - - Randolph Bentson - bentson@grieg.seaslug.org - - --------------------------------------------------------- - - - A pseudo-device driver, EQL, written by Simon Janes, can be used - to bundle multiple SLIP connections into what appears to be a - single connection. This allows one to improve dial-up network - connectivity gradually, without having to buy expensive DSU/CSU - hardware and services. - - I have done some testing of this software, with two goals in - mind: first, to ensure it actually works as described and - second, as a method of exercising my device driver. - - The following performance measurements were derived from a set - of SLIP connections run between two Linux systems (1.1.84) using - a 486DX2/66 with a Cyclom-8Ys and a 486SLC/40 with a Cyclom-16Y. - (Ports 0,1,2,3 were used. A later configuration will distribute - port selection across the different Cirrus chips on the boards.) - Once a link was established, I timed a binary ftp transfer of - 289284 bytes of data. If there were no overhead (packet headers, - inter-character and inter-packet delays, etc.) the transfers - would take the following times: - - bits/sec seconds - 345600 8.3 - 234600 12.3 - 172800 16.7 - 153600 18.8 - 76800 37.6 - 57600 50.2 - 38400 75.3 - 28800 100.4 - 19200 150.6 - 9600 301.3 - - A single line running at the lower speeds and with large packets - comes to within 2% of this. Performance is limited for the higher - speeds (as predicted by the Cirrus databook) to an aggregate of - about 160 kbits/sec. The next round of testing will distribute - the load across two or more Cirrus chips. - - The good news is that one gets nearly the full advantage of the - second, third, and fourth line's bandwidth. (The bad news is - that the connection establishment seemed fragile for the higher - speeds. Once established, the connection seemed robust enough.) - - #lines speed mtu seconds theory actual %of - kbit/sec duration speed speed max - 3 115200 900 _ 345600 - 3 115200 400 18.1 345600 159825 46 - 2 115200 900 _ 230400 - 2 115200 600 18.1 230400 159825 69 - 2 115200 400 19.3 230400 149888 65 - 4 57600 900 _ 234600 - 4 57600 600 _ 234600 - 4 57600 400 _ 234600 - 3 57600 600 20.9 172800 138413 80 - 3 57600 900 21.2 172800 136455 78 - 3 115200 600 21.7 345600 133311 38 - 3 57600 400 22.5 172800 128571 74 - 4 38400 900 25.2 153600 114795 74 - 4 38400 600 26.4 153600 109577 71 - 4 38400 400 27.3 153600 105965 68 - 2 57600 900 29.1 115200 99410.3 86 - 1 115200 900 30.7 115200 94229.3 81 - 2 57600 600 30.2 115200 95789.4 83 - 3 38400 900 30.3 115200 95473.3 82 - 3 38400 600 31.2 115200 92719.2 80 - 1 115200 600 31.3 115200 92423 80 - 2 57600 400 32.3 115200 89561.6 77 - 1 115200 400 32.8 115200 88196.3 76 - 3 38400 400 33.5 115200 86353.4 74 - 2 38400 900 43.7 76800 66197.7 86 - 2 38400 600 44 76800 65746.4 85 - 2 38400 400 47.2 76800 61289 79 - 4 19200 900 50.8 76800 56945.7 74 - 4 19200 400 53.2 76800 54376.7 70 - 4 19200 600 53.7 76800 53870.4 70 - 1 57600 900 54.6 57600 52982.4 91 - 1 57600 600 56.2 57600 51474 89 - 3 19200 900 60.5 57600 47815.5 83 - 1 57600 400 60.2 57600 48053.8 83 - 3 19200 600 62 57600 46658.7 81 - 3 19200 400 64.7 57600 44711.6 77 - 1 38400 900 79.4 38400 36433.8 94 - 1 38400 600 82.4 38400 35107.3 91 - 2 19200 900 84.4 38400 34275.4 89 - 1 38400 400 86.8 38400 33327.6 86 - 2 19200 600 87.6 38400 33023.3 85 - 2 19200 400 91.2 38400 31719.7 82 - 4 9600 900 94.7 38400 30547.4 79 - 4 9600 400 106 38400 27290.9 71 - 4 9600 600 110 38400 26298.5 68 - 3 9600 900 118 28800 24515.6 85 - 3 9600 600 120 28800 24107 83 - 3 9600 400 131 28800 22082.7 76 - 1 19200 900 155 19200 18663.5 97 - 1 19200 600 161 19200 17968 93 - 1 19200 400 170 19200 17016.7 88 - 2 9600 600 176 19200 16436.6 85 - 2 9600 900 180 19200 16071.3 83 - 2 9600 400 181 19200 15982.5 83 - 1 9600 900 305 9600 9484.72 98 - 1 9600 600 314 9600 9212.87 95 - 1 9600 400 332 9600 8713.37 90 - - - - - - 5.2. Anthony Healy's Report - - - - - - - - Date: Mon, 13 Feb 1995 16:17:29 +1100 (EST) - From: Antony Healey - To: Simon Janes - Subject: Re: Load Balancing - - Hi Simon, - I've installed your patch and it works great. I have trialed - it over twin SL/IP lines, just over null modems, but I was - able to data at over 48Kb/s [ISDN link -Simon]. I managed a - transfer of upto 7.5 Kbyte/s on one go, but averaged around - 6.4 Kbyte/s, which I think is pretty cool. :) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.ewrk3 linux/drivers/net/README.ewrk3 --- v2.1.66/linux/drivers/net/README.ewrk3 Wed Mar 6 05:04:20 1996 +++ linux/drivers/net/README.ewrk3 Wed Dec 31 16:00:00 1969 @@ -1,45 +0,0 @@ -The EtherWORKS 3 driver in this distribution is designed to work with all -kernels > 1.1.33 (approx) and includes tools in the 'ewrk3tools' -subdirectory to allow set up of the card, similar to the MSDOS -'NICSETUP.EXE' tools provided on the DOS drivers disk (type 'make' in that -subdirectory to make the tools). - -The supported cards are DE203, DE204 and DE205. All other cards are NOT -supported - refer to 'depca.c' for running the LANCE based network cards and -'de4x5.c' for the DIGITAL Semiconductor PCI chip based adapters from -Digital. - -The ability to load this driver as a loadable module has been included and -used extensively during the driver development (to save those long reboot -sequences). To utilise this ability, you have to do 8 things: - - 0) have a copy of the loadable modules code installed on your system. - 1) copy ewrk3.c from the /linux/drivers/net directory to your favourite - temporary directory. - 2) edit the source code near line 1898 to reflect the I/O address and - IRQ you're using. - 3) compile ewrk3.c, but include -DMODULE in the command line to ensure - that the correct bits are compiled (see end of source code). - 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a - kernel with the ewrk3 configuration turned off and reboot. - 5) insmod ewrk3.o - [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y] - 6) run the net startup bits for your new eth?? interface manually - (usually /etc/rc.inet[12] at boot time). - 7) enjoy! - - Note that autoprobing is not allowed in loadable modules - the system is - already up and running and you're messing with interrupts. - - To unload a module, turn off the associated interface - 'ifconfig eth?? down' then 'rmmod ewrk3'. - -The performance we've achieved so far has been measured through the 'ttcp' -tool at 975kB/s. This measures the total tcp stack performance which -includes the card, so don't expect to get much nearer the 1.25MB/s -theoretical ethernet rate. - - -Enjoy! - -Dave diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.ltpc linux/drivers/net/README.ltpc --- v2.1.66/linux/drivers/net/README.ltpc Sun Feb 2 05:18:36 1997 +++ linux/drivers/net/README.ltpc Wed Dec 31 16:00:00 1969 @@ -1,98 +0,0 @@ -This is the ALPHA version of the ltpc driver. - -In order to use it, you will need at least version 1.3.3 of the -netatalk package, and the Apple or Farallon Localtalk PC card. -There are a number of different Localtalk cards for the PC; this -driver applies only to the one with the 65c02 processor chip on it. - -To include it in the kernel, select the CONFIG_LTPC switch in the -configuration dialog; at this time (kernel 2.1.23) compiling it as -a module will not work. - -Before starting up the netatalk demons (perhaps in rc.local), you -need to add a line such as: - -/sbin/ifconfig ltalk0 127.0.0.42 - - -The driver will autoprobe, and you should see a message like: -"LocalTalk card found at 240, IR9, DMA1." -at bootup. - -The appropriate netatalk configuration depends on whether you are -attached to a network that includes appletalk routers or not. If, -like me, you are simply connecting to your home Macintoshes and -printers, you need to set up netatalk to "seed". The way I do this -is to have the lines - -dummy -seed -phase 2 -net 2000 -addr 2000.26 -zone "1033" -ltalk0 -seed -phase 1 -net 1033 -addr 1033.27 -zone "1033" - -in my atalkd.conf. What is going on here is that I need to fool -netatalk into thinking that there are two appletalk interfaces -present -- otherwise it refuses to seed. This is a hack, and a -more permanent solution would be to alter the netatalk code. -Note that the dummy driver needs to accept multicasts also -- earlier -versions of dummy.c may need to be patched. - - -If you are attached to an extended appletalk network, with routers on -it, then you don't need to fool around with this -- the appropriate -line in atalkd.conf is - -ltalk0 -phase 1 - --------------------------------------- - -Card Configuration: - -The interrupts and so forth are configured via the dipswitch 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 - polled mode. Because the card was developed in the XT era, the - original documentation refers to IRQ2. Since you'll be running - this on an AT (or later) class machine, that really means IRQ9. - - SW1 IRQ 4 - SW2 IRQ 3 - SW3 IRQ 9 (2 in original card documentation only applies to XT) - - - DMA -- choose DMA 1 or 3, and set both corresponding switches. - - SW4 DMA 3 - SW5 DMA 1 - SW6 DMA 3 - SW7 DMA 1 - - - I/O address -- choose one. - - SW8 220 / 240 - --------------------------------------- - -IP: - Many people are interested in this driver in order to use IP -when Localtalk, but no Ethernet, is available. While the code to do -this is not strictly speaking part of this driver, an experimental -version is available which seems to work under kernel 2.0.xx. It is -not yet functional in the 2.1.xx kernels. - --------------------------------------- - -BUGS: - -2.0.xx: - -2.1.xx: The module support doesn't work yet. - -______________________________________ - -THANKS: - Thanks to Alan Cox for helpful discussions early on in this -work, and to Denis Hainsworth for doing the bleeding-edge testing. - --- Bradford Johnson - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.multicast linux/drivers/net/README.multicast --- v2.1.66/linux/drivers/net/README.multicast Mon Nov 17 18:47:21 1997 +++ linux/drivers/net/README.multicast Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -Behaviour of cards under Multicast. This is how they currently -behave not what the hardware can do. In particular all the 8390 based -cards don't use the onboard hash filter, and the lance driver doesn't -use its filter, even though the code for loading it is in the DEC -lance based driver. - -The following multicast requirements are needed ------------------------------------------------ -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 - - -Board Multicast AllMulti Promisc Filter ------------------------------------------------------------------------- -3c501 YES YES YES Software -3c503 YES YES YES Hardware -3c505 YES NO YES Hardware -3c507 NO NO NO N/A -3c509 YES YES YES Software -3c59x YES YES YES Software -ac3200 YES YES YES Hardware -apricot YES PROMISC YES Hardware -arcnet NO NO NO N/A -at1700 PROMISC PROMISC YES Software -atp PROMISC PROMISC YES Software -cs89x0 YES YES YES Software -de4x5 YES YES YES Hardware -de600 NO NO NO N/A -de620 PROMISC PROMISC YES Software -depca YES PROMISC YES Hardware -e2100 YES YES YES Hardware -eepro YES PROMISC YES Hardware -eexpress NO NO NO N/A -ewrk3 YES PROMISC YES Hardware -hp-plus YES YES YES Hardware -hp YES YES YES Hardware -hp100 YES YES YES Hardware -ibmtr NO NO NO N/A -lance YES YES YES Software(#) -ne YES YES YES Hardware -ni52 <------------------ Buggy ------------------> -ni65 YES YES YES Software(#) -seeq NO NO NO N/A -sk_g16 NO NO YES N/A -smc-ultra YES YES YES Hardware -sunlance YES YES YES Hardware -tulip YES YES YES Hardware -wavelan YES PROMISC YES Hardware -wd YES YES YES Hardware -znet YES YES YES Software - - -PROMISC = This multicasts mode is in fact promiscuous mode. Avoid using -cards who go PROMISC on any multicast in a multicast kernel. -(#) = Hardware multicast support is not used yet. diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.pt linux/drivers/net/README.pt --- v2.1.66/linux/drivers/net/README.pt Thu Apr 11 23:49:36 1996 +++ linux/drivers/net/README.pt Wed Dec 31 16:00:00 1969 @@ -1,62 +0,0 @@ -This is the README for the Gracilis Packetwin device driver, version 0.5 -ALPHA for Linux 1.3.43. - -These files will allow you to talk to the PackeTwin (now know as PT) and -connect through it just like a pair of TNC's. To do this you will also -require the AX.25 code in the kernel enabled. - -There are four files in this archive; this readme, a patch file, a .c file -and finally a .h file. The two program files need to be put into the -drivers/net directory in the Linux source tree, for me this is the -directory /usr/src/linux/drivers/net. The patch file needs to be patched in -at the top of the Linux source tree (/usr/src/linux in my case). - -You will most probably have to edit the pt.c file to suit your own setup, -this should just involve changing some of the defines at the top of the file. -Please note that if you run an external modem you must specify a speed of 0. - -The program is currently setup to run a 4800 baud external modem on port A -and a Kantronics DE-9600 daughter board on port B so if you have this (or -something similar) then you're right. - -To compile in the driver, put the files in the correct place and patch in -the diff. You will have to re-configure the kernel again before you -recompile it. - -The driver is not real good at the moment for finding the card. You can -'help' it by changing the order of the potential addresses in the structure -found in the pt_init() function so the address of where the card is is put -first. - -After compiling, you have to get them going, they are pretty well like any -other net device and just need ifconfig to get them going. -As an example, here is my /etc/rc.net --------------------------- - -# -# Configure the PackeTwin, port A. -/sbin/ifconfig pt0a 44.136.8.87 hw ax25 vk2xlz mtu 512 -/sbin/ifconfig pt0a 44.136.8.87 broadcast 44.136.8.255 netmask 255.255.255.0 -/sbin/route add -net 44.136.8.0 netmask 255.255.255.0 dev pt0a -/sbin/route add -net 44.0.0.0 netmask 255.0.0.0 gw 44.136.8.68 dev pt0a -/sbin/route add -net 138.25.16.0 netmask 255.255.240.0 dev pt0a -/sbin/route add -host 44.136.8.255 dev pt0a -# -# Configure the PackeTwin, port B. -/sbin/ifconfig pt0b 44.136.8.87 hw ax25 vk2xlz-1 mtu 512 -/sbin/ifconfig pt0b 44.136.8.87 broadcast 44.255.255.255 netmask 255.0.0.0 -/sbin/route add -host 44.136.8.216 dev pt0b -/sbin/route add -host 44.136.8.95 dev pt0b -/sbin/route add -host 44.255.255.255 dev pt0b - -This version of the driver comes under the GNU GPL. If you have one on my -previous (non-GPL) versions of the driver, please update to this one. - -I hope that this all works well for you. I would be pleased to hear how -many people use the driver and if it does its job. - - - Craig vk2xlz - -INET: csmall@acacia.itd.uts.edu.au craig.small@eol.ieaust.org.au -AMPR: vk2xlz@gonzo.vk2xlz.ampr.org -AX25: vk2xlz@vk2gdm.nsw.aus.oc diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.scc linux/drivers/net/README.scc --- v2.1.66/linux/drivers/net/README.scc Tue Oct 29 05:33:38 1996 +++ linux/drivers/net/README.scc Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ - -You will find subset of the documentation in - - linux/Documentation/networking/z8530drv.txt - -To use this driver you MUST have the full package from: - -Internet: -========= - -1. db0bm.automation.fh-aachen.de/incoming/dl1bke/z8530drv-utils-3.0.tar.gz - -2. ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz - If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz - -and various mirrors (i.e. nic.switch.ch) - -The package includes the utilities necessary to initialize and -control the driver. - -Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@lykos.oche.de diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.smc9 linux/drivers/net/README.smc9 --- v2.1.66/linux/drivers/net/README.smc9 Fri Mar 8 00:03:32 1996 +++ linux/drivers/net/README.smc9 Wed Dec 31 16:00:00 1969 @@ -1,42 +0,0 @@ - -SMC 9xxxx Driver -Revision 0.12 -3/5/96 -Copyright 1996 Erik Stahlman -Released under terms of the GNU public license. - -This file contains the instructions and caveats for my SMC9xxx driver. You -should not be using the driver without reading this file. - -Things to note about installation: - - 1. The driver should work on all kernels from 1.2.13 until 1.3.71. - (A kernel patch is supplied for 1.3.71 ) - - 2. If you include this into the kernel, you might need to change some - options, such as for forcing IRQ. - - - 3. To compile as a module, run 'make' . - Make will give you the appropriate options for various kernel support. - - 4. Loading the driver as a module : - - use: insmod smc9194.o - optional parameters: - io=xxxx : your base address - irq=xx : your irq - ifport=x : 0 for whatever is default - 1 for twisted pair - 2 for AUI ( or BNC on some cards ) - -How to obtain the latest version? - -FTP: - ftp://fenris.campus.vt.edu/smc9/smc9-12.tar.gz - ftp://sfbox.vt.edu/filebox/F/fenris/smc9/smc9-12.tar.gz - - -Contacting me: - erik@mail.vt.edu - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.tunnel linux/drivers/net/README.tunnel --- v2.1.66/linux/drivers/net/README.tunnel Mon May 6 02:26:07 1996 +++ linux/drivers/net/README.tunnel Wed Dec 31 16:00:00 1969 @@ -1,123 +0,0 @@ - -This is the alpha version of my IP tunneling driver. - -Protocol Tunneling: - - A network tunneling driver encapsulates packets of one -protocol type within packets of another protocol type. It sends -them out over the network to a relay (or destination) where the -packet is unwrapped and is forwarded to its ultimate destination. -Packet tunneling is useful in situations where you want to route -packets of a non-standard protocol type over the common network. -A good example of this is 'IPX encapsulation', in which IPX packets -from a DOS network are routed across an IP network by encapsulating -them in IP packets. - - There are two parts to every protocol tunnel. There is -the encapsulator, and the decapsulator. The encapsulator wraps -the packets in the host protocol and sends them on their way, -while the decapsulator takes wrapped packets at the other end -and unwraps them and forwards them (or whatever else should be -done with them.) - - IP tunneling is a specific case of protocol tunneling, -in which the encapsulating protocol is IP, and the encapsulated -protocol may be any other protocol, including Apple-Talk, IPX, -or even IP within IP. - - For more information on the semantics and specifications -of IP encapsulation, see RFC-1241, also included in this package. - - -My Implementation: - - My implementation of IP tunneling for Linux consists -of two loadable module drivers, one an encapsulator (tunnel.o) -and the other a decapsulator (ipip.o). Both are used for -setting up a working IP-in-IP tunnel. Currently, the drivers -only support IP encapsulated in IP. - - The tunnel driver is implemented as a network device, -based on the Linux loopback driver written (in part) by Ross Biro, -Fred N. van Kempen, and Donald Becker. After the driver is -loaded, it can be set up as any other network interface, using -ifconfig. The tunnel device is given its own IP address, which -can match that of the machine, and also is given a pointopoint -address. This pointopoint address is the address of the machine -providing the decapsulating endpoint for the IP tunnel. After -the device is configured for use, the 'route' command can be used -to route traffic through the IP tunnel. There must be a route to -the decapsulating endpoint that does not go through the tunnel -device, otherwise a looping tunnel is created, preventing the -network traffic from leaving the local endpoint. - - The decapsulating endpoint must have loaded the ipip.o -decapsulator module for it to understand IP-in-IP encapsulation. -This module takes any IP-in-IP packet that is destined for the local -machine, unwraps it, and sends it on its way, using standard -routing rules. The current implementation of IP decapsulation does -no checking on the packet, other than making sure wrapper is bound -for the local machine. - - Note that the above setup only provides a one-way pipe. -To provide a full two-way IP tunnel, the decapsulation host must -set up an IP encapsulation driver, and the encapsulating host must -load the IP decapsulation module, providing full duplex communication -through the IP tunnel. - -An example setup might be as follows. - - Machine A has an ethernet interface with an IP address -of 111.112.101.37, while machine B is on a different network, with -an ethernet interface at IP address 111.112.100.86. For some -reason, machine A needs to appear on machine B's network. It could -do that by setting up an IP tunnel with machine B. - -First, the commands that would be run on machine A: -(Assuming both machines are Linux hosts, running Linux 1.1.x) - -# insmod ipip.o ; insmod tunnel.o // Here the drivers are loaded. -# ifconfig tunl 111.112.100.87 pointopoint 111.112.100.86 -# ifconfig tunl netmask 255.255.255.0 // Set a proper netmask. -# route add 111.112.100.86 dev eth0 // Set a static route to B. -# route add -net 111.112.100.0 dev tunl // Set up other routes. - -At this point, machine A is ready to route all traffic to the -network that machine B resides on. But now, machine B needs to -set up its half of the IP tunnel: - -# insmod ipip.o ; insmod tunnel.o // Here the drivers are loaded. -# ifconfig tunl 111.112.100.86 pointopoint 111.112.101.37 -# ifconfig tunl netmask 255.255.255.0 // Set a proper netmask. -# route add 111.112.100.87 dev eth0 // Set a static route to B. -# arp -s 111.112.100.87 EE.EE.EE.EE.EE pub // Act as a proxy arp server. - -The extra step of "arp -s" is needed so that when machines on -network B query to see if 111.112.100.87 (the "ghost" host) -exists, machine B will respond, acting as an arp proxy for machine -A. In the command line, EE.EE.EE.EE.EE should be replaced with -the ethernet hardware address of machine B's ethernet card. - -Notice that machine B's setup is almost the inverse of machine A's -setup. This is because IP tunneling is a peer-to-peer concept. -There is no client and no server, there is no state to keep track -of. The concept is simple. Every IP packet outbound through the -tunnel interface is wrapped and sent to the pointopoint address -and every incoming IP-in-IP packet bound for the local machine is -unwrapped and re-routed normally. -The only difference in the two machines setup shown above is that -machine A set its tunnel address to one existing on machine B's -network, while B set a route to machine A's tunnel device address -through the tunnel. This is because machine A wants to have a new -address on network B, and machine B is simply acting as a proxy -for machine A. Machine A needs its tunnel address to be on network -B so that when packets from machine B are unwrapped, the Linux -routing system knows that the address is a local one. Due to a -feature of Linux, any packets received locally, bound for another -local address, are simply routed through the loopback interface. -This means that the tunnel device should never receive packets. Even -on machine B, it is the ethernet interface that is receiving wrapped -packets, and once they are unwrapped they go back out the ethernet -interface. This could cause Linux to generate ICMP redirect messages -if this special routing case isn't caught (see /linux/net/inet/ip.c) - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.wanpipe linux/drivers/net/README.wanpipe --- v2.1.66/linux/drivers/net/README.wanpipe Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/README.wanpipe Wed Dec 31 16:00:00 1969 @@ -1,148 +0,0 @@ ------------------------------------------------------------------------------- -WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router ------------------------------------------------------------------------------- -Release 3.1.0 -January 30, 1997 -Author: Gene Kozin -Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------- - -INTRODUCTION - -WANPIPE(tm) is a family of intelligent muliprotocol WAN communication adapters -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 variety of synchronous communications protocols, -including frame relay, PPP, X.25, SDLC, etc. - -WANPIPE driver together with Linux WAN Router module allows you to build -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 WAN Tools -package to be able to use Linux WAN Router and WANPIPE driver. The package -is available via the Internet from Sangoma Technologies' anonymous FTP server: - - ftp.sangoma.com/pub/linux/wantools-X.Y.Z.tgz - -For technical questions and/or comments please e-mail to genek@compuserve.com. -For general inquiries please contact Sangoma Technologies Inc. by - - Hotline: 1-800-388-2475 (USA and Canada, toll free) - Phone: (905) 474-1990 - Fax: (905) 474-9223 - E-mail: dm@sangoma.com (David Mandelstam) - WWW: http://www.sangoma.com - - - -COPYRIGHT AND LICENSING INFORMATION - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; 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. - -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. - - - -NEW IN THIS RELEASE - - o Implemented as WAN Link Driver compliant with Linux WAN Router interface - o Added support for X.25 protocol - o Miscellaneous bug fixes and performance improvements - - - -FILE LIST - -drivers/net: - README.wanpipe This file - sdladrv.c SDLA support module source code - wpmain.c WANPIPE driver module main source code - wpx.c WANPIPE driver module X.25 source code - wpf.c WANPIPE driver module frame relay source code - wpp.c WANPIPE driver module PPP source code - 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 - -include/linux: - wanpipe.h WANPIPE API definitions - sdladrv.h SDLA support module API definitions - sdlasfm.h SDLA firmware module definitions - - - -REVISION HISTORY - -3.1.0 January 30, 1997 - - o Implemented IOCTL for executing adapter commands. - o Fixed a bug in frame relay code causing driver configured as a FR - switch to be stuck in WAN_DISCONNECTED mode. - -3.0.0 December 31, 1996 - - o Uses Linux WAN Router interface - o Added support for X.25 routing - o Miscellaneous bug fixes and performance improvements - -2.4.1 December 18, 1996 - - o Added support for LMI and Q.933 frame relay link management - -2.3.0 October 17, 1996 - - o All shell scripts use meta-configuration file - o Miscellaneous bug fixes - -2.2.0 July 16, 1996 - - o Compatible with Linux 2.0 - o Added uninstall script - o User's Manual is available in HTML format - -2.1.0 June 20, 1996 - - o Added support for synchronous PPP - o Added support for S503 adapter - o Added API for executing adapter commands - o Fixed a re-entrancy problem in frame relaty driver - o Changed interface between SDLA driver and protocol support modules - o Updated frame relay firmware - -2.0.0 May 1, 1996 - - o Added interactive installation and configuration scripts - o Added System V-style start-up script - o Added dynamic memory window address selection in SDLA driver - o Miscellaneous bug fixes in SDLA driver - o Updated S508 frame relay firmware - o Changed SFM file format - -1.0.0 February 12, 1996 - - o Final release - o Added support for Linux 1.3 - o Updated S508 frame relay firmware - -0.9.0 December 21, 1995 - - o Added SNAP encapsulation for routed frames - o Added support for the frame relay switch emulation mode - o Added support for S508 adapter - o Added capability to autodetect adapter type - o Miscellaneous bug fixes in SDLA and frame relay drivers - -0.1.0 October 12, 1995 - - o Initial version - ->>>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README.wavelan linux/drivers/net/README.wavelan --- v2.1.66/linux/drivers/net/README.wavelan Sun Jul 2 00:30:37 1995 +++ linux/drivers/net/README.wavelan Wed Dec 31 16:00:00 1969 @@ -1,33 +0,0 @@ -Sun Jul 2 01:38:33 EST 1995 - -1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390. - The version of the card that I use (NCR) supports four I/O addresses (selectable - via a pair of DIP switches). If you want the driver to autoprobe a different - subset of the four valid addresses then you will need to edit - .../drivers/net/wavelan.c (near line 714) and change the initialisation of the - `iobase[]' array. Normally, I use a LILO configuration file directive to - obviate the need for autoprobing entirely, a course of action I heartily - recommend. - -2. By default, the driver uses the Network ID (NWID) stored in the card's Parameter - Storage Area (PSA). However, the PSA NWID can be overridden by a value passed - explicitly as the third numeric argument to LILO's "ether=" directive, either - at the LILO prompt at boot time or within LILO's configuration file. - For example, the following line from such a LILO configuration file would - auto-configure the IRQ value, set the I/O base to 0x390 and set the NWID to - 0x4321, all on a WaveLAN card labelled "eth0": - - .. - append ="ether=0,0x390,0x4321,eth0" - .. - -3. The driver uses the IRQ stored in the card's PSA. - To change this you will need to use the configuration/setup software that - accompanies each WaveLAN device. Yes, the driver should use the value passed - in via LILO and it will, just as soon as I can work out why that part of the - code doesn't work :-(. - -4. If you encounter any problems send me some email. - -Good luck, -Bruce Janson (bruce@cs.usyd.edu.au) diff -u --recursive --new-file v2.1.66/linux/drivers/net/README1.PLIP linux/drivers/net/README1.PLIP --- v2.1.66/linux/drivers/net/README1.PLIP Wed Aug 10 09:26:00 1994 +++ linux/drivers/net/README1.PLIP Wed Dec 31 16:00:00 1969 @@ -1,113 +0,0 @@ -\title{PLIP: The Parallel Line Internet Protocol Device} - -\author{ Donald Becker (becker@super.org)} -\affiliation{I.D.A. Supercomputing Research Center, Bowie MD 20715} - -%% At some point T. Thorn will probably contribute text, -%% \author{ Tommy Thorn (tthorn@daimi.aau.dk)} - -\section{PLIP Introduction} -This document describes the parallel port packet pusher for Net/LGX. -This device interface allows a point-to-point connection between two -parallel ports to appear as a IP network interface. - -\chapter{PLIP hardware interconnection} -PLIP uses several different data transfer methods. The first (and the -only one implemented in the early version of the code) uses a standard -printer "null" cable to transfers data four bits at a time using -data bit outputs connected to status bit inputs. - -The second data transfer method relies on both machines having -bi-directional parallel ports, rather than output-only ``printer'' -ports. This allows byte-wide transfers and avoids reconstructing -nibbles into bytes, leading to much faster transfers. - -\section{Parallel Transfer Mode 0 Cable} -The cable for the first transfer mode is a standard -printer "null" cable which transfers data four bits at a time using -data bit outputs of the first port (machine T) connected to the -status bit inputs of the second port (machine R). There are five -status inputs, and they are used as four data inputs and a clock (data -strobe) input, arranged so that the data input bits appear as contiguous -bits with standard status register implementation. - -A cable that implements this protocol is available commercially as a -"Null Printer" or "Turbo Laplink" cable. It can be constructed with -two DB-25 male connectors symmetrically connected as follows: - - STROBE output 1* - D0->ERROR 2 - 15 15 - 2 - D1->SLCT 3 - 13 13 - 3 - D2->PAPOUT 4 - 12 12 - 4 - D3->ACK 5 - 10 10 - 5 - D4->BUSY 6 - 11 11 - 6 - D5,D6,D7 are 7*, 8*, 9* - AUTOFD output 14* - INIT output 16* - SLCTIN 17 - 17 - extra grounds are 18*,19*,20*,21*,22*,23*,24* - GROUND 25 - 25 -* Do not connect these pins on either end - -If the cable you are using has a metallic shield it should be -connected to the metallic DB-25 shell at one end only. - -\section{Parallel Transfer Mode 1} -The second data transfer method relies on both machines having -bi-directional parallel ports, rather than output-only ``printer'' -ports. This allows byte-wide transfers, and avoids reconstructing -nibbles into bytes. This cable should not be used on unidirectional -``printer'' (as opposed to ``parallel'') ports or when the machine -isn't configured for PLIP, as it will result in output driver -conflicts and the (unlikely) possibility of damage. - -The cable for this transfer mode should be constructed as follows: - - STROBE->BUSY 1 - 11 - D0->D0 2 - 2 - D1->D1 3 - 3 - D2->D2 4 - 4 - D3->D3 5 - 5 - D4->D4 6 - 6 - D5->D5 7 - 7 - D6->D6 8 - 8 - D7->D7 9 - 9 - INIT -> ACK 16 - 10 - AUTOFD->PAPOUT 14 - 12 - SLCT->SLCTIN 13 - 17 - GND->ERROR 18 - 15 - extra grounds are 19*,20*,21*,22*,23*,24* - GROUND 25 - 25 -* Do not connect these pins on either end - -Once again, if the cable you are using has a metallic shield it should -be connected to the metallic DB-25 shell at one end only. - -\section{PLIP Mode 0 transfer protocol} -The PLIP driver is compatible with the "Crynwr" parallel port transfer -standard in Mode 0. That standard specifies the following protocol: - - send header nibble '8' - count-low octet - count-high octet - ... data octets - checksum octet - -Each octet is sent as - - >4)&0x0F)> - -To start a transfer the transmitting machine outputs a nibble 0x08. -The raises the ACK line, triggering an interrupt in the receiving -machine. The receiving machine disables - -Restated: - -(OUT is bit 0-4, OUT.j is bit j from OUT. IN likewise) -Send_Byte: - OUT := low nibble, OUT.4 := 1 - WAIT FOR IN.4 = 1 - OUT := high nibble, OUT.4 := 0 - WAIT FOR IN.4 = 0 - - diff -u --recursive --new-file v2.1.66/linux/drivers/net/README2.PLIP linux/drivers/net/README2.PLIP --- v2.1.66/linux/drivers/net/README2.PLIP Wed Aug 10 09:26:00 1994 +++ linux/drivers/net/README2.PLIP Wed Dec 31 16:00:00 1969 @@ -1,78 +0,0 @@ - -(2nd attempt. 1st bounced.) -Hi again - -About my previous mail: I've looked into parallel.asm, and I'm -rather confused. Looks like the code agrees with you, but not -the protocol description preceding it?? I got to look more -careful, but it wont be for a while (approx a week). - ->From plip.c (v0.04): - ->make one yourself. The wiring is: -> INIT 16 - 16 SLCTIN 17 - 17 -> GROUND 25 - 25 -> D0->ERROR 2 - 15 15 - 2 - -I saw you removed 1 and 14 from the cable description, but not -16 and 17. Why is that? - -Have been successful in getting parallel.com working (the Messy-Loss -software). Using the pksend on the sender and pkall/pkwatch/whatnot -gives me a hung receiver. (The cable works, I've tried unet11, a DOS -cheap-net prog.) - -Using PLIP v0.03 and trying to ping the other end gives - 88 timeout 88 timeout....(more) 2386 bogus packet size, dropped -on the receiver, and on the sender lots of timeout, but of -course I don't know how much is supposed to work. - -The following to something I wrote when I should have gone to bed a -long time ago. Use it for whatever you like, or dump it in the bin. ;^) - -/Tommy ------ -Becker [& Co] proudly presents PLIP - -What is PLIP? -============= - -PLIP is Parallel Line IP, that is, the transportation of IP packages -over a parallel port. In the case of a PC, the obvious choice is the -printer port. PLIP is a non-standard, but [can use] uses the standard -LapLink null-printer cable [can also work in turbo mode, with a PLIP -cable]. [The protocol used to pack IP packages, is a simple one -initiated by Crynwr.] - -Advantages of PLIP -================== - -It's cheap, it's available everywhere, and it's easy. - -The PLIP cable is all that's needed to connect two Linux boxes, and it -can be build for very bucks. - -Connecting two Linux boxes takes only a seconds decision and a few -minutes work, no need to search for a [supported] netcard. This might -even be especially important in the case of notebooks, where netcard -are not easily available. - -Not requiring a netcard also means that apart from connecting the -cables, everything else is software configuration [which in principle -could be made very easy.] - -Disadvantages of PLIP -===================== - -Doesn't work over a modem, like SLIP and PPP. Limited range, 15 m. -Can only be used to connect three (?) Linux boxes. Doesn't connect to -an exiting ethernet. Isn't standard (not even de facto standard, like -SLIP). - -Performance -========== - -PLIP easily outperforms ethernet cards....(ups, I was dreaming, but -it *is* getting late. EOB) - - diff -u --recursive --new-file v2.1.66/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.66/linux/drivers/net/Space.c Tue Sep 23 16:48:48 1997 +++ linux/drivers/net/Space.c Sat Nov 29 10:33:19 1997 @@ -32,8 +32,6 @@ #include #include -#include - #define NEXT_DEV NULL @@ -100,6 +98,11 @@ extern int de600_probe(struct device *); extern int de620_probe(struct device *); +/* FDDI adapters */ +extern int dfx_probe(struct device *dev); +extern int apfddi_init(struct device *dev); + + __initfunc(static int ethif_probe(struct device *dev)) { u_long base_addr = dev->base_addr; @@ -280,6 +283,27 @@ } +#ifdef CONFIG_FDDI +__initfunc(static int fddiif_probe(struct device *dev)) +{ + unsigned long base_addr = dev->base_addr; + + if ((base_addr == 0xffe0) || (base_addr == 1)) + return 1; /* ENXIO */ + + if (1 +#ifdef CONFIG_DEFXX + && dfx_probe(dev) +#endif +#ifdef CONFIG_APFDDI + && apfddi_init(dev); +#endif + && 1 ) { + return 1; /* -ENODEV or -EAGAIN would be more accurate. */ + } + return 0; +} +#endif #ifdef CONFIG_ETHERTAP @@ -317,13 +341,11 @@ #if defined(CONFIG_COPS) extern int cops_probe(struct device *); - static struct device dev_cops = { - "lt0", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NEXT_DEV, cops_probe }; + static struct device cops2_dev = { "lt2", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe }; + static struct device cops1_dev = { "lt1", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe }; + static struct device cops0_dev = { "lt0", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe }; # undef NEXT_DEV -# define NEXT_DEV (&dev_cops) +# define NEXT_DEV (&cops0_dev) #endif /* COPS */ #if defined(CONFIG_IPDDP) @@ -483,48 +505,26 @@ #endif -#ifdef CONFIG_NET_IPIP - extern int tunnel_init(struct device *); - - static struct device tunnel_dev1 = - { - "tunl1", /* IPIP tunnel */ - 0x0, /* recv memory end */ - 0x0, /* recv memory start */ - 0x0, /* memory end */ - 0x0, /* memory start */ - 0x0, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - NEXT_DEV, /* next device */ - tunnel_init /* Fill in the details */ - }; - - static struct device tunnel_dev0 = - { - "tunl0", /* IPIP tunnel */ - 0x0, /* recv memory end */ - 0x0, /* recv memory start */ - 0x0, /* memory end */ - 0x0, /* memory start */ - 0x0, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - &tunnel_dev1, /* next device */ - tunnel_init /* Fill in the details */ - }; -# undef NEXT_DEV -# define NEXT_DEV (&tunnel_dev0) - -#endif - -#ifdef CONFIG_APFDDI - extern int apfddi_init(struct device *dev); - static struct device fddi_dev = { - "fddi", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, apfddi_init }; -# undef NEXT_DEV -# define NEXT_DEV (&fddi_dev) -#endif +#ifdef CONFIG_FDDI + static struct device fddi7_dev = + {"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe}; + static struct device fddi6_dev = + {"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe}; + static struct device fddi5_dev = + {"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe}; + static struct device fddi4_dev = + {"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe}; + static struct device fddi3_dev = + {"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe}; + static struct device fddi2_dev = + {"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe}; + static struct device fddi1_dev = + {"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe}; + static struct device fddi0_dev = + {"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe}; +#undef NEXT_DEV +#define NEXT_DEV (&fddi0_dev) +#endif #ifdef CONFIG_APBIF extern int bif_init(struct device *dev); diff -u --recursive --new-file v2.1.66/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.1.66/linux/drivers/net/a2065.c Tue May 13 22:41:08 1997 +++ linux/drivers/net/a2065.c Sat Nov 29 10:33:19 1997 @@ -129,7 +129,7 @@ unsigned short busmaster_regval; #ifdef CONFIG_AMIGA - int key; + unsigned int key; #endif #ifdef CONFIG_SUNLANCE struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */ @@ -585,16 +585,6 @@ return status; } - if (skb == NULL) { - dev_tint (dev); - printk ("skb is NULL\n"); - return 0; - } - - if (skb->len <= 0) { - printk ("skb len is %d\n", skb->len); - return 0; - } /* Block a timer-based transmit from overlapping. */ #ifdef OLD_METHOD dev->tbusy = 1; @@ -737,20 +727,20 @@ __initfunc(int a2065_probe(struct device *dev)) { - int key1, key2 = 0; - struct ConfigDev *cd; + unsigned int key, is_cbm; + const struct ConfigDev *cd; u_long board; u_long sn; struct lance_private *priv; struct A2065Board *a2065; - if ((key1 = zorro_find(MANUF_COMMODORE, PROD_A2065, 0, 0)) || - (key1 = zorro_find(MANUF_COMMODORE, PROD_A2065_2, 0, 0)) || - (key2 = zorro_find(MANUF_AMERISTAR, PROD_AMERISTAR2065, 0, 0))) { - cd = zorro_get_board(key1 ? key1 : key2); + if ((key = is_cbm = zorro_find(ZORRO_PROD_CBM_A2065_1, 0, 0)) || + (key = is_cbm = zorro_find(ZORRO_PROD_CBM_A2065_2, 0, 0)) || + (key = zorro_find(ZORRO_PROD_AMERISTAR_A2065, 0, 0))) { + cd = zorro_get_board(key); if ((board = (u_long)cd->cd_BoardAddr)) { sn = cd->cd_Rom.er_SerialNumber; - if (key1) { /* Commodore */ + if (is_cbm) { /* Commodore */ dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x80; dev->dev_addr[2] = 0x10; @@ -783,7 +773,7 @@ priv->lance_init_block = (struct lance_init_block *) offsetof(struct A2065Board, RAM); priv->auto_select = 0; - priv->key = key1 ? key1 : key2; + priv->key = key; priv->busmaster_regval = LE_C3_BSWP; priv->lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS; @@ -799,11 +789,11 @@ dev->dma = 0; ether_setup(dev); - zorro_config_board(key1 ? key1 : key2, 0); + zorro_config_board(key, 0); return(0); } } - return(ENODEV); + return(-ENODEV); } diff -u --recursive --new-file v2.1.66/linux/drivers/net/apricot.c linux/drivers/net/apricot.c --- v2.1.66/linux/drivers/net/apricot.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/apricot.c Sat Nov 29 10:33:19 1997 @@ -598,17 +598,6 @@ dev->trans_start = jiffies; } - /* If some higher level thinks we've misses a tx-done interrupt - we are passed NULL. n.b. dev_tint handles the cli()/sti() - itself. */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - /* shouldn't happen */ - if (skb->len <= 0) return 0; - if (i596_debug > 3) printk("%s: i596_start_xmit() called\n", dev->name); /* Block a timer-based transmit from overlapping. This could better be diff -u --recursive --new-file v2.1.66/linux/drivers/net/arc-rimi.c linux/drivers/net/arc-rimi.c --- v2.1.66/linux/drivers/net/arc-rimi.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/arc-rimi.c Sat Nov 29 10:33:19 1997 @@ -1,4 +1,4 @@ -/* $Id: arc-rimi.c,v 1.2 1997/09/05 08:57:51 mj Exp $ +/* $Id: arc-rimi.c,v 1.5 1997/11/09 11:04:57 mj Exp $ Derived from the original arcnet.c, Written 1994-1996 by Avery Pennarun, @@ -131,7 +131,7 @@ #define SETCONF writeb(lp->config,_CONFIG) static const char *version = -"arc-rimi.c: v2.92 97/09/02 Avery Pennarun et al.\n"; +"arc-rimi.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** * * diff -u --recursive --new-file v2.1.66/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.1.66/linux/drivers/net/arcnet.c Sat Oct 25 02:44:15 1997 +++ linux/drivers/net/arcnet.c Sat Nov 29 10:33:19 1997 @@ -1,4 +1,4 @@ -/* $Id: arcnet.c,v 1.30 1997/09/05 08:57:46 mj Exp $ +/* $Id: arcnet.c,v 1.34 1997/11/09 11:04:55 mj Exp $ Written 1994-1996 by Avery Pennarun, derived from skeleton.c by Donald Becker. @@ -18,13 +18,21 @@ ********************** - v2.92 ALPHA (97/02/09) + v3.00 (97/11/09) + - Minor cleanup of debugging messages. [mj] + + v2.93 ALPHA (97/11/06) + - irq2dev mapping removed. + - Interrupt handler now checks whether dev->priv is non-null in order + to avoid crashes in interrupts which come during card init. [mj] + + v2.92 ALPHA (97/09/02) - Code cleanup [Martin Mares ] - Better probing for the COM90xx chipset, although only as a temporary solution until we implement adding of all found devices at once. [mj] - v2.91 ALPHA (97/19/08) + v2.91 ALPHA (97/08/19) - Add counting of octets in/out. v2.90 ALPHA (97/08/08) @@ -162,7 +170,7 @@ */ static const char *version = - "arcnet.c: v2.92 97/09/02 Avery Pennarun et al.\n"; + "arcnet.c: v3.00 97/11/09 Avery Pennarun et al.\n"; #include #include @@ -377,11 +385,6 @@ /* New-style flags. */ dev->flags = IFF_BROADCAST; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; /* Put in this stuff here, so we don't have to export the symbols * to the chipset drivers. @@ -541,7 +544,6 @@ #ifdef CONFIG_ARCNET_ETH /* free the ethernet-encap protocol device */ lp->edev->priv=NULL; - dev_close(lp->edev); unregister_netdev(lp->edev); kfree(lp->edev->name); kfree(lp->edev); @@ -551,7 +553,6 @@ #ifdef CONFIG_ARCNET_1051 /* free the RFC1051-encap protocol device */ lp->sdev->priv=NULL; - dev_close(lp->sdev); unregister_netdev(lp->sdev); kfree(lp->sdev->name); kfree(lp->sdev); @@ -924,14 +925,18 @@ if (dev==NULL) { - BUGLVL(D_DURING) - printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq); + BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq); return; } BUGMSG(D_DURING,"in arcnet_interrupt\n"); lp=(struct arcnet_local *)dev->priv; + if (!lp) + { + BUGMSG(D_DURING, "arcnet: irq ignored.\n"); + return; + } /* RESET flag was enabled - if !dev->start, we must clear it right * away (but nothing else) since inthandler() is never called. diff -u --recursive --new-file v2.1.66/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.1.66/linux/drivers/net/ariadne.c Tue May 13 22:41:08 1997 +++ linux/drivers/net/ariadne.c Sat Nov 29 10:33:19 1997 @@ -6,7 +6,7 @@ * Peter De Schrijver * (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) * - * ---------------------------------------------------------------------------------- + * --------------------------------------------------------------------------- * * This program is based on * @@ -20,13 +20,13 @@ * MC68230: Parallel Interface/Timer (PI/T) * Motorola Semiconductors, December, 1983 * - * ---------------------------------------------------------------------------------- + * --------------------------------------------------------------------------- * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of the Linux * distribution for more details. * - * ---------------------------------------------------------------------------------- + * --------------------------------------------------------------------------- * * The Ariadne is a Zorro-II board made by Village Tronic. It contains: * @@ -107,7 +107,7 @@ struct net_device_stats stats; char tx_full; unsigned long lock; - int key; + unsigned int key; }; @@ -148,13 +148,13 @@ __initfunc(int ariadne_probe(struct device *dev)) { - int key; - struct ConfigDev *cd; + unsigned int key; + const struct ConfigDev *cd; u_long board; struct ariadne_private *priv; /* Ethernet is part 0, Parallel is part 1 */ - if ((key = zorro_find(MANUF_VILLAGE_TRONIC, PROD_ARIADNE, 0, 0))) { + if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE, 0, 0))) { cd = zorro_get_board(key); if ((board = (u_long)cd->cd_BoardAddr)) { dev->dev_addr[0] = 0x00; diff -u --recursive --new-file v2.1.66/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c --- v2.1.66/linux/drivers/net/atarilance.c Tue May 13 22:41:09 1997 +++ linux/drivers/net/atarilance.c Sat Nov 29 10:33:19 1997 @@ -763,14 +763,6 @@ return( 0 ); } - if (skb == NULL) { - dev_tint( dev ); - return( 0 ); - } - - if (skb->len <= 0) - return( 0 ); - DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); diff -u --recursive --new-file v2.1.66/linux/drivers/net/bpqether.c linux/drivers/net/bpqether.c --- v2.1.66/linux/drivers/net/bpqether.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/bpqether.c Sat Nov 29 10:33:19 1997 @@ -77,7 +77,6 @@ #include #include #include -#include #include #include @@ -159,9 +158,6 @@ return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5) -#ifdef CONFIG_NET_ALIAS - && !net_alias_is(dev) -#endif ); } @@ -552,17 +548,7 @@ memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); - /* preset with reasonable values */ - dev->flags = 0; - dev->family = AF_INET; - -#ifdef CONFIG_INET - dev->pa_addr = in_aton("192.168.0.1"); - dev->pa_brdaddr = in_aton("192.168.0.255"); - dev->pa_mask = in_aton("255.255.255.0"); - dev->pa_alen = 4; -#endif #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) dev->hard_header = ax25_encapsulate; diff -u --recursive --new-file v2.1.66/linux/drivers/net/bsd_comp.c linux/drivers/net/bsd_comp.c --- v2.1.66/linux/drivers/net/bsd_comp.c Tue Dec 31 06:27:23 1996 +++ linux/drivers/net/bsd_comp.c Sat Nov 29 10:33:19 1997 @@ -39,17 +39,18 @@ /* * This version is for use with contiguous buffers on Linux-derived systems. * - * ==FILEVERSION 4== + * ==FILEVERSION 970607== * * NOTE TO MAINTAINERS: - * If you modify this file at all, increment the number above. + * If you modify this file at all, please set the number above to the + * date of the modification as YYMMDD (year month day). * bsd_comp.c is shipped with a PPP distribution as well as with * the kernel; if everyone increases the FILEVERSION number above, * then scripts can do the right thing when deciding whether to * install a new bsd_comp.c file. Don't change the format of that * line otherwise, so the installation script can recognize it. * - * $Id: bsd_comp.c,v 1.1 1994/12/08 01:59:58 paulus Exp $ + * From: bsd_comp.c,v 1.3 1994/12/08 01:59:58 paulus Exp */ #ifndef MODULE @@ -57,7 +58,6 @@ #endif #include - #include #include #include @@ -76,7 +76,6 @@ #include #include -#include #include #include @@ -89,14 +88,6 @@ #include -#ifdef NEW_SKBUFF -# /*nodep*/ include -#endif - -#include -#include -#include - #undef PACKETPTR #define PACKETPTR 1 #include @@ -142,14 +133,16 @@ union { /* hash value */ unsigned long fcode; struct { -#if defined(__LITTLE_ENDIAN) /* Little endian order */ +#if defined(__LITTLE_ENDIAN) /* Little endian order */ unsigned short prefix; /* preceding code */ unsigned char suffix; /* last character of new code */ unsigned char pad; -#elif defined(__BIG_ENDIAN) /* Big endian order */ +#elif defined(__BIG_ENDIAN) /* Big endian order */ unsigned char pad; unsigned char suffix; /* last character of new code */ unsigned short prefix; /* preceding code */ +#else +#error Endianness not defined... #endif } hs; } f; @@ -250,7 +243,6 @@ db->n_bits = BSD_INIT_BITS; db->bytes_out = 0; db->in_count = 0; - db->incomp_count = 0; db->ratio = 0; db->checkpoint = CHECK_GAP; } @@ -685,7 +677,7 @@ /* Skip the input header */ rptr += PPP_HDRLEN; isize -= PPP_HDRLEN; - ilen = ++isize; /* This is off by one, but that is what is in draft! */ + ilen = ++isize; /* Low byte of protocol is counted as input */ while (--ilen > 0) { @@ -774,7 +766,7 @@ OUTPUT(ent); /* output the last code */ - db->bytes_out += olen; /* Do not count bytes from here */ + db->bytes_out += olen - PPP_HDRLEN - BSD_OVHD; db->uncomp_bytes += isize; db->in_count += isize; ++db->uncomp_count; diff -u --recursive --new-file v2.1.66/linux/drivers/net/com20020.c linux/drivers/net/com20020.c --- v2.1.66/linux/drivers/net/com20020.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/com20020.c Sat Nov 29 10:33:19 1997 @@ -1,4 +1,4 @@ -/* $Id: com20020.c,v 1.2 1997/09/05 08:57:50 mj Exp $ +/* $Id: com20020.c,v 1.6 1997/11/09 11:04:58 mj Exp $ Written 1997 by David Woodhouse @@ -215,7 +215,7 @@ static const char *version = - "com20020.c: v2.92 97/09/02 Avery Pennarun et al.\n"; + "com20020.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** * * @@ -922,7 +922,8 @@ * frame. */ - put_whole_buffer(dev, lp->txbuf*512+offset,4,"\0\0xff\0xff\0xff"); + put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); + put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); offset+=4; } else /* "other" Exception packet */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/com90io.c linux/drivers/net/com90io.c --- v2.1.66/linux/drivers/net/com90io.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/com90io.c Sat Nov 29 10:33:19 1997 @@ -1,4 +1,4 @@ -/* $Id: com90io.c,v 1.2 1997/09/05 08:57:52 mj Exp $ +/* $Id: com90io.c,v 1.6 1997/11/09 11:04:59 mj Exp $ Written 1997 by David Woodhouse @@ -184,7 +184,7 @@ static const char *version = - "com90io.c: v2.91 97/08/19 Avery Pennarun et al.\n"; + "com90io.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** @@ -805,7 +805,8 @@ * frame. */ - put_whole_buffer(dev, lp->txbuf*512+offset,4,"\0\0xff\0xff\0xff"); + put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); + put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); offset+=4; } else /* "other" Exception packet */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c --- v2.1.66/linux/drivers/net/com90xx.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/com90xx.c Sat Nov 29 10:33:19 1997 @@ -1,4 +1,4 @@ -/* $Id: com90xx.c,v 1.3 1997/09/05 18:27:23 mj Exp $ +/* $Id: com90xx.c,v 1.6 1997/11/09 11:05:01 mj Exp $ Derived from the original arcnet.c, Written 1994-1996 by Avery Pennarun, @@ -154,7 +154,7 @@ #define ARCRESET inb(_RESET) static const char *version = - "com90xx.c: v2.92 97/09/02 Avery Pennarun et al.\n"; + "com90xx.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** diff -u --recursive --new-file v2.1.66/linux/drivers/net/cops.c linux/drivers/net/cops.c --- v2.1.66/linux/drivers/net/cops.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/cops.c Sat Nov 29 10:33:19 1997 @@ -23,10 +23,11 @@ * Can set board type in insmod * Hooks for cops_setup routine * (not yet implemented). + * 19971101 Jay Schulist Fixes for multiple lt* devices. */ static const char *version = - "cops.c:v0.01 3/17/97 Jay Schulist \n"; + "cops.c:v0.02 3/17/97 Jay Schulist \n"; /* * Sources: * COPS Localtalk SDK. This provides almost all of the information @@ -62,6 +63,7 @@ #include #include #include +#include #include #include @@ -119,9 +121,9 @@ * TANGENT driver mode: * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200 * DAYNA driver mode: - * Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, Farallon PhoneNET PC III + * Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, + * Farallon PhoneNET PC III, Farallon PhoneNET PC II * Other cards possibly supported mode unkown though: - * Farallon PhoneNET PC II * Dayna DL2000 (Full length) * * Cards NOT supported by this driver but supported by the ltpc.c @@ -165,29 +167,9 @@ int board; /* Holds what board type is. */ int nodeid; /* Set to 1 once have nodeid. */ unsigned char node_acquire; /* Node ID when acquired. */ + struct at_addr node_addr; /* Full node addres */ }; -/* Allocate a new device with the form of lt0, lt1, lt2, etc. */ -struct device *cops_dev_alloc(char *name) -{ - int i=0; - struct device *d=kmalloc(sizeof(struct device)+8, GFP_KERNEL); - - memset(d,0,sizeof(*d)); /* Clear the structure */ - if(d==NULL) - return NULL; - d->name=(char *)(d+1); /* Name string space */ - - /* Get next free device name */ - for(i=0;i<100;i++) - { - sprintf(d->name,name,i); - if(dev_get(d->name)==NULL) - return d; - } - return NULL; /* Over 100 of the things .. bail out! */ -} - /* Index to functions, as function prototypes. */ extern int cops_probe (struct device *dev); static int cops_probe1 (struct device *dev, int ioaddr); @@ -218,29 +200,27 @@ * If dev->base_addr == 2, allocate space for the device and return success * (detachable devices only). */ -int cops_probe(struct device *dev) +__initfunc(int cops_probe(struct device *dev)) { int i; int base_addr = dev ? dev->base_addr : 0; - if (base_addr == 0 && io) + if(base_addr == 0 && io) base_addr=io; - if (base_addr > 0x1ff) /* Check a single specified location. */ + if(base_addr > 0x1ff) /* Check a single specified location. */ return cops_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ + else if(base_addr != 0) /* Don't probe at all. */ return -ENXIO; - for (i=0; cops_portlist[i]; i++) { + for(i=0; cops_portlist[i]; i++) { int ioaddr = cops_portlist[i]; - if (check_region(ioaddr, COPS_IO_EXTENT)) + if(check_region(ioaddr, COPS_IO_EXTENT)) continue; - if (cops_probe1(dev, ioaddr) == 0) + if(cops_probe1(dev, ioaddr) == 0) return 0; } - /* No "lt" devices found. */ - printk(KERN_WARNING "%s: No COPS localtalk devices found!\n", dev->name); return -ENODEV; } @@ -249,7 +229,7 @@ * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ -static int cops_probe1(struct device *dev, int ioaddr) +__initfunc(static int cops_probe1(struct device *dev, int ioaddr)) { struct cops_local *lp; static unsigned version_printed = 0; @@ -258,17 +238,7 @@ int board = board_type; -/* Defined here to save some trouble */ - - /* Allocate a new 'dev' if needed. */ - if (dev == NULL) - { - dev=cops_dev_alloc(dev->name); /* New "lt" device; beyond lt0. */ - if(dev==NULL) - return -ENOMEM; - } - - if (cops_debug && version_printed++ == 0) + if(cops_debug && version_printed++ == 0) printk("%s", version); /* Fill in the 'dev' fields. */ @@ -280,21 +250,20 @@ * can use the interrupt, and this marks the irq as busy. Jumpered * interrupts are typically not reported by the boards, and we must * used AutoIRQ to find them. - * */ - if (dev->irq < 2 && irq) + if(dev->irq < 2 && irq) dev->irq = irq; - if (dev->irq < 2) + if(dev->irq < 2) { irqaddr = cops_irq(ioaddr, board); /* COPS AutoIRQ routine */ - if (irqaddr == 0) + if(irqaddr == 0) return -EAGAIN; /* No IRQ found on this port */ else dev->irq = irqaddr; } - else if (dev->irq == 2) + else if(dev->irq == 2) /* * Fixup for users that don't know that IRQ 2 is really * IRQ 9, or don't know which one to set. @@ -303,17 +272,18 @@ /* Snarf the interrupt now. */ irqval = request_irq(dev->irq, &cops_interrupt, 0, cardname, dev); - if (irqval) - { - printk(KERN_WARNING "%s: Unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); - return -EAGAIN; - } + + /* If its in use set it to 0 and disallow open() calls.. users can still + ifconfig the irq one day */ + + if(irqval) + dev->irq = 0; dev->hard_start_xmit = &cops_send_packet; /* Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL); - if (dev->priv == NULL) + if(dev->priv == NULL) return -ENOMEM; lp = (struct cops_local *)dev->priv; @@ -347,7 +317,7 @@ return 0; } -static int cops_irq (int ioaddr, int board) +__initfunc(static int cops_irq (int ioaddr, int board)) { /* * This does not use the IRQ to determine where the IRQ is. We just * assume that when we get a correct status response that is the IRQ then. @@ -379,7 +349,7 @@ if(board==DAYNA) { status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); - if (status == 1) + if(status == 1) return irqaddr; } if(board==TANGENT) @@ -398,6 +368,12 @@ */ static int cops_open(struct device *dev) { + if(dev->irq==0) + { + printk(KERN_WARNING "%s: No irq line set.\n", dev->name); + return -EAGAIN; + } + cops_jumpstart(dev); /* Start the card up. */ dev->tbusy = 0; @@ -508,7 +484,7 @@ /* Get card's firmware code and do some checks on it. */ #ifdef CONFIG_COPS_DAYNA - if (lp->board==DAYNA) + if(lp->board==DAYNA) { ltf->length=sizeof(ffdrv_code); ltf->data=ffdrv_code; @@ -516,7 +492,7 @@ else #endif #ifdef CONFIG_COPS_TANGENT - if (lp->board==TANGENT) + if(lp->board==TANGENT) { ltf->length=sizeof(ltdrv_code); ltf->data=ltdrv_code; @@ -595,7 +571,7 @@ struct cops_local *lp = (struct cops_local *) dev->priv; int ioaddr = dev->base_addr; - if (lp->board == DAYNA) + if(lp->board == DAYNA) { /* Empty any pending adapter responses. */ while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) @@ -612,7 +588,7 @@ outb(nodeid, ioaddr); /* Suggest node address. */ } - if (lp->board == TANGENT) + if(lp->board == TANGENT) { /* Empty any pending adapter responses. */ while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) @@ -669,7 +645,7 @@ int ioaddr, status; int boguscount = 0; - if (dev == NULL) + if(dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); return; @@ -693,7 +669,7 @@ else { status=inb(ioaddr+TANG_CARD_STATUS); - if (status&TANG_RX_READY) + if(status&TANG_RX_READY) cops_rx(dev); } @@ -747,7 +723,7 @@ /* Malloc up new buffer. */ skb = dev_alloc_skb(pkt_len); - if (skb == NULL) + if(skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; @@ -767,7 +743,7 @@ sti(); /* Restore interrupts. */ /* Check for bad response length */ - if (pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) + if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) { printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len); lp->stats.tx_errors++; @@ -814,14 +790,14 @@ struct cops_local *lp = (struct cops_local *)dev->priv; int ioaddr = dev->base_addr; - if (dev->tbusy) + 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 < 5) + if(tickssofar < 5) return 1; lp->stats.tx_errors++; if(lp->board==TANGENT) @@ -839,7 +815,7 @@ * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*) &dev->tbusy) != 0) + if(test_and_set_bit(0, (void*) &dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { @@ -916,7 +892,7 @@ { struct cops_local *lp = (struct cops_local *)dev->priv; struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr; - struct at_addr *aa=(struct at_addr *)&dev->pa_addr; + struct at_addr *aa=(struct at_addr *)&lp->node_addr; switch(cmd) { @@ -971,9 +947,11 @@ } #ifdef MODULE -static struct device dev_cops = +static char lt_name[16]; + +static struct device cops0_dev = { - "lt0", /* device name */ + lt_name, /* device name */ 0, 0, 0, 0, 0x0, 0, /* I/O address, IRQ */ 0, 0, 0, NULL, cops_probe @@ -986,16 +964,20 @@ int init_module(void) { - int result; + int result, err; - if (io == 0) + if(io == 0) printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n", cardname); /* Copy the parameters from insmod into the device structure. */ - dev_cops.base_addr = io; - dev_cops.irq = irq; + cops0_dev.base_addr = io; + cops0_dev.irq = irq; + + err=dev_alloc_name(&cops0_dev, "lt%d"); + if(err < 0) + return err; - if ((result = register_netdev(&dev_cops)) != 0) + if((result = register_netdev(&cops0_dev)) != 0) return result; return 0; @@ -1004,12 +986,10 @@ void cleanup_module(void) { /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - - free_irq(dev_cops.irq, &dev_cops); - release_region(dev_cops.base_addr, COPS_IO_EXTENT); - unregister_netdev(&dev_cops); - - if (dev_cops.priv) - kfree_s(dev_cops.priv, sizeof(struct cops_local)); + unregister_netdev(&cops0_dev); + if(cops0_dev.priv) + kfree_s(cops0_dev.priv, sizeof(struct cops_local)); + free_irq(cops0_dev.irq, &cops0_dev); + release_region(cops0_dev.base_addr, COPS_IO_EXTENT); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.66/linux/drivers/net/de4x5.c Mon Nov 17 18:47:21 1997 +++ linux/drivers/net/de4x5.c Sat Nov 29 10:33:19 1997 @@ -1,45 +1,45 @@ /* de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500 - ethernet driver for Linux. + ethernet driver for Linux. - Copyright 1994, 1995 Digital Equipment Corporation. + Copyright 1994, 1995 Digital Equipment Corporation. - Testing resources for this driver have been made available - in part by NASA Ames Research Center (mjacob@nas.nasa.gov). + Testing resources for this driver have been made available + in part by NASA Ames Research Center (mjacob@nas.nasa.gov). - The author may be reached at davies@maniac.ultranet.com. + The author may be reached at davies@maniac.ultranet.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - 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. - - Originally, this driver was written for the Digital Equipment - Corporation series of EtherWORKS ethernet cards: - - DE425 TP/COAX EISA - DE434 TP PCI - DE435 TP/COAX/AUI PCI - DE450 TP/COAX/AUI PCI - DE500 10/100 PCI Fasternet - - but it will now attempt to support all cards which conform to the - Digital Semiconductor SROM Specification. The driver currently - recognises the following chips: + 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + 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. + + Originally, this driver was written for the Digital Equipment + Corporation series of EtherWORKS ethernet cards: + + DE425 TP/COAX EISA + DE434 TP PCI + DE435 TP/COAX/AUI PCI + DE450 TP/COAX/AUI PCI + DE500 10/100 PCI Fasternet + + but it will now attempt to support all cards which conform to the + Digital Semiconductor SROM Specification. The driver currently + recognises the following chips: DC21040 (no SROM) DC21041[A] @@ -49,136 +49,136 @@ So far the driver is known to work with the following cards: - KINGSTON - Linksys - ZNYX342 - SMC8432 - SMC9332 (w/new SROM) - ZNYX31[45] - ZNYX346 10/100 4 port (can act as a 10/100 bridge!) - - The driver has been tested on a relatively busy network using the DE425, - DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred - 16M of data to a DECstation 5000/200 as follows: - - TCP UDP - TX RX TX RX - DE425 1030k 997k 1170k 1128k - DE434 1063k 995k 1170k 1125k - DE435 1063k 995k 1170k 1125k - DE500 1063k 998k 1170k 1125k in 10Mb/s mode - - All values are typical (in kBytes/sec) from a sample of 4 for each - measurement. Their error is +/-20k on a quiet (private) network and also - depend on what load the CPU has. - - ========================================================================= - This driver has been written substantially from scratch, although its - inheritance of style and stack interface from 'ewrk3.c' and in turn from - Donald Becker's 'lance.c' should be obvious. With the module autoload of - every usable DECchip board, I pinched Donald's 'next_module' field to - link my modules together. - - Upto 15 EISA cards can be supported under this driver, limited primarily - by the available IRQ lines. I have checked different configurations of - multiple depca, EtherWORKS 3 cards and de4x5 cards and have not found a - problem yet (provided you have at least depca.c v0.38) ... - - PCI support has been added to allow the driver to work with the DE434, - DE435, DE450 and DE500 cards. The I/O accesses are a bit of a kludge due - to the differences in the EISA and PCI CSR address offsets from the base - address. - - The ability to load this driver as a loadable module has been included - and used extensively during the driver development (to save those long - reboot sequences). Loadable module support under PCI and EISA has been - achieved by letting the driver autoprobe as if it were compiled into the - kernel. Do make sure you're not sharing interrupts with anything that - cannot accommodate interrupt sharing! - - To utilise this ability, you have to do 8 things: - - 0) have a copy of the loadable modules code installed on your system. - 1) copy de4x5.c from the /linux/drivers/net directory to your favourite - temporary directory. - 2) for fixed autoprobes (not recommended), edit the source code near - line 5539 to reflect the I/O address you're using, or assign these when - loading by: - - insmod de4x5 io=0xghh where g = bus number - hh = device number - - NB: autoprobing for modules is now supported by default. You may just - use: - - insmod de4x5 - - to load all available boards. For a specific board, still use - the 'io=?' above. - 3) compile de4x5.c, but include -DMODULE in the command line to ensure - that the correct bits are compiled (see end of source code). - 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a - kernel with the de4x5 configuration turned off and reboot. - 5) insmod de4x5 [io=0xghh] - 6) run the net startup bits for your new eth?? interface(s) manually - (usually /etc/rc.inet[12] at boot time). - 7) enjoy! - - To unload a module, turn off the associated interface(s) - 'ifconfig eth?? down' then 'rmmod de4x5'. - - Automedia detection is included so that in principal you can disconnect - from, e.g. TP, reconnect to BNC and things will still work (after a - pause whilst the driver figures out where its media went). My tests - using ping showed that it appears to work.... - - By default, the driver will now autodetect any DECchip based card. - Should you have a need to restrict the driver to DIGITAL only cards, you - can compile with a DEC_ONLY define, or if loading as a module, use the - 'dec_only=1' parameter. - - I've changed the timing routines to use the kernel timer and scheduling - functions so that the hangs and other assorted problems that occurred - while autosensing the media should be gone. A bonus for the DC21040 - auto media sense algorithm is that it can now use one that is more in - line with the rest (the DC21040 chip doesn't have a hardware timer). - The downside is the 1 'jiffies' (10ms) resolution. - - IEEE 802.3u MII interface code has been added in anticipation that some - products may use it in the future. - - The SMC9332 card has a non-compliant SROM which needs fixing - I have - patched this driver to detect it because the SROM format used complies - to a previous DEC-STD format. - - I have removed the buffer copies needed for receive on Intels. I cannot - remove them for Alphas since the Tulip hardware only does longword - aligned DMA transfers and the Alphas get alignment traps with non - longword aligned data copies (which makes them really slow). No comment. - - I have added SROM decoding routines to make this driver work with any - card that supports the Digital Semiconductor SROM spec. This will help - all cards running the dc2114x series chips in particular. Cards using - the dc2104x chips should run correctly with the basic driver. I'm in - debt to for the testing and feedback that helped get - this feature working. So far we have tested KINGSTON, SMC8432, SMC9332 - (with the latest SROM complying with the SROM spec V3: their first was - broken), ZNYX342 and LinkSys. ZYNX314 (dual 21041 MAC) and ZNYX 315 - (quad 21041 MAC) cards also appear to work despite their incorrectly - wired IRQs. - - I have added a temporary fix for interrupt problems when some SCSI cards - share the same interrupt as the DECchip based cards. The problem occurs - because the SCSI card wants to grab the interrupt as a fast interrupt - (runs the service routine with interrupts turned off) vs. this card - which really needs to run the service routine with interrupts turned on. - This driver will now add the interrupt service routine as a fast - interrupt if it is bounced from the slow interrupt. THIS IS NOT A - RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time - until people sort out their compatibility issues and the kernel - interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST - INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not - run on the same interrupt. PCMCIA/CardBus is another can of worms... + KINGSTON + Linksys + ZNYX342 + SMC8432 + SMC9332 (w/new SROM) + ZNYX31[45] + ZNYX346 10/100 4 port (can act as a 10/100 bridge!) + + The driver has been tested on a relatively busy network using the DE425, + DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred + 16M of data to a DECstation 5000/200 as follows: + + TCP UDP + TX RX TX RX + DE425 1030k 997k 1170k 1128k + DE434 1063k 995k 1170k 1125k + DE435 1063k 995k 1170k 1125k + DE500 1063k 998k 1170k 1125k in 10Mb/s mode + + All values are typical (in kBytes/sec) from a sample of 4 for each + measurement. Their error is +/-20k on a quiet (private) network and also + depend on what load the CPU has. + + ========================================================================= + This driver has been written substantially from scratch, although its + inheritance of style and stack interface from 'ewrk3.c' and in turn from + Donald Becker's 'lance.c' should be obvious. With the module autoload of + every usable DECchip board, I pinched Donald's 'next_module' field to + link my modules together. + + Upto 15 EISA cards can be supported under this driver, limited primarily + by the available IRQ lines. I have checked different configurations of + multiple depca, EtherWORKS 3 cards and de4x5 cards and have not found a + problem yet (provided you have at least depca.c v0.38) ... + + PCI support has been added to allow the driver to work with the DE434, + DE435, DE450 and DE500 cards. The I/O accesses are a bit of a kludge due + to the differences in the EISA and PCI CSR address offsets from the base + address. + + The ability to load this driver as a loadable module has been included + and used extensively during the driver development (to save those long + reboot sequences). Loadable module support under PCI and EISA has been + achieved by letting the driver autoprobe as if it were compiled into the + kernel. Do make sure you're not sharing interrupts with anything that + cannot accommodate interrupt sharing! + + To utilise this ability, you have to do 8 things: + + 0) have a copy of the loadable modules code installed on your system. + 1) copy de4x5.c from the /linux/drivers/net directory to your favourite + temporary directory. + 2) for fixed autoprobes (not recommended), edit the source code near + line 5539 to reflect the I/O address you're using, or assign these when + loading by: + + insmod de4x5 io=0xghh where g = bus number + hh = device number + + NB: autoprobing for modules is now supported by default. You may just + use: + + insmod de4x5 + + to load all available boards. For a specific board, still use + the 'io=?' above. + 3) compile de4x5.c, but include -DMODULE in the command line to ensure + that the correct bits are compiled (see end of source code). + 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a + kernel with the de4x5 configuration turned off and reboot. + 5) insmod de4x5 [io=0xghh] + 6) run the net startup bits for your new eth?? interface(s) manually + (usually /etc/rc.inet[12] at boot time). + 7) enjoy! + + To unload a module, turn off the associated interface(s) + 'ifconfig eth?? down' then 'rmmod de4x5'. + + Automedia detection is included so that in principal you can disconnect + from, e.g. TP, reconnect to BNC and things will still work (after a + pause whilst the driver figures out where its media went). My tests + using ping showed that it appears to work.... + + By default, the driver will now autodetect any DECchip based card. + Should you have a need to restrict the driver to DIGITAL only cards, you + can compile with a DEC_ONLY define, or if loading as a module, use the + 'dec_only=1' parameter. + + I've changed the timing routines to use the kernel timer and scheduling + functions so that the hangs and other assorted problems that occurred + while autosensing the media should be gone. A bonus for the DC21040 + auto media sense algorithm is that it can now use one that is more in + line with the rest (the DC21040 chip doesn't have a hardware timer). + The downside is the 1 'jiffies' (10ms) resolution. + + IEEE 802.3u MII interface code has been added in anticipation that some + products may use it in the future. + + The SMC9332 card has a non-compliant SROM which needs fixing - I have + patched this driver to detect it because the SROM format used complies + to a previous DEC-STD format. + + I have removed the buffer copies needed for receive on Intels. I cannot + remove them for Alphas since the Tulip hardware only does longword + aligned DMA transfers and the Alphas get alignment traps with non + longword aligned data copies (which makes them really slow). No comment. + + I have added SROM decoding routines to make this driver work with any + card that supports the Digital Semiconductor SROM spec. This will help + all cards running the dc2114x series chips in particular. Cards using + the dc2104x chips should run correctly with the basic driver. I'm in + debt to for the testing and feedback that helped get + this feature working. So far we have tested KINGSTON, SMC8432, SMC9332 + (with the latest SROM complying with the SROM spec V3: their first was + broken), ZNYX342 and LinkSys. ZYNX314 (dual 21041 MAC) and ZNYX 315 + (quad 21041 MAC) cards also appear to work despite their incorrectly + wired IRQs. + + I have added a temporary fix for interrupt problems when some SCSI cards + share the same interrupt as the DECchip based cards. The problem occurs + because the SCSI card wants to grab the interrupt as a fast interrupt + (runs the service routine with interrupts turned off) vs. this card + which really needs to run the service routine with interrupts turned on. + This driver will now add the interrupt service routine as a fast + interrupt if it is bounced from the slow interrupt. THIS IS NOT A + RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time + until people sort out their compatibility issues and the kernel + interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST + INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not + run on the same interrupt. PCMCIA/CardBus is another can of worms... Finally, I think I have really fixed the module loading problem with more than one DECchip based card. As a side effect, I don't mess with @@ -196,129 +196,129 @@ feature in the SROM autoconf code, this detection will occur automatically. - TO DO: - ------ + TO DO: + ------ o check what revision numbers the 21142 and 21143 have o - Revision History - ---------------- + Revision History + ---------------- - Version Date Description - - 0.1 17-Nov-94 Initial writing. ALPHA code release. - 0.2 13-Jan-95 Added PCI support for DE435's. - 0.21 19-Jan-95 Added auto media detection. - 0.22 10-Feb-95 Fix interrupt handler call . - Fix recognition bug reported by . - Add request/release_region code. - Add loadable modules support for PCI. - Clean up loadable modules support. - 0.23 28-Feb-95 Added DC21041 and DC21140 support. - Fix missed frame counter value and initialisation. - Fixed EISA probe. - 0.24 11-Apr-95 Change delay routine to use . - Change TX_BUFFS_AVAIL macro. - Change media autodetection to allow manual setting. - Completed DE500 (DC21140) support. - 0.241 18-Apr-95 Interim release without DE500 Autosense Algorithm. - 0.242 10-May-95 Minor changes. - 0.30 12-Jun-95 Timer fix for DC21140. - Portability changes. - Add ALPHA changes from . - Add DE500 semi automatic autosense. - Add Link Fail interrupt TP failure detection. - Add timer based link change detection. - Plugged a memory leak in de4x5_queue_pkt(). - 0.31 13-Jun-95 Fixed PCI stuff for 1.3.1. - 0.32 26-Jun-95 Added verify_area() calls in de4x5_ioctl() from a - suggestion by . - 0.33 8-Aug-95 Add shared interrupt support (not released yet). - 0.331 21-Aug-95 Fix de4x5_open() with fast CPUs. - Fix de4x5_interrupt(). - Fix dc21140_autoconf() mess. - No shared interrupt support. - 0.332 11-Sep-95 Added MII management interface routines. - 0.40 5-Mar-96 Fix setup frame timeout . - Add kernel timer code (h/w is too flaky). - Add MII based PHY autosense. - Add new multicasting code. - Add new autosense algorithms for media/mode - selection using kernel scheduling/timing. - Re-formatted. - Made changes suggested by : - Change driver to detect all DECchip based cards - with DEC_ONLY restriction a special case. - Changed driver to autoprobe as a module. No irq - checking is done now - assume BIOS is good! - Added SMC9332 detection - 0.41 21-Mar-96 Don't check for get_hw_addr checksum unless DEC card - only - Fix for multiple PCI cards reported by - Duh, put the SA_SHIRQ flag into request_interrupt(). - Fix SMC ethernet address in enet_det[]. - Print chip name instead of "UNKNOWN" during boot. - 0.42 26-Apr-96 Fix MII write TA bit error. - Fix bug in dc21040 and dc21041 autosense code. - Remove buffer copies on receive for Intels. - Change sk_buff handling during media disconnects to - eliminate DUP packets. - Add dynamic TX thresholding. - Change all chips to use perfect multicast filtering. - Fix alloc_device() bug - 0.43 21-Jun-96 Fix unconnected media TX retry bug. - Add Accton to the list of broken cards. - Fix TX under-run bug for non DC21140 chips. - Fix boot command probe bug in alloc_device() as - reported by and - . - Add cache locks to prevent a race condition as - reported by and - . - Upgraded alloc_device() code. - 0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion - with - 0.44 13-Aug-96 Fix RX overflow bug in 2114[023] chips. - Fix EISA probe bugs reported by - and . - 0.441 9-Sep-96 Change dc21041_autoconf() to probe quiet BNC media - with a loopback packet. - 0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported - by - 0.45 8-Dec-96 Include endian functions for PPC use, from work - by and . - 0.451 28-Dec-96 Added fix to allow autoprobe for modules after - suggestion from . - 0.5 30-Jan-97 Added SROM decoding functions. - Updated debug flags. - Fix sleep/wakeup calls for PCI cards, bug reported - by . - Added multi-MAC, one SROM feature from discussion - with . - Added full module autoprobe capability. - Added attempt to use an SMC9332 with broken SROM. - Added fix for ZYNX multi-mac cards that didn't - get their IRQs wired correctly. - 0.51 13-Feb-97 Added endian fixes for the SROM accesses from - - Fix init_connection() to remove extra device reset. - Fix MAC/PHY reset ordering in dc21140m_autoconf(). - Fix initialisation problem with lp->timeout in - typeX_infoblock() from . - Fix MII PHY reset problem from work done by - . - 0.52 26-Apr-97 Some changes may not credit the right people - - a disk crash meant I lost some mail. - Change RX interrupt routine to drop rather than - defer packets to avoid hang reported by - . - Fix srom_exec() to return for COMPACT and type 1 - infoblocks. - Added DC21142 and DC21143 functions. - Added byte counters from - Added SA_INTERRUPT temporary fix from - . + Version Date Description + + 0.1 17-Nov-94 Initial writing. ALPHA code release. + 0.2 13-Jan-95 Added PCI support for DE435's. + 0.21 19-Jan-95 Added auto media detection. + 0.22 10-Feb-95 Fix interrupt handler call . + Fix recognition bug reported by . + Add request/release_region code. + Add loadable modules support for PCI. + Clean up loadable modules support. + 0.23 28-Feb-95 Added DC21041 and DC21140 support. + Fix missed frame counter value and initialisation. + Fixed EISA probe. + 0.24 11-Apr-95 Change delay routine to use . + Change TX_BUFFS_AVAIL macro. + Change media autodetection to allow manual setting. + Completed DE500 (DC21140) support. + 0.241 18-Apr-95 Interim release without DE500 Autosense Algorithm. + 0.242 10-May-95 Minor changes. + 0.30 12-Jun-95 Timer fix for DC21140. + Portability changes. + Add ALPHA changes from . + Add DE500 semi automatic autosense. + Add Link Fail interrupt TP failure detection. + Add timer based link change detection. + Plugged a memory leak in de4x5_queue_pkt(). + 0.31 13-Jun-95 Fixed PCI stuff for 1.3.1. + 0.32 26-Jun-95 Added verify_area() calls in de4x5_ioctl() from a + suggestion by . + 0.33 8-Aug-95 Add shared interrupt support (not released yet). + 0.331 21-Aug-95 Fix de4x5_open() with fast CPUs. + Fix de4x5_interrupt(). + Fix dc21140_autoconf() mess. + No shared interrupt support. + 0.332 11-Sep-95 Added MII management interface routines. + 0.40 5-Mar-96 Fix setup frame timeout . + Add kernel timer code (h/w is too flaky). + Add MII based PHY autosense. + Add new multicasting code. + Add new autosense algorithms for media/mode + selection using kernel scheduling/timing. + Re-formatted. + Made changes suggested by : + Change driver to detect all DECchip based cards + with DEC_ONLY restriction a special case. + Changed driver to autoprobe as a module. No irq + checking is done now - assume BIOS is good! + Added SMC9332 detection + 0.41 21-Mar-96 Don't check for get_hw_addr checksum unless DEC card + only + Fix for multiple PCI cards reported by + Duh, put the SA_SHIRQ flag into request_interrupt(). + Fix SMC ethernet address in enet_det[]. + Print chip name instead of "UNKNOWN" during boot. + 0.42 26-Apr-96 Fix MII write TA bit error. + Fix bug in dc21040 and dc21041 autosense code. + Remove buffer copies on receive for Intels. + Change sk_buff handling during media disconnects to + eliminate DUP packets. + Add dynamic TX thresholding. + Change all chips to use perfect multicast filtering. + Fix alloc_device() bug + 0.43 21-Jun-96 Fix unconnected media TX retry bug. + Add Accton to the list of broken cards. + Fix TX under-run bug for non DC21140 chips. + Fix boot command probe bug in alloc_device() as + reported by and + . + Add cache locks to prevent a race condition as + reported by and + . + Upgraded alloc_device() code. + 0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion + with + 0.44 13-Aug-96 Fix RX overflow bug in 2114[023] chips. + Fix EISA probe bugs reported by + and . + 0.441 9-Sep-96 Change dc21041_autoconf() to probe quiet BNC media + with a loopback packet. + 0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported + by + 0.45 8-Dec-96 Include endian functions for PPC use, from work + by and . + 0.451 28-Dec-96 Added fix to allow autoprobe for modules after + suggestion from . + 0.5 30-Jan-97 Added SROM decoding functions. + Updated debug flags. + Fix sleep/wakeup calls for PCI cards, bug reported + by . + Added multi-MAC, one SROM feature from discussion + with . + Added full module autoprobe capability. + Added attempt to use an SMC9332 with broken SROM. + Added fix for ZYNX multi-mac cards that didn't + get their IRQs wired correctly. + 0.51 13-Feb-97 Added endian fixes for the SROM accesses from + + Fix init_connection() to remove extra device reset. + Fix MAC/PHY reset ordering in dc21140m_autoconf(). + Fix initialisation problem with lp->timeout in + typeX_infoblock() from . + Fix MII PHY reset problem from work done by + . + 0.52 26-Apr-97 Some changes may not credit the right people - + a disk crash meant I lost some mail. + Change RX interrupt routine to drop rather than + defer packets to avoid hang reported by + . + Fix srom_exec() to return for COMPACT and type 1 + infoblocks. + Added DC21142 and DC21143 functions. + Added byte counters from + Added SA_INTERRUPT temporary fix from + . 0.53 12-Nov-97 Fix the *_probe() to include 'eth??' name during module load: bug reported by @@ -328,8 +328,8 @@ direction. Completed DC2114[23] autosense functions. - ========================================================================= -*/ + ========================================================================= + */ static const char *version = "de4x5.c:V0.53 1997/11/12 davies@maniac.ultranet.com\n"; @@ -388,71 +388,77 @@ #else # include # include -#endif /* LINUX_VERSION_CODE */ +#endif /* LINUX_VERSION_CODE */ #define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) /* ** MII Information */ struct phy_table { - int reset; /* Hard reset required? */ - int id; /* IEEE OUI */ - int ta; /* One cycle TA time - 802.3u is confusing here */ - struct { /* Non autonegotiation (parallel) speed det. */ - int reg; - int mask; - int value; - } spd; + int reset; /* Hard reset required? */ + int id; /* IEEE OUI */ + int ta; /* One cycle TA time - 802.3u is confusing here */ + struct { /* Non autonegotiation (parallel) speed det. */ + int reg; + int mask; + int value; + } spd; }; struct mii_phy { - int reset; /* Hard reset required? */ - int id; /* IEEE OUI */ - int ta; /* One cycle TA time */ - struct { /* Non autonegotiation (parallel) speed det. */ - int reg; - int mask; - int value; - } spd; - int addr; /* MII address for the PHY */ - u_char *gep; /* Start of GEP sequence block in SROM */ - u_char *rst; /* Start of reset sequence in SROM */ - u_int mc; /* Media Capabilities */ - u_int ana; /* NWay Advertisement */ - u_int fdx; /* Full DupleX capabilites for each media */ - u_int ttm; /* Transmit Threshold Mode for each media */ - u_int mci; /* 21142 MII Connector Interrupt info */ + int reset; /* Hard reset required? */ + int id; /* IEEE OUI */ + int ta; /* One cycle TA time */ + struct { /* Non autonegotiation (parallel) speed det. */ + int reg; + int mask; + int value; + } spd; + int addr; /* MII address for the PHY */ + u_char *gep; /* Start of GEP sequence block in SROM */ + u_char *rst; /* Start of reset sequence in SROM */ + u_int mc; /* Media Capabilities */ + u_int ana; /* NWay Advertisement */ + u_int fdx; /* Full DupleX capabilites for each media */ + u_int ttm; /* Transmit Threshold Mode for each media */ + u_int mci; /* 21142 MII Connector Interrupt info */ }; -#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */ +#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */ struct sia_phy { - u_char mc; /* Media Code */ - u_char ext; /* csr13-15 valid when set */ - int csr13; /* SIA Connectivity Register */ - int csr14; /* SIA TX/RX Register */ - int csr15; /* SIA General Register */ - int gepc; /* SIA GEP Control Information */ - int gep; /* SIA GEP Data */ + u_char mc; /* Media Code */ + u_char ext; /* csr13-15 valid when set */ + int csr13; /* SIA Connectivity Register */ + int csr14; /* SIA TX/RX Register */ + int csr15; /* SIA General Register */ + int gepc; /* SIA GEP Control Information */ + int gep; /* SIA GEP Data */ }; /* ** Define the know universe of PHY devices that can be ** recognised by this driver */ -static struct phy_table phy_info[] = { - {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */ - {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */ - {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */ - {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */ +static struct phy_table phy_info[] = +{ + {0, NATIONAL_TX, 1, + {0x19, 0x40, 0x00}}, /* National TX */ + {1, BROADCOM_T4, 1, + {0x10, 0x02, 0x02}}, /* Broadcom T4 */ + {0, SEEQ_T4, 1, + {0x12, 0x10, 0x10}}, /* SEEQ T4 */ + {0, CYPRESS_T4, 1, + {0x05, 0x20, 0x20}} /* Cypress T4 */ }; /* ** Define special SROM detection cases */ -static c_char enet_det[][ETH_ALEN] = { - {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00} +static c_char enet_det[][ETH_ALEN] = +{ + {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00} }; #define SMC 1 @@ -463,14 +469,14 @@ ** use this information to help figure out what to do. This is a ** "stab in the dark" and so far for SMC9332's only. */ -static c_char srom_repair_info[][100] = { - {0x00,0x1e,0x00,0x00,0x00,0x08, /* SMC9332 */ - 0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02, - 0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50, - 0x00,0x18,} +static c_char srom_repair_info[][100] = +{ + {0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, /* SMC9332 */ + 0x1f, 0x01, 0x8f, 0x01, 0x00, 0x01, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x78, 0xe0, 0x01, 0x00, 0x50, + 0x00, 0x18,} }; - #ifdef DE4X5_DEBUG static int de4x5_debug = DE4X5_DEBUG; #else @@ -478,20 +484,20 @@ static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION); #endif -#ifdef DE4X5_AUTOSENSE /* Should be done on a per adapter basis */ +#ifdef DE4X5_AUTOSENSE /* Should be done on a per adapter basis */ static int de4x5_autosense = DE4X5_AUTOSENSE; #else -static int de4x5_autosense = AUTO; /* Do auto media/mode sensing */ +static int de4x5_autosense = AUTO; /* Do auto media/mode sensing */ #endif -#define DE4X5_AUTOSENSE_MS 250 /* msec autosense tick (DE500) */ +#define DE4X5_AUTOSENSE_MS 250 /* msec autosense tick (DE500) */ -#ifdef DE4X5_FULL_DUPLEX /* Should be done on a per adapter basis */ +#ifdef DE4X5_FULL_DUPLEX /* Should be done on a per adapter basis */ static s32 de4x5_full_duplex = 1; #else static s32 de4x5_full_duplex = 0; #endif -#define DE4X5_NDA 0xffe0 /* No Device (I/O) Address */ +#define DE4X5_NDA 0xffe0 /* No Device (I/O) Address */ /* ** Ethernet PROM defines @@ -502,24 +508,24 @@ /* ** Ethernet Info */ -#define PKT_BUF_SZ 1536 /* Buffer size for each Tx/Rx buffer */ -#define IEEE802_3_SZ 1518 /* Packet + CRC */ -#define MAX_PKT_SZ 1514 /* Maximum ethernet packet length */ -#define MAX_DAT_SZ 1500 /* Maximum ethernet data length */ -#define MIN_DAT_SZ 1 /* Minimum ethernet data length */ -#define PKT_HDR_LEN 14 /* Addresses and data length info */ +#define PKT_BUF_SZ 1536 /* Buffer size for each Tx/Rx buffer */ +#define IEEE802_3_SZ 1518 /* Packet + CRC */ +#define MAX_PKT_SZ 1514 /* Maximum ethernet packet length */ +#define MAX_DAT_SZ 1500 /* Maximum ethernet data length */ +#define MIN_DAT_SZ 1 /* Minimum ethernet data length */ +#define PKT_HDR_LEN 14 /* Addresses and data length info */ #define FAKE_FRAME_LEN (MAX_PKT_SZ + 1) -#define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */ +#define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */ -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ /* ** EISA bus defines */ -#define DE4X5_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ -#define DE4X5_EISA_TOTAL_SIZE 0x100 /* I/O address extent */ +#define DE4X5_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ +#define DE4X5_EISA_TOTAL_SIZE 0x100 /* I/O address extent */ #define MAX_EISA_SLOTS 16 #define EISA_SLOT_INC 0x1000 @@ -532,8 +538,8 @@ ** PCI Bus defines */ #define PCI_MAX_BUS_NUM 8 -#define DE4X5_PCI_TOTAL_SIZE 0x80 /* I/O address extent */ -#define DE4X5_CLASS_CODE 0x00020000 /* Network controller, Ethernet */ +#define DE4X5_PCI_TOTAL_SIZE 0x80 /* I/O address extent */ +#define DE4X5_CLASS_CODE 0x00020000 /* Network controller, Ethernet */ #define NO_MORE_PCI -2 /* PCI bus search all done */ /* @@ -542,20 +548,20 @@ ** DESC_ALIGN. ALIGN aligns the start address of the private memory area ** and hence the RX descriptor ring's first entry. */ -#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ -#define ALIGN8 ((u_long)8 - 1) /* 2 longword align */ -#define ALIGN16 ((u_long)16 - 1) /* 4 longword align */ -#define ALIGN32 ((u_long)32 - 1) /* 8 longword align */ -#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */ -#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */ +#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ +#define ALIGN8 ((u_long)8 - 1) /* 2 longword align */ +#define ALIGN16 ((u_long)16 - 1) /* 4 longword align */ +#define ALIGN32 ((u_long)32 - 1) /* 8 longword align */ +#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */ +#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */ -#define ALIGN ALIGN32 /* Keep the DC21040 happy... */ +#define ALIGN ALIGN32 /* Keep the DC21040 happy... */ #define CACHE_ALIGN CAL_16LONG -#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */ +#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */ /*#define DESC_ALIGN u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */ #define DESC_ALIGN -#ifndef DEC_ONLY /* See README.de4x5 for using this */ +#ifndef DEC_ONLY /* See README.de4x5 for using this */ static int dec_only = 0; #else static int dec_only = 1; @@ -604,7 +610,7 @@ /* ** DE4X5 SIA RESET */ -#define RESET_SIA outl(0, DE4X5_SICR); /* Reset SIA connectivity regs */ +#define RESET_SIA outl(0, DE4X5_SICR); /* Reset SIA connectivity regs */ /* ** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS) @@ -615,17 +621,18 @@ ** SROM Structure */ struct de4x5_srom { - char sub_vendor_id[2]; - char sub_system_id[2]; - char reserved[12]; - char id_block_crc; - char reserved2; - char version; - char num_controllers; - char ieee_addr[6]; - char info[100]; - short chksum; + char sub_vendor_id[2]; + char sub_system_id[2]; + char reserved[12]; + char id_block_crc; + char reserved2; + char version; + char num_controllers; + char ieee_addr[6]; + char info[100]; + short chksum; }; + #define SUB_VENDOR_ID 0x500a /* @@ -636,106 +643,106 @@ ** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX ** descriptors are needed for machines with an ALPHA CPU. */ -#define NUM_RX_DESC 8 /* Number of RX descriptors */ -#define NUM_TX_DESC 32 /* Number of TX descriptors */ -#define RX_BUFF_SZ 1536 /* Power of 2 for kmalloc and */ - /* Multiple of 4 for DC21040 */ - /* Allows 512 byte alignment */ +#define NUM_RX_DESC 8 /* Number of RX descriptors */ +#define NUM_TX_DESC 32 /* Number of TX descriptors */ +#define RX_BUFF_SZ 1536 /* Power of 2 for kmalloc and */ + /* Multiple of 4 for DC21040 */ + /* Allows 512 byte alignment */ struct de4x5_desc { - volatile s32 status; - u32 des1; - u32 buf; - u32 next; - DESC_ALIGN + volatile s32 status; + u32 des1; + u32 buf; + u32 next; + DESC_ALIGN }; /* ** The DE4X5 private structure */ #define DE4X5_PKT_STAT_SZ 16 -#define DE4X5_PKT_BIN_SZ 128 /* Should be >=100 unless you - increase DE4X5_PKT_STAT_SZ */ +#define DE4X5_PKT_BIN_SZ 128 /* Should be >=100 unless you + increase DE4X5_PKT_STAT_SZ */ struct de4x5_private { - char adapter_name[80]; /* Adapter name */ - struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ - struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ - struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */ - struct sk_buff *rx_skb[NUM_RX_DESC]; /* RX skb's */ - int rx_new, rx_old; /* RX descriptor ring pointers */ - int tx_new, tx_old; /* TX descriptor ring pointers */ - char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */ - char frame[64]; /* Min sized packet for loopback*/ - struct net_device_stats stats; /* Public stats */ - struct { - u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */ - u_int unicast; - u_int multicast; - u_int broadcast; - u_int excessive_collisions; - u_int tx_underruns; - u_int excessive_underruns; - u_int rx_runt_frames; - u_int rx_collision; - u_int rx_dribble; - u_int rx_overflow; - } pktStats; - char rxRingSize; - char txRingSize; - int bus; /* EISA or PCI */ - int bus_num; /* PCI Bus number */ - int device; /* Device number on PCI bus */ - int state; /* Adapter OPENED or CLOSED */ - int chipset; /* DC21040, DC21041 or DC21140 */ - s32 irq_mask; /* Interrupt Mask (Enable) bits */ - s32 irq_en; /* Summary interrupt bits */ - int media; /* Media (eg TP), mode (eg 100B)*/ - int c_media; /* Remember the last media conn */ - int fdx; /* media full duplex flag */ - int linkOK; /* Link is OK */ - int autosense; /* Allow/disallow autosensing */ - int tx_enable; /* Enable descriptor polling */ - int setup_f; /* Setup frame filtering type */ - int local_state; /* State within a 'media' state */ - struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */ - struct sia_phy sia; /* SIA PHY Information */ - int active; /* Index to active PHY device */ - int mii_cnt; /* Number of attached PHY's */ - int timeout; /* Scheduling counter */ - struct timer_list timer; /* Timer info for kernel */ - int tmp; /* Temporary global per card */ - struct { - void *priv; /* Original kmalloc'd mem addr */ - void *buf; /* Original kmalloc'd mem addr */ - int lock; /* Lock the cache accesses */ - s32 csr0; /* Saved Bus Mode Register */ - s32 csr6; /* Saved Operating Mode Reg. */ - s32 csr7; /* Saved IRQ Mask Register */ - s32 gep; /* Saved General Purpose Reg. */ - s32 gepc; /* Control info for GEP */ - s32 csr13; /* Saved SIA Connectivity Reg. */ - s32 csr14; /* Saved SIA TX/RX Register */ - s32 csr15; /* Saved SIA General Register */ - int save_cnt; /* Flag if state already saved */ - struct sk_buff *skb; /* Save the (re-ordered) skb's */ - } cache; - struct de4x5_srom srom; /* A copy of the SROM */ - struct device *next_module; /* Link to the next module */ - int rx_ovf; /* Check for 'RX overflow' tag */ - int useSROM; /* For non-DEC card use SROM */ - int useMII; /* Infoblock using the MII */ - int asBitValid; /* Autosense bits in GEP? */ - int asPolarity; /* 0 => asserted high */ - int asBit; /* Autosense bit number in GEP */ - int defMedium; /* SROM default medium */ - int tcount; /* Last infoblock number */ - int infoblock_init; /* Initialised this infoblock? */ - int infoleaf_offset; /* SROM infoleaf for controller */ - s32 infoblock_csr6; /* csr6 value in SROM infoblock */ - int infoblock_media; /* infoblock media */ - int (*infoleaf_fn)(struct device *); /* Pointer to infoleaf function */ - u_char *rst; /* Pointer to Type 5 reset info */ - u_char ibn; /* Infoblock number */ + char adapter_name[80]; /* Adapter name */ + struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ + struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ + struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */ + struct sk_buff *rx_skb[NUM_RX_DESC]; /* RX skb's */ + int rx_new, rx_old; /* RX descriptor ring pointers */ + int tx_new, tx_old; /* TX descriptor ring pointers */ + char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */ + char frame[64]; /* Min sized packet for loopback */ + struct net_device_stats stats; /* Public stats */ + struct { + u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */ + u_int unicast; + u_int multicast; + u_int broadcast; + u_int excessive_collisions; + u_int tx_underruns; + u_int excessive_underruns; + u_int rx_runt_frames; + u_int rx_collision; + u_int rx_dribble; + u_int rx_overflow; + } pktStats; + char rxRingSize; + char txRingSize; + int bus; /* EISA or PCI */ + int bus_num; /* PCI Bus number */ + int device; /* Device number on PCI bus */ + int state; /* Adapter OPENED or CLOSED */ + int chipset; /* DC21040, DC21041 or DC21140 */ + s32 irq_mask; /* Interrupt Mask (Enable) bits */ + s32 irq_en; /* Summary interrupt bits */ + int media; /* Media (eg TP), mode (eg 100B) */ + int c_media; /* Remember the last media conn */ + int fdx; /* media full duplex flag */ + int linkOK; /* Link is OK */ + int autosense; /* Allow/disallow autosensing */ + int tx_enable; /* Enable descriptor polling */ + int setup_f; /* Setup frame filtering type */ + int local_state; /* State within a 'media' state */ + struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */ + struct sia_phy sia; /* SIA PHY Information */ + int active; /* Index to active PHY device */ + int mii_cnt; /* Number of attached PHY's */ + int timeout; /* Scheduling counter */ + struct timer_list timer; /* Timer info for kernel */ + int tmp; /* Temporary global per card */ + struct { + void *priv; /* Original kmalloc'd mem addr */ + void *buf; /* Original kmalloc'd mem addr */ + unsigned long lock; /* Lock the cache accesses */ + s32 csr0; /* Saved Bus Mode Register */ + s32 csr6; /* Saved Operating Mode Reg. */ + s32 csr7; /* Saved IRQ Mask Register */ + s32 gep; /* Saved General Purpose Reg. */ + s32 gepc; /* Control info for GEP */ + s32 csr13; /* Saved SIA Connectivity Reg. */ + s32 csr14; /* Saved SIA TX/RX Register */ + s32 csr15; /* Saved SIA General Register */ + int save_cnt; /* Flag if state already saved */ + struct sk_buff *skb; /* Save the (re-ordered) skb's */ + } cache; + struct de4x5_srom srom; /* A copy of the SROM */ + struct device *next_module; /* Link to the next module */ + int rx_ovf; /* Check for 'RX overflow' tag */ + int useSROM; /* For non-DEC card use SROM */ + int useMII; /* Infoblock using the MII */ + int asBitValid; /* Autosense bits in GEP? */ + int asPolarity; /* 0 => asserted high */ + int asBit; /* Autosense bit number in GEP */ + int defMedium; /* SROM default medium */ + int tcount; /* Last infoblock number */ + int infoblock_init; /* Initialised this infoblock? */ + int infoleaf_offset; /* SROM infoleaf for controller */ + s32 infoblock_csr6; /* csr6 value in SROM infoblock */ + int infoblock_media; /* infoblock media */ + int (*infoleaf_fn) (struct device *); /* Pointer to infoleaf function */ + u_char *rst; /* Pointer to Type 5 reset info */ + u_char ibn; /* Infoblock number */ }; /* @@ -744,13 +751,13 @@ ** PROM is accessed differently. */ static struct bus_type { - int bus; - int bus_num; - int device; - int chipset; - struct de4x5_srom srom; - int autosense; - int useSROM; + int bus; + int bus_num; + int device; + int chipset; + struct de4x5_srom srom; + int autosense; + int useSROM; } bus; /* @@ -766,11 +773,14 @@ ** can't follow the PCI to PCI Bridge Architecture spec. */ static struct { - int chipset; - int bus; - int irq; - u_char addr[ETH_ALEN]; -} last = {0,}; + int chipset; + int bus; + int irq; + u_char addr[ETH_ALEN]; +} last = { + + 0, +}; /* ** The transmit ring full condition is described by the tx_old and tx_new @@ -788,129 +798,131 @@ /* ** Public Functions */ -static int de4x5_open(struct device *dev); -static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev); -static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int de4x5_close(struct device *dev); -static struct net_device_stats *de4x5_get_stats(struct device *dev); -static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len); -static void set_multicast_list(struct device *dev); -static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static int de4x5_open(struct device *dev); +static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev); +static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int de4x5_close(struct device *dev); +static struct net_device_stats *de4x5_get_stats(struct device *dev); +static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len); +static void set_multicast_list(struct device *dev); +static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd); /* ** Private functions */ -static int de4x5_hw_init(struct device *dev, u_long iobase); -static int de4x5_init(struct device *dev); -static int de4x5_sw_reset(struct device *dev); -static int de4x5_rx(struct device *dev); -static int de4x5_tx(struct device *dev); -static int de4x5_ast(struct device *dev); -static int de4x5_txur(struct device *dev); -static int de4x5_rx_ovfc(struct device *dev); - -static int autoconf_media(struct device *dev); -static void create_packet(struct device *dev, char *frame, int len); -static void de4x5_us_delay(u32 usec); -static void de4x5_ms_delay(u32 msec); -static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb); -static int dc21040_autoconf(struct device *dev); -static int dc21041_autoconf(struct device *dev); -static int dc21140m_autoconf(struct device *dev); -static int dc2114x_autoconf(struct device *dev); -static int srom_autoconf(struct device *dev); -static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *)); -static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int)); -static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec); -static int test_for_100Mb(struct device *dev, int msec); -static int wait_for_link(struct device *dev); -static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec); -static int is_spd_100(struct device *dev); -static int is_100_up(struct device *dev); -static int is_10_up(struct device *dev); -static int is_anc_capable(struct device *dev); -static int ping_media(struct device *dev, int msec); +static int de4x5_hw_init(struct device *dev, u_long iobase); +static int de4x5_init(struct device *dev); +static int de4x5_sw_reset(struct device *dev); +static int de4x5_rx(struct device *dev); +static int de4x5_tx(struct device *dev); +static int de4x5_ast(struct device *dev); +static int de4x5_txur(struct device *dev); +static int de4x5_rx_ovfc(struct device *dev); + +static int autoconf_media(struct device *dev); +static void create_packet(struct device *dev, char *frame, int len); +static void de4x5_us_delay(u32 usec); +static void de4x5_ms_delay(u32 msec); +static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb); +static int dc21040_autoconf(struct device *dev); +static int dc21041_autoconf(struct device *dev); +static int dc21140m_autoconf(struct device *dev); +static int dc2114x_autoconf(struct device *dev); +static int srom_autoconf(struct device *dev); +static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn) (struct device *, int), int (*asfn) (struct device *)); +static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn) (struct device *, int)); +static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec); +static int test_for_100Mb(struct device *dev, int msec); +static int wait_for_link(struct device *dev); +static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec); +static int is_spd_100(struct device *dev); +static int is_100_up(struct device *dev); +static int is_10_up(struct device *dev); +static int is_anc_capable(struct device *dev); +static int ping_media(struct device *dev, int msec); static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len); -static void de4x5_free_rx_buffs(struct device *dev); -static void de4x5_free_tx_buffs(struct device *dev); -static void de4x5_save_skbs(struct device *dev); -static void de4x5_restore_skbs(struct device *dev); -static void de4x5_cache_state(struct device *dev, int flag); -static void de4x5_put_cache(struct device *dev, struct sk_buff *skb); -static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb); -static struct sk_buff *de4x5_get_cache(struct device *dev); -static void de4x5_setup_intr(struct device *dev); -static void de4x5_init_connection(struct device *dev); -static int de4x5_reset_phy(struct device *dev); -static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr); -static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec); -static int test_tp(struct device *dev, s32 msec); -static int EISA_signature(char *name, s32 eisa_id); -static int PCI_signature(char *name, struct bus_type *lp); -static void DevicePresent(u_long iobase); -static int de4x5_bad_srom(struct bus_type *lp); -static short srom_rd(u_long address, u_char offset); -static void srom_latch(u_int command, u_long address); -static void srom_command(u_int command, u_long address); -static void srom_address(u_int command, u_long address, u_char offset); -static short srom_data(u_int command, u_long address); -/*static void srom_busy(u_int command, u_long address);*/ -static void sendto_srom(u_int command, u_long addr); -static int getfrom_srom(u_long addr); -static int srom_map_media(struct device *dev); -static int srom_infoleaf_info(struct device *dev); -static void srom_init(struct device *dev); -static void srom_exec(struct device *dev, u_char *p); -static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr); -static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr); -static int mii_rdata(u_long ioaddr); -static void mii_wdata(int data, int len, u_long ioaddr); -static void mii_ta(u_long rw, u_long ioaddr); -static int mii_swap(int data, int len); -static void mii_address(u_char addr, u_long ioaddr); -static void sendto_mii(u32 command, int data, u_long ioaddr); -static int getfrom_mii(u32 command, u_long ioaddr); -static int mii_get_oui(u_char phyaddr, u_long ioaddr); -static int mii_get_phy(struct device *dev); -static void SetMulticastFilter(struct device *dev); -static int get_hw_addr(struct device *dev); -static void srom_repair(struct device *dev, int card); -static int test_bad_enet(struct device *dev, int status); - -static void eisa_probe(struct device *dev, u_long iobase); -static void pci_probe(struct device *dev, u_long iobase); -static void srom_search(int index); -static char *build_setup_frame(struct device *dev, int mode); -static void disable_ast(struct device *dev); -static void enable_ast(struct device *dev, u32 time_out); -static long de4x5_switch_mac_port(struct device *dev); -static int gep_rd(struct device *dev); -static void gep_wr(s32 data, struct device *dev); -static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec); -static void yawn(struct device *dev, int state); -static void link_modules(struct device *dev, struct device *tmp); -static void de4x5_dbg_open(struct device *dev); -static void de4x5_dbg_mii(struct device *dev, int k); -static void de4x5_dbg_media(struct device *dev); -static void de4x5_dbg_srom(struct de4x5_srom *p); -static void de4x5_dbg_rx(struct sk_buff *skb, int len); -static int de4x5_strncmp(char *a, char *b, int n); -static int dc21041_infoleaf(struct device *dev); -static int dc21140_infoleaf(struct device *dev); -static int dc21142_infoleaf(struct device *dev); -static int dc21143_infoleaf(struct device *dev); -static int type0_infoblock(struct device *dev, u_char count, u_char *p); -static int type1_infoblock(struct device *dev, u_char count, u_char *p); -static int type2_infoblock(struct device *dev, u_char count, u_char *p); -static int type3_infoblock(struct device *dev, u_char count, u_char *p); -static int type4_infoblock(struct device *dev, u_char count, u_char *p); -static int type5_infoblock(struct device *dev, u_char count, u_char *p); -static int compact_infoblock(struct device *dev, u_char count, u_char *p); +static void de4x5_free_rx_buffs(struct device *dev); +static void de4x5_free_tx_buffs(struct device *dev); +static void de4x5_save_skbs(struct device *dev); +static void de4x5_restore_skbs(struct device *dev); +static void de4x5_cache_state(struct device *dev, int flag); +static void de4x5_put_cache(struct device *dev, struct sk_buff *skb); +static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb); +static struct sk_buff *de4x5_get_cache(struct device *dev); +static void de4x5_setup_intr(struct device *dev); +static void de4x5_init_connection(struct device *dev); +static int de4x5_reset_phy(struct device *dev); +static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr); +static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec); +static int test_tp(struct device *dev, s32 msec); +static int EISA_signature(char *name, s32 eisa_id); +static int PCI_signature(char *name, struct bus_type *lp); +static void DevicePresent(u_long iobase); +static int de4x5_bad_srom(struct bus_type *lp); +static short srom_rd(u_long address, u_char offset); +static void srom_latch(u_int command, u_long address); +static void srom_command(u_int command, u_long address); +static void srom_address(u_int command, u_long address, u_char offset); +static short srom_data(u_int command, u_long address); +/*static void srom_busy(u_int command, u_long address); */ +static void sendto_srom(u_int command, u_long addr); +static int getfrom_srom(u_long addr); +static int srom_map_media(struct device *dev); +static int srom_infoleaf_info(struct device *dev); +static void srom_init(struct device *dev); +static void srom_exec(struct device *dev, u_char * p); +static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr); +static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr); +static int mii_rdata(u_long ioaddr); +static void mii_wdata(int data, int len, u_long ioaddr); +static void mii_ta(u_long rw, u_long ioaddr); +static int mii_swap(int data, int len); +static void mii_address(u_char addr, u_long ioaddr); +static void sendto_mii(u32 command, int data, u_long ioaddr); +static int getfrom_mii(u32 command, u_long ioaddr); +static int mii_get_oui(u_char phyaddr, u_long ioaddr); +static int mii_get_phy(struct device *dev); +static void SetMulticastFilter(struct device *dev); +static int get_hw_addr(struct device *dev); +static void srom_repair(struct device *dev, int card); +static int test_bad_enet(struct device *dev, int status); + +#ifndef __sparc_v9__ +static void eisa_probe(struct device *dev, u_long iobase); +#endif +static void pci_probe(struct device *dev, u_long iobase); +static void srom_search(int index); +static char *build_setup_frame(struct device *dev, int mode); +static void disable_ast(struct device *dev); +static void enable_ast(struct device *dev, u32 time_out); +static long de4x5_switch_mac_port(struct device *dev); +static int gep_rd(struct device *dev); +static void gep_wr(s32 data, struct device *dev); +static void timeout(struct device *dev, void (*fn) (u_long data), u_long data, u_long msec); +static void yawn(struct device *dev, int state); +static void link_modules(struct device *dev, struct device *tmp); +static void de4x5_dbg_open(struct device *dev); +static void de4x5_dbg_mii(struct device *dev, int k); +static void de4x5_dbg_media(struct device *dev); +static void de4x5_dbg_srom(struct de4x5_srom *p); +static void de4x5_dbg_rx(struct sk_buff *skb, int len); +static int de4x5_strncmp(char *a, char *b, int n); +static int dc21041_infoleaf(struct device *dev); +static int dc21140_infoleaf(struct device *dev); +static int dc21142_infoleaf(struct device *dev); +static int dc21143_infoleaf(struct device *dev); +static int type0_infoblock(struct device *dev, u_char count, u_char * p); +static int type1_infoblock(struct device *dev, u_char count, u_char * p); +static int type2_infoblock(struct device *dev, u_char count, u_char * p); +static int type3_infoblock(struct device *dev, u_char count, u_char * p); +static int type4_infoblock(struct device *dev, u_char count, u_char * p); +static int type5_infoblock(struct device *dev, u_char count, u_char * p); +static int compact_infoblock(struct device *dev, u_char count, u_char * p); #ifdef MODULE -int init_module(void); +int init_module(void); void cleanup_module(void); -static struct device *unlink_modules(struct device *p); +static struct device *unlink_modules(struct device *p); static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)); static int count_adapters(void); @@ -920,12 +932,14 @@ MODULE_PARM(de4x5_full_duplex, "i"); MODULE_PARM(dec_only, "i"); #endif /* LINUX_VERSION_CODE */ -# else +#else static int loading_module = 0; -#endif /* MODULE */ +#endif /* MODULE */ static char name[DE4X5_NAME_LENGTH + 1]; +#ifndef __sparc_v9__ static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; +#endif static int num_de4x5s = 0; static int cfrv = 0, useSROM = 0; static int lastEISA = 0, lastPCI = -1; @@ -935,28 +949,29 @@ ** List the SROM infoleaf functions and chipsets */ struct InfoLeaf { - int chipset; - int (*fn)(struct device *); + int chipset; + int (*fn) (struct device *); }; -static struct InfoLeaf infoleaf_array[] = { - {DC21041, dc21041_infoleaf}, - {DC21140, dc21140_infoleaf}, - {DC21142, dc21142_infoleaf}, - {DC21143, dc21143_infoleaf} +static struct InfoLeaf infoleaf_array[] = +{ + {DC21041, dc21041_infoleaf}, + {DC21140, dc21140_infoleaf}, + {DC21142, dc21142_infoleaf}, + {DC21143, dc21143_infoleaf} }; #define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *))) /* ** List the SROM info block functions */ -static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = { - type0_infoblock, - type1_infoblock, - type2_infoblock, - type3_infoblock, - type4_infoblock, - type5_infoblock, - compact_infoblock +static int (*dc_infoblock[]) (struct device * dev, u_char, u_char *) = { + type0_infoblock, + type1_infoblock, + type2_infoblock, + type3_infoblock, + type4_infoblock, + type5_infoblock, + compact_infoblock }; #define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1) @@ -982,309 +997,300 @@ outl(0x00, DE4X5_GEP);\ udelay(2000); /* Wait for 2ms */\ } - + /* ** Autoprobing in modules is allowed here. See the top of the file for ** more info. */ -__initfunc(int -de4x5_probe(struct device *dev)) +__initfunc(int de4x5_probe(struct device *dev)) { - u_long iobase = dev->base_addr; + u_long iobase = dev->base_addr; - eisa_probe(dev, iobase); - pci_probe(dev, iobase); - - return (dev->priv ? 0 : -ENODEV); +#ifndef __sparc_v9__ + eisa_probe(dev, iobase); +#endif + pci_probe(dev, iobase); + + return (dev->priv ? 0 : -ENODEV); } __initfunc(static int -de4x5_hw_init(struct device *dev, u_long iobase)) + de4x5_hw_init(struct device *dev, u_long iobase)) { - struct bus_type *lp = &bus; - int i, status=0; - char *tmp; - - /* Ensure we're not sleeping */ - if (lp->bus == EISA) { - outb(WAKEUP, PCI_CFPM); - } else { - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, WAKEUP); - } - de4x5_ms_delay(10); + struct bus_type *lp = &bus; + int i, status = 0; + char *tmp; - RESET_DE4X5; - - if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) { - return -ENXIO; /* Hardware could not reset */ - } - - /* - ** Now find out what kind of DC21040/DC21041/DC21140 board we have. - */ - useSROM = FALSE; - if (lp->bus == PCI) { - PCI_signature(name, lp); - } else { - EISA_signature(name, EISA_ID0); - } - - if (*name == '\0') { /* Not found a board signature */ - return -ENXIO; - } - - dev->base_addr = iobase; - if (lp->bus == EISA) { - printk("%s: %s at 0x%04lx (EISA slot %ld)", - dev->name, name, iobase, ((iobase>>12)&0x0f)); - } else { /* PCI port address */ - printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name, - iobase, lp->bus_num, lp->device); - } - - printk(", h/w address "); - status = get_hw_addr(dev); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); - - if (status != 0) { - printk(" which has an Ethernet PROM CRC error.\n"); - return -ENXIO; - } else { - struct de4x5_private *lp; - - /* - ** Reserve a section of kernel memory for the adapter - ** private area and the TX/RX descriptor rings. - */ - dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, - GFP_KERNEL); - if (dev->priv == NULL) { - return -ENOMEM; + /* Ensure we're not sleeping */ + if (lp->bus == EISA) { + outb(WAKEUP, PCI_CFPM); + } else { + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, WAKEUP); } - - /* - ** Align to a longword boundary - */ - tmp = dev->priv; - dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN); - lp = (struct de4x5_private *)dev->priv; - memset(dev->priv, 0, sizeof(struct de4x5_private)); - lp->bus = bus.bus; - lp->bus_num = bus.bus_num; - lp->device = bus.device; - lp->chipset = bus.chipset; - lp->cache.priv = tmp; - lp->cache.gepc = GEP_INIT; - lp->asBit = GEP_SLNK; - lp->asPolarity = GEP_SLNK; - lp->asBitValid = TRUE; - lp->timeout = -1; - lp->useSROM = useSROM; - memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom)); + de4x5_ms_delay(10); - /* - ** Choose correct autosensing in case someone messed up - */ - if ((de4x5_autosense & AUTO) || lp->useSROM) { - lp->autosense = AUTO; - } else { - if (lp->chipset != DC21140) { - if ((lp->chipset == DC21040) && (de4x5_autosense & TP_NW)) { - de4x5_autosense = TP; - } - if ((lp->chipset == DC21041) && (de4x5_autosense & BNC_AUI)) { - de4x5_autosense = BNC; - } - lp->autosense = de4x5_autosense & 0x001f; - } else { - lp->autosense = de4x5_autosense & 0x00c0; - } + RESET_DE4X5; + + if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) { + return -ENXIO; /* Hardware could not reset */ } - lp->fdx = de4x5_full_duplex; - sprintf(lp->adapter_name,"%s (%s)", name, dev->name); - - /* - ** Set up the RX descriptor ring (Intels) - ** Allocate contiguous receive buffers, long word aligned (Alphas) + /* + ** Now find out what kind of DC21040/DC21041/DC21140 board we have. */ -#if !defined(__alpha__) && !defined(__powerpc__) && !defined(DE4X5_DO_MEMCPY) - for (i=0; irx_ring[i].status = 0; - lp->rx_ring[i].des1 = RX_BUFF_SZ; - lp->rx_ring[i].buf = 0; - lp->rx_ring[i].next = 0; - lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + useSROM = FALSE; + if (lp->bus == PCI) { + PCI_signature(name, lp); + } else { + EISA_signature(name, EISA_ID0); } -#else - if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, - GFP_KERNEL)) == NULL) { - kfree(lp->cache.priv); - return -ENOMEM; + if (*name == '\0') { /* Not found a board signature */ + return -ENXIO; } - - lp->cache.buf = tmp; - tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN); - for (i=0; irx_ring[i].status = 0; - lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); - lp->rx_ring[i].buf = cpu_to_le32(virt_to_bus(tmp+i*RX_BUFF_SZ)); - lp->rx_ring[i].next = 0; - lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + dev->base_addr = iobase; + if (lp->bus == EISA) { + printk("%s: %s at 0x%04lx (EISA slot %ld)", + dev->name, name, iobase, ((iobase >> 12) & 0x0f)); + } else { /* PCI port address */ + printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name, + iobase, lp->bus_num, lp->device); + } + + printk(", h/w address "); + status = get_hw_addr(dev); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ + printk("%2.2x:", dev->dev_addr[i]); } + printk("%2.2x,\n", dev->dev_addr[i]); + + if (status != 0) { + printk(" which has an Ethernet PROM CRC error.\n"); + return -ENXIO; + } else { + struct de4x5_private *lp; + + /* + ** Reserve a section of kernel memory for the adapter + ** private area and the TX/RX descriptor rings. + */ + dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, + GFP_KERNEL); + if (dev->priv == NULL) { + return -ENOMEM; + } + /* + ** Align to a longword boundary + */ + tmp = dev->priv; + dev->priv = (void *) (((u_long) dev->priv + ALIGN) & ~ALIGN); + lp = (struct de4x5_private *) dev->priv; + memset(dev->priv, 0, sizeof(struct de4x5_private)); + lp->bus = bus.bus; + lp->bus_num = bus.bus_num; + lp->device = bus.device; + lp->chipset = bus.chipset; + lp->cache.priv = tmp; + lp->cache.gepc = GEP_INIT; + lp->asBit = GEP_SLNK; + lp->asPolarity = GEP_SLNK; + lp->asBitValid = TRUE; + lp->timeout = -1; + lp->useSROM = useSROM; + memcpy((char *) &lp->srom, (char *) &bus.srom, sizeof(struct de4x5_srom)); + + /* + ** Choose correct autosensing in case someone messed up + */ + if ((de4x5_autosense & AUTO) || lp->useSROM) { + lp->autosense = AUTO; + } else { + if (lp->chipset != DC21140) { + if ((lp->chipset == DC21040) && (de4x5_autosense & TP_NW)) { + de4x5_autosense = TP; + } + if ((lp->chipset == DC21041) && (de4x5_autosense & BNC_AUI)) { + de4x5_autosense = BNC; + } + lp->autosense = de4x5_autosense & 0x001f; + } else { + lp->autosense = de4x5_autosense & 0x00c0; + } + } + lp->fdx = de4x5_full_duplex; + sprintf(lp->adapter_name, "%s (%s)", name, dev->name); + + /* + ** Set up the RX descriptor ring (Intels) + ** Allocate contiguous receive buffers, long word aligned (Alphas) + */ +#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) + for (i = 0; i < NUM_RX_DESC; i++) { + lp->rx_ring[i].status = 0; + lp->rx_ring[i].des1 = RX_BUFF_SZ; + lp->rx_ring[i].buf = 0; + lp->rx_ring[i].next = 0; + lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + } + +#else + if ((tmp = (void *) kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, + GFP_KERNEL)) == NULL) { + kfree(lp->cache.priv); + return -ENOMEM; + } + lp->cache.buf = tmp; + tmp = (char *) (((u_long) tmp + ALIGN) & ~ALIGN); + for (i = 0; i < NUM_RX_DESC; i++) { + lp->rx_ring[i].status = 0; + lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); + lp->rx_ring[i].buf = cpu_to_le32(virt_to_bus(tmp + i * RX_BUFF_SZ)); + lp->rx_ring[i].next = 0; + lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + } #endif - barrier(); - - request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE), - lp->adapter_name); - - lp->rxRingSize = NUM_RX_DESC; - lp->txRingSize = NUM_TX_DESC; - - /* Write the end of list marker to the descriptor lists */ - lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER); - lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER); - - /* Tell the adapter where the TX/RX rings are located. */ - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - - /* Initialise the IRQ mask and Enable/Disable */ - lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM; - lp->irq_en = IMR_NIM | IMR_AIM; + barrier(); - /* Create a loopback packet frame for later media probing */ - create_packet(dev, lp->frame, sizeof(lp->frame)); + request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : + DE4X5_EISA_TOTAL_SIZE), + lp->adapter_name); + + lp->rxRingSize = NUM_RX_DESC; + lp->txRingSize = NUM_TX_DESC; + + /* Write the end of list marker to the descriptor lists */ + lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER); + lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER); + + /* Tell the adapter where the TX/RX rings are located. */ + outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); + outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + + /* Initialise the IRQ mask and Enable/Disable */ + lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM; + lp->irq_en = IMR_NIM | IMR_AIM; + + /* Create a loopback packet frame for later media probing */ + create_packet(dev, lp->frame, sizeof(lp->frame)); + + /* Check if the RX overflow bug needs testing for */ + i = cfrv & 0x000000fe; + if ((lp->chipset == DC21140) && (i == 0x20)) { + lp->rx_ovf = 1; + } + /* Initialise the SROM pointers if possible */ + if (lp->useSROM) { + lp->state = INITIALISED; + if (srom_infoleaf_info(dev)) { + return -ENXIO; + } + srom_init(dev); + } + lp->state = CLOSED; - /* Check if the RX overflow bug needs testing for */ - i = cfrv & 0x000000fe; - if ((lp->chipset == DC21140) && (i == 0x20)) { - lp->rx_ovf = 1; + /* + ** Check for an MII interface + */ + if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) { + mii_get_phy(dev); + } + printk(" and requires IRQ %x (provided by %s).\n", dev->irq, + ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); } - /* Initialise the SROM pointers if possible */ - if (lp->useSROM) { - lp->state = INITIALISED; - if (srom_infoleaf_info(dev)) { - return -ENXIO; - } - srom_init(dev); + if (de4x5_debug & DEBUG_VERSION) { + printk(version); } + /* The DE4X5-specific entries in the device structure. */ + dev->open = &de4x5_open; + dev->hard_start_xmit = &de4x5_queue_pkt; + dev->stop = &de4x5_close; + dev->get_stats = &de4x5_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = &de4x5_ioctl; - lp->state = CLOSED; + dev->mem_start = 0; + + /* Fill in the generic fields of the device structure. */ + ether_setup(dev); + + /* Let the adapter sleep to save power */ + yawn(dev, SLEEP); + + return status; +} + + +static int de4x5_open(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int i, status = 0; + s32 omr; + + /* Allocate the RX buffers */ + for (i = 0; i < lp->rxRingSize; i++) { + if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) { + de4x5_free_rx_buffs(dev); + return -EAGAIN; + } + } /* - ** Check for an MII interface + ** Wake up the adapter */ - if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) { - mii_get_phy(dev); + yawn(dev, WAKEUP); + + /* + ** Re-initialize the DE4X5... + */ + status = de4x5_init(dev); + + lp->state = OPEN; + de4x5_dbg_open(dev); + + if (request_irq(dev->irq, (void *) de4x5_interrupt, SA_SHIRQ, + lp->adapter_name, dev)) { + printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq); + if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ, + lp->adapter_name, dev)) { + printk("\n Cannot get IRQ- reconfigure your hardware.\n"); + disable_ast(dev); + de4x5_free_rx_buffs(dev); + de4x5_free_tx_buffs(dev); + yawn(dev, SLEEP); + lp->state = CLOSED; + return -EAGAIN; + } else { + printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n"); + printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n"); + } } - - printk(" and requires IRQ%d (provided by %s).\n", dev->irq, - ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); - } - - if (de4x5_debug & DEBUG_VERSION) { - printk(version); - } - - /* The DE4X5-specific entries in the device structure. */ - dev->open = &de4x5_open; - dev->hard_start_xmit = &de4x5_queue_pkt; - dev->stop = &de4x5_close; - dev->get_stats = &de4x5_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &de4x5_ioctl; - - dev->mem_start = 0; - - /* Fill in the generic fields of the device structure. */ - ether_setup(dev); - - /* Let the adapter sleep to save power */ - yawn(dev, SLEEP); - - return status; -} - -static int -de4x5_open(struct device *dev) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int i, status = 0; - s32 omr; - - /* Allocate the RX buffers */ - for (i=0; irxRingSize; i++) { - if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) { - de4x5_free_rx_buffs(dev); - return -EAGAIN; - } - } - - /* - ** Wake up the adapter - */ - yawn(dev, WAKEUP); - - /* - ** Re-initialize the DE4X5... - */ - status = de4x5_init(dev); - - lp->state = OPEN; - de4x5_dbg_open(dev); - - if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, - lp->adapter_name, dev)) { - printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq); - if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ, - lp->adapter_name, dev)) { - printk("\n Cannot get IRQ- reconfigure your hardware.\n"); - disable_ast(dev); - de4x5_free_rx_buffs(dev); - de4x5_free_tx_buffs(dev); - yawn(dev, SLEEP); - lp->state = CLOSED; - return -EAGAIN; - } else { - printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n"); - printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n"); + dev->tbusy = 0; + dev->start = 1; + dev->interrupt = UNMASK_INTERRUPTS; + dev->trans_start = jiffies; + + START_DE4X5; + + de4x5_setup_intr(dev); + + if (de4x5_debug & DEBUG_OPEN) { + printk("\tsts: 0x%08x\n", inl(DE4X5_STS)); + printk("\tbmr: 0x%08x\n", inl(DE4X5_BMR)); + printk("\timr: 0x%08x\n", inl(DE4X5_IMR)); + printk("\tomr: 0x%08x\n", inl(DE4X5_OMR)); + printk("\tsisr: 0x%08x\n", inl(DE4X5_SISR)); + printk("\tsicr: 0x%08x\n", inl(DE4X5_SICR)); + printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR)); + printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR)); } - } + MOD_INC_USE_COUNT; - dev->tbusy = 0; - dev->start = 1; - dev->interrupt = UNMASK_INTERRUPTS; - dev->trans_start = jiffies; - - START_DE4X5; - - de4x5_setup_intr(dev); - - if (de4x5_debug & DEBUG_OPEN) { - printk("\tsts: 0x%08x\n", inl(DE4X5_STS)); - printk("\tbmr: 0x%08x\n", inl(DE4X5_BMR)); - printk("\timr: 0x%08x\n", inl(DE4X5_IMR)); - printk("\tomr: 0x%08x\n", inl(DE4X5_OMR)); - printk("\tsisr: 0x%08x\n", inl(DE4X5_SISR)); - printk("\tsicr: 0x%08x\n", inl(DE4X5_SICR)); - printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR)); - printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR)); - } - - MOD_INC_USE_COUNT; - - return status; + return status; } /* @@ -1295,168 +1301,157 @@ ** to be data corruption problems if it is larger (UDP errors seen from a ** ttcp source). */ -static int -de4x5_init(struct device *dev) -{ - /* Lock out other processes whilst setting up the hardware */ - test_and_set_bit(0, (void *)&dev->tbusy); - - de4x5_sw_reset(dev); - - /* Autoconfigure the connected port */ - autoconf_media(dev); - - return 0; +static int de4x5_init(struct device *dev) +{ + /* Lock out other processes whilst setting up the hardware */ + test_and_set_bit(0, (void *)&dev->tbusy); + + de4x5_sw_reset(dev); + + /* Autoconfigure the connected port */ + autoconf_media(dev); + + return 0; } -static int -de4x5_sw_reset(struct device *dev) +static int de4x5_sw_reset(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int i, j, status = 0; - s32 bmr, omr; - - /* Select the MII or SRL port now and RESET the MAC */ - if (!lp->useSROM) { - if (lp->phy[lp->active].id != 0) { - lp->infoblock_csr6 = OMR_PS | OMR_HBD; - } else { - lp->infoblock_csr6 = OMR_TTM; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int i, j, status = 0; + s32 bmr, omr; + + /* Select the MII or SRL port now and RESET the MAC */ + if (!lp->useSROM) { + if (lp->phy[lp->active].id != 0) { + lp->infoblock_csr6 = OMR_PS | OMR_HBD; + } else { + lp->infoblock_csr6 = OMR_TTM; + } + de4x5_switch_mac_port(dev); } - de4x5_switch_mac_port(dev); - } + /* + ** Set the programmable burst length to 8 longwords for all the DC21140 + ** Fasternet chips and 4 longwords for all others: DMA errors result + ** without these values. Cache align 16 long. + */ + bmr = (lp->chipset == DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN; + bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0); + outl(bmr, DE4X5_BMR); - /* - ** Set the programmable burst length to 8 longwords for all the DC21140 - ** Fasternet chips and 4 longwords for all others: DMA errors result - ** without these values. Cache align 16 long. - */ - bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN; - bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0); - outl(bmr, DE4X5_BMR); - - omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn off promiscuous mode */ - if (lp->chipset == DC21140) { - omr |= (OMR_SDP | OMR_SB); - } - lp->setup_f = PERFECT; - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - - lp->rx_new = lp->rx_old = 0; - lp->tx_new = lp->tx_old = 0; - - for (i = 0; i < lp->rxRingSize; i++) { - lp->rx_ring[i].status = cpu_to_le32(R_OWN); - } - - for (i = 0; i < lp->txRingSize; i++) { - lp->tx_ring[i].status = cpu_to_le32(0); - } - - barrier(); + omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn off promiscuous mode */ + if (lp->chipset == DC21140) { + omr |= (OMR_SDP | OMR_SB); + } + lp->setup_f = PERFECT; + outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); + outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - /* Build the setup frame depending on filtering mode */ - SetMulticastFilter(dev); - - load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL); - outl(omr|OMR_ST, DE4X5_OMR); + lp->rx_new = lp->rx_old = 0; + lp->tx_new = lp->tx_old = 0; - /* Poll for setup frame completion (adapter interrupts are disabled now) */ - sti(); /* Ensure timer interrupts */ - for (j=0, i=0;(i<500) && (j==0);i++) { /* Upto 500ms delay */ - udelay(1000); - if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1; - } - outl(omr, DE4X5_OMR); /* Stop everything! */ - - if (j == 0) { - printk("%s: Setup frame timed out, status %08x\n", dev->name, - inl(DE4X5_STS)); - status = -EIO; - } - - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - lp->tx_old = lp->tx_new; + for (i = 0; i < lp->rxRingSize; i++) { + lp->rx_ring[i].status = cpu_to_le32(R_OWN); + } + + for (i = 0; i < lp->txRingSize; i++) { + lp->tx_ring[i].status = cpu_to_le32(0); + } + + barrier(); + + /* Build the setup frame depending on filtering mode */ + SetMulticastFilter(dev); + + load_packet(dev, lp->setup_frame, PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); + outl(omr | OMR_ST, DE4X5_OMR); + + /* Poll for setup frame completion (adapter interrupts are disabled now) */ + sti(); /* Ensure timer interrupts */ + for (j = 0, i = 0; (i < 500) && (j == 0); i++) { /* Upto 500ms delay */ + udelay(1000); + if ((s32) le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) + j = 1; + } + outl(omr, DE4X5_OMR); /* Stop everything! */ + + if (j == 0) { + printk("%s: Setup frame timed out, status %08x\n", dev->name, + inl(DE4X5_STS)); + status = -EIO; + } + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + lp->tx_old = lp->tx_new; - return status; + return status; } /* ** Writes a socket buffer address to the next available transmit descriptor */ -static int -de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) +static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int status = 0; - - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - test_and_set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */ - if (lp->tx_enable == NO) { /* Cannot send for now */ - return -1; - } - - /* - ** Clean out the TX ring asynchronously to interrupts - sometimes the - ** interrupts are lost by delayed descriptor status updates relative to - ** the irq assertion, especially with a busy PCI bus. - */ - cli(); - de4x5_tx(dev); - sti(); - - /* Test if cache is already locked - requeue skb if so */ - if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) - return -1; - - /* Transmit descriptor ring full or stale skb */ - if (dev->tbusy || lp->tx_skb[lp->tx_new]) { - if (dev->interrupt) { - de4x5_putb_cache(dev, skb); /* Requeue the buffer */ - } else { - de4x5_put_cache(dev, skb); - } - if (de4x5_debug & DEBUG_TX) { - printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int status = 0; + + test_and_set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */ + if (lp->tx_enable == NO) { /* Cannot send for now */ + return -1; } - } else if (skb->len > 0) { - /* If we already have stuff queued locally, use that first */ - if (lp->cache.skb && !dev->interrupt) { - de4x5_put_cache(dev, skb); - skb = de4x5_get_cache(dev); - } - - while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) { - cli(); - test_and_set_bit(0, (void*)&dev->tbusy); - load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); + /* + ** Clean out the TX ring asynchronously to interrupts - sometimes the + ** interrupts are lost by delayed descriptor status updates relative to + ** the irq assertion, especially with a busy PCI bus. + */ + cli(); + de4x5_tx(dev); + sti(); + + /* Test if cache is already locked - requeue skb if so */ + if (test_and_set_bit(0, (void *) &lp->cache.lock) && !dev->interrupt) + return -1; + + /* Transmit descriptor ring full or stale skb */ + if (dev->tbusy || lp->tx_skb[lp->tx_new]) { + if (dev->interrupt) { + de4x5_putb_cache(dev, skb); /* Requeue the buffer */ + } else { + de4x5_put_cache(dev, skb); + } + if (de4x5_debug & DEBUG_TX) { + printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n", dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); + } + } else if (skb->len > 0) { + /* If we already have stuff queued locally, use that first */ + if (lp->cache.skb && !dev->interrupt) { + de4x5_put_cache(dev, skb); + skb = de4x5_get_cache(dev); + } + while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) { + cli(); + test_and_set_bit(0, (void*)&dev->tbusy); + load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); #if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ - - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - dev->trans_start = jiffies; - - if (TX_BUFFS_AVAIL) { - dev->tbusy = 0; /* Another pkt may be queued */ - } - skb = de4x5_get_cache(dev); - sti(); + outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ + + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + dev->trans_start = jiffies; + + if (TX_BUFFS_AVAIL) { + dev->tbusy = 0; /* Another pkt may be queued */ + } + skb = de4x5_get_cache(dev); + sti(); + } + if (skb) + de4x5_putb_cache(dev, skb); } - if (skb) de4x5_putb_cache(dev, skb); - } - - lp->cache.lock = 0; + lp->cache.lock = 0; - return status; + return status; } /* @@ -1470,395 +1465,389 @@ ** is high and descriptor status bits cannot be set before the associated ** interrupt is asserted and this routine entered. */ -static void -de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct device *dev = (struct device *)dev_id; - struct de4x5_private *lp; - s32 imr, omr, sts, limit; - u_long iobase; - - if (dev == NULL) { - printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq); - return; - } - lp = (struct de4x5_private *)dev->priv; - iobase = dev->base_addr; - - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - - DISABLE_IRQs; /* Ensure non re-entrancy */ + struct device *dev = (struct device *) dev_id; + struct de4x5_private *lp; + s32 imr, omr, sts, limit; + u_long iobase; + + if (dev == NULL) { + printk("de4x5_interrupt(): irq %d for unknown device.\n", irq); + return; + } + lp = (struct de4x5_private *) dev->priv; + iobase = dev->base_addr; + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + DISABLE_IRQs; /* Ensure non re-entrancy */ #if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) - synchronize_irq(); + synchronize_irq(); #endif - dev->interrupt = MASK_INTERRUPTS; - - for (limit=0; limit<8; limit++) { - sts = inl(DE4X5_STS); /* Read IRQ status */ - outl(sts, DE4X5_STS); /* Reset the board interrupts */ - - if (!(sts & lp->irq_mask)) break;/* All done */ - - if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */ - de4x5_rx(dev); - - if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */ - de4x5_tx(dev); - - if (sts & STS_LNF) { /* TP Link has failed */ - lp->irq_mask &= ~IMR_LFM; - } - - if (sts & STS_UNF) { /* Transmit underrun */ - de4x5_txur(dev); + dev->interrupt = MASK_INTERRUPTS; + + for (limit = 0; limit < 8; limit++) { + sts = inl(DE4X5_STS); /* Read IRQ status */ + outl(sts, DE4X5_STS); /* Reset the board interrupts */ + + if (!(sts & lp->irq_mask)) + break; /* All done */ + + if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */ + de4x5_rx(dev); + + if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */ + de4x5_tx(dev); + + if (sts & STS_LNF) { /* TP Link has failed */ + lp->irq_mask &= ~IMR_LFM; + } + if (sts & STS_UNF) { /* Transmit underrun */ + de4x5_txur(dev); + } + if (sts & STS_SE) { /* Bus Error */ + STOP_DE4X5; + printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n", + dev->name, sts); + return; + } } - - if (sts & STS_SE) { /* Bus Error */ - STOP_DE4X5; - printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n", - dev->name, sts); - return; - } - } - - /* Load the TX ring with any locally stored packets */ - if (!test_and_set_bit(0, (void *)&lp->cache.lock)) { - while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { - de4x5_queue_pkt(de4x5_get_cache(dev), dev); + + /* Load the TX ring with any locally stored packets */ + if (!test_and_set_bit(0, (void *) &lp->cache.lock)) { + while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { + de4x5_queue_pkt(de4x5_get_cache(dev), dev); + } + lp->cache.lock = 0; } - lp->cache.lock = 0; - } + dev->interrupt = UNMASK_INTERRUPTS; + ENABLE_IRQs; - dev->interrupt = UNMASK_INTERRUPTS; - ENABLE_IRQs; - - return; + return; } -static int -de4x5_rx(struct device *dev) +static int de4x5_rx(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int entry; - s32 status; - - for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0; - entry=lp->rx_new) { - status = (s32)le32_to_cpu(lp->rx_ring[entry].status); - - if (lp->rx_ovf) { - if (inl(DE4X5_MFC) & MFC_FOCM) { - de4x5_rx_ovfc(dev); - break; - } - } + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int entry; + s32 status; + + for (entry = lp->rx_new; (s32) le32_to_cpu(lp->rx_ring[entry].status) >= 0; + entry = lp->rx_new) { + status = (s32) le32_to_cpu(lp->rx_ring[entry].status); + + if (lp->rx_ovf) { + if (inl(DE4X5_MFC) & MFC_FOCM) { + de4x5_rx_ovfc(dev); + break; + } + } + if (status & RD_FS) { /* Remember the start of frame */ + lp->rx_old = entry; + } + if (status & RD_LS) { /* Valid frame status */ + if (lp->tx_enable) + lp->linkOK++; + if (status & RD_ES) { /* There was an error. */ + lp->stats.rx_errors++; /* Update the error stats. */ + if (status & (RD_RF | RD_TL)) + lp->stats.rx_frame_errors++; + if (status & RD_CE) + lp->stats.rx_crc_errors++; + if (status & RD_OF) + lp->stats.rx_fifo_errors++; + if (status & RD_TL) + lp->stats.rx_length_errors++; + if (status & RD_RF) + lp->pktStats.rx_runt_frames++; + if (status & RD_CS) + lp->pktStats.rx_collision++; + if (status & RD_DB) + lp->pktStats.rx_dribble++; + if (status & RD_OF) + lp->pktStats.rx_overflow++; + } else { /* A valid frame received */ + struct sk_buff *skb; + short pkt_len = (short) (le32_to_cpu(lp->rx_ring[entry].status) + >> 16) - 4; + + if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { + printk("%s: Insufficient memory; nuking packet.\n", + dev->name); + lp->stats.rx_dropped++; + } else { + de4x5_dbg_rx(skb, pkt_len); + + /* Push up the protocol stack */ + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); - if (status & RD_FS) { /* Remember the start of frame */ - lp->rx_old = entry; - } - - if (status & RD_LS) { /* Valid frame status */ - if (lp->tx_enable) lp->linkOK++; - if (status & RD_ES) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ - if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++; - if (status & RD_CE) lp->stats.rx_crc_errors++; - if (status & RD_OF) lp->stats.rx_fifo_errors++; - if (status & RD_TL) lp->stats.rx_length_errors++; - if (status & RD_RF) lp->pktStats.rx_runt_frames++; - if (status & RD_CS) lp->pktStats.rx_collision++; - if (status & RD_DB) lp->pktStats.rx_dribble++; - if (status & RD_OF) lp->pktStats.rx_overflow++; - } else { /* A valid frame received */ - struct sk_buff *skb; - short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status) - >> 16) - 4; - - if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { - printk("%s: Insufficient memory; nuking packet.\n", - dev->name); - lp->stats.rx_dropped++; - } else { - de4x5_dbg_rx(skb, pkt_len); - - /* Push up the protocol stack */ - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - - /* Update stats */ - lp->stats.rx_packets++; + /* Update stats */ + lp->stats.rx_packets++; #if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) - lp->stats.rx_bytes += pkt_len; + lp->stats.rx_bytes += pkt_len; #endif - de4x5_local_stats(dev, skb->data, pkt_len); + de4x5_local_stats(dev, skb->data, pkt_len); + } + } + + /* Change buffer ownership for this frame, back to the adapter */ + for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) % lp->rxRingSize) { + lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN); + barrier(); + } + lp->rx_ring[entry].status = cpu_to_le32(R_OWN); + barrier(); } - } - - /* Change buffer ownership for this frame, back to the adapter */ - for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) { - lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN); - barrier(); - } - lp->rx_ring[entry].status = cpu_to_le32(R_OWN); - barrier(); + /* + ** Update entry information + */ + lp->rx_new = (++lp->rx_new) % lp->rxRingSize; } - - /* - ** Update entry information - */ - lp->rx_new = (++lp->rx_new) % lp->rxRingSize; - } - - return 0; + + return 0; } /* ** Buffer sent - check for TX buffer errors. */ -static int -de4x5_tx(struct device *dev) +static int de4x5_tx(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int entry; - s32 status; - - for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) { - status = (s32)le32_to_cpu(lp->tx_ring[entry].status); - if (status < 0) { /* Buffer not sent yet */ - break; - } else if (status != 0x7fffffff) { /* Not setup frame */ - if (status & TD_ES) { /* An error happened */ - lp->stats.tx_errors++; - if (status & TD_NC) lp->stats.tx_carrier_errors++; - if (status & TD_LC) lp->stats.tx_window_errors++; - if (status & TD_UF) lp->stats.tx_fifo_errors++; - if (status & TD_EC) lp->pktStats.excessive_collisions++; - if (status & TD_DE) lp->stats.tx_aborted_errors++; - - if (TX_PKT_PENDING) { - outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int entry; + s32 status; + + for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) { + status = (s32) le32_to_cpu(lp->tx_ring[entry].status); + if (status < 0) { /* Buffer not sent yet */ + break; + } else if (status != 0x7fffffff) { /* Not setup frame */ + if (status & TD_ES) { /* An error happened */ + lp->stats.tx_errors++; + if (status & TD_NC) + lp->stats.tx_carrier_errors++; + if (status & TD_LC) + lp->stats.tx_window_errors++; + if (status & TD_UF) + lp->stats.tx_fifo_errors++; + if (status & TD_EC) + lp->pktStats.excessive_collisions++; + if (status & TD_DE) + lp->stats.tx_aborted_errors++; + + if (TX_PKT_PENDING) { + outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */ + } + } else { /* Packet sent */ + lp->stats.tx_packets++; + if (lp->tx_enable) + lp->linkOK++; + } + /* Update the collision counter */ + lp->stats.collisions += ((status & TD_EC) ? 16 : + ((status & TD_CC) >> 3)); + + /* Free the buffer. */ + if (lp->tx_skb[entry] != NULL) { + dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE); + lp->tx_skb[entry] = NULL; + } } - } else { /* Packet sent */ - lp->stats.tx_packets++; - if (lp->tx_enable) lp->linkOK++; - } - /* Update the collision counter */ - lp->stats.collisions += ((status & TD_EC) ? 16 : - ((status & TD_CC) >> 3)); - - /* Free the buffer. */ - if (lp->tx_skb[entry] != NULL) { - dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE); - lp->tx_skb[entry] = NULL; - } + /* Update all the pointers */ + lp->tx_old = (++lp->tx_old) % lp->txRingSize; } - - /* Update all the pointers */ - lp->tx_old = (++lp->tx_old) % lp->txRingSize; - } - - if (TX_BUFFS_AVAIL && dev->tbusy) { /* Any resources available? */ - dev->tbusy = 0; /* Clear TX busy flag */ - if (dev->interrupt) mark_bh(NET_BH); - } - - return 0; -} -static int -de4x5_ast(struct device *dev) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int next_tick = DE4X5_AUTOSENSE_MS; - - disable_ast(dev); - - if (lp->useSROM) { - next_tick = srom_autoconf(dev); - } else if (lp->chipset == DC21140) { - next_tick = dc21140m_autoconf(dev); - } else if (lp->chipset == DC21041) { - next_tick = dc21041_autoconf(dev); - } else if (lp->chipset == DC21040) { - next_tick = dc21040_autoconf(dev); - } - lp->linkOK = 0; - enable_ast(dev, next_tick); - - return 0; + if (TX_BUFFS_AVAIL && dev->tbusy) { /* Any resources available? */ + dev->tbusy = 0; /* Clear TX busy flag */ + if (dev->interrupt) + mark_bh(NET_BH); + } + return 0; } -static int -de4x5_txur(struct device *dev) +static int de4x5_ast(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; - int omr; - - omr = inl(DE4X5_OMR); - if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) { - omr &= ~(OMR_ST|OMR_SR); - outl(omr, DE4X5_OMR); - while (inl(DE4X5_STS) & STS_TS); - if ((omr & OMR_TR) < OMR_TR) { - omr += 0x4000; - } else { - omr |= OMR_SF; - } - outl(omr | OMR_ST | OMR_SR, DE4X5_OMR); - } - - return 0; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int next_tick = DE4X5_AUTOSENSE_MS; + + disable_ast(dev); + + if (lp->useSROM) { + next_tick = srom_autoconf(dev); + } else if (lp->chipset == DC21140) { + next_tick = dc21140m_autoconf(dev); + } else if (lp->chipset == DC21041) { + next_tick = dc21041_autoconf(dev); + } else if (lp->chipset == DC21040) { + next_tick = dc21040_autoconf(dev); + } + lp->linkOK = 0; + enable_ast(dev, next_tick); + + return 0; } -static int -de4x5_rx_ovfc(struct device *dev) +static int de4x5_txur(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; - int omr; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int omr; + + omr = inl(DE4X5_OMR); + if (!(omr & OMR_SF) || (lp->chipset == DC21041) || (lp->chipset == DC21040)) { + omr &= ~(OMR_ST | OMR_SR); + outl(omr, DE4X5_OMR); + while (inl(DE4X5_STS) & STS_TS); + if ((omr & OMR_TR) < OMR_TR) { + omr += 0x4000; + } else { + omr |= OMR_SF; + } + outl(omr | OMR_ST | OMR_SR, DE4X5_OMR); + } + return 0; +} - omr = inl(DE4X5_OMR); - outl(omr & ~OMR_SR, DE4X5_OMR); - while (inl(DE4X5_STS) & STS_RS); +static int de4x5_rx_ovfc(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int omr; + + omr = inl(DE4X5_OMR); + outl(omr & ~OMR_SR, DE4X5_OMR); + while (inl(DE4X5_STS) & STS_RS); + + for (; (s32) le32_to_cpu(lp->rx_ring[lp->rx_new].status) >= 0;) { + lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN); + lp->rx_new = (++lp->rx_new % lp->rxRingSize); + } - for (; (s32)le32_to_cpu(lp->rx_ring[lp->rx_new].status)>=0;) { - lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN); - lp->rx_new = (++lp->rx_new % lp->rxRingSize); - } + outl(omr, DE4X5_OMR); - outl(omr, DE4X5_OMR); - - return 0; + return 0; } -static int -de4x5_close(struct device *dev) +static int de4x5_close(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - s32 imr, omr; - - disable_ast(dev); - dev->start = 0; - dev->tbusy = 1; - - if (de4x5_debug & DEBUG_CLOSE) { - printk("%s: Shutting down ethercard, status was %8.8x.\n", - dev->name, inl(DE4X5_STS)); - } - - /* - ** We stop the DE4X5 here... mask interrupts and stop TX & RX - */ - DISABLE_IRQs; - STOP_DE4X5; - - /* Free the associated irq */ - free_irq(dev->irq, dev); - lp->state = CLOSED; - - /* Free any socket buffers */ - de4x5_free_rx_buffs(dev); - de4x5_free_tx_buffs(dev); - - MOD_DEC_USE_COUNT; - - /* Put the adapter to sleep to save power */ - yawn(dev, SLEEP); - - return 0; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 imr, omr; + + disable_ast(dev); + dev->start = 0; + dev->tbusy = 1; + + if (de4x5_debug & DEBUG_CLOSE) { + printk("%s: Shutting down ethercard, status was %8.8x.\n", + dev->name, inl(DE4X5_STS)); + } + /* + ** We stop the DE4X5 here... mask interrupts and stop TX & RX + */ + DISABLE_IRQs; + STOP_DE4X5; + + /* Free the associated irq */ + free_irq(dev->irq, dev); + lp->state = CLOSED; + + /* Free any socket buffers */ + de4x5_free_rx_buffs(dev); + de4x5_free_tx_buffs(dev); + + MOD_DEC_USE_COUNT; + + /* Put the adapter to sleep to save power */ + yawn(dev, SLEEP); + + return 0; } static struct net_device_stats * de4x5_get_stats(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - - lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR)); - - return &lp->stats; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + + lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR)); + + return &lp->stats; } -static void -de4x5_local_stats(struct device *dev, char *buf, int pkt_len) +static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int i; - for (i=1; ipktStats.bins[i]++; - i = DE4X5_PKT_STAT_SZ; + for (i = 1; i < DE4X5_PKT_STAT_SZ - 1; i++) { + if (pkt_len < (i * DE4X5_PKT_BIN_SZ)) { + lp->pktStats.bins[i]++; + i = DE4X5_PKT_STAT_SZ; + } } - } - if (buf[0] & 0x01) { /* Multicast/Broadcast */ - if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) { - lp->pktStats.broadcast++; - } else { - lp->pktStats.multicast++; + if (buf[0] & 0x01) { /* Multicast/Broadcast */ + if ((*(s32 *) & buf[0] == -1) && (*(s16 *) & buf[4] == -1)) { + lp->pktStats.broadcast++; + } else { + lp->pktStats.multicast++; + } + } else if ((*(s32 *) & buf[0] == *(s32 *) & dev->dev_addr[0]) && + (*(s16 *) & buf[4] == *(s16 *) & dev->dev_addr[4])) { + lp->pktStats.unicast++; + } + lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ + if (lp->pktStats.bins[0] == 0) { /* Reset counters */ + memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats)); } - } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) && - (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { - lp->pktStats.unicast++; - } - - lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ - if (lp->pktStats.bins[0] == 0) { /* Reset counters */ - memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats)); - } - - return; + return; } -static void -load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) +static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - - lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf)); - lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER); - lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags); - lp->tx_skb[lp->tx_new] = skb; - barrier(); - lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN); - barrier(); - - return; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + + lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf)); + lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER); + lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags); + lp->tx_skb[lp->tx_new] = skb; + barrier(); + lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN); + barrier(); + + return; } /* ** Set or clear the multicast filter for this adaptor. */ -static void -set_multicast_list(struct device *dev) +static void set_multicast_list(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; - /* First, double check that the adapter is open */ - if (lp->state == OPEN) { - if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ - u32 omr; - omr = inl(DE4X5_OMR); - omr |= OMR_PR; - outl(omr, DE4X5_OMR); - } else { - SetMulticastFilter(dev); - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); - - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ - dev->trans_start = jiffies; + /* First, double check that the adapter is open */ + if (lp->state == OPEN) { + if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ + u32 omr; + omr = inl(DE4X5_OMR); + omr |= OMR_PR; + outl(omr, DE4X5_OMR); + } else { + SetMulticastFilter(dev); + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + SETUP_FRAME_LEN, NULL); + + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ + dev->trans_start = jiffies; + } } - } - - return; + return; } /* @@ -1866,130 +1855,136 @@ ** from a list of ethernet multicast addresses. ** Little endian crc one liner from Matt Thomas, DEC. */ -static void -SetMulticastFilter(struct device *dev) +static void SetMulticastFilter(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - struct dev_mc_list *dmi=dev->mc_list; - u_long iobase = dev->base_addr; - int i, j, bit, byte; - u16 hashcode; - u32 omr, crc, poly = CRC_POLYNOMIAL_LE; - char *pa; - unsigned char *addrs; - - omr = inl(DE4X5_OMR); - omr &= ~(OMR_PR | OMR_PM); - pa = build_setup_frame(dev, ALL); /* Build the basic frame */ - - if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) { - omr |= OMR_PM; /* Pass all multicasts */ - } else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */ - for (i=0;imc_count;i++) { /* for each address in the list */ - addrs=dmi->dmi_addr; - dmi=dmi->next; - if ((*addrs & 0x01) == 1) { /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte=0;byte>=1) { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } - } - hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ - - byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ - bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */ - - byte <<= 1; /* calc offset into setup frame */ - if (byte & 0x02) { - byte -= 1; - } - lp->setup_frame[byte] |= bit; - } - } - } else { /* Perfect filtering */ - for (j=0; jmc_count; j++) { - addrs=dmi->dmi_addr; - dmi=dmi->next; - for (i=0; ipriv; + struct dev_mc_list *dmi = dev->mc_list; + u_long iobase = dev->base_addr; + int i, j, bit, byte; + u16 hashcode; + u32 omr, crc, poly = CRC_POLYNOMIAL_LE; + char *pa; + unsigned char *addrs; + + omr = inl(DE4X5_OMR); + omr &= ~(OMR_PR | OMR_PM); + pa = build_setup_frame(dev, ALL); /* Build the basic frame */ + + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) { + omr |= OMR_PM; /* Pass all multicasts */ + } else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */ + for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + addrs = dmi->dmi_addr; + dmi = dmi->next; + if ((*addrs & 0x01) == 1) { /* multicast address? */ + crc = 0xffffffff; /* init CRC for each address */ + for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ + /* process each address bit */ + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); + } + } + hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ + + byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + + byte <<= 1; /* calc offset into setup frame */ + if (byte & 0x02) { + byte -= 1; + } + lp->setup_frame[byte] |= bit; + } + } + } else { /* Perfect filtering */ + for (j = 0; j < dev->mc_count; j++) { + addrs = dmi->dmi_addr; + dmi = dmi->next; + for (i = 0; i < ETH_ALEN; i++) { + *(pa + (i & 1)) = *addrs++; + if (i & 0x01) + pa += 4; + } + } } - } - outl(omr, DE4X5_OMR); - - return; + outl(omr, DE4X5_OMR); + + return; } +#ifndef __sparc_v9__ /* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. Upto 15 EISA devices are supported. */ __initfunc(static void -eisa_probe(struct device *dev, u_long ioaddr)) + eisa_probe(struct device *dev, u_long ioaddr)) { - int i, maxSlots, status, device; - u_char irq; - u_short vendor; - u32 cfid; - u_long iobase; - struct bus_type *lp = &bus; - char name[DE4X5_STRLEN]; - - if (lastEISA == MAX_EISA_SLOTS) return; /* No more EISA devices to search */ - - lp->bus = EISA; - - if (ioaddr == 0) { /* Autoprobing */ - iobase = EISA_SLOT_INC; /* Get the first slot address */ - i = 1; - maxSlots = MAX_EISA_SLOTS; - } else { /* Probe a specific location */ - iobase = ioaddr; - i = (ioaddr >> 12); - maxSlots = i + 1; - } - - for (status = -ENODEV; (i> 8) & 0x00ffff00; - vendor = (u_short) cfid; - - /* Read the EISA Configuration Registers */ - irq = inb(EISA_REG0); - irq = de4x5_irq[(irq >> 1) & 0x03]; - - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; - - /* Write the PCI Configuration Registers */ - outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); - outl(0x00006000, PCI_CFLT); - outl(iobase, PCI_CBIO); - - DevicePresent(DE4X5_APROM); - if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) link_modules(lastModule, dev); - lastEISA = i; - return; - } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase); - } + int i, maxSlots, status, device; + u_char irq; + u_short vendor; + u32 cfid; + u_long iobase; + struct bus_type *lp = &bus; + char name[DE4X5_STRLEN]; + + if (lastEISA == MAX_EISA_SLOTS) + return; /* No more EISA devices to search */ + + lp->bus = EISA; + + if (ioaddr == 0) { /* Autoprobing */ + iobase = EISA_SLOT_INC; /* Get the first slot address */ + i = 1; + maxSlots = MAX_EISA_SLOTS; + } else { /* Probe a specific location */ + iobase = ioaddr; + i = (ioaddr >> 12); + maxSlots = i + 1; + } + + for (status = -ENODEV; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { + if (EISA_signature(name, EISA_ID)) { + cfid = (u32) inl(PCI_CFID); + cfrv = (u_short) inl(PCI_CFRV); + device = (cfid >> 8) & 0x00ffff00; + vendor = (u_short) cfid; + + /* Read the EISA Configuration Registers */ + irq = inb(EISA_REG0); + irq = de4x5_irq[(irq >> 1) & 0x03]; + + if (is_DC2114x) + device |= (cfrv & CFRV_RN); + lp->chipset = device; + + /* Write the PCI Configuration Registers */ + outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); + outl(0x00006000, PCI_CFLT); + outl(iobase, PCI_CBIO); + + DevicePresent(DE4X5_APROM); + if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) link_modules(lastModule, dev); + lastEISA = i; + return; + } + } else if (ioaddr != 0) { + printk("%s: region already allocated at 0x%04lx.\n", + dev->name, iobase); + } + } } - } - if (ioaddr == 0) lastEISA = i; + if (ioaddr == 0) + lastEISA = i; - return; + return; } +#endif /* !(__sparc_v9__) */ /* ** PCI bus I/O device probe @@ -2007,110 +2002,151 @@ #define PCI_LAST_DEV 32 __initfunc(static void -pci_probe(struct device *dev, u_long ioaddr)) + pci_probe(struct device *dev, u_long ioaddr)) { - u_char irq, timer; - u_char pb, pbus, dev_num, dnum, dev_fn; - u_short dev_id, vendor, index, status; - u_int class = DE4X5_CLASS_CODE; - u_int device, iobase; - struct bus_type *lp = &bus; - - if (lastPCI == NO_MORE_PCI) return; - - if (!pcibios_present()) { - lastPCI = NO_MORE_PCI; - return; /* No PCI bus in this machine! */ - } - - lp->bus = PCI; - lp->bus_num = 0; + u_char pb, pbus, dev_num, dnum, dev_fn, timer; + u_short dev_id, vendor, index, status; + u_int irq; + u_int class = DE4X5_CLASS_CODE; + u_int device; + u_long iobase; + struct bus_type *lp = &bus; - if ((ioaddr < 0x1000) && loading_module) { - pbus = (u_short)(ioaddr >> 8); - dnum = (u_short)(ioaddr & 0xff); - } else { - pbus = 0; - dnum = 0; - } - - for (index=lastPCI+1; - (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); - index++) { - dev_num = PCI_SLOT(dev_fn); - - if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } + if (lastPCI == NO_MORE_PCI) + return; - /* Search for an SROM on this bus */ - if (lp->bus_num != pb) { - lp->bus_num = pb; - srom_search(index); - } + if (!pcibios_present()) { + lastPCI = NO_MORE_PCI; + return; /* No PCI bus in this machine! */ + } - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + lp->bus = PCI; - /* Set the device number information */ - lp->device = dev_num; - lp->bus_num = pb; - - /* Set the chipset information */ - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; - - /* Get the board I/O address */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase); - iobase &= CBIO_MASK; - - /* Fetch the IRQ to be used */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq); - if ((irq == 0) || (irq == (u_char) 0xff)) continue; - - /* Check if I/O accesses and Bus Mastering are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - if (!(status & PCI_COMMAND_IO)) continue; - if (!(status & PCI_COMMAND_MASTER)) { - status |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } - if (!(status & PCI_COMMAND_MASTER)) continue; + if ((ioaddr < 0x1000) && loading_module) { + pbus = (u_short) (ioaddr >> 8); + dnum = (u_short) (ioaddr & 0xff); + } else { + pbus = 0; + dnum = 0; + } + + for (index = lastPCI+1; + (pcibios_find_class(class, index, &pb, &dev_fn) != PCIBIOS_DEVICE_NOT_FOUND); + index++) { + dev_num = PCI_SLOT(dev_fn); + + if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { +#ifdef __sparc_v9__ + struct pci_dev *pdev; + + for (pdev = pci_devices; pdev; pdev = pdev->next) + if (pdev->bus->number == pb && + pdev->devfn == dev_fn) + break; +#endif + device = 0; + pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; + device <<= 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { + continue; + } + + /* Search for an SROM on this bus */ + if (lp->bus_num != pb) { + lp->bus_num = pb; + srom_search(index); + } + + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + + /* Set the device number information */ + lp->device = dev_num; + lp->bus_num = pb; + + /* Set the chipset information */ + if (is_DC2114x) + device |= (cfrv & CFRV_RN); + lp->chipset = device; + + /* Get the board I/O address */ +#ifdef __sparc_v9__ + iobase = pdev->base_address[0]; +#else + { + unsigned int tmp; + pcibios_read_config_dword(pb, PCI_DEVICE, + PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; + } +#endif + iobase &= CBIO_MASK; + + /* Fetch the IRQ to be used */ +#ifdef __sparc_v9__ + irq = pdev->irq; +#else + { + unsigned char tmp; + pcibios_read_config_byte(pb, PCI_DEVICE, + PCI_INTERRUPT_LINE, &tmp); + irq = tmp; + } + if ((irq == 0) || (irq == (u_char) 0xff)) + continue; +#endif + + /* Check if I/O accesses and Bus Mastering are enabled */ + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); +#ifdef __powerpc__ + if (!(status & PCI_COMMAND_IO)) { + status |= PCI_COMMAND_IO; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } +#endif /* __powerpc__ */ + if (!(status & PCI_COMMAND_IO)) + continue; + if (!(status & PCI_COMMAND_MASTER)) { + status |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } + if (!(status & PCI_COMMAND_MASTER)) + continue; + + /* Check the latency timer for values > 0x60 */ + pcibios_read_config_byte(pb, PCI_DEVICE, + PCI_LATENCY_TIMER, &timer); + if (timer < 0x60) { + pcibios_write_config_byte(pb, PCI_DEVICE, + PCI_LATENCY_TIMER, 0x60); + } - /* Check the latency timer for values > 0x60 */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); - if (timer < 0x60) { - pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); - } - - DevicePresent(DE4X5_APROM); - if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) { - link_modules(lastModule, dev); - lastPCI = index; - } - return; - } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04x.\n", dev->name, - (u_short)iobase); - } + DevicePresent(DE4X5_APROM); + if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) { + link_modules(lastModule, dev); + lastPCI = index; + } + return; + } + } else if (ioaddr != 0) { + printk("%s: region already allocated at 0x%04x.\n", dev->name, + (u_short) iobase); + } + } } - } - if (loading_module) lastPCI = NO_MORE_PCI; + if (loading_module) + lastPCI = NO_MORE_PCI; - return; + return; } /* @@ -2120,90 +2156,95 @@ ** For single port cards this is a time waster... */ __initfunc(static void -srom_search(int index)) + srom_search(int index)) { - u_char irq, pb, dev_fn; - u_short dev_id, dev_num, vendor, status; - u_int class = DE4X5_CLASS_CODE; - u_int device, iobase; - int i, j; - struct bus_type *lp = &bus; - - for (; - (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); - index++) { - - if (lp->bus_num != pb) return; - dev_num = PCI_SLOT(dev_fn); - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } - - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); - - /* Set the device number information */ - lp->device = dev_num; - lp->bus_num = pb; + u_char irq, pb, dev_fn; + u_short dev_id, dev_num, vendor, status; + u_int class = DE4X5_CLASS_CODE; + u_int device, iobase; + int i, j; + struct bus_type *lp = &bus; + + for (; + (pcibios_find_class(class, index, + &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); + index++) { + + if (lp->bus_num != pb) + return; + dev_num = PCI_SLOT(dev_fn); + device = 0; + pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; + device <<= 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { + continue; + } + + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + + /* Set the device number information */ + lp->device = dev_num; + lp->bus_num = pb; - /* Set the chipset information */ - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; - - /* Get the board I/O address */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase); - iobase &= CBIO_MASK; - - /* Fetch the IRQ to be used */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq); - if ((irq == 0) || (irq == (u_char) 0xff)) continue; + /* Set the chipset information */ + if (is_DC2114x) + device |= (cfrv & CFRV_RN); + lp->chipset = device; + + /* Get the board I/O address */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase); + iobase &= CBIO_MASK; + + /* Fetch the IRQ to be used */ + pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq); + if ((irq == 0) || (irq == (u_char) 0xff)) + continue; - /* Check if I/O accesses are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - if (!(status & PCI_COMMAND_IO)) continue; - - /* Search for a valid SROM attached to this DECchip */ - DevicePresent(DE4X5_APROM); - for (j=0, i=0; isrom + SROM_HWADD + i); - } - if ((j != 0) && (j != 0x5fa)) { - last.chipset = device; - last.bus = pb; - last.irq = irq; - for (i=0; isrom + SROM_HWADD + i); - } - return; + /* Check if I/O accesses are enabled */ + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + if (!(status & PCI_COMMAND_IO)) + continue; + + /* Search for a valid SROM attached to this DECchip */ + DevicePresent(DE4X5_APROM); + for (j=0, i=0; isrom + SROM_HWADD + i); + } + if ((j != 0) && (j != 0x5fa)) { + last.chipset = device; + last.bus = pb; + last.irq = irq; + for (i=0; isrom + SROM_HWADD + i); + } + return; + } } - } - return; + return; } __initfunc(static void -link_modules(struct device *dev, struct device *tmp)) + link_modules(struct device *dev, struct device *tmp)) { - struct device *p=dev; + struct device *p = dev; - if (p) { - while (((struct de4x5_private *)(p->priv))->next_module) { - p = ((struct de4x5_private *)(p->priv))->next_module; - } + if (p) { + while (((struct de4x5_private *) (p->priv))->next_module) { + p = ((struct de4x5_private *) (p->priv))->next_module; + } - if (dev != tmp) { - ((struct de4x5_private *)(p->priv))->next_module = tmp; - } else { - ((struct de4x5_private *)(p->priv))->next_module = NULL; + if (dev != tmp) { + ((struct de4x5_private *) (p->priv))->next_module = tmp; + } else { + ((struct de4x5_private *) (p->priv))->next_module = NULL; + } } - } - - return; + return; } /* @@ -2213,33 +2254,31 @@ ** [TP] or no recent receive activity) to check whether the user has been ** sneaky and changed the port on us. */ -static int -autoconf_media(struct device *dev) +static int autoconf_media(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int next_tick = DE4X5_AUTOSENSE_MS; - - lp->linkOK = 0; - lp->c_media = AUTO; /* Bogus last media */ - disable_ast(dev); - inl(DE4X5_MFC); /* Zero the lost frames counter */ - lp->media = INIT; - lp->tcount = 0; - - if (lp->useSROM) { - next_tick = srom_autoconf(dev); - } else if (lp->chipset == DC21040) { - next_tick = dc21040_autoconf(dev); - } else if (lp->chipset == DC21041) { - next_tick = dc21041_autoconf(dev); - } else if (lp->chipset == DC21140) { - next_tick = dc21140m_autoconf(dev); - } + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int next_tick = DE4X5_AUTOSENSE_MS; + + lp->linkOK = 0; + lp->c_media = AUTO; /* Bogus last media */ + disable_ast(dev); + inl(DE4X5_MFC); /* Zero the lost frames counter */ + lp->media = INIT; + lp->tcount = 0; - enable_ast(dev, next_tick); - - return (lp->media); + if (lp->useSROM) { + next_tick = srom_autoconf(dev); + } else if (lp->chipset == DC21040) { + next_tick = dc21040_autoconf(dev); + } else if (lp->chipset == DC21041) { + next_tick = dc21041_autoconf(dev); + } else if (lp->chipset == DC21140) { + next_tick = dc21140m_autoconf(dev); + } + enable_ast(dev, next_tick); + + return (lp->media); } /* @@ -2254,149 +2293,146 @@ ** I may have to "age out" locally queued packets so that the higher layer ** timeouts don't effectively duplicate packets on the network. */ -static int -dc21040_autoconf(struct device *dev) +static int dc21040_autoconf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int next_tick = DE4X5_AUTOSENSE_MS; - s32 imr; - - switch (lp->media) { - case INIT: - DISABLE_IRQs; - lp->tx_enable = NO; - lp->timeout = -1; - de4x5_save_skbs(dev); - if ((lp->autosense == AUTO) || (lp->autosense == TP)) { - lp->media = TP; - } else if ((lp->autosense == BNC) || (lp->autosense == AUI) || (lp->autosense == BNC_AUI)) { - lp->media = BNC_AUI; - } else if (lp->autosense == EXT_SIA) { - lp->media = EXT_SIA; - } else { - lp->media = NC; - } - lp->local_state = 0; - next_tick = dc21040_autoconf(dev); - break; - - case TP: - next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, - TP_SUSPECT, test_tp); - break; - - case TP_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf); - break; - - case BNC: - case AUI: - case BNC_AUI: - next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, - BNC_AUI_SUSPECT, ping_media); - break; - - case BNC_AUI_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf); - break; - - case EXT_SIA: - next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, - NC, EXT_SIA_SUSPECT, ping_media); - break; - - case EXT_SIA_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf); - break; - - case NC: - /* default to TP for all */ - reset_init_sia(dev, 0x8f01, 0xffff, 0x0000); - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int next_tick = DE4X5_AUTOSENSE_MS; + s32 imr; + + switch (lp->media) { + case INIT: + DISABLE_IRQs; + lp->tx_enable = NO; + lp->timeout = -1; + de4x5_save_skbs(dev); + if ((lp->autosense == AUTO) || (lp->autosense == TP)) { + lp->media = TP; + } else if ((lp->autosense == BNC) || (lp->autosense == AUI) || (lp->autosense == BNC_AUI)) { + lp->media = BNC_AUI; + } else if (lp->autosense == EXT_SIA) { + lp->media = EXT_SIA; + } else { + lp->media = NC; + } + lp->local_state = 0; + next_tick = dc21040_autoconf(dev); + break; + + case TP: + next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, + TP_SUSPECT, test_tp); + break; + + case TP_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf); + break; + + case BNC: + case AUI: + case BNC_AUI: + next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, + BNC_AUI_SUSPECT, ping_media); + break; + + case BNC_AUI_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf); + break; + + case EXT_SIA: + next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, + NC, EXT_SIA_SUSPECT, ping_media); + break; + + case EXT_SIA_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf); + break; + + case NC: + /* default to TP for all */ + reset_init_sia(dev, 0x8f01, 0xffff, 0x0000); + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tx_enable = NO; + break; } - lp->media = INIT; - lp->tx_enable = NO; - break; - } - - return next_tick; + + return next_tick; } -static int -dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, - int next_state, int suspect_state, - int (*fn)(struct device *, int)) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int next_tick = DE4X5_AUTOSENSE_MS; - int linkBad; - - switch (lp->local_state) { - case 0: - reset_init_sia(dev, csr13, csr14, csr15); - lp->local_state++; - next_tick = 500; - break; - - case 1: - if (!lp->tx_enable) { - linkBad = fn(dev, timeout); - if (linkBad < 0) { - next_tick = linkBad & ~TIMER_CB; - } else { - if (linkBad && (lp->autosense == AUTO)) { - lp->local_state = 0; - lp->media = next_state; - } else { - de4x5_init_connection(dev); - } - } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = suspect_state; - next_tick = 3000; +static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, + int next_state, int suspect_state, + int (*fn) (struct device *, int)) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int next_tick = DE4X5_AUTOSENSE_MS; + int linkBad; + + switch (lp->local_state) { + case 0: + reset_init_sia(dev, csr13, csr14, csr15); + lp->local_state++; + next_tick = 500; + break; + + case 1: + if (!lp->tx_enable) { + linkBad = fn(dev, timeout); + if (linkBad < 0) { + next_tick = linkBad & ~TIMER_CB; + } else { + if (linkBad && (lp->autosense == AUTO)) { + lp->local_state = 0; + lp->media = next_state; + } else { + de4x5_init_connection(dev); + } + } + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = suspect_state; + next_tick = 3000; + } + break; } - break; - } - - return next_tick; + + return next_tick; } -static int -de4x5_suspect_state(struct device *dev, int timeout, int prev_state, - int (*fn)(struct device *, int), - int (*asfn)(struct device *)) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int next_tick = DE4X5_AUTOSENSE_MS; - int linkBad; - - switch (lp->local_state) { - case 1: - if (lp->linkOK) { - lp->media = prev_state; - } else { - lp->local_state++; - next_tick = asfn(dev); - } - break; +static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, + int (*fn) (struct device *, int), + int (*asfn) (struct device *)) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int next_tick = DE4X5_AUTOSENSE_MS; + int linkBad; - case 2: - linkBad = fn(dev, timeout); - if (linkBad < 0) { - next_tick = linkBad & ~TIMER_CB; - } else if (!linkBad) { - lp->local_state--; - lp->media = prev_state; - } else { - lp->media = INIT; - lp->tcount++; + switch (lp->local_state) { + case 1: + if (lp->linkOK) { + lp->media = prev_state; + } else { + lp->local_state++; + next_tick = asfn(dev); + } + break; + + case 2: + linkBad = fn(dev, timeout); + if (linkBad < 0) { + next_tick = linkBad & ~TIMER_CB; + } else if (!linkBad) { + lp->local_state--; + lp->media = prev_state; + } else { + lp->media = INIT; + lp->tcount++; + } } - } - return next_tick; + return next_tick; } /* @@ -2408,374 +2444,375 @@ ** any more packets to be queued to the hardware. Re-enable everything only ** when the media is found. */ -static int -dc21041_autoconf(struct device *dev) +static int dc21041_autoconf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - s32 sts, irqs, irq_mask, imr, omr; - int next_tick = DE4X5_AUTOSENSE_MS; - - switch (lp->media) { - case INIT: - DISABLE_IRQs; - lp->tx_enable = NO; - lp->timeout = -1; - de4x5_save_skbs(dev); /* Save non transmitted skb's */ - if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) { - lp->media = TP; /* On chip auto negotiation is broken */ - } else if (lp->autosense == TP) { - lp->media = TP; - } else if (lp->autosense == BNC) { - lp->media = BNC; - } else if (lp->autosense == AUI) { - lp->media = AUI; - } else { - lp->media = NC; - } - lp->local_state = 0; - next_tick = dc21041_autoconf(dev); - break; - - case TP_NW: - if (lp->timeout < 0) { - omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */ - outl(omr | OMR_FDX, DE4X5_OMR); - } - irqs = STS_LNF | STS_LNP; - irq_mask = IMR_LFM | IMR_LPM; - sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - if (sts & STS_LNP) { - lp->media = ANS; - } else { - lp->media = AUI; - } - next_tick = dc21041_autoconf(dev); - } - break; - - case ANS: - if (!lp->tx_enable) { - irqs = STS_LNP; - irq_mask = IMR_LPM; - sts = test_ans(dev, irqs, irq_mask, 3000); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - if (!(sts & STS_LNP) && (lp->autosense == AUTO)) { - lp->media = TP; - next_tick = dc21041_autoconf(dev); - } else { - lp->local_state = 1; - de4x5_init_connection(dev); - } - } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = ANS_SUSPECT; - next_tick = 3000; - } - break; - - case ANS_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf); - break; - - case TP: - if (!lp->tx_enable) { - if (lp->timeout < 0) { - omr = inl(DE4X5_OMR); /* Set up half duplex for TP */ - outl(omr & ~OMR_FDX, DE4X5_OMR); - } - irqs = STS_LNF | STS_LNP; - irq_mask = IMR_LFM | IMR_LPM; - sts = test_media(dev,irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - if (!(sts & STS_LNP) && (lp->autosense == AUTO)) { - if (inl(DE4X5_SISR) & SISR_NRA) { - lp->media = AUI; /* Non selected port activity */ - } else { + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 sts, irqs, irq_mask, imr, omr; + int next_tick = DE4X5_AUTOSENSE_MS; + + switch (lp->media) { + case INIT: + DISABLE_IRQs; + lp->tx_enable = NO; + lp->timeout = -1; + de4x5_save_skbs(dev); /* Save non transmitted skb's */ + if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) { + lp->media = TP; /* On chip auto negotiation is broken */ + } else if (lp->autosense == TP) { + lp->media = TP; + } else if (lp->autosense == BNC) { lp->media = BNC; - } - next_tick = dc21041_autoconf(dev); - } else { - lp->local_state = 1; - de4x5_init_connection(dev); - } - } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = TP_SUSPECT; - next_tick = 3000; - } - break; - - case TP_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf); - break; - - case AUI: - if (!lp->tx_enable) { - if (lp->timeout < 0) { - omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ - outl(omr & ~OMR_FDX, DE4X5_OMR); - } - irqs = 0; - irq_mask = 0; - sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) { - lp->media = BNC; - next_tick = dc21041_autoconf(dev); - } else { - lp->local_state = 1; - de4x5_init_connection(dev); - } - } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = AUI_SUSPECT; - next_tick = 3000; - } - break; - - case AUI_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf); - break; - - case BNC: - switch (lp->local_state) { - case 0: - if (lp->timeout < 0) { - omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ - outl(omr & ~OMR_FDX, DE4X5_OMR); - } - irqs = 0; - irq_mask = 0; - sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - lp->local_state++; /* Ensure media connected */ - next_tick = dc21041_autoconf(dev); - } - break; - - case 1: - if (!lp->tx_enable) { - if ((sts = ping_media(dev, 3000)) < 0) { - next_tick = sts & ~TIMER_CB; + } else if (lp->autosense == AUI) { + lp->media = AUI; } else { - if (sts) { - lp->local_state = 0; lp->media = NC; - } else { - de4x5_init_connection(dev); - } } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = BNC_SUSPECT; - next_tick = 3000; - } - break; - } - break; - - case BNC_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf); - break; - - case NC: - omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */ - outl(omr | OMR_FDX, DE4X5_OMR); - reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */ - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; - } - lp->media = INIT; - lp->tx_enable = NO; - break; - } - - return next_tick; -} + lp->local_state = 0; + next_tick = dc21041_autoconf(dev); + break; -/* -** Some autonegotiation chips are broken in that they do not return the -** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement -** register, except at the first power up negotiation. -*/ -static int -dc21140m_autoconf(struct device *dev) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int ana, anlpa, cap, cr, slnk, sr, iobase = dev->base_addr; - int next_tick = DE4X5_AUTOSENSE_MS; - u_long imr, omr; - - switch(lp->media) { - case INIT: - if (lp->timeout < 0) { - DISABLE_IRQs; - lp->tx_enable = FALSE; - lp->linkOK = 0; - de4x5_save_skbs(dev); /* Save non transmitted skb's */ - } - if ((next_tick = de4x5_reset_phy(dev)) < 0) { - next_tick &= ~TIMER_CB; - } else { - if (lp->useSROM) { - if (srom_map_media(dev) < 0) { - lp->tcount++; - return next_tick; + case TP_NW: + if (lp->timeout < 0) { + omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */ + outl(omr | OMR_FDX, DE4X5_OMR); } - srom_exec(dev, lp->phy[lp->active].gep); - if (lp->infoblock_media == ANS) { - ana = lp->phy[lp->active].ana | MII_ANA_CSMA; - mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - } - } else { - lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ - SET_10Mb; - if (lp->autosense == _100Mb) { - lp->media = _100Mb; - } else if (lp->autosense == _10Mb) { - lp->media = _10Mb; - } else if ((lp->autosense == AUTO) && - ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { - ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); - ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM); - mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - lp->media = ANS; - } else if (lp->autosense == AUTO) { - lp->media = SPD_DET; - } else if (is_spd_100(dev) && is_100_up(dev)) { - lp->media = _100Mb; - } else { - lp->media = NC; - } - } - lp->local_state = 0; - next_tick = dc21140m_autoconf(dev); - } - break; - - case ANS: - switch (lp->local_state) { - case 0: - if (lp->timeout < 0) { - mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); - } - cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500); - if (cr < 0) { - next_tick = cr & ~TIMER_CB; - } else { - if (cr) { - lp->local_state = 0; - lp->media = SPD_DET; + irqs = STS_LNF | STS_LNP; + irq_mask = IMR_LFM | IMR_LPM; + sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; } else { - lp->local_state++; + if (sts & STS_LNP) { + lp->media = ANS; + } else { + lp->media = AUI; + } + next_tick = dc21041_autoconf(dev); } - next_tick = dc21140m_autoconf(dev); - } - break; - - case 1: - if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { - next_tick = sr & ~TIMER_CB; - } else { - lp->media = SPD_DET; - lp->local_state = 0; - if (sr) { /* Success! */ - lp->tmp = MII_SR_ASSC; - anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII); - ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - if (!(anlpa & MII_ANLPA_RF) && - (cap = anlpa & MII_ANLPA_TAF & ana)) { - if (cap & MII_ANA_100M) { - lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); - lp->media = _100Mb; - } else if (cap & MII_ANA_10M) { - lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); + break; - lp->media = _10Mb; + case ANS: + if (!lp->tx_enable) { + irqs = STS_LNP; + irq_mask = IMR_LPM; + sts = test_ans(dev, irqs, irq_mask, 3000); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; + } else { + if (!(sts & STS_LNP) && (lp->autosense == AUTO)) { + lp->media = TP; + next_tick = dc21041_autoconf(dev); + } else { + lp->local_state = 1; + de4x5_init_connection(dev); + } } - } - } /* Auto Negotiation failed to finish */ - next_tick = dc21140m_autoconf(dev); - } /* Auto Negotiation failed to start */ - break; - } - break; - - case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ - if (lp->timeout < 0) { - lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : - (~gep_rd(dev) & GEP_LNP)); - SET_100Mb_PDET; - } - if ((slnk = test_for_100Mb(dev, 6500)) < 0) { - next_tick = slnk & ~TIMER_CB; - } else { - if (is_spd_100(dev) && is_100_up(dev)) { - lp->media = _100Mb; - } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) { - lp->media = _10Mb; - } else { - lp->media = NC; - } - next_tick = dc21140m_autoconf(dev); - } - break; - - case _100Mb: /* Set 100Mb/s */ - next_tick = 3000; - if (!lp->tx_enable) { - SET_100Mb; - de4x5_init_connection(dev); - } else { - if (!lp->linkOK && (lp->autosense == AUTO)) { - if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) { - lp->media = INIT; - lp->tcount++; - next_tick = DE4X5_AUTOSENSE_MS; + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = ANS_SUSPECT; + next_tick = 3000; } - } - } - break; - - case _10Mb: /* Set 10Mb/s */ - next_tick = 3000; - if (!lp->tx_enable) { - SET_10Mb; - de4x5_init_connection(dev); - } else { - if (!lp->linkOK && (lp->autosense == AUTO)) { - if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) { - lp->media = INIT; - lp->tcount++; - next_tick = DE4X5_AUTOSENSE_MS; + break; + + case ANS_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf); + break; + + case TP: + if (!lp->tx_enable) { + if (lp->timeout < 0) { + omr = inl(DE4X5_OMR); /* Set up half duplex for TP */ + outl(omr & ~OMR_FDX, DE4X5_OMR); + } + irqs = STS_LNF | STS_LNP; + irq_mask = IMR_LFM | IMR_LPM; + sts = test_media(dev, irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; + } else { + if (!(sts & STS_LNP) && (lp->autosense == AUTO)) { + if (inl(DE4X5_SISR) & SISR_NRA) { + lp->media = AUI; /* Non selected port activity */ + } else { + lp->media = BNC; + } + next_tick = dc21041_autoconf(dev); + } else { + lp->local_state = 1; + de4x5_init_connection(dev); + } + } + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = TP_SUSPECT; + next_tick = 3000; } - } + break; + + case TP_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf); + break; + + case AUI: + if (!lp->tx_enable) { + if (lp->timeout < 0) { + omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ + outl(omr & ~OMR_FDX, DE4X5_OMR); + } + irqs = 0; + irq_mask = 0; + sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; + } else { + if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) { + lp->media = BNC; + next_tick = dc21041_autoconf(dev); + } else { + lp->local_state = 1; + de4x5_init_connection(dev); + } + } + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = AUI_SUSPECT; + next_tick = 3000; + } + break; + + case AUI_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf); + break; + + case BNC: + switch (lp->local_state) { + case 0: + if (lp->timeout < 0) { + omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ + outl(omr & ~OMR_FDX, DE4X5_OMR); + } + irqs = 0; + irq_mask = 0; + sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; + } else { + lp->local_state++; /* Ensure media connected */ + next_tick = dc21041_autoconf(dev); + } + break; + + case 1: + if (!lp->tx_enable) { + if ((sts = ping_media(dev, 3000)) < 0) { + next_tick = sts & ~TIMER_CB; + } else { + if (sts) { + lp->local_state = 0; + lp->media = NC; + } else { + de4x5_init_connection(dev); + } + } + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = BNC_SUSPECT; + next_tick = 3000; + } + break; + } + break; + + case BNC_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf); + break; + + case NC: + omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */ + outl(omr | OMR_FDX, DE4X5_OMR); + reset_init_sia(dev, 0xef01, 0xffff, 0x0008); /* Initialise the SIA */ + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tx_enable = NO; + break; } - break; - - case NC: - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; + + return next_tick; +} + +/* +** Some autonegotiation chips are broken in that they do not return the +** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement +** register, except at the first power up negotiation. +*/ +static int dc21140m_autoconf(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int ana, anlpa, cap, cr, slnk, sr; + u_long iobase = dev->base_addr; + int next_tick = DE4X5_AUTOSENSE_MS; + u_long imr, omr; + + switch (lp->media) { + case INIT: + if (lp->timeout < 0) { + DISABLE_IRQs; + lp->tx_enable = FALSE; + lp->linkOK = 0; + de4x5_save_skbs(dev); /* Save non transmitted skb's */ + } + if ((next_tick = de4x5_reset_phy(dev)) < 0) { + next_tick &= ~TIMER_CB; + } else { + if (lp->useSROM) { + if (srom_map_media(dev) < 0) { + lp->tcount++; + return next_tick; + } + srom_exec(dev, lp->phy[lp->active].gep); + if (lp->infoblock_media == ANS) { + ana = lp->phy[lp->active].ana | MII_ANA_CSMA; + mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + } + } else { + lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ + SET_10Mb; + if (lp->autosense == _100Mb) { + lp->media = _100Mb; + } else if (lp->autosense == _10Mb) { + lp->media = _10Mb; + } else if ((lp->autosense == AUTO) && + ((sr = is_anc_capable(dev)) & MII_SR_ANC)) { + ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); + ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM); + mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + lp->media = ANS; + } else if (lp->autosense == AUTO) { + lp->media = SPD_DET; + } else if (is_spd_100(dev) && is_100_up(dev)) { + lp->media = _100Mb; + } else { + lp->media = NC; + } + } + lp->local_state = 0; + next_tick = dc21140m_autoconf(dev); + } + break; + + case ANS: + switch (lp->local_state) { + case 0: + if (lp->timeout < 0) { + mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); + } + cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500); + if (cr < 0) { + next_tick = cr & ~TIMER_CB; + } else { + if (cr) { + lp->local_state = 0; + lp->media = SPD_DET; + } else { + lp->local_state++; + } + next_tick = dc21140m_autoconf(dev); + } + break; + + case 1: + if ((sr = test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { + next_tick = sr & ~TIMER_CB; + } else { + lp->media = SPD_DET; + lp->local_state = 0; + if (sr) { /* Success! */ + lp->tmp = MII_SR_ASSC; + anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII); + ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + if (!(anlpa & MII_ANLPA_RF) && + (cap = anlpa & MII_ANLPA_TAF & ana)) { + if (cap & MII_ANA_100M) { + lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); + lp->media = _100Mb; + } else if (cap & MII_ANA_10M) { + lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); + + lp->media = _10Mb; + } + } + } /* Auto Negotiation failed to finish */ + next_tick = dc21140m_autoconf(dev); + } /* Auto Negotiation failed to start */ + break; + } + break; + + case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ + if (lp->timeout < 0) { + lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : + (~gep_rd(dev) & GEP_LNP)); + SET_100Mb_PDET; + } + if ((slnk = test_for_100Mb(dev, 6500)) < 0) { + next_tick = slnk & ~TIMER_CB; + } else { + if (is_spd_100(dev) && is_100_up(dev)) { + lp->media = _100Mb; + } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) { + lp->media = _10Mb; + } else { + lp->media = NC; + } + next_tick = dc21140m_autoconf(dev); + } + break; + + case _100Mb: /* Set 100Mb/s */ + next_tick = 3000; + if (!lp->tx_enable) { + SET_100Mb; + de4x5_init_connection(dev); + } else { + if (!lp->linkOK && (lp->autosense == AUTO)) { + if (!is_100_up(dev) || + (!lp->useSROM && !is_spd_100(dev))) { + lp->media = INIT; + lp->tcount++; + next_tick = DE4X5_AUTOSENSE_MS; + } + } + } + break; + + case _10Mb: /* Set 10Mb/s */ + next_tick = 3000; + if (!lp->tx_enable) { + SET_10Mb; + de4x5_init_connection(dev); + } else { + if (!lp->linkOK && (lp->autosense == AUTO)) { + if (!is_10_up(dev) || + (!lp->useSROM && is_spd_100(dev))) { + lp->media = INIT; + lp->tcount++; + next_tick = DE4X5_AUTOSENSE_MS; + } + } + } + break; + + case NC: + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tx_enable = FALSE; + break; } - lp->media = INIT; - lp->tx_enable = FALSE; - break; - } - - return next_tick; + + return next_tick; } /* @@ -2795,231 +2832,241 @@ static int dc2114x_autoconf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; - s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts; - int next_tick = DE4X5_AUTOSENSE_MS; - - switch (lp->media) { - case INIT: - if (lp->timeout < 0) { - DISABLE_IRQs; - lp->tx_enable = FALSE; - lp->linkOK = 0; - lp->timeout = -1; - de4x5_save_skbs(dev); /* Save non transmitted skb's */ - } - if ((next_tick = de4x5_reset_phy(dev)) < 0) { - next_tick &= ~TIMER_CB; - } else { - lp->media = SPD_DET; - if ((lp->infoblock_media == ANS) && - ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { - ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); - ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM); - mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - lp->media = ANS; - } - lp->local_state = 0; - next_tick = dc2114x_autoconf(dev); - } - break; - - case ANS: - switch (lp->local_state) { - case 0: - if (lp->timeout < 0) { - mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); - } - cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500); - if (cr < 0) { - next_tick = cr & ~TIMER_CB; - } else { - if (cr) { - lp->local_state = 0; - lp->media = SPD_DET; - } else { - lp->local_state++; - } - next_tick = dc2114x_autoconf(dev); - } - break; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts; + int next_tick = DE4X5_AUTOSENSE_MS; + + switch (lp->media) { + case INIT: + if (lp->timeout < 0) { + DISABLE_IRQs; + lp->tx_enable = FALSE; + lp->linkOK = 0; + lp->timeout = -1; + de4x5_save_skbs(dev); /* Save non transmitted skb's */ + } + if ((next_tick = de4x5_reset_phy(dev)) < 0) { + next_tick &= ~TIMER_CB; + } else { + lp->media = SPD_DET; + if ((lp->infoblock_media == ANS) && + ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { + ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); + ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM); + mii_wr(ana, MII_ANA, + lp->phy[lp->active].addr, + DE4X5_MII); + lp->media = ANS; + } + lp->local_state = 0; + next_tick = dc2114x_autoconf(dev); + } + break; + + case ANS: + switch (lp->local_state) { + case 0: + if (lp->timeout < 0) { + mii_wr(MII_CR_ASSE | MII_CR_RAN, + MII_CR, lp->phy[lp->active].addr, DE4X5_MII); + } + cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500); + if (cr < 0) { + next_tick = cr & ~TIMER_CB; + } else { + if (cr) { + lp->local_state = 0; + lp->media = SPD_DET; + } else { + lp->local_state++; + } + next_tick = dc2114x_autoconf(dev); + } + break; - case 1: - if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { - next_tick = sr & ~TIMER_CB; - } else { - lp->media = SPD_DET; - lp->local_state = 0; - if (sr) { /* Success! */ - lp->tmp = MII_SR_ASSC; - anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII); - ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - if (!(anlpa & MII_ANLPA_RF) && - (cap = anlpa & MII_ANLPA_TAF & ana)) { - if (cap & MII_ANA_100M) { - lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); - lp->media = _100Mb; - } else if (cap & MII_ANA_10M) { - lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); - lp->media = _10Mb; - } - } - } /* Auto Negotiation failed to finish */ - next_tick = dc2114x_autoconf(dev); - } /* Auto Negotiation failed to start */ - break; - } - break; + case 1: + if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { + next_tick = sr & ~TIMER_CB; + } else { + lp->media = SPD_DET; + lp->local_state = 0; + if (sr) { /* Success! */ + lp->tmp = MII_SR_ASSC; + anlpa = mii_rd(MII_ANLPA, + lp->phy[lp->active].addr, + DE4X5_MII); + ana = mii_rd(MII_ANA, + lp->phy[lp->active].addr, + DE4X5_MII); + if (!(anlpa & MII_ANLPA_RF) && + (cap = anlpa & MII_ANLPA_TAF & ana)) { + if (cap & MII_ANA_100M) { + lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); + lp->media = _100Mb; + } else if (cap & MII_ANA_10M) { + lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); + lp->media = _10Mb; + } + } + } /* Auto Negotiation failed to finish */ + next_tick = dc2114x_autoconf(dev); + } /* Auto Negotiation failed to start */ + break; + } + break; - case AUI: - if (!lp->tx_enable) { - if (lp->timeout < 0) { - omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ - outl(omr & ~OMR_FDX, DE4X5_OMR); - } - irqs = 0; - irq_mask = 0; - sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) { - lp->media = BNC; - next_tick = dc2114x_autoconf(dev); - } else { - lp->local_state = 1; - de4x5_init_connection(dev); - } - } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = AUI_SUSPECT; - next_tick = 3000; - } - break; + case AUI: + if (!lp->tx_enable) { + if (lp->timeout < 0) { + omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ + outl(omr & ~OMR_FDX, DE4X5_OMR); + } + irqs = 0; + irq_mask = 0; + sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; + } else { + if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) { + lp->media = BNC; + next_tick = dc2114x_autoconf(dev); + } else { + lp->local_state = 1; + de4x5_init_connection(dev); + } + } + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = AUI_SUSPECT; + next_tick = 3000; + } + break; - case AUI_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf); - break; + case AUI_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, AUI, + ping_media, dc2114x_autoconf); + break; - case BNC: - switch (lp->local_state) { - case 0: - if (lp->timeout < 0) { - omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ - outl(omr & ~OMR_FDX, DE4X5_OMR); - } - irqs = 0; - irq_mask = 0; - sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000); - if (sts < 0) { - next_tick = sts & ~TIMER_CB; - } else { - lp->local_state++; /* Ensure media connected */ - next_tick = dc2114x_autoconf(dev); - } - break; + case BNC: + switch (lp->local_state) { + case 0: + if (lp->timeout < 0) { + omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ + outl(omr & ~OMR_FDX, DE4X5_OMR); + } + irqs = 0; + irq_mask = 0; + sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000); + if (sts < 0) { + next_tick = sts & ~TIMER_CB; + } else { + lp->local_state++; /* Ensure media connected */ + next_tick = dc2114x_autoconf(dev); + } + break; - case 1: - if (!lp->tx_enable) { - if ((sts = ping_media(dev, 3000)) < 0) { - next_tick = sts & ~TIMER_CB; + case 1: + if (!lp->tx_enable) { + if ((sts = ping_media(dev, 3000)) < 0) { + next_tick = sts & ~TIMER_CB; + } else { + if (sts) { + lp->local_state = 0; + lp->tcount++; + lp->media = INIT; + } else { + de4x5_init_connection(dev); + } + } + } else if (!lp->linkOK && (lp->autosense == AUTO)) { + lp->media = BNC_SUSPECT; + next_tick = 3000; + } + break; + } + break; + + case BNC_SUSPECT: + next_tick = de4x5_suspect_state(dev, 1000, BNC, + ping_media, dc2114x_autoconf); + break; + + case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ + if (srom_map_media(dev) < 0) { + lp->tcount++; + lp->media = INIT; + return next_tick; + } + if (lp->media == _100Mb) { + if ((slnk = test_for_100Mb(dev, 6500)) < 0) { + lp->media = SPD_DET; + return (slnk & ~TIMER_CB); + } + } else { + if (wait_for_link(dev) < 0) { + lp->media = SPD_DET; + return PDET_LINK_WAIT; + } + } + if (((lp->media == _100Mb) && is_100_up(dev)) || + ((lp->media == _10Mb) && is_10_up(dev)) || + (lp->media == BNC) || (lp->media == AUI)) { + next_tick = dc2114x_autoconf(dev); } else { - if (sts) { - lp->local_state = 0; lp->tcount++; lp->media = INIT; - } else { + } + break; + + case _10Mb: + next_tick = 3000; + if (!lp->tx_enable) { + SET_10Mb; de4x5_init_connection(dev); - } + } else { + if (!lp->linkOK && (lp->autosense == AUTO)) { + if (!is_10_up(dev) || + (!lp->useSROM && is_spd_100(dev))) { + lp->media = INIT; + lp->tcount++; + next_tick = DE4X5_AUTOSENSE_MS; + } + } } - } else if (!lp->linkOK && (lp->autosense == AUTO)) { - lp->media = BNC_SUSPECT; + break; + + case _100Mb: next_tick = 3000; - } - break; + if (!lp->tx_enable) { + SET_100Mb; + de4x5_init_connection(dev); + } else { + if (!lp->linkOK && (lp->autosense == AUTO)) { + if (!is_100_up(dev) || + (!lp->useSROM && !is_spd_100(dev))) { + lp->media = INIT; + lp->tcount++; + next_tick = DE4X5_AUTOSENSE_MS; + } + } + } + break; + + default: + lp->tcount++; + printk("Huh?: media:%02x\n", lp->media); + lp->media = INIT; + break; } - break; - - case BNC_SUSPECT: - next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf); - break; - - case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ - if (srom_map_media(dev) < 0) { - lp->tcount++; - lp->media = INIT; - return next_tick; - } - if (lp->media == _100Mb) { - if ((slnk = test_for_100Mb(dev, 6500)) < 0) { - lp->media = SPD_DET; - return (slnk & ~TIMER_CB); - } - } else { - if (wait_for_link(dev) < 0) { - lp->media = SPD_DET; - return PDET_LINK_WAIT; - } - } - if (((lp->media == _100Mb) && is_100_up(dev)) || - ((lp->media == _10Mb) && is_10_up(dev)) || - (lp->media == BNC) || (lp->media == AUI)) { - next_tick = dc2114x_autoconf(dev); - } else { - lp->tcount++; - lp->media = INIT; - } - break; - - case _10Mb: - next_tick = 3000; - if (!lp->tx_enable) { - SET_10Mb; - de4x5_init_connection(dev); - } else { - if (!lp->linkOK && (lp->autosense == AUTO)) { - if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) { - lp->media = INIT; - lp->tcount++; - next_tick = DE4X5_AUTOSENSE_MS; - } - } - } - break; - - case _100Mb: - next_tick = 3000; - if (!lp->tx_enable) { - SET_100Mb; - de4x5_init_connection(dev); - } else { - if (!lp->linkOK && (lp->autosense == AUTO)) { - if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) { - lp->media = INIT; - lp->tcount++; - next_tick = DE4X5_AUTOSENSE_MS; - } - } - } - break; - - default: - lp->tcount++; -printk("Huh?: media:%02x\n", lp->media); - lp->media = INIT; - break; - } - return next_tick; + return next_tick; } -static int -srom_autoconf(struct device *dev) +static int srom_autoconf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - return lp->infoleaf_fn(dev); + return lp->infoleaf_fn(dev); } /* @@ -3027,91 +3074,95 @@ ** While it isn't strictly necessary, it helps me for the moment... ** The early return avoids a media state / SROM media space clash. */ -static int -srom_map_media(struct device *dev) +static int srom_map_media(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - lp->fdx = 0; - if (lp->infoblock_media == lp->media) - return 0; - - switch(lp->infoblock_media) { - case SROM_10BASETF: - if (!de4x5_full_duplex) return -1; - lp->fdx = TRUE; - case SROM_10BASET: - if (de4x5_full_duplex && !lp->fdx) return -1; - if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) { - lp->media = _10Mb; - } else { - lp->media = TP; + lp->fdx = 0; + if (lp->infoblock_media == lp->media) + return 0; + + switch(lp->infoblock_media) { + case SROM_10BASETF: + if (!de4x5_full_duplex) + return -1; + lp->fdx = TRUE; + case SROM_10BASET: + if (de4x5_full_duplex && !lp->fdx) + return -1; + if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) { + lp->media = _10Mb; + } else { + lp->media = TP; + } + break; + + case SROM_10BASE2: + lp->media = BNC; + break; + + case SROM_10BASE5: + lp->media = AUI; + break; + + case SROM_100BASETF: + if (!de4x5_full_duplex) + return -1; + lp->fdx = TRUE; + case SROM_100BASET: + if (de4x5_full_duplex && !lp->fdx) + return -1; + lp->media = _100Mb; + break; + + case SROM_100BASET4: + lp->media = _100Mb; + break; + + case SROM_100BASEFF: + if (!de4x5_full_duplex) + return -1; + lp->fdx = TRUE; + case SROM_100BASEF: + if (de4x5_full_duplex && !lp->fdx) + return -1; + lp->media = _100Mb; + break; + + case ANS: + lp->media = ANS; + break; + + default: + printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, + lp->infoblock_media); + return -1; + break; } - break; - case SROM_10BASE2: - lp->media = BNC; - break; - - case SROM_10BASE5: - lp->media = AUI; - break; - - case SROM_100BASETF: - if (!de4x5_full_duplex) return -1; - lp->fdx = TRUE; - case SROM_100BASET: - if (de4x5_full_duplex && !lp->fdx) return -1; - lp->media = _100Mb; - break; - - case SROM_100BASET4: - lp->media = _100Mb; - break; - - case SROM_100BASEFF: - if (!de4x5_full_duplex) return -1; - lp->fdx = TRUE; - case SROM_100BASEF: - if (de4x5_full_duplex && !lp->fdx) return -1; - lp->media = _100Mb; - break; - - case ANS: - lp->media = ANS; - break; - - default: - printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, - lp->infoblock_media); - return -1; - break; - } - - return 0; -} - -static void -de4x5_init_connection(struct device *dev) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; /* Stop scrolling media messages */ - } - - cli(); - de4x5_restore_skbs(dev); - de4x5_setup_intr(dev); - lp->tx_enable = YES; - dev->tbusy = 0; - sti(); - outl(POLL_DEMAND, DE4X5_TPD); - mark_bh(NET_BH); + return 0; +} + +static void de4x5_init_connection(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; /* Stop scrolling media messages */ + } + + cli(); + de4x5_restore_skbs(dev); + de4x5_setup_intr(dev); + lp->tx_enable = YES; + dev->tbusy = 0; + sti(); + outl(POLL_DEMAND, DE4X5_TPD); + mark_bh(NET_BH); - return; + return; } /* @@ -3119,98 +3170,94 @@ ** since their MII address pins can float at voltages that are dependent ** on the signal pin use. Do a double reset to ensure a reset. */ -static int -de4x5_reset_phy(struct device *dev) +static int de4x5_reset_phy(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int next_tick = 0; - - if ((lp->useSROM) || (lp->phy[lp->active].id)) { - if (lp->timeout < 0) { - if (lp->useSROM) { - if (lp->phy[lp->active].rst) { - srom_exec(dev, lp->phy[lp->active].rst); - srom_exec(dev, lp->phy[lp->active].rst); - } else if (lp->rst) { /* Type 5 infoblock reset */ - srom_exec(dev, lp->rst); - srom_exec(dev, lp->rst); + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; + int next_tick = 0; + + if ((lp->useSROM) || (lp->phy[lp->active].id)) { + if (lp->timeout < 0) { + if (lp->useSROM) { + if (lp->phy[lp->active].rst) { + srom_exec(dev, lp->phy[lp->active].rst); + srom_exec(dev, lp->phy[lp->active].rst); + } else if (lp->rst) { /* Type 5 infoblock reset */ + srom_exec(dev, lp->rst); + srom_exec(dev, lp->rst); + } + } else { + PHY_HARD_RESET; + } + if (lp->useMII) { + mii_wr(MII_CR_RST, MII_CR, + lp->phy[lp->active].addr, DE4X5_MII); + } + } + if (lp->useMII) { + next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500); } - } else { + } else if (lp->chipset == DC21140) { PHY_HARD_RESET; - } - if (lp->useMII) { - mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); - } - } - if (lp->useMII) { - next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500); } - } else if (lp->chipset == DC21140) { - PHY_HARD_RESET; - } - return next_tick; + return next_tick; } -static int -test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec) +static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - s32 sts, csr12; - - if (lp->timeout < 0) { - lp->timeout = msec/100; - if (!lp->useSROM) { /* Already done if by SROM, else dc2104[01] */ - reset_init_sia(dev, csr13, csr14, csr15); + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 sts, csr12; + + if (lp->timeout < 0) { + lp->timeout = msec / 100; + if (!lp->useSROM) { /* Already done if by SROM, else dc2104[01] */ + reset_init_sia(dev, csr13, csr14, csr15); + } + + /* set up the interrupt mask */ + outl(irq_mask, DE4X5_IMR); + + /* clear all pending interrupts */ + sts = inl(DE4X5_STS); + outl(sts, DE4X5_STS); + + /* clear csr12 NRA and SRA bits */ + if ((lp->chipset == DC21041) || lp->useSROM) { + csr12 = inl(DE4X5_SISR); + outl(csr12, DE4X5_SISR); + } } + sts = inl(DE4X5_STS) & ~TIMER_CB; - /* set up the interrupt mask */ - outl(irq_mask, DE4X5_IMR); - - /* clear all pending interrupts */ - sts = inl(DE4X5_STS); - outl(sts, DE4X5_STS); - - /* clear csr12 NRA and SRA bits */ - if ((lp->chipset == DC21041) || lp->useSROM) { - csr12 = inl(DE4X5_SISR); - outl(csr12, DE4X5_SISR); + if (!(sts & irqs) && --lp->timeout) { + sts = 100 | TIMER_CB; + } else { + lp->timeout = -1; } - } - - sts = inl(DE4X5_STS) & ~TIMER_CB; - - if (!(sts & irqs) && --lp->timeout) { - sts = 100 | TIMER_CB; - } else { - lp->timeout = -1; - } - - return sts; + + return sts; } -static int -test_tp(struct device *dev, s32 msec) +static int test_tp(struct device *dev, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int sisr; - - if (lp->timeout < 0) { - lp->timeout = msec/100; - } - - sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR); + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int sisr; - if (sisr && --lp->timeout) { - sisr = 100 | TIMER_CB; - } else { - lp->timeout = -1; - } - - return sisr; + if (lp->timeout < 0) { + lp->timeout = msec / 100; + } + sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR); + + if (sisr && --lp->timeout) { + sisr = 100 | TIMER_CB; + } else { + lp->timeout = -1; + } + + return sisr; } /* @@ -3220,203 +3267,195 @@ */ #define SAMPLE_INTERVAL 500 /* ms */ #define SAMPLE_DELAY 2000 /* ms */ -static int -test_for_100Mb(struct device *dev, int msec) +static int test_for_100Mb(struct device *dev, int msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK); + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK); - if (lp->timeout < 0) { - if ((msec/SAMPLE_INTERVAL) <= 0) return 0; - if (msec > SAMPLE_DELAY) { - lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL; - gep = SAMPLE_DELAY | TIMER_CB; - return gep; + if (lp->timeout < 0) { + if ((msec/SAMPLE_INTERVAL) <= 0) + return 0; + if (msec > SAMPLE_DELAY) { + lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL; + gep = SAMPLE_DELAY | TIMER_CB; + return gep; + } else { + lp->timeout = msec/SAMPLE_INTERVAL; + } + } + if (lp->phy[lp->active].id || lp->useSROM) { + gep = is_100_up(dev) | is_spd_100(dev); } else { - lp->timeout = msec/SAMPLE_INTERVAL; + gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP)); } - } - - if (lp->phy[lp->active].id || lp->useSROM) { - gep = is_100_up(dev) | is_spd_100(dev); - } else { - gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP)); - } - if (!(gep & ret) && --lp->timeout) { - gep = SAMPLE_INTERVAL | TIMER_CB; - } else { - lp->timeout = -1; - } - - return gep; + if (!(gep & ret) && --lp->timeout) { + gep = SAMPLE_INTERVAL | TIMER_CB; + } else { + lp->timeout = -1; + } + + return gep; } -static int -wait_for_link(struct device *dev) +static int wait_for_link(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - if (lp->timeout < 0) { - lp->timeout = 1; - } + if (lp->timeout < 0) { + lp->timeout = 1; + } - if (lp->timeout--) { - return TIMER_CB; - } else { - lp->timeout = -1; - } + if (lp->timeout--) { + return TIMER_CB; + } else { + lp->timeout = -1; + } - return 0; + return 0; } /* ** ** */ -static int -test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec) +static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int test, iobase = dev->base_addr; - - if (lp->timeout < 0) { - lp->timeout = msec/100; - } - - if (pol) pol = ~0; - reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask; - test = (reg ^ pol) & mask; - - if (test && --lp->timeout) { - reg = 100 | TIMER_CB; - } else { - lp->timeout = -1; - } - - return reg; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int test; + u_long iobase = dev->base_addr; + + if (lp->timeout < 0) { + lp->timeout = msec / 100; + } + if (pol) + pol = ~0; + reg = mii_rd((u_char) reg, lp->phy[lp->active].addr, DE4X5_MII) & mask; + test = (reg ^ pol) & mask; + + if (test && --lp->timeout) { + reg = 100 | TIMER_CB; + } else { + lp->timeout = -1; + } + + return reg; } -static int -is_spd_100(struct device *dev) +static int is_spd_100(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int spd; - - if (lp->useMII) { - spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII); - spd = ~(spd ^ lp->phy[lp->active].spd.value); - spd &= lp->phy[lp->active].spd.mask; - } else if (!lp->useSROM) { /* de500-xa */ - spd = ((~gep_rd(dev)) & GEP_SLNK); - } else { - if ((lp->ibn == 2) || !lp->asBitValid) - return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0); - - spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) | - (lp->linkOK & ~lp->asBitValid); - } - - return spd; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int spd; + + if (lp->useMII) { + spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII); + spd = ~(spd ^ lp->phy[lp->active].spd.value); + spd &= lp->phy[lp->active].spd.mask; + } else if (!lp->useSROM) { /* de500-xa */ + spd = ((~gep_rd(dev)) & GEP_SLNK); + } else { + if ((lp->ibn == 2) || !lp->asBitValid) + return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0); + + spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) | + (lp->linkOK & ~lp->asBitValid); + } + + return spd; } -static int -is_100_up(struct device *dev) +static int is_100_up(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - - if (lp->useMII) { - /* Double read for sticky bits & temporary drops */ - mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII); - return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS); - } else if (!lp->useSROM) { /* de500-xa */ - return ((~gep_rd(dev)) & GEP_SLNK); - } else { - if ((lp->ibn == 2) || !lp->asBitValid) - return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0); - - return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) | - (lp->linkOK & ~lp->asBitValid)); - } + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + + if (lp->useMII) { + /* Double read for sticky bits & temporary drops */ + mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII); + return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS); + } else if (!lp->useSROM) { /* de500-xa */ + return ((~gep_rd(dev)) & GEP_SLNK); + } else { + if ((lp->ibn == 2) || !lp->asBitValid) + return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0); + + return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) | + (lp->linkOK & ~lp->asBitValid)); + } } -static int -is_10_up(struct device *dev) +static int is_10_up(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - - if (lp->useMII) { - /* Double read for sticky bits & temporary drops */ - mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII); - return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS); - } else if (!lp->useSROM) { /* de500-xa */ - return ((~gep_rd(dev)) & GEP_LNP); - } else { - if ((lp->ibn == 2) || !lp->asBitValid) - return (((lp->chipset & ~0x00ff) == DC2114x) ? - (~inl(DE4X5_SISR)&SISR_LS10): - 0); - - return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) | - (lp->linkOK & ~lp->asBitValid)); - } + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + + if (lp->useMII) { + /* Double read for sticky bits & temporary drops */ + mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII); + return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS); + } else if (!lp->useSROM) { /* de500-xa */ + return ((~gep_rd(dev)) & GEP_LNP); + } else { + if ((lp->ibn == 2) || !lp->asBitValid) + return (((lp->chipset & ~0x00ff) == DC2114x) ? + (~inl(DE4X5_SISR)&SISR_LS10): + 0); + + return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) | + (lp->linkOK & ~lp->asBitValid)); + } } -static int -is_anc_capable(struct device *dev) +static int is_anc_capable(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - - if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { - return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII)); - } else if ((lp->chipset & ~0x00ff) == DC2114x) { - return (inl(DE4X5_SISR) & SISR_LPN) >> 11; - } else { - return 0; - } + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + + if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { + return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII)); + } else if ((lp->chipset & ~0x00ff) == DC2114x) { + return (inl(DE4X5_SISR) & SISR_LPN) >> 11; + } else { + return 0; + } } /* ** Send a packet onto the media and watch for send errors that indicate the ** media is bad or unconnected. */ -static int -ping_media(struct device *dev, int msec) +static int ping_media(struct device *dev, int msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int sisr; - - if (lp->timeout < 0) { - lp->timeout = msec/100; - - lp->tmp = lp->tx_new; /* Remember the ring position */ - load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL); - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - outl(POLL_DEMAND, DE4X5_TPD); - } - - sisr = inl(DE4X5_SISR); + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int sisr; - if ((!(sisr & SISR_NCR)) && - ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && - (--lp->timeout)) { - sisr = 100 | TIMER_CB; - } else { - if ((!(sisr & SISR_NCR)) && - !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) && - lp->timeout) { - sisr = 0; - } else { - sisr = 1; + if (lp->timeout < 0) { + lp->timeout = msec / 100; + + lp->tmp = lp->tx_new; /* Remember the ring position */ + load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL); + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + outl(POLL_DEMAND, DE4X5_TPD); + } + sisr = inl(DE4X5_SISR); + + if ((!(sisr & SISR_NCR)) && + ((s32) le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && + (--lp->timeout)) { + sisr = 100 | TIMER_CB; + } else { + if ((!(sisr & SISR_NCR)) && + !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) && + lp->timeout) { + sisr = 0; + } else { + sisr = 1; + } + lp->timeout = -1; } - lp->timeout = -1; - } - - return sisr; + + return sisr; } /* @@ -3424,94 +3463,93 @@ ** replace the one about to be passed up. On Alpha's it kmallocs a buffer ** into which the packet is copied. */ -static struct sk_buff * -de4x5_alloc_rx_buff(struct device *dev, int index, int len) +static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - struct sk_buff *p; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct sk_buff *p; -#if !defined(__alpha__) && !defined(__powerpc__) && !defined(DE4X5_DO_MEMCPY) - struct sk_buff *ret; - u_long i=0, tmp; +#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) + struct sk_buff *ret; + u_long i = 0, tmp; - p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2); - if (!p) return NULL; + p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2); + if (!p) + return NULL; - p->dev = dev; - tmp = virt_to_bus(p->data); - i = ((tmp + ALIGN) & ~ALIGN) - tmp; - skb_reserve(p, i); - lp->rx_ring[index].buf = tmp + i; + p->dev = dev; + tmp = virt_to_bus(p->data); + i = ((tmp + ALIGN) & ~ALIGN) - tmp; + skb_reserve(p, i); + lp->rx_ring[index].buf = tmp + i; - ret = lp->rx_skb[index]; - lp->rx_skb[index] = p; + ret = lp->rx_skb[index]; + lp->rx_skb[index] = p; - if ((u_long) ret > 1) { - skb_put(ret, len); - } - - return ret; + if ((u_long) ret > 1) { + skb_put(ret, len); + } + return ret; #else - if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */ + if (lp->state != OPEN) + return (struct sk_buff *) 1; /* Fake out the open */ - p = dev_alloc_skb(len + 2); - if (!p) return NULL; + p = dev_alloc_skb(len + 2); + if (!p) + return NULL; + + p->dev = dev; + skb_reserve(p, 2); /* Align */ + if (index < lp->rx_old) { /* Wrapped buffer */ + short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; + memcpy(skb_put(p, tlen), + bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)), tlen); + memcpy(skb_put(p, len - tlen), + bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len - tlen); + } else { /* Linear buffer */ + memcpy(skb_put(p, len), + bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)), len); + } - p->dev = dev; - skb_reserve(p, 2); /* Align */ - if (index < lp->rx_old) { /* Wrapped buffer */ - short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; - memcpy(skb_put(p,tlen), - bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),tlen); - memcpy(skb_put(p,len-tlen), - bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len-tlen); - } else { /* Linear buffer */ - memcpy(skb_put(p,len), - bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),len); - } - - return p; + return p; #endif } -static void -de4x5_free_rx_buffs(struct device *dev) +static void de4x5_free_rx_buffs(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int i; - for (i=0; irxRingSize; i++) { - if ((u_long) lp->rx_skb[i] > 1) { - dev_kfree_skb(lp->rx_skb[i], FREE_WRITE); + for (i = 0; i < lp->rxRingSize; i++) { + if ((u_long) lp->rx_skb[i] > 1) { + dev_kfree_skb(lp->rx_skb[i], FREE_WRITE); + } + lp->rx_ring[i].status = 0; + lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ } - lp->rx_ring[i].status = 0; - lp->rx_skb[i] = (struct sk_buff *)1; /* Dummy entry */ - } - return; + return; } -static void -de4x5_free_tx_buffs(struct device *dev) +static void de4x5_free_tx_buffs(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int i; - for (i=0; itxRingSize; i++) { - if (lp->tx_skb[i]) { - dev_kfree_skb(lp->tx_skb[i], FREE_WRITE); - lp->tx_skb[i] = NULL; + for (i = 0; i < lp->txRingSize; i++) { + if (lp->tx_skb[i]) { + dev_kfree_skb(lp->tx_skb[i], FREE_WRITE); + lp->tx_skb[i] = NULL; + } + lp->tx_ring[i].status = 0; } - lp->tx_ring[i].status = 0; - } - /* Unload the locally queued packets */ - while (lp->cache.skb) { - dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE); - } + /* Unload the locally queued packets */ + while (lp->cache.skb) { + dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE); + } - return; + return; } /* @@ -3521,340 +3559,321 @@ ** the hardware and software and make any media probes using a loopback ** packet meaningful. */ -static void -de4x5_save_skbs(struct device *dev) +static void de4x5_save_skbs(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - s32 omr; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 omr; + + if (!lp->cache.save_cnt) { + STOP_DE4X5; + de4x5_tx(dev); /* Flush any sent skb's */ + de4x5_free_tx_buffs(dev); + de4x5_cache_state(dev, DE4X5_SAVE_STATE); + de4x5_sw_reset(dev); + de4x5_cache_state(dev, DE4X5_RESTORE_STATE); + lp->cache.save_cnt++; + START_DE4X5; + } + return; +} - if (!lp->cache.save_cnt) { - STOP_DE4X5; - de4x5_tx(dev); /* Flush any sent skb's */ - de4x5_free_tx_buffs(dev); - de4x5_cache_state(dev, DE4X5_SAVE_STATE); - de4x5_sw_reset(dev); - de4x5_cache_state(dev, DE4X5_RESTORE_STATE); - lp->cache.save_cnt++; - START_DE4X5; - } +static void de4x5_restore_skbs(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int i; + s32 omr; + + if (lp->cache.save_cnt) { + STOP_DE4X5; + outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); + outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + + lp->rx_new = lp->rx_old = 0; + lp->tx_new = lp->tx_old = 0; - return; + for (i = 0; i < lp->rxRingSize; i++) { + lp->rx_ring[i].status = cpu_to_le32(R_OWN); + } + + for (i = 0; i < lp->txRingSize; i++) { + lp->tx_ring[i].status = cpu_to_le32(0); + } + + barrier(); + lp->cache.save_cnt--; + START_DE4X5; + } + return; } -static void -de4x5_restore_skbs(struct device *dev) +static void de4x5_cache_state(struct device *dev, int flag) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - int i; - s32 omr; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; - if (lp->cache.save_cnt) { - STOP_DE4X5; - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - - lp->rx_new = lp->rx_old = 0; - lp->tx_new = lp->tx_old = 0; - - for (i = 0; i < lp->rxRingSize; i++) { - lp->rx_ring[i].status = cpu_to_le32(R_OWN); - } - - for (i = 0; i < lp->txRingSize; i++) { - lp->tx_ring[i].status = cpu_to_le32(0); - } - - barrier(); - lp->cache.save_cnt--; - START_DE4X5; - } - - return; -} - -static void -de4x5_cache_state(struct device *dev, int flag) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - - switch(flag) { - case DE4X5_SAVE_STATE: - lp->cache.csr0 = inl(DE4X5_BMR); - lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR)); - lp->cache.csr7 = inl(DE4X5_IMR); - break; - - case DE4X5_RESTORE_STATE: - outl(lp->cache.csr0, DE4X5_BMR); - outl(lp->cache.csr6, DE4X5_OMR); - outl(lp->cache.csr7, DE4X5_IMR); - if (lp->chipset == DC21140) { + switch (flag) { + case DE4X5_SAVE_STATE: + lp->cache.csr0 = inl(DE4X5_BMR); + lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR)); + lp->cache.csr7 = inl(DE4X5_IMR); + break; + + case DE4X5_RESTORE_STATE: + outl(lp->cache.csr0, DE4X5_BMR); + outl(lp->cache.csr6, DE4X5_OMR); + outl(lp->cache.csr7, DE4X5_IMR); + if (lp->chipset == DC21140) { gep_wr(lp->cache.gepc, dev); gep_wr(lp->cache.gep, dev); - } else { - reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, - lp->cache.csr15); + } else { + reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, + lp->cache.csr15); + } + break; } - break; - } - return; + return; } -static void -de4x5_put_cache(struct device *dev, struct sk_buff *skb) +static void de4x5_put_cache(struct device *dev, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - struct sk_buff *p; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct sk_buff *p; - if (lp->cache.skb) { - for (p=lp->cache.skb; p->next; p=p->next); - p->next = skb; - } else { - lp->cache.skb = skb; - } - skb->next = NULL; + if (lp->cache.skb) { + for (p = lp->cache.skb; p->next; p = p->next); + p->next = skb; + } else { + lp->cache.skb = skb; + } + skb->next = NULL; - return; + return; } -static void -de4x5_putb_cache(struct device *dev, struct sk_buff *skb) +static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - struct sk_buff *p = lp->cache.skb; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct sk_buff *p = lp->cache.skb; - lp->cache.skb = skb; - skb->next = p; + lp->cache.skb = skb; + skb->next = p; - return; + return; } -static struct sk_buff * -de4x5_get_cache(struct device *dev) +static struct sk_buff *de4x5_get_cache(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - struct sk_buff *p = lp->cache.skb; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct sk_buff *p = lp->cache.skb; - if (p) { - lp->cache.skb = p->next; - p->next = NULL; - } - - return p; + if (p) { + lp->cache.skb = p->next; + p->next = NULL; + } + return p; } /* ** Check the Auto Negotiation State. Return OK when a link pass interrupt ** is received and the auto-negotiation status is NWAY OK. */ -static int -test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec) +static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - s32 sts, ans; - - if (lp->timeout < 0) { - lp->timeout = msec/100; - outl(irq_mask, DE4X5_IMR); - - /* clear all pending interrupts */ - sts = inl(DE4X5_STS); - outl(sts, DE4X5_STS); - } - - ans = inl(DE4X5_SISR) & SISR_ANS; - sts = inl(DE4X5_STS) & ~TIMER_CB; - - if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) { - sts = 100 | TIMER_CB; - } else { - lp->timeout = -1; - } - - return sts; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 sts, ans; + + if (lp->timeout < 0) { + lp->timeout = msec / 100; + outl(irq_mask, DE4X5_IMR); + + /* clear all pending interrupts */ + sts = inl(DE4X5_STS); + outl(sts, DE4X5_STS); + } + ans = inl(DE4X5_SISR) & SISR_ANS; + sts = inl(DE4X5_STS) & ~TIMER_CB; + + if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) { + sts = 100 | TIMER_CB; + } else { + lp->timeout = -1; + } + + return sts; } -static void -de4x5_setup_intr(struct device *dev) +static void de4x5_setup_intr(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - s32 imr, sts; - - if (inl(DE4X5_OMR) & OMR_SR) { /* Only unmask if TX/RX is enabled */ - imr = 0; - UNMASK_IRQs; - sts = inl(DE4X5_STS); /* Reset any pending (stale) interrupts */ - outl(sts, DE4X5_STS); - ENABLE_IRQs; - } - - return; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 imr, sts; + + if (inl(DE4X5_OMR) & OMR_SR) { /* Only unmask if TX/RX is enabled */ + imr = 0; + UNMASK_IRQs; + sts = inl(DE4X5_STS); /* Reset any pending (stale) interrupts */ + outl(sts, DE4X5_STS); + ENABLE_IRQs; + } + return; } /* ** */ -static void -reset_init_sia(struct device *dev, s32 csr13, s32 csr14, s32 csr15) +void reset_init_sia(struct device *dev, s32 csr13, s32 csr14, s32 csr15) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; - RESET_SIA; - if (lp->useSROM) { - if (lp->ibn == 3) { - srom_exec(dev, lp->phy[lp->active].rst); - srom_exec(dev, lp->phy[lp->active].gep); - outl(1, DE4X5_SICR); - return; + RESET_SIA; + if (lp->useSROM) { + if (lp->ibn == 3) { + srom_exec(dev, lp->phy[lp->active].rst); + srom_exec(dev, lp->phy[lp->active].gep); + outl(1, DE4X5_SICR); + return; + } else { + csr15 = lp->cache.csr15; + csr14 = lp->cache.csr14; + csr13 = lp->cache.csr13; + outl(csr15 | lp->cache.gepc, DE4X5_SIGR); + outl(csr15 | lp->cache.gep, DE4X5_SIGR); + } } else { - csr15 = lp->cache.csr15; - csr14 = lp->cache.csr14; - csr13 = lp->cache.csr13; - outl(csr15 | lp->cache.gepc, DE4X5_SIGR); - outl(csr15 | lp->cache.gep, DE4X5_SIGR); - } - } else { - outl(csr15, DE4X5_SIGR); - } - outl(csr14, DE4X5_STRR); - outl(csr13, DE4X5_SICR); + outl(csr15, DE4X5_SIGR); + } + outl(csr14, DE4X5_STRR); + outl(csr13, DE4X5_SICR); - de4x5_ms_delay(10); + de4x5_ms_delay(10); - return; + return; } /* ** Create a loopback ethernet packet */ -static void -create_packet(struct device *dev, char *frame, int len) +static void create_packet(struct device *dev, char *frame, int len) { - int i; - char *buf = frame; - - for (i=0; idev_addr[i]; - } - for (i=0; idev_addr[i]; - } - - *buf++ = 0; /* Packet length (2 bytes) */ - *buf++ = 1; - - return; + int i; + char *buf = frame; + + for (i = 0; i < ETH_ALEN; i++) { /* Use this source address */ + *buf++ = dev->dev_addr[i]; + } + for (i = 0; i < ETH_ALEN; i++) { /* Use this destination address */ + *buf++ = dev->dev_addr[i]; + } + + *buf++ = 0; /* Packet length (2 bytes) */ + *buf++ = 1; + + return; } /* ** Known delay in microseconds */ -static void -de4x5_us_delay(u32 usec) +static void de4x5_us_delay(u32 usec) { - udelay(usec); - - return; + udelay(usec); + + return; } /* ** Known delay in milliseconds, in millisecond steps. */ -static void -de4x5_ms_delay(u32 msec) +static void de4x5_ms_delay(u32 msec) { - u_int i; - - for (i=0; i>2)&0x1f)+0x40); - ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40); - ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30); - ManCode[3]=((Eisa.Id[2]&0x0f)+0x30); - ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30); - ManCode[5]='\0'; - - for (i=0;i> 2) & 0x1f) + 0x40); + ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40); + ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30); + ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30); + ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30); + ManCode[5] = '\0'; + + for (i = 0; i < siglen; i++) { + if (strstr(ManCode, signatures[i]) != NULL) { + strcpy(name, ManCode); + status = 1; + break; + } } - } - - return status; /* return the device name string */ + + return status; /* return the device name string */ } /* ** Look for a particular board name in the PCI configuration space */ -static int -PCI_signature(char *name, struct bus_type *lp) +static int PCI_signature(char *name, struct bus_type *lp) { - c_char *de4x5_signatures[] = DE4X5_SIGNATURE; - int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); - - if (lp->chipset == DC21040) { - strcpy(name, "DE434/5"); - return status; - } else { /* Search for a DEC name in the SROM */ - int i = *((char *)&lp->srom + 19) * 3; - strncpy(name, (char *)&lp->srom + 26 + i, 8); - } - name[8] = '\0'; - for (i=0; ichipset == DC21040) ? "DC21040" : - ((lp->chipset == DC21041) ? "DC21041" : - ((lp->chipset == DC21140) ? "DC21140" : - ((lp->chipset == DC21142) ? "DC21142" : - ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN" - ))))))); - } - if (lp->chipset != DC21041) { - useSROM = TRUE; /* card is not recognisably DEC */ - } - } else if ((lp->chipset & ~0x00ff) == DC2114x) { - useSROM = TRUE; - } + c_char *de4x5_signatures[] = DE4X5_SIGNATURE; + int i, status = 0, siglen = sizeof(de4x5_signatures) / sizeof(c_char *); - - return status; + if (lp->chipset == DC21040) { + strcpy(name, "DE434/5"); + return status; + } else { /* Search for a DEC name in the SROM */ + int i = *((char *) &lp->srom + 19) * 3; + strncpy(name, (char *) &lp->srom + 26 + i, 8); + } + name[8] = '\0'; + for (i = 0; i < siglen; i++) { + if (strstr(name, de4x5_signatures[i]) != NULL) + break; + } + if (i == siglen) { + if (dec_only) { + *name = '\0'; + } else { /* Use chip name to avoid confusion */ + strcpy(name, (((lp->chipset == DC21040) ? "DC21040" : + ((lp->chipset == DC21041) ? "DC21041" : + ((lp->chipset == DC21140) ? "DC21140" : + ((lp->chipset == DC21142) ? "DC21142" : + ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN" + ))))))); + } + if (lp->chipset != DC21041) { + useSROM = TRUE; /* card is not recognisably DEC */ + } + } else if ((lp->chipset & ~0x00ff) == DC2114x) { + useSROM = TRUE; + } + + return status; } /* @@ -3865,34 +3884,33 @@ ** immediately with the prior srom contents intact (the h/w address will ** be fixed up later). */ -static void -DevicePresent(u_long aprom_addr) +static void DevicePresent(u_long aprom_addr) { - int i, j=0; - struct bus_type *lp = &bus; - - if (lp->chipset == DC21040) { - outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ - } else { /* Read new srom */ - u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD); - for (i=0; i<(ETH_ALEN>>1); i++) { - tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i); - *p = le16_to_cpu(tmp); - j += *p++; - } - if ((j == 0) || (j == 0x2fffd)) { - return; - } - - p=(short *)&lp->srom; - for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) { - tmp = srom_rd(aprom_addr, i); - *p++ = le16_to_cpu(tmp); + int i, j=0; + struct bus_type *lp = &bus; + + if (lp->chipset == DC21040) { + outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ + } else { /* Read new srom */ + u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD); + for (i=0; i<(ETH_ALEN>>1); i++) { + tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i); + *p = le16_to_cpu(tmp); + j += *p++; + } + if ((j == 0) || (j == 0x2fffd)) { + return; + } + + p=(short *)&lp->srom; + for (i = 0; i < (sizeof(struct de4x5_srom) >> 1); i++) { + tmp = srom_rd(aprom_addr, i); + *p++ = le16_to_cpu(tmp); + } + de4x5_dbg_srom((struct de4x5_srom *) &lp->srom); } - de4x5_dbg_srom((struct de4x5_srom *)&lp->srom); - } - - return; + + return; } /* @@ -3901,303 +3919,302 @@ ** as one or more of the bytes. Only the last 3 bytes should be checked ** as the first three are invariant - assigned to an organisation. */ -static int -get_hw_addr(struct device *dev) +static int get_hw_addr(struct device *dev) { - u_long iobase = dev->base_addr; - int broken, i, k, tmp, status = 0; - u_short j,chksum; - struct bus_type *lp = &bus; - - broken = de4x5_bad_srom(lp); - - for (i=0,k=0,j=0;j<3;j++) { - k <<= 1; - if (k > 0xffff) k-=0xffff; - + u_long iobase = dev->base_addr; + int broken, i, k, tmp, status = 0; + u_short j, chksum; + struct bus_type *lp = &bus; + + broken = de4x5_bad_srom(lp); + + for (i = 0, k = 0, j = 0; j < 3; j++) { + k <<= 1; + if (k > 0xffff) + k -= 0xffff; + + if (lp->bus == PCI) { + if (lp->chipset == DC21040) { + while ((tmp = inl(DE4X5_APROM)) < 0); + k += (u_char) tmp; + dev->dev_addr[i++] = (u_char) tmp; + while ((tmp = inl(DE4X5_APROM)) < 0); + k += (u_short) (tmp << 8); + dev->dev_addr[i++] = (u_char) tmp; + } else if (!broken) { + dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; + i++; + dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; + i++; + } else if ((broken == SMC) || (broken == ACCTON)) { + dev->dev_addr[i] = *((u_char *) & lp->srom + i); + i++; + dev->dev_addr[i] = *((u_char *) & lp->srom + i); + i++; + } + } else { + k += (u_char) (tmp = inb(EISA_APROM)); + dev->dev_addr[i++] = (u_char) tmp; + k += (u_short) ((tmp = inb(EISA_APROM)) << 8); + dev->dev_addr[i++] = (u_char) tmp; + } + + if (k > 0xffff) + k -= 0xffff; + } + if (k == 0xffff) + k = 0; + if (lp->bus == PCI) { - if (lp->chipset == DC21040) { - while ((tmp = inl(DE4X5_APROM)) < 0); - k += (u_char) tmp; - dev->dev_addr[i++] = (u_char) tmp; - while ((tmp = inl(DE4X5_APROM)) < 0); - k += (u_short) (tmp << 8); - dev->dev_addr[i++] = (u_char) tmp; - } else if (!broken) { - dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++; - dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++; - } else if ((broken == SMC) || (broken == ACCTON)) { - dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++; - dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++; - } + if (lp->chipset == DC21040) { + while ((tmp = inl(DE4X5_APROM)) < 0); + chksum = (u_char) tmp; + while ((tmp = inl(DE4X5_APROM)) < 0); + chksum |= (u_short) (tmp << 8); + if ((k != chksum) && (dec_only)) + status = -1; + } } else { - k += (u_char) (tmp = inb(EISA_APROM)); - dev->dev_addr[i++] = (u_char) tmp; - k += (u_short) ((tmp = inb(EISA_APROM)) << 8); - dev->dev_addr[i++] = (u_char) tmp; + chksum = (u_char) inb(EISA_APROM); + chksum |= (u_short) (inb(EISA_APROM) << 8); + if ((k != chksum) && (dec_only)) + status = -1; } - - if (k > 0xffff) k-=0xffff; - } - if (k == 0xffff) k=0; - - if (lp->bus == PCI) { - if (lp->chipset == DC21040) { - while ((tmp = inl(DE4X5_APROM)) < 0); - chksum = (u_char) tmp; - while ((tmp = inl(DE4X5_APROM)) < 0); - chksum |= (u_short) (tmp << 8); - if ((k != chksum) && (dec_only)) status = -1; - } - } else { - chksum = (u_char) inb(EISA_APROM); - chksum |= (u_short) (inb(EISA_APROM) << 8); - if ((k != chksum) && (dec_only)) status = -1; - } - /* If possible, try to fix a broken card - SMC only so far */ - srom_repair(dev, broken); + /* If possible, try to fix a broken card - SMC only so far */ + srom_repair(dev, broken); - /* Test for a bad enet address */ - status = test_bad_enet(dev, status); + /* Test for a bad enet address */ + status = test_bad_enet(dev, status); - return status; + return status; } /* ** Test for enet addresses in the first 32 bytes. The built-in strncmp ** didn't seem to work here...? */ -static int -de4x5_bad_srom(struct bus_type *lp) +static int de4x5_bad_srom(struct bus_type *lp) { - int i, status = 0; + int i, status = 0; - for (i=0; isrom, (char *)&enet_det[i], 3) && - !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) { - if (i == 0) { - status = SMC; - } else if (i == 1) { - status = ACCTON; - } - break; + for (i = 0; i < sizeof(enet_det) / ETH_ALEN; i++) { + if (!de4x5_strncmp((char *) &lp->srom, (char *) &enet_det[i], 3) && + !de4x5_strncmp((char *) &lp->srom + 0x10, (char *) &enet_det[i], 3)) { + if (i == 0) { + status = SMC; + } else if (i == 1) { + status = ACCTON; + } + break; + } } - } - return status; + return status; } -static int -de4x5_strncmp(char *a, char *b, int n) +static int de4x5_strncmp(char *a, char *b, int n) { - int ret=0; + int ret = 0; - for (;n && !ret;n--) { - ret = *a++ - *b++; - } + for (; n && !ret; n--) { + ret = *a++ - *b++; + } - return ret; + return ret; } -static void -srom_repair(struct device *dev, int card) +static void srom_repair(struct device *dev, int card) { - struct bus_type *lp = &bus; + struct bus_type *lp = &bus; - switch(card) { - case SMC: - memset((char *)&bus.srom, 0, sizeof(struct de4x5_srom)); - memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN); - memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100); - useSROM = TRUE; - break; - } + switch (card) { + case SMC: + memset((char *) &bus.srom, 0, sizeof(struct de4x5_srom)); + memcpy(lp->srom.ieee_addr, (char *) dev->dev_addr, ETH_ALEN); + memcpy(lp->srom.info, (char *) &srom_repair_info[SMC - 1], 100); + useSROM = TRUE; + break; + } - return; + return; } /* ** Assume that the irq's do not follow the PCI spec - this is seems ** to be true so far (2 for 2). */ -static int -test_bad_enet(struct device *dev, int status) +static int test_bad_enet(struct device *dev, int status) { - struct bus_type *lp = &bus; - int i, tmp; + struct bus_type *lp = &bus; + int i, tmp; - for (tmp=0,i=0; idev_addr[i]; - if ((tmp == 0) || (tmp == 0x5fa)) { - if ((lp->chipset == last.chipset) && - (lp->bus_num == last.bus) && (lp->bus_num > 0)) { - for (i=0; idev_addr[i] = last.addr[i]; - for (i=ETH_ALEN-1; i>2; --i) { - dev->dev_addr[i] += 1; - if (dev->dev_addr[i] != 0) break; - } - for (i=0; idev_addr[i]; - dev->irq = last.irq; - - status = 0; - } - } else if (!status) { - last.chipset = lp->chipset; - last.bus = lp->bus_num; - last.irq = dev->irq; - for (i=0; idev_addr[i]; - } + for (tmp = 0, i = 0; i < ETH_ALEN; i++) + tmp += (u_char) dev->dev_addr[i]; + if ((tmp == 0) || (tmp == 0x5fa)) { + if ((lp->chipset == last.chipset) && + (lp->bus_num == last.bus) && (lp->bus_num > 0)) { + for (i = 0; i < ETH_ALEN; i++) + dev->dev_addr[i] = last.addr[i]; + for (i = ETH_ALEN - 1; i > 2; --i) { + dev->dev_addr[i] += 1; + if (dev->dev_addr[i] != 0) + break; + } + for (i = 0; i < ETH_ALEN; i++) + last.addr[i] = dev->dev_addr[i]; + dev->irq = last.irq; - return status; + status = 0; + } + } else if (!status) { + last.chipset = lp->chipset; + last.bus = lp->bus_num; + last.irq = dev->irq; + for (i = 0; i < ETH_ALEN; i++) + last.addr[i] = dev->dev_addr[i]; + } + return status; } /* ** SROM Read */ -static short -srom_rd(u_long addr, u_char offset) +static short srom_rd(u_long addr, u_char offset) { - sendto_srom(SROM_RD | SROM_SR, addr); - - srom_latch(SROM_RD | SROM_SR | DT_CS, addr); - srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr); - srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset); - - return srom_data(SROM_RD | SROM_SR | DT_CS, addr); + sendto_srom(SROM_RD | SROM_SR, addr); + + srom_latch(SROM_RD | SROM_SR | DT_CS, addr); + srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr); + srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset); + + return srom_data(SROM_RD | SROM_SR | DT_CS, addr); } -static void -srom_latch(u_int command, u_long addr) +static void srom_latch(u_int command, u_long addr) { - sendto_srom(command, addr); - sendto_srom(command | DT_CLK, addr); - sendto_srom(command, addr); - - return; + sendto_srom(command, addr); + sendto_srom(command | DT_CLK, addr); + sendto_srom(command, addr); + + return; } -static void -srom_command(u_int command, u_long addr) +static void srom_command(u_int command, u_long addr) { - srom_latch(command, addr); - srom_latch(command, addr); - srom_latch((command & 0x0000ff00) | DT_CS, addr); - - return; + srom_latch(command, addr); + srom_latch(command, addr); + srom_latch((command & 0x0000ff00) | DT_CS, addr); + + return; } -static void -srom_address(u_int command, u_long addr, u_char offset) +static void srom_address(u_int command, u_long addr, u_char offset) { - int i; - char a; - - a = (char)(offset << 2); - for (i=0; i<6; i++, a <<= 1) { - srom_latch(command | ((a < 0) ? DT_IN : 0), addr); - } - de4x5_us_delay(1); - - i = (getfrom_srom(addr) >> 3) & 0x01; - - return; + int i; + char a; + + a = (char) (offset << 2); + for (i = 0; i < 6; i++, a <<= 1) { + srom_latch(command | ((a < 0) ? DT_IN : 0), addr); + } + de4x5_us_delay(1); + + i = (getfrom_srom(addr) >> 3) & 0x01; + return; } -static short -srom_data(u_int command, u_long addr) +static short srom_data(u_int command, u_long addr) { - int i; - short word = 0; - s32 tmp; - - for (i=0; i<16; i++) { - sendto_srom(command | DT_CLK, addr); - tmp = getfrom_srom(addr); - sendto_srom(command, addr); - - word = (word << 1) | ((tmp >> 3) & 0x01); - } - - sendto_srom(command & 0x0000ff00, addr); - - return word; + int i; + short word = 0; + s32 tmp; + + for (i = 0; i < 16; i++) { + sendto_srom(command | DT_CLK, addr); + tmp = getfrom_srom(addr); + sendto_srom(command, addr); + + word = (word << 1) | ((tmp >> 3) & 0x01); + } + + sendto_srom(command & 0x0000ff00, addr); + + return word; } /* -static void -srom_busy(u_int command, u_long addr) -{ + static void + srom_busy(u_int command, u_long addr) + { sendto_srom((command & 0x0000ff00) | DT_CS, addr); - + while (!((getfrom_srom(addr) >> 3) & 0x01)) { - de4x5_ms_delay(1); + de4x5_ms_delay(1); } - + sendto_srom(command & 0x0000ff00, addr); - + return; -} -*/ + } + */ -static void -sendto_srom(u_int command, u_long addr) +static void sendto_srom(u_int command, u_long addr) { - outl(command, addr); - udelay(1); - - return; + outl(command, addr); + udelay(1); + + return; } -static int -getfrom_srom(u_long addr) +static int getfrom_srom(u_long addr) { - s32 tmp; - - tmp = inl(addr); - udelay(1); - - return tmp; + s32 tmp; + + tmp = inl(addr); + udelay(1); + + return tmp; } -static int -srom_infoleaf_info(struct device *dev) +static int srom_infoleaf_info(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i, count; - u_char *p; - - /* Find the infoleaf decoder function that matches this chipset */ - for (i=0; ichipset == infoleaf_array[i].chipset) break; - } - if (i == INFOLEAF_SIZE) { - lp->useSROM = FALSE; - printk("%s: Cannot find correct chipset for SROM decoding!\n", - dev->name); - return -ENXIO; - } - - lp->infoleaf_fn = infoleaf_array[i].fn; - - /* Find the information offset that this function should use */ - count = *((u_char *)&lp->srom + 19); - p = (u_char *)&lp->srom + 26; - - if (count > 1) { - for (i=count; i; --i, p+=3) { - if (lp->device == *p) break; - } - if (i == 0) { - lp->useSROM = FALSE; - printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", - dev->name, lp->device); - return -ENXIO; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int i, count; + u_char *p; + + /* Find the infoleaf decoder function that matches this chipset */ + for (i = 0; i < INFOLEAF_SIZE; i++) { + if (lp->chipset == infoleaf_array[i].chipset) + break; + } + if (i == INFOLEAF_SIZE) { + lp->useSROM = FALSE; + printk("%s: Cannot find correct chipset for SROM decoding!\n", + dev->name); + return -ENXIO; } - } + lp->infoleaf_fn = infoleaf_array[i].fn; - lp->infoleaf_offset = TWIDDLE(p+1); + /* Find the information offset that this function should use */ + count = *((u_char *) & lp->srom + 19); + p = (u_char *) & lp->srom + 26; + + if (count > 1) { + for (i = count; i; --i, p += 3) { + if (lp->device == *p) + break; + } + if (i == 0) { + lp->useSROM = FALSE; + printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", + dev->name, lp->device); + return -ENXIO; + } + } + lp->infoleaf_offset = TWIDDLE(p + 1); - return 0; + return 0; } /* @@ -4207,75 +4224,74 @@ ** The info for the MII devices will be valid since the index used ** will follow the discovery process from MII address 1-31 then 0. */ -static void -srom_init(struct device *dev) +static void srom_init(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; - u_char count; - - p+=2; - if (lp->chipset == DC21140) { - lp->cache.gepc = (*p++ | GEP_CTRL); - gep_wr(lp->cache.gepc, dev); - } + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char *p = (u_char *) & lp->srom + lp->infoleaf_offset; + u_char count; - /* Block count */ - count = *p++; + p += 2; + if (lp->chipset == DC21140) { + lp->cache.gepc = (*p++ | GEP_CTRL); + gep_wr(lp->cache.gepc, dev); + } + /* Block count */ + count = *p++; - /* Jump the infoblocks to find types */ - for (;count; --count) { - if (*p < 128) { - p += COMPACT_LEN; - } else if (*(p+1) == 5) { - type5_infoblock(dev, 1, p); - p += ((*p & BLOCK_LEN) + 1); - } else if (*(p+1) == 4) { - p += ((*p & BLOCK_LEN) + 1); - } else if (*(p+1) == 3) { - type3_infoblock(dev, 1, p); - p += ((*p & BLOCK_LEN) + 1); - } else if (*(p+1) == 2) { - p += ((*p & BLOCK_LEN) + 1); - } else if (*(p+1) == 1) { - type1_infoblock(dev, 1, p); - p += ((*p & BLOCK_LEN) + 1); - } else { - p += ((*p & BLOCK_LEN) + 1); + /* Jump the infoblocks to find types */ + for (; count; --count) { + if (*p < 128) { + p += COMPACT_LEN; + } else if (*(p + 1) == 5) { + type5_infoblock(dev, 1, p); + p += ((*p & BLOCK_LEN) + 1); + } else if (*(p+1) == 4) { + p += ((*p & BLOCK_LEN) + 1); + } else if (*(p + 1) == 3) { + type3_infoblock(dev, 1, p); + p += ((*p & BLOCK_LEN) + 1); + } else if (*(p+1) == 2) { + p += ((*p & BLOCK_LEN) + 1); + } else if (*(p + 1) == 1) { + type1_infoblock(dev, 1, p); + p += ((*p & BLOCK_LEN) + 1); + } else { + p += ((*p & BLOCK_LEN) + 1); + } } - } - return; + return; } /* ** A generic routine that writes GEP control, data and reset information ** to the GEP register (21140) or csr15 GEP portion (2114[23]). */ -static void -srom_exec(struct device *dev, u_char *p) +static void srom_exec(struct device *dev, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; - u_char count = (p ? *p++ : 0); - u_short *w = (u_short *)p; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + u_char count = (p ? *p++ : 0); + u_short *w = (u_short *)p; - if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return; + if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) + return; - if (lp->chipset != DC21140) RESET_SIA; + if (lp->chipset != DC21140) + RESET_SIA; - while (count--) { - gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? - *p++ : TWIDDLE(w++)), dev); - udelay(2000); /* 2ms per action */ - } - - if (lp->chipset != DC21140) { - outl(lp->cache.csr14, DE4X5_STRR); - outl(lp->cache.csr13, DE4X5_SICR); - } + while (count--) { + gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? + *p++ : TWIDDLE(w++)), dev); + udelay(2000); /* 2ms per action */ + } + + if (lp->chipset != DC21140) { + outl(lp->cache.csr14, DE4X5_STRR); + outl(lp->cache.csr13, DE4X5_SICR); + } - return; + return; } /* @@ -4283,970 +4299,944 @@ ** unless I implement the DC21041 SROM functions. There's no need ** since the existing code will be satisfactory for all boards. */ -static int -dc21041_infoleaf(struct device *dev) +static int dc21041_infoleaf(struct device *dev) { - return DE4X5_AUTOSENSE_MS; + return DE4X5_AUTOSENSE_MS; } -static int -dc21140_infoleaf(struct device *dev) +static int dc21140_infoleaf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char count = 0; - u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; - int next_tick = DE4X5_AUTOSENSE_MS; - - /* Read the connection type */ - p+=2; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char count = 0; + u_char *p = (u_char *) & lp->srom + lp->infoleaf_offset; + int next_tick = DE4X5_AUTOSENSE_MS; - /* GEP control */ - lp->cache.gepc = (*p++ | GEP_CTRL); + /* Read the connection type */ + p += 2; - /* Block count */ - count = *p++; + /* GEP control */ + lp->cache.gepc = (*p++ | GEP_CTRL); - /* Recursively figure out the info blocks */ - if (*p < 128) { - next_tick = dc_infoblock[COMPACT](dev, count, p); - } else { - next_tick = dc_infoblock[*(p+1)](dev, count, p); - } + /* Block count */ + count = *p++; - if (lp->tcount == count) { - lp->media = NC; - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; + /* Recursively figure out the info blocks */ + if (*p < 128) { + next_tick = dc_infoblock[COMPACT] (dev, count, p); + } else { + next_tick = dc_infoblock[*(p + 1)] (dev, count, p); } - lp->media = INIT; - lp->tcount = 0; - lp->tx_enable = FALSE; - } - return next_tick & ~TIMER_CB; + if (lp->tcount == count) { + lp->media = NC; + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tcount = 0; + lp->tx_enable = FALSE; + } + return next_tick & ~TIMER_CB; } -static int -dc21142_infoleaf(struct device *dev) +static int dc21142_infoleaf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char count = 0; - u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; - int next_tick = DE4X5_AUTOSENSE_MS; - - /* Read the connection type */ - p+=2; - - /* Block count */ - count = *p++; - - /* Recursively figure out the info blocks */ - if (*p < 128) { - next_tick = dc_infoblock[COMPACT](dev, count, p); - } else { - next_tick = dc_infoblock[*(p+1)](dev, count, p); - } - - if (lp->tcount == count) { - lp->media = NC; - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_char count = 0; + u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; + int next_tick = DE4X5_AUTOSENSE_MS; + + /* Read the connection type */ + p+=2; + + /* Block count */ + count = *p++; + + /* Recursively figure out the info blocks */ + if (*p < 128) { + next_tick = dc_infoblock[COMPACT](dev, count, p); + } else { + next_tick = dc_infoblock[*(p+1)](dev, count, p); + } + + if (lp->tcount == count) { + lp->media = NC; + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tcount = 0; + lp->tx_enable = FALSE; } - lp->media = INIT; - lp->tcount = 0; - lp->tx_enable = FALSE; - } - return next_tick & ~TIMER_CB; + return next_tick & ~TIMER_CB; } -static int -dc21143_infoleaf(struct device *dev) +static int dc21143_infoleaf(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char count = 0; - u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; - int next_tick = DE4X5_AUTOSENSE_MS; - - /* Read the connection type */ - p+=2; - - /* Block count */ - count = *p++; - - /* Recursively figure out the info blocks */ - if (*p < 128) { - next_tick = dc_infoblock[COMPACT](dev, count, p); - } else { - next_tick = dc_infoblock[*(p+1)](dev, count, p); - } - if (lp->tcount == count) { - lp->media = NC; - if (lp->media != lp->c_media) { - de4x5_dbg_media(dev); - lp->c_media = lp->media; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_char count = 0; + u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; + int next_tick = DE4X5_AUTOSENSE_MS; + + /* Read the connection type */ + p+=2; + + /* Block count */ + count = *p++; + + /* Recursively figure out the info blocks */ + if (*p < 128) { + next_tick = dc_infoblock[COMPACT](dev, count, p); + } else { + next_tick = dc_infoblock[*(p+1)](dev, count, p); + } + if (lp->tcount == count) { + lp->media = NC; + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } + lp->media = INIT; + lp->tcount = 0; + lp->tx_enable = FALSE; } - lp->media = INIT; - lp->tcount = 0; - lp->tx_enable = FALSE; - } - return next_tick & ~TIMER_CB; + return next_tick & ~TIMER_CB; } /* ** The compact infoblock is only designed for DC21140[A] chips, so ** we'll reuse the dc21140m_autoconf function. Non MII media only. */ -static int -compact_infoblock(struct device *dev, u_char count, u_char *p) +static int compact_infoblock(struct device *dev, u_char count, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char flags, csr6; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char flags, csr6; - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+COMPACT_LEN) < 128) { - return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN); - } else { - return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN); + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p + COMPACT_LEN) < 128) { + return dc_infoblock[COMPACT] (dev, count, p + COMPACT_LEN); + } else { + return dc_infoblock[*(p + COMPACT_LEN + 1)] (dev, count, p + COMPACT_LEN); + } } - } - - if ((lp->media == INIT) && (lp->timeout < 0)) { - lp->ibn = COMPACT; - lp->active = 0; - gep_wr(lp->cache.gepc, dev); - lp->infoblock_media = (*p++) & COMPACT_MC; - lp->cache.gep = *p++; - csr6 = *p++; - flags = *p++; - - lp->asBitValid = (flags & 0x80) ? 0 : -1; - lp->defMedium = (flags & 0x40) ? -1 : 0; - lp->asBit = 1 << ((csr6 >> 1) & 0x07); - lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; - lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18); - lp->useMII = FALSE; + if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = COMPACT; + lp->active = 0; + gep_wr(lp->cache.gepc, dev); + lp->infoblock_media = (*p++) & COMPACT_MC; + lp->cache.gep = *p++; + csr6 = *p++; + flags = *p++; + + lp->asBitValid = (flags & 0x80) ? 0 : -1; + lp->defMedium = (flags & 0x40) ? -1 : 0; + lp->asBit = 1 << ((csr6 >> 1) & 0x07); + lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; + lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18); + lp->useMII = FALSE; - de4x5_switch_mac_port(dev); - } - - return dc21140m_autoconf(dev); + de4x5_switch_mac_port(dev); + } + return dc21140m_autoconf(dev); } /* ** This block describes non MII media for the DC21140[A] only. */ -static int -type0_infoblock(struct device *dev, u_char count, u_char *p) +static int type0_infoblock(struct device *dev, u_char count, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char flags, csr6, len = (*p & BLOCK_LEN)+1; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char flags, csr6, len = (*p & BLOCK_LEN) + 1; - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+len) < 128) { - return dc_infoblock[COMPACT](dev, count, p+len); - } else { - return dc_infoblock[*(p+len+1)](dev, count, p+len); + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p + len) < 128) { + return dc_infoblock[COMPACT] (dev, count, p + len); + } else { + return dc_infoblock[*(p + len + 1)] (dev, count, p + len); + } } - } - - if ((lp->media == INIT) && (lp->timeout < 0)) { - lp->ibn = 0; - lp->active = 0; - gep_wr(lp->cache.gepc, dev); - p+=2; - lp->infoblock_media = (*p++) & BLOCK0_MC; - lp->cache.gep = *p++; - csr6 = *p++; - flags = *p++; - - lp->asBitValid = (flags & 0x80) ? 0 : -1; - lp->defMedium = (flags & 0x40) ? -1 : 0; - lp->asBit = 1 << ((csr6 >> 1) & 0x07); - lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; - lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18); - lp->useMII = FALSE; - - de4x5_switch_mac_port(dev); - } + if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 0; + lp->active = 0; + gep_wr(lp->cache.gepc, dev); + p += 2; + lp->infoblock_media = (*p++) & BLOCK0_MC; + lp->cache.gep = *p++; + csr6 = *p++; + flags = *p++; + + lp->asBitValid = (flags & 0x80) ? 0 : -1; + lp->defMedium = (flags & 0x40) ? -1 : 0; + lp->asBit = 1 << ((csr6 >> 1) & 0x07); + lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; + lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18); + lp->useMII = FALSE; - return dc21140m_autoconf(dev); + de4x5_switch_mac_port(dev); + } + return dc21140m_autoconf(dev); } /* These functions are under construction! */ -static int -type1_infoblock(struct device *dev, u_char count, u_char *p) +static int type1_infoblock(struct device *dev, u_char count, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char len = (*p & BLOCK_LEN)+1; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char len = (*p & BLOCK_LEN) + 1; - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+len) < 128) { - return dc_infoblock[COMPACT](dev, count, p+len); - } else { - return dc_infoblock[*(p+len+1)](dev, count, p+len); + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p + len) < 128) { + return dc_infoblock[COMPACT] (dev, count, p + len); + } else { + return dc_infoblock[*(p + len + 1)] (dev, count, p + len); + } } - } - - p += 2; - if (lp->state == INITIALISED) { - lp->active = *p++; - lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); - return 0; - } else if ((lp->media == INIT) && (lp->timeout < 0)) { - lp->ibn = 1; - lp->active = *p; - lp->infoblock_csr6 = OMR_MII_100; - lp->useMII = TRUE; - lp->infoblock_media = ANS; - lp->media = ANS; - de4x5_switch_mac_port(dev); - } - - return dc21140m_autoconf(dev); + p += 2; + if (lp->state == INITIALISED) { + lp->active = *p++; + lp->phy[lp->active].gep = (*p ? p : 0); + p += (*p + 1); + lp->phy[lp->active].rst = (*p ? p : 0); + p += (*p + 1); + lp->phy[lp->active].mc = TWIDDLE(p); + p += 2; + lp->phy[lp->active].ana = TWIDDLE(p); + p += 2; + lp->phy[lp->active].fdx = TWIDDLE(p); + p += 2; + lp->phy[lp->active].ttm = TWIDDLE(p); + return 0; + } else if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 1; + lp->active = *p; + lp->infoblock_csr6 = OMR_MII_100; + lp->useMII = TRUE; + lp->infoblock_media = ANS; + lp->media = ANS; + de4x5_switch_mac_port(dev); + } + return dc21140m_autoconf(dev); } -static int -type2_infoblock(struct device *dev, u_char count, u_char *p) +static int type2_infoblock(struct device *dev, u_char count, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char len = (*p & BLOCK_LEN)+1; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_char len = (*p & BLOCK_LEN)+1; - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+len) < 128) { - return dc_infoblock[COMPACT](dev, count, p+len); - } else { - return dc_infoblock[*(p+len+1)](dev, count, p+len); + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+len) < 128) { + return dc_infoblock[COMPACT](dev, count, p+len); + } else { + return dc_infoblock[*(p+len+1)](dev, count, p+len); + } } - } - if ((lp->media == INIT) && (lp->timeout < 0)) { - lp->ibn = 2; - lp->active = 0; - p += 2; - lp->infoblock_media = (*p) & MEDIA_CODE; + if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 2; + lp->active = 0; + p += 2; + lp->infoblock_media = (*p) & MEDIA_CODE; + + if ((*p++) & EXT_FIELD) { + lp->cache.csr13 = TWIDDLE(p); p += 2; + lp->cache.csr14 = TWIDDLE(p); p += 2; + lp->cache.csr15 = TWIDDLE(p); p += 2; + } else { + lp->cache.csr13 = CSR13; + lp->cache.csr14 = CSR14; + lp->cache.csr15 = CSR15; + } + lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; + lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); + lp->infoblock_csr6 = OMR_SIA; + lp->useMII = FALSE; - if ((*p++) & EXT_FIELD) { - lp->cache.csr13 = TWIDDLE(p); p += 2; - lp->cache.csr14 = TWIDDLE(p); p += 2; - lp->cache.csr15 = TWIDDLE(p); p += 2; - } else { - lp->cache.csr13 = CSR13; - lp->cache.csr14 = CSR14; - lp->cache.csr15 = CSR15; + de4x5_switch_mac_port(dev); } - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); - lp->infoblock_csr6 = OMR_SIA; - lp->useMII = FALSE; - de4x5_switch_mac_port(dev); - } - - return dc2114x_autoconf(dev); + return dc2114x_autoconf(dev); } -static int -type3_infoblock(struct device *dev, u_char count, u_char *p) +static int type3_infoblock(struct device *dev, u_char count, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char len = (*p & BLOCK_LEN)+1; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char len = (*p & BLOCK_LEN)+1; - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+len) < 128) { - return dc_infoblock[COMPACT](dev, count, p+len); - } else { - return dc_infoblock[*(p+len+1)](dev, count, p+len); + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p + len) < 128) { + return dc_infoblock[COMPACT] (dev, count, p + len); + } else { + return dc_infoblock[*(p + len + 1)] (dev, count, p + len); + } } - } - p += 2; - if (lp->state == INITIALISED) { - lp->active = *p++; - lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1); - lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); p += 2; - lp->phy[lp->active].mci = *p; - return 0; - } else if ((lp->media == INIT) && (lp->timeout < 0)) { - lp->ibn = 3; - lp->active = *p; - lp->infoblock_csr6 = OMR_MII_100; - lp->useMII = TRUE; - lp->infoblock_media = ANS; - - de4x5_switch_mac_port(dev); - } - - return dc2114x_autoconf(dev); -} - -static int -type4_infoblock(struct device *dev, u_char count, u_char *p) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char flags, csr6, len = (*p & BLOCK_LEN)+1; - - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+len) < 128) { - return dc_infoblock[COMPACT](dev, count, p+len); - } else { - return dc_infoblock[*(p+len+1)](dev, count, p+len); + p += 2; + if (lp->state == INITIALISED) { + lp->active = *p++; + lp->phy[lp->active].gep = (*p ? p : 0); + p += (2 * (*p) + 1); + lp->phy[lp->active].rst = (*p ? p : 0); + p += (2 * (*p) + 1); + lp->phy[lp->active].mc = TWIDDLE(p); + p += 2; + lp->phy[lp->active].ana = TWIDDLE(p); + p += 2; + lp->phy[lp->active].fdx = TWIDDLE(p); + p += 2; + lp->phy[lp->active].ttm = TWIDDLE(p); + p += 2; + lp->phy[lp->active].mci = *p; + return 0; + } else if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 3; + lp->active = *p; + lp->infoblock_csr6 = OMR_MII_100; + lp->useMII = TRUE; + lp->infoblock_media = ANS; + + de4x5_switch_mac_port(dev); + } + + return dc2114x_autoconf(dev); +} + +static int type4_infoblock(struct device *dev, u_char count, u_char *p) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_char flags, csr6, len = (*p & BLOCK_LEN)+1; + + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p+len) < 128) { + return dc_infoblock[COMPACT](dev, count, p+len); + } else { + return dc_infoblock[*(p+len+1)](dev, count, p+len); + } } - } - if ((lp->media == INIT) && (lp->timeout < 0)) { - lp->ibn = 4; - lp->active = 0; - p+=2; - lp->infoblock_media = (*p++) & MEDIA_CODE; - lp->cache.csr13 = CSR13; /* Hard coded defaults */ - lp->cache.csr14 = CSR14; - lp->cache.csr15 = CSR15; - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2; - csr6 = *p++; - flags = *p++; - - lp->asBitValid = (flags & 0x80) ? 0 : -1; - lp->defMedium = (flags & 0x40) ? -1 : 0; - lp->asBit = 1 << ((csr6 >> 1) & 0x07); - lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; - lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18); - lp->useMII = FALSE; + if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 4; + lp->active = 0; + p += 2; + lp->infoblock_media = (*p++) & MEDIA_CODE; + lp->cache.csr13 = CSR13; /* Hard coded defaults */ + lp->cache.csr14 = CSR14; + lp->cache.csr15 = CSR15; + lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; + lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2; + csr6 = *p++; + flags = *p++; + + lp->asBitValid = (flags & 0x80) ? 0 : -1; + lp->defMedium = (flags & 0x40) ? -1 : 0; + lp->asBit = 1 << ((csr6 >> 1) & 0x07); + lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit; + lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18); + lp->useMII = FALSE; - de4x5_switch_mac_port(dev); - } + de4x5_switch_mac_port(dev); + } - return dc2114x_autoconf(dev); + return dc2114x_autoconf(dev); } /* ** This block type provides information for resetting external devices ** (chips) through the General Purpose Register. */ -static int -type5_infoblock(struct device *dev, u_char count, u_char *p) +static int type5_infoblock(struct device *dev, u_char count, u_char * p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_char len = (*p & BLOCK_LEN)+1; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_char len = (*p & BLOCK_LEN)+1; - /* Recursively figure out the info blocks */ - if (--count > lp->tcount) { - if (*(p+len) < 128) { - return dc_infoblock[COMPACT](dev, count, p+len); - } else { - return dc_infoblock[*(p+len+1)](dev, count, p+len); + /* Recursively figure out the info blocks */ + if (--count > lp->tcount) { + if (*(p + len) < 128) { + return dc_infoblock[COMPACT] (dev, count, p + len); + } else { + return dc_infoblock[*(p + len + 1)] (dev, count, p + len); + } } - } - - /* Must be initializing to run this code */ - if ((lp->state == INITIALISED) || (lp->media == INIT)) { - p+=2; - lp->rst = p; - srom_exec(dev, lp->rst); - } - - return DE4X5_AUTOSENSE_MS; + /* Must be initializing to run this code */ + if ((lp->state == INITIALISED) || (lp->media == INIT)) { + p += 2; + lp->rst = p; + srom_exec(dev, lp->rst); + } + return DE4X5_AUTOSENSE_MS; } /* ** MII Read/Write */ -static int -mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr) +static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr) { - mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */ - mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */ - mii_wdata(MII_STRD, 4, ioaddr); /* SFD and Read operation */ - mii_address(phyaddr, ioaddr); /* PHY address to be accessed */ - mii_address(phyreg, ioaddr); /* PHY Register to read */ - mii_ta(MII_STRD, ioaddr); /* Turn around time - 2 MDC */ - - return mii_rdata(ioaddr); /* Read data */ -} + mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */ + mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */ + mii_wdata(MII_STRD, 4, ioaddr); /* SFD and Read operation */ + mii_address(phyaddr, ioaddr); /* PHY address to be accessed */ + mii_address(phyreg, ioaddr); /* PHY Register to read */ + mii_ta(MII_STRD, ioaddr); /* Turn around time - 2 MDC */ + + return mii_rdata(ioaddr); /* Read data */ +} + +static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr) +{ + mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */ + mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */ + mii_wdata(MII_STWR, 4, ioaddr); /* SFD and Write operation */ + mii_address(phyaddr, ioaddr); /* PHY address to be accessed */ + mii_address(phyreg, ioaddr); /* PHY Register to write */ + mii_ta(MII_STWR, ioaddr); /* Turn around time - 2 MDC */ + data = mii_swap(data, 16); /* Swap data bit ordering */ + mii_wdata(data, 16, ioaddr); /* Write data */ -static void -mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr) -{ - mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */ - mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */ - mii_wdata(MII_STWR, 4, ioaddr); /* SFD and Write operation */ - mii_address(phyaddr, ioaddr); /* PHY address to be accessed */ - mii_address(phyreg, ioaddr); /* PHY Register to write */ - mii_ta(MII_STWR, ioaddr); /* Turn around time - 2 MDC */ - data = mii_swap(data, 16); /* Swap data bit ordering */ - mii_wdata(data, 16, ioaddr); /* Write data */ - - return; + return; } -static int -mii_rdata(u_long ioaddr) +static int mii_rdata(u_long ioaddr) { - int i; - s32 tmp = 0; - - for (i=0; i<16; i++) { - tmp <<= 1; - tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr); - } - - return tmp; + int i; + s32 tmp = 0; + + for (i = 0; i < 16; i++) { + tmp <<= 1; + tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr); + } + + return tmp; } -static void -mii_wdata(int data, int len, u_long ioaddr) +static void mii_wdata(int data, int len, u_long ioaddr) { - int i; - - for (i=0; i>= 1; - } - - return; + int i; + + for (i = 0; i < len; i++) { + sendto_mii(MII_MWR | MII_WR, data, ioaddr); + data >>= 1; + } + + return; } -static void -mii_address(u_char addr, u_long ioaddr) +static void mii_address(u_char addr, u_long ioaddr) { - int i; - - addr = mii_swap(addr, 5); - for (i=0; i<5; i++) { - sendto_mii(MII_MWR | MII_WR, addr, ioaddr); - addr >>= 1; - } - - return; + int i; + + addr = mii_swap(addr, 5); + for (i = 0; i < 5; i++) { + sendto_mii(MII_MWR | MII_WR, addr, ioaddr); + addr >>= 1; + } + + return; } -static void -mii_ta(u_long rw, u_long ioaddr) +static void mii_ta(u_long rw, u_long ioaddr) { - if (rw == MII_STWR) { - sendto_mii(MII_MWR | MII_WR, 1, ioaddr); - sendto_mii(MII_MWR | MII_WR, 0, ioaddr); - } else { - getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */ - } - - return; + if (rw == MII_STWR) { + sendto_mii(MII_MWR | MII_WR, 1, ioaddr); + sendto_mii(MII_MWR | MII_WR, 0, ioaddr); + } else { + getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */ + } + + return; } -static int -mii_swap(int data, int len) +static int mii_swap(int data, int len) { - int i, tmp = 0; - - for (i=0; i>= 1; - } - - return tmp; + int i, tmp = 0; + + for (i = 0; i < len; i++) { + tmp <<= 1; + tmp |= (data & 1); + data >>= 1; + } + + return tmp; } -static void -sendto_mii(u32 command, int data, u_long ioaddr) +static void sendto_mii(u32 command, int data, u_long ioaddr) { - u32 j; - - j = (data & 1) << 17; - outl(command | j, ioaddr); - udelay(1); - outl(command | MII_MDC | j, ioaddr); - udelay(1); - - return; + u32 j; + + j = (data & 1) << 17; + outl(command | j, ioaddr); + udelay(1); + outl(command | MII_MDC | j, ioaddr); + udelay(1); + + return; } -static int -getfrom_mii(u32 command, u_long ioaddr) +static int getfrom_mii(u32 command, u_long ioaddr) { - outl(command, ioaddr); - udelay(1); - outl(command | MII_MDC, ioaddr); - udelay(1); - - return ((inl(ioaddr) >> 19) & 1); + outl(command, ioaddr); + udelay(1); + outl(command | MII_MDC, ioaddr); + udelay(1); + + return ((inl(ioaddr) >> 19) & 1); } /* ** Here's 3 ways to calculate the OUI from the ID registers. */ -static int -mii_get_oui(u_char phyaddr, u_long ioaddr) +static int mii_get_oui(u_char phyaddr, u_long ioaddr) { /* - union { - u_short reg; - u_char breg[2]; - } a; - int i, r2, r3, ret=0;*/ - int r2, r3; - - /* Read r2 and r3 */ - r2 = mii_rd(MII_ID0, phyaddr, ioaddr); - r3 = mii_rd(MII_ID1, phyaddr, ioaddr); - /* SEEQ and Cypress way * / - / * Shuffle r2 and r3 * / - a.reg=0; - r3 = ((r3>>10)|(r2<<6))&0x0ff; - r2 = ((r2>>2)&0x3fff); - - / * Bit reverse r3 * / - for (i=0;i<8;i++) { - ret<<=1; - ret |= (r3&1); - r3>>=1; - } - - / * Bit reverse r2 * / - for (i=0;i<16;i++) { - a.reg<<=1; - a.reg |= (r2&1); - r2>>=1; - } - - / * Swap r2 bytes * / - i=a.breg[0]; - a.breg[0]=a.breg[1]; - a.breg[1]=i; - - return ((a.reg<<8)|ret); */ /* SEEQ and Cypress way */ -/* return ((r2<<6)|(u_int)(r3>>10)); */ /* NATIONAL and BROADCOM way */ - return r2; /* (I did it) My way */ + union { + u_short reg; + u_char breg[2]; + } a; + int i, r2, r3, ret=0; */ + int r2, r3; + + /* Read r2 and r3 */ + r2 = mii_rd(MII_ID0, phyaddr, ioaddr); + r3 = mii_rd(MII_ID1, phyaddr, ioaddr); + /* SEEQ and Cypress way * / + / * Shuffle r2 and r3 * / + a.reg=0; + r3 = ((r3>>10)|(r2<<6))&0x0ff; + r2 = ((r2>>2)&0x3fff); + + / * Bit reverse r3 * / + for (i=0;i<8;i++) { + ret<<=1; + ret |= (r3&1); + r3>>=1; + } + + / * Bit reverse r2 * / + for (i=0;i<16;i++) { + a.reg<<=1; + a.reg |= (r2&1); + r2>>=1; + } + + / * Swap r2 bytes * / + i=a.breg[0]; + a.breg[0]=a.breg[1]; + a.breg[1]=i; + + return ((a.reg<<8)|ret); *//* SEEQ and Cypress way */ + /* return ((r2<<6)|(u_int)(r3>>10)); *//* NATIONAL and BROADCOM way */ + return r2; /* (I did it) My way */ } /* ** The SROM spec forces us to search addresses [1-31 0]. Bummer. */ -static int -mii_get_phy(struct device *dev) +static int mii_get_phy(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; - int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table); - int id; - - lp->active = 0; - lp->useMII = TRUE; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + int i, j, k, n, limit = sizeof(phy_info) / sizeof(struct phy_table); + int id; + + lp->active = 0; + lp->useMII = TRUE; - /* Search the MII address space for possible PHY devices */ - for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) { - lp->phy[lp->active].addr = i; - if (i==0) n++; /* Count cycles */ - while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */ - id = mii_get_oui(i, DE4X5_MII); - if ((id == 0) || (id == 65535)) continue; /* Valid ID? */ - for (j=0; jphy[k].id && (k < DE4X5_MAX_PHY); k++); - if (k < DE4X5_MAX_PHY) { - memcpy((char *)&lp->phy[k], - (char *)&phy_info[j], sizeof(struct phy_table)); - lp->phy[k].addr = i; - lp->mii_cnt++; - lp->active++; - } else { - goto purgatory; /* Stop the search */ - } - break; - } - if ((j == limit) && (i < DE4X5_MAX_MII)) { - printk("%s: Found MII device not currently supported. Please mail the following dump to\nthe author:\n", dev->name); - de4x5_debug |= DEBUG_MII; - de4x5_dbg_mii(dev, i); - printk("\n"); + /* Search the MII address space for possible PHY devices */ + for (n = 0, lp->mii_cnt = 0, i = 1; !((i == 1) && (n == 1)); i = (++i) % DE4X5_MAX_MII) { + lp->phy[lp->active].addr = i; + if (i == 0) + n++; /* Count cycles */ + while (de4x5_reset_phy(dev) < 0) + udelay(100); /* Wait for reset */ + id = mii_get_oui(i, DE4X5_MII); + if ((id == 0) || (id == 65535)) + continue; /* Valid ID? */ + for (j = 0; j < limit; j++) { /* Search PHY table */ + if (id != phy_info[j].id) + continue; /* ID match? */ + for (k = 0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++); + if (k < DE4X5_MAX_PHY) { + memcpy((char *) &lp->phy[k], + (char *) &phy_info[j], sizeof(struct phy_table)); + lp->phy[k].addr = i; + lp->mii_cnt++; + lp->active++; + } else { + goto purgatory; /* Stop the search */ + } + break; + } + if ((j == limit) && (i < DE4X5_MAX_MII)) { + printk("%s: Found MII device not currently supported. Please mail the following dump to\nthe author:\n", dev->name); + de4x5_debug |= DEBUG_MII; + de4x5_dbg_mii(dev, i); + printk("\n"); + } } - } purgatory: - lp->active = 0; - if (lp->phy[0].id) { /* Reset the PHY devices */ - for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/ - mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII); - while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST); - - de4x5_dbg_mii(dev, k); + lp->active = 0; + if (lp->phy[0].id) { /* Reset the PHY devices */ + for (k = 0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY */ + mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII); + while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST); + + de4x5_dbg_mii(dev, k); + } } - } - if (!lp->mii_cnt) lp->useMII = FALSE; + if (!lp->mii_cnt) + lp->useMII = FALSE; - return lp->mii_cnt; + return lp->mii_cnt; } -static char * -build_setup_frame(struct device *dev, int mode) +static char *build_setup_frame(struct device *dev, int mode) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i; - char *pa = lp->setup_frame; - - /* Initialise the setup frame */ - if (mode == ALL) { - memset(lp->setup_frame, 0, SETUP_FRAME_LEN); - } - - if (lp->setup_f == HASH_PERF) { - for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; idev_addr[i]; /* Host address */ - if (i & 0x01) pa += 2; - } - *(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80; - } else { - for (i=0; idev_addr[i]; - if (i & 0x01) pa += 4; - } - for (i=0; ipriv; + int i; + char *pa = lp->setup_frame; + + /* Initialise the setup frame */ + if (mode == ALL) { + memset(lp->setup_frame, 0, SETUP_FRAME_LEN); } - } - - return pa; /* Points to the next entry */ + if (lp->setup_f == HASH_PERF) { + for (pa = lp->setup_frame + IMPERF_PA_OFFSET, i = 0; i < ETH_ALEN; i++) { + *(pa + i) = dev->dev_addr[i]; /* Host address */ + if (i & 0x01) + pa += 2; + } + *(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80; + } else { + for (i = 0; i < ETH_ALEN; i++) { /* Host address */ + *(pa + (i & 1)) = dev->dev_addr[i]; + if (i & 0x01) + pa += 4; + } + for (i = 0; i < ETH_ALEN; i++) { /* Broadcast address */ + *(pa + (i & 1)) = (char) 0xff; + if (i & 0x01) + pa += 4; + } + } + + return pa; /* Points to the next entry */ } -static void -enable_ast(struct device *dev, u32 time_out) +static void enable_ast(struct device *dev, u32 time_out) { - timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out); - - return; + timeout(dev, (void *) &de4x5_ast, (u_long) dev, time_out); + + return; } -static void -disable_ast(struct device *dev) +static void disable_ast(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - - del_timer(&lp->timer); - - return; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + + del_timer(&lp->timer); + + return; } -static long -de4x5_switch_mac_port(struct device *dev) +static long de4x5_switch_mac_port(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; - s32 omr; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + s32 omr; - STOP_DE4X5; + STOP_DE4X5; - /* Assert the OMR_PS bit in CSR6 */ - omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | - OMR_FDX)); - omr |= lp->infoblock_csr6; - if (omr & OMR_PS) omr |= OMR_HBD; - outl(omr, DE4X5_OMR); - - /* Soft Reset */ - RESET_DE4X5; - - /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */ - if (lp->chipset == DC21140) { - gep_wr(lp->cache.gepc, dev); - gep_wr(lp->cache.gep, dev); - } else if ((lp->chipset & ~0x0ff) == DC2114x) { - reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15); - } + /* Assert the OMR_PS bit in CSR6 */ + omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | + OMR_FDX)); + omr |= lp->infoblock_csr6; + if (omr & OMR_PS) + omr |= OMR_HBD; + outl(omr, DE4X5_OMR); + + /* Soft Reset */ + RESET_DE4X5; - /* Restore CSR6 */ - outl(omr, DE4X5_OMR); + /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */ + if (lp->chipset == DC21140) { + gep_wr(lp->cache.gepc, dev); + gep_wr(lp->cache.gep, dev); + } else if ((lp->chipset & ~0x0ff) == DC2114x) { + reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15); + } + /* Restore CSR6 */ + outl(omr, DE4X5_OMR); - /* Reset CSR8 */ - inl(DE4X5_MFC); + /* Reset CSR8 */ + inl(DE4X5_MFC); - return omr; + return omr; } -static void -gep_wr(s32 data, struct device *dev) +static void gep_wr(s32 data, struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; - if (lp->chipset == DC21140) { - outl(data, DE4X5_GEP); - } else if ((lp->chipset & ~0x00ff) == DC2114x) { - outl((data<<16) | lp->cache.csr15, DE4X5_SIGR); - } + if (lp->chipset == DC21140) { + outl(data, DE4X5_GEP); + } else if ((lp->chipset & ~0x00ff) == DC2114x) { + outl((data<<16) | lp->cache.csr15, DE4X5_SIGR); + } - return; + return; } -static int -gep_rd(struct device *dev) +static int gep_rd(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; - if (lp->chipset == DC21140) { - return inl(DE4X5_GEP); - } else if ((lp->chipset & ~0x00ff) == DC2114x) { - return (inl(DE4X5_SIGR) & 0x000fffff); - } + if (lp->chipset == DC21140) { + return inl(DE4X5_GEP); + } else if ((lp->chipset & ~0x00ff) == DC2114x) { + return (inl(DE4X5_SIGR) & 0x000fffff); + } - return 0; + return 0; } -static void -timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec) +static void timeout(struct device *dev, void (*fn) (u_long data), u_long data, u_long msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int dt; - - /* First, cancel any pending timer events */ - del_timer(&lp->timer); - - /* Convert msec to ticks */ - dt = (msec * HZ) / 1000; - if (dt==0) dt=1; - - /* Set up timer */ - lp->timer.expires = jiffies + dt; - lp->timer.function = fn; - lp->timer.data = data; - add_timer(&lp->timer); - - return; -} + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int dt; -static void -yawn(struct device *dev, int state) -{ - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; + /* First, cancel any pending timer events */ + del_timer(&lp->timer); - if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return; + /* Convert msec to ticks */ + dt = (msec * HZ) / 1000; + if (dt == 0) + dt = 1; + + /* Set up timer */ + lp->timer.expires = jiffies + dt; + lp->timer.function = fn; + lp->timer.data = data; + add_timer(&lp->timer); + + return; +} - if(lp->bus == EISA) { - switch(state) { - case WAKEUP: - outb(WAKEUP, PCI_CFPM); - de4x5_ms_delay(10); - break; +static void yawn(struct device *dev, int state) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; - case SNOOZE: - outb(SNOOZE, PCI_CFPM); - break; + if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) + return; - case SLEEP: - outl(0, DE4X5_SICR); - outb(SLEEP, PCI_CFPM); - break; + if (lp->bus == EISA) { + switch (state) { + case WAKEUP: + outb(WAKEUP, PCI_CFPM); + de4x5_ms_delay(10); + break; + + case SNOOZE: + outb(SNOOZE, PCI_CFPM); + break; + + case SLEEP: + outl(0, DE4X5_SICR); + outb(SLEEP, PCI_CFPM); + break; + } + } else { + switch (state) { + case WAKEUP: + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, WAKEUP); + de4x5_ms_delay(10); + break; + + case SNOOZE: + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, SNOOZE); + break; + + case SLEEP: + outl(0, DE4X5_SICR); + pcibios_write_config_byte(lp->bus_num, lp->device << 3, + PCI_CFDA_PSM, SLEEP); + break; + } } - } else { - switch(state) { - case WAKEUP: - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, WAKEUP); - de4x5_ms_delay(10); - break; - case SNOOZE: - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, SNOOZE); - break; + return; +} - case SLEEP: - outl(0, DE4X5_SICR); - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, SLEEP); - break; - } - } +static void de4x5_dbg_open(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + int i; - return; + if (de4x5_debug & DEBUG_OPEN) { + printk("%s: de4x5 opening with irq %d\n", dev->name, dev->irq); + printk("\tphysical address: "); + for (i = 0; i < 6; i++) { + printk("%2.2x:", (short) dev->dev_addr[i]); + } + printk("\n"); + printk("Descriptor head addresses:\n"); + printk("\t0x%8.8lx 0x%8.8lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring); + printk("Descriptor addresses:\nRX: "); + for (i = 0; i < lp->rxRingSize - 1; i++) { + if (i < 3) { + printk("0x%8.8lx ", (u_long) & lp->rx_ring[i].status); + } + } + printk("...0x%8.8lx\n", (u_long) & lp->rx_ring[i].status); + printk("TX: "); + for (i = 0; i < lp->txRingSize - 1; i++) { + if (i < 3) { + printk("0x%8.8lx ", (u_long) & lp->tx_ring[i].status); + } + } + printk("...0x%8.8lx\n", (u_long) & lp->tx_ring[i].status); + printk("Descriptor buffers:\nRX: "); + for (i = 0; i < lp->rxRingSize - 1; i++) { + if (i < 3) { + printk("0x%8.8x ", le32_to_cpu(lp->rx_ring[i].buf)); + } + } + printk("...0x%8.8x\n", le32_to_cpu(lp->rx_ring[i].buf)); + printk("TX: "); + for (i = 0; i < lp->txRingSize - 1; i++) { + if (i < 3) { + printk("0x%8.8x ", le32_to_cpu(lp->tx_ring[i].buf)); + } + } + printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf)); + printk("Ring size: \nRX: %d\nTX: %d\n", + (short) lp->rxRingSize, + (short) lp->txRingSize); + } + return; } -static void -de4x5_dbg_open(struct device *dev) +static void de4x5_dbg_mii(struct device *dev, int k) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i; - - if (de4x5_debug & DEBUG_OPEN) { - printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq); - printk("\tphysical address: "); - for (i=0;i<6;i++) { - printk("%2.2x:",(short)dev->dev_addr[i]); - } - printk("\n"); - printk("Descriptor head addresses:\n"); - printk("\t0x%8.8lx 0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring); - printk("Descriptor addresses:\nRX: "); - for (i=0;irxRingSize-1;i++){ - if (i < 3) { - printk("0x%8.8lx ",(u_long)&lp->rx_ring[i].status); - } - } - printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status); - printk("TX: "); - for (i=0;itxRingSize-1;i++){ - if (i < 3) { - printk("0x%8.8lx ", (u_long)&lp->tx_ring[i].status); - } - } - printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status); - printk("Descriptor buffers:\nRX: "); - for (i=0;irxRingSize-1;i++){ - if (i < 3) { - printk("0x%8.8x ",le32_to_cpu(lp->rx_ring[i].buf)); - } - } - printk("...0x%8.8x\n",le32_to_cpu(lp->rx_ring[i].buf)); - printk("TX: "); - for (i=0;itxRingSize-1;i++){ - if (i < 3) { - printk("0x%8.8x ", le32_to_cpu(lp->tx_ring[i].buf)); - } - } - printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf)); - printk("Ring size: \nRX: %d\nTX: %d\n", - (short)lp->rxRingSize, - (short)lp->txRingSize); - } - - return; + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + u_long iobase = dev->base_addr; + + if (de4x5_debug & DEBUG_MII) { + printk("\nMII CR: %x\n", mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII)); + printk("MII SR: %x\n", mii_rd(MII_SR, lp->phy[k].addr, DE4X5_MII)); + printk("MII ID0: %x\n", mii_rd(MII_ID0, lp->phy[k].addr, DE4X5_MII)); + printk("MII ID1: %x\n", mii_rd(MII_ID1, lp->phy[k].addr, DE4X5_MII)); + if (lp->phy[k].id != BROADCOM_T4) { + printk("MII ANA: %x\n", mii_rd(0x04, lp->phy[k].addr, DE4X5_MII)); + printk("MII ANC: %x\n", mii_rd(0x05, lp->phy[k].addr, DE4X5_MII)); + } + printk("MII 16: %x\n", mii_rd(0x10, lp->phy[k].addr, DE4X5_MII)); + if (lp->phy[k].id != BROADCOM_T4) { + printk("MII 17: %x\n", mii_rd(0x11, lp->phy[k].addr, DE4X5_MII)); + printk("MII 18: %x\n", mii_rd(0x12, lp->phy[k].addr, DE4X5_MII)); + } else { + printk("MII 20: %x\n", mii_rd(0x14, lp->phy[k].addr, DE4X5_MII)); + } + } + return; } -static void -de4x5_dbg_mii(struct device *dev, int k) +static void de4x5_dbg_media(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int iobase = dev->base_addr; - - if (de4x5_debug & DEBUG_MII) { - printk("\nMII CR: %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII)); - printk("MII SR: %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII)); - printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII)); - printk("MII ID1: %x\n",mii_rd(MII_ID1,lp->phy[k].addr,DE4X5_MII)); - if (lp->phy[k].id != BROADCOM_T4) { - printk("MII ANA: %x\n",mii_rd(0x04,lp->phy[k].addr,DE4X5_MII)); - printk("MII ANC: %x\n",mii_rd(0x05,lp->phy[k].addr,DE4X5_MII)); - } - printk("MII 16: %x\n",mii_rd(0x10,lp->phy[k].addr,DE4X5_MII)); - if (lp->phy[k].id != BROADCOM_T4) { - printk("MII 17: %x\n",mii_rd(0x11,lp->phy[k].addr,DE4X5_MII)); - printk("MII 18: %x\n",mii_rd(0x12,lp->phy[k].addr,DE4X5_MII)); - } else { - printk("MII 20: %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII)); + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + + if (lp->media != lp->c_media) { + if (de4x5_debug & DEBUG_MEDIA) { + if (lp->chipset != DC21140) { + printk("%s: media is %s%s\n", dev->name, + (lp->media == NC ? "unconnected, link down or incompatible connection" : + (lp->media == TP ? "TP" : + (lp->media == ANS ? "TP/Nway" : + (lp->media == BNC ? "BNC" : + (lp->media == AUI ? "AUI" : + (lp->media == BNC_AUI ? "BNC/AUI" : + (lp->media == EXT_SIA ? "EXT SIA" : + (lp->media == _100Mb ? "100Mb/s" : + (lp->media == _10Mb ? "10Mb/s" : + "???" + ))))))))), + (lp->fdx?" full duplex.":".")); + } + } + lp->c_media = lp->media; } - } - - return; + return; } -static void -de4x5_dbg_media(struct device *dev) +static void de4x5_dbg_srom(struct de4x5_srom *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - - if (lp->media != lp->c_media) { - if (de4x5_debug & DEBUG_MEDIA) { - printk("%s: media is %s%s\n", dev->name, - (lp->media == NC ? "unconnected, link down or incompatible connection" : - (lp->media == TP ? "TP" : - (lp->media == ANS ? "TP/Nway" : - (lp->media == BNC ? "BNC" : - (lp->media == AUI ? "AUI" : - (lp->media == BNC_AUI ? "BNC/AUI" : - (lp->media == EXT_SIA ? "EXT SIA" : - (lp->media == _100Mb ? "100Mb/s" : - (lp->media == _10Mb ? "10Mb/s" : - "???" - ))))))))), (lp->fdx?" full duplex.":".")); + int i; + + if (de4x5_debug & DEBUG_SROM) { + printk("Sub-system Vendor ID: %04x\n", *((u_short *) p->sub_vendor_id)); + printk("Sub-system ID: %04x\n", *((u_short *) p->sub_system_id)); + printk("ID Block CRC: %02x\n", (u_char) (p->id_block_crc)); + printk("SROM version: %02x\n", (u_char) (p->version)); + printk("# controllers: %02x\n", (u_char) (p->num_controllers)); + + printk("Hardware Address: "); + for (i = 0; i < ETH_ALEN - 1; i++) { + printk("%02x:", (u_char) * (p->ieee_addr + i)); + } + printk("%02x\n", (u_char) * (p->ieee_addr + i)); + printk("CRC checksum: %04x\n", (u_short) (p->chksum)); + for (i = 0; i < 64; i++) { + printk("%3d %04x\n", i << 1, (u_short) * ((u_short *) p + i)); + } } - lp->c_media = lp->media; - } - - return; + return; } -static void -de4x5_dbg_srom(struct de4x5_srom *p) +static void de4x5_dbg_rx(struct sk_buff *skb, int len) { - int i; + int i, j; - if (de4x5_debug & DEBUG_SROM) { - printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id)); - printk("Sub-system ID: %04x\n", *((u_short *)p->sub_system_id)); - printk("ID Block CRC: %02x\n", (u_char)(p->id_block_crc)); - printk("SROM version: %02x\n", (u_char)(p->version)); - printk("# controllers: %02x\n", (u_char)(p->num_controllers)); - - printk("Hardware Address: "); - for (i=0;iieee_addr+i)); - } - printk("%02x\n", (u_char)*(p->ieee_addr+i)); - printk("CRC checksum: %04x\n", (u_short)(p->chksum)); - for (i=0; i<64; i++) { - printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i)); - } - } - - return; -} - -static void -de4x5_dbg_rx(struct sk_buff *skb, int len) -{ - int i, j; - - if (de4x5_debug & DEBUG_RX) { - printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", - (u_char)skb->data[0], - (u_char)skb->data[1], - (u_char)skb->data[2], - (u_char)skb->data[3], - (u_char)skb->data[4], - (u_char)skb->data[5], - (u_char)skb->data[6], - (u_char)skb->data[7], - (u_char)skb->data[8], - (u_char)skb->data[9], - (u_char)skb->data[10], - (u_char)skb->data[11], - (u_char)skb->data[12], - (u_char)skb->data[13], - len); if (de4x5_debug & DEBUG_RX) { - for (j=0; len>0;j+=16, len-=16) { - printk(" %03x: ",j); - for (i=0; i<16 && idata[i+j]); + printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", + (u_char) skb->data[0], + (u_char) skb->data[1], + (u_char) skb->data[2], + (u_char) skb->data[3], + (u_char) skb->data[4], + (u_char) skb->data[5], + (u_char) skb->data[6], + (u_char) skb->data[7], + (u_char) skb->data[8], + (u_char) skb->data[9], + (u_char) skb->data[10], + (u_char) skb->data[11], + (u_char) skb->data[12], + (u_char) skb->data[13], + len); + if (de4x5_debug & DEBUG_RX) { + for (j = 0; len > 0; j += 16, len -= 16) { + printk(" %03x: ", j); + for (i = 0; i < 16 && i < len; i++) { + printk("%02x ", (u_char) skb->data[i + j]); + } + printk("\n"); + } } - printk("\n"); - } } - } - - return; + return; } /* @@ -5254,242 +5244,248 @@ ** effective uid is checked in those cases. In the normal course of events ** this function is only used for my testing. */ -static int -de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) +static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data; - u_long iobase = dev->base_addr; - int i, j, status = 0; - s32 omr; - union { - u8 addr[144]; - u16 sval[72]; - u32 lval[36]; - } tmp; - - switch(ioc->cmd) { - case DE4X5_GET_HWADDR: /* Get the hardware address */ - ioc->len = ETH_ALEN; - status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len); - if (status) - break; - for (i=0; idev_addr[i]; - } - copy_to_user(ioc->data, tmp.addr, ioc->len); - - break; - case DE4X5_SET_HWADDR: /* Set the hardware address */ - status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN); - if (status) - break; - status = -EPERM; - if (!suser()) - break; - status = 0; - copy_from_user(tmp.addr, ioc->data, ETH_ALEN); - for (i=0; idev_addr[i] = tmp.addr[i]; - } - build_setup_frame(dev, PHYS_ADDR_ONLY); - /* Set up the descriptor and give ownership to the card */ - while (test_and_set_bit(0, (void *)&dev->tbusy) != 0); - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ - dev->tbusy = 0; /* Unlock the TX ring */ - - break; - case DE4X5_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { - omr = inl(DE4X5_OMR); - omr |= OMR_PR; - outl(omr, DE4X5_OMR); - dev->flags |= IFF_PROMISC; - } else { - status = -EPERM; - } - - break; - case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { - omr = inl(DE4X5_OMR); - omr &= ~OMR_PR; - outb(omr, DE4X5_OMR); - dev->flags &= ~IFF_PROMISC; - } else { - status = -EPERM; - } - - break; - case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */ - printk("%s: Boo!\n", dev->name); - - break; - case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ - if (suser()) { - omr = inl(DE4X5_OMR); - omr |= OMR_PM; - outl(omr, DE4X5_OMR); - } else { - status = -EPERM; - } - - break; - case DE4X5_GET_STATS: /* Get the driver statistics */ - ioc->len = sizeof(lp->pktStats); - status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len); - if (status) - break; - - cli(); - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - sti(); - - break; - case DE4X5_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { - cli(); - memset(&lp->pktStats, 0, sizeof(lp->pktStats)); - sti(); - } else { - status = -EPERM; - } - - break; - case DE4X5_GET_OMR: /* Get the OMR Register contents */ - tmp.addr[0] = inl(DE4X5_OMR); - if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) { - copy_to_user(ioc->data, tmp.addr, 1); - } - - break; - case DE4X5_SET_OMR: /* Set the OMR Register contents */ - if (suser()) { - if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) { - copy_from_user(tmp.addr, ioc->data, 1); - outl(tmp.addr[0], DE4X5_OMR); - } - } else { - status = -EPERM; - } - - break; - case DE4X5_GET_REG: /* Get the DE4X5 Registers */ - j = 0; - tmp.lval[0] = inl(DE4X5_STS); j+=4; - tmp.lval[1] = inl(DE4X5_BMR); j+=4; - tmp.lval[2] = inl(DE4X5_IMR); j+=4; - tmp.lval[3] = inl(DE4X5_OMR); j+=4; - tmp.lval[4] = inl(DE4X5_SISR); j+=4; - tmp.lval[5] = inl(DE4X5_SICR); j+=4; - tmp.lval[6] = inl(DE4X5_STRR); j+=4; - tmp.lval[7] = inl(DE4X5_SIGR); j+=4; - ioc->len = j; - if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - break; - + struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data; + u_long iobase = dev->base_addr; + int i, j, status = 0; + s32 omr; + union { + u8 addr[144]; + u16 sval[72]; + u32 lval[36]; + } tmp; + + switch (ioc->cmd) { + case DE4X5_GET_HWADDR: /* Get the hardware address */ + ioc->len = ETH_ALEN; + status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len); + if (status) + break; + for (i = 0; i < ETH_ALEN; i++) { + tmp.addr[i] = dev->dev_addr[i]; + } + copy_to_user(ioc->data, tmp.addr, ioc->len); + + break; + case DE4X5_SET_HWADDR: /* Set the hardware address */ + status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN); + if (status) + break; + status = -EPERM; + if (!suser()) + break; + status = 0; + copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) { + dev->dev_addr[i] = tmp.addr[i]; + } + build_setup_frame(dev, PHYS_ADDR_ONLY); + /* Set up the descriptor and give ownership to the card */ + while (test_and_set_bit(0, (void *)&dev->tbusy) != 0); + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + SETUP_FRAME_LEN, NULL); + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ + dev->tbusy = 0; /* Unlock the TX ring */ + + break; + case DE4X5_SET_PROM: /* Set Promiscuous Mode */ + if (suser()) { + omr = inl(DE4X5_OMR); + omr |= OMR_PR; + outl(omr, DE4X5_OMR); + dev->flags |= IFF_PROMISC; + } else { + status = -EPERM; + } + + break; + case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ + if (suser()) { + omr = inl(DE4X5_OMR); + omr &= ~OMR_PR; + outb(omr, DE4X5_OMR); + dev->flags &= ~IFF_PROMISC; + } else { + status = -EPERM; + } + + break; + case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */ + printk("%s: Boo!\n", dev->name); + + break; + case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ + if (suser()) { + omr = inl(DE4X5_OMR); + omr |= OMR_PM; + outl(omr, DE4X5_OMR); + } else { + status = -EPERM; + } + + break; + case DE4X5_GET_STATS: /* Get the driver statistics */ + ioc->len = sizeof(lp->pktStats); + status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len); + if (status) + break; + + cli(); + copy_to_user(ioc->data, &lp->pktStats, ioc->len); + sti(); + + break; + case DE4X5_CLR_STATS: /* Zero out the driver statistics */ + if (suser()) { + cli(); + memset(&lp->pktStats, 0, sizeof(lp->pktStats)); + sti(); + } else { + status = -EPERM; + } + + break; + case DE4X5_GET_OMR: /* Get the OMR Register contents */ + tmp.addr[0] = inl(DE4X5_OMR); + if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, 1))) { + copy_to_user(ioc->data, tmp.addr, 1); + } + break; + case DE4X5_SET_OMR: /* Set the OMR Register contents */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, 1))) { + copy_from_user(tmp.addr, ioc->data, 1); + outl(tmp.addr[0], DE4X5_OMR); + } + } else { + status = -EPERM; + } + + break; + case DE4X5_GET_REG: /* Get the DE4X5 Registers */ + j = 0; + tmp.lval[0] = inl(DE4X5_STS); + j += 4; + tmp.lval[1] = inl(DE4X5_BMR); + j += 4; + tmp.lval[2] = inl(DE4X5_IMR); + j += 4; + tmp.lval[3] = inl(DE4X5_OMR); + j += 4; + tmp.lval[4] = inl(DE4X5_SISR); + j += 4; + tmp.lval[5] = inl(DE4X5_SICR); + j += 4; + tmp.lval[6] = inl(DE4X5_STRR); + j += 4; + tmp.lval[7] = inl(DE4X5_SIGR); + j += 4; + ioc->len = j; + if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + break; + #define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */ /* - case DE4X5_DUMP: - j = 0; - tmp.addr[j++] = dev->irq; - for (i=0; idev_addr[i]; - } - tmp.addr[j++] = lp->rxRingSize; - tmp.lval[j>>2] = (long)lp->rx_ring; j+=4; - tmp.lval[j>>2] = (long)lp->tx_ring; j+=4; - - for (i=0;irxRingSize-1;i++){ - if (i < 3) { - tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; - } - } - tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; - for (i=0;itxRingSize-1;i++){ - if (i < 3) { - tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; - } - } - tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; - - for (i=0;irxRingSize-1;i++){ - if (i < 3) { - tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4; - } - } - tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4; - for (i=0;itxRingSize-1;i++){ - if (i < 3) { - tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4; - } - } - tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4; - - for (i=0;irxRingSize;i++){ - tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4; - } - for (i=0;itxRingSize;i++){ - tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4; - } - - tmp.lval[j>>2] = inl(DE4X5_BMR); j+=4; - tmp.lval[j>>2] = inl(DE4X5_TPD); j+=4; - tmp.lval[j>>2] = inl(DE4X5_RPD); j+=4; - tmp.lval[j>>2] = inl(DE4X5_RRBA); j+=4; - tmp.lval[j>>2] = inl(DE4X5_TRBA); j+=4; - tmp.lval[j>>2] = inl(DE4X5_STS); j+=4; - tmp.lval[j>>2] = inl(DE4X5_OMR); j+=4; - tmp.lval[j>>2] = inl(DE4X5_IMR); j+=4; - tmp.lval[j>>2] = lp->chipset; j+=4; - if (lp->chipset == DC21140) { - tmp.lval[j>>2] = gep_rd(dev); j+=4; - } else { - tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4; - tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4; - tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4; - tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; - } - tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; - if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { - tmp.lval[j>>2] = lp->active; j+=4; - tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - tmp.lval[j>>2]=mii_rd(MII_ID1,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - if (lp->phy[lp->active].id != BROADCOM_T4) { - tmp.lval[j>>2]=mii_rd(MII_ANA,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - tmp.lval[j>>2]=mii_rd(MII_ANLPA,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - } - tmp.lval[j>>2]=mii_rd(0x10,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - if (lp->phy[lp->active].id != BROADCOM_T4) { - tmp.lval[j>>2]=mii_rd(0x11,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - tmp.lval[j>>2]=mii_rd(0x12,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - } else { - tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4; - } - } - - tmp.addr[j++] = lp->txRingSize; - tmp.addr[j++] = dev->tbusy; - - ioc->len = j; - if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); + case DE4X5_DUMP: + j = 0; + tmp.addr[j++] = dev->irq; + for (i=0; idev_addr[i]; + } + tmp.addr[j++] = lp->rxRingSize; + tmp.lval[j>>2] = (long)lp->rx_ring; j+=4; + tmp.lval[j>>2] = (long)lp->tx_ring; j+=4; + + for (i=0;irxRingSize-1;i++){ + if (i < 3) { + tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; + } + } + tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; + for (i=0;itxRingSize-1;i++){ + if (i < 3) { + tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; + } + } + tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; + + for (i=0;irxRingSize-1;i++){ + if (i < 3) { + tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4; + } + } + tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4; + for (i=0;itxRingSize-1;i++){ + if (i < 3) { + tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4; + } + } + tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4; + + for (i=0;irxRingSize;i++){ + tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4; + } + for (i=0;itxRingSize;i++){ + tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4; + } + + tmp.lval[j>>2] = inl(DE4X5_BMR); j+=4; + tmp.lval[j>>2] = inl(DE4X5_TPD); j+=4; + tmp.lval[j>>2] = inl(DE4X5_RPD); j+=4; + tmp.lval[j>>2] = inl(DE4X5_RRBA); j+=4; + tmp.lval[j>>2] = inl(DE4X5_TRBA); j+=4; + tmp.lval[j>>2] = inl(DE4X5_STS); j+=4; + tmp.lval[j>>2] = inl(DE4X5_OMR); j+=4; + tmp.lval[j>>2] = inl(DE4X5_IMR); j+=4; + tmp.lval[j>>2] = lp->chipset; j+=4; + if (lp->chipset == DC21140) { + tmp.lval[j>>2] = gep_rd(dev); j+=4; + } else { + tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4; + tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4; + tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4; + tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; + } + tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; + if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { + tmp.lval[j>>2] = lp->active; j+=4; + tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + tmp.lval[j>>2]=mii_rd(MII_ID1,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + if (lp->phy[lp->active].id != BROADCOM_T4) { + tmp.lval[j>>2]=mii_rd(MII_ANA,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + tmp.lval[j>>2]=mii_rd(MII_ANLPA,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + } + tmp.lval[j>>2]=mii_rd(0x10,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + if (lp->phy[lp->active].id != BROADCOM_T4) { + tmp.lval[j>>2]=mii_rd(0x11,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + tmp.lval[j>>2]=mii_rd(0x12,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + } else { + tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4; + } + } + + tmp.addr[j++] = lp->txRingSize; + tmp.addr[j++] = dev->tbusy; + + ioc->len = j; + if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + + break; + */ + default: + status = -EOPNOTSUPP; } - - break; -*/ - default: - status = -EOPNOTSUPP; - } - - return status; + + return status; } #ifdef MODULE @@ -5500,97 +5496,100 @@ */ #define LP(a) ((struct de4x5_private *)(a)) static struct device *mdev = NULL; -static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED */ +static int io = 0x0; /* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED */ #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) MODULE_PARM(io, "i"); #endif /* LINUX_VERSION_CODE */ -int -init_module(void) +int init_module(void) { - int i, num, status = -EIO; - struct device *p; + int i, num, status = -EIO; + struct device *p; - num = count_adapters(); + num = count_adapters(); - for (i=0; ipriv) { /* Private areas allocated? */ - struct de4x5_private *lp = (struct de4x5_private *)p->priv; + if (p->priv) { /* Private areas allocated? */ + struct de4x5_private *lp = (struct de4x5_private *) p->priv; - next = lp->next_module; - if (lp->cache.buf) { /* MAC buffers allocated? */ - kfree(lp->cache.buf); /* Free the MAC buffers */ + next = lp->next_module; + if (lp->cache.buf) { /* MAC buffers allocated? */ + kfree(lp->cache.buf); /* Free the MAC buffers */ + } + kfree(lp->cache.priv); /* Free the private area */ + release_region(p->base_addr, (lp->bus == PCI ? + DE4X5_PCI_TOTAL_SIZE : + DE4X5_EISA_TOTAL_SIZE)); + } + unregister_netdev(p); + kfree(p); /* Free the device structure */ + + return next; +} + +static int count_adapters(void) +{ + int i, j = 0; + char name[DE4X5_STRLEN]; + u_char pb, dev_fn, dev_num; + u_short dev_id, vendor; + u_int class = DE4X5_CLASS_CODE; + u_int device; +#ifndef __sparc_v9__ + u_int iobase = 0x1000; + + for (i=1; icache.priv); /* Free the private area */ - release_region(p->base_addr, (lp->bus == PCI ? - DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE)); - } - unregister_netdev(p); - kfree(p); /* Free the device structure */ - - return next; -} +#endif + if (!pcibios_present()) + return j; -static int -count_adapters(void) -{ - int i, j; - char name[DE4X5_STRLEN]; - u_char pb, dev_fn, dev_num; - u_short dev_id, vendor; - u_int class = DE4X5_CLASS_CODE; - u_int device, iobase = 0x1000; - - for (j=0, i=1; iname = (char *)(new + 1); - new->base_addr = iobase; /* assign the io address */ - new->init = init; /* initialisation routine */ - } + new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); + if (new == NULL) { + printk("de4x5.c: Device not initialised, insufficient memory\n"); + return NULL; + } else { + memset((char *)new, 0, sizeof(struct device)+8); + new->name = (char *)(new + 1); + new->base_addr = iobase; /* assign the io address */ + new->init = init; /* initialisation routine */ + } - return new; + return new; } -#endif /* MODULE */ - +#endif /* MODULE */ + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" diff -u --recursive --new-file v2.1.66/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h --- v2.1.66/linux/drivers/net/de4x5.h Mon Nov 17 18:47:21 1997 +++ linux/drivers/net/de4x5.h Sat Nov 29 10:33:19 1997 @@ -166,7 +166,11 @@ /* ** PCI Configuration Base I/O Address Register (PCI_CBIO) */ +#ifdef __sparc_v9__ +#define CBIO_MASK 0xffffffffffffff80 /* Base I/O Address Mask */ +#else #define CBIO_MASK 0xffffff80 /* Base I/O Address Mask */ +#endif #define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */ /* @@ -903,7 +907,6 @@ #define OPEN 2 /* Running */ /* -** Various wait times */ #define PDET_LINK_WAIT 1200 /* msecs to wait for link detect bits */ #define ANS_FINISH_WAIT 1000 /* msecs to wait for link detect bits */ @@ -933,7 +936,7 @@ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ - outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\ + outl(omr | lp->infoblock_csr6, DE4X5_OMR);\ } else {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ @@ -961,7 +964,7 @@ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ - outl(omr | lp->infoblock_csr6, DE4X5_OMR);\ + outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\ } else {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ @@ -978,7 +981,7 @@ outl(omr, DE4X5_OMR);\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ - outl(omr, DE4X5_OMR);\ + outl(omr | lp->infoblock_csr6, DE4X5_OMR);\ } else {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\ diff -u --recursive --new-file v2.1.66/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.1.66/linux/drivers/net/defxx.c Thu Sep 4 17:07:30 1997 +++ linux/drivers/net/defxx.c Sat Nov 29 10:33:19 1997 @@ -3208,7 +3208,7 @@ printk("%s: Invalid packet length - %u bytes\n", dev->name, skb->len); bp->xmt_length_errors++; /* bump error counter */ - dev_tint(dev); /* dequeue packets from xmt queue and send them */ + mark_bh(NET_BH); dev_kfree_skb(skb, FREE_WRITE); return(0); /* return "success" */ } diff -u --recursive --new-file v2.1.66/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.1.66/linux/drivers/net/depca.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/depca.c Sat Nov 29 10:33:19 1997 @@ -1,210 +1,210 @@ /* depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux. - Written 1994, 1995 by David C. Davies. + Written 1994, 1995 by David C. Davies. - Copyright 1994 David C. Davies - and - United States Government - (as represented by the Director, National Security Agency). - - Copyright 1995 Digital Equipment Corporation. - - - This software may be used and distributed according to the terms of - the GNU Public License, incorporated herein by reference. - - This driver is written for the Digital Equipment Corporation series - of DEPCA and EtherWORKS ethernet cards: - - DEPCA (the original) - DE100 - DE101 - DE200 Turbo - DE201 Turbo - DE202 Turbo (TP BNC) - DE210 - DE422 (EISA) - - The driver has been tested on DE100, DE200 and DE202 cards in a - relatively busy network. The DE422 has been tested a little. - - This driver will NOT work for the DE203, DE204 and DE205 series of - cards, since they have a new custom ASIC in place of the AMD LANCE - chip. See the 'ewrk3.c' driver in the Linux source tree for running - those cards. - - I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from) - a DECstation 5000/200. - - The author may be reached at davies@maniac.ultranet.com - - ========================================================================= - - The driver was originally based on the 'lance.c' driver from Donald - Becker which is included with the standard driver distribution for - linux. V0.4 is a complete re-write with only the kernel interface - remaining from the original code. - - 1) Lance.c code in /linux/drivers/net/ - 2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook", - AMD, 1992 [(800) 222-9323]. - 3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", - AMD, Pub. #17881, May 1993. - 4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA", - AMD, Pub. #16907, May 1992 - 5) "DEC EtherWORKS LC Ethernet Controller Owners Manual", - Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003 - 6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual", - Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003 - 7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR - Digital Equipment Corporation, 1989 - 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual", - Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001 - - - Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this - driver. - - The original DEPCA card requires that the ethernet ROM address counter - be enabled to count and has an 8 bit NICSR. The ROM counter enabling is - only done when a 0x08 is read as the first address octet (to minimise - the chances of writing over some other hardware's I/O register). The - NICSR accesses have been changed to byte accesses for all the cards - supported by this driver, since there is only one useful bit in the MSB - (remote boot timeout) and it is not used. Also, there is a maximum of - only 48kB network RAM for this card. My thanks to Torbjorn Lindh for - help debugging all this (and holding my feet to the fire until I got it - right). - - The DE200 series boards have on-board 64kB RAM for use as a shared - memory network buffer. Only the DE100 cards make use of a 2kB buffer - mode which has not been implemented in this driver (only the 32kB and - 64kB modes are supported [16kB/48kB for the original DEPCA]). - - At the most only 2 DEPCA cards can be supported on the ISA bus because - there is only provision for two I/O base addresses on each card (0x300 - and 0x200). The I/O address is detected by searching for a byte sequence - in the Ethernet station address PROM at the expected I/O address for the - Ethernet PROM. The shared memory base address is 'autoprobed' by - looking for the self test PROM and detecting the card name. When a - second DEPCA is detected, information is placed in the base_addr - variable of the next device structure (which is created if necessary), - thus enabling ethif_probe initialization for the device. More than 2 - EISA cards can be supported, but care will be needed assigning the - shared memory to ensure that each slot has the correct IRQ, I/O address - and shared memory address assigned. - - ************************************************************************ - - NOTE: If you are using two ISA DEPCAs, it is important that you assign - the base memory addresses correctly. The driver autoprobes I/O 0x300 - then 0x200. The base memory address for the first device must be less - than that of the second so that the auto probe will correctly assign the - I/O and memory addresses on the same card. I can't think of a way to do - this unambiguously at the moment, since there is nothing on the cards to - tie I/O and memory information together. - - I am unable to test 2 cards together for now, so this code is - unchecked. All reports, good or bad, are welcome. - - ************************************************************************ - - The board IRQ setting must be at an unused IRQ which is auto-probed - using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are - {2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is - really IRQ9 in machines with 16 IRQ lines. - - No 16MB memory limitation should exist with this driver as DMA is not - used and the common memory area is in low memory on the network card (my - current system has 20MB and I've not had problems yet). - - The ability to load this driver as a loadable module has been added. To - utilise this ability, you have to do <8 things: - - 0) have a copy of the loadable modules code installed on your system. - 1) copy depca.c from the /linux/drivers/net directory to your favourite - temporary directory. - 2) if you wish, edit the source code near line 1530 to reflect the I/O - address and IRQ you're using (see also 5). - 3) compile depca.c, but include -DMODULE in the command line to ensure - that the correct bits are compiled (see end of source code). - 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a - kernel with the depca configuration turned off and reboot. - 5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100] - [Alan Cox: Changed the code to allow command line irq/io assignments] - [Dave Davies: Changed the code to allow command line mem/name - assignments] - 6) run the net startup bits for your eth?? interface manually - (usually /etc/rc.inet[12] at boot time). - 7) enjoy! - - Note that autoprobing is not allowed in loadable modules - the system is - already up and running and you're messing with interrupts. - - To unload a module, turn off the associated interface - 'ifconfig eth?? down' then 'rmmod depca'. - - To assign a base memory address for the shared memory when running as a - loadable module, see 5 above. To include the adapter name (if you have - no PROM but know the card name) also see 5 above. Note that this last - option will not work with kernel built-in depca's. - - The shared memory assignment for a loadable module makes sense to avoid - the 'memory autoprobe' picking the wrong shared memory (for the case of - 2 depca's in a PC). - - - TO DO: - ------ - - - Revision History - ---------------- - - Version Date Description - - 0.1 25-jan-94 Initial writing. - 0.2 27-jan-94 Added LANCE TX hardware buffer chaining. - 0.3 1-feb-94 Added multiple DEPCA support. - 0.31 4-feb-94 Added DE202 recognition. - 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support. - 0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable. - Add jabber packet fix from murf@perftech.com - and becker@super.org - 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access. - 0.35 8-mar-94 Added DE201 recognition. Tidied up. - 0.351 30-apr-94 Added EISA support. Added DE422 recognition. - 0.36 16-may-94 DE422 fix released. - 0.37 22-jul-94 Added MODULE support - 0.38 15-aug-94 Added DBR ROM switch in depca_close(). - Multi DEPCA bug fix. - 0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0. - 0.381 12-dec-94 Added DE101 recognition, fix multicast bug. - 0.382 9-feb-95 Fix recognition bug reported by . - 0.383 22-feb-95 Fix for conflict with VESA SCSI reported by - - 0.384 17-mar-95 Fix a ring full bug reported by - 0.385 3-apr-95 Fix a recognition bug reported by - - 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility - 0.40 25-May-95 Rewrite for portability & updated. - ALPHA support from - 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from - suggestion by - 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable - modules. - Add 'adapter_name' for loadable modules when no PROM. - Both above from a suggestion by - . - Add new multicasting code. - 0.421 22-Apr-96 Fix alloc_device() bug - 0.422 29-Apr-96 Fix depca_hw_init() bug - 0.423 7-Jun-96 Fix module load bug - 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c + Copyright 1994 David C. Davies + and + United States Government + (as represented by the Director, National Security Agency). + + Copyright 1995 Digital Equipment Corporation. + + + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. + + This driver is written for the Digital Equipment Corporation series + of DEPCA and EtherWORKS ethernet cards: + + DEPCA (the original) + DE100 + DE101 + DE200 Turbo + DE201 Turbo + DE202 Turbo (TP BNC) + DE210 + DE422 (EISA) + + The driver has been tested on DE100, DE200 and DE202 cards in a + relatively busy network. The DE422 has been tested a little. + + This driver will NOT work for the DE203, DE204 and DE205 series of + cards, since they have a new custom ASIC in place of the AMD LANCE + chip. See the 'ewrk3.c' driver in the Linux source tree for running + those cards. + + I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from) + a DECstation 5000/200. + + The author may be reached at davies@maniac.ultranet.com + + ========================================================================= + + The driver was originally based on the 'lance.c' driver from Donald + Becker which is included with the standard driver distribution for + linux. V0.4 is a complete re-write with only the kernel interface + remaining from the original code. + + 1) Lance.c code in /linux/drivers/net/ + 2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook", + AMD, 1992 [(800) 222-9323]. + 3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", + AMD, Pub. #17881, May 1993. + 4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA", + AMD, Pub. #16907, May 1992 + 5) "DEC EtherWORKS LC Ethernet Controller Owners Manual", + Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003 + 6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual", + Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003 + 7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR + Digital Equipment Corporation, 1989 + 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual", + Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001 + + + Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this + driver. + + The original DEPCA card requires that the ethernet ROM address counter + be enabled to count and has an 8 bit NICSR. The ROM counter enabling is + only done when a 0x08 is read as the first address octet (to minimise + the chances of writing over some other hardware's I/O register). The + NICSR accesses have been changed to byte accesses for all the cards + supported by this driver, since there is only one useful bit in the MSB + (remote boot timeout) and it is not used. Also, there is a maximum of + only 48kB network RAM for this card. My thanks to Torbjorn Lindh for + help debugging all this (and holding my feet to the fire until I got it + right). + + The DE200 series boards have on-board 64kB RAM for use as a shared + memory network buffer. Only the DE100 cards make use of a 2kB buffer + mode which has not been implemented in this driver (only the 32kB and + 64kB modes are supported [16kB/48kB for the original DEPCA]). + + At the most only 2 DEPCA cards can be supported on the ISA bus because + there is only provision for two I/O base addresses on each card (0x300 + and 0x200). The I/O address is detected by searching for a byte sequence + in the Ethernet station address PROM at the expected I/O address for the + Ethernet PROM. The shared memory base address is 'autoprobed' by + looking for the self test PROM and detecting the card name. When a + second DEPCA is detected, information is placed in the base_addr + variable of the next device structure (which is created if necessary), + thus enabling ethif_probe initialization for the device. More than 2 + EISA cards can be supported, but care will be needed assigning the + shared memory to ensure that each slot has the correct IRQ, I/O address + and shared memory address assigned. + + ************************************************************************ + + NOTE: If you are using two ISA DEPCAs, it is important that you assign + the base memory addresses correctly. The driver autoprobes I/O 0x300 + then 0x200. The base memory address for the first device must be less + than that of the second so that the auto probe will correctly assign the + I/O and memory addresses on the same card. I can't think of a way to do + this unambiguously at the moment, since there is nothing on the cards to + tie I/O and memory information together. + + I am unable to test 2 cards together for now, so this code is + unchecked. All reports, good or bad, are welcome. + + ************************************************************************ + + The board IRQ setting must be at an unused IRQ which is auto-probed + using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are + {2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is + really IRQ9 in machines with 16 IRQ lines. + + No 16MB memory limitation should exist with this driver as DMA is not + used and the common memory area is in low memory on the network card (my + current system has 20MB and I've not had problems yet). + + The ability to load this driver as a loadable module has been added. To + utilise this ability, you have to do <8 things: + + 0) have a copy of the loadable modules code installed on your system. + 1) copy depca.c from the /linux/drivers/net directory to your favourite + temporary directory. + 2) if you wish, edit the source code near line 1530 to reflect the I/O + address and IRQ you're using (see also 5). + 3) compile depca.c, but include -DMODULE in the command line to ensure + that the correct bits are compiled (see end of source code). + 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a + kernel with the depca configuration turned off and reboot. + 5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100] + [Alan Cox: Changed the code to allow command line irq/io assignments] + [Dave Davies: Changed the code to allow command line mem/name + assignments] + 6) run the net startup bits for your eth?? interface manually + (usually /etc/rc.inet[12] at boot time). + 7) enjoy! + + Note that autoprobing is not allowed in loadable modules - the system is + already up and running and you're messing with interrupts. + + To unload a module, turn off the associated interface + 'ifconfig eth?? down' then 'rmmod depca'. + + To assign a base memory address for the shared memory when running as a + loadable module, see 5 above. To include the adapter name (if you have + no PROM but know the card name) also see 5 above. Note that this last + option will not work with kernel built-in depca's. + + The shared memory assignment for a loadable module makes sense to avoid + the 'memory autoprobe' picking the wrong shared memory (for the case of + 2 depca's in a PC). + + + TO DO: + ------ + + + Revision History + ---------------- + + Version Date Description + + 0.1 25-jan-94 Initial writing. + 0.2 27-jan-94 Added LANCE TX hardware buffer chaining. + 0.3 1-feb-94 Added multiple DEPCA support. + 0.31 4-feb-94 Added DE202 recognition. + 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support. + 0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable. + Add jabber packet fix from murf@perftech.com + and becker@super.org + 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access. + 0.35 8-mar-94 Added DE201 recognition. Tidied up. + 0.351 30-apr-94 Added EISA support. Added DE422 recognition. + 0.36 16-may-94 DE422 fix released. + 0.37 22-jul-94 Added MODULE support + 0.38 15-aug-94 Added DBR ROM switch in depca_close(). + Multi DEPCA bug fix. + 0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0. + 0.381 12-dec-94 Added DE101 recognition, fix multicast bug. + 0.382 9-feb-95 Fix recognition bug reported by . + 0.383 22-feb-95 Fix for conflict with VESA SCSI reported by + + 0.384 17-mar-95 Fix a ring full bug reported by + 0.385 3-apr-95 Fix a recognition bug reported by + + 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility + 0.40 25-May-95 Rewrite for portability & updated. + ALPHA support from + 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from + suggestion by + 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable + modules. + Add 'adapter_name' for loadable modules when no PROM. + Both above from a suggestion by + . + Add new multicasting code. + 0.421 22-Apr-96 Fix alloc_device() bug + 0.422 29-Apr-96 Fix depca_hw_init() bug + 0.423 7-Jun-96 Fix module load bug + 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c - ========================================================================= -*/ + ========================================================================= + */ static const char *version = "depca.c:v0.43 96/8/16 davies@maniac.ultranet.com\n"; @@ -242,1643 +242,1650 @@ static int depca_debug = 1; #endif -#define DEPCA_NDA 0xffe0 /* No Device Address */ +#define DEPCA_NDA 0xffe0 /* No Device Address */ /* -** Ethernet PROM defines -*/ + ** Ethernet PROM defines + */ #define PROBE_LENGTH 32 #define ETH_PROM_SIG 0xAA5500FFUL /* -** Set the number of Tx and Rx buffers. Ensure that the memory requested -** here is <= to the amount of shared memory set up by the board switches. -** The number of descriptors MUST BE A POWER OF 2. -** -** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ) -*/ -#define NUM_RX_DESC 8 /* Number of RX descriptors */ -#define NUM_TX_DESC 8 /* Number of TX descriptors */ -#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */ -#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */ - -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - -/* -** EISA bus defines -*/ -#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ + ** Set the number of Tx and Rx buffers. Ensure that the memory requested + ** here is <= to the amount of shared memory set up by the board switches. + ** The number of descriptors MUST BE A POWER OF 2. + ** + ** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ) + */ +#define NUM_RX_DESC 8 /* Number of RX descriptors */ +#define NUM_TX_DESC 8 /* Number of TX descriptors */ +#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */ +#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */ + +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + +/* + ** EISA bus defines + */ +#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ #define MAX_EISA_SLOTS 16 #define EISA_SLOT_INC 0x1000 /* -** ISA Bus defines -*/ + ** ISA Bus defines + */ #define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000} #define DEPCA_IO_PORTS {0x300, 0x200, 0} #define DEPCA_TOTAL_SIZE 0x10 static short mem_chkd = 0; /* -** Name <-> Adapter mapping -*/ + ** Name <-> Adapter mapping + */ #define DEPCA_SIGNATURE {"DEPCA",\ "DE100","DE101",\ "DE200","DE201","DE202",\ "DE210",\ "DE422",\ ""} -static enum {DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown} adapter; +static enum { + DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown +} adapter; /* -** Miscellaneous info... -*/ + ** Miscellaneous info... + */ #define DEPCA_STRLEN 16 #define MAX_NUM_DEPCAS 2 /* -** Memory Alignment. Each descriptor is 4 longwords long. To force a -** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and -** DESC_ALIGN. ALIGN aligns the start address of the private memory area -** and hence the RX descriptor ring's first entry. -*/ -#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ -#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */ -#define ALIGN ALIGN8 /* Keep the LANCE happy... */ + ** Memory Alignment. Each descriptor is 4 longwords long. To force a + ** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and + ** DESC_ALIGN. ALIGN aligns the start address of the private memory area + ** and hence the RX descriptor ring's first entry. + */ +#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */ +#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */ +#define ALIGN ALIGN8 /* Keep the LANCE happy... */ /* -** The DEPCA Rx and Tx ring descriptors. -*/ + ** The DEPCA Rx and Tx ring descriptors. + */ struct depca_rx_desc { - volatile s32 base; - s16 buf_length; /* This length is negative 2's complement! */ - s16 msg_length; /* This length is "normal". */ + volatile s32 base; + s16 buf_length; /* This length is negative 2's complement! */ + s16 msg_length; /* This length is "normal". */ }; struct depca_tx_desc { - volatile s32 base; - s16 length; /* This length is negative 2's complement! */ - s16 misc; /* Errors and TDR info */ + volatile s32 base; + s16 length; /* This length is negative 2's complement! */ + s16 misc; /* Errors and TDR info */ }; -#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM +#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM to LANCE memory address space */ /* -** The Lance initialization block, described in databook, in common memory. -*/ + ** The Lance initialization block, described in databook, in common memory. + */ struct depca_init { - u16 mode; /* Mode register */ - u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */ - u8 mcast_table[8]; /* Multicast Hash Table. */ - u32 rx_ring; /* Rx ring base pointer & ring length */ - u32 tx_ring; /* Tx ring base pointer & ring length */ + u16 mode; /* Mode register */ + u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */ + u8 mcast_table[8]; /* Multicast Hash Table. */ + u32 rx_ring; /* Rx ring base pointer & ring length */ + u32 tx_ring; /* Tx ring base pointer & ring length */ }; #define DEPCA_PKT_STAT_SZ 16 -#define DEPCA_PKT_BIN_SZ 128 /* Should be >=100 unless you - increase DEPCA_PKT_STAT_SZ */ +#define DEPCA_PKT_BIN_SZ 128 /* Should be >=100 unless you + increase DEPCA_PKT_STAT_SZ */ struct depca_private { - char devname[DEPCA_STRLEN]; /* Device Product String */ - char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */ - char adapter; /* Adapter type */ - struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */ - struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */ - struct depca_init init_block;/* Shadow Initialization block */ - char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */ - char *tx_memcpy[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */ - u_long bus_offset; /* (E)ISA bus address offset vs LANCE */ - u_long sh_mem; /* Physical start addr of shared mem area */ - u_long dma_buffs; /* LANCE Rx and Tx buffers start address. */ - int rx_new, tx_new; /* The next free ring entry */ - int rx_old, tx_old; /* The ring entries to be free()ed. */ - struct net_device_stats stats; - struct { /* Private stats counters */ - u32 bins[DEPCA_PKT_STAT_SZ]; - u32 unicast; - u32 multicast; - u32 broadcast; - u32 excessive_collisions; - u32 tx_underruns; - u32 excessive_underruns; - } pktStats; - int txRingMask; /* TX ring mask */ - int rxRingMask; /* RX ring mask */ - s32 rx_rlen; /* log2(rxRingMask+1) for the descriptors */ - s32 tx_rlen; /* log2(txRingMask+1) for the descriptors */ + char devname[DEPCA_STRLEN]; /* Device Product String */ + char adapter_name[DEPCA_STRLEN]; /* /proc/ioports string */ + char adapter; /* Adapter type */ + struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */ + struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */ + struct depca_init init_block; /* Shadow Initialization block */ + char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */ + char *tx_memcpy[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */ + u_long bus_offset; /* (E)ISA bus address offset vs LANCE */ + u_long sh_mem; /* Physical start addr of shared mem area */ + u_long dma_buffs; /* LANCE Rx and Tx buffers start address. */ + int rx_new, tx_new; /* The next free ring entry */ + int rx_old, tx_old; /* The ring entries to be free()ed. */ + struct net_device_stats stats; + struct { /* Private stats counters */ + u32 bins[DEPCA_PKT_STAT_SZ]; + u32 unicast; + u32 multicast; + u32 broadcast; + u32 excessive_collisions; + u32 tx_underruns; + u32 excessive_underruns; + } pktStats; + int txRingMask; /* TX ring mask */ + int rxRingMask; /* RX ring mask */ + s32 rx_rlen; /* log2(rxRingMask+1) for the descriptors */ + s32 tx_rlen; /* log2(txRingMask+1) for the descriptors */ }; /* -** The transmit ring full condition is described by the tx_old and tx_new -** pointers by: -** tx_old = tx_new Empty ring -** tx_old = tx_new+1 Full ring -** tx_old+txRingMask = tx_new Full ring (wrapped condition) -*/ + ** The transmit ring full condition is described by the tx_old and tx_new + ** pointers by: + ** tx_old = tx_new Empty ring + ** tx_old = tx_new+1 Full ring + ** tx_old+txRingMask = tx_new Full ring (wrapped condition) + */ #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ lp->tx_old+lp->txRingMask-lp->tx_new:\ lp->tx_old -lp->tx_new-1) /* -** Public Functions -*/ -static int depca_open(struct device *dev); -static int depca_start_xmit(struct sk_buff *skb, struct device *dev); -static void depca_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static int depca_close(struct device *dev); -static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd); + ** Public Functions + */ +static int depca_open(struct device *dev); +static int depca_start_xmit(struct sk_buff *skb, struct device *dev); +static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int depca_close(struct device *dev); +static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *depca_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev); +static void set_multicast_list(struct device *dev); /* -** Private functions -*/ -static int depca_hw_init(struct device *dev, u_long ioaddr); -static void depca_init_ring(struct device *dev); -static int depca_rx(struct device *dev); -static int depca_tx(struct device *dev); - -static void LoadCSRs(struct device *dev); -static int InitRestartDepca(struct device *dev); -static void DepcaSignature(char *name, u_long paddr); -static int DevicePresent(u_long ioaddr); -static int get_hw_addr(struct device *dev); -static int EISA_signature(char *name, s32 eisa_id); -static void SetMulticastFilter(struct device *dev); -static void isa_probe(struct device *dev, u_long iobase); -static void eisa_probe(struct device *dev, u_long iobase); + ** Private functions + */ +static int depca_hw_init(struct device *dev, u_long ioaddr); +static void depca_init_ring(struct device *dev); +static int depca_rx(struct device *dev); +static int depca_tx(struct device *dev); + +static void LoadCSRs(struct device *dev); +static int InitRestartDepca(struct device *dev); +static void DepcaSignature(char *name, u_long paddr); +static int DevicePresent(u_long ioaddr); +static int get_hw_addr(struct device *dev); +static int EISA_signature(char *name, s32 eisa_id); +static void SetMulticastFilter(struct device *dev); +static void isa_probe(struct device *dev, u_long iobase); +static void eisa_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); -static int depca_dev_index(char *s); -static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)); -static int load_packet(struct device *dev, struct sk_buff *skb); -static void depca_dbg_open(struct device *dev); +static int depca_dev_index(char *s); +static struct device *insert_device(struct device *dev, u_long iobase, int (*init) (struct device *)); +static int load_packet(struct device *dev, struct sk_buff *skb); +static void depca_dbg_open(struct device *dev); #ifdef MODULE -int init_module(void); -void cleanup_module(void); -static int autoprobed = 1, loading_module = 1; -# else -static u_char de1xx_irq[] __initdata = {2,3,4,5,7,9,0}; -static u_char de2xx_irq[] __initdata = {5,9,10,11,15,0}; -static u_char de422_irq[] __initdata = {5,9,10,11,0}; +int init_module(void); +void cleanup_module(void); +static int autoprobed = 1, loading_module = 1; +#else +static u_char de1xx_irq[] __initdata = +{2, 3, 4, 5, 7, 9, 0}; +static u_char de2xx_irq[] __initdata = +{5, 9, 10, 11, 15, 0}; +static u_char de422_irq[] __initdata = +{5, 9, 10, 11, 0}; static u_char *depca_irq; -static int autoprobed = 0, loading_module = 0; -#endif /* MODULE */ +static int autoprobed = 0, loading_module = 0; +#endif /* MODULE */ -static char name[DEPCA_STRLEN]; -static int num_depcas = 0, num_eth = 0; -static int mem=0; /* For loadable module assignment - use insmod mem=0x????? .... */ -static char *adapter_name = '\0'; /* If no PROM when loadable module - use insmod adapter_name=DE??? ... - */ +static char name[DEPCA_STRLEN]; +static int num_depcas = 0, num_eth = 0; +static int mem = 0; /* For loadable module assignment + use insmod mem=0x????? .... */ +static char *adapter_name = '\0'; /* If no PROM when loadable module + use insmod adapter_name=DE??? ... + */ /* -** Miscellaneous defines... -*/ + ** Miscellaneous defines... + */ #define STOP_DEPCA \ outw(CSR0, DEPCA_ADDR);\ outw(STOP, DEPCA_DATA) - + __initfunc(int depca_probe(struct device *dev)) { - int tmp = num_depcas, status = -ENODEV; - u_long iobase = dev->base_addr; + int tmp = num_depcas, status = -ENODEV; + u_long iobase = dev->base_addr; - if ((iobase == 0) && loading_module){ - printk("Autoprobing is not supported when loading a module based driver.\n"); - status = -EIO; - } else { - isa_probe(dev, iobase); - eisa_probe(dev, iobase); - - if ((tmp == num_depcas) && (iobase != 0) && loading_module) { - printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, - iobase); - } - - /* - ** Walk the device list to check that at least one device - ** initialised OK - */ - for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); - - if (dev->priv) status = 0; - if (iobase == 0) autoprobed = 1; - } + if ((iobase == 0) && loading_module) { + printk("Autoprobing is not supported when loading a module based driver.\n"); + status = -EIO; + } else { + isa_probe(dev, iobase); + eisa_probe(dev, iobase); - return status; + if ((tmp == num_depcas) && (iobase != 0) && loading_module) { + printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, + iobase); + } + /* + ** Walk the device list to check that at least one device + ** initialised OK + */ + for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); + + if (dev->priv) + status = 0; + if (iobase == 0) + autoprobed = 1; + } + + return status; } __initfunc(static int -depca_hw_init(struct device *dev, u_long ioaddr)) + depca_hw_init(struct device *dev, u_long ioaddr)) { - struct depca_private *lp; - int i, j, offset, netRAM, mem_len, status=0; - s16 nicsr; - u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES; - - STOP_DEPCA; - - nicsr = inb(DEPCA_NICSR); - nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM); - outb(nicsr, DEPCA_NICSR); - - if (inw(DEPCA_DATA) == STOP) { - do { - strcpy(name, (adapter_name ? adapter_name : "")); - mem_start = (mem ? mem & 0xf0000 : mem_base[mem_chkd++]); - DepcaSignature(name, mem_start); - } while (!mem && mem_base[mem_chkd] && (adapter == unknown)); - - if ((adapter != unknown) && mem_start) { /* found a DEPCA device */ - dev->base_addr = ioaddr; - - if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */ - printk("%s: %s at 0x%04lx (EISA slot %d)", - dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f)); - } else { /* ISA port address */ - printk("%s: %s at 0x%04lx", dev->name, name, ioaddr); - } - - printk(", h/w address "); - status = get_hw_addr(dev); - for (i=0; idev_addr[i]); - } - printk("%2.2x", dev->dev_addr[i]); - - if (status == 0) { - /* Set up the maximum amount of network RAM(kB) */ - netRAM = ((adapter != DEPCA) ? 64 : 48); - if ((nicsr & _128KB) && (adapter == de422)) netRAM = 128; - offset = 0x0000; - - /* Shared Memory Base Address */ - if (nicsr & BUF) { - offset = 0x8000; /* 32kbyte RAM offset*/ - nicsr &= ~BS; /* DEPCA RAM in top 32k */ - netRAM -= 32; - } - mem_start += offset; /* (E)ISA start address */ - if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) + - NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) + - sizeof(struct depca_init))) <= - (netRAM<<10)) { - printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start); - - /* Enable the shadow RAM. */ - if (adapter != DEPCA) { - nicsr |= SHE; - outb(nicsr, DEPCA_NICSR); - } - - /* Define the device private memory */ - dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - lp = (struct depca_private *)dev->priv; - memset((char *)dev->priv, 0, sizeof(struct depca_private)); - lp->adapter = adapter; - sprintf(lp->adapter_name,"%s (%s)", name, dev->name); - request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name); - - /* Initialisation Block */ - lp->sh_mem = mem_start; - mem_start += sizeof(struct depca_init); - - /* Tx & Rx descriptors (aligned to a quadword boundary) */ - mem_start = (mem_start + ALIGN) & ~ALIGN; - lp->rx_ring = (struct depca_rx_desc *)mem_start; - - mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC); - lp->tx_ring = (struct depca_tx_desc *)mem_start; - - mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC); - lp->bus_offset = mem_start & 0x00ff0000; - mem_start &= LA_MASK; /* LANCE re-mapped start address */ - - lp->dma_buffs = mem_start; - - /* Finish initialising the ring information. */ - lp->rxRingMask = NUM_RX_DESC - 1; - lp->txRingMask = NUM_TX_DESC - 1; - - /* Calculate Tx/Rx RLEN size for the descriptors. */ - for (i=0, j = lp->rxRingMask; j>0; i++) { - j >>= 1; - } - lp->rx_rlen = (s32)(i << 29); - for (i=0, j = lp->txRingMask; j>0; i++) { - j >>= 1; - } - lp->tx_rlen = (s32)(i << 29); - - /* Load the initialisation block */ - depca_init_ring(dev); - - /* Initialise the control and status registers */ - LoadCSRs(dev); - - /* Enable DEPCA board interrupts for autoprobing */ - nicsr = ((nicsr & ~IM)|IEN); - outb(nicsr, DEPCA_NICSR); - - /* To auto-IRQ we enable the initialization-done and DMA err, - interrupts. For now we will always get a DMA error. */ - if (dev->irq < 2) { + struct depca_private *lp; + int i, j, offset, netRAM, mem_len, status = 0; + s16 nicsr; + u_long mem_start = 0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES; + + STOP_DEPCA; + + nicsr = inb(DEPCA_NICSR); + nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM); + outb(nicsr, DEPCA_NICSR); + + if (inw(DEPCA_DATA) == STOP) { + do { + strcpy(name, (adapter_name ? adapter_name : "")); + mem_start = (mem ? mem & 0xf0000 : mem_base[mem_chkd++]); + DepcaSignature(name, mem_start); + } while (!mem && mem_base[mem_chkd] && (adapter == unknown)); + + if ((adapter != unknown) && mem_start) { /* found a DEPCA device */ + dev->base_addr = ioaddr; + + if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */ + printk("%s: %s at 0x%04lx (EISA slot %d)", + dev->name, name, ioaddr, (int) ((ioaddr >> 12) & 0x0f)); + } else { /* ISA port address */ + printk("%s: %s at 0x%04lx", dev->name, name, ioaddr); + } + + printk(", h/w address "); + status = get_hw_addr(dev); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */ + printk("%2.2x:", dev->dev_addr[i]); + } + printk("%2.2x", dev->dev_addr[i]); + + if (status == 0) { + /* Set up the maximum amount of network RAM(kB) */ + netRAM = ((adapter != DEPCA) ? 64 : 48); + if ((nicsr & _128KB) && (adapter == de422)) + netRAM = 128; + offset = 0x0000; + + /* Shared Memory Base Address */ + if (nicsr & BUF) { + offset = 0x8000; /* 32kbyte RAM offset */ + nicsr &= ~BS; /* DEPCA RAM in top 32k */ + netRAM -= 32; + } + mem_start += offset; /* (E)ISA start address */ + if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + + sizeof(struct depca_init))) <= + (netRAM << 10)) { + printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start); + + /* Enable the shadow RAM. */ + if (adapter != DEPCA) { + nicsr |= SHE; + outb(nicsr, DEPCA_NICSR); + } + /* Define the device private memory */ + dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + lp = (struct depca_private *) dev->priv; + memset((char *) dev->priv, 0, sizeof(struct depca_private)); + lp->adapter = adapter; + sprintf(lp->adapter_name, "%s (%s)", name, dev->name); + request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name); + + /* Initialisation Block */ + lp->sh_mem = mem_start; + mem_start += sizeof(struct depca_init); + + /* Tx & Rx descriptors (aligned to a quadword boundary) */ + mem_start = (mem_start + ALIGN) & ~ALIGN; + lp->rx_ring = (struct depca_rx_desc *) mem_start; + + mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC); + lp->tx_ring = (struct depca_tx_desc *) mem_start; + + mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC); + lp->bus_offset = mem_start & 0x00ff0000; + mem_start &= LA_MASK; /* LANCE re-mapped start address */ + + lp->dma_buffs = mem_start; + + /* Finish initialising the ring information. */ + lp->rxRingMask = NUM_RX_DESC - 1; + lp->txRingMask = NUM_TX_DESC - 1; + + /* Calculate Tx/Rx RLEN size for the descriptors. */ + for (i = 0, j = lp->rxRingMask; j > 0; i++) { + j >>= 1; + } + lp->rx_rlen = (s32) (i << 29); + for (i = 0, j = lp->txRingMask; j > 0; i++) { + j >>= 1; + } + lp->tx_rlen = (s32) (i << 29); + + /* Load the initialisation block */ + depca_init_ring(dev); + + /* Initialise the control and status registers */ + LoadCSRs(dev); + + /* Enable DEPCA board interrupts for autoprobing */ + nicsr = ((nicsr & ~IM) | IEN); + outb(nicsr, DEPCA_NICSR); + + /* To auto-IRQ we enable the initialization-done and DMA err, + interrupts. For now we will always get a DMA error. */ + if (dev->irq < 2) { #ifndef MODULE - unsigned char irqnum; - autoirq_setup(0); + unsigned char irqnum; + autoirq_setup(0); - /* Assign the correct irq list */ - switch (lp->adapter) { - case DEPCA: - case de100: - case de101: - depca_irq = de1xx_irq; - break; - case de200: - case de201: - case de202: - case de210: - depca_irq = de2xx_irq; - break; - case de422: - depca_irq = de422_irq; - break; - } - - /* Trigger an initialization just for the interrupt. */ - outw(INEA | INIT, DEPCA_DATA); - - irqnum = autoirq_report(1); - if (!irqnum) { - printk(" and failed to detect IRQ line.\n"); - status = -ENXIO; - } else { - for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) { - if (irqnum == depca_irq[i]) { - dev->irq = irqnum; - printk(" and uses IRQ%d.\n", dev->irq); + /* Assign the correct irq list */ + switch (lp->adapter) { + case DEPCA: + case de100: + case de101: + depca_irq = de1xx_irq; + break; + case de200: + case de201: + case de202: + case de210: + depca_irq = de2xx_irq; + break; + case de422: + depca_irq = de422_irq; + break; + } + + /* Trigger an initialization just for the interrupt. */ + outw(INEA | INIT, DEPCA_DATA); + + irqnum = autoirq_report(1); + if (!irqnum) { + printk(" and failed to detect IRQ line.\n"); + status = -ENXIO; + } else { + for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++) { + if (irqnum == depca_irq[i]) { + dev->irq = irqnum; + printk(" and uses IRQ%d.\n", dev->irq); + } + } + + if (!dev->irq) { + printk(" but incorrect IRQ line detected.\n"); + status = -ENXIO; + } + } +#endif /* MODULE */ + } else { + printk(" and assigned IRQ%d.\n", dev->irq); + } + if (status) + release_region(ioaddr, DEPCA_TOTAL_SIZE); + } else { + printk(",\n requests %dkB RAM: only %dkB is available!\n", + (mem_len >> 10), netRAM); + status = -ENXIO; + } + } else { + printk(" which has an Ethernet PROM CRC error.\n"); + status = -ENXIO; + } + } else { + status = -ENXIO; + } + if (!status) { + if (depca_debug > 1) { + printk(version); + } + /* The DEPCA-specific entries in the device structure. */ + dev->open = &depca_open; + dev->hard_start_xmit = &depca_start_xmit; + dev->stop = &depca_close; + dev->get_stats = &depca_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = &depca_ioctl; + + dev->mem_start = 0; + + /* Fill in the generic field of the device structure. */ + ether_setup(dev); + } else { /* Incorrectly initialised hardware */ + if (dev->priv) { + kfree_s(dev->priv, sizeof(struct depca_private)); + dev->priv = NULL; + } } - } - - if (!dev->irq) { - printk(" but incorrect IRQ line detected.\n"); - status = -ENXIO; - } - } -#endif /* MODULE */ - } else { - printk(" and assigned IRQ%d.\n", dev->irq); - } - if (status) release_region(ioaddr, DEPCA_TOTAL_SIZE); } else { - printk(",\n requests %dkB RAM: only %dkB is available!\n", - (mem_len>>10), netRAM); - status = -ENXIO; - } - } else { - printk(" which has an Ethernet PROM CRC error.\n"); - status = -ENXIO; - } - } else { - status = -ENXIO; - } - if (!status) { - if (depca_debug > 1) { - printk(version); - } - - /* The DEPCA-specific entries in the device structure. */ - dev->open = &depca_open; - dev->hard_start_xmit = &depca_start_xmit; - dev->stop = &depca_close; - dev->get_stats = &depca_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &depca_ioctl; - - dev->mem_start = 0; - - /* Fill in the generic field of the device structure. */ - ether_setup(dev); - } else { /* Incorrectly initialised hardware */ - if (dev->priv) { - kfree_s(dev->priv, sizeof(struct depca_private)); - dev->priv = NULL; - } - } - } else { - status = -ENXIO; - } + status = -ENXIO; + } - return status; + return status; } - -static int -depca_open(struct device *dev) + +static int depca_open(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - u_long ioaddr = dev->base_addr; - s16 nicsr; - int status = 0; - - STOP_DEPCA; - nicsr = inb(DEPCA_NICSR); - - /* Make sure the shadow RAM is enabled */ - if (adapter != DEPCA) { - nicsr |= SHE; - outb(nicsr, DEPCA_NICSR); - } - - /* Re-initialize the DEPCA... */ - depca_init_ring(dev); - LoadCSRs(dev); - - depca_dbg_open(dev); - - if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) { - printk("depca_open(): Requested IRQ%d is busy\n",dev->irq); - status = -EAGAIN; - } else { - - /* Enable DEPCA board interrupts and turn off LED */ - nicsr = ((nicsr & ~IM & ~LED)|IEN); - outb(nicsr, DEPCA_NICSR); - outw(CSR0,DEPCA_ADDR); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - status = InitRestartDepca(dev); - - if (depca_debug > 1){ - printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA)); - printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR)); - } - } + struct depca_private *lp = (struct depca_private *) dev->priv; + u_long ioaddr = dev->base_addr; + s16 nicsr; + int status = 0; + + STOP_DEPCA; + nicsr = inb(DEPCA_NICSR); + + /* Make sure the shadow RAM is enabled */ + if (adapter != DEPCA) { + nicsr |= SHE; + outb(nicsr, DEPCA_NICSR); + } + /* Re-initialize the DEPCA... */ + depca_init_ring(dev); + LoadCSRs(dev); + + depca_dbg_open(dev); + + if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) { + printk("depca_open(): Requested IRQ%d is busy\n", dev->irq); + status = -EAGAIN; + } else { - MOD_INC_USE_COUNT; + /* Enable DEPCA board interrupts and turn off LED */ + nicsr = ((nicsr & ~IM & ~LED) | IEN); + outb(nicsr, DEPCA_NICSR); + outw(CSR0, DEPCA_ADDR); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + status = InitRestartDepca(dev); + + if (depca_debug > 1) { + printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA)); + printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR)); + } + } + + MOD_INC_USE_COUNT; - return status; + return status; } /* Initialize the lance Rx and Tx descriptor rings. */ -static void -depca_init_ring(struct device *dev) +static void depca_init_ring(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - u_int i; - u_long p; - - /* Lock out other processes whilst setting up the hardware */ - set_bit(0, (void *)&dev->tbusy); - - lp->rx_new = lp->tx_new = 0; - lp->rx_old = lp->tx_old = 0; - - /* Initialize the base addresses and length of each buffer in the ring */ - for (i = 0; i <= lp->rxRingMask; i++) { - writel((p=lp->dma_buffs+i*RX_BUFF_SZ) | R_OWN, &lp->rx_ring[i].base); - writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length); - lp->rx_memcpy[i]=(char *)(p+lp->bus_offset); - } - for (i = 0; i <= lp->txRingMask; i++) { - writel((p=lp->dma_buffs+(i+lp->txRingMask+1)*TX_BUFF_SZ) & 0x00ffffff, - &lp->tx_ring[i].base); - lp->tx_memcpy[i]=(char *)(p+lp->bus_offset); - } - - /* Set up the initialization block */ - lp->init_block.rx_ring = ((u32)((u_long)lp->rx_ring)&LA_MASK) | lp->rx_rlen; - lp->init_block.tx_ring = ((u32)((u_long)lp->tx_ring)&LA_MASK) | lp->tx_rlen; - - SetMulticastFilter(dev); - - for (i = 0; i < ETH_ALEN; i++) { - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - } - - lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */ - - return; -} - -/* -** Writes a socket buffer to TX descriptor ring and starts transmission -*/ -static int -depca_start_xmit(struct sk_buff *skb, struct device *dev) -{ - struct depca_private *lp = (struct depca_private *)dev->priv; - u_long ioaddr = dev->base_addr; - int status = 0; - - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 1*HZ) { - status = -1; - } else { - printk("%s: transmit timed out, status %04x, resetting.\n", - dev->name, inw(DEPCA_DATA)); - - STOP_DEPCA; - depca_init_ring(dev); - LoadCSRs(dev); - dev->interrupt = UNMASK_INTERRUPTS; - dev->start = 1; - dev->tbusy=0; - dev->trans_start = jiffies; - InitRestartDepca(dev); - } - return status; - } else if (skb == NULL) { - dev_tint(dev); - } else if (skb->len > 0) { - /* Enforce 1 process per h/w access */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - status = -1; - } else { - if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */ - status = load_packet(dev, skb); - - if (!status) { - /* Trigger an immediate send demand. */ - outw(CSR0, DEPCA_ADDR); - outw(INEA | TDMD, DEPCA_DATA); - - dev->trans_start = jiffies; - dev_kfree_skb(skb, FREE_WRITE); - } - if (TX_BUFFS_AVAIL) { - dev->tbusy=0; - } - } else { - status = -1; - } - } - } - - return status; -} - -/* -** The DEPCA interrupt handler. -*/ -static void -depca_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct device *dev =dev_id; - struct depca_private *lp; - s16 csr0, nicsr; - u_long ioaddr; - - if (dev == NULL) { - printk ("depca_interrupt(): irq %d for unknown device.\n", irq); - } else { - lp = (struct depca_private *)dev->priv; - ioaddr = dev->base_addr; - - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - - dev->interrupt = MASK_INTERRUPTS; - - /* mask the DEPCA board interrupts and turn on the LED */ - nicsr = inb(DEPCA_NICSR); - nicsr |= (IM|LED); - outb(nicsr, DEPCA_NICSR); - - outw(CSR0, DEPCA_ADDR); - csr0 = inw(DEPCA_DATA); - - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & INTE, DEPCA_DATA); - - if (csr0 & RINT) /* Rx interrupt (packet arrived) */ - depca_rx(dev); - - if (csr0 & TINT) /* Tx interrupt (packet sent) */ - depca_tx(dev); - - if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */ - dev->tbusy = 0; /* clear TX busy flag */ - mark_bh(NET_BH); - } - - /* Unmask the DEPCA board interrupts and turn off the LED */ - nicsr = (nicsr & ~IM & ~LED); - outb(nicsr, DEPCA_NICSR); - - dev->interrupt = UNMASK_INTERRUPTS; - } - - return; -} - -static int -depca_rx(struct device *dev) -{ - struct depca_private *lp = (struct depca_private *)dev->priv; - int i, entry; - s32 status; - - for (entry=lp->rx_new; - !(readl(&lp->rx_ring[entry].base) & R_OWN); - entry=lp->rx_new){ - status = readl(&lp->rx_ring[entry].base) >> 16 ; - if (status & R_STP) { /* Remember start of frame */ - lp->rx_old = entry; - } - if (status & R_ENP) { /* Valid frame status */ - if (status & R_ERR) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ - if (status & R_FRAM) lp->stats.rx_frame_errors++; - if (status & R_OFLO) lp->stats.rx_over_errors++; - if (status & R_CRC) lp->stats.rx_crc_errors++; - if (status & R_BUFF) lp->stats.rx_fifo_errors++; - } else { - short len, pkt_len = readw(&lp->rx_ring[entry].msg_length); - struct sk_buff *skb; - - skb = dev_alloc_skb(pkt_len+2); - if (skb != NULL) { - unsigned char *buf; - skb_reserve(skb,2); /* 16 byte align the IP header */ - buf = skb_put(skb,pkt_len); - skb->dev = dev; - if (entry < lp->rx_old) { /* Wrapped buffer */ - len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ; - memcpy_fromio(buf, lp->rx_memcpy[lp->rx_old], len); - memcpy_fromio(buf + len, lp->rx_memcpy[0], pkt_len-len); - } else { /* Linear buffer */ - memcpy_fromio(buf, lp->rx_memcpy[lp->rx_old], pkt_len); - } - - /* - ** Notify the upper protocol layers that there is another - ** packet to handle - */ - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - - /* - ** Update stats - */ - lp->stats.rx_packets++; - for (i=1; ipktStats.bins[i]++; - i = DEPCA_PKT_STAT_SZ; - } - } - if (buf[0] & 0x01) { /* Multicast/Broadcast */ - if ((*(s16 *)&buf[0] == -1) && - (*(s16 *)&buf[2] == -1) && - (*(s16 *)&buf[4] == -1)) { - lp->pktStats.broadcast++; - } else { - lp->pktStats.multicast++; - } - } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) && - (*(s16 *)&buf[2] == *(s16 *)&dev->dev_addr[2]) && - (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { - lp->pktStats.unicast++; - } - - lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ - if (lp->pktStats.bins[0] == 0) { /* Reset counters */ - memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats)); - } + struct depca_private *lp = (struct depca_private *) dev->priv; + u_int i; + u_long p; + + /* Lock out other processes whilst setting up the hardware */ + set_bit(0, (void *) &dev->tbusy); + + lp->rx_new = lp->tx_new = 0; + lp->rx_old = lp->tx_old = 0; + + /* Initialize the base addresses and length of each buffer in the ring */ + for (i = 0; i <= lp->rxRingMask; i++) { + writel((p = lp->dma_buffs + i * RX_BUFF_SZ) | R_OWN, &lp->rx_ring[i].base); + writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length); + lp->rx_memcpy[i] = (char *) (p + lp->bus_offset); + } + for (i = 0; i <= lp->txRingMask; i++) { + writel((p = lp->dma_buffs + (i + lp->txRingMask + 1) * TX_BUFF_SZ) & 0x00ffffff, + &lp->tx_ring[i].base); + lp->tx_memcpy[i] = (char *) (p + lp->bus_offset); + } + + /* Set up the initialization block */ + lp->init_block.rx_ring = ((u32) ((u_long) lp->rx_ring) & LA_MASK) | lp->rx_rlen; + lp->init_block.tx_ring = ((u32) ((u_long) lp->tx_ring) & LA_MASK) | lp->tx_rlen; + + SetMulticastFilter(dev); + + for (i = 0; i < ETH_ALEN; i++) { + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + } + + lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */ + + return; +} + +/* + ** Writes a socket buffer to TX descriptor ring and starts transmission + */ +static int depca_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct depca_private *lp = (struct depca_private *) dev->priv; + u_long ioaddr = dev->base_addr; + int status = 0; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 1 * HZ) { + status = -1; + } else { + printk("%s: transmit timed out, status %04x, resetting.\n", + dev->name, inw(DEPCA_DATA)); + + STOP_DEPCA; + depca_init_ring(dev); + LoadCSRs(dev); + dev->interrupt = UNMASK_INTERRUPTS; + dev->start = 1; + dev->tbusy = 0; + dev->trans_start = jiffies; + InitRestartDepca(dev); + } + return status; + } + else if (skb->len > 0) + { + /* Enforce 1 process per h/w access */ + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + status = -1; + } else { + if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */ + status = load_packet(dev, skb); + + if (!status) { + /* Trigger an immediate send demand. */ + outw(CSR0, DEPCA_ADDR); + outw(INEA | TDMD, DEPCA_DATA); + + dev->trans_start = jiffies; + dev_kfree_skb(skb, FREE_WRITE); + } + if (TX_BUFFS_AVAIL) { + dev->tbusy = 0; + } + } else { + status = -1; + } + } + } + return status; +} + +/* + ** The DEPCA interrupt handler. + */ +static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = dev_id; + struct depca_private *lp; + s16 csr0, nicsr; + u_long ioaddr; + + if (dev == NULL) { + printk("depca_interrupt(): irq %d for unknown device.\n", irq); } else { - printk("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ - break; - } - } - /* Change buffer ownership for this last frame, back to the adapter */ - for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) { - writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, - &lp->rx_ring[lp->rx_old].base); - } - writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base); - } - - /* - ** Update entry information - */ - lp->rx_new = (++lp->rx_new) & lp->rxRingMask; - } - - return 0; + lp = (struct depca_private *) dev->priv; + ioaddr = dev->base_addr; + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = MASK_INTERRUPTS; + + /* mask the DEPCA board interrupts and turn on the LED */ + nicsr = inb(DEPCA_NICSR); + nicsr |= (IM | LED); + outb(nicsr, DEPCA_NICSR); + + outw(CSR0, DEPCA_ADDR); + csr0 = inw(DEPCA_DATA); + + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(csr0 & INTE, DEPCA_DATA); + + if (csr0 & RINT) /* Rx interrupt (packet arrived) */ + depca_rx(dev); + + if (csr0 & TINT) /* Tx interrupt (packet sent) */ + depca_tx(dev); + + if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */ + dev->tbusy = 0; /* clear TX busy flag */ + mark_bh(NET_BH); + } + /* Unmask the DEPCA board interrupts and turn off the LED */ + nicsr = (nicsr & ~IM & ~LED); + outb(nicsr, DEPCA_NICSR); + + dev->interrupt = UNMASK_INTERRUPTS; + } + + return; +} + +static int depca_rx(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *) dev->priv; + int i, entry; + s32 status; + + for (entry = lp->rx_new; + !(readl(&lp->rx_ring[entry].base) & R_OWN); + entry = lp->rx_new) { + status = readl(&lp->rx_ring[entry].base) >> 16; + if (status & R_STP) { /* Remember start of frame */ + lp->rx_old = entry; + } + if (status & R_ENP) { /* Valid frame status */ + if (status & R_ERR) { /* There was an error. */ + lp->stats.rx_errors++; /* Update the error stats. */ + if (status & R_FRAM) + lp->stats.rx_frame_errors++; + if (status & R_OFLO) + lp->stats.rx_over_errors++; + if (status & R_CRC) + lp->stats.rx_crc_errors++; + if (status & R_BUFF) + lp->stats.rx_fifo_errors++; + } else { + short len, pkt_len = readw(&lp->rx_ring[entry].msg_length); + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_len + 2); + if (skb != NULL) { + unsigned char *buf; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + buf = skb_put(skb, pkt_len); + skb->dev = dev; + if (entry < lp->rx_old) { /* Wrapped buffer */ + len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ; + memcpy_fromio(buf, lp->rx_memcpy[lp->rx_old], len); + memcpy_fromio(buf + len, lp->rx_memcpy[0], pkt_len - len); + } else { /* Linear buffer */ + memcpy_fromio(buf, lp->rx_memcpy[lp->rx_old], pkt_len); + } + + /* + ** Notify the upper protocol layers that there is another + ** packet to handle + */ + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + /* + ** Update stats + */ + lp->stats.rx_packets++; + for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) { + if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) { + lp->pktStats.bins[i]++; + i = DEPCA_PKT_STAT_SZ; + } + } + if (buf[0] & 0x01) { /* Multicast/Broadcast */ + if ((*(s16 *) & buf[0] == -1) && + (*(s16 *) & buf[2] == -1) && + (*(s16 *) & buf[4] == -1)) { + lp->pktStats.broadcast++; + } else { + lp->pktStats.multicast++; + } + } else if ((*(s16 *) & buf[0] == *(s16 *) & dev->dev_addr[0]) && + (*(s16 *) & buf[2] == *(s16 *) & dev->dev_addr[2]) && + (*(s16 *) & buf[4] == *(s16 *) & dev->dev_addr[4])) { + lp->pktStats.unicast++; + } + lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ + if (lp->pktStats.bins[0] == 0) { /* Reset counters */ + memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats)); + } + } else { + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + lp->stats.rx_dropped++; /* Really, deferred. */ + break; + } + } + /* Change buffer ownership for this last frame, back to the adapter */ + for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) & lp->rxRingMask) { + writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, + &lp->rx_ring[lp->rx_old].base); + } + writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base); + } + /* + ** Update entry information + */ + lp->rx_new = (++lp->rx_new) & lp->rxRingMask; + } + + return 0; } /* -** Buffer sent - check for buffer errors. -*/ -static int -depca_tx(struct device *dev) -{ - struct depca_private *lp = (struct depca_private *)dev->priv; - int entry; - s32 status; - u_long ioaddr = dev->base_addr; - - for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) { - status = readl(&lp->tx_ring[entry].base) >> 16 ; - - if (status < 0) { /* Packet not yet sent! */ - break; - } else if (status & T_ERR) { /* An error occurred. */ - status = readl(&lp->tx_ring[entry].misc); - lp->stats.tx_errors++; - if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++; - if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++; - if (status & TMD3_LCOL) lp->stats.tx_window_errors++; - if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++; - if (status & (TMD3_BUFF | TMD3_UFLO)) { - /* Trigger an immediate send demand. */ + ** Buffer sent - check for buffer errors. + */ +static int depca_tx(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *) dev->priv; + int entry; + s32 status; + u_long ioaddr = dev->base_addr; + + for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) { + status = readl(&lp->tx_ring[entry].base) >> 16; + + if (status < 0) { /* Packet not yet sent! */ + break; + } else if (status & T_ERR) { /* An error occurred. */ + status = readl(&lp->tx_ring[entry].misc); + lp->stats.tx_errors++; + if (status & TMD3_RTRY) + lp->stats.tx_aborted_errors++; + if (status & TMD3_LCAR) + lp->stats.tx_carrier_errors++; + if (status & TMD3_LCOL) + lp->stats.tx_window_errors++; + if (status & TMD3_UFLO) + lp->stats.tx_fifo_errors++; + if (status & (TMD3_BUFF | TMD3_UFLO)) { + /* Trigger an immediate send demand. */ + outw(CSR0, DEPCA_ADDR); + outw(INEA | TDMD, DEPCA_DATA); + } + } else if (status & (T_MORE | T_ONE)) { + lp->stats.collisions++; + } else { + lp->stats.tx_packets++; + } + + /* Update all the pointers */ + lp->tx_old = (++lp->tx_old) & lp->txRingMask; + } + + return 0; +} + +static int depca_close(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *) dev->priv; + s16 nicsr; + u_long ioaddr = dev->base_addr; + + dev->start = 0; + dev->tbusy = 1; + outw(CSR0, DEPCA_ADDR); - outw(INEA | TDMD, DEPCA_DATA); - } - } else if (status & (T_MORE | T_ONE)) { - lp->stats.collisions++; - } else { - lp->stats.tx_packets++; - } - - /* Update all the pointers */ - lp->tx_old = (++lp->tx_old) & lp->txRingMask; - } - - return 0; -} - -static int -depca_close(struct device *dev) -{ - struct depca_private *lp = (struct depca_private *)dev->priv; - s16 nicsr; - u_long ioaddr = dev->base_addr; - - dev->start = 0; - dev->tbusy = 1; - - outw(CSR0, DEPCA_ADDR); - - if (depca_debug > 1) { - printk("%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inw(DEPCA_DATA)); - } - - /* - ** We stop the DEPCA here -- it occasionally polls - ** memory if we don't. - */ - outw(STOP, DEPCA_DATA); - - /* - ** Give back the ROM in case the user wants to go to DOS - */ - if (lp->adapter != DEPCA) { - nicsr = inb(DEPCA_NICSR); - nicsr &= ~SHE; - outb(nicsr, DEPCA_NICSR); - } - - /* - ** Free the associated irq - */ - free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; + if (depca_debug > 1) { + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inw(DEPCA_DATA)); + } + /* + ** We stop the DEPCA here -- it occasionally polls + ** memory if we don't. + */ + outw(STOP, DEPCA_DATA); + + /* + ** Give back the ROM in case the user wants to go to DOS + */ + if (lp->adapter != DEPCA) { + nicsr = inb(DEPCA_NICSR); + nicsr &= ~SHE; + outb(nicsr, DEPCA_NICSR); + } + /* + ** Free the associated irq + */ + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; - return 0; + return 0; } static void LoadCSRs(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - u_long ioaddr = dev->base_addr; + struct depca_private *lp = (struct depca_private *) dev->priv; + u_long ioaddr = dev->base_addr; - outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ - outw((u16)(lp->sh_mem & LA_MASK), DEPCA_DATA); - outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ - outw((u16)((lp->sh_mem & LA_MASK) >> 16), DEPCA_DATA); - outw(CSR3, DEPCA_ADDR); /* ALE control */ - outw(ACON, DEPCA_DATA); + outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ + outw((u16) (lp->sh_mem & LA_MASK), DEPCA_DATA); + outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ + outw((u16) ((lp->sh_mem & LA_MASK) >> 16), DEPCA_DATA); + outw(CSR3, DEPCA_ADDR); /* ALE control */ + outw(ACON, DEPCA_DATA); - outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */ + outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */ - return; + return; } static int InitRestartDepca(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - u_long ioaddr = dev->base_addr; - int i, status=0; - - /* Copy the shadow init_block to shared memory */ - memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init)); - - outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ - outw(INIT, DEPCA_DATA); /* initialize DEPCA */ - - /* wait for lance to complete initialisation */ - for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); - - if (i!=100) { - /* clear IDON by writing a "1", enable interrupts and start lance */ - outw(IDON | INEA | STRT, DEPCA_DATA); - if (depca_debug > 2) { - printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", - dev->name, i, lp->sh_mem, inw(DEPCA_DATA)); - } - } else { - printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", - dev->name, i, lp->sh_mem, inw(DEPCA_DATA)); - status = -1; - } + struct depca_private *lp = (struct depca_private *) dev->priv; + u_long ioaddr = dev->base_addr; + int i, status = 0; + + /* Copy the shadow init_block to shared memory */ + memcpy_toio((char *) lp->sh_mem, &lp->init_block, sizeof(struct depca_init)); + + outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ + outw(INIT, DEPCA_DATA); /* initialize DEPCA */ + + /* wait for lance to complete initialisation */ + for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++); + + if (i != 100) { + /* clear IDON by writing a "1", enable interrupts and start lance */ + outw(IDON | INEA | STRT, DEPCA_DATA); + if (depca_debug > 2) { + printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", + dev->name, i, lp->sh_mem, inw(DEPCA_DATA)); + } + } else { + printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", + dev->name, i, lp->sh_mem, inw(DEPCA_DATA)); + status = -1; + } - return status; + return status; } static struct net_device_stats * -depca_get_stats(struct device *dev) + depca_get_stats(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; + struct depca_private *lp = (struct depca_private *) dev->priv; - /* Null body since there is no framing error counter */ + /* Null body since there is no framing error counter */ - return &lp->stats; + return &lp->stats; } /* -** Set or clear the multicast filter for this adaptor. -*/ -static void -set_multicast_list(struct device *dev) + ** Set or clear the multicast filter for this adaptor. + */ +static void set_multicast_list(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - u_long ioaddr = dev->base_addr; + struct depca_private *lp = (struct depca_private *) dev->priv; + u_long ioaddr = dev->base_addr; - while(dev->tbusy); /* Stop ring access */ - set_bit(0, (void*)&dev->tbusy); - while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ + while (dev->tbusy); /* Stop ring access */ + set_bit(0, (void *) &dev->tbusy); + while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ - STOP_DEPCA; /* Temporarily stop the depca. */ - depca_init_ring(dev); /* Initialize the descriptor rings */ + STOP_DEPCA; /* Temporarily stop the depca. */ + depca_init_ring(dev); /* Initialize the descriptor rings */ - if (dev->flags & IFF_PROMISC) { /* Set promiscuous mode */ - lp->init_block.mode |= PROM; - } else { - SetMulticastFilter(dev); - lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ - } + if (dev->flags & IFF_PROMISC) { /* Set promiscuous mode */ + lp->init_block.mode |= PROM; + } else { + SetMulticastFilter(dev); + lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ + } - LoadCSRs(dev); /* Reload CSR3 */ - InitRestartDepca(dev); /* Resume normal operation. */ - dev->tbusy = 0; /* Unlock the TX ring */ + LoadCSRs(dev); /* Reload CSR3 */ + InitRestartDepca(dev); /* Resume normal operation. */ + dev->tbusy = 0; /* Unlock the TX ring */ } /* -** Calculate the hash code and update the logical address filter -** from a list of ethernet multicast addresses. -** Big endian crc one liner is mine, all mine, ha ha ha ha! -** LANCE calculates its hash codes big endian. -*/ + ** Calculate the hash code and update the logical address filter + ** from a list of ethernet multicast addresses. + ** Big endian crc one liner is mine, all mine, ha ha ha ha! + ** LANCE calculates its hash codes big endian. + */ static void SetMulticastFilter(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - struct dev_mc_list *dmi=dev->mc_list; - char *addrs; - int i, j, bit, byte; - u16 hashcode; - s32 crc, poly = CRC_POLYNOMIAL_BE; - - if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */ - for (i=0; i<(HASH_TABLE_LEN>>3); i++) { - lp->init_block.mcast_table[i] = (char)0xff; - } - } else { - for (i=0; i<(HASH_TABLE_LEN>>3); i++){ /* Clear the multicast table */ - lp->init_block.mcast_table[i]=0; - } - /* Add multicast addresses */ - for (i=0;imc_count;i++) { /* for each address in the list */ - addrs=dmi->dmi_addr; - dmi=dmi->next; - if ((*addrs & 0x01) == 1) { /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte=0;byte>=1) { - crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0); - } - } - hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ - for (j=0;j<5;j++) { /* ... in reverse order. */ - hashcode = (hashcode << 1) | ((crc>>=1) & 1); + struct depca_private *lp = (struct depca_private *) dev->priv; + struct dev_mc_list *dmi = dev->mc_list; + char *addrs; + int i, j, bit, byte; + u16 hashcode; + s32 crc, poly = CRC_POLYNOMIAL_BE; + + if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */ + for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { + lp->init_block.mcast_table[i] = (char) 0xff; + } + } else { + for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { /* Clear the multicast table */ + lp->init_block.mcast_table[i] = 0; + } + /* Add multicast addresses */ + for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + addrs = dmi->dmi_addr; + dmi = dmi->next; + if ((*addrs & 0x01) == 1) { /* multicast address? */ + crc = 0xffffffff; /* init CRC for each address */ + for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ + /* process each address bit */ + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + crc = (crc << 1) ^ ((((crc < 0 ? 1 : 0) ^ bit) & 0x01) ? poly : 0); + } + } + hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */ + for (j = 0; j < 5; j++) { /* ... in reverse order. */ + hashcode = (hashcode << 1) | ((crc >>= 1) & 1); + } + + + byte = hashcode >> 3; /* bit[3-5] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + lp->init_block.mcast_table[byte] |= bit; + } + } } - - byte = hashcode >> 3; /* bit[3-5] -> byte in filter */ - bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ - lp->init_block.mcast_table[byte] |= bit; - } - } - } - - return; + return; } /* -** ISA bus I/O device probe -*/ + ** ISA bus I/O device probe + */ __initfunc(static void isa_probe(struct device *dev, u_long ioaddr)) { - int i = num_depcas, maxSlots; - s32 ports[] = DEPCA_IO_PORTS; + int i = num_depcas, maxSlots; + s32 ports[] = DEPCA_IO_PORTS; + + if (!ioaddr && autoprobed) + return; /* Been here before ! */ + if (ioaddr > 0x400) + return; /* EISA Address */ + if (i >= MAX_NUM_DEPCAS) + return; /* Too many ISA adapters */ + + if (ioaddr == 0) { /* Autoprobing */ + maxSlots = MAX_NUM_DEPCAS; + } else { /* Probe a specific location */ + ports[i] = ioaddr; + maxSlots = i + 1; + } + + for (; (i < maxSlots) && (dev != NULL) && ports[i]; i++) { + if (DevicePresent(ports[i]) == 0) { + if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) { + if ((dev = alloc_device(dev, ports[i])) != NULL) { + if (depca_hw_init(dev, ports[i]) == 0) { + num_depcas++; + } + num_eth++; + } + } else if (autoprobed) { + printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]); + } + } + } - if (!ioaddr && autoprobed) return ; /* Been here before ! */ - if (ioaddr > 0x400) return; /* EISA Address */ - if (i >= MAX_NUM_DEPCAS) return; /* Too many ISA adapters */ - - if (ioaddr == 0) { /* Autoprobing */ - maxSlots = MAX_NUM_DEPCAS; - } else { /* Probe a specific location */ - ports[i] = ioaddr; - maxSlots = i + 1; - } - - for (; (iname,ports[i]); - } - } - } - - return; + return; } /* -** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually -** the motherboard. Upto 15 EISA devices are supported. -*/ + ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually + ** the motherboard. Upto 15 EISA devices are supported. + */ __initfunc(static void eisa_probe(struct device *dev, u_long ioaddr)) { - int i, maxSlots; - u_long iobase; - char name[DEPCA_STRLEN]; - - if (!ioaddr && autoprobed) return ; /* Been here before ! */ - if ((ioaddr < 0x400) && (ioaddr > 0)) return; /* ISA Address */ - - if (ioaddr == 0) { /* Autoprobing */ - iobase = EISA_SLOT_INC; /* Get the first slot address */ - i = 1; - maxSlots = MAX_EISA_SLOTS; - } else { /* Probe a specific location */ - iobase = ioaddr; - i = (ioaddr >> 12); - maxSlots = i + 1; - } - if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS; - - for (; (iname,iobase); - } - } - } - } - - return; + int i, maxSlots; + u_long iobase; + char name[DEPCA_STRLEN]; + + if (!ioaddr && autoprobed) + return; /* Been here before ! */ + if ((ioaddr < 0x400) && (ioaddr > 0)) + return; /* ISA Address */ + + if (ioaddr == 0) { /* Autoprobing */ + iobase = EISA_SLOT_INC; /* Get the first slot address */ + i = 1; + maxSlots = MAX_EISA_SLOTS; + } else { /* Probe a specific location */ + iobase = ioaddr; + i = (ioaddr >> 12); + maxSlots = i + 1; + } + if ((iobase & 0x0fff) == 0) + iobase += DEPCA_EISA_IO_PORTS; + + for (; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { + if (EISA_signature(name, EISA_ID)) { + if (DevicePresent(iobase) == 0) { + if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) { + if ((dev = alloc_device(dev, iobase)) != NULL) { + if (depca_hw_init(dev, iobase) == 0) { + num_depcas++; + } + num_eth++; + } + } else if (autoprobed) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + } + } + } + } + + return; } /* -** Search the entire 'eth' device list for a fixed probe. If a match isn't -** found then check for an autoprobe or unused device location. If they -** are not available then insert a new device structure at the end of -** the current list. -*/ + ** Search the entire 'eth' device list for a fixed probe. If a match isn't + ** found then check for an autoprobe or unused device location. If they + ** are not available then insert a new device structure at the end of + ** the current list. + */ __initfunc(static struct device * -alloc_device(struct device *dev, u_long iobase)) + alloc_device(struct device *dev, u_long iobase)) { - struct device *adev = NULL; - int fixed = 0, new_dev = 0; - - num_eth = depca_dev_index(dev->name); - if (loading_module) return dev; + struct device *adev = NULL; + int fixed = 0, new_dev = 0; - while (1) { - if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr==0)) && !adev) { - adev=dev; - } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "eth", 3) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) break; - dev = dev->next; - num_eth++; - } - if (adev && !fixed) { - dev = adev; num_eth = depca_dev_index(dev->name); - new_dev = 0; - } + if (loading_module) + return dev; - if (((dev->next == NULL) && - ((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_eth++; /* New device */ - dev = insert_device(dev, iobase, depca_probe); - } - - return dev; + while (1) { + if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) && !adev) { + adev = dev; + } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "eth", 3) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) + break; + dev = dev->next; + num_eth++; + } + if (adev && !fixed) { + dev = adev; + num_eth = depca_dev_index(dev->name); + new_dev = 0; + } + if (((dev->next == NULL) && + ((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_eth++; /* New device */ + dev = insert_device(dev, iobase, depca_probe); + } + return dev; } /* -** If at end of eth device list and can't use current entry, malloc -** one up. If memory could not be allocated, print an error message. -*/ + ** If at end of eth device list and can't use current entry, malloc + ** one up. If memory could not be allocated, print an error message. + */ __initfunc(static struct device * -insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))) + insert_device(struct device *dev, u_long iobase, int (*init) (struct device *))) { - struct device *new; + struct device *new; - new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); - if (new == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n",num_eth); - return NULL; - } else { - new->next = dev->next; - dev->next = new; - dev = dev->next; /* point to the new device */ - dev->name = (char *)(dev + 1); - if (num_eth > 9999) { - sprintf(dev->name,"eth????");/* New device name */ + new = (struct device *) kmalloc(sizeof(struct device) + 8, GFP_KERNEL); + if (new == NULL) { + printk("eth%d: Device not initialised, insufficient memory\n", num_eth); + return NULL; } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ + new->next = dev->next; + dev->next = new; + dev = dev->next; /* point to the new device */ + dev->name = (char *) (dev + 1); + if (num_eth > 9999) { + sprintf(dev->name, "eth????"); /* New device name */ + } else { + sprintf(dev->name, "eth%d", num_eth); /* New device name */ + } + dev->base_addr = iobase; /* assign the io address */ + dev->init = init; /* initialisation routine */ } - dev->base_addr = iobase; /* assign the io address */ - dev->init = init; /* initialisation routine */ - } - return dev; + return dev; } __initfunc(static int -depca_dev_index(char *s)) + depca_dev_index(char *s)) { - int i=0, j=0; + int i = 0, j = 0; - for (;*s; s++) { - if (isdigit(*s)) { - j=1; - i = (i * 10) + (*s - '0'); - } else if (j) break; - } + for (; *s; s++) { + if (isdigit(*s)) { + j = 1; + i = (i * 10) + (*s - '0'); + } else if (j) + break; + } - return i; + return i; } /* -** Look for a particular board name in the on-board Remote Diagnostics -** and Boot (readb) ROM. This will also give us a clue to the network RAM -** base address. -*/ + ** Look for a particular board name in the on-board Remote Diagnostics + ** and Boot (readb) ROM. This will also give us a clue to the network RAM + ** base address. + */ __initfunc(static void DepcaSignature(char *name, u_long paddr)) { - u_int i,j,k; - const char *signatures[] = DEPCA_SIGNATURE; - char tmpstr[16]; - - /* Copy the first 16 bytes of ROM */ - for (i=0;i<16;i++) { - tmpstr[i] = readb(paddr+0xc000+i); - } - - /* Check if PROM contains a valid string */ - for (i=0;*signatures[i]!='\0';i++) { - for (j=0,k=0;j<16 && kbase_addr; - int i, k, tmp, status = 0; - u_short j, x, chksum; - - x = (((adapter == de100) || (adapter == de101)) ? 1 : 0); - - for (i=0,k=0,j=0;j<3;j++) { - k <<= 1 ; - if (k > 0xffff) k-=0xffff; + u_long ioaddr = dev->base_addr; + int i, k, tmp, status = 0; + u_short j, x, chksum; + + x = (((adapter == de100) || (adapter == de101)) ? 1 : 0); + + for (i = 0, k = 0, j = 0; j < 3; j++) { + k <<= 1; + if (k > 0xffff) + k -= 0xffff; + + k += (u_char) (tmp = inb(DEPCA_PROM + x)); + dev->dev_addr[i++] = (u_char) tmp; + k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8); + dev->dev_addr[i++] = (u_char) tmp; - k += (u_char) (tmp = inb(DEPCA_PROM + x)); - dev->dev_addr[i++] = (u_char) tmp; - k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8); - dev->dev_addr[i++] = (u_char) tmp; - - if (k > 0xffff) k-=0xffff; - } - if (k == 0xffff) k=0; + if (k > 0xffff) + k -= 0xffff; + } + if (k == 0xffff) + k = 0; - chksum = (u_char) inb(DEPCA_PROM + x); - chksum |= (u_short) (inb(DEPCA_PROM + x) << 8); - if (k != chksum) status = -1; + chksum = (u_char) inb(DEPCA_PROM + x); + chksum |= (u_short) (inb(DEPCA_PROM + x) << 8); + if (k != chksum) + status = -1; - return status; + return status; } /* -** Load a packet into the shared memory -*/ + ** Load a packet into the shared memory + */ static int load_packet(struct device *dev, struct sk_buff *skb) { - struct depca_private *lp = (struct depca_private *)dev->priv; - int i, entry, end, len, status = 0; + struct depca_private *lp = (struct depca_private *) dev->priv; + int i, entry, end, len, status = 0; + + entry = lp->tx_new; /* Ring around buffer number. */ + end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask; + if (!(readl(&lp->tx_ring[end].base) & T_OWN)) { /* Enough room? */ + /* + ** Caution: the write order is important here... don't set up the + ** ownership rights until all the other information is in place. + */ + if (end < entry) { /* wrapped buffer */ + len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ; + memcpy_toio(lp->tx_memcpy[entry], skb->data, len); + memcpy_toio(lp->tx_memcpy[0], skb->data + len, skb->len - len); + } else { /* linear buffer */ + memcpy_toio(lp->tx_memcpy[entry], skb->data, skb->len); + } + + /* set up the buffer descriptors */ + len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; + for (i = entry; i != end; i = (++i) & lp->txRingMask) { + /* clean out flags */ + writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base); + writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */ + writew(-TX_BUFF_SZ, &lp->tx_ring[i].length); /* packet length in buffer */ + len -= TX_BUFF_SZ; + } + /* clean out flags */ + writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base); + writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */ + writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */ + + /* start of packet */ + writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base); + /* end of packet */ + writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base); + + for (i = end; i != entry; --i) { + /* ownership of packet */ + writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base); + if (i == 0) + i = lp->txRingMask + 1; + } + writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base); - entry = lp->tx_new; /* Ring around buffer number. */ - end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask; - if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */ - /* - ** Caution: the write order is important here... don't set up the - ** ownership rights until all the other information is in place. - */ - if (end < entry) { /* wrapped buffer */ - len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ; - memcpy_toio(lp->tx_memcpy[entry], skb->data, len); - memcpy_toio(lp->tx_memcpy[0], skb->data + len, skb->len - len); - } else { /* linear buffer */ - memcpy_toio(lp->tx_memcpy[entry], skb->data, skb->len); - } - - /* set up the buffer descriptors */ - len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - for (i = entry; i != end; i = (++i) & lp->txRingMask) { - /* clean out flags */ - writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base); - writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */ - writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */ - len -= TX_BUFF_SZ; - } - /* clean out flags */ - writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base); - writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */ - writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */ - - /* start of packet */ - writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base); - /* end of packet */ - writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base); - - for (i=end; i!=entry; --i) { - /* ownership of packet */ - writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base); - if (i == 0) i=lp->txRingMask+1; - } - writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base); - - lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */ - } else { - status = -1; - } + lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */ + } else { + status = -1; + } - return status; + return status; } /* -** Look for a particular board name in the EISA configuration space -*/ + ** Look for a particular board name in the EISA configuration space + */ __initfunc(static int EISA_signature(char *name, s32 eisa_id)) { - u_int i; - const char *signatures[] = DEPCA_SIGNATURE; - char ManCode[DEPCA_STRLEN]; - union { - s32 ID; - char Id[4]; - } Eisa; - int status = 0; - - *name = '\0'; - Eisa.ID = inl(eisa_id); - - ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40); - ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40); - ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30); - ManCode[3]=(( Eisa.Id[2]&0x0f)+0x30); - ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30); - ManCode[5]='\0'; - - for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) { - if (strstr(ManCode, signatures[i]) != NULL) { - strcpy(name,ManCode); - status = 1; - } - } + u_int i; + const char *signatures[] = DEPCA_SIGNATURE; + char ManCode[DEPCA_STRLEN]; + union { + s32 ID; + char Id[4]; + } Eisa; + int status = 0; + + *name = '\0'; + Eisa.ID = inl(eisa_id); + + ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40); + ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40); + ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30); + ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30); + ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30); + ManCode[5] = '\0'; + + for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) { + if (strstr(ManCode, signatures[i]) != NULL) { + strcpy(name, ManCode); + status = 1; + } + } - return status; + return status; } static void depca_dbg_open(struct device *dev) { - struct depca_private *lp = (struct depca_private *)dev->priv; - u_long ioaddr = dev->base_addr; - struct depca_init *p = (struct depca_init *)lp->sh_mem; - int i; - - if (depca_debug > 1){ - /* Copy the shadow init_block to shared memory */ - memcpy_toio((char *)lp->sh_mem,&lp->init_block,sizeof(struct depca_init)); - - printk("%s: depca open with irq %d\n",dev->name,dev->irq); - printk("Descriptor head addresses:\n"); - printk("\t0x%lx 0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring); - printk("Descriptor addresses:\nRX: "); - for (i=0;irxRingMask;i++){ - if (i < 3) { - printk("0x%8.8lx ", (long) &lp->rx_ring[i].base); - } - } - printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base); - printk("TX: "); - for (i=0;itxRingMask;i++){ - if (i < 3) { - printk("0x%8.8lx ", (long) &lp->tx_ring[i].base); - } - } - printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base); - printk("\nDescriptor buffers:\nRX: "); - for (i=0;irxRingMask;i++){ - if (i < 3) { - printk("0x%8.8x ", readl(&lp->rx_ring[i].base)); - } - } - printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base)); - printk("TX: "); - for (i=0;itxRingMask;i++){ - if (i < 3) { - printk("0x%8.8x ", readl(&lp->tx_ring[i].base)); - } - } - printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); - printk("Initialisation block at 0x%8.8lx\n",lp->sh_mem); - printk("\tmode: 0x%4.4x\n",readw(&p->mode)); - printk("\tphysical address: "); - for (i=0;iphys_addr[i])); - } - printk("%2.2x\n",(u_char)readb(&p->phys_addr[i])); - printk("\tmulticast hash table: "); - for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){ - printk("%2.2x:",(u_char)readb(&p->mcast_table[i])); - } - printk("%2.2x\n",(u_char)readb(&p->mcast_table[i])); - printk("\trx_ring at: 0x%8.8x\n",readl(&p->rx_ring)); - printk("\ttx_ring at: 0x%8.8x\n",readl(&p->tx_ring)); - printk("dma_buffs: 0x%8.8lx\n",lp->dma_buffs); - printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n", - (int)lp->rxRingMask + 1, - lp->rx_rlen); - printk("TX: %d Log2(txRingMask): 0x%8.8x\n", - (int)lp->txRingMask + 1, - lp->tx_rlen); - outw(CSR2,DEPCA_ADDR); - printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA)); - outw(CSR1,DEPCA_ADDR); - printk("%4.4x\n",inw(DEPCA_DATA)); - outw(CSR3,DEPCA_ADDR); - printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA)); - } - - return; -} - -/* -** Perform IOCTL call functions here. Some are privileged operations and the -** effective uid is checked in those cases. -** All MCA IOCTLs will not work here and are for testing purposes only. -*/ + struct depca_private *lp = (struct depca_private *) dev->priv; + u_long ioaddr = dev->base_addr; + struct depca_init *p = (struct depca_init *) lp->sh_mem; + int i; + + if (depca_debug > 1) { + /* Copy the shadow init_block to shared memory */ + memcpy_toio((char *) lp->sh_mem, &lp->init_block, sizeof(struct depca_init)); + + printk("%s: depca open with irq %d\n", dev->name, dev->irq); + printk("Descriptor head addresses:\n"); + printk("\t0x%lx 0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring); + printk("Descriptor addresses:\nRX: "); + for (i = 0; i < lp->rxRingMask; i++) { + if (i < 3) { + printk("0x%8.8lx ", (long) &lp->rx_ring[i].base); + } + } + printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base); + printk("TX: "); + for (i = 0; i < lp->txRingMask; i++) { + if (i < 3) { + printk("0x%8.8lx ", (long) &lp->tx_ring[i].base); + } + } + printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base); + printk("\nDescriptor buffers:\nRX: "); + for (i = 0; i < lp->rxRingMask; i++) { + if (i < 3) { + printk("0x%8.8x ", readl(&lp->rx_ring[i].base)); + } + } + printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base)); + printk("TX: "); + for (i = 0; i < lp->txRingMask; i++) { + if (i < 3) { + printk("0x%8.8x ", readl(&lp->tx_ring[i].base)); + } + } + printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); + printk("Initialisation block at 0x%8.8lx\n", lp->sh_mem); + printk("\tmode: 0x%4.4x\n", readw(&p->mode)); + printk("\tphysical address: "); + for (i = 0; i < ETH_ALEN - 1; i++) { + printk("%2.2x:", (u_char) readb(&p->phys_addr[i])); + } + printk("%2.2x\n", (u_char) readb(&p->phys_addr[i])); + printk("\tmulticast hash table: "); + for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) { + printk("%2.2x:", (u_char) readb(&p->mcast_table[i])); + } + printk("%2.2x\n", (u_char) readb(&p->mcast_table[i])); + printk("\trx_ring at: 0x%8.8x\n", readl(&p->rx_ring)); + printk("\ttx_ring at: 0x%8.8x\n", readl(&p->tx_ring)); + printk("dma_buffs: 0x%8.8lx\n", lp->dma_buffs); + printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n", + (int) lp->rxRingMask + 1, + lp->rx_rlen); + printk("TX: %d Log2(txRingMask): 0x%8.8x\n", + (int) lp->txRingMask + 1, + lp->tx_rlen); + outw(CSR2, DEPCA_ADDR); + printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA)); + outw(CSR1, DEPCA_ADDR); + printk("%4.4x\n", inw(DEPCA_DATA)); + outw(CSR3, DEPCA_ADDR); + printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA)); + } + return; +} + +/* + ** Perform IOCTL call functions here. Some are privileged operations and the + ** effective uid is checked in those cases. + ** All MCA IOCTLs will not work here and are for testing purposes only. + */ static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd) { - struct depca_private *lp = (struct depca_private *)dev->priv; - struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data; - int i, status = 0; - u_long ioaddr = dev->base_addr; - union { - u8 addr[(HASH_TABLE_LEN * ETH_ALEN)]; - u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1]; - u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2]; - } tmp; - - switch(ioc->cmd) { - case DEPCA_GET_HWADDR: /* Get the hardware address */ - for (i=0; idev_addr[i]; - } - ioc->len = ETH_ALEN; - if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - - break; - case DEPCA_SET_HWADDR: /* Set the hardware address */ - if (suser()) { - if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) { - copy_from_user(tmp.addr,ioc->data,ETH_ALEN); - for (i=0; idev_addr[i] = tmp.addr[i]; - } - while(dev->tbusy); /* Stop ring access */ - set_bit(0, (void*)&dev->tbusy); - while(lp->tx_old != lp->tx_new);/* Wait for the ring to empty */ - - STOP_DEPCA; /* Temporarily stop the depca. */ - depca_init_ring(dev); /* Initialize the descriptor rings */ - LoadCSRs(dev); /* Reload CSR3 */ - InitRestartDepca(dev); /* Resume normal operation. */ - dev->tbusy = 0; /* Unlock the TX ring */ - } - } else { - status = -EPERM; - } - - break; - case DEPCA_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { - while(dev->tbusy); /* Stop ring access */ - set_bit(0, (void*)&dev->tbusy); - while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ - - STOP_DEPCA; /* Temporarily stop the depca. */ - depca_init_ring(dev); /* Initialize the descriptor rings */ - lp->init_block.mode |= PROM; /* Set promiscuous mode */ - - LoadCSRs(dev); /* Reload CSR3 */ - InitRestartDepca(dev); /* Resume normal operation. */ - dev->tbusy = 0; /* Unlock the TX ring */ - } else { - status = -EPERM; - } - - break; - case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { - while(dev->tbusy); /* Stop ring access */ - set_bit(0, (void*)&dev->tbusy); - while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ - - STOP_DEPCA; /* Temporarily stop the depca. */ - depca_init_ring(dev); /* Initialize the descriptor rings */ - lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */ - - LoadCSRs(dev); /* Reload CSR3 */ - InitRestartDepca(dev); /* Resume normal operation. */ - dev->tbusy = 0; /* Unlock the TX ring */ - } else { - status = -EPERM; - } - - break; - case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */ - printk("%s: Boo!\n", dev->name); - - break; - case DEPCA_GET_MCA: /* Get the multicast address table */ - ioc->len = (HASH_TABLE_LEN >> 3); - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); - } - - break; - case DEPCA_SET_MCA: /* Set a multicast address */ - if (suser()) { - if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) { - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev); - } - } else { - status = -EPERM; - } - - break; - case DEPCA_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { - set_multicast_list(dev); - } else { - status = -EPERM; - } - - break; - case DEPCA_MCA_EN: /* Enable pass all multicast addressing */ - if (suser()) { - set_multicast_list(dev); - } else { - status = -EPERM; - } - - break; - case DEPCA_GET_STATS: /* Get the driver statistics */ - cli(); - ioc->len = sizeof(lp->pktStats); - if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } - sti(); - - break; - case DEPCA_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { - cli(); - memset(&lp->pktStats, 0, sizeof(lp->pktStats)); - sti(); - } else { - status = -EPERM; - } - - break; - case DEPCA_GET_REG: /* Get the DEPCA Registers */ - i=0; - tmp.sval[i++] = inw(DEPCA_NICSR); - outw(CSR0, DEPCA_ADDR); /* status register */ - tmp.sval[i++] = inw(DEPCA_DATA); - memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init)); - ioc->len = i+sizeof(struct depca_init); - if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - - break; - default: - status = -EOPNOTSUPP; - } + struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data; + int i, status = 0; + u_long ioaddr = dev->base_addr; + union { + u8 addr[(HASH_TABLE_LEN * ETH_ALEN)]; + u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1]; + u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2]; + } tmp; + + switch (ioc->cmd) { + case DEPCA_GET_HWADDR: /* Get the hardware address */ + for (i = 0; i < ETH_ALEN; i++) { + tmp.addr[i] = dev->dev_addr[i]; + } + ioc->len = ETH_ALEN; + if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + break; + case DEPCA_SET_HWADDR: /* Set the hardware address */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) { + copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) { + dev->dev_addr[i] = tmp.addr[i]; + } + while (dev->tbusy); /* Stop ring access */ + set_bit(0, (void *) &dev->tbusy); + while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ + + STOP_DEPCA; /* Temporarily stop the depca. */ + depca_init_ring(dev); /* Initialize the descriptor rings */ + LoadCSRs(dev); /* Reload CSR3 */ + InitRestartDepca(dev); /* Resume normal operation. */ + dev->tbusy = 0; /* Unlock the TX ring */ + } + } else { + status = -EPERM; + } + + break; + case DEPCA_SET_PROM: /* Set Promiscuous Mode */ + if (suser()) { + while (dev->tbusy); /* Stop ring access */ + set_bit(0, (void *) &dev->tbusy); + while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ + + STOP_DEPCA; /* Temporarily stop the depca. */ + depca_init_ring(dev); /* Initialize the descriptor rings */ + lp->init_block.mode |= PROM; /* Set promiscuous mode */ + + LoadCSRs(dev); /* Reload CSR3 */ + InitRestartDepca(dev); /* Resume normal operation. */ + dev->tbusy = 0; /* Unlock the TX ring */ + } else { + status = -EPERM; + } + + break; + case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */ + if (suser()) { + while (dev->tbusy); /* Stop ring access */ + set_bit(0, (void *) &dev->tbusy); + while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ + + STOP_DEPCA; /* Temporarily stop the depca. */ + depca_init_ring(dev); /* Initialize the descriptor rings */ + lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */ + + LoadCSRs(dev); /* Reload CSR3 */ + InitRestartDepca(dev); /* Resume normal operation. */ + dev->tbusy = 0; /* Unlock the TX ring */ + } else { + status = -EPERM; + } + + break; + case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */ + printk("%s: Boo!\n", dev->name); + + break; + case DEPCA_GET_MCA: /* Get the multicast address table */ + ioc->len = (HASH_TABLE_LEN >> 3); + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); + } + break; + case DEPCA_SET_MCA: /* Set a multicast address */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) { + copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); + set_multicast_list(dev); + } + } else { + status = -EPERM; + } + + break; + case DEPCA_CLR_MCA: /* Clear all multicast addresses */ + if (suser()) { + set_multicast_list(dev); + } else { + status = -EPERM; + } + + break; + case DEPCA_MCA_EN: /* Enable pass all multicast addressing */ + if (suser()) { + set_multicast_list(dev); + } else { + status = -EPERM; + } - return status; + break; + case DEPCA_GET_STATS: /* Get the driver statistics */ + cli(); + ioc->len = sizeof(lp->pktStats); + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, &lp->pktStats, ioc->len); + } + sti(); + + break; + case DEPCA_CLR_STATS: /* Zero out the driver statistics */ + if (suser()) { + cli(); + memset(&lp->pktStats, 0, sizeof(lp->pktStats)); + sti(); + } else { + status = -EPERM; + } + + break; + case DEPCA_GET_REG: /* Get the DEPCA Registers */ + i = 0; + tmp.sval[i++] = inw(DEPCA_NICSR); + outw(CSR0, DEPCA_ADDR); /* status register */ + tmp.sval[i++] = inw(DEPCA_DATA); + memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init)); + ioc->len = i + sizeof(struct depca_init); + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + break; + default: + status = -EOPNOTSUPP; + } + + return status; } #ifdef MODULE -static char devicename[9] = { 0, }; -static struct device thisDepca = { - devicename, /* device name is inserted by /linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0x200, 7, /* I/O address, IRQ */ - 0, 0, 0, NULL, depca_probe }; +static char devicename[9] = +{0,}; +static struct device thisDepca = +{ + devicename, /* device name is inserted by /linux/drivers/net/net_init.c */ + 0, 0, 0, 0, + 0x200, 7, /* I/O address, IRQ */ + 0, 0, 0, NULL, depca_probe}; -static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */ -static int io=0x200; /* Or use the irq= io= options to insmod */ +static int irq = 7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */ +static int io = 0x200; /* Or use the irq= io= options to insmod */ MODULE_PARM(irq, "i"); MODULE_PARM(io, "i"); /* See depca_probe() for autoprobe messages when a module */ -int -init_module(void) +int init_module(void) { - thisDepca.irq=irq; - thisDepca.base_addr=io; + thisDepca.irq = irq; + thisDepca.base_addr = io; - if (register_netdev(&thisDepca) != 0) - return -EIO; + if (register_netdev(&thisDepca) != 0) + return -EIO; - return 0; + return 0; } -void -cleanup_module(void) +void cleanup_module(void) { - if (thisDepca.priv) { - kfree(thisDepca.priv); - thisDepca.priv = NULL; - } - thisDepca.irq=0; + if (thisDepca.priv) { + kfree(thisDepca.priv); + thisDepca.priv = NULL; + } + thisDepca.irq = 0; - unregister_netdev(&thisDepca); - release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE); + unregister_netdev(&thisDepca); + release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE); } -#endif /* MODULE */ - +#endif /* MODULE */ + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c depca.c" diff -u --recursive --new-file v2.1.66/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.1.66/linux/drivers/net/dlci.c Tue May 13 22:41:09 1997 +++ linux/drivers/net/dlci.c Sat Nov 29 10:33:19 1997 @@ -591,16 +591,9 @@ dlp->receive = dlci_receive; dev->type = ARPHRD_DLCI; - dev->family = AF_INET; dev->hard_header_len = sizeof(struct frhdr); - dev->pa_alen = 4; dev->addr_len = sizeof(short); memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); - - dev->pa_addr = 0; - dev->pa_dstaddr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; dev_init_buffers(dev); diff -u --recursive --new-file v2.1.66/linux/drivers/net/dummy.c linux/drivers/net/dummy.c --- v2.1.66/linux/drivers/net/dummy.c Sat May 24 09:10:23 1997 +++ linux/drivers/net/dummy.c Sat Nov 29 10:33:19 1997 @@ -82,7 +82,7 @@ if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_device_stats)); - dev->get_stats = dummy_get_stats; + dev->get_stats = dummy_get_stats; dev->open = dummy_open; dev->stop = dummy_close; @@ -92,6 +92,7 @@ ether_setup(dev); dev->tx_queue_len = 0; dev->flags |= IFF_NOARP; + dev->flags &= ~IFF_BROADCAST; return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.66/linux/drivers/net/eepro100.c Tue Nov 18 17:22:07 1997 +++ linux/drivers/net/eepro100.c Sat Nov 29 10:33:19 1997 @@ -1040,13 +1040,6 @@ int ioaddr = dev->base_addr; int entry; - if (skb == NULL || skb->len <= 0) { - printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n", - dev->name); - dev_tint(dev); - return 0; - } - /* 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 this ever occurs the queue layer is doing something evil! */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.1.66/linux/drivers/net/eql.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/eql.c Sat Nov 29 10:33:19 1997 @@ -262,12 +262,6 @@ dev->mtu = EQL_DEFAULT_MTU; /* set to 576 in eql.h */ dev->flags = IFF_MASTER; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; - dev->type = ARPHRD_SLIP; dev->tx_queue_len = 5; /* Hands them off fast */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c --- v2.1.66/linux/drivers/net/ethertap.c Thu Sep 4 17:07:30 1997 +++ linux/drivers/net/ethertap.c Sat Nov 29 10:33:19 1997 @@ -20,11 +20,12 @@ #include #include +#include #include #include #include -#include +#include /* * Index to functions. @@ -98,14 +99,25 @@ static int ethertap_open(struct device *dev) { + struct in_device *in_dev; if (ethertap_debug > 2) printk("%s: Doing ethertap_open()...", dev->name); netlink_attach(dev->base_addr, ethertap_rx); dev->start = 1; dev->tbusy = 0; + /* Fill in the MAC based on the IP address. We do the same thing here as PLIP does */ - memcpy(dev->dev_addr+2,&dev->pa_addr,4); + + if((in_dev=dev->ip_ptr)!=NULL) + { + /* + * Any address wil do - we take the first + */ + struct in_ifaddr *ifa=in_dev->ifa_list; + if(ifa!=NULL) + memcpy(dev->dev_addr+2,&ifa->ifa_local,4); + } MOD_INC_USE_COUNT; return 0; } @@ -147,7 +159,7 @@ if(dev==NULL) { - printk("%s: bad unit!\n",dev->name); + printk("ethertap: bad unit!\n"); kfree_skb(skb, FREE_WRITE); return -ENXIO; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.1.66/linux/drivers/net/ewrk3.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/ewrk3.c Sat Nov 29 10:33:19 1997 @@ -1,140 +1,140 @@ /* ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for Linux. - Written 1994 by David C. Davies. + Written 1994 by David C. Davies. - Copyright 1994 Digital Equipment Corporation. + Copyright 1994 Digital Equipment Corporation. - This software may be used and distributed according to the terms of - the GNU Public License, incorporated herein by reference. + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. - This driver is written for the Digital Equipment Corporation series - of EtherWORKS ethernet cards: - - DE203 Turbo (BNC) - DE204 Turbo (TP) - DE205 Turbo (TP BNC) - - The driver has been tested on a relatively busy network using the DE205 - card and benchmarked with 'ttcp': it transferred 16M of data at 975kB/s - (7.8Mb/s) to a DECstation 5000/200. - - The author may be reached at davies@maniac.ultranet.com. - - ========================================================================= - This driver has been written substantially from scratch, although its - inheritance of style and stack interface from 'depca.c' and in turn from - Donald Becker's 'lance.c' should be obvious. - - The DE203/4/5 boards all use a new proprietary chip in place of the - LANCE chip used in prior cards (DEPCA, DE100, DE200/1/2, DE210, DE422). - Use the depca.c driver in the standard distribution for the LANCE based - cards from DIGITAL; this driver will not work with them. - - The DE203/4/5 cards have 2 main modes: shared memory and I/O only. I/O - only makes all the card accesses through I/O transactions and no high - (shared) memory is used. This mode provides a >48% performance penalty - and is deprecated in this driver, although allowed to provide initial - setup when hardstrapped. - - The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is - no point in using any mode other than the 2kB mode - their performances - are virtually identical, although the driver has been tested in the 2kB - and 32kB modes. I would suggest you uncomment the line: - - FORCE_2K_MODE; - - to allow the driver to configure the card as a 2kB card at your current - base address, thus leaving more room to clutter your system box with - other memory hungry boards. - - As many ISA and EISA cards can be supported under this driver as you - wish, limited primarily by the available IRQ lines, rather than by the - available I/O addresses (24 ISA, 16 EISA). I have checked different - configurations of multiple depca cards and ewrk3 cards and have not - found a problem yet (provided you have at least depca.c v0.38) ... - - The board IRQ setting must be at an unused IRQ which is auto-probed - using Donald Becker's autoprobe routines. All these cards are at - {5,10,11,15}. - - No 16MB memory limitation should exist with this driver as DMA is not - used and the common memory area is in low memory on the network card (my - current system has 20MB and I've not had problems yet). - - The ability to load this driver as a loadable module has been included - and used extensively during the driver development (to save those long - reboot sequences). To utilise this ability, you have to do 8 things: - - 0) have a copy of the loadable modules code installed on your system. - 1) copy ewrk3.c from the /linux/drivers/net directory to your favourite - temporary directory. - 2) edit the source code near line 1898 to reflect the I/O address and - IRQ you're using. - 3) compile ewrk3.c, but include -DMODULE in the command line to ensure - that the correct bits are compiled (see end of source code). - 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a - kernel with the ewrk3 configuration turned off and reboot. - 5) insmod ewrk3.o - [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y] - 6) run the net startup bits for your new eth?? interface manually - (usually /etc/rc.inet[12] at boot time). - 7) enjoy! - - Note that autoprobing is not allowed in loadable modules - the system is - already up and running and you're messing with interrupts. - - To unload a module, turn off the associated interface - 'ifconfig eth?? down' then 'rmmod ewrk3'. - - Promiscuous mode has been turned off in this driver, but all the - multicast address bits have been turned on. This improved the send - performance on a busy network by about 13%. - - Ioctl's have now been provided (primarily because I wanted to grab some - packet size statistics). They are patterned after 'plipconfig.c' from a - suggestion by Alan Cox. Using these ioctls, you can enable promiscuous - mode, add/delete multicast addresses, change the hardware address, get - packet size distribution statistics and muck around with the control and - status register. I'll add others if and when the need arises. - - TO DO: - ------ - - - Revision History - ---------------- - - Version Date Description - - 0.1 26-aug-94 Initial writing. ALPHA code release. - 0.11 31-aug-94 Fixed: 2k mode memory base calc., - LeMAC version calc., - IRQ vector assignments during autoprobe. - 0.12 31-aug-94 Tested working on LeMAC2 (DE20[345]-AC) card. - Fixed up MCA hash table algorithm. - 0.20 4-sep-94 Added IOCTL functionality. - 0.21 14-sep-94 Added I/O mode. - 0.21axp 15-sep-94 Special version for ALPHA AXP Linux V1.0. - 0.22 16-sep-94 Added more IOCTLs & tidied up. - 0.23 21-sep-94 Added transmit cut through. - 0.24 31-oct-94 Added uid checks in some ioctls. - 0.30 1-nov-94 BETA code release. - 0.31 5-dec-94 Added check/allocate region code. - 0.32 16-jan-95 Broadcast packet fix. - 0.33 10-Feb-95 Fix recognition bug reported by . - 0.40 27-Dec-95 Rationalise MODULE and autoprobe code. - Rewrite for portability & updated. - ALPHA support from - Added verify_area() calls in ewrk3_ioctl() from - suggestion by . - Add new multicasting code. - 0.41 20-Jan-96 Fix IRQ set up problem reported by - . - 0.42 22-Apr-96 Fix alloc_device() bug - 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c + This driver is written for the Digital Equipment Corporation series + of EtherWORKS ethernet cards: + + DE203 Turbo (BNC) + DE204 Turbo (TP) + DE205 Turbo (TP BNC) + + The driver has been tested on a relatively busy network using the DE205 + card and benchmarked with 'ttcp': it transferred 16M of data at 975kB/s + (7.8Mb/s) to a DECstation 5000/200. + + The author may be reached at davies@maniac.ultranet.com. + + ========================================================================= + This driver has been written substantially from scratch, although its + inheritance of style and stack interface from 'depca.c' and in turn from + Donald Becker's 'lance.c' should be obvious. + + The DE203/4/5 boards all use a new proprietary chip in place of the + LANCE chip used in prior cards (DEPCA, DE100, DE200/1/2, DE210, DE422). + Use the depca.c driver in the standard distribution for the LANCE based + cards from DIGITAL; this driver will not work with them. + + The DE203/4/5 cards have 2 main modes: shared memory and I/O only. I/O + only makes all the card accesses through I/O transactions and no high + (shared) memory is used. This mode provides a >48% performance penalty + and is deprecated in this driver, although allowed to provide initial + setup when hardstrapped. + + The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is + no point in using any mode other than the 2kB mode - their performances + are virtually identical, although the driver has been tested in the 2kB + and 32kB modes. I would suggest you uncomment the line: + + FORCE_2K_MODE; + + to allow the driver to configure the card as a 2kB card at your current + base address, thus leaving more room to clutter your system box with + other memory hungry boards. + + As many ISA and EISA cards can be supported under this driver as you + wish, limited primarily by the available IRQ lines, rather than by the + available I/O addresses (24 ISA, 16 EISA). I have checked different + configurations of multiple depca cards and ewrk3 cards and have not + found a problem yet (provided you have at least depca.c v0.38) ... + + The board IRQ setting must be at an unused IRQ which is auto-probed + using Donald Becker's autoprobe routines. All these cards are at + {5,10,11,15}. + + No 16MB memory limitation should exist with this driver as DMA is not + used and the common memory area is in low memory on the network card (my + current system has 20MB and I've not had problems yet). + + The ability to load this driver as a loadable module has been included + and used extensively during the driver development (to save those long + reboot sequences). To utilise this ability, you have to do 8 things: + + 0) have a copy of the loadable modules code installed on your system. + 1) copy ewrk3.c from the /linux/drivers/net directory to your favourite + temporary directory. + 2) edit the source code near line 1898 to reflect the I/O address and + IRQ you're using. + 3) compile ewrk3.c, but include -DMODULE in the command line to ensure + that the correct bits are compiled (see end of source code). + 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a + kernel with the ewrk3 configuration turned off and reboot. + 5) insmod ewrk3.o + [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y] + 6) run the net startup bits for your new eth?? interface manually + (usually /etc/rc.inet[12] at boot time). + 7) enjoy! + + Note that autoprobing is not allowed in loadable modules - the system is + already up and running and you're messing with interrupts. + + To unload a module, turn off the associated interface + 'ifconfig eth?? down' then 'rmmod ewrk3'. + + Promiscuous mode has been turned off in this driver, but all the + multicast address bits have been turned on. This improved the send + performance on a busy network by about 13%. + + Ioctl's have now been provided (primarily because I wanted to grab some + packet size statistics). They are patterned after 'plipconfig.c' from a + suggestion by Alan Cox. Using these ioctls, you can enable promiscuous + mode, add/delete multicast addresses, change the hardware address, get + packet size distribution statistics and muck around with the control and + status register. I'll add others if and when the need arises. + + TO DO: + ------ + + + Revision History + ---------------- + + Version Date Description + + 0.1 26-aug-94 Initial writing. ALPHA code release. + 0.11 31-aug-94 Fixed: 2k mode memory base calc., + LeMAC version calc., + IRQ vector assignments during autoprobe. + 0.12 31-aug-94 Tested working on LeMAC2 (DE20[345]-AC) card. + Fixed up MCA hash table algorithm. + 0.20 4-sep-94 Added IOCTL functionality. + 0.21 14-sep-94 Added I/O mode. + 0.21axp 15-sep-94 Special version for ALPHA AXP Linux V1.0. + 0.22 16-sep-94 Added more IOCTLs & tidied up. + 0.23 21-sep-94 Added transmit cut through. + 0.24 31-oct-94 Added uid checks in some ioctls. + 0.30 1-nov-94 BETA code release. + 0.31 5-dec-94 Added check/allocate region code. + 0.32 16-jan-95 Broadcast packet fix. + 0.33 10-Feb-95 Fix recognition bug reported by . + 0.40 27-Dec-95 Rationalise MODULE and autoprobe code. + Rewrite for portability & updated. + ALPHA support from + Added verify_area() calls in ewrk3_ioctl() from + suggestion by . + Add new multicasting code. + 0.41 20-Jan-96 Fix IRQ set up problem reported by + . + 0.42 22-Apr-96 Fix alloc_device() bug + 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c - ========================================================================= -*/ + ========================================================================= + */ static const char *version = "ewrk3.c:v0.43 96/8/16 davies@maniac.ultranet.com\n"; @@ -172,7 +172,7 @@ static int ewrk3_debug = 1; #endif -#define EWRK3_NDA 0xffe0 /* No Device Address */ +#define EWRK3_NDA 0xffe0 /* No Device Address */ #define PROBE_LENGTH 32 #define ETH_PROM_SIG 0xAA5500FFUL @@ -187,18 +187,18 @@ #endif /* -** Sets up the I/O area for the autoprobe. -*/ -#define EWRK3_IO_BASE 0x100 /* Start address for probe search */ -#define EWRK3_IOP_INC 0x20 /* I/O address increment */ -#define EWRK3_TOTAL_SIZE 0x20 /* required I/O address length */ + ** Sets up the I/O area for the autoprobe. + */ +#define EWRK3_IO_BASE 0x100 /* Start address for probe search */ +#define EWRK3_IOP_INC 0x20 /* I/O address increment */ +#define EWRK3_TOTAL_SIZE 0x20 /* required I/O address length */ #ifndef MAX_NUM_EWRK3S #define MAX_NUM_EWRK3S 21 #endif #ifndef EWRK3_EISA_IO_PORTS -#define EWRK3_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ +#define EWRK3_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */ #endif #ifndef MAX_EISA_SLOTS @@ -206,22 +206,22 @@ #define EISA_SLOT_INC 0x1000 #endif -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ -#define QUEUE_PKT_TIMEOUT (1*HZ) /* Jiffies */ +#define QUEUE_PKT_TIMEOUT (1*HZ) /* Jiffies */ /* -** EtherWORKS 3 shared memory window sizes -*/ + ** EtherWORKS 3 shared memory window sizes + */ #define IO_ONLY 0x00 #define SHMEM_2K 0x800 #define SHMEM_32K 0x8000 #define SHMEM_64K 0x10000 /* -** EtherWORKS 3 IRQ ENABLE/DISABLE -*/ + ** EtherWORKS 3 IRQ ENABLE/DISABLE + */ #define ENABLE_IRQs { \ icr |= lp->irq_mask;\ outb(icr, EWRK3_ICR); /* Enable the IRQs */\ @@ -234,8 +234,8 @@ } /* -** EtherWORKS 3 START/STOP -*/ + ** EtherWORKS 3 START/STOP + */ #define START_EWRK3 { \ csr = inb(EWRK3_CSR);\ csr &= ~(CSR_TXD|CSR_RXD);\ @@ -248,1662 +248,1674 @@ } /* -** The EtherWORKS 3 private structure -*/ + ** The EtherWORKS 3 private structure + */ #define EWRK3_PKT_STAT_SZ 16 -#define EWRK3_PKT_BIN_SZ 128 /* Should be >=100 unless you - increase EWRK3_PKT_STAT_SZ */ +#define EWRK3_PKT_BIN_SZ 128 /* Should be >=100 unless you + increase EWRK3_PKT_STAT_SZ */ struct ewrk3_private { - char adapter_name[80]; /* Name exported to /proc/ioports */ - u_long shmem_base; /* Shared memory start address */ - u_long shmem_length; /* Shared memory window length */ - struct net_device_stats stats; /* Public stats */ - struct { - u32 bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */ - u32 unicast; - u32 multicast; - u32 broadcast; - u32 excessive_collisions; - u32 tx_underruns; - u32 excessive_underruns; - } pktStats; - u_char irq_mask; /* Adapter IRQ mask bits */ - u_char mPage; /* Maximum 2kB Page number */ - u_char lemac; /* Chip rev. level */ - u_char hard_strapped; /* Don't allow a full open */ - u_char lock; /* Lock the page register */ - u_char txc; /* Transmit cut through */ - u_char *mctbl; /* Pointer to the multicast table */ + char adapter_name[80]; /* Name exported to /proc/ioports */ + u_long shmem_base; /* Shared memory start address */ + u_long shmem_length; /* Shared memory window length */ + struct net_device_stats stats; /* Public stats */ + struct { + u32 bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */ + u32 unicast; + u32 multicast; + u32 broadcast; + u32 excessive_collisions; + u32 tx_underruns; + u32 excessive_underruns; + } pktStats; + u_char irq_mask; /* Adapter IRQ mask bits */ + u_char mPage; /* Maximum 2kB Page number */ + u_char lemac; /* Chip rev. level */ + u_char hard_strapped; /* Don't allow a full open */ + u_char lock; /* Lock the page register */ + u_char txc; /* Transmit cut through */ + u_char *mctbl; /* Pointer to the multicast table */ }; /* -** Force the EtherWORKS 3 card to be in 2kB MODE -*/ + ** Force the EtherWORKS 3 card to be in 2kB MODE + */ #define FORCE_2K_MODE { \ shmem_length = SHMEM_2K;\ outb(((mem_start - 0x80000) >> 11), EWRK3_MBR);\ } /* -** Public Functions -*/ -static int ewrk3_open(struct device *dev); -static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev); -static void ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int ewrk3_close(struct device *dev); + ** Public Functions + */ +static int ewrk3_open(struct device *dev); +static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev); +static void ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int ewrk3_close(struct device *dev); static struct net_device_stats *ewrk3_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev); -static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static void set_multicast_list(struct device *dev); +static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd); /* -** Private functions -*/ -static int ewrk3_hw_init(struct device *dev, u_long iobase); -static void ewrk3_init(struct device *dev); -static int ewrk3_rx(struct device *dev); -static int ewrk3_tx(struct device *dev); - -static void EthwrkSignature(char * name, char *eeprom_image); -static int DevicePresent(u_long iobase); -static void SetMulticastFilter(struct device *dev); -static int EISA_signature(char *name, s32 eisa_id); - -static int Read_EEPROM(u_long iobase, u_char eaddr); -static int Write_EEPROM(short data, u_long iobase, u_char eaddr); -static u_char get_hw_addr (struct device *dev, u_char *eeprom_image, char chipType); + ** Private functions + */ +static int ewrk3_hw_init(struct device *dev, u_long iobase); +static void ewrk3_init(struct device *dev); +static int ewrk3_rx(struct device *dev); +static int ewrk3_tx(struct device *dev); + +static void EthwrkSignature(char *name, char *eeprom_image); +static int DevicePresent(u_long iobase); +static void SetMulticastFilter(struct device *dev); +static int EISA_signature(char *name, s32 eisa_id); + +static int Read_EEPROM(u_long iobase, u_char eaddr); +static int Write_EEPROM(short data, u_long iobase, u_char eaddr); +static u_char get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType); -static void isa_probe(struct device *dev, u_long iobase); -static void eisa_probe(struct device *dev, u_long iobase); +static void isa_probe(struct device *dev, u_long iobase); +static void eisa_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); -static int ewrk3_dev_index(char *s); -static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)); +static int ewrk3_dev_index(char *s); +static struct device *insert_device(struct device *dev, u_long iobase, int (*init) (struct device *)); #ifdef MODULE -int init_module(void); +int init_module(void); void cleanup_module(void); static int autoprobed = 1, loading_module = 1; -# else -static u_char irq[] = {5,0,10,3,11,9,15,12}; +#else +static u_char irq[] = +{5, 0, 10, 3, 11, 9, 15, 12}; static int autoprobed = 0, loading_module = 0; -#endif /* MODULE */ +#endif /* MODULE */ static char name[EWRK3_STRLEN + 1]; static int num_ewrk3s = 0, num_eth = 0; /* -** Miscellaneous defines... -*/ + ** Miscellaneous defines... + */ #define INIT_EWRK3 {\ outb(EEPROM_INIT, EWRK3_IOPR);\ udelay(1000);\ } + - __initfunc(int ewrk3_probe(struct device *dev)) { - int tmp = num_ewrk3s, status = -ENODEV; - u_long iobase = dev->base_addr; + int tmp = num_ewrk3s, status = -ENODEV; + u_long iobase = dev->base_addr; - if ((iobase == 0) && loading_module){ - printk("Autoprobing is not supported when loading a module based driver.\n"); - status = -EIO; - } else { /* First probe for the Ethernet */ - /* Address PROM pattern */ - isa_probe(dev, iobase); - eisa_probe(dev, iobase); - - if ((tmp == num_ewrk3s) && (iobase != 0) && loading_module) { - printk("%s: ewrk3_probe() cannot find device at 0x%04lx.\n", dev->name, - iobase); - } - - /* - ** Walk the device list to check that at least one device - ** initialised OK - */ - for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); - - if (dev->priv) status = 0; - if (iobase == 0) autoprobed = 1; - } + if ((iobase == 0) && loading_module) { + printk("Autoprobing is not supported when loading a module based driver.\n"); + status = -EIO; + } else { /* First probe for the Ethernet */ + /* Address PROM pattern */ + isa_probe(dev, iobase); + eisa_probe(dev, iobase); + + if ((tmp == num_ewrk3s) && (iobase != 0) && loading_module) { + printk("%s: ewrk3_probe() cannot find device at 0x%04lx.\n", dev->name, + iobase); + } + /* + ** Walk the device list to check that at least one device + ** initialised OK + */ + for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next); + + if (dev->priv) + status = 0; + if (iobase == 0) + autoprobed = 1; + } - return status; + return status; } __initfunc(static int -ewrk3_hw_init(struct device *dev, u_long iobase)) + ewrk3_hw_init(struct device *dev, u_long iobase)) { - struct ewrk3_private *lp; - int i, status=0; - u_long mem_start, shmem_length; - u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0; - u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; - - /* - ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. - ** This also disables the EISA_ENABLE bit in the EISA Control Register. - */ - if (iobase > 0x400) eisa_cr = inb(EISA_CR); - INIT_EWRK3; - - nicsr = inb(EWRK3_CSR); - - icr = inb(EWRK3_ICR); - icr &= 0x70; - outb(icr, EWRK3_ICR); /* Disable all the IRQs */ - - if (nicsr == (CSR_TXD|CSR_RXD)) { - - /* Check that the EEPROM is alive and well and not living on Pluto... */ - for (chksum=0, i=0; i>1)); - eeprom_image[i] = tmp.c[0]; - eeprom_image[i+1] = tmp.c[1]; - chksum += eeprom_image[i] + eeprom_image[i+1]; - } - - if (chksum != 0) { /* Bad EEPROM Data! */ - printk("%s: Device has a bad on-board EEPROM.\n", dev->name); - status = -ENXIO; - } else { - EthwrkSignature(name, eeprom_image); - if (*name != '\0') { /* found a EWRK3 device */ - dev->base_addr = iobase; - - if (iobase > 0x400) { - outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ - } - - lemac = eeprom_image[EEPROM_CHIPVER]; - cmr = inb(EWRK3_CMR); - - if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || - ((lemac == LeMAC2) && !(cmr & CMR_HS))) { - printk("%s: %s at %#4lx", dev->name, name, iobase); - hard_strapped = 1; - } else if ((iobase&0x0fff)==EWRK3_EISA_IO_PORTS) { - /* EISA slot address */ - printk("%s: %s at %#4lx (EISA slot %ld)", - dev->name, name, iobase, ((iobase>>12)&0x0f)); - } else { /* ISA port address */ - printk("%s: %s at %#4lx", dev->name, name, iobase); - } - - if (!status) { - printk(", h/w address "); - if (lemac!=LeMAC2) DevicePresent(iobase);/* need after EWRK3_INIT */ - status = get_hw_addr(dev, eeprom_image, lemac); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); - - if (status) { - printk(" which has an EEPROM CRC error.\n"); - status = -ENXIO; - } else { - if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ - cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); - if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) cmr |= CMR_RA; - if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) cmr |= CMR_WB; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) cmr |= CMR_POLARITY; - if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) cmr |= CMR_LINK; - if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) cmr |= CMR_0WS; - } - if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) cmr |= CMR_DRAM; - outb(cmr, EWRK3_CMR); - - cr = inb(EWRK3_CR); /* Set up the Control Register */ - cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; - if (cr & SETUP_APD) cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; - cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; - cr |= eeprom_image[EEPROM_MISC0] & ENA_16; - outb(cr, EWRK3_CR); - - /* - ** Determine the base address and window length for the EWRK3 - ** RAM from the memory base register. - */ - mem_start = inb(EWRK3_MBR); - shmem_length = 0; - if (mem_start != 0) { - if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { - mem_start *= SHMEM_64K; - shmem_length = SHMEM_64K; - } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { - mem_start *= SHMEM_32K; - shmem_length = SHMEM_32K; - } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { - mem_start = mem_start * SHMEM_2K + 0x80000; - shmem_length = SHMEM_2K; - } else { - status = -ENXIO; - } - } + struct ewrk3_private *lp; + int i, status = 0; + u_long mem_start, shmem_length; + u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0; + u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; - /* - ** See the top of this source code for comments about - ** uncommenting this line. - */ -/* FORCE_2K_MODE;*/ - - if (!status) { - if (hard_strapped) { - printk(" is hard strapped.\n"); - } else if (mem_start) { - printk(" has a %dk RAM window", (int)(shmem_length >> 10)); - printk(" at 0x%.5lx", mem_start); - } else { - printk(" is in I/O only mode"); - } - - /* private area & initialise */ - dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), - GFP_KERNEL); - if (dev->priv == NULL) { - return -ENOMEM; - } - lp = (struct ewrk3_private *)dev->priv; - memset(dev->priv, 0, sizeof(struct ewrk3_private)); - lp->shmem_base = mem_start; - lp->shmem_length = shmem_length; - lp->lemac = lemac; - lp->hard_strapped = hard_strapped; - - lp->mPage = 64; - if (cmr & CMR_DRAM) lp->mPage <<= 1 ;/* 2 DRAMS on module */ - - sprintf(lp->adapter_name,"%s (%s)", name, dev->name); - request_region(iobase, EWRK3_TOTAL_SIZE, lp->adapter_name); - - lp->irq_mask = ICR_TNEM|ICR_TXDM|ICR_RNEM|ICR_RXDM; + /* + ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. + ** This also disables the EISA_ENABLE bit in the EISA Control Register. + */ + if (iobase > 0x400) + eisa_cr = inb(EISA_CR); + INIT_EWRK3; + + nicsr = inb(EWRK3_CSR); + + icr = inb(EWRK3_ICR); + icr &= 0x70; + outb(icr, EWRK3_ICR); /* Disable all the IRQs */ + + if (nicsr == (CSR_TXD | CSR_RXD)) { + + /* Check that the EEPROM is alive and well and not living on Pluto... */ + for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) { + union { + short val; + char c[2]; + } tmp; + + tmp.val = (short) Read_EEPROM(iobase, (i >> 1)); + eeprom_image[i] = tmp.c[0]; + eeprom_image[i + 1] = tmp.c[1]; + chksum += eeprom_image[i] + eeprom_image[i + 1]; + } - if (!hard_strapped) { - /* - ** Enable EWRK3 board interrupts for autoprobing - */ - icr |= ICR_IE; /* Enable interrupts */ - outb(icr, EWRK3_ICR); - - /* The DMA channel may be passed in on this parameter. */ - dev->dma = 0; - - /* To auto-IRQ we enable the initialization-done and DMA err, - interrupts. For now we will always get a DMA error. */ - if (dev->irq < 2) { + if (chksum != 0) { /* Bad EEPROM Data! */ + printk("%s: Device has a bad on-board EEPROM.\n", dev->name); + status = -ENXIO; + } else { + EthwrkSignature(name, eeprom_image); + if (*name != '\0') { /* found a EWRK3 device */ + dev->base_addr = iobase; + + if (iobase > 0x400) { + outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */ + } + lemac = eeprom_image[EEPROM_CHIPVER]; + cmr = inb(EWRK3_CMR); + + if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) || + ((lemac == LeMAC2) && !(cmr & CMR_HS))) { + printk("%s: %s at %#4lx", dev->name, name, iobase); + hard_strapped = 1; + } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) { + /* EISA slot address */ + printk("%s: %s at %#4lx (EISA slot %ld)", + dev->name, name, iobase, ((iobase >> 12) & 0x0f)); + } else { /* ISA port address */ + printk("%s: %s at %#4lx", dev->name, name, iobase); + } + + if (!status) { + printk(", h/w address "); + if (lemac != LeMAC2) + DevicePresent(iobase); /* need after EWRK3_INIT */ + status = get_hw_addr(dev, eeprom_image, lemac); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ + printk("%2.2x:", dev->dev_addr[i]); + } + printk("%2.2x,\n", dev->dev_addr[i]); + + if (status) { + printk(" which has an EEPROM CRC error.\n"); + status = -ENXIO; + } else { + if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */ + cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS); + if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) + cmr |= CMR_RA; + if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) + cmr |= CMR_WB; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) + cmr |= CMR_POLARITY; + if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) + cmr |= CMR_LINK; + if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) + cmr |= CMR_0WS; + } + if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) + cmr |= CMR_DRAM; + outb(cmr, EWRK3_CMR); + + cr = inb(EWRK3_CR); /* Set up the Control Register */ + cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD; + if (cr & SETUP_APD) + cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS; + cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS; + cr |= eeprom_image[EEPROM_MISC0] & ENA_16; + outb(cr, EWRK3_CR); + + /* + ** Determine the base address and window length for the EWRK3 + ** RAM from the memory base register. + */ + mem_start = inb(EWRK3_MBR); + shmem_length = 0; + if (mem_start != 0) { + if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) { + mem_start *= SHMEM_64K; + shmem_length = SHMEM_64K; + } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) { + mem_start *= SHMEM_32K; + shmem_length = SHMEM_32K; + } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) { + mem_start = mem_start * SHMEM_2K + 0x80000; + shmem_length = SHMEM_2K; + } else { + status = -ENXIO; + } + } + /* + ** See the top of this source code for comments about + ** uncommenting this line. + */ +/* FORCE_2K_MODE; */ + + if (!status) { + if (hard_strapped) { + printk(" is hard strapped.\n"); + } else if (mem_start) { + printk(" has a %dk RAM window", (int) (shmem_length >> 10)); + printk(" at 0x%.5lx", mem_start); + } else { + printk(" is in I/O only mode"); + } + + /* private area & initialise */ + dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), + GFP_KERNEL); + if (dev->priv == NULL) { + return -ENOMEM; + } + lp = (struct ewrk3_private *) dev->priv; + memset(dev->priv, 0, sizeof(struct ewrk3_private)); + lp->shmem_base = mem_start; + lp->shmem_length = shmem_length; + lp->lemac = lemac; + lp->hard_strapped = hard_strapped; + + lp->mPage = 64; + if (cmr & CMR_DRAM) + lp->mPage <<= 1; /* 2 DRAMS on module */ + + sprintf(lp->adapter_name, "%s (%s)", name, dev->name); + request_region(iobase, EWRK3_TOTAL_SIZE, lp->adapter_name); + + lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM; + + if (!hard_strapped) { + /* + ** Enable EWRK3 board interrupts for autoprobing + */ + icr |= ICR_IE; /* Enable interrupts */ + outb(icr, EWRK3_ICR); + + /* The DMA channel may be passed in on this parameter. */ + dev->dma = 0; + + /* To auto-IRQ we enable the initialization-done and DMA err, + interrupts. For now we will always get a DMA error. */ + if (dev->irq < 2) { #ifndef MODULE - u_char irqnum; + u_char irqnum; - autoirq_setup(0); + autoirq_setup(0); - /* - ** Trigger a TNE interrupt. - */ - icr |=ICR_TNEM; - outb(1,EWRK3_TDQ); /* Write to the TX done queue */ - outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ - - irqnum = irq[((icr & IRQ_SEL) >> 4)]; - - dev->irq = autoirq_report(1); - if ((dev->irq) && (irqnum == dev->irq)) { - printk(" and uses IRQ%d.\n", dev->irq); - } else { - if (!dev->irq) { - printk(" and failed to detect IRQ line.\n"); - } else if ((irqnum == 1) && (lemac == LeMAC2)) { - printk(" and an illegal IRQ line detected.\n"); - } else { - printk(", but incorrect IRQ line detected.\n"); - } - status = -ENXIO; - } + /* + ** Trigger a TNE interrupt. + */ + icr |= ICR_TNEM; + outb(1, EWRK3_TDQ); /* Write to the TX done queue */ + outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */ + + irqnum = irq[((icr & IRQ_SEL) >> 4)]; + + dev->irq = autoirq_report(1); + if ((dev->irq) && (irqnum == dev->irq)) { + printk(" and uses IRQ%d.\n", dev->irq); + } else { + if (!dev->irq) { + printk(" and failed to detect IRQ line.\n"); + } else if ((irqnum == 1) && (lemac == LeMAC2)) { + printk(" and an illegal IRQ line detected.\n"); + } else { + printk(", but incorrect IRQ line detected.\n"); + } + status = -ENXIO; + } + + DISABLE_IRQs; /* Mask all interrupts */ + +#endif /* MODULE */ + } else { + printk(" and requires IRQ%d.\n", dev->irq); + } + } + if (status) + release_region(iobase, EWRK3_TOTAL_SIZE); + } else { + status = -ENXIO; + } + } + } + } else { + status = -ENXIO; + } + } - DISABLE_IRQs; /* Mask all interrupts */ + if (!status) { + if (ewrk3_debug > 1) { + printk(version); + } + /* The EWRK3-specific entries in the device structure. */ + dev->open = &ewrk3_open; + dev->hard_start_xmit = &ewrk3_queue_pkt; + dev->stop = &ewrk3_close; + dev->get_stats = &ewrk3_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = &ewrk3_ioctl; -#endif /* MODULE */ - } else { - printk(" and requires IRQ%d.\n", dev->irq); + dev->mem_start = 0; + + /* Fill in the generic field of the device structure. */ + ether_setup(dev); } - } - if (status) release_region(iobase, EWRK3_TOTAL_SIZE); - } else { - status = -ENXIO; - } - } - } - } else { - status = -ENXIO; - } - } - - if (!status) { - if (ewrk3_debug > 1) { - printk(version); - } - - /* The EWRK3-specific entries in the device structure. */ - dev->open = &ewrk3_open; - dev->hard_start_xmit = &ewrk3_queue_pkt; - dev->stop = &ewrk3_close; - dev->get_stats = &ewrk3_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &ewrk3_ioctl; - - dev->mem_start = 0; - - /* Fill in the generic field of the device structure. */ - ether_setup(dev); - } - } else { - status = -ENXIO; - } + } else { + status = -ENXIO; + } - return status; + return status; } - -static int -ewrk3_open(struct device *dev) + +static int ewrk3_open(struct device *dev) { - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_long iobase = dev->base_addr; - int i, status = 0; - u_char icr, csr; - - /* - ** Stop the TX and RX... - */ - STOP_EWRK3; - - if (!lp->hard_strapped) { - if (request_irq(dev->irq, (void *)ewrk3_interrupt, 0, "ewrk3", dev)) { - printk("ewrk3_open(): Requested IRQ%d is busy\n",dev->irq); - status = -EAGAIN; - } else { - - /* - ** Re-initialize the EWRK3... - */ - ewrk3_init(dev); - - if (ewrk3_debug > 1){ - printk("%s: ewrk3 open with irq %d\n",dev->name,dev->irq); - printk(" physical address: "); - for (i=0;i<5;i++){ - printk("%2.2x:",(u_char)dev->dev_addr[i]); - } - printk("%2.2x\n",(u_char)dev->dev_addr[i]); - if (lp->shmem_length == 0) { - printk(" no shared memory, I/O only mode\n"); + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + int i, status = 0; + u_char icr, csr; + + /* + ** Stop the TX and RX... + */ + STOP_EWRK3; + + if (!lp->hard_strapped) { + if (request_irq(dev->irq, (void *) ewrk3_interrupt, 0, "ewrk3", dev)) { + printk("ewrk3_open(): Requested IRQ%d is busy\n", dev->irq); + status = -EAGAIN; + } else { + + /* + ** Re-initialize the EWRK3... + */ + ewrk3_init(dev); + + if (ewrk3_debug > 1) { + printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq); + printk(" physical address: "); + for (i = 0; i < 5; i++) { + printk("%2.2x:", (u_char) dev->dev_addr[i]); + } + printk("%2.2x\n", (u_char) dev->dev_addr[i]); + if (lp->shmem_length == 0) { + printk(" no shared memory, I/O only mode\n"); + } else { + printk(" start of shared memory: 0x%08lx\n", lp->shmem_base); + printk(" window length: 0x%04lx\n", lp->shmem_length); + } + printk(" # of DRAMS: %d\n", ((inb(EWRK3_CMR) & 0x02) ? 2 : 1)); + printk(" csr: 0x%02x\n", inb(EWRK3_CSR)); + printk(" cr: 0x%02x\n", inb(EWRK3_CR)); + printk(" icr: 0x%02x\n", inb(EWRK3_ICR)); + printk(" cmr: 0x%02x\n", inb(EWRK3_CMR)); + printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC)); + } + dev->tbusy = 0; + dev->start = 1; + dev->interrupt = UNMASK_INTERRUPTS; + + /* + ** Unmask EWRK3 board interrupts + */ + icr = inb(EWRK3_ICR); + ENABLE_IRQs; + + } } else { - printk(" start of shared memory: 0x%08lx\n",lp->shmem_base); - printk(" window length: 0x%04lx\n",lp->shmem_length); + dev->start = 0; + dev->tbusy = 1; + printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name); + printk(" Run the 'ewrk3setup' utility or remove the hard straps.\n"); } - printk(" # of DRAMS: %d\n",((inb(EWRK3_CMR) & 0x02) ? 2 : 1)); - printk(" csr: 0x%02x\n", inb(EWRK3_CSR)); - printk(" cr: 0x%02x\n", inb(EWRK3_CR)); - printk(" icr: 0x%02x\n", inb(EWRK3_ICR)); - printk(" cmr: 0x%02x\n", inb(EWRK3_CMR)); - printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC)); - } - - dev->tbusy = 0; - dev->start = 1; - dev->interrupt = UNMASK_INTERRUPTS; - - /* - ** Unmask EWRK3 board interrupts - */ - icr = inb(EWRK3_ICR); - ENABLE_IRQs; - - } - } else { - dev->start = 0; - dev->tbusy = 1; - printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name); - printk(" Run the 'ewrk3setup' utility or remove the hard straps.\n"); - } - - MOD_INC_USE_COUNT; - - return status; -} - -/* -** Initialize the EtherWORKS 3 operating conditions -*/ -static void -ewrk3_init(struct device *dev) -{ - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_char csr, page; - u_long iobase = dev->base_addr; - - /* - ** Enable any multicasts - */ - set_multicast_list(dev); - - /* - ** Clean out any remaining entries in all the queues here - */ - while (inb(EWRK3_TQ)); - while (inb(EWRK3_TDQ)); - while (inb(EWRK3_RQ)); - while (inb(EWRK3_FMQ)); - - /* - ** Write a clean free memory queue - */ - for (page=1;pagemPage;page++) { /* Write the free page numbers */ - outb(page, EWRK3_FMQ); /* to the Free Memory Queue */ - } - - lp->lock = 0; /* Ensure there are no locks */ - - START_EWRK3; /* Enable the TX and/or RX */ -} - -/* -** Writes a socket buffer to the free page queue -*/ -static int -ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev) -{ - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_long iobase = dev->base_addr; - int status = 0; - u_char icr, csr; - - /* Transmitter timeout, serious problems. */ - if (dev->tbusy || lp->lock) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < QUEUE_PKT_TIMEOUT) { - status = -1; - } else if (!lp->hard_strapped) { - printk("%s: transmit timed/locked out, status %04x, resetting.\n", - dev->name, inb(EWRK3_CSR)); - - /* - ** Mask all board interrupts - */ - DISABLE_IRQs; - - /* - ** Stop the TX and RX... - */ - STOP_EWRK3; - - ewrk3_init(dev); - - /* - ** Unmask EWRK3 board interrupts - */ - ENABLE_IRQs; - - dev->tbusy=0; - dev->trans_start = jiffies; - } - } else if (skb == NULL) { - dev_tint(dev); - } else if (skb->len > 0) { - - /* - ** 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("%s: Transmitter access conflict.\n", dev->name); - - DISABLE_IRQs; /* So that the page # remains correct */ - - /* - ** Get a free page from the FMQ when resources are available - */ - if (inb(EWRK3_FMQC) > 0) { - u_long buf = 0; - u_char page; - if ((page = inb(EWRK3_FMQ)) < lp->mPage) { + MOD_INC_USE_COUNT; + + return status; +} + +/* + ** Initialize the EtherWORKS 3 operating conditions + */ +static void ewrk3_init(struct device *dev) +{ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_char csr, page; + u_long iobase = dev->base_addr; + /* - ** Set up shared memory window and pointer into the window - */ - while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ - if (lp->shmem_length == IO_ONLY) { - outb(page, EWRK3_IOPR); - } else if (lp->shmem_length == SHMEM_2K) { - buf = lp->shmem_base; - outb(page, EWRK3_MPR); - } else if (lp->shmem_length == SHMEM_32K) { - buf = ((((short)page << 11) & 0x7800) + lp->shmem_base); - outb((page >> 4), EWRK3_MPR); - } else if (lp->shmem_length == SHMEM_64K) { - buf = ((((short)page << 11) & 0xf800) + lp->shmem_base); - outb((page >> 5), EWRK3_MPR); - } else { - status = -1; - printk("%s: Oops - your private data area is hosed!\n",dev->name); + ** Enable any multicasts + */ + set_multicast_list(dev); + + /* + ** Clean out any remaining entries in all the queues here + */ + while (inb(EWRK3_TQ)); + while (inb(EWRK3_TDQ)); + while (inb(EWRK3_RQ)); + while (inb(EWRK3_FMQ)); + + /* + ** Write a clean free memory queue + */ + for (page = 1; page < lp->mPage; page++) { /* Write the free page numbers */ + outb(page, EWRK3_FMQ); /* to the Free Memory Queue */ } - if (!status) { + lp->lock = 0; /* Ensure there are no locks */ - /* - ** Set up the buffer control structures and copy the data from - ** the socket buffer to the shared memory . - */ - - if (lp->shmem_length == IO_ONLY) { - int i; - u_char *p = skb->data; - - outb((char)(TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA); - outb((char)(skb->len & 0xff), EWRK3_DATA); - outb((char)((skb->len >> 8) & 0xff), EWRK3_DATA); - outb((char)0x04, EWRK3_DATA); - for (i=0; ilen; i++) { - outb(*p++, EWRK3_DATA); - } - outb(page, EWRK3_TQ); /* Start sending pkt */ - } else { - writeb((char)(TCR_QMODE|TCR_PAD|TCR_IFC), (char *)buf);/* ctrl byte*/ - buf+=1; - writeb((char)(skb->len & 0xff), (char *)buf);/* length (16 bit xfer)*/ - buf+=1; - if (lp->txc) { - writeb((char)(((skb->len >> 8) & 0xff) | XCT), (char *)buf); - buf+=1; - writeb(0x04, (char *)buf); /* index byte */ - buf+=1; - writeb(0x00, (char *)(buf + skb->len)); /* Write the XCT flag */ - memcpy_toio(buf, skb->data, PRELOAD);/* Write PRELOAD bytes*/ - outb(page, EWRK3_TQ); /* Start sending pkt */ - memcpy_toio(buf+PRELOAD, skb->data+PRELOAD, skb->len-PRELOAD); - writeb(0xff, (char *)(buf + skb->len)); /* Write the XCT flag */ - } else { - writeb((char)((skb->len >> 8) & 0xff), (char *)buf); - buf+=1; - writeb(0x04, (char *)buf); /* index byte */ - buf+=1; - memcpy_toio((char *)buf, skb->data, skb->len);/* Write data bytes */ - outb(page, EWRK3_TQ); /* Start sending pkt */ - } - } - - dev->trans_start = jiffies; - dev_kfree_skb (skb, FREE_WRITE); - - } else { /* return unused page to the free memory queue */ - outb(page, EWRK3_FMQ); - } - lp->lock = 0; /* unlock the page register */ - } else { - printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n", - (u_char) page); - } - } else { - printk("ewrk3_queue_pkt(): No free resources...\n"); - printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC)); - } - - /* Check for free resources: clear 'tbusy' if there are some */ - if (inb(EWRK3_FMQC) > 0) { - dev->tbusy = 0; - } - - ENABLE_IRQs; - } - - return status; -} - -/* -** The EWRK3 interrupt handler. -*/ -static void -ewrk3_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct device *dev = dev_id; - struct ewrk3_private *lp; - u_long iobase; - u_char icr, cr, csr; - - if (dev == NULL) { - printk ("ewrk3_interrupt(): irq %d for unknown device.\n", irq); - } else { - lp = (struct ewrk3_private *)dev->priv; - iobase = dev->base_addr; - - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - - dev->interrupt = MASK_INTERRUPTS; - - /* get the interrupt information */ - csr = inb(EWRK3_CSR); - - /* - ** Mask the EWRK3 board interrupts and turn on the LED - */ - DISABLE_IRQs; - - cr = inb(EWRK3_CR); - cr |= CR_LED; - outb(cr, EWRK3_CR); - - if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */ - ewrk3_rx(dev); - - if (csr & CSR_TNE) /* Tx interrupt (packet sent) */ - ewrk3_tx(dev); - - /* - ** Now deal with the TX/RX disable flags. These are set when there - ** are no more resources. If resources free up then enable these - ** interrupts, otherwise mask them - failure to do this will result - ** in the system hanging in an interrupt loop. - */ - if (inb(EWRK3_FMQC)) { /* any resources available? */ - lp->irq_mask |= ICR_TXDM|ICR_RXDM;/* enable the interrupt source */ - csr &= ~(CSR_TXD|CSR_RXD);/* ensure restart of a stalled TX or RX */ - outb(csr, EWRK3_CSR); - dev->tbusy = 0; /* clear TX busy flag */ - mark_bh(NET_BH); - } else { - lp->irq_mask &= ~(ICR_TXDM|ICR_RXDM);/* disable the interrupt source */ - } - - /* Unmask the EWRK3 board interrupts and turn off the LED */ - cr &= ~CR_LED; - outb(cr, EWRK3_CR); - - dev->interrupt = UNMASK_INTERRUPTS; - ENABLE_IRQs; - } - - return; -} - -static int -ewrk3_rx(struct device *dev) -{ - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_long iobase = dev->base_addr; - int i, status = 0; - u_char page, tmpPage = 0, tmpLock = 0; - u_long buf = 0; - - while (inb(EWRK3_RQC) && !status) { /* Whilst there's incoming data */ - if ((page = inb(EWRK3_RQ)) < lp->mPage) {/* Get next entry's buffer page */ - /* - ** Preempt any process using the current page register. Check for - ** an existing lock to reduce time taken in I/O transactions. - */ - if ((tmpLock = test_and_set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */ - if (lp->shmem_length == IO_ONLY) { /* Get existing page */ - tmpPage = inb(EWRK3_IOPR); - } else { - tmpPage = inb(EWRK3_MPR); + START_EWRK3; /* Enable the TX and/or RX */ +} + +/* + ** Writes a socket buffer to the free page queue + */ +static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev) +{ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + int status = 0; + u_char icr, csr; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy || lp->lock) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < QUEUE_PKT_TIMEOUT) { + status = -1; + } else if (!lp->hard_strapped) { + printk("%s: transmit timed/locked out, status %04x, resetting.\n", + dev->name, inb(EWRK3_CSR)); + + /* + ** Mask all board interrupts + */ + DISABLE_IRQs; + + /* + ** Stop the TX and RX... + */ + STOP_EWRK3; + + ewrk3_init(dev); + + /* + ** Unmask EWRK3 board interrupts + */ + ENABLE_IRQs; + + dev->tbusy = 0; + dev->trans_start = jiffies; + } + } else if (skb->len > 0) { + + /* + ** 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("%s: Transmitter access conflict.\n", dev->name); + + DISABLE_IRQs; /* So that the page # remains correct */ + + /* + ** Get a free page from the FMQ when resources are available + */ + if (inb(EWRK3_FMQC) > 0) { + u_long buf = 0; + u_char page; + + if ((page = inb(EWRK3_FMQ)) < lp->mPage) { + /* + ** Set up shared memory window and pointer into the window + */ + while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ + if (lp->shmem_length == IO_ONLY) { + outb(page, EWRK3_IOPR); + } else if (lp->shmem_length == SHMEM_2K) { + buf = lp->shmem_base; + outb(page, EWRK3_MPR); + } else if (lp->shmem_length == SHMEM_32K) { + buf = ((((short) page << 11) & 0x7800) + lp->shmem_base); + outb((page >> 4), EWRK3_MPR); + } else if (lp->shmem_length == SHMEM_64K) { + buf = ((((short) page << 11) & 0xf800) + lp->shmem_base); + outb((page >> 5), EWRK3_MPR); + } else { + status = -1; + printk("%s: Oops - your private data area is hosed!\n", dev->name); + } + + if (!status) { + + /* + ** Set up the buffer control structures and copy the data from + ** the socket buffer to the shared memory . + */ + + if (lp->shmem_length == IO_ONLY) { + int i; + u_char *p = skb->data; + + outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA); + outb((char) (skb->len & 0xff), EWRK3_DATA); + outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA); + outb((char) 0x04, EWRK3_DATA); + for (i = 0; i < skb->len; i++) { + outb(*p++, EWRK3_DATA); + } + outb(page, EWRK3_TQ); /* Start sending pkt */ + } else { + writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */ + buf += 1; + writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */ + buf += 1; + if (lp->txc) { + writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf); + buf += 1; + writeb(0x04, (char *) buf); /* index byte */ + buf += 1; + writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */ + memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */ + outb(page, EWRK3_TQ); /* Start sending pkt */ + memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD); + writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */ + } else { + writeb((char) ((skb->len >> 8) & 0xff), (char *) buf); + buf += 1; + writeb(0x04, (char *) buf); /* index byte */ + buf += 1; + memcpy_toio((char *) buf, skb->data, skb->len); /* Write data bytes */ + outb(page, EWRK3_TQ); /* Start sending pkt */ + } + } + + dev->trans_start = jiffies; + dev_kfree_skb(skb, FREE_WRITE); + + } else { /* return unused page to the free memory queue */ + outb(page, EWRK3_FMQ); + } + lp->lock = 0; /* unlock the page register */ + } else { + printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n", + (u_char) page); + } + } else { + printk("ewrk3_queue_pkt(): No free resources...\n"); + printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC)); + } + + /* Check for free resources: clear 'tbusy' if there are some */ + if (inb(EWRK3_FMQC) > 0) { + dev->tbusy = 0; + } + ENABLE_IRQs; } - } + return status; +} - /* - ** Set up shared memory window and pointer into the window - */ - if (lp->shmem_length == IO_ONLY) { - outb(page, EWRK3_IOPR); - } else if (lp->shmem_length == SHMEM_2K) { - buf = lp->shmem_base; - outb(page, EWRK3_MPR); - } else if (lp->shmem_length == SHMEM_32K) { - buf = ((((short)page << 11) & 0x7800) + lp->shmem_base); - outb((page >> 4), EWRK3_MPR); - } else if (lp->shmem_length == SHMEM_64K) { - buf = ((((short)page << 11) & 0xf800) + lp->shmem_base); - outb((page >> 5), EWRK3_MPR); - } else { - status = -1; - printk("%s: Oops - your private data area is hosed!\n",dev->name); - } - - if (!status) { - char rx_status; - int pkt_len; +/* + ** The EWRK3 interrupt handler. + */ +static void ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = dev_id; + struct ewrk3_private *lp; + u_long iobase; + u_char icr, cr, csr; - if (lp->shmem_length == IO_ONLY) { - rx_status = inb(EWRK3_DATA); - pkt_len = inb(EWRK3_DATA); - pkt_len |= ((u_short)inb(EWRK3_DATA) << 8); + if (dev == NULL) { + printk("ewrk3_interrupt(): irq %d for unknown device.\n", irq); } else { - rx_status = readb(buf); - buf+=1; - pkt_len = readw(buf); - buf+=3; + lp = (struct ewrk3_private *) dev->priv; + iobase = dev->base_addr; + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = MASK_INTERRUPTS; + + /* get the interrupt information */ + csr = inb(EWRK3_CSR); + + /* + ** Mask the EWRK3 board interrupts and turn on the LED + */ + DISABLE_IRQs; + + cr = inb(EWRK3_CR); + cr |= CR_LED; + outb(cr, EWRK3_CR); + + if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */ + ewrk3_rx(dev); + + if (csr & CSR_TNE) /* Tx interrupt (packet sent) */ + ewrk3_tx(dev); + + /* + ** Now deal with the TX/RX disable flags. These are set when there + ** are no more resources. If resources free up then enable these + ** interrupts, otherwise mask them - failure to do this will result + ** in the system hanging in an interrupt loop. + */ + if (inb(EWRK3_FMQC)) { /* any resources available? */ + lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */ + csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */ + outb(csr, EWRK3_CSR); + dev->tbusy = 0; /* clear TX busy flag */ + mark_bh(NET_BH); + } else { + lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */ + } + + /* Unmask the EWRK3 board interrupts and turn off the LED */ + cr &= ~CR_LED; + outb(cr, EWRK3_CR); + + dev->interrupt = UNMASK_INTERRUPTS; + ENABLE_IRQs; } - if (!(rx_status & R_ROK)) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ - if (rx_status & R_DBE) lp->stats.rx_frame_errors++; - if (rx_status & R_CRC) lp->stats.rx_crc_errors++; - if (rx_status & R_PLL) lp->stats.rx_fifo_errors++; - } else { - struct sk_buff *skb; + return; +} - if ((skb = dev_alloc_skb(pkt_len+2)) != NULL) { - unsigned char *p; - skb->dev = dev; - skb_reserve(skb,2); /* Align to 16 bytes */ - p = skb_put(skb,pkt_len); - - if (lp->shmem_length == IO_ONLY) { - *p = inb(EWRK3_DATA); /* dummy read */ - for (i=0; iprotocol=eth_type_trans(skb,dev); - netif_rx(skb); - - /* - ** Update stats - */ - lp->stats.rx_packets++; - for (i=1; ipktStats.bins[i]++; - i = EWRK3_PKT_STAT_SZ; - } - } - p = skb->data; /* Look at the dest addr */ - if (p[0] & 0x01) { /* Multicast/Broadcast */ - if ((*(s32 *)&p[0] == -1) && (*(s16 *)&p[4] == -1)) { - lp->pktStats.broadcast++; - } else { - lp->pktStats.multicast++; - } - } else if ((*(s32 *)&p[0] == *(s32 *)&dev->dev_addr[0]) && - (*(s16 *)&p[4] == *(s16 *)&dev->dev_addr[4])) { - lp->pktStats.unicast++; - } - - lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ - if (lp->pktStats.bins[0] == 0) { /* Reset counters */ - memset(&lp->pktStats, 0, sizeof(lp->pktStats)); - } - } else { - printk("%s: Insufficient memory; nuking packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ - break; - } - } - } - /* - ** Return the received buffer to the free memory queue - */ - outb(page, EWRK3_FMQ); - - if (tmpLock) { /* If a lock was preempted */ - if (lp->shmem_length == IO_ONLY) { /* Replace old page */ - outb(tmpPage, EWRK3_IOPR); - } else { - outb(tmpPage, EWRK3_MPR); +static int ewrk3_rx(struct device *dev) +{ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + int i, status = 0; + u_char page, tmpPage = 0, tmpLock = 0; + u_long buf = 0; + + while (inb(EWRK3_RQC) && !status) { /* Whilst there's incoming data */ + if ((page = inb(EWRK3_RQ)) < lp->mPage) { /* Get next entry's buffer page */ + /* + ** Preempt any process using the current page register. Check for + ** an existing lock to reduce time taken in I/O transactions. + */ + if ((tmpLock = test_and_set_bit(0, (void *) &lp->lock)) == 1) { /* Assert lock */ + if (lp->shmem_length == IO_ONLY) { /* Get existing page */ + tmpPage = inb(EWRK3_IOPR); + } else { + tmpPage = inb(EWRK3_MPR); + } + } + /* + ** Set up shared memory window and pointer into the window + */ + if (lp->shmem_length == IO_ONLY) { + outb(page, EWRK3_IOPR); + } else if (lp->shmem_length == SHMEM_2K) { + buf = lp->shmem_base; + outb(page, EWRK3_MPR); + } else if (lp->shmem_length == SHMEM_32K) { + buf = ((((short) page << 11) & 0x7800) + lp->shmem_base); + outb((page >> 4), EWRK3_MPR); + } else if (lp->shmem_length == SHMEM_64K) { + buf = ((((short) page << 11) & 0xf800) + lp->shmem_base); + outb((page >> 5), EWRK3_MPR); + } else { + status = -1; + printk("%s: Oops - your private data area is hosed!\n", dev->name); + } + + if (!status) { + char rx_status; + int pkt_len; + + if (lp->shmem_length == IO_ONLY) { + rx_status = inb(EWRK3_DATA); + pkt_len = inb(EWRK3_DATA); + pkt_len |= ((u_short) inb(EWRK3_DATA) << 8); + } else { + rx_status = readb(buf); + buf += 1; + pkt_len = readw(buf); + buf += 3; + } + + if (!(rx_status & R_ROK)) { /* There was an error. */ + lp->stats.rx_errors++; /* Update the error stats. */ + if (rx_status & R_DBE) + lp->stats.rx_frame_errors++; + if (rx_status & R_CRC) + lp->stats.rx_crc_errors++; + if (rx_status & R_PLL) + lp->stats.rx_fifo_errors++; + } else { + struct sk_buff *skb; + + if ((skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + unsigned char *p; + skb->dev = dev; + skb_reserve(skb, 2); /* Align to 16 bytes */ + p = skb_put(skb, pkt_len); + + if (lp->shmem_length == IO_ONLY) { + *p = inb(EWRK3_DATA); /* dummy read */ + for (i = 0; i < pkt_len; i++) { + *p++ = inb(EWRK3_DATA); + } + } else { + memcpy_fromio(p, buf, pkt_len); + } + + /* + ** Notify the upper protocol layers that there is another + ** packet to handle + */ + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + /* + ** Update stats + */ + lp->stats.rx_packets++; + for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { + if (pkt_len < i * EWRK3_PKT_BIN_SZ) { + lp->pktStats.bins[i]++; + i = EWRK3_PKT_STAT_SZ; + } + } + p = skb->data; /* Look at the dest addr */ + if (p[0] & 0x01) { /* Multicast/Broadcast */ + if ((*(s32 *) & p[0] == -1) && (*(s16 *) & p[4] == -1)) { + lp->pktStats.broadcast++; + } else { + lp->pktStats.multicast++; + } + } else if ((*(s32 *) & p[0] == *(s32 *) & dev->dev_addr[0]) && + (*(s16 *) & p[4] == *(s16 *) & dev->dev_addr[4])) { + lp->pktStats.unicast++; + } + lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ + if (lp->pktStats.bins[0] == 0) { /* Reset counters */ + memset(&lp->pktStats, 0, sizeof(lp->pktStats)); + } + } else { + printk("%s: Insufficient memory; nuking packet.\n", dev->name); + lp->stats.rx_dropped++; /* Really, deferred. */ + break; + } + } + } + /* + ** Return the received buffer to the free memory queue + */ + outb(page, EWRK3_FMQ); + + if (tmpLock) { /* If a lock was preempted */ + if (lp->shmem_length == IO_ONLY) { /* Replace old page */ + outb(tmpPage, EWRK3_IOPR); + } else { + outb(tmpPage, EWRK3_MPR); + } + } + lp->lock = 0; /* Unlock the page register */ + } else { + printk("ewrk3_rx(): Illegal page number, page %d\n", page); + printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC)); + } + } + return status; +} + +/* + ** Buffer sent - check for TX buffer errors. + */ +static int ewrk3_tx(struct device *dev) +{ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + u_char tx_status; + + while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */ + if (tx_status & T_VSTS) { /* The status is valid */ + if (tx_status & T_TXE) { + lp->stats.tx_errors++; + if (tx_status & T_NCL) + lp->stats.tx_carrier_errors++; + if (tx_status & T_LCL) + lp->stats.tx_window_errors++; + if (tx_status & T_CTU) { + if ((tx_status & T_COLL) ^ T_XUR) { + lp->pktStats.tx_underruns++; + } else { + lp->pktStats.excessive_underruns++; + } + } else if (tx_status & T_COLL) { + if ((tx_status & T_COLL) ^ T_XCOLL) { + lp->stats.collisions++; + } else { + lp->pktStats.excessive_collisions++; + } + } + } else { + lp->stats.tx_packets++; + } + } + } + + return 0; +} + +static int ewrk3_close(struct device *dev) +{ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + u_char icr, csr; + + dev->start = 0; + dev->tbusy = 1; + + if (ewrk3_debug > 1) { + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inb(EWRK3_CSR)); } - } - lp->lock = 0; /* Unlock the page register */ - } else { - printk("ewrk3_rx(): Illegal page number, page %d\n",page); - printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC)); - } - } - return status; -} - -/* -** Buffer sent - check for TX buffer errors. -*/ -static int -ewrk3_tx(struct device *dev) -{ - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_long iobase = dev->base_addr; - u_char tx_status; - - while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */ - if (tx_status & T_VSTS) { /* The status is valid */ - if (tx_status & T_TXE) { - lp->stats.tx_errors++; - if (tx_status & T_NCL) lp->stats.tx_carrier_errors++; - if (tx_status & T_LCL) lp->stats.tx_window_errors++; - if (tx_status & T_CTU) { - if ((tx_status & T_COLL) ^ T_XUR) { - lp->pktStats.tx_underruns++; - } else { - lp->pktStats.excessive_underruns++; - } - } else if (tx_status & T_COLL) { - if ((tx_status & T_COLL) ^ T_XCOLL) { - lp->stats.collisions++; - } else { - lp->pktStats.excessive_collisions++; - } - } - } else { - lp->stats.tx_packets++; - } - } - } - - return 0; -} - -static int -ewrk3_close(struct device *dev) -{ - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_long iobase = dev->base_addr; - u_char icr, csr; - - dev->start = 0; - dev->tbusy = 1; - - if (ewrk3_debug > 1) { - printk("%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inb(EWRK3_CSR)); - } - - /* - ** We stop the EWRK3 here... mask interrupts and stop TX & RX - */ - DISABLE_IRQs; - - STOP_EWRK3; - - /* - ** Clean out the TX and RX queues here (note that one entry - ** may get added to either the TXD or RX queues if the the TX or RX - ** just starts processing a packet before the STOP_EWRK3 command - ** is received. This will be flushed in the ewrk3_open() call). - */ - while (inb(EWRK3_TQ)); - while (inb(EWRK3_TDQ)); - while (inb(EWRK3_RQ)); - - if (!lp->hard_strapped) { - free_irq(dev->irq, dev); - } + /* + ** We stop the EWRK3 here... mask interrupts and stop TX & RX + */ + DISABLE_IRQs; + + STOP_EWRK3; - MOD_DEC_USE_COUNT; + /* + ** Clean out the TX and RX queues here (note that one entry + ** may get added to either the TXD or RX queues if the the TX or RX + ** just starts processing a packet before the STOP_EWRK3 command + ** is received. This will be flushed in the ewrk3_open() call). + */ + while (inb(EWRK3_TQ)); + while (inb(EWRK3_TDQ)); + while (inb(EWRK3_RQ)); - return 0; + if (!lp->hard_strapped) { + free_irq(dev->irq, dev); + } + MOD_DEC_USE_COUNT; + + return 0; } static struct net_device_stats *ewrk3_get_stats(struct device *dev) { - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; /* Null body since there is no framing error counter */ return &lp->stats; } /* -** Set or clear the multicast filter for this adapter. -*/ + ** Set or clear the multicast filter for this adapter. + */ static void set_multicast_list(struct device *dev) { - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - u_long iobase = dev->base_addr; - u_char csr; - - csr = inb(EWRK3_CSR); - - if (lp->shmem_length == IO_ONLY) { - lp->mctbl = (char *) PAGE0_HTE; - } else { - lp->mctbl = (char *)(lp->shmem_base + PAGE0_HTE); - } - - csr &= ~(CSR_PME | CSR_MCE); - if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ - csr |= CSR_PME; - outb(csr, EWRK3_CSR); - } else { - SetMulticastFilter(dev); - csr |= CSR_MCE; - outb(csr, EWRK3_CSR); - } + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + u_char csr; + + csr = inb(EWRK3_CSR); + + if (lp->shmem_length == IO_ONLY) { + lp->mctbl = (char *) PAGE0_HTE; + } else { + lp->mctbl = (char *) (lp->shmem_base + PAGE0_HTE); + } + + csr &= ~(CSR_PME | CSR_MCE); + if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ + csr |= CSR_PME; + outb(csr, EWRK3_CSR); + } else { + SetMulticastFilter(dev); + csr |= CSR_MCE; + outb(csr, EWRK3_CSR); + } } /* -** Calculate the hash code and update the logical address filter -** from a list of ethernet multicast addresses. -** Little endian crc one liner from Matt Thomas, DEC. -** -** Note that when clearing the table, the broadcast bit must remain asserted -** to receive broadcast messages. -*/ + ** Calculate the hash code and update the logical address filter + ** from a list of ethernet multicast addresses. + ** Little endian crc one liner from Matt Thomas, DEC. + ** + ** Note that when clearing the table, the broadcast bit must remain asserted + ** to receive broadcast messages. + */ static void SetMulticastFilter(struct device *dev) { - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - struct dev_mc_list *dmi=dev->mc_list; - u_long iobase = dev->base_addr; - int i; - char *addrs, j, bit, byte; - short *p = (short *) lp->mctbl; - u16 hashcode; - s32 crc, poly = CRC_POLYNOMIAL_LE; - - while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ - - if (lp->shmem_length == IO_ONLY) { - outb(0, EWRK3_IOPR); - outw(EEPROM_OFFSET(lp->mctbl), EWRK3_PIR1); - } else { - outb(0, EWRK3_MPR); - } - - if (dev->flags & IFF_ALLMULTI) { - for (i=0; i<(HASH_TABLE_LEN >> 3); i++) { - if (lp->shmem_length == IO_ONLY) { - outb(0xff, EWRK3_DATA); - } else { /* memset didn't work here */ - writew(0xffff, p); - p++; i++; - } - } - } else { - /* Clear table except for broadcast bit */ - if (lp->shmem_length == IO_ONLY) { - for (i=0; i<(HASH_TABLE_LEN >> 4) - 1; i++) { - outb(0x00, EWRK3_DATA); - } - outb(0x80, EWRK3_DATA); i++; /* insert the broadcast bit */ - for (; i<(HASH_TABLE_LEN >> 3); i++) { - outb(0x00, EWRK3_DATA); - } - } else { - memset_io(lp->mctbl, 0, (HASH_TABLE_LEN >> 3)); - writeb(0x80, (char *)(lp->mctbl + (HASH_TABLE_LEN >> 4) - 1)); - } - - /* Update table */ - for (i=0;imc_count;i++) { /* for each address in the list */ - addrs=dmi->dmi_addr; - dmi=dmi->next; - if ((*addrs & 0x01) == 1) { /* multicast address? */ - crc = 0xffffffff; /* init CRC for each address */ - for (byte=0;byte>=1) { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } - } - hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + struct dev_mc_list *dmi = dev->mc_list; + u_long iobase = dev->base_addr; + int i; + char *addrs, j, bit, byte; + short *p = (short *) lp->mctbl; + u16 hashcode; + s32 crc, poly = CRC_POLYNOMIAL_LE; - byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ - bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { - u_char tmp; + outb(0, EWRK3_IOPR); + outw(EEPROM_OFFSET(lp->mctbl), EWRK3_PIR1); + } else { + outb(0, EWRK3_MPR); + } - outw((short)((long)lp->mctbl) + byte, EWRK3_PIR1); - tmp = inb(EWRK3_DATA); - tmp |= bit; - outw((short)((long)lp->mctbl) + byte, EWRK3_PIR1); - outb(tmp, EWRK3_DATA); + if (dev->flags & IFF_ALLMULTI) { + for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { + if (lp->shmem_length == IO_ONLY) { + outb(0xff, EWRK3_DATA); + } else { /* memset didn't work here */ + writew(0xffff, p); + p++; + i++; + } + } } else { - writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte); + /* Clear table except for broadcast bit */ + if (lp->shmem_length == IO_ONLY) { + for (i = 0; i < (HASH_TABLE_LEN >> 4) - 1; i++) { + outb(0x00, EWRK3_DATA); + } + outb(0x80, EWRK3_DATA); + i++; /* insert the broadcast bit */ + for (; i < (HASH_TABLE_LEN >> 3); i++) { + outb(0x00, EWRK3_DATA); + } + } else { + memset_io(lp->mctbl, 0, (HASH_TABLE_LEN >> 3)); + writeb(0x80, (char *) (lp->mctbl + (HASH_TABLE_LEN >> 4) - 1)); + } + + /* Update table */ + for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */ + addrs = dmi->dmi_addr; + dmi = dmi->next; + if ((*addrs & 0x01) == 1) { /* multicast address? */ + crc = 0xffffffff; /* init CRC for each address */ + for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */ + /* process each address bit */ + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); + } + } + hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */ + + byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + + if (lp->shmem_length == IO_ONLY) { + u_char tmp; + + outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1); + tmp = inb(EWRK3_DATA); + tmp |= bit; + outw((short) ((long) lp->mctbl) + byte, EWRK3_PIR1); + outb(tmp, EWRK3_DATA); + } else { + writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte); + } + } + } } - } - } - } - lp->lock = 0; /* Unlock the page register */ + lp->lock = 0; /* Unlock the page register */ - return; + return; } /* -** ISA bus I/O device probe -*/ + ** ISA bus I/O device probe + */ __initfunc(static void isa_probe(struct device *dev, u_long ioaddr)) { - int i = num_ewrk3s, maxSlots; - u_long iobase; + int i = num_ewrk3s, maxSlots; + u_long iobase; - if (!ioaddr && autoprobed) return ; /* Been here before ! */ - if (ioaddr >= 0x400) return; /* Not ISA */ + if (!ioaddr && autoprobed) + return; /* Been here before ! */ + if (ioaddr >= 0x400) + return; /* Not ISA */ + + if (ioaddr == 0) { /* Autoprobing */ + iobase = EWRK3_IO_BASE; /* Get the first slot address */ + maxSlots = 24; + } else { /* Probe a specific location */ + iobase = ioaddr; + maxSlots = i + 1; + } + + for (; (i < maxSlots) && (dev != NULL); iobase += EWRK3_IOP_INC, i++) { + if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { + if (DevicePresent(iobase) == 0) { + if ((dev = alloc_device(dev, iobase)) != NULL) { + if (ewrk3_hw_init(dev, iobase) == 0) { + num_ewrk3s++; + } + num_eth++; + } + } + } else if (autoprobed) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + } + } - if (ioaddr == 0) { /* Autoprobing */ - iobase = EWRK3_IO_BASE; /* Get the first slot address */ - maxSlots = 24; - } else { /* Probe a specific location */ - iobase = ioaddr; - maxSlots = i + 1; - } - - for (; (iname, iobase); - } - } - - return; + return; } /* -** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually -** the motherboard. -*/ + ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually + ** the motherboard. + */ __initfunc(static void eisa_probe(struct device *dev, u_long ioaddr)) { - int i, maxSlots; - u_long iobase; - char name[EWRK3_STRLEN]; - - if (!ioaddr && autoprobed) return ; /* Been here before ! */ - if (ioaddr < 0x1000) return; /* Not EISA */ - - if (ioaddr == 0) { /* Autoprobing */ - iobase = EISA_SLOT_INC; /* Get the first slot address */ - i = 1; - maxSlots = MAX_EISA_SLOTS; - } else { /* Probe a specific location */ - iobase = ioaddr; - i = (ioaddr >> 12); - maxSlots = i + 1; - } - - for (i=1; (iname, iobase); - } - } - } - - return; + int i, maxSlots; + u_long iobase; + char name[EWRK3_STRLEN]; + + if (!ioaddr && autoprobed) + return; /* Been here before ! */ + if (ioaddr < 0x1000) + return; /* Not EISA */ + + if (ioaddr == 0) { /* Autoprobing */ + iobase = EISA_SLOT_INC; /* Get the first slot address */ + i = 1; + maxSlots = MAX_EISA_SLOTS; + } else { /* Probe a specific location */ + iobase = ioaddr; + i = (ioaddr >> 12); + maxSlots = i + 1; + } + + for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { + if (EISA_signature(name, EISA_ID) == 0) { + if (!check_region(iobase, EWRK3_TOTAL_SIZE)) { + if (DevicePresent(iobase) == 0) { + if ((dev = alloc_device(dev, iobase)) != NULL) { + if (ewrk3_hw_init(dev, iobase) == 0) { + num_ewrk3s++; + } + num_eth++; + } + } + } else if (autoprobed) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + } + } + } + + return; } /* -** Search the entire 'eth' device list for a fixed probe. If a match isn't -** found then check for an autoprobe or unused device location. If they -** are not available then insert a new device structure at the end of -** the current list. -*/ + ** Search the entire 'eth' device list for a fixed probe. If a match isn't + ** found then check for an autoprobe or unused device location. If they + ** are not available then insert a new device structure at the end of + ** the current list. + */ __initfunc(static struct device * -alloc_device(struct device *dev, u_long iobase)) + alloc_device(struct device *dev, u_long iobase)) { - struct device *adev = NULL; - int fixed = 0, new_dev = 0; - - num_eth = ewrk3_dev_index(dev->name); - if (loading_module) return dev; + struct device *adev = NULL; + int fixed = 0, new_dev = 0; - while (1) { - if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr==0)) && !adev) { - adev=dev; - } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) { - fixed = 1; - } else { - if (dev->next == NULL) { - new_dev = 1; - } else if (strncmp(dev->next->name, "eth", 3) != 0) { - new_dev = 1; - } - } - if ((dev->next == NULL) || new_dev || fixed) break; - dev = dev->next; - num_eth++; - } - if (adev && !fixed) { - dev = adev; num_eth = ewrk3_dev_index(dev->name); - new_dev = 0; - } - - if (((dev->next == NULL) && - ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || - new_dev) { - num_eth++; /* New device */ - dev = insert_device(dev, iobase, ewrk3_probe); - } + if (loading_module) + return dev; - return dev; + while (1) { + if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0)) && !adev) { + adev = dev; + } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "eth", 3) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) + break; + dev = dev->next; + num_eth++; + } + if (adev && !fixed) { + dev = adev; + num_eth = ewrk3_dev_index(dev->name); + new_dev = 0; + } + if (((dev->next == NULL) && + ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_eth++; /* New device */ + dev = insert_device(dev, iobase, ewrk3_probe); + } + return dev; } /* -** If at end of eth device list and can't use current entry, malloc -** one up. If memory could not be allocated, print an error message. -*/ + ** If at end of eth device list and can't use current entry, malloc + ** one up. If memory could not be allocated, print an error message. + */ __initfunc(static struct device * -insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))) + insert_device(struct device *dev, u_long iobase, int (*init) (struct device *))) { - struct device *new; + struct device *new; - new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); - if (new == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n",num_eth); - return NULL; - } else { - new->next = dev->next; - dev->next = new; - dev = dev->next; /* point to the new device */ - dev->name = (char *)(dev + 1); - if (num_eth > 9999) { - sprintf(dev->name,"eth????");/* New device name */ + new = (struct device *) kmalloc(sizeof(struct device) + 8, GFP_KERNEL); + if (new == NULL) { + printk("eth%d: Device not initialised, insufficient memory\n", num_eth); + return NULL; } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ + new->next = dev->next; + dev->next = new; + dev = dev->next; /* point to the new device */ + dev->name = (char *) (dev + 1); + if (num_eth > 9999) { + sprintf(dev->name, "eth????"); /* New device name */ + } else { + sprintf(dev->name, "eth%d", num_eth); /* New device name */ + } + dev->base_addr = iobase; /* assign the io address */ + dev->init = init; /* initialisation routine */ } - dev->base_addr = iobase; /* assign the io address */ - dev->init = init; /* initialisation routine */ - } - return dev; + return dev; } __initfunc(static int -ewrk3_dev_index(char *s)) + ewrk3_dev_index(char *s)) { - int i=0, j=0; + int i = 0, j = 0; - for (;*s; s++) { - if (isdigit(*s)) { - j=1; - i = (i * 10) + (*s - '0'); - } else if (j) break; - } + for (; *s; s++) { + if (isdigit(*s)) { + j = 1; + i = (i * 10) + (*s - '0'); + } else if (j) + break; + } - return i; + return i; } /* -** Read the EWRK3 EEPROM using this routine -*/ + ** Read the EWRK3 EEPROM using this routine + */ static int Read_EEPROM(u_long iobase, u_char eaddr) { - int i; + int i; - outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */ - outb(EEPROM_RD, EWRK3_IOPR); /* issue read command */ - for (i=0;i<5000;i++) inb(EWRK3_CSR); /* wait 1msec */ + outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */ + outb(EEPROM_RD, EWRK3_IOPR); /* issue read command */ + for (i = 0; i < 5000; i++) + inb(EWRK3_CSR); /* wait 1msec */ - return inw(EWRK3_EPROM1); /* 16 bits data return */ + return inw(EWRK3_EPROM1); /* 16 bits data return */ } /* -** Write the EWRK3 EEPROM using this routine -*/ + ** Write the EWRK3 EEPROM using this routine + */ static int Write_EEPROM(short data, u_long iobase, u_char eaddr) { - int i; + int i; - outb(EEPROM_WR_EN, EWRK3_IOPR); /* issue write enable command */ - for (i=0;i<5000;i++) inb(EWRK3_CSR); /* wait 1msec */ - outw(data, EWRK3_EPROM1); /* write data to register */ - outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */ - outb(EEPROM_WR, EWRK3_IOPR); /* issue write command */ - for (i=0;i<75000;i++) inb(EWRK3_CSR); /* wait 15msec */ - outb(EEPROM_WR_DIS, EWRK3_IOPR); /* issue write disable command */ - for (i=0;i<5000;i++) inb(EWRK3_CSR); /* wait 1msec */ + outb(EEPROM_WR_EN, EWRK3_IOPR); /* issue write enable command */ + for (i = 0; i < 5000; i++) + inb(EWRK3_CSR); /* wait 1msec */ + outw(data, EWRK3_EPROM1); /* write data to register */ + outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */ + outb(EEPROM_WR, EWRK3_IOPR); /* issue write command */ + for (i = 0; i < 75000; i++) + inb(EWRK3_CSR); /* wait 15msec */ + outb(EEPROM_WR_DIS, EWRK3_IOPR); /* issue write disable command */ + for (i = 0; i < 5000; i++) + inb(EWRK3_CSR); /* wait 1msec */ - return 0; + return 0; } /* -** Look for a particular board name in the on-board EEPROM. -*/ + ** Look for a particular board name in the on-board EEPROM. + */ __initfunc(static void EthwrkSignature(char *name, char *eeprom_image)) { - u_long i,j,k; - char *signatures[] = EWRK3_SIGNATURE; + u_long i, j, k; + char *signatures[] = EWRK3_SIGNATURE; - strcpy(name, ""); - for (i=0;*signatures[i] != '\0' && *name == '\0';i++) { - for (j=EEPROM_PNAME7,k=0;j<=EEPROM_PNAME0 && kbase_addr; - u16 tmp; - - if (chipType == LeMAC2) { - for (crc=0x6a, j=0; jdev_addr[j] = eeprom_image[EEPROM_PADDR0 + j]; - outb(dev->dev_addr[j], EWRK3_PAR0 + j); - for (k=0; k<8; k++, sd >>= 1) { - lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7; - crc = (crc >> 1) + lfsr; - } - } - if (crc != eeprom_image[EEPROM_PA_CRC]) status = -1; - } else { - for (i=0,k=0;i 0xffff) k-=0xffff; - - k += (u_char) (tmp = inb(EWRK3_APROM)); - dev->dev_addr[i] = (u_char) tmp; - outb(dev->dev_addr[i], EWRK3_PAR0 + i); - i++; - k += (u_short) ((tmp = inb(EWRK3_APROM)) << 8); - dev->dev_addr[i] = (u_char) tmp; - outb(dev->dev_addr[i], EWRK3_PAR0 + i); - i++; - - if (k > 0xffff) k-=0xffff; - } - if (k == 0xffff) k=0; - chksum = inb(EWRK3_APROM); - chksum |= (inb(EWRK3_APROM)<<8); - if (k != chksum) status = -1; - } + union { + struct { + u32 a; + u32 b; + } llsig; + char Sig[sizeof(u32) << 1]; + } + dev; + short sigLength; + char data; + int i, j, status = 0; + + dev.llsig.a = ETH_PROM_SIG; + dev.llsig.b = ETH_PROM_SIG; + sigLength = sizeof(u32) << 1; + + for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) { + data = inb(EWRK3_APROM); + if (dev.Sig[j] == data) { /* track signature */ + j++; + } else { /* lost signature; begin search again */ + if (data == dev.Sig[0]) { + j = 1; + } else { + j = 0; + } + } + } + + if (j != sigLength) { + status = -ENODEV; /* search failed */ + } + return status; +} + +__initfunc(static u_char get_hw_addr(struct device *dev, u_char * eeprom_image, char chipType)) +{ + int i, j, k; + u_short chksum; + u_char crc, lfsr, sd, status = 0; + u_long iobase = dev->base_addr; + u16 tmp; + + if (chipType == LeMAC2) { + for (crc = 0x6a, j = 0; j < ETH_ALEN; j++) { + sd = dev->dev_addr[j] = eeprom_image[EEPROM_PADDR0 + j]; + outb(dev->dev_addr[j], EWRK3_PAR0 + j); + for (k = 0; k < 8; k++, sd >>= 1) { + lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7; + crc = (crc >> 1) + lfsr; + } + } + if (crc != eeprom_image[EEPROM_PA_CRC]) + status = -1; + } else { + for (i = 0, k = 0; i < ETH_ALEN;) { + k <<= 1; + if (k > 0xffff) + k -= 0xffff; + + k += (u_char) (tmp = inb(EWRK3_APROM)); + dev->dev_addr[i] = (u_char) tmp; + outb(dev->dev_addr[i], EWRK3_PAR0 + i); + i++; + k += (u_short) ((tmp = inb(EWRK3_APROM)) << 8); + dev->dev_addr[i] = (u_char) tmp; + outb(dev->dev_addr[i], EWRK3_PAR0 + i); + i++; + + if (k > 0xffff) + k -= 0xffff; + } + if (k == 0xffff) + k = 0; + chksum = inb(EWRK3_APROM); + chksum |= (inb(EWRK3_APROM) << 8); + if (k != chksum) + status = -1; + } - return status; + return status; } /* -** Look for a particular board name in the EISA configuration space -*/ + ** Look for a particular board name in the EISA configuration space + */ __initfunc(static int EISA_signature(char *name, s32 eisa_id)) { - u_long i; - char *signatures[] = EWRK3_SIGNATURE; - char ManCode[EWRK3_STRLEN]; - union { - s32 ID; - char Id[4]; - } Eisa; - int status = 0; - - *name = '\0'; - for (i=0; i<4; i++) { - Eisa.Id[i] = inb(eisa_id + i); - } - - ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40); - ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40); - ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30); - ManCode[3]=((Eisa.Id[2]&0x0f)+0x30); - ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30); - ManCode[5]='\0'; - - for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) { - if (strstr(ManCode, signatures[i]) != NULL) { - strcpy(name,ManCode); - status = 1; - } - } - - return status; /* return the device name string */ + u_long i; + char *signatures[] = EWRK3_SIGNATURE; + char ManCode[EWRK3_STRLEN]; + union { + s32 ID; + char Id[4]; + } Eisa; + int status = 0; + + *name = '\0'; + for (i = 0; i < 4; i++) { + Eisa.Id[i] = inb(eisa_id + i); + } + + ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40); + ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40); + ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30); + ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30); + ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30); + ManCode[5] = '\0'; + + for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) { + if (strstr(ManCode, signatures[i]) != NULL) { + strcpy(name, ManCode); + status = 1; + } + } + + return status; /* return the device name string */ } /* -** Perform IOCTL call functions here. Some are privileged operations and the -** effective uid is checked in those cases. -*/ + ** Perform IOCTL call functions here. Some are privileged operations and the + ** effective uid is checked in those cases. + */ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) { - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data; - u_long iobase = dev->base_addr; - int i, j, status = 0; - u_char csr; - union { - u_char addr[HASH_TABLE_LEN * ETH_ALEN]; - u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1]; - } tmp; - - switch(ioc->cmd) { - case EWRK3_GET_HWADDR: /* Get the hardware address */ - for (i=0; idev_addr[i]; - } - ioc->len = ETH_ALEN; - if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - - break; - case EWRK3_SET_HWADDR: /* Set the hardware address */ - if (suser()) { - if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) { - csr = inb(EWRK3_CSR); - csr |= (CSR_TXD|CSR_RXD); - outb(csr, EWRK3_CSR); /* Disable the TX and RX */ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data; + u_long iobase = dev->base_addr; + int i, j, status = 0; + u_char csr; + union { + u_char addr[HASH_TABLE_LEN * ETH_ALEN]; + u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1]; + } tmp; + + switch (ioc->cmd) { + case EWRK3_GET_HWADDR: /* Get the hardware address */ + for (i = 0; i < ETH_ALEN; i++) { + tmp.addr[i] = dev->dev_addr[i]; + } + ioc->len = ETH_ALEN; + if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + break; + case EWRK3_SET_HWADDR: /* Set the hardware address */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) { + csr = inb(EWRK3_CSR); + csr |= (CSR_TXD | CSR_RXD); + outb(csr, EWRK3_CSR); /* Disable the TX and RX */ + + copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) { + dev->dev_addr[i] = tmp.addr[i]; + outb(tmp.addr[i], EWRK3_PAR0 + i); + } + + csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */ + outb(csr, EWRK3_CSR); + } + } else { + status = -EPERM; + } - copy_from_user(tmp.addr,ioc->data,ETH_ALEN); - for (i=0; idev_addr[i] = tmp.addr[i]; - outb(tmp.addr[i], EWRK3_PAR0 + i); - } - - csr &= ~(CSR_TXD|CSR_RXD); /* Enable the TX and RX */ - outb(csr, EWRK3_CSR); - } - } else { - status = -EPERM; - } - - break; - case EWRK3_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { - csr = inb(EWRK3_CSR); - csr |= CSR_PME; - csr &= ~CSR_MCE; - outb(csr, EWRK3_CSR); - } else { - status = -EPERM; - } - - break; - case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { - csr = inb(EWRK3_CSR); - csr &= ~CSR_PME; - outb(csr, EWRK3_CSR); - } else { - status = -EPERM; - } - - break; - case EWRK3_SAY_BOO: /* Say "Boo!" to the kernel log file */ - printk("%s: Boo!\n", dev->name); - - break; - case EWRK3_GET_MCA: /* Get the multicast address table */ - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ - if (lp->shmem_length == IO_ONLY) { - outb(0, EWRK3_IOPR); - outw(PAGE0_HTE, EWRK3_PIR1); - for (i=0; i<(HASH_TABLE_LEN >> 3); i++) { - tmp.addr[i] = inb(EWRK3_DATA); - } - } else { - outb(0, EWRK3_MPR); - memcpy_fromio(tmp.addr, (char *)(lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3)); - } - ioc->len = (HASH_TABLE_LEN >> 3); - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - lp->lock = 0; /* Unlock the page register */ - - break; - case EWRK3_SET_MCA: /* Set a multicast address */ - if (suser()) { - if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) { - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev); - } - } else { - status = -EPERM; - } - - break; - case EWRK3_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { - set_multicast_list(dev); - } else { - status = -EPERM; - } - - break; - case EWRK3_MCA_EN: /* Enable multicast addressing */ - if (suser()) { - csr = inb(EWRK3_CSR); - csr |= CSR_MCE; - csr &= ~CSR_PME; - outb(csr, EWRK3_CSR); - } else { - status = -EPERM; - } - - break; - case EWRK3_GET_STATS: /* Get the driver statistics */ - cli(); - ioc->len = sizeof(lp->pktStats); - if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } - sti(); - - break; - case EWRK3_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { - cli(); - memset(&lp->pktStats, 0, sizeof(lp->pktStats)); - sti(); - } else { - status = -EPERM; - } - - break; - case EWRK3_GET_CSR: /* Get the CSR Register contents */ - tmp.addr[0] = inb(EWRK3_CSR); - ioc->len = 1; - if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - - break; - case EWRK3_SET_CSR: /* Set the CSR Register contents */ - if (suser()) { - if (!(status=verify_area(VERIFY_READ, ioc->data, 1))) { - copy_from_user(tmp.addr, ioc->data, 1); - outb(tmp.addr[0], EWRK3_CSR); - } - } else { - status = -EPERM; - } - - break; - case EWRK3_GET_EEPROM: /* Get the EEPROM contents */ - if (suser()) { - for (i=0; i<(EEPROM_MAX>>1); i++) { - tmp.val[i] = (short)Read_EEPROM(iobase, i); - } - i = EEPROM_MAX; - tmp.addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */ - for (j=0;jlen = EEPROM_MAX + 1 + ETH_ALEN; - if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - } else { - status = -EPERM; - } - - break; - case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ - if (suser()) { - if (!(status=verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) { - copy_from_user(tmp.addr, ioc->data, EEPROM_MAX); - for (i=0; i<(EEPROM_MAX>>1); i++) { - Write_EEPROM(tmp.val[i], iobase, i); - } - } - } else { - status = -EPERM; - } - - break; - case EWRK3_GET_CMR: /* Get the CMR Register contents */ - tmp.addr[0] = inb(EWRK3_CMR); - ioc->len = 1; - if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } - - break; - case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */ - if (suser()) { - lp->txc = 1; - } else { - status = -EPERM; - } - - break; - case EWRK3_CLR_TX_CUT_THRU: /* Clear TX cut through mode */ - if (suser()) { - lp->txc = 0; - } else { - status = -EPERM; - } - - break; - default: - status = -EOPNOTSUPP; - } + break; + case EWRK3_SET_PROM: /* Set Promiscuous Mode */ + if (suser()) { + csr = inb(EWRK3_CSR); + csr |= CSR_PME; + csr &= ~CSR_MCE; + outb(csr, EWRK3_CSR); + } else { + status = -EPERM; + } + + break; + case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */ + if (suser()) { + csr = inb(EWRK3_CSR); + csr &= ~CSR_PME; + outb(csr, EWRK3_CSR); + } else { + status = -EPERM; + } + + break; + case EWRK3_SAY_BOO: /* Say "Boo!" to the kernel log file */ + printk("%s: Boo!\n", dev->name); + + break; + case EWRK3_GET_MCA: /* Get the multicast address table */ + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ + if (lp->shmem_length == IO_ONLY) { + outb(0, EWRK3_IOPR); + outw(PAGE0_HTE, EWRK3_PIR1); + for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { + tmp.addr[i] = inb(EWRK3_DATA); + } + } else { + outb(0, EWRK3_MPR); + memcpy_fromio(tmp.addr, (char *) (lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3)); + } + ioc->len = (HASH_TABLE_LEN >> 3); + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + lp->lock = 0; /* Unlock the page register */ + + break; + case EWRK3_SET_MCA: /* Set a multicast address */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) { + copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); + set_multicast_list(dev); + } + } else { + status = -EPERM; + } + + break; + case EWRK3_CLR_MCA: /* Clear all multicast addresses */ + if (suser()) { + set_multicast_list(dev); + } else { + status = -EPERM; + } + + break; + case EWRK3_MCA_EN: /* Enable multicast addressing */ + if (suser()) { + csr = inb(EWRK3_CSR); + csr |= CSR_MCE; + csr &= ~CSR_PME; + outb(csr, EWRK3_CSR); + } else { + status = -EPERM; + } + + break; + case EWRK3_GET_STATS: /* Get the driver statistics */ + cli(); + ioc->len = sizeof(lp->pktStats); + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, &lp->pktStats, ioc->len); + } + sti(); + + break; + case EWRK3_CLR_STATS: /* Zero out the driver statistics */ + if (suser()) { + cli(); + memset(&lp->pktStats, 0, sizeof(lp->pktStats)); + sti(); + } else { + status = -EPERM; + } + + break; + case EWRK3_GET_CSR: /* Get the CSR Register contents */ + tmp.addr[0] = inb(EWRK3_CSR); + ioc->len = 1; + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + break; + case EWRK3_SET_CSR: /* Set the CSR Register contents */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, ioc->data, 1))) { + copy_from_user(tmp.addr, ioc->data, 1); + outb(tmp.addr[0], EWRK3_CSR); + } + } else { + status = -EPERM; + } + + break; + case EWRK3_GET_EEPROM: /* Get the EEPROM contents */ + if (suser()) { + for (i = 0; i < (EEPROM_MAX >> 1); i++) { + tmp.val[i] = (short) Read_EEPROM(iobase, i); + } + i = EEPROM_MAX; + tmp.addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */ + for (j = 0; j < ETH_ALEN; j++) { + tmp.addr[i++] = inb(EWRK3_PAR0 + j); + } + ioc->len = EEPROM_MAX + 1 + ETH_ALEN; + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + } else { + status = -EPERM; + } + + break; + case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ + if (suser()) { + if (!(status = verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) { + copy_from_user(tmp.addr, ioc->data, EEPROM_MAX); + for (i = 0; i < (EEPROM_MAX >> 1); i++) { + Write_EEPROM(tmp.val[i], iobase, i); + } + } + } else { + status = -EPERM; + } - return status; + break; + case EWRK3_GET_CMR: /* Get the CMR Register contents */ + tmp.addr[0] = inb(EWRK3_CMR); + ioc->len = 1; + if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { + copy_to_user(ioc->data, tmp.addr, ioc->len); + } + break; + case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */ + if (suser()) { + lp->txc = 1; + } else { + status = -EPERM; + } + + break; + case EWRK3_CLR_TX_CUT_THRU: /* Clear TX cut through mode */ + if (suser()) { + lp->txc = 0; + } else { + status = -EPERM; + } + + break; + default: + status = -EOPNOTSUPP; + } + + return status; } #ifdef MODULE -static char devicename[9] = { 0, }; -static struct device thisEthwrk = { - devicename, /* device name is inserted by /linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0x300, 5, /* I/O address, IRQ */ - 0, 0, 0, NULL, ewrk3_probe }; +static char devicename[9] = +{0,}; +static struct device thisEthwrk = +{ + devicename, /* device name is inserted by /linux/drivers/net/net_init.c */ + 0, 0, 0, 0, + 0x300, 5, /* I/O address, IRQ */ + 0, 0, 0, NULL, ewrk3_probe}; -static int io=0x300; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=5; /* or use the insmod io= irq= options */ +static int io = 0x300; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ +static int irq = 5; /* or use the insmod io= irq= options */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); -int -init_module(void) +int init_module(void) { - thisEthwrk.base_addr=io; - thisEthwrk.irq=irq; - if (register_netdev(&thisEthwrk) != 0) - return -EIO; - return 0; + thisEthwrk.base_addr = io; + thisEthwrk.irq = irq; + if (register_netdev(&thisEthwrk) != 0) + return -EIO; + return 0; } -void -cleanup_module(void) +void cleanup_module(void) { - if (thisEthwrk.priv) { - kfree(thisEthwrk.priv); - thisEthwrk.priv = NULL; - } - thisEthwrk.irq = 0; + if (thisEthwrk.priv) { + kfree(thisEthwrk.priv); + thisEthwrk.priv = NULL; + } + thisEthwrk.irq = 0; - unregister_netdev(&thisEthwrk); - release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE); + unregister_netdev(&thisEthwrk); + release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE); } -#endif /* MODULE */ - +#endif /* MODULE */ + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" diff -u --recursive --new-file v2.1.66/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.66/linux/drivers/net/hdlcdrv.c Mon Aug 11 14:47:04 1997 +++ linux/drivers/net/hdlcdrv.c Sat Nov 29 10:33:19 1997 @@ -63,7 +63,6 @@ #include #include #include -#include /* --------------------------------------------------------------------- */ @@ -569,15 +568,6 @@ if (hdlcdrv_paranoia_check(dev, "hdlcdrv_send_packet")) return 0; sm = (struct hdlcdrv_state *)dev->priv; - /* - * If some higher layer thinks we've missed an tx-done interrupt - * we are passed NULL. Caution: dev_tint() handles the cli()/sti() - * itself. - */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } skb_queue_tail(&sm->send_queue, skb); dev->trans_start = jiffies; return 0; @@ -908,11 +898,6 @@ /* New style flags */ dev->flags = 0; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.1.66/linux/drivers/net/hp100.c Sat Oct 25 02:44:16 1997 +++ linux/drivers/net/hp100.c Sat Nov 29 10:33:19 1997 @@ -1,51 +1,51 @@ /* -** hp100.c -** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters -** -** $Id: hp100.c,v 1.52 1997/04/21 14:20:20 perex Exp perex $ -** -** Based on the HP100 driver written by Jaroslav Kysela -** Extended for new busmaster capable chipsets by -** Siegfried "Frieder" Loeffler (dg1sek) -** -** Maintained by: Jaroslav Kysela -** -** This driver has only been tested with -** -- HP J2585B 10/100 Mbit/s PCI Busmaster -** -- HP J2585A 10/100 Mbit/s PCI -** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC -** -- HP J2973 10 Mbit/s PCI 10base-T -** -- HP J2573 10/100 ISA -** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA -** -** but it should also work with the other CASCADE based adapters. -** -** TODO: -** - J2573 seems to hang sometimes when in shared memory mode. -** - Mode for Priority TX -** - Check PCI registers, performance might be improved? -** - To reduce interrupt load in busmaster, one could switch off -** the interrupts that are used to refill the queues whenever the -** queues are filled up to more than a certain threshold. -** -** -** This source/code is public free; you can distribute it and/or modify -** it under terms of the GNU General Public License (published by the -** Free Software Foundation) either version two of this License, or any -** later version. -** -*/ + ** hp100.c + ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters + ** + ** $Id: hp100.c,v 1.14 1997/11/16 13:57:28 alan Exp $ + ** + ** Based on the HP100 driver written by Jaroslav Kysela + ** Extended for new busmaster capable chipsets by + ** Siegfried "Frieder" Loeffler (dg1sek) + ** + ** Maintained by: Jaroslav Kysela + ** + ** This driver has only been tested with + ** -- HP J2585B 10/100 Mbit/s PCI Busmaster + ** -- HP J2585A 10/100 Mbit/s PCI + ** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC + ** -- HP J2973 10 Mbit/s PCI 10base-T + ** -- HP J2573 10/100 ISA + ** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA + ** + ** but it should also work with the other CASCADE based adapters. + ** + ** TODO: + ** - J2573 seems to hang sometimes when in shared memory mode. + ** - Mode for Priority TX + ** - Check PCI registers, performance might be improved? + ** - To reduce interrupt load in busmaster, one could switch off + ** the interrupts that are used to refill the queues whenever the + ** queues are filled up to more than a certain threshold. + ** + ** + ** This source/code is public free; you can distribute it and/or modify + ** it under terms of the GNU General Public License (published by the + ** Free Software Foundation) either version two of this License, or any + ** later version. + ** + */ -#define HP100_DEFAULT_PRIORITY_TX 0 +#define HP100_DEFAULT_PRIORITY_TX 0 #undef HP100_DEBUG -#undef HP100_DEBUG_B /* Trace */ -#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ +#undef HP100_DEBUG_B /* Trace */ +#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ -#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ -#undef HP100_DEBUG_TX -#undef HP100_DEBUG_IRQ -#undef HP100_DEBUG_RX +#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ +#undef HP100_DEBUG_TX +#undef HP100_DEBUG_IRQ +#undef HP100_DEBUG_RX #include #include @@ -67,7 +67,7 @@ #include #include -#include /* for CONFIG_PCI */ +#include /* for CONFIG_PCI */ #include #if LINUX_VERSION_CODE < 0x020100 @@ -99,7 +99,7 @@ #define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 #endif -#define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_REGION_SIZE 0x20 /* for ioports */ #define HP100_MAX_PACKET_SIZE (1536+4) #define HP100_MIN_PACKET_SIZE 60 @@ -119,84 +119,85 @@ */ struct hp100_eisa_id { - u_int id; - const char *name; - u_char bus; + u_int id; + const char *name; + u_char bus; }; struct hp100_private { - struct hp100_eisa_id *id; - u_short chip; - u_short soft_model; - u_int memory_size; - u_short rx_ratio; /* 1 - 99 */ - u_short priority_tx; /* != 0 - priority tx */ - u_short mode; /* PIO, Shared Mem or Busmaster */ - u_char bus; - u_char pci_bus; - u_char pci_device_fn; - short mem_mapped; /* memory mapped access */ - u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ - u_int *mem_ptr_phys; /* physical memory mapped area */ - short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ - int hub_status; /* was login to hub successful? */ - u_char mac1_mode; - u_char mac2_mode; - hp100_stats_t stats; - - /* Rings for busmaster mode: */ - hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ - hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ - hp100_ring_t *txrhead; /* Head (oldest) index into txring */ - hp100_ring_t *txrtail; /* Tail (newest) index into txring */ - - hp100_ring_t rxring[ MAX_RX_PDL ]; - hp100_ring_t txring[ MAX_TX_PDL ]; - - u_int *page_vaddr; /* Virtual address of allocated page */ - u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ - int rxrcommit; /* # Rx PDLs commited to adapter */ - int txrcommit; /* # Tx PDLs commited to adapter */ + struct hp100_eisa_id *id; + u_short chip; + u_short soft_model; + u_int memory_size; + u_short rx_ratio; /* 1 - 99 */ + u_short priority_tx; /* != 0 - priority tx */ + u_short mode; /* PIO, Shared Mem or Busmaster */ + u_char bus; + u_char pci_bus; + u_char pci_device_fn; + short mem_mapped; /* memory mapped access */ + u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + u_int *mem_ptr_phys; /* physical memory mapped area */ + short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ + int hub_status; /* was login to hub successful? */ + u_char mac1_mode; + u_char mac2_mode; + hp100_stats_t stats; + + /* Rings for busmaster mode: */ + hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ + hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ + hp100_ring_t *txrhead; /* Head (oldest) index into txring */ + hp100_ring_t *txrtail; /* Tail (newest) index into txring */ + + hp100_ring_t rxring[MAX_RX_PDL]; + hp100_ring_t txring[MAX_TX_PDL]; + + u_int *page_vaddr; /* Virtual address of allocated page */ + u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ + int rxrcommit; /* # Rx PDLs commited to adapter */ + int txrcommit; /* # Tx PDLs commited to adapter */ }; /* * variables */ -static struct hp100_eisa_id hp100_eisa_ids[] = { +static struct hp100_eisa_id hp100_eisa_ids[] = +{ /* 10/100 EISA card with revision A Cascade chip */ - { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA }, + {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, /* 10/100 ISA card with revision A Cascade chip */ - { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA }, + {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, /* 10 only EISA card with Cascade chip */ - { 0x2019F022, "HP 27248B", HP100_BUS_EISA }, + {0x2019F022, "HP 27248B", HP100_BUS_EISA}, /* 10/100 EISA card with Cascade chip */ - { 0x4019F022, "HP J2577", HP100_BUS_EISA }, + {0x4019F022, "HP J2577", HP100_BUS_EISA}, /* 10/100 ISA card with Cascade chip */ - { 0x5019F022, "HP J2573", HP100_BUS_ISA }, + {0x5019F022, "HP J2573", HP100_BUS_ISA}, /* 10/100 PCI card - old J2585A */ - { 0x1030103c, "HP J2585A", HP100_BUS_PCI }, + {0x1030103c, "HP J2585A", HP100_BUS_PCI}, /* 10/100 PCI card - new J2585B - master capable */ - { 0x1041103c, "HP J2585B", HP100_BUS_PCI }, + {0x1041103c, "HP J2585B", HP100_BUS_PCI}, /* 10 Mbit Combo Adapter */ - { 0x1042103c, "HP J2970", HP100_BUS_PCI }, + {0x1042103c, "HP J2970", HP100_BUS_PCI}, /* 10 Mbit 10baseT Adapter */ - { 0x1040103c, "HP J2973", HP100_BUS_PCI }, + {0x1040103c, "HP J2973", HP100_BUS_PCI}, /* 10/100 EISA card from Compex */ - { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA }, + {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, /* 10/100 PCI card from Compex (J2585A compatible) */ - { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI } + {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI} }; static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; @@ -204,49 +205,49 @@ static int hp100_mode = 1; #ifdef LINUX_2_1 -MODULE_PARM( hp100_rx_ratio, "1i" ); -MODULE_PARM( hp100_priority_tx, "1i" ); -MODULE_PARM( hp100_mode, "1i" ); +MODULE_PARM(hp100_rx_ratio, "1i"); +MODULE_PARM(hp100_priority_tx, "1i"); +MODULE_PARM(hp100_mode, "1i"); #endif /* * prototypes */ -static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); -static int hp100_open( struct device *dev ); -static int hp100_close( struct device *dev ); -static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); -static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev ); -static void hp100_rx( struct device *dev ); -static hp100_stats_t *hp100_get_stats( struct device *dev ); -static void hp100_update_stats( struct device *dev ); -static void hp100_clear_stats( int ioaddr ); -static void hp100_set_multicast_list( struct device *dev); -static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ); -static void hp100_start_interface( struct device *dev ); -static void hp100_stop_interface( struct device *dev ); -static void hp100_load_eeprom( struct device *dev ); -static int hp100_sense_lan( struct device *dev ); -static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ); -static int hp100_down_vg_link( struct device *dev ); -static void hp100_cascade_reset( struct device *dev, u_short enable ); -static void hp100_BM_shutdown( struct device *dev ); -static void hp100_mmuinit( struct device *dev ); -static void hp100_init_pdls( struct device *dev ); -static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u_int *pdlptr); -static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u_int *pdlptr); -static void hp100_rxfill( struct device *dev ); -static void hp100_hwinit( struct device *dev ); -static void hp100_clean_txring( struct device *dev ); +static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn); +static int hp100_open(struct device *dev); +static int hp100_close(struct device *dev); +static int hp100_start_xmit(struct sk_buff *skb, struct device *dev); +static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev); +static void hp100_rx(struct device *dev); +static hp100_stats_t *hp100_get_stats(struct device *dev); +static void hp100_update_stats(struct device *dev); +static void hp100_clear_stats(int ioaddr); +static void hp100_set_multicast_list(struct device *dev); +static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void hp100_start_interface(struct device *dev); +static void hp100_stop_interface(struct device *dev); +static void hp100_load_eeprom(struct device *dev); +static int hp100_sense_lan(struct device *dev); +static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin); +static int hp100_down_vg_link(struct device *dev); +static void hp100_cascade_reset(struct device *dev, u_short enable); +static void hp100_BM_shutdown(struct device *dev); +static void hp100_mmuinit(struct device *dev); +static void hp100_init_pdls(struct device *dev); +static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u_int * pdlptr); +static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u_int * pdlptr); +static void hp100_rxfill(struct device *dev); +static void hp100_hwinit(struct device *dev); +static void hp100_clean_txring(struct device *dev); #ifdef HP100_DEBUG -static void hp100_RegisterDump( struct device *dev ); +static void hp100_RegisterDump(struct device *dev); #endif /* TODO: This function should not really be needed in a good design... */ -static void wait( void ) +static void wait(void) { - udelay( 1000 ); + udelay(1000); } /* @@ -255,926 +256,862 @@ * since this could cause problems when the card is not installed. */ -__initfunc(int hp100_probe( struct device *dev )) +__initfunc(int hp100_probe(struct device *dev)) { - int base_addr = dev ? dev -> base_addr : 0; - int ioaddr = 0; + int base_addr = dev ? dev->base_addr : 0; + int ioaddr = 0; #ifdef CONFIG_PCI - int pci_start_index = 0; + int pci_start_index = 0; #endif #ifdef HP100_DEBUG_B - hp100_outw( 0x4200, TRACE ); - printk( "hp100: probe\n" ); + hp100_outw(0x4200, TRACE); + printk("hp100: probe\n"); #endif - if ( base_addr > 0xff ) /* Check a single specified location. */ - { - if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL; - if ( base_addr < 0x400 ) - return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 ); - else - return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 ); - } - else + if (base_addr > 0xff) { /* Check a single specified location. */ + if (check_region(base_addr, HP100_REGION_SIZE)) + return -EINVAL; + if (base_addr < 0x400) + return hp100_probe1(dev, base_addr, HP100_BUS_ISA, 0, 0); + else + return hp100_probe1(dev, base_addr, HP100_BUS_EISA, 0, 0); + } else #ifdef CONFIG_PCI - if ( base_addr > 0 && base_addr < 8 + 1 ) - pci_start_index = 0x100 | ( base_addr - 1 ); - else + if (base_addr > 0 && base_addr < 8 + 1) + pci_start_index = 0x100 | (base_addr - 1); + else #endif - if ( base_addr != 0 ) return -ENXIO; + if (base_addr != 0) + return -ENXIO; - /* at first - scan PCI bus(es) */ + /* at first - scan PCI bus(es) */ #ifdef CONFIG_PCI - if ( pcibios_present() ) - { - int pci_index; + if (pcibios_present()) { + int pci_index; #ifdef HP100_DEBUG_PCI - printk( "hp100: PCI BIOS is present, checking for devices..\n" ); -#endif - for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ ) - { - u_char pci_bus, pci_device_fn; - u_short pci_command; - - if ((pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, - pci_index, &pci_bus, - &pci_device_fn ) != 0 ) && - (pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, - pci_index, &pci_bus, - &pci_device_fn ) != 0 ) && - (pcibios_find_device( PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, - pci_index, &pci_bus, - &pci_device_fn ) != 0 ) ) break; - - pcibios_read_config_dword( pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &ioaddr ); - - ioaddr &= ~3; /* remove I/O space marker in bit 0. */ - - if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; - - pcibios_read_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command ); - if ( !( pci_command & PCI_COMMAND_MASTER ) ) - { -#ifdef HP100_DEBUG - printk( "hp100: PCI Master Bit has not been set. Setting...\n" ); -#endif - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, pci_command ); - } -#ifdef HP100_DEBUG - printk( "hp100: PCI adapter found at 0x%x\n", ioaddr ); -#endif - if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 ) - return 0; - } - } - if ( pci_start_index > 0 ) return -ENODEV; -#endif /* CONFIG_PCI */ - - /* Second: Probe all EISA possible port regions (if EISA bus present) */ - for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 ) - { - if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; - if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0; - } - - /* Third Probe all ISA possible port regions */ - for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 ) - { - if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; - if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0; - } - - return -ENODEV; -} - - -__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )) -{ - int i; - - u_char uc, uc_1; - u_int eisa_id; - u_int chip; - u_int memory_size = 0; - short mem_mapped; - u_int *mem_ptr_phys, *mem_ptr_virt; - struct hp100_private *lp; - struct hp100_eisa_id *eid; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4201, TRACE ); - printk("hp100: probe1\n"); -#endif - - if ( dev == NULL ) - { -#ifdef HP100_DEBUG - printk( "hp100_probe1: dev == NULL ?\n" ); -#endif - return EIO; - } - - if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE ) - { - return -ENODEV; - } - else - { - chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK; -#ifdef HP100_DEBUG - if ( chip == HP100_CHIPID_SHASTA ) - printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n"); - else if ( chip == HP100_CHIPID_RAINIER ) - printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n"); - else if ( chip == HP100_CHIPID_LASSEN ) - printk("hp100: Lassen Chip detected.\n"); - else - printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n",chip); -#endif - } - - dev->base_addr = ioaddr; - - hp100_page( ID_MAC_ADDR ); - for ( i = uc = eisa_id = 0; i < 4; i++ ) - { - eisa_id >>= 8; - uc_1 = hp100_inb( BOARD_ID + i ); - eisa_id |= uc_1 << 24; - uc += uc_1; - } - uc += hp100_inb( BOARD_ID + 4 ); - - if ( uc != 0xff ) /* bad checksum? */ - { - printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr ); - return -ENODEV; - } - - for ( i=0; i= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) ) - { - printk( "hp100_probe1: card at port 0x%x isn't known (id = 0x%x)\n", ioaddr, eisa_id ); - return -ENODEV; - } - eid = &hp100_eisa_ids[ i ]; - if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) ) - { - printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n", - eid->name, ioaddr ); - return -ENODEV; - } - - for ( i = uc = 0; i < 7; i++ ) - uc += hp100_inb( LAN_ADDR + i ); - if ( uc != 0xff ) - { - printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", - eid->name, ioaddr ); - return -EIO; - } - - /* Determine driver operation mode - * - * Use the variable "hp100_mode" upon insmod or as kernel parameter to - * force driver modes: - * hp100_mode=1 -> default, use busmaster mode if configured. - * hp100_mode=2 -> enable shared memory mode - * hp100_mode=3 -> force use of i/o mapped mode. - * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. - */ - - if(hp100_mode==3) - { - hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); - printk("hp100: IO mapped mode forced.\n"); - } - else if(hp100_mode==2) - { - hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); - printk("hp100: Shared memory mode requested.\n"); - } - else if(hp100_mode==4) - { - if(chip==HP100_CHIPID_LASSEN) - { - hp100_outw(HP100_BM_WRITE| - HP100_BM_READ | HP100_SET_HB, OPTION_LSW); - hp100_outw(HP100_IO_EN | - HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: Busmaster mode requested.\n"); - } - hp100_mode=1; - } - - if(hp100_mode==1) /* default behaviour */ - { - if( (hp100_inw(OPTION_LSW)&HP100_IO_EN) && - (~hp100_inw(OPTION_LSW)&HP100_MEM_EN) && - (~hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ)) - ) - { -#ifdef HP100_DEBUG - printk("hp100: IO_EN bit is set on card.\n"); -#endif - hp100_mode=3; - } - else if( ( chip==HP100_CHIPID_LASSEN ) && - ( (hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ) ) == - (HP100_BM_WRITE|HP100_BM_READ) ) ) - { - printk("hp100: Busmaster mode enabled.\n"); - hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); - } - else - { -#ifdef HP100_DEBUG - printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n"); -#endif - /* In this case, try shared memory mode */ - hp100_mode=2; - hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); - /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ - } - } - - /* Check for shared memory on the card, eventually remap it */ - hp100_page( HW_MAP ); - mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0); - mem_ptr_phys = mem_ptr_virt = NULL; - memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07)); - - /* For memory mapped or busmaster mode, we want the memory address */ - if ( mem_mapped || (hp100_mode==1)) - { - mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) | - ( hp100_inw( MEM_MAP_MSW ) << 16 ) ); - (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */ - - if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 ) - { - printk("hp100: Can only use programmed i/o mode.\n"); - mem_ptr_phys = NULL; - mem_mapped = 0; - hp100_mode=3; /* Use programmed i/o */ - } - - /* We do not need access to shared memory in busmaster mode */ - /* However in slave mode we need to remap high (>1GB) card memory */ - if(hp100_mode!=1) /* = not busmaster */ - { - if ( bus == HP100_BUS_PCI ) - { - /* We try with smaller memory sizes, if ioremap fails */ - for(; memory_size>16383; memory_size=memory_size/2) - { - if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,memory_size))==NULL) - { -#ifdef HP100_DEBUG - printk( "hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long)mem_ptr_phys ); + printk("hp100: PCI BIOS is present, checking for devices..\n"); #endif - } - else - { + for (pci_index = pci_start_index & 7; pci_index < 8; pci_index++) { + u_char pci_bus, pci_device_fn; + u_short pci_command; + + if ((pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, + pci_index, &pci_bus, + &pci_device_fn) != 0) && + (pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, + pci_index, &pci_bus, + &pci_device_fn) != 0) && + (pcibios_find_device(PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, + pci_index, &pci_bus, + &pci_device_fn) != 0)) + break; + + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &ioaddr); + + ioaddr &= ~3; /* remove I/O space marker in bit 0. */ + + if (check_region(ioaddr, HP100_REGION_SIZE)) + continue; + + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + if (!(pci_command & PCI_COMMAND_MASTER)) { +#ifdef HP100_DEBUG + printk("hp100: PCI Master Bit has not been set. Setting...\n"); +#endif + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, pci_command); + } #ifdef HP100_DEBUG - printk( "hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt); + printk("hp100: PCI adapter found at 0x%x\n", ioaddr); #endif - break; - } + if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn) == 0) + return 0; } - - if(mem_ptr_virt==NULL) /* all ioremap tries failed */ - { - printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); - hp100_mode=3; - memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07) ); - } - } - } - - } - - if(hp100_mode==3) /* io mapped forced */ - { - mem_mapped = 0; - mem_ptr_phys = mem_ptr_virt = NULL; - printk("hp100: Using (slow) programmed i/o mode.\n"); - } - - /* Initialise the "private" data structure for this card. */ - if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset( dev->priv, 0, sizeof(struct hp100_private) ); - - lp = (struct hp100_private *)dev->priv; - lp->id = eid; - lp->chip = chip; - lp->mode = hp100_mode; - lp->pci_bus = pci_bus; - lp->bus = bus; - lp->pci_device_fn = pci_device_fn; - lp->priority_tx = hp100_priority_tx; - lp->rx_ratio = hp100_rx_ratio; - lp->mem_ptr_phys = mem_ptr_phys; - lp->mem_ptr_virt = mem_ptr_virt; - hp100_page( ID_MAC_ADDR ); - lp->soft_model = hp100_inb( SOFT_MODEL ); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; - - dev->base_addr = ioaddr; - - lp->memory_size = memory_size; - lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - - /* memory region for programmed i/o */ - request_region( dev->base_addr, HP100_REGION_SIZE, eid->name ); - - dev->open = hp100_open; - dev->stop = hp100_close; - - if (lp->mode==1) /* busmaster */ - dev->hard_start_xmit = hp100_start_xmit_bm; - else - dev->hard_start_xmit = hp100_start_xmit; - - dev->get_stats = hp100_get_stats; - dev->set_multicast_list = &hp100_set_multicast_list; - - /* Ask the card for which IRQ line it is configured */ - hp100_page( HW_MAP ); - dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; - if ( dev->irq == 2 ) - dev->irq = 9; - - if(lp->mode==1) /* busmaster */ - dev->dma=4; - - /* Ask the card for its MAC address and store it for later use. */ - hp100_page( ID_MAC_ADDR ); - for ( i = uc = 0; i < 6; i++ ) - dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i ); - - /* Reset statistics (counters) */ - hp100_clear_stats( ioaddr ); - - ether_setup( dev ); - - /* If busmaster mode is wanted, a dma-capable memory area is needed for - * the rx and tx PDLs - * PCI cards can access the whole PC memory. Therefore GFP_DMA is not - * needed for the allocation of the memory area. - */ - - /* TODO: We do not need this with old cards, where PDLs are stored - * in the cards shared memory area. But currently, busmaster has been - * implemented/tested only with the lassen chip anyway... */ - if(lp->mode==1) /* busmaster */ - { - /* Get physically continous memory for TX & RX PDLs */ - if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL) - return -ENOMEM; - lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f)); - memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f); + } + if (pci_start_index > 0) + return -ENODEV; +#endif /* CONFIG_PCI */ + + /* Second: Probe all EISA possible port regions (if EISA bus present) */ + for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) { + if (check_region(ioaddr, HP100_REGION_SIZE)) + continue; + if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, 0, 0) == 0) + return 0; + } + + /* Third Probe all ISA possible port regions */ + for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { + if (check_region(ioaddr, HP100_REGION_SIZE)) + continue; + if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, 0, 0) == 0) + return 0; + } + + return -ENODEV; +} + + +__initfunc(static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn)) +{ + int i; + + u_char uc, uc_1; + u_int eisa_id; + u_int chip; + u_int memory_size = 0; + short mem_mapped; + u_int *mem_ptr_phys, *mem_ptr_virt; + struct hp100_private *lp; + struct hp100_eisa_id *eid; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4201, TRACE); + printk("hp100: probe1\n"); +#endif + + if (dev == NULL) { +#ifdef HP100_DEBUG + printk("hp100_probe1: dev == NULL ?\n"); +#endif + return EIO; + } + if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { + return -ENODEV; + } else { + chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; +#ifdef HP100_DEBUG + if (chip == HP100_CHIPID_SHASTA) + printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n"); + else if (chip == HP100_CHIPID_RAINIER) + printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n"); + else if (chip == HP100_CHIPID_LASSEN) + printk("hp100: Lassen Chip detected.\n"); + else + printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n", chip); +#endif + } + + dev->base_addr = ioaddr; + + hp100_page(ID_MAC_ADDR); + for (i = uc = eisa_id = 0; i < 4; i++) { + eisa_id >>= 8; + uc_1 = hp100_inb(BOARD_ID + i); + eisa_id |= uc_1 << 24; + uc += uc_1; + } + uc += hp100_inb(BOARD_ID + 4); + + if (uc != 0xff) { /* bad checksum? */ + printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr); + return -ENODEV; + } + for (i = 0; i < sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id); i++) + if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff)) + break; + if (i >= sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id)) { + printk("hp100_probe1: card at port 0x%x isn't known (id = 0x%x)\n", ioaddr, eisa_id); + return -ENODEV; + } + eid = &hp100_eisa_ids[i]; + if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) { + printk("hp100_probe1: newer version of card %s at port 0x%x - unsupported\n", + eid->name, ioaddr); + return -ENODEV; + } + for (i = uc = 0; i < 7; i++) + uc += hp100_inb(LAN_ADDR + i); + if (uc != 0xff) { + printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", + eid->name, ioaddr); + return -EIO; + } + /* Determine driver operation mode + + * Use the variable "hp100_mode" upon insmod or as kernel parameter to + * force driver modes: + * hp100_mode=1 -> default, use busmaster mode if configured. + * hp100_mode=2 -> enable shared memory mode + * hp100_mode=3 -> force use of i/o mapped mode. + * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. + */ + + if (hp100_mode == 3) { + hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); + printk("hp100: IO mapped mode forced.\n"); + } else if (hp100_mode == 2) { + hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); + printk("hp100: Shared memory mode requested.\n"); + } else if (hp100_mode == 4) { + if (chip == HP100_CHIPID_LASSEN) { + hp100_outw(HP100_BM_WRITE | + HP100_BM_READ | HP100_SET_HB, OPTION_LSW); + hp100_outw(HP100_IO_EN | + HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + printk("hp100: Busmaster mode requested.\n"); + } + hp100_mode = 1; + } + if (hp100_mode == 1) { /* default behaviour */ + if ((hp100_inw(OPTION_LSW) & HP100_IO_EN) && + (~hp100_inw(OPTION_LSW) & HP100_MEM_EN) && + (~hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) + ) { +#ifdef HP100_DEBUG + printk("hp100: IO_EN bit is set on card.\n"); +#endif + hp100_mode = 3; + } else if ((chip == HP100_CHIPID_LASSEN) && + ((hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) == + (HP100_BM_WRITE | HP100_BM_READ))) { + printk("hp100: Busmaster mode enabled.\n"); + hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + } else { +#ifdef HP100_DEBUG + printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n"); +#endif + /* In this case, try shared memory mode */ + hp100_mode = 2; + hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); + /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ + } + } + /* Check for shared memory on the card, eventually remap it */ + hp100_page(HW_MAP); + mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0); + mem_ptr_phys = mem_ptr_virt = NULL; + memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); + + /* For memory mapped or busmaster mode, we want the memory address */ + if (mem_mapped || (hp100_mode == 1)) { + mem_ptr_phys = (u_int *) (hp100_inw(MEM_MAP_LSW) | + (hp100_inw(MEM_MAP_MSW) << 16)); + (u_int) mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + + if (bus == HP100_BUS_ISA && ((u_long) mem_ptr_phys & ~0xfffff) != 0) { + printk("hp100: Can only use programmed i/o mode.\n"); + mem_ptr_phys = NULL; + mem_mapped = 0; + hp100_mode = 3; /* Use programmed i/o */ + } + /* We do not need access to shared memory in busmaster mode */ + /* However in slave mode we need to remap high (>1GB) card memory */ + if (hp100_mode != 1) { /* = not busmaster */ + if (bus == HP100_BUS_PCI) { + /* We try with smaller memory sizes, if ioremap fails */ + for (; memory_size > 16383; memory_size = memory_size / 2) { + if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, memory_size)) == NULL) { +#ifdef HP100_DEBUG + printk("hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long) mem_ptr_phys); +#endif + } else { +#ifdef HP100_DEBUG + printk("hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long) mem_ptr_phys, (u_long) mem_ptr_virt); +#endif + break; + } + } + + if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ + printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); + hp100_mode = 3; + memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); + } + } + } + } + if (hp100_mode == 3) { /* io mapped forced */ + mem_mapped = 0; + mem_ptr_phys = mem_ptr_virt = NULL; + printk("hp100: Using (slow) programmed i/o mode.\n"); + } + /* Initialise the "private" data structure for this card. */ + if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct hp100_private)); + + lp = (struct hp100_private *) dev->priv; + lp->id = eid; + lp->chip = chip; + lp->mode = hp100_mode; + lp->pci_bus = pci_bus; + lp->bus = bus; + lp->pci_device_fn = pci_device_fn; + lp->priority_tx = hp100_priority_tx; + lp->rx_ratio = hp100_rx_ratio; + lp->mem_ptr_phys = mem_ptr_phys; + lp->mem_ptr_virt = mem_ptr_virt; + hp100_page(ID_MAC_ADDR); + lp->soft_model = hp100_inb(SOFT_MODEL); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + + dev->base_addr = ioaddr; + + lp->memory_size = memory_size; + lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ + + /* memory region for programmed i/o */ + request_region(dev->base_addr, HP100_REGION_SIZE, eid->name); + + dev->open = hp100_open; + dev->stop = hp100_close; + + if (lp->mode == 1) /* busmaster */ + dev->hard_start_xmit = hp100_start_xmit_bm; + else + dev->hard_start_xmit = hp100_start_xmit; + + dev->get_stats = hp100_get_stats; + dev->set_multicast_list = &hp100_set_multicast_list; + + /* Ask the card for which IRQ line it is configured */ + hp100_page(HW_MAP); + dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK; + if (dev->irq == 2) + dev->irq = 9; + + if (lp->mode == 1) /* busmaster */ + dev->dma = 4; + + /* Ask the card for its MAC address and store it for later use. */ + hp100_page(ID_MAC_ADDR); + for (i = uc = 0; i < 6; i++) + dev->dev_addr[i] = hp100_inb(LAN_ADDR + i); + + /* Reset statistics (counters) */ + hp100_clear_stats(ioaddr); + + ether_setup(dev); + + /* If busmaster mode is wanted, a dma-capable memory area is needed for + * the rx and tx PDLs + * PCI cards can access the whole PC memory. Therefore GFP_DMA is not + * needed for the allocation of the memory area. + */ + + /* TODO: We do not need this with old cards, where PDLs are stored + * in the cards shared memory area. But currently, busmaster has been + * implemented/tested only with the lassen chip anyway... */ + if (lp->mode == 1) { /* busmaster */ + /* Get physically continous memory for TX & RX PDLs */ + if ((lp->page_vaddr = kmalloc(MAX_RINGSIZE + 0x0f, GFP_KERNEL)) == NULL) + return -ENOMEM; + lp->page_vaddr_algn = ((u_int *) (((u_int) (lp->page_vaddr) + 0x0f) & ~0x0f)); + memset(lp->page_vaddr, 0, MAX_RINGSIZE + 0x0f); #ifdef HP100_DEBUG_BM - printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n", - (u_int)lp->page_vaddr_algn, - (u_int)lp->page_vaddr_algn+MAX_RINGSIZE); -#endif - lp->rxrcommit = lp->txrcommit = 0; - lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - lp->txrhead = lp->txrtail = &(lp->txring[0]); - } - - /* Initialise the card. */ - /* (I'm not really sure if it's a good idea to do this during probing, but - * like this it's assured that the lan connection type can be sensed - * correctly) - */ - hp100_hwinit( dev ); - - /* Try to find out which kind of LAN the card is connected to. */ - lp->lan_type = hp100_sense_lan( dev ); - - /* Print out a message what about what we think we have probed. */ - printk( "hp100: %s: %s at 0x%x, IRQ %d, ", - dev->name, lp->id->name, ioaddr, dev->irq ); - switch ( bus ) { - case HP100_BUS_EISA: printk( "EISA" ); break; - case HP100_BUS_PCI: printk( "PCI" ); break; - default: printk( "ISA" ); break; - } - printk( " bus, %dk SRAM (rx/tx %d%%).\n", - lp->memory_size >> 10, lp->rx_ratio ); - - if ( lp->mode==2 ) /* memory mapped */ - { - printk( "%s: Memory area at 0x%lx-0x%lx", - dev->name,(u_long)mem_ptr_phys,(u_long)mem_ptr_phys+(u_long)lp->memory_size ); - if ( mem_ptr_virt ) - printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); - printk( ".\n" ); - - /* Set for info when doing ifconfig */ - dev->mem_start = (u_long)mem_ptr_phys; - dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size; - } - printk( "%s: ", dev->name ); - if ( lp->lan_type != HP100_LAN_ERR ) - printk( "Adapter is attached to " ); - switch ( lp->lan_type ) { - case HP100_LAN_100: - printk( "100Mb/s Voice Grade AnyLAN network.\n" ); - break; - case HP100_LAN_10: - printk( "10Mb/s network.\n" ); - break; - default: - printk( "Warning! Link down.\n" ); - } - return 0; -} + printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n", + (u_int) lp->page_vaddr_algn, + (u_int) lp->page_vaddr_algn + MAX_RINGSIZE); +#endif + lp->rxrcommit = lp->txrcommit = 0; + lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + lp->txrhead = lp->txrtail = &(lp->txring[0]); + } + /* Initialise the card. */ + /* (I'm not really sure if it's a good idea to do this during probing, but + * like this it's assured that the lan connection type can be sensed + * correctly) + */ + hp100_hwinit(dev); + + /* Try to find out which kind of LAN the card is connected to. */ + lp->lan_type = hp100_sense_lan(dev); + + /* Print out a message what about what we think we have probed. */ + printk("hp100: %s: %s at 0x%x, IRQ %d, ", + dev->name, lp->id->name, ioaddr, dev->irq); + switch (bus) { + case HP100_BUS_EISA: + printk("EISA"); + break; + case HP100_BUS_PCI: + printk("PCI"); + break; + default: + printk("ISA"); + break; + } + printk(" bus, %dk SRAM (rx/tx %d%%).\n", + lp->memory_size >> 10, lp->rx_ratio); + if (lp->mode == 2) { /* memory mapped */ + printk("%s: Memory area at 0x%lx-0x%lx", + dev->name, (u_long) mem_ptr_phys, (u_long) mem_ptr_phys + (u_long) lp->memory_size); + if (mem_ptr_virt) + printk(" (virtual base 0x%lx)", (u_long) mem_ptr_virt); + printk(".\n"); + + /* Set for info when doing ifconfig */ + dev->mem_start = (u_long) mem_ptr_phys; + dev->mem_end = (u_long) mem_ptr_phys + (u_long) lp->memory_size; + } + printk("%s: ", dev->name); + if (lp->lan_type != HP100_LAN_ERR) + printk("Adapter is attached to "); + switch (lp->lan_type) { + case HP100_LAN_100: + printk("100Mb/s Voice Grade AnyLAN network.\n"); + break; + case HP100_LAN_10: + printk("10Mb/s network.\n"); + break; + default: + printk("Warning! Link down.\n"); + } + return 0; +} + /* This procedure puts the card into a stable init state */ -static void hp100_hwinit( struct device *dev ) +static void hp100_hwinit(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; #ifdef HP100_DEBUG_B - hp100_outw( 0x4202, TRACE ); - printk("hp100: hwinit\n"); + hp100_outw(0x4202, TRACE); + printk("hp100: hwinit\n"); #endif - /* Initialise the card. -------------------------------------------- */ - - /* Clear all pending Ints and disable Ints */ - hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */ - - hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); - hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW ); - - if(lp->mode==1) - { - hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */ - wait(); - } - else - { - hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); - hp100_cascade_reset( dev, TRUE ); - hp100_page( MAC_CTRL ); - hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1); - } - - /* Initiate EEPROM reload */ - hp100_load_eeprom( dev ); - - wait(); - - /* Go into reset again. */ - hp100_cascade_reset( dev, TRUE ); - - /* Set Option Registers to a safe state */ - hp100_outw( HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | - HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB | - HP100_FAKE_INT | - HP100_INT_EN | - HP100_MEM_EN | - HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw( HP100_TRI_INT | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); - - hp100_outb( HP100_PRIORITY_TX | - HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); - - /* TODO: Configure MMU for Ram Test. */ - /* TODO: Ram Test. */ - - /* Re-check if adapter is still at same i/o location */ - /* (If the base i/o in eeprom has been changed but the */ - /* registers had not been changed, a reload of the eeprom */ - /* would move the adapter to the address stored in eeprom */ - - /* TODO: Code to implement. */ - - /* Until here it was code from HWdiscover procedure. */ - /* Next comes code from mmuinit procedure of SCO BM driver which is - * called from HWconfigure in the SCO driver. */ - - /* Initialise MMU, eventually switch on Busmaster Mode, initialise - * multicast filter... - */ - hp100_mmuinit( dev ); - - /* We don't turn the interrupts on here - this is done by start_interface. */ - wait(); /* TODO: Do we really need this? */ - - /* Enable Hardware (e.g. unreset) */ - hp100_cascade_reset( dev, FALSE ); - - /* ------- initialisation complete ----------- */ - - /* Finally try to log in the Hub if there may be a VG connection. */ - if( lp->lan_type != HP100_LAN_10 ) - hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ -} + /* Initialise the card. -------------------------------------------- */ + + /* Clear all pending Ints and disable Ints */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */ + + hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if (lp->mode == 1) { + hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */ + wait(); + } else { + hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + hp100_cascade_reset(dev, TRUE); + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); + } + + /* Initiate EEPROM reload */ + hp100_load_eeprom(dev); + + wait(); + + /* Go into reset again. */ + hp100_cascade_reset(dev, TRUE); + + /* Set Option Registers to a safe state */ + hp100_outw(HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | + HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB | + HP100_FAKE_INT | + HP100_INT_EN | + HP100_MEM_EN | + HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw(HP100_TRI_INT | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); + + hp100_outb(HP100_PRIORITY_TX | + HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); + + /* TODO: Configure MMU for Ram Test. */ + /* TODO: Ram Test. */ + /* Re-check if adapter is still at same i/o location */ + /* (If the base i/o in eeprom has been changed but the */ + /* registers had not been changed, a reload of the eeprom */ + /* would move the adapter to the address stored in eeprom */ + + /* TODO: Code to implement. */ + + /* Until here it was code from HWdiscover procedure. */ + /* Next comes code from mmuinit procedure of SCO BM driver which is + * called from HWconfigure in the SCO driver. */ + + /* Initialise MMU, eventually switch on Busmaster Mode, initialise + * multicast filter... + */ + hp100_mmuinit(dev); + + /* We don't turn the interrupts on here - this is done by start_interface. */ + wait(); /* TODO: Do we really need this? */ + + /* Enable Hardware (e.g. unreset) */ + hp100_cascade_reset(dev, FALSE); + + /* ------- initialisation complete ----------- */ + + /* Finally try to log in the Hub if there may be a VG connection. */ + if (lp->lan_type != HP100_LAN_10) + hp100_login_to_vg_hub(dev, FALSE); /* relogin */ +} + /* * mmuinit - Reinitialise Cascade MMU and MAC settings. * Note: Must already be in reset and leaves card in reset. */ -static void hp100_mmuinit( struct device *dev ) +static void hp100_mmuinit(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - int i; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4203, TRACE ); - printk("hp100: mmuinit\n"); -#endif - -#ifdef HP100_DEBUG - if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) ) - { - printk("hp100: Not in reset when entering mmuinit. Fix me.\n"); - return; - } -#endif - - /* Make sure IRQs are masked off and ack'ed. */ - hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ - - /* - * Enable Hardware - * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En - * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable - * - Clear Priority, Advance Pkt and Xmit Cmd - */ - - hp100_outw( HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | HP100_RESET_HB | - HP100_IO_EN | - HP100_FAKE_INT | - HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); - - hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if(lp->mode==1) /* busmaster */ - { - hp100_outw( HP100_BM_WRITE | - HP100_BM_READ | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); - } - else if(lp->mode==2) /* memory mapped */ - { - hp100_outw( HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB, OPTION_LSW ); - hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); - hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW ); - hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); - } - else if( lp->mode==3 ) /* i/o mapped mode */ - { - hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | - HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); - } - - hp100_page( HW_MAP ); - hp100_outb( 0, EARLYRXCFG ); - hp100_outw( 0, EARLYTXCFG ); - - /* - * Enable Bus Master mode - */ - if(lp->mode==1) /* busmaster */ - { - /* Experimental: Set some PCI configuration bits */ - hp100_page( HW_MAP ); - hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */ - hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */ - - /* PCI Bus failures should result in a Misc. Interrupt */ - hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2); - - hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW ); - hp100_page( HW_MAP ); - /* Use Burst Mode and switch on PAGE_CK */ - hp100_orb( HP100_BM_BURST_RD | - HP100_BM_BURST_WR, BM); - if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) - hp100_orb( HP100_BM_PAGE_CK, BM ); - hp100_orb( HP100_BM_MASTER, BM ); - } - else /* not busmaster */ - { - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM ); - } - - /* - * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs - */ - hp100_page( MMU_CFG ); - if(lp->mode==1) /* only needed for Busmaster */ - { - int xmit_stop, recv_stop; - - if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) - { - int pdl_stop; - - /* - * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and - * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded - * to the next higher 1k boundary) bytes for the rx-pdl's - * Note: For non-etr chips the transmit stop register must be - * programmed on a 1k boundary, i.e. bits 9:0 must be zero. - */ - pdl_stop = lp->memory_size; - xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff); - recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff); - hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP ); + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + int i; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4203, TRACE); + printk("hp100: mmuinit\n"); +#endif + +#ifdef HP100_DEBUG + if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { + printk("hp100: Not in reset when entering mmuinit. Fix me.\n"); + return; + } +#endif + + /* Make sure IRQs are masked off and ack'ed. */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ + + /* + * Enable Hardware + * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En + * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable + * - Clear Priority, Advance Pkt and Xmit Cmd + */ + + hp100_outw(HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | HP100_RESET_HB | + HP100_IO_EN | + HP100_FAKE_INT | + HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if (lp->mode == 1) { /* busmaster */ + hp100_outw(HP100_BM_WRITE | + HP100_BM_READ | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); + } else if (lp->mode == 2) { /* memory mapped */ + hp100_outw(HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); + hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); + hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + } else if (lp->mode == 3) { /* i/o mapped mode */ + hp100_outw(HP100_MMAP_DIS | HP100_SET_HB | + HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + } + hp100_page(HW_MAP); + hp100_outb(0, EARLYRXCFG); + hp100_outw(0, EARLYTXCFG); + + /* + * Enable Bus Master mode + */ + if (lp->mode == 1) { /* busmaster */ + /* Experimental: Set some PCI configuration bits */ + hp100_page(HW_MAP); + hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */ + hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */ + + /* PCI Bus failures should result in a Misc. Interrupt */ + hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2); + + hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW); + hp100_page(HW_MAP); + /* Use Burst Mode and switch on PAGE_CK */ + hp100_orb(HP100_BM_BURST_RD | + HP100_BM_BURST_WR, BM); + if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) + hp100_orb(HP100_BM_PAGE_CK, BM); + hp100_orb(HP100_BM_MASTER, BM); + } else { /* not busmaster */ + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM); + } + + /* + * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs + */ + hp100_page(MMU_CFG); + if (lp->mode == 1) { /* only needed for Busmaster */ + int xmit_stop, recv_stop; + + if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) { + int pdl_stop; + + /* + * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and + * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded + * to the next higher 1k boundary) bytes for the rx-pdl's + * Note: For non-etr chips the transmit stop register must be + * programmed on a 1k boundary, i.e. bits 9:0 must be zero. + */ + pdl_stop = lp->memory_size; + xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff); + recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff); + hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP); #ifdef HP100_DEBUG_BM - printk("hp100: PDL_STOP = 0x%x\n", pdl_stop); + printk("hp100: PDL_STOP = 0x%x\n", pdl_stop); #endif - } - else /* ETR chip (Lassen) in busmaster mode */ - { - xmit_stop = ( lp->memory_size ) - 1; - recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff); - } + } else { /* ETR chip (Lassen) in busmaster mode */ + xmit_stop = (lp->memory_size) - 1; + recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff); + } - hp100_outw( xmit_stop>>4 , TX_MEM_STOP ); - hp100_outw( recv_stop>>4 , RX_MEM_STOP ); + hp100_outw(xmit_stop >> 4, TX_MEM_STOP); + hp100_outw(recv_stop >> 4, RX_MEM_STOP); #ifdef HP100_DEBUG_BM - printk("hp100: TX_STOP = 0x%x\n",xmit_stop>>4); - printk("hp100: RX_STOP = 0x%x\n",recv_stop>>4); + printk("hp100: TX_STOP = 0x%x\n", xmit_stop >> 4); + printk("hp100: RX_STOP = 0x%x\n", recv_stop >> 4); #endif - } - else /* Slave modes (memory mapped and programmed io) */ - { - hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP ); - hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP ); -#ifdef HP100_DEBUG - printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP)); - printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP)); -#endif - } - - /* Write MAC address into page 1 */ - hp100_page( MAC_ADDRESS ); - for ( i = 0; i < 6; i++ ) - hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i ); - - /* Zero the multicast hash registers */ - for ( i = 0; i < 8; i++ ) - hp100_outb( 0x0, HASH_BYTE0 + i ); - - /* Set up MAC defaults */ - hp100_page( MAC_CTRL ); - - /* Go to LAN Page and zero all filter bits */ - /* Zero accept error, accept multicast, accept broadcast and accept */ - /* all directed packet bits */ - hp100_andb( ~(HP100_RX_EN| - HP100_TX_EN| - HP100_ACC_ERRORED| - HP100_ACC_MC| - HP100_ACC_BC| - HP100_ACC_PHY), MAC_CFG_1 ); - - hp100_outb( 0x00, MAC_CFG_2 ); - - /* Zero the frame format bit. This works around a training bug in the */ - /* new hubs. */ - hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */ - - if(lp->priority_tx) - hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW ); - else - hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW ); - - hp100_outb( HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); - - /* If busmaster, initialize the PDLs */ - if(lp->mode==1) - hp100_init_pdls( dev ); - - /* Go to performance page and initalize isr and imr registers */ - hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ -} + } else { /* Slave modes (memory mapped and programmed io) */ + hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP); + hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP); +#ifdef HP100_DEBUG + printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP)); + printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP)); +#endif + } + /* Write MAC address into page 1 */ + hp100_page(MAC_ADDRESS); + for (i = 0; i < 6; i++) + hp100_outb(dev->dev_addr[i], MAC_ADDR + i); + + /* Zero the multicast hash registers */ + for (i = 0; i < 8; i++) + hp100_outb(0x0, HASH_BYTE0 + i); + + /* Set up MAC defaults */ + hp100_page(MAC_CTRL); + + /* Go to LAN Page and zero all filter bits */ + /* Zero accept error, accept multicast, accept broadcast and accept */ + /* all directed packet bits */ + hp100_andb(~(HP100_RX_EN | + HP100_TX_EN | + HP100_ACC_ERRORED | + HP100_ACC_MC | + HP100_ACC_BC | + HP100_ACC_PHY), MAC_CFG_1); + + hp100_outb(0x00, MAC_CFG_2); + + /* Zero the frame format bit. This works around a training bug in the */ + /* new hubs. */ + hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */ + + if (lp->priority_tx) + hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW); + else + hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW); + + hp100_outb(HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); + + /* If busmaster, initialize the PDLs */ + if (lp->mode == 1) + hp100_init_pdls(dev); + + /* Go to performance page and initalize isr and imr registers */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ +} + /* * open/close functions */ -static int hp100_open( struct device *dev ) +static int hp100_open(struct device *dev) { - struct hp100_private *lp = (struct hp100_private *)dev->priv; -#ifdef HP100_DEBUG_B - int ioaddr=dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_B - hp100_outw( 0x4204, TRACE ); - printk("hp100: open\n"); + hp100_outw(0x4204, TRACE); + printk("hp100: open\n"); #endif - - /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ - if((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA)) - { - if(request_irq(dev->irq,hp100_interrupt,SA_SHIRQ,lp->id->name,dev)) - { - printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq ); - return -EAGAIN; + + /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ + if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) { + if (request_irq(dev->irq, hp100_interrupt, SA_SHIRQ, lp->id->name, dev)) { + printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); + return -EAGAIN; + } + } else if (request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, dev)) { + printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); + return -EAGAIN; } - } - else - if(request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, dev)) - { - printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq ); - return -EAGAIN; - } + MOD_INC_USE_COUNT; - MOD_INC_USE_COUNT; + dev->tbusy = 0; + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; - dev->tbusy = 0; - dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; + lp->lan_type = hp100_sense_lan(dev); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; - lp->lan_type = hp100_sense_lan( dev ); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; + hp100_stop_interface(dev); - hp100_stop_interface( dev ); - - hp100_hwinit( dev ); + hp100_hwinit(dev); - hp100_start_interface( dev ); /* sets mac modes, enables interrupts */ + hp100_start_interface(dev); /* sets mac modes, enables interrupts */ - return 0; + return 0; } - + /* The close function is called when the interface is to be brought down */ -static int hp100_close( struct device *dev ) +static int hp100_close(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; #ifdef HP100_DEBUG_B - hp100_outw( 0x4205, TRACE ); - printk("hp100:close\n"); + hp100_outw(0x4205, TRACE); + printk("hp100:close\n"); #endif - hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all IRQs */ - hp100_stop_interface( dev ); + hp100_stop_interface(dev); - if ( lp->lan_type == HP100_LAN_100 ) - lp->hub_status=hp100_login_to_vg_hub( dev, FALSE ); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - dev->tbusy = 1; - dev->start = 0; + dev->tbusy = 1; + dev->start = 0; - if ((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA)) - free_irq( dev->irq, dev ); - else - free_irq( dev->irq, NULL ); - MOD_DEC_USE_COUNT; - return 0; + if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) + free_irq(dev->irq, dev); + else + free_irq(dev->irq, NULL); + MOD_DEC_USE_COUNT; + return 0; } - + /* * Configure the PDL Rx rings and LAN */ -static void hp100_init_pdls( struct device *dev ) +static void hp100_init_pdls(struct device *dev) { - struct hp100_private *lp = (struct hp100_private *)dev->priv; - hp100_ring_t *ringptr; - u_int *pageptr; - int i; - -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + hp100_ring_t *ringptr; + u_int *pageptr; + int i; + +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_B - hp100_outw( 0x4206, TRACE ); - printk("hp100: init pdls\n"); -#endif - - if(0==lp->page_vaddr_algn) - printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n"); - else - { - /* pageptr shall point into the DMA accessible memory region */ - /* we use this pointer to status the upper limit of allocated */ - /* memory in the allocated page. */ - /* note: align the pointers to the pci cache line size */ - memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ - pageptr=lp->page_vaddr_algn; - - lp->rxrcommit =0; - ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]); - - /* Initialise Rx Ring */ - for (i=MAX_RX_PDL-1; i>=0; i--) - { - lp->rxring[i].next = ringptr; - ringptr=&(lp->rxring[i]); - pageptr+=hp100_init_rxpdl(ringptr, pageptr); - } - - /* Initialise Tx Ring */ - lp->txrcommit = 0; - ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); - for (i=MAX_TX_PDL-1; i>=0; i--) - { - lp->txring[i].next = ringptr; - ringptr=&(lp->txring[i]); - pageptr+=hp100_init_txpdl(ringptr, pageptr); - } - } -} + hp100_outw(0x4206, TRACE); + printk("hp100: init pdls\n"); +#endif + + if (0 == lp->page_vaddr_algn) + printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n"); + else { + /* pageptr shall point into the DMA accessible memory region */ + /* we use this pointer to status the upper limit of allocated */ + /* memory in the allocated page. */ + /* note: align the pointers to the pci cache line size */ + memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ + pageptr = lp->page_vaddr_algn; + lp->rxrcommit = 0; + ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + + /* Initialise Rx Ring */ + for (i = MAX_RX_PDL - 1; i >= 0; i--) { + lp->rxring[i].next = ringptr; + ringptr = &(lp->rxring[i]); + pageptr += hp100_init_rxpdl(ringptr, pageptr); + } + + /* Initialise Tx Ring */ + lp->txrcommit = 0; + ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); + for (i = MAX_TX_PDL - 1; i >= 0; i--) { + lp->txring[i].next = ringptr; + ringptr = &(lp->txring[i]); + pageptr += hp100_init_txpdl(ringptr, pageptr); + } + } +} + /* These functions "format" the entries in the pdl structure */ /* They return how much memory the fragments need. */ -static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u32 *pdlptr ) +static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u32 * pdlptr) { - /* pdlptr is starting adress for this pdl */ + /* pdlptr is starting adress for this pdl */ - if( 0!=( ((unsigned)pdlptr) & 0xf) ) - printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n",(unsigned)pdlptr); + if (0 != (((unsigned) pdlptr) & 0xf)) + printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr); - ringptr->pdl = pdlptr+1; - ringptr->pdl_paddr = virt_to_bus(pdlptr+1); - ringptr->skb = (void *) NULL; + ringptr->pdl = pdlptr + 1; + ringptr->pdl_paddr = virt_to_bus(pdlptr + 1); + ringptr->skb = (void *) NULL; - /* - * Write address and length of first PDL Fragment (which is used for - * storing the RX-Header - * We use the 4 bytes _before_ the PDH in the pdl memory area to - * store this information. (PDH is at offset 0x04) - */ - /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ + /* + * Write address and length of first PDL Fragment (which is used for + * storing the RX-Header + * We use the 4 bytes _before_ the PDH in the pdl memory area to + * store this information. (PDH is at offset 0x04) + */ + /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ - *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ - *(pdlptr+3) = 4; /* Length Frag 1 */ + *(pdlptr + 2) = (u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ + *(pdlptr + 3) = 4; /* Length Frag 1 */ - return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 ); + return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4); } -static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u32 *pdlptr ) +static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u32 * pdlptr) { - if( 0!=( ((unsigned)pdlptr) & 0xf) ) - printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n",(unsigned) pdlptr); + if (0 != (((unsigned) pdlptr) & 0xf)) + printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr); - ringptr->pdl = pdlptr; /* +1; */ - ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ - ringptr->skb = (void *) NULL; - - return((((MAX_TX_FRAG*2+2)+3)/4)*4); -} + ringptr->pdl = pdlptr; /* +1; */ + ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ + ringptr->skb = (void *) NULL; + return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4); +} + /* * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes * for possible odd word alignment rounding up to next dword and set PDL @@ -1182,78 +1119,77 @@ * Returns: 0 if unable to allocate skb_buff * 1 if successful */ -int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev ) +int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct device *dev) { #ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_BM - u_int *p; + u_int *p; #endif #ifdef HP100_DEBUG_B - hp100_outw( 0x4207, TRACE ); - printk("hp100: build rx pdl\n"); + hp100_outw(0x4207, TRACE); + printk("hp100: build rx pdl\n"); #endif - /* Allocate skb buffer of maximum size */ - /* Note: This depends on the alloc_skb functions allocating more - * space than requested, i.e. aligning to 16bytes */ - - ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 ); - - if(NULL!=ringptr->skb) - { - /* - * Reserve 2 bytes at the head of the buffer to land the IP header - * on a long word boundary (According to the Network Driver section - * in the Linux KHG, this should help to increase performance.) - */ - skb_reserve(ringptr->skb, 2); - - ringptr->skb->dev=dev; - ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE ); - - /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ - /* Note: 1st Fragment is used for the 4 byte packet status - * (receive header). Its PDL entries are set up by init_rxpdl. So - * here we only have to set up the PDL fragment entries for the data - * part. Those 4 bytes will be stored in the DMA memory region - * directly before the PDL. - */ + /* Allocate skb buffer of maximum size */ + /* Note: This depends on the alloc_skb functions allocating more + * space than requested, i.e. aligning to 16bytes */ + + ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4); + + if (NULL != ringptr->skb) { + /* + * Reserve 2 bytes at the head of the buffer to land the IP header + * on a long word boundary (According to the Network Driver section + * in the Linux KHG, this should help to increase performance.) + */ + skb_reserve(ringptr->skb, 2); + + ringptr->skb->dev = dev; + ringptr->skb->data = (u_char *) skb_put(ringptr->skb, MAX_ETHER_SIZE); + + /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ + /* Note: 1st Fragment is used for the 4 byte packet status + * (receive header). Its PDL entries are set up by init_rxpdl. So + * here we only have to set up the PDL fragment entries for the data + * part. Those 4 bytes will be stored in the DMA memory region + * directly before the PDL. + */ #ifdef HP100_DEBUG_BM - printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", - (u_int) ringptr->pdl, - ((MAX_ETHER_SIZE+2+3)/4)*4, - (unsigned int) ringptr->skb->data); + printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", + (u_int) ringptr->pdl, + ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4, + (unsigned int) ringptr->skb->data); #endif - ringptr->pdl[0] = 0x00020000; /* Write PDH */ - ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data)); - ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ - + ringptr->pdl[0] = 0x00020000; /* Write PDH */ + ringptr->pdl[3] = ((u_int) virt_to_bus(ringptr->skb->data)); + ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ + #ifdef HP100_DEBUG_BM - for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++) - printk("Adr 0x%.8x = 0x%.8x\n",(u_int) p,(u_int) *p ); + for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++) + printk("Adr 0x%.8x = 0x%.8x\n", (u_int) p, (u_int) * p); #endif - return(1); - } - /* else: */ - /* alloc_skb failed (no memory) -> still can receive the header - * fragment into PDL memory. make PDL safe by clearing msgptr and - * making the PDL only 1 fragment (i.e. the 4 byte packet status) - */ + return (1); + } + /* else: */ + /* alloc_skb failed (no memory) -> still can receive the header + * fragment into PDL memory. make PDL safe by clearing msgptr and + * making the PDL only 1 fragment (i.e. the 4 byte packet status) + */ #ifdef HP100_DEBUG_BM - printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n", - (u_int) ringptr->pdl); + printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n", + (u_int) ringptr->pdl); #endif - ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */ + ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */ - return(0); + return (0); } - + /* * hp100_rxfill - attempt to fill the Rx Ring will empty skb's * @@ -1264,273 +1200,246 @@ * b. Put the physical address of the buffer into the PDL. * c. Output physical address of PDL to adapter. */ -static void hp100_rxfill( struct device *dev ) +static void hp100_rxfill(struct device *dev) { - int ioaddr=dev->base_addr; + int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - hp100_ring_t *ringptr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + hp100_ring_t *ringptr; #ifdef HP100_DEBUG_B - hp100_outw( 0x4208, TRACE ); - printk("hp100: rxfill\n"); -#endif - - hp100_page( PERFORMANCE ); - - while (lp->rxrcommit < MAX_RX_PDL) - { - /* - ** Attempt to get a buffer and build a Rx PDL. - */ - ringptr = lp->rxrtail; - if (0 == hp100_build_rx_pdl( ringptr, dev )) - { - return; /* None available, return */ - } - - /* Hand this PDL over to the card */ - /* Note: This needs performance page selected! */ + hp100_outw(0x4208, TRACE); + printk("hp100: rxfill\n"); +#endif + + hp100_page(PERFORMANCE); + + while (lp->rxrcommit < MAX_RX_PDL) { + /* + ** Attempt to get a buffer and build a Rx PDL. + */ + ringptr = lp->rxrtail; + if (0 == hp100_build_rx_pdl(ringptr, dev)) { + return; /* None available, return */ + } + /* Hand this PDL over to the card */ + /* Note: This needs performance page selected! */ #ifdef HP100_DEBUG_BM - printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", - lp->rxrcommit, - (u_int)ringptr->pdl, - (u_int)ringptr->pdl_paddr, - (u_int)ringptr->pdl[3]); + printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", + lp->rxrcommit, + (u_int) ringptr->pdl, + (u_int) ringptr->pdl_paddr, + (u_int) ringptr->pdl[3]); #endif - hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA); - - lp->rxrcommit += 1; - lp->rxrtail = ringptr->next; - } -} + hp100_outl((u32) ringptr->pdl_paddr, RX_PDA); + lp->rxrcommit += 1; + lp->rxrtail = ringptr->next; + } +} + /* * BM_shutdown - shutdown bus mastering and leave chip in reset state */ -static void hp100_BM_shutdown( struct device *dev ) +static void hp100_BM_shutdown(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - unsigned long time; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4209, TRACE ); - printk("hp100: bm shutdown\n"); -#endif - - hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */ - - /* Ensure Interrupts are off */ - hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW ); - - /* Disable all MAC activity */ - hp100_page( MAC_CTRL ); - hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ - - /* If cascade MMU is not already in reset */ - if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) ) - { - /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so - * MMU pointers will not be reset out from underneath - */ - hp100_page( MAC_CTRL ); - for(time=0; time<5000; time++) - { - if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))== - (HP100_TX_IDLE|HP100_RX_IDLE) ) break; - } - - /* Shutdown algorithm depends on the generation of Cascade */ - if( lp->chip==HP100_CHIPID_LASSEN ) - { /* ETR shutdown/reset */ - /* Disable Busmaster mode and wait for bit to go to zero. */ - hp100_page(HW_MAP); - hp100_andb( ~HP100_BM_MASTER, BM ); - /* 100 ms timeout */ - for(time=0; time<32000; time++) - { - if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break; - } - } - else - { /* Shasta or Rainier Shutdown/Reset */ - /* To ensure all bus master inloading activity has ceased, - * wait for no Rx PDAs or no Rx packets on card. - */ - hp100_page( PERFORMANCE ); - /* 100 ms timeout */ - for(time=0; time<10000; time++) - { - /* RX_PDL: PDLs not executed. */ - /* RX_PKT_CNT: RX'd packets on card. */ - if ( (hp100_inb( RX_PDL ) == 0) && - (hp100_inb( RX_PKT_CNT ) == 0) ) break; - } - - if(time>=10000) - printk("hp100: BM shutdown error.\n"); - - /* To ensure all bus master outloading activity has ceased, - * wait until the Tx PDA count goes to zero or no more Tx space - * available in the Tx region of the card. - */ - /* 100 ms timeout */ - for(time=0; time<10000; time++) { - if ( (0 == hp100_inb( TX_PKT_CNT )) && - (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break; - } - - /* Disable Busmaster mode */ - hp100_page(HW_MAP); - hp100_andb( ~HP100_BM_MASTER, BM ); - } /* end of shutdown procedure for non-etr parts */ - - hp100_cascade_reset( dev, TRUE ); - } - hp100_page( PERFORMANCE ); - hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); - /* Busmaster mode should be shut down now. */ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + unsigned long time; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4209, TRACE); + printk("hp100: bm shutdown\n"); +#endif + + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */ + + /* Ensure Interrupts are off */ + hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + + /* Disable all MAC activity */ + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ + + /* If cascade MMU is not already in reset */ + if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { + /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so + * MMU pointers will not be reset out from underneath + */ + hp100_page(MAC_CTRL); + for (time = 0; time < 5000; time++) { + if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == + (HP100_TX_IDLE | HP100_RX_IDLE)) + break; + } + + /* Shutdown algorithm depends on the generation of Cascade */ + if (lp->chip == HP100_CHIPID_LASSEN) { /* ETR shutdown/reset */ + /* Disable Busmaster mode and wait for bit to go to zero. */ + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM); + /* 100 ms timeout */ + for (time = 0; time < 32000; time++) { + if (0 == (hp100_inb(BM) & HP100_BM_MASTER)) + break; + } + } else { /* Shasta or Rainier Shutdown/Reset */ + /* To ensure all bus master inloading activity has ceased, + * wait for no Rx PDAs or no Rx packets on card. + */ + hp100_page(PERFORMANCE); + /* 100 ms timeout */ + for (time = 0; time < 10000; time++) { + /* RX_PDL: PDLs not executed. */ + /* RX_PKT_CNT: RX'd packets on card. */ + if ((hp100_inb(RX_PDL) == 0) && + (hp100_inb(RX_PKT_CNT) == 0)) + break; + } + + if (time >= 10000) + printk("hp100: BM shutdown error.\n"); + + /* To ensure all bus master outloading activity has ceased, + * wait until the Tx PDA count goes to zero or no more Tx space + * available in the Tx region of the card. + */ + /* 100 ms timeout */ + for (time = 0; time < 10000; time++) { + if ((0 == hp100_inb(TX_PKT_CNT)) && + (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE))) + break; + } + + /* Disable Busmaster mode */ + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM); + } /* end of shutdown procedure for non-etr parts */ + + hp100_cascade_reset(dev, TRUE); + } + hp100_page(PERFORMANCE); + hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW); + /* Busmaster mode should be shut down now. */ } + - /* * transmit functions */ /* tx function for busmaster mode */ -static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev ) +static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev) { - int i, ok_flag; - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - hp100_ring_t *ringptr; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4210, TRACE ); - printk("hp100: start_xmit_bm\n"); -#endif - - if ( skb==NULL ) - { - dev_tint( dev ); - return 0; - } - - if ( skb->len <= 0 ) return 0; - - /* Get Tx ring tail pointer */ - if( lp->txrtail->next==lp->txrhead ) - { - /* No memory. */ -#ifdef HP100_DEBUG - printk("hp100: start_xmit_bm: No TX PDL available.\n"); -#endif - /* not waited long enough since last tx? */ - if ( jiffies - dev->trans_start < HZ/10 ) return -EAGAIN; - - if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ - { - hp100_stop_interface( dev ); - if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) - { - printk( "%s: no connection found - check wire\n", dev->name ); - hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */ - return -EIO; - } - if ( lp->lan_type == HP100_LAN_100 ) - lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ - hp100_start_interface( dev ); - } - - if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) - /* we have a 100Mb/s adapter but it isn't connected to hub */ - { - printk( "%s: login to 100Mb/s hub retry\n", dev->name ); - hp100_stop_interface( dev ); - lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); - hp100_start_interface( dev ); - } - else - { - hp100_ints_off(); - i = hp100_sense_lan( dev ); - hp100_page( PERFORMANCE ); - hp100_ints_on(); - if ( i == HP100_LAN_ERR ) - printk( "%s: link down detected\n", dev->name ); - else - if ( lp->lan_type != i ) /* cable change! */ - { - /* it's very hard - all network setting must be changed!!! */ - printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); - lp->lan_type = i; - hp100_stop_interface( dev ); - if ( lp->lan_type == HP100_LAN_100 ) - lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); - hp100_start_interface( dev ); - } - else - { - printk( "%s: interface reset\n", dev->name ); - hp100_stop_interface( dev ); - hp100_start_interface( dev ); - } - } - - dev->trans_start = jiffies; - return -EAGAIN; - } - - /* - * we have to turn int's off before modifying this, otherwise - * a tx_pdl_cleanup could occur at the same time - */ - cli(); - ringptr=lp->txrtail; - lp->txrtail=ringptr->next; - - /* Check whether packet has minimal packet size */ - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - ringptr->skb=skb; - ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */ - ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ - if(lp->chip==HP100_CHIPID_SHASTA) - { - /* TODO:Could someone who has the EISA card please check if this works? */ - ringptr->pdl[2]=i; - } - else /* Lassen */ - { - /* In the PDL, don't use the padded size but the real packet size: */ - ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */ - } - - /* Hand this PDL to the card. */ - hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */ - - lp->txrcommit++; - sti(); - - /* Update statistics */ - lp->stats.tx_packets++; + int i, ok_flag; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + hp100_ring_t *ringptr; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4210, TRACE); + printk("hp100: start_xmit_bm\n"); +#endif + + /* Get Tx ring tail pointer */ + if (lp->txrtail->next == lp->txrhead) { + /* No memory. */ +#ifdef HP100_DEBUG + printk("hp100: start_xmit_bm: No TX PDL available.\n"); +#endif + /* not waited long enough since last tx? */ + if (jiffies - dev->trans_start < HZ / 10) + return -EAGAIN; + + if (lp->lan_type < 0) { /* no LAN type detected yet? */ + hp100_stop_interface(dev); + if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { + printk("%s: no connection found - check wire\n", dev->name); + hp100_start_interface(dev); /* 10Mb/s RX pkts maybe handled */ + return -EIO; + } + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */ + hp100_start_interface(dev); + } + if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk("%s: login to 100Mb/s hub retry\n", dev->name); + hp100_stop_interface(dev); + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); + hp100_start_interface(dev); + } else { + hp100_ints_off(); + i = hp100_sense_lan(dev); + hp100_page(PERFORMANCE); + hp100_ints_on(); + if (i == HP100_LAN_ERR) + printk("%s: link down detected\n", dev->name); + else if (lp->lan_type != i) { /* cable change! */ + /* it's very hard - all network setting must be changed!!! */ + printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); + lp->lan_type = i; + hp100_stop_interface(dev); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); + hp100_start_interface(dev); + } else { + printk("%s: interface reset\n", dev->name); + hp100_stop_interface(dev); + hp100_start_interface(dev); + } + } + + dev->trans_start = jiffies; + return -EAGAIN; + } + /* + * we have to turn int's off before modifying this, otherwise + * a tx_pdl_cleanup could occur at the same time + */ + cli(); + ringptr = lp->txrtail; + lp->txrtail = ringptr->next; + + /* Check whether packet has minimal packet size */ + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + ringptr->skb = skb; + ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */ + ringptr->pdl[1] = (u32) virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ + if (lp->chip == HP100_CHIPID_SHASTA) { + /* TODO:Could someone who has the EISA card please check if this works? */ + ringptr->pdl[2] = i; + } else { /* Lassen */ + /* In the PDL, don't use the padded size but the real packet size: */ + ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */ + } + + /* Hand this PDL to the card. */ + hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ + + lp->txrcommit++; + sti(); + + /* Update statistics */ + lp->stats.tx_packets++; #ifdef LINUX_2_1 - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - dev->trans_start = jiffies; - - return 0; -} + dev->trans_start = jiffies; + return 0; +} + /* clean_txring checks if packets have been sent by the card by reading * the TX_PDL register from the performance page and comparing it to the * number of commited packets. It then frees the skb's of the packets that @@ -1538,188 +1447,168 @@ * * Needs the PERFORMANCE page selected. */ -static void hp100_clean_txring( struct device *dev ) +static void hp100_clean_txring(struct device *dev) { - struct hp100_private *lp = (struct hp100_private *)dev->priv; - int ioaddr = dev->base_addr; - int donecount; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + int donecount; #ifdef HP100_DEBUG_B - hp100_outw( 0x4211, TRACE ); - printk("hp100: clean txring\n"); + hp100_outw(0x4211, TRACE); + printk("hp100: clean txring\n"); #endif - /* How many PDLs have been transmitted? */ - donecount=(lp->txrcommit)-hp100_inb(TX_PDL); + /* How many PDLs have been transmitted? */ + donecount = (lp->txrcommit) - hp100_inb(TX_PDL); #ifdef HP100_DEBUG - if(donecount>MAX_TX_PDL) - printk("hp100: Warning: More PDLs transmitted than commited to card???\n"); + if (donecount > MAX_TX_PDL) + printk("hp100: Warning: More PDLs transmitted than commited to card???\n"); #endif - for( ; 0!=donecount; donecount-- ) - { + for (; 0 != donecount; donecount--) { #ifdef HP100_DEBUG_BM - printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", - (u_int) lp->txrhead->skb->data, - lp->txrcommit, - hp100_inb(TX_PDL), - donecount); -#endif - dev_kfree_skb( lp->txrhead->skb, FREE_WRITE ); - lp->txrhead->skb=(void *)NULL; - lp->txrhead=lp->txrhead->next; - lp->txrcommit--; - } + printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", + (u_int) lp->txrhead->skb->data, + lp->txrcommit, + hp100_inb(TX_PDL), + donecount); +#endif + dev_kfree_skb(lp->txrhead->skb, FREE_WRITE); + lp->txrhead->skb = (void *) NULL; + lp->txrhead = lp->txrhead->next; + lp->txrcommit--; + } } - + /* tx function for slave modes */ -static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ) +static int hp100_start_xmit(struct sk_buff *skb, struct device *dev) { - int i, ok_flag; - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4212, TRACE ); - printk("hp100: start_xmit\n"); -#endif - - if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ - { - hp100_stop_interface( dev ); - if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) - { - printk( "%s: no connection found - check wire\n", dev->name ); - hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */ - return -EIO; - } - if ( lp->lan_type == HP100_LAN_100 ) - lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ - hp100_start_interface( dev ); - } - - /* If there is not enough free memory on the card... */ - i=hp100_inl(TX_MEM_FREE)&0x7fffffff; - if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) ) - { -#ifdef HP100_DEBUG - printk( "hp100_start_xmit: tx free mem = 0x%x\n", i ); -#endif - /* not waited long enough since last failed tx try? */ - if ( jiffies - dev->trans_start < HZ/2 ) - { -#ifdef HP100_DEBUG - printk("hp100: trans_start timing problem\n"); -#endif - return -EAGAIN; - } - if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) - /* we have a 100Mb/s adapter but it isn't connected to hub */ - { - printk( "%s: login to 100Mb/s hub retry\n", dev->name ); - hp100_stop_interface( dev ); - lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); - hp100_start_interface( dev ); - } - else - { - hp100_ints_off(); - i = hp100_sense_lan( dev ); - hp100_page( PERFORMANCE ); - hp100_ints_on(); - if ( i == HP100_LAN_ERR ) - printk( "%s: link down detected\n", dev->name ); - else - if ( lp->lan_type != i ) /* cable change! */ - { - /* it's very hard - all network setting must be changed!!! */ - printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); - lp->lan_type = i; - hp100_stop_interface( dev ); - if ( lp->lan_type == HP100_LAN_100 ) - lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); - hp100_start_interface( dev ); - } - else - { - printk( "%s: interface reset\n", dev->name ); - hp100_stop_interface( dev ); - hp100_start_interface( dev ); - udelay(1000); - } - } - dev->trans_start = jiffies; - return -EAGAIN; - } + int i, ok_flag; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = (struct hp100_private *) dev->priv; - for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ ) - { +#ifdef HP100_DEBUG_B + hp100_outw(0x4212, TRACE); + printk("hp100: start_xmit\n"); +#endif + + if (lp->lan_type < 0) { /* no LAN type detected yet? */ + hp100_stop_interface(dev); + if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { + printk("%s: no connection found - check wire\n", dev->name); + hp100_start_interface(dev); /* 10Mb/s RX packets maybe handled */ + return -EIO; + } + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */ + hp100_start_interface(dev); + } + /* If there is not enough free memory on the card... */ + i = hp100_inl(TX_MEM_FREE) & 0x7fffffff; + if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) { +#ifdef HP100_DEBUG + printk("hp100_start_xmit: tx free mem = 0x%x\n", i); +#endif + /* not waited long enough since last failed tx try? */ + if (jiffies - dev->trans_start < HZ / 2) { +#ifdef HP100_DEBUG + printk("hp100: trans_start timing problem\n"); +#endif + return -EAGAIN; + } + if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk("%s: login to 100Mb/s hub retry\n", dev->name); + hp100_stop_interface(dev); + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); + hp100_start_interface(dev); + } else { + hp100_ints_off(); + i = hp100_sense_lan(dev); + hp100_page(PERFORMANCE); + hp100_ints_on(); + if (i == HP100_LAN_ERR) + printk("%s: link down detected\n", dev->name); + else if (lp->lan_type != i) { /* cable change! */ + /* it's very hard - all network setting must be changed!!! */ + printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); + lp->lan_type = i; + hp100_stop_interface(dev); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); + hp100_start_interface(dev); + } else { + printk("%s: interface reset\n", dev->name); + hp100_stop_interface(dev); + hp100_start_interface(dev); + udelay(1000); + } + } + dev->trans_start = jiffies; + return -EAGAIN; + } + for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) { #ifdef HP100_DEBUG_TX - printk( "hp100_start_xmit: busy\n" ); + printk("hp100_start_xmit: busy\n"); #endif - } - - hp100_ints_off(); - val = hp100_inw( IRQ_STATUS ); - /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set - * when the current packet being transmitted on the wire is completed. */ - hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS ); + } + + hp100_ints_off(); + val = hp100_inw(IRQ_STATUS); + /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set + * when the current packet being transmitted on the wire is completed. */ + hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS); #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",val,hp100_inw(IRQ_MASK),(int)skb->len ); + printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n", val, hp100_inw(IRQ_MASK), (int) skb->len); #endif - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + hp100_outw(i, DATA32); /* tell card the total packet length */ + hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */ + + if (lp->mode == 2) { /* memory mapped */ + if (lp->mem_ptr_virt) { /* high pci memory was remapped */ + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); + if (!ok_flag) + memset(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); + } else { + memcpy_toio(lp->mem_ptr_phys, skb->data, skb->len); + if (!ok_flag) + memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len); + } + } else { /* programmed i/o */ + outsl(ioaddr + HP100_REG_DATA32, skb->data, (skb->len + 3) >> 2); + if (!ok_flag) + for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4) + hp100_outl(0, DATA32); + } + + hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */ - hp100_outw( i, DATA32 ); /* tell card the total packet length */ - hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */ - - if ( lp->mode==2 ) /* memory mapped */ - { - if ( lp->mem_ptr_virt ) /* high pci memory was remapped */ - { - /* Note: The J2585B needs alignment to 32bits here! */ - memcpy( lp->mem_ptr_virt, skb->data, ( skb->len +3 ) & ~3 ); - if ( !ok_flag ) - memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); - } - else - { - memcpy_toio( lp->mem_ptr_phys, skb->data, skb->len ); - if ( !ok_flag ) - memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); - } - } - else /* programmed i/o */ - { - outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 ); - if ( !ok_flag ) - for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) - hp100_outl( 0, DATA32 ); - } - - hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ - - lp->stats.tx_packets++; + lp->stats.tx_packets++; #ifdef LINUX_2_1 - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - dev->trans_start=jiffies; - hp100_ints_on(); - - dev_kfree_skb( skb, FREE_WRITE ); - + dev->trans_start = jiffies; + hp100_ints_on(); + + dev_kfree_skb(skb, FREE_WRITE); + #ifdef HP100_DEBUG_TX - printk( "hp100_start_xmit: end\n" ); + printk("hp100_start_xmit: end\n"); #endif - - return 0; -} + return 0; +} + /* * Receive Function (Non-Busmaster mode) * Called when an "Receive Packet" interrupt occurs, i.e. the receive @@ -1729,306 +1618,285 @@ * and netif_rx. */ -static void hp100_rx( struct device *dev ) +static void hp100_rx(struct device *dev) { - int packets, pkt_len; - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - u_int header; - struct sk_buff *skb; + int packets, pkt_len; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + u_int header; + struct sk_buff *skb; #ifdef DEBUG_B - hp100_outw( 0x4213, TRACE ); - printk("hp100: rx\n"); + hp100_outw(0x4213, TRACE); + printk("hp100: rx\n"); #endif - /* First get indication of received lan packet */ - /* RX_PKT_CND indicates the number of packets which have been fully */ - /* received onto the card but have not been fully transfered of the card */ - packets = hp100_inb( RX_PKT_CNT ); + /* First get indication of received lan packet */ + /* RX_PKT_CND indicates the number of packets which have been fully */ + /* received onto the card but have not been fully transfered of the card */ + packets = hp100_inb(RX_PKT_CNT); #ifdef HP100_DEBUG_RX - if ( packets > 1 ) - printk( "hp100_rx: waiting packets = %d\n", packets ); + if (packets > 1) + printk("hp100_rx: waiting packets = %d\n", packets); #endif - while ( packets-- > 0 ) - { - /* If ADV_NXT_PKT is still set, we have to wait until the card has */ - /* really advanced to the next packet. */ - for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT); - pkt_len++ ) - { + while (packets-- > 0) { + /* If ADV_NXT_PKT is still set, we have to wait until the card has */ + /* really advanced to the next packet. */ + for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT); + pkt_len++) { #ifdef HP100_DEBUG_RX - printk( "hp100_rx: busy, remaining packets = %d\n", packets ); -#endif - } - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - if( lp->mode==2 ) /* memory mapped mode */ - { - if ( lp->mem_ptr_virt ) /* if memory was remapped */ - header = *(__u32 *)lp->mem_ptr_virt; - else - header = readl( lp->mem_ptr_phys ); - } - else /* programmed i/o */ - header = hp100_inl( DATA32 ); - - pkt_len = header & HP100_PKT_LEN_MASK; + printk("hp100_rx: busy, remaining packets = %d\n", packets); +#endif + } + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + if (lp->mode == 2) { /* memory mapped mode */ + if (lp->mem_ptr_virt) /* if memory was remapped */ + header = *(__u32 *) lp->mem_ptr_virt; + else + header = readl(lp->mem_ptr_phys); + } else /* programmed i/o */ + header = hp100_inl(DATA32); + + pkt_len = header & HP100_PKT_LEN_MASK; #ifdef HP100_DEBUG_RX - printk( "hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", - header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8, - (header>>16)&7); -#endif - - /* Now we allocate the skb and transfer the data into it. */ - /* NOTE! This (and the skb_put() below) depends on the skb-functions - * allocating more than asked (notably, aligning the request up to - * the next 16-byte length). - */ - skb = dev_alloc_skb( pkt_len ); - if ( skb == NULL ) /* Not enough memory->drop packet */ - { -#ifdef HP100_DEBUG - printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len ); -#endif - lp->stats.rx_dropped++; - } - else /* skb successfully allocated */ - { - u_char *ptr; - - skb->dev = dev; - - /* ptr to start of the sk_buff data area */ - ptr = (u_char *)skb_put( skb, pkt_len ); - - /* Now transfer the data from the card into that area */ - if ( lp->mode==2 ) - { - if ( lp->mem_ptr_virt ) - memcpy( ptr, lp->mem_ptr_virt, ( pkt_len + 3 ) & ~3 ); - /* Note alignment to 32bit transfers */ - else - memcpy_fromio( ptr, lp->mem_ptr_phys, ( pkt_len + 3 ) & ~3 ); - } - else /* io mapped */ - insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 ); - - skb->protocol = eth_type_trans( skb, dev ); + printk("hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", + header & HP100_PKT_LEN_MASK, (header >> 16) & 0xfff8, + (header >> 16) & 7); +#endif + + /* Now we allocate the skb and transfer the data into it. */ + /* NOTE! This (and the skb_put() below) depends on the skb-functions + * allocating more than asked (notably, aligning the request up to + * the next 16-byte length). + */ + skb = dev_alloc_skb(pkt_len); + if (skb == NULL) { /* Not enough memory->drop packet */ +#ifdef HP100_DEBUG + printk("hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len); +#endif + lp->stats.rx_dropped++; + } else { /* skb successfully allocated */ + u_char *ptr; + + skb->dev = dev; + + /* ptr to start of the sk_buff data area */ + ptr = (u_char *) skb_put(skb, pkt_len); + + /* Now transfer the data from the card into that area */ + if (lp->mode == 2) { + if (lp->mem_ptr_virt) + memcpy(ptr, lp->mem_ptr_virt, (pkt_len + 3) & ~3); + /* Note alignment to 32bit transfers */ + else + memcpy_fromio(ptr, lp->mem_ptr_phys, (pkt_len + 3) & ~3); + } else /* io mapped */ + insl(ioaddr + HP100_REG_DATA32, ptr, (pkt_len + 3) >> 2); + + skb->protocol = eth_type_trans(skb, dev); - netif_rx( skb ); - lp->stats.rx_packets++; + netif_rx(skb); + lp->stats.rx_packets++; #ifdef LINUX_2_1 - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += skb->len; #endif - + #ifdef HP100_DEBUG_RX - printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], - ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); + printk("rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], + ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11]); #endif - } - - /* Indicate the card that we have got the packet */ - hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW ); - - switch ( header & 0x00070000 ) { - case (HP100_MULTI_ADDR_HASH<<16): - case (HP100_MULTI_ADDR_NO_HASH<<16): - lp->stats.multicast++; break; - } - } /* end of while(there are packets) loop */ + } + + /* Indicate the card that we have got the packet */ + hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW); + + switch (header & 0x00070000) { + case (HP100_MULTI_ADDR_HASH << 16): + case (HP100_MULTI_ADDR_NO_HASH << 16): + lp->stats.multicast++; + break; + } + } /* end of while(there are packets) loop */ #ifdef HP100_DEBUG_RX - printk( "hp100_rx: end\n" ); + printk("hp100_rx: end\n"); #endif } - + /* * Receive Function for Busmaster Mode */ -static void hp100_rx_bm( struct device *dev ) +static void hp100_rx_bm(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - hp100_ring_t *ptr; - u_int header; - int pkt_len; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4214, TRACE ); - printk("hp100: rx_bm\n"); + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + hp100_ring_t *ptr; + u_int header; + int pkt_len; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4214, TRACE); + printk("hp100: rx_bm\n"); #endif #ifdef HP100_DEBUG - if(0==lp->rxrcommit) - { - printk("hp100: rx_bm called although no PDLs were committed to adapter?\n"); - return; - } - else - - /* RX_PKT_CNT states how many PDLs are currently formatted and available to - * the cards BM engine */ - if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit) - { - printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit); - return; - } -#endif - - while( (lp->rxrcommit > hp100_inb(RX_PDL)) ) - { - /* - * The packet was received into the pdl pointed to by lp->rxrhead ( - * the oldest pdl in the ring - */ - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - - ptr=lp->rxrhead; - - header = *(ptr->pdl-1); - pkt_len = (header & HP100_PKT_LEN_MASK); + if (0 == lp->rxrcommit) { + printk("hp100: rx_bm called although no PDLs were committed to adapter?\n"); + return; + } else + /* RX_PKT_CNT states how many PDLs are currently formatted and available to + * the cards BM engine */ + if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { + printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT) & 0x00ff, lp->rxrcommit); + return; + } +#endif + + while ((lp->rxrcommit > hp100_inb(RX_PDL))) { + /* + * The packet was received into the pdl pointed to by lp->rxrhead ( + * the oldest pdl in the ring + */ + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + + ptr = lp->rxrhead; + + header = *(ptr->pdl - 1); + pkt_len = (header & HP100_PKT_LEN_MASK); #ifdef HP100_DEBUG_BM - printk( "hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", - (u_int) (ptr->pdl-1),(u_int) header, - pkt_len, - (header>>16)&0xfff8, - (header>>16)&7); - printk( "hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", - hp100_inb( RX_PDL ), - hp100_inb( TX_PDL ), - hp100_inb( RX_PKT_CNT ), - (u_int) *(ptr->pdl), - (u_int) *(ptr->pdl+3), - (u_int) *(ptr->pdl+4)); -#endif - - if( (pkt_len>=MIN_ETHER_SIZE) && - (pkt_len<=MAX_ETHER_SIZE) ) - { - if(ptr->skb==NULL) - { - printk("hp100: rx_bm: skb null\n"); - /* can happen if we only allocated room for the pdh due to memory shortage. */ - lp->stats.rx_dropped++; - } - else - { - skb_trim( ptr->skb, pkt_len ); /* Shorten it */ - ptr->skb->protocol = eth_type_trans( ptr->skb, dev ); - - netif_rx( ptr->skb ); /* Up and away... */ + printk("hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", + (u_int) (ptr->pdl - 1), (u_int) header, + pkt_len, + (header >> 16) & 0xfff8, + (header >> 16) & 7); + printk("hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", + hp100_inb(RX_PDL), + hp100_inb(TX_PDL), + hp100_inb(RX_PKT_CNT), + (u_int) * (ptr->pdl), + (u_int) * (ptr->pdl + 3), + (u_int) * (ptr->pdl + 4)); +#endif + + if ((pkt_len >= MIN_ETHER_SIZE) && + (pkt_len <= MAX_ETHER_SIZE)) { + if (ptr->skb == NULL) { + printk("hp100: rx_bm: skb null\n"); + /* can happen if we only allocated room for the pdh due to memory shortage. */ + lp->stats.rx_dropped++; + } else { + skb_trim(ptr->skb, pkt_len); /* Shorten it */ + ptr->skb->protocol = eth_type_trans(ptr->skb, dev); + + netif_rx(ptr->skb); /* Up and away... */ - lp->stats.rx_packets++; + lp->stats.rx_packets++; #ifdef LINUX_2_1 - lp->stats.rx_bytes += ptr->skb->len; + lp->stats.rx_bytes += ptr->skb->len; #endif - } + } + + switch (header & 0x00070000) { + case (HP100_MULTI_ADDR_HASH << 16): + case (HP100_MULTI_ADDR_NO_HASH << 16): + lp->stats.multicast++; + break; + } + } else { +#ifdef HP100_DEBUG + printk("hp100: rx_bm: Received bad packet (length=%d)\n", pkt_len); +#endif + if (ptr->skb != NULL) + dev_kfree_skb(ptr->skb, FREE_READ); + lp->stats.rx_errors++; + } + + lp->rxrhead = lp->rxrhead->next; + + /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ + if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) { + /* No space for skb, header can still be received. */ +#ifdef HP100_DEBUG + printk("hp100: rx_bm: No space for new PDL.\n"); +#endif + return; + } else { /* successfully allocated new PDL - put it in ringlist at tail. */ + hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA); + lp->rxrtail = lp->rxrtail->next; + } - switch ( header & 0x00070000 ) { - case (HP100_MULTI_ADDR_HASH<<16): - case (HP100_MULTI_ADDR_NO_HASH<<16): - lp->stats.multicast++; break; - } - } - else - { -#ifdef HP100_DEBUG - printk("hp100: rx_bm: Received bad packet (length=%d)\n",pkt_len); -#endif - if(ptr->skb!=NULL) - dev_kfree_skb( ptr->skb, FREE_READ ); - lp->stats.rx_errors++; - } - - lp->rxrhead=lp->rxrhead->next; - - /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ - if (0 == hp100_build_rx_pdl( lp->rxrtail, dev )) - { - /* No space for skb, header can still be received. */ -#ifdef HP100_DEBUG - printk("hp100: rx_bm: No space for new PDL.\n"); -#endif - return; - } - else - { /* successfully allocated new PDL - put it in ringlist at tail. */ - hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA); - lp->rxrtail=lp->rxrtail->next; } - - } } + - /* * statistics */ -static hp100_stats_t *hp100_get_stats( struct device *dev ) +static hp100_stats_t *hp100_get_stats(struct device *dev) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #ifdef HP100_DEBUG_B - hp100_outw( 0x4215, TRACE ); + hp100_outw(0x4215, TRACE); #endif - hp100_ints_off(); - hp100_update_stats( dev ); - hp100_ints_on(); - return &((struct hp100_private *)dev->priv)->stats; + hp100_ints_off(); + hp100_update_stats(dev); + hp100_ints_on(); + return &((struct hp100_private *) dev->priv)->stats; } -static void hp100_update_stats( struct device *dev ) +static void hp100_update_stats(struct device *dev) { - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = (struct hp100_private *) dev->priv; #ifdef HP100_DEBUG_B - hp100_outw( 0x4216, TRACE ); - printk("hp100: update-stats\n"); + hp100_outw(0x4216, TRACE); + printk("hp100: update-stats\n"); #endif - /* Note: Statistics counters clear when read. */ - hp100_page( MAC_CTRL ); - val = hp100_inw( DROPPED ) & 0x0fff; - lp->stats.rx_errors += val; - lp->stats.rx_over_errors += val; - val = hp100_inb( CRC ); - lp->stats.rx_errors += val; - lp->stats.rx_crc_errors += val; - val = hp100_inb( ABORT ); - lp->stats.tx_errors += val; - lp->stats.tx_aborted_errors += val; - hp100_page( PERFORMANCE ); + /* Note: Statistics counters clear when read. */ + hp100_page(MAC_CTRL); + val = hp100_inw(DROPPED) & 0x0fff; + lp->stats.rx_errors += val; + lp->stats.rx_over_errors += val; + val = hp100_inb(CRC); + lp->stats.rx_errors += val; + lp->stats.rx_crc_errors += val; + val = hp100_inb(ABORT); + lp->stats.tx_errors += val; + lp->stats.tx_aborted_errors += val; + hp100_page(PERFORMANCE); } -static void hp100_clear_stats( int ioaddr ) +static void hp100_clear_stats(int ioaddr) { #ifdef HP100_DEBUG_B - hp100_outw( 0x4217, TRACE ); - printk("hp100: clear_stats\n"); + hp100_outw(0x4217, TRACE); + printk("hp100: clear_stats\n"); #endif - cli(); - hp100_page( MAC_CTRL ); /* get all statistics bytes */ - hp100_inw( DROPPED ); - hp100_inb( CRC ); - hp100_inb( ABORT ); - hp100_page( PERFORMANCE ); - sti(); + cli(); + hp100_page(MAC_CTRL); /* get all statistics bytes */ + hp100_inw(DROPPED); + hp100_inb(CRC); + hp100_inb(ABORT); + hp100_page(PERFORMANCE); + sti(); } - + /* * multicast setup */ @@ -2038,736 +1906,693 @@ * TODO: Currently when in multicast mode, card accepts all multicast packets * for all MC addresses. Should better use the list on the card. */ - -static void hp100_set_multicast_list( struct device *dev) + +static void hp100_set_multicast_list(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; #ifdef HP100_DEBUG_B - hp100_outw( 0x4218, TRACE ); - printk("hp100: set_mc_list\n"); -#endif - - cli(); - hp100_ints_off(); - hp100_page( MAC_CTRL ); - hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ - - if ( dev->flags & IFF_PROMISC ) - { - lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ - lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ - } - else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) ) - { - lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ - lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ - } - else - { - lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ - lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ - } - - if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) || - ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) { - hp100_outb( lp->mac2_mode, MAC_CFG_2 ); - hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */ - hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */ - - if(lp->lan_type==HP100_LAN_100) - { -#ifdef HP100_DEBUG - printk("hp100: 100VG MAC settings have changed - relogin.\n"); -#endif - lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */ - } - } - - hp100_page( MAC_CTRL ); - hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ - HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */ - - hp100_page( PERFORMANCE ); - hp100_ints_on(); - sti(); -} + hp100_outw(0x4218, TRACE); + printk("hp100: set_mc_list\n"); +#endif + cli(); + hp100_ints_off(); + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ + + if (dev->flags & IFF_PROMISC) { + lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ + lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ + } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ + lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ + } else { + lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ + lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ + } + + if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) || + (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) { + hp100_outb(lp->mac2_mode, MAC_CFG_2); + hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */ + hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */ + + if (lp->lan_type == HP100_LAN_100) { +#ifdef HP100_DEBUG + printk("hp100: 100VG MAC settings have changed - relogin.\n"); +#endif + lp->hub_status = hp100_login_to_vg_hub(dev, TRUE); /* force a relogin to the hub */ + } + } + hp100_page(MAC_CTRL); + hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ + HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1); /* enable tx */ + + hp100_page(PERFORMANCE); + hp100_ints_on(); + sti(); +} + /* * hardware interrupt handling */ -static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ) +static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct device *dev = dev_id; - struct hp100_private *lp = (struct hp100_private *)dev->priv; + struct device *dev = dev_id; + struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr; - u_int val; + int ioaddr; + u_int val; - if ( dev == NULL ) return; - ioaddr = dev->base_addr; + if (dev == NULL) + return; + ioaddr = dev->base_addr; - if ( dev->interrupt ) - printk( "%s: re-entering the interrupt handler\n", dev->name ); - hp100_ints_off(); - dev->interrupt = 1; /* mark that we are inside the handler */ + if (dev->interrupt) + printk("%s: re-entering the interrupt handler\n", dev->name); + hp100_ints_off(); + dev->interrupt = 1; /* mark that we are inside the handler */ #ifdef HP100_DEBUG_B - hp100_outw( 0x4219, TRACE ); + hp100_outw(0x4219, TRACE); #endif - /* hp100_page( PERFORMANCE ); */ - val = hp100_inw( IRQ_STATUS ); + /* hp100_page( PERFORMANCE ); */ + val = hp100_inw(IRQ_STATUS); #ifdef HP100_DEBUG_IRQ - printk( "hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", - lp->mode, - (u_int)val, - hp100_inb( RX_PKT_CNT ), - hp100_inb( RX_PDL ), - hp100_inb( TX_PKT_CNT ), - hp100_inb( TX_PDL ) - ); -#endif - - if(val==0) /* might be a shared interrupt */ - { - dev->interrupt=0; - hp100_ints_on(); - return; - } - /* We're only interested in those interrupts we really enabled. */ - /* val &= hp100_inw( IRQ_MASK ); */ - - /* - * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL - * is considered executed whenever the RX_PDL data structure is no longer - * needed. - */ - if ( val & HP100_RX_PDL_FILL_COMPL ) - { - if(lp->mode==1) - hp100_rx_bm( dev ); - else - printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n"); - } - - /* - * The RX_PACKET interrupt is set, when the receive packet counter is - * non zero. We use this interrupt for receiving in slave mode. In - * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill - * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then - * we somehow have missed a rx_pdl_fill_compl interrupt. - */ - - if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */ - { - if(lp->mode!=1) /* non busmaster */ - hp100_rx( dev ); - else if ( !(val & HP100_RX_PDL_FILL_COMPL )) - { - /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ - hp100_rx_bm( dev ); - } - } - - /* - * Ack. that we have noticed the interrupt and thereby allow next one. - * Note that this is now done after the slave rx function, since first - * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt - * on the J2573. - */ - hp100_outw( val, IRQ_STATUS ); - - /* - * RX_ERROR is set when a packet is dropped due to no memory resources on - * the card or when a RCV_ERR occurs. - * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists - * only in the 802.3 MAC and happens when 16 collisions occur during a TX - */ - if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) ) - { + printk("hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", + lp->mode, + (u_int) val, + hp100_inb(RX_PKT_CNT), + hp100_inb(RX_PDL), + hp100_inb(TX_PKT_CNT), + hp100_inb(TX_PDL) + ); +#endif + + if (val == 0) { /* might be a shared interrupt */ + dev->interrupt = 0; + hp100_ints_on(); + return; + } + /* We're only interested in those interrupts we really enabled. */ + /* val &= hp100_inw( IRQ_MASK ); */ + + /* + * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL + * is considered executed whenever the RX_PDL data structure is no longer + * needed. + */ + if (val & HP100_RX_PDL_FILL_COMPL) { + if (lp->mode == 1) + hp100_rx_bm(dev); + else + printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n"); + } + /* + * The RX_PACKET interrupt is set, when the receive packet counter is + * non zero. We use this interrupt for receiving in slave mode. In + * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill + * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then + * we somehow have missed a rx_pdl_fill_compl interrupt. + */ + + if (val & HP100_RX_PACKET) { /* Receive Packet Counter is non zero */ + if (lp->mode != 1) /* non busmaster */ + hp100_rx(dev); + else if (!(val & HP100_RX_PDL_FILL_COMPL)) { + /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ + hp100_rx_bm(dev); + } + } + /* + * Ack. that we have noticed the interrupt and thereby allow next one. + * Note that this is now done after the slave rx function, since first + * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt + * on the J2573. + */ + hp100_outw(val, IRQ_STATUS); + + /* + * RX_ERROR is set when a packet is dropped due to no memory resources on + * the card or when a RCV_ERR occurs. + * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists + * only in the 802.3 MAC and happens when 16 collisions occur during a TX + */ + if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) { #ifdef HP100_DEBUG_IRQ - printk("hp100: TX/RX Error IRQ\n"); + printk("hp100: TX/RX Error IRQ\n"); #endif - hp100_update_stats( dev ); - if(lp->mode==1) - { - hp100_rxfill( dev ); - hp100_clean_txring( dev ); - } - } - - /* - * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. - */ - if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) ) - hp100_rxfill( dev ); - - /* - * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire - * is completed - */ - if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) ) - hp100_clean_txring( dev ); - - /* - * MISC_ERROR is set when either the LAN link goes down or a detected - * bus error occurs. - */ - if ( val & HP100_MISC_ERROR ) /* New for J2585B */ - { - printk("hp100: Misc. Error Interrupt - Check cabling.\n"); - if(lp->mode==1) - { - hp100_clean_txring( dev ); - hp100_rxfill( dev ); - } - } - - dev->interrupt = 0; - hp100_ints_on(); + hp100_update_stats(dev); + if (lp->mode == 1) { + hp100_rxfill(dev); + hp100_clean_txring(dev); + } + } + /* + * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. + */ + if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO))) + hp100_rxfill(dev); + + /* + * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire + * is completed + */ + if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE))) + hp100_clean_txring(dev); + + /* + * MISC_ERROR is set when either the LAN link goes down or a detected + * bus error occurs. + */ + if (val & HP100_MISC_ERROR) { /* New for J2585B */ + printk("hp100: Misc. Error Interrupt - Check cabling.\n"); + if (lp->mode == 1) { + hp100_clean_txring(dev); + hp100_rxfill(dev); + } + } + dev->interrupt = 0; + hp100_ints_on(); } - + /* * some misc functions */ -static void hp100_start_interface( struct device *dev ) +static void hp100_start_interface(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4220, TRACE); + printk("hp100: hp100_start_interface %s\n", dev->name); +#endif + + cli(); + + /* Ensure the adapter does not want to request an interrupt when */ + /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */ + hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ + hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW); + + if (lp->mode == 1) { + /* Make sure BM bit is set... */ + hp100_page(HW_MAP); + hp100_orb(HP100_BM_MASTER, BM); + hp100_rxfill(dev); + } else if (lp->mode == 2) { + /* Enable memory mapping. Note: Don't do this when busmaster. */ + hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); + } + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ + + /* enable a few interrupts: */ + if (lp->mode == 1) { /* busmaster mode */ + hp100_outw(HP100_RX_PDL_FILL_COMPL | + HP100_RX_PDA_ZERO | + HP100_RX_ERROR | + /* HP100_RX_PACKET | */ + /* HP100_RX_EARLY_INT | */ HP100_SET_HB | + /* HP100_TX_PDA_ZERO | */ + HP100_TX_COMPLETE | + /* HP100_MISC_ERROR | */ + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); + } else { + hp100_outw(HP100_RX_PACKET | + HP100_RX_ERROR | HP100_SET_HB | + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); + } + + /* Enable MAC Tx and RX, set MAC modes, ... */ + /* Note: This function also turns on the interrupts. */ + hp100_set_multicast_list(dev); +} + + +static void hp100_stop_interface(struct device *dev) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + u_int val; #ifdef HP100_DEBUG_B - hp100_outw( 0x4220, TRACE ); - printk("hp100: hp100_start_interface %s\n",dev->name); + printk("hp100: hp100_stop_interface %s\n", dev->name); + hp100_outw(0x4221, TRACE); #endif - cli(); - - /* Ensure the adapter does not want to request an interrupt when */ - /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ - hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */ - hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW); - /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ - hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW ); - - if(lp->mode==1) - { - /* Make sure BM bit is set... */ - hp100_page(HW_MAP); - hp100_orb( HP100_BM_MASTER, BM ); - hp100_rxfill( dev ); - } - else if(lp->mode==2) - { - /* Enable memory mapping. Note: Don't do this when busmaster. */ - hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); - } - - hp100_page(PERFORMANCE); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ - - /* enable a few interrupts: */ - if(lp->mode==1) /* busmaster mode */ - { - hp100_outw( HP100_RX_PDL_FILL_COMPL | - HP100_RX_PDA_ZERO | - HP100_RX_ERROR | - /* HP100_RX_PACKET | */ - /* HP100_RX_EARLY_INT | */ HP100_SET_HB | - /* HP100_TX_PDA_ZERO | */ - HP100_TX_COMPLETE | - /* HP100_MISC_ERROR | */ - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK ); - } - else - { - hp100_outw( HP100_RX_PACKET | - HP100_RX_ERROR | HP100_SET_HB | - HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK ); - } - - /* Enable MAC Tx and RX, set MAC modes, ... */ - /* Note: This function also turns on the interrupts. */ - hp100_set_multicast_list( dev ); -} - - -static void hp100_stop_interface( struct device *dev ) -{ - struct hp100_private *lp = (struct hp100_private *)dev->priv; - int ioaddr = dev->base_addr; - u_int val; - -#ifdef HP100_DEBUG_B - printk("hp100: hp100_stop_interface %s\n",dev->name); - hp100_outw( 0x4221, TRACE ); -#endif - - if (lp->mode==1) - hp100_BM_shutdown( dev ); - else - { - /* Note: MMAP_DIS will be reenabled by start_interface */ - hp100_outw( HP100_INT_EN | HP100_RESET_LB | - HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); - val = hp100_inw( OPTION_LSW ); - - hp100_page( MAC_CTRL ); - hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); - - if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */ - /* ... else: busy wait until idle */ - for ( val = 0; val < 6000; val++ ) - if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) == - (HP100_TX_IDLE | HP100_RX_IDLE) ) - { - hp100_page(PERFORMANCE); - return; - } - printk( "%s: hp100_stop_interface - timeout\n", dev->name ); - hp100_page(PERFORMANCE); - } -} - - -static void hp100_load_eeprom( struct device *dev ) -{ - int i; - int ioaddr = dev->base_addr; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4222, TRACE ); -#endif - - hp100_page( EEPROM_CTRL ); - hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL ); - hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL ); - for ( i = 0; i < 10000; i++ ) - if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return; - printk( "%s: hp100_load_eeprom - timeout\n", dev->name ); + if (lp->mode == 1) + hp100_BM_shutdown(dev); + else { + /* Note: MMAP_DIS will be reenabled by start_interface */ + hp100_outw(HP100_INT_EN | HP100_RESET_LB | + HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); + val = hp100_inw(OPTION_LSW); + + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); + + if (!(val & HP100_HW_RST)) + return; /* If reset, imm. return ... */ + /* ... else: busy wait until idle */ + for (val = 0; val < 6000; val++) + if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == + (HP100_TX_IDLE | HP100_RX_IDLE)) { + hp100_page(PERFORMANCE); + return; + } + printk("%s: hp100_stop_interface - timeout\n", dev->name); + hp100_page(PERFORMANCE); + } } + + +static void hp100_load_eeprom(struct device *dev) +{ + int i; + int ioaddr = dev->base_addr; +#ifdef HP100_DEBUG_B + hp100_outw(0x4222, TRACE); +#endif + + hp100_page(EEPROM_CTRL); + hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL); + hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL); + for (i = 0; i < 10000; i++) + if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD)) + return; + printk("%s: hp100_load_eeprom - timeout\n", dev->name); +} + /* Sense connection status. * return values: LAN_10 - Connected to 10Mbit/s network * LAN_100 - Connected to 100Mbit/s network * LAN_ERR - not connected or 100Mbit/s Hub down */ -static int hp100_sense_lan( struct device *dev ) +static int hp100_sense_lan(struct device *dev) +{ + int ioaddr = dev->base_addr; + u_short val_VG, val_10; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4223, TRACE); +#endif + + hp100_page(MAC_CTRL); + /* Enable Auto Selection */ + /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */ + /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */ + /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */ + /* Now we have to wait a while... */ + /* for(i=0; i<5000; i++) */ + /* { */ + val_10 = hp100_inb(10_LAN_CFG_1); + val_VG = hp100_inb(VG_LAN_CFG_1); + /* } */ +#ifdef HP100_DEBUG + printk("hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10); +#endif + if (val_10 & HP100_LINK_BEAT_ST) + return HP100_LAN_10; + if ((lp->id->id == 0x02019F022) || + (lp->id->id == 0x01042103c) || + (lp->id->id == 0x01040103c)) { + hp100_page(PERFORMANCE); + return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ + } + /* for ( i = 0; i < 2500; i++ ) */ + /* { */ + val_VG = hp100_inb(VG_LAN_CFG_1); + hp100_page(PERFORMANCE); + + if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ + return HP100_LAN_100; + /* } */ + return HP100_LAN_ERR; +} + + + +static int hp100_down_vg_link(struct device *dev) { - int ioaddr = dev->base_addr; - u_short val_VG, val_10; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4223, TRACE ); -#endif - - hp100_page( MAC_CTRL ); - /* Enable Auto Selection */ - /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */ - /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */ - /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */ - /* Now we have to wait a while... */ - /* for(i=0; i<5000; i++) */ - /* { */ - val_10 = hp100_inb( 10_LAN_CFG_1 ); - val_VG = hp100_inb( VG_LAN_CFG_1 ); - /* } */ -#ifdef HP100_DEBUG - printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 ); -#endif - if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10; - if ( (lp->id->id == 0x02019F022) || - (lp->id->id == 0x01042103c) || - (lp->id->id == 0x01040103c) ) - { - hp100_page(PERFORMANCE); - return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ - } - /* for ( i = 0; i < 2500; i++ ) */ - /* { */ - val_VG = hp100_inb( VG_LAN_CFG_1 ); - hp100_page(PERFORMANCE); - - if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */ - return HP100_LAN_100; - /* } */ - return HP100_LAN_ERR; -} - - - -static int hp100_down_vg_link( struct device *dev ) -{ - struct hp100_private *lp = (struct hp100_private *)dev->priv; - int ioaddr = dev->base_addr; - unsigned long time; - long savelan, newlan; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4224, TRACE ); - printk("hp100: down_vg_link\n"); -#endif - - hp100_page( MAC_CTRL ); - time=jiffies+(HZ/4); - do{ - if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; - } while (time>jiffies); - - if ( jiffies >= time ) /* no signal->no logout */ - return 0; - - /* Drop the VG Link by clearing the link up cmd and load addr.*/ - - hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1); - hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1); - - /* Conditionally stall for >250ms on Link-Up Status (to go down) */ - time=jiffies+(HZ/2); - do{ - if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break; - } while(time>jiffies); - -#ifdef HP100_DEBUG - if (jiffies>=time) - printk("hp100_down_vg_link: Link does not go down?\n"); -#endif - - /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ - /* logout under traffic (even though all the status bits are cleared), */ - /* do this workaround to get the Rev 1 MAC in its idle state */ - if ( lp->chip==HP100_CHIPID_LASSEN ) - { - /* Reset VG MAC to insure it leaves the logoff state even if */ - /* the Hub is still emitting tones */ - hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); - udelay(1500); /* wait for >1ms */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ - udelay(1500); - } - - /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ - /* to get the VG mac to full reset. This is not req.d with later chips */ - /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ - /* selected again! This will be left to the connect hub function to */ - /* perform if desired. */ - if (lp->chip==HP100_CHIPID_LASSEN) - { - /* Have to write to 10 and 100VG control registers simultaneously */ - savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ - newlan &= ~(HP100_VG_SEL<<16); - newlan |= (HP100_DOT3_MAC)<<8; - hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ - hp100_outl(newlan, 10_LAN_CFG_1); - - /* Conditionally stall for 5sec on VG selected. */ - time=jiffies+(HZ*5); - do{ - if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break; - } while(time>jiffies); - - hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ - hp100_outl(savelan, 10_LAN_CFG_1); - } - - time=jiffies+(3*HZ); /* Timeout 3s */ - do { - if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break; - } while (time>jiffies); - - if(time<=jiffies) - { -#ifdef HP100_DEBUG - printk( "hp100_down_vg_link: timeout\n" ); -#endif - return -EIO; - } - - time=jiffies+(2*HZ); /* This seems to take a while.... */ - do {} while (time>jiffies); - - return 0; -} - - -static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - u_short val=0; - unsigned long time; - int startst; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4225, TRACE ); - printk("hp100: login_to_vg_hub\n"); -#endif - - /* Initiate a login sequence iff VG MAC is enabled and either Load Address - * bit is zero or the force relogin flag is set (e.g. due to MAC address or - * promiscuous mode change) - */ - hp100_page( MAC_CTRL ); - startst=hp100_inb( VG_LAN_CFG_1 ); - if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST)) - { + struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + unsigned long time; + long savelan, newlan; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4224, TRACE); + printk("hp100: down_vg_link\n"); +#endif + + hp100_page(MAC_CTRL); + time = jiffies + (HZ / 4); + do { + if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) + break; + } while (time > jiffies); + + if (jiffies >= time) /* no signal->no logout */ + return 0; + + /* Drop the VG Link by clearing the link up cmd and load addr. */ + + hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1); + hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1); + + /* Conditionally stall for >250ms on Link-Up Status (to go down) */ + time = jiffies + (HZ / 2); + do { + if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) + break; + } while (time > jiffies); + +#ifdef HP100_DEBUG + if (jiffies >= time) + printk("hp100_down_vg_link: Link does not go down?\n"); +#endif + + /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ + /* logout under traffic (even though all the status bits are cleared), */ + /* do this workaround to get the Rev 1 MAC in its idle state */ + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Reset VG MAC to insure it leaves the logoff state even if */ + /* the Hub is still emitting tones */ + hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); + udelay(1500); /* wait for >1ms */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ + udelay(1500); + } + /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ + /* to get the VG mac to full reset. This is not req.d with later chips */ + /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ + /* selected again! This will be left to the connect hub function to */ + /* perform if desired. */ + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Have to write to 10 and 100VG control registers simultaneously */ + savelan = newlan = hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ + newlan &= ~(HP100_VG_SEL << 16); + newlan |= (HP100_DOT3_MAC) << 8; + hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ + hp100_outl(newlan, 10_LAN_CFG_1); + + /* Conditionally stall for 5sec on VG selected. */ + time = jiffies + (HZ * 5); + do { + if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) + break; + } while (time > jiffies); + + hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ + hp100_outl(savelan, 10_LAN_CFG_1); + } + time = jiffies + (3 * HZ); /* Timeout 3s */ + do { + if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) + break; + } while (time > jiffies); + + if (time <= jiffies) { +#ifdef HP100_DEBUG + printk("hp100_down_vg_link: timeout\n"); +#endif + return -EIO; + } + time = jiffies + (2 * HZ); /* This seems to take a while.... */ + do { + } while (time > jiffies); + + return 0; +} + + +static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + u_short val = 0; + unsigned long time; + int startst; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4225, TRACE); + printk("hp100: login_to_vg_hub\n"); +#endif + + /* Initiate a login sequence iff VG MAC is enabled and either Load Address + * bit is zero or the force relogin flag is set (e.g. due to MAC address or + * promiscuous mode change) + */ + hp100_page(MAC_CTRL); + startst = hp100_inb(VG_LAN_CFG_1); + if ((force_relogin == TRUE) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Start training\n"); + printk("hp100: Start training\n"); #endif - /* Ensure VG Reset bit is 1 (i.e., do not reset)*/ - hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 ); + /* Ensure VG Reset bit is 1 (i.e., do not reset) */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); + + /* If Lassen AND auto-select-mode AND VG tones were sensed on */ + /* entry then temporarily put them into force 100Mbit mode */ + if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) + hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2); - /* If Lassen AND auto-select-mode AND VG tones were sensed on */ - /* entry then temporarily put them into force 100Mbit mode */ - if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) ) - hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 ); - - /* Drop the VG link by zeroing Link Up Command and Load Address */ - hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1); + /* Drop the VG link by zeroing Link Up Command and Load Address */ + hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1); #ifdef HP100_DEBUG_TRAINING - printk("hp100: Bring down the link\n"); + printk("hp100: Bring down the link\n"); #endif - /* Wait for link to drop */ - time = jiffies + (HZ/10); - do { - if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break; - } while (time>jiffies); - - /* Start an addressed training and optionally request promiscuous port */ - if ( (dev->flags) & IFF_PROMISC ) - { - hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2); - if(lp->chip==HP100_CHIPID_LASSEN) - hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST ); - } - else - { - hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2); - /* For ETR parts we need to reset the prom. bit in the training - * register, otherwise promiscious mode won't be disabled. - */ - if(lp->chip==HP100_CHIPID_LASSEN) - { - hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST ); - } - } - - /* With ETR parts, frame format request bits can be set. */ - if(lp->chip==HP100_CHIPID_LASSEN) - hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); - - hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1); - - /* Note: Next wait could be omitted for Hood and earlier chips under */ - /* certain circumstances */ - /* TODO: check if hood/earlier and skip wait. */ - - /* Wait for either short timeout for VG tones or long for login */ - /* Wait for the card hardware to signalise link cable status ok... */ - hp100_page( MAC_CTRL ); - time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */ - do { - if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; - } while ( jiffies < time ); - - if ( jiffies >= time ) - { + /* Wait for link to drop */ + time = jiffies + (HZ / 10); + do { + if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) + break; + } while (time > jiffies); + + /* Start an addressed training and optionally request promiscuous port */ + if ((dev->flags) & IFF_PROMISC) { + hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2); + if (lp->chip == HP100_CHIPID_LASSEN) + hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST); + } else { + hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2); + /* For ETR parts we need to reset the prom. bit in the training + * register, otherwise promiscious mode won't be disabled. + */ + if (lp->chip == HP100_CHIPID_LASSEN) { + hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST); + } + } + + /* With ETR parts, frame format request bits can be set. */ + if (lp->chip == HP100_CHIPID_LASSEN) + hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); + + hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1); + + /* Note: Next wait could be omitted for Hood and earlier chips under */ + /* certain circumstances */ + /* TODO: check if hood/earlier and skip wait. */ + + /* Wait for either short timeout for VG tones or long for login */ + /* Wait for the card hardware to signalise link cable status ok... */ + hp100_page(MAC_CTRL); + time = jiffies + (1 * HZ); /* 1 sec timeout for cable st */ + do { + if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) + break; + } while (jiffies < time); + + if (jiffies >= time) { #ifdef HP100_DEBUG_TRAINING - printk( "hp100: Link cable status not ok? Training aborted.\n" ); -#endif - } - else - { + printk("hp100: Link cable status not ok? Training aborted.\n"); +#endif + } else { #ifdef HP100_DEBUG_TRAINING - printk( "hp100: HUB tones detected. Trying to train.\n"); + printk("hp100: HUB tones detected. Trying to train.\n"); #endif - time = jiffies + ( 2*HZ ); /* again a timeout */ - do { - val = hp100_inb( VG_LAN_CFG_1 ); - if ( (val & ( HP100_LINK_UP_ST )) ) - { + time = jiffies + (2 * HZ); /* again a timeout */ + do { + val = hp100_inb(VG_LAN_CFG_1); + if ((val & (HP100_LINK_UP_ST))) { #ifdef HP100_DEBUG_TRAINING - printk( "hp100: Passed training.\n"); + printk("hp100: Passed training.\n"); #endif - break; - } - } while ( time > jiffies ); - } - - /* If LINK_UP_ST is set, then we are logged into the hub. */ - if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) ) - { + break; + } + } while (time > jiffies); + } + + /* If LINK_UP_ST is set, then we are logged into the hub. */ + if ((jiffies <= time) && (val & HP100_LINK_UP_ST)) { #ifdef HP100_DEBUG_TRAINING - printk( "hp100: Successfully logged into the HUB.\n"); - if(lp->chip==HP100_CHIPID_LASSEN) - { - val = hp100_inw(TRAIN_ALLOW); - printk( "hp100: Card supports 100VG MAC Version \"%s\" ", - (hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre"); - printk( "Driver will use MAC Version \"%s\"\n", - ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" ); - printk( "hp100: Frame format is %s.\n",(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3"); - } -#endif - } - else - { - /* If LINK_UP_ST is not set, login was not successful */ - printk("hp100/%s: Problem logging into the HUB.\n",dev->name); - if(lp->chip==HP100_CHIPID_LASSEN) - { - /* Check allowed Register to find out why there is a problem. */ - val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */ + printk("hp100: Successfully logged into the HUB.\n"); + if (lp->chip == HP100_CHIPID_LASSEN) { + val = hp100_inw(TRAIN_ALLOW); + printk("hp100: Card supports 100VG MAC Version \"%s\" ", + (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre"); + printk("Driver will use MAC Version \"%s\"\n", + (val & HP100_HUB_MACVER) ? "802.12" : "Pre"); + printk("hp100: Frame format is %s.\n", (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3"); + } +#endif + } else { + /* If LINK_UP_ST is not set, login was not successful */ + printk("hp100/%s: Problem logging into the HUB.\n", dev->name); + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Check allowed Register to find out why there is a problem. */ + val = hp100_inw(TRAIN_ALLOW); /* wont work on non-ETR card */ #ifdef HP100_DEBUG_TRAINING - printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val); + printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val); #endif - if ( val & HP100_MALLOW_ACCDENIED ) - printk("hp100: HUB access denied.\n"); - if ( val & HP100_MALLOW_CONFIGURE ) - printk("hp100: MAC Configuration is incompatible with the Network.\n"); - if ( val & HP100_MALLOW_DUPADDR ) - printk("hp100: Duplicate MAC Address on the Network.\n"); - } - } - - /* If we have put the chip into forced 100 Mbit mode earlier, go back */ - /* to auto-select mode */ - - if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) ) - { - hp100_page( MAC_CTRL ); - hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 ); - } - - val=hp100_inb(VG_LAN_CFG_1); - - /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ - hp100_page(PERFORMANCE); - hp100_outw( HP100_MISC_ERROR, IRQ_STATUS); - - if (val&HP100_LINK_UP_ST) - return(0); /* login was ok */ - else - { - printk("hp100: Training failed.\n"); - hp100_down_vg_link( dev ); - return -EIO; - } - } - /* no forced relogin & already link there->no training. */ - return -EIO; -} - - -static void hp100_cascade_reset( struct device *dev, u_short enable ) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *)dev->priv; - int i; - -#ifdef HP100_DEBUG_B - hp100_outw( 0x4226, TRACE ); - printk("hp100: cascade_reset\n"); -#endif - - if (enable==TRUE) - { - hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW ); - if(lp->chip==HP100_CHIPID_LASSEN) - { - /* Lassen requires a PCI transmit fifo reset */ - hp100_page( HW_MAP ); - hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); - hp100_orb( HP100_PCI_RESET, PCICTRL2 ); - /* Wait for min. 300 ns */ - /* we cant use jiffies here, because it may be */ - /* that we have disabled the timer... */ - for (i=0; i<0xffff; i++); - hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); - hp100_page( PERFORMANCE ); - } - } - else - { /* bring out of reset */ - hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW); - for (i=0; i<0xffff; i++ ); - hp100_page(PERFORMANCE); - } -} - -#ifdef HP100_DEBUG -void hp100_RegisterDump( struct device *dev ) -{ - int ioaddr=dev->base_addr; - int Page; - int Register; - - /* Dump common registers */ - printk("hp100: Cascade Register Dump\n"); - printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID)); - printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING)); - printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW)); - printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW)); - - /* Dump paged registers */ - for (Page = 0; Page < 8; Page++) - { - /* Dump registers */ - printk("page: 0x%.2x\n",Page); - outw( Page, ioaddr+0x02); - for (Register = 0x8; Register < 0x22; Register += 2) - { - /* Display Register contents except data port */ - if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) - { - printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register)); - } + if (val & HP100_MALLOW_ACCDENIED) + printk("hp100: HUB access denied.\n"); + if (val & HP100_MALLOW_CONFIGURE) + printk("hp100: MAC Configuration is incompatible with the Network.\n"); + if (val & HP100_MALLOW_DUPADDR) + printk("hp100: Duplicate MAC Address on the Network.\n"); + } + } + + /* If we have put the chip into forced 100 Mbit mode earlier, go back */ + /* to auto-select mode */ + + if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) { + hp100_page(MAC_CTRL); + hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2); + } + val = hp100_inb(VG_LAN_CFG_1); + + /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ + hp100_page(PERFORMANCE); + hp100_outw(HP100_MISC_ERROR, IRQ_STATUS); + + if (val & HP100_LINK_UP_ST) + return (0); /* login was ok */ + else { + printk("hp100: Training failed.\n"); + hp100_down_vg_link(dev); + return -EIO; + } } - } - hp100_page(PERFORMANCE); + /* no forced relogin & already link there->no training. */ + return -EIO; } + + +static void hp100_cascade_reset(struct device *dev, u_short enable) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *) dev->priv; + int i; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4226, TRACE); + printk("hp100: cascade_reset\n"); #endif + if (enable == TRUE) { + hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW); + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Lassen requires a PCI transmit fifo reset */ + hp100_page(HW_MAP); + hp100_andb(~HP100_PCI_RESET, PCICTRL2); + hp100_orb(HP100_PCI_RESET, PCICTRL2); + /* Wait for min. 300 ns */ + /* we cant use jiffies here, because it may be */ + /* that we have disabled the timer... */ + for (i = 0; i < 0xffff; i++); + hp100_andb(~HP100_PCI_RESET, PCICTRL2); + hp100_page(PERFORMANCE); + } + } else { /* bring out of reset */ + hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW); + for (i = 0; i < 0xffff; i++); + hp100_page(PERFORMANCE); + } +} +#ifdef HP100_DEBUG +void hp100_RegisterDump(struct device *dev) +{ + int ioaddr = dev->base_addr; + int Page; + int Register; + + /* Dump common registers */ + printk("hp100: Cascade Register Dump\n"); + printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID)); + printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING)); + printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW)); + printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW)); + + /* Dump paged registers */ + for (Page = 0; Page < 8; Page++) { + /* Dump registers */ + printk("page: 0x%.2x\n", Page); + outw(Page, ioaddr + 0x02); + for (Register = 0x8; Register < 0x22; Register += 2) { + /* Display Register contents except data port */ + if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) { + printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register)); + } + } + } + hp100_page(PERFORMANCE); +} +#endif + + /* * module section */ - + #ifdef MODULE /* Parameters set by insmod */ -int hp100_port[5] = { 0, -1, -1, -1, -1 }; +int hp100_port[5] = +{0, -1, -1, -1, -1}; #ifdef LINUX_2_1 MODULE_PARM(hp100_port, "1-5i"); #endif #ifdef LINUX_2_1 -char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; +char hp100_name[5][IFNAMSIZ] = +{"", "", "", "", ""}; MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); #else -static char devname[5][IFNAMSIZ] = { "", "", "", "", "" }; -static char *hp100_name[5] = { devname[0], devname[1], - devname[2], devname[3], - devname[4] }; +static char devname[5][IFNAMSIZ] = +{"", "", "", "", ""}; +static char *hp100_name[5] = +{devname[0], devname[1], + devname[2], devname[3], + devname[4]}; #endif /* List of devices */ -static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; +static struct device *hp100_devlist[5] = +{NULL, NULL, NULL, NULL, NULL}; /* * Note: if you have more than five 100vg cards in your pc, feel free to @@ -2781,64 +2606,61 @@ * option hp100 hp100_port=0x280 hp100_name=eth239 */ -int init_module( void ) +int init_module(void) { - int i; - int ret = 0; + int i; + int ret = 0; - if (hp100_port == 0 && !EISA_bus && !pcibios_present()) - printk("HP100: You should not use auto-probing with insmod!\n"); + if (hp100_port == 0 && !EISA_bus && !pcibios_present()) + printk("HP100: You should not use auto-probing with insmod!\n"); - /* Loop on all possible base addresses */ - i = -1; - while((hp100_port[++i] != -1) && (i < 5)) - { - /* Create device and set basics args */ - hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); - memset(hp100_devlist[i], 0x00, sizeof(struct device)); - hp100_devlist[i]->name = hp100_name[i]; - hp100_devlist[i]->base_addr = hp100_port[i]; - hp100_devlist[i]->init = &hp100_probe; - - /* Try to create the device */ - if(register_netdev(hp100_devlist[i]) != 0) - { - /* DeAllocate everything */ - /* Note: if dev->priv is mallocated, there is no way to fail */ - kfree_s(hp100_devlist[i], sizeof(struct device)); - hp100_devlist[i] = (struct device *) NULL; - ret = -EIO; - } - } /* Loop over all devices */ - - return ret; -} - -void cleanup_module( void ) -{ - int i; - - /* TODO: Check if all skb's are released/freed. */ - for(i = 0; i < 5; i++) - if(hp100_devlist[i] != (struct device *) NULL) - { - unregister_netdev( hp100_devlist[i] ); - release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE ); - if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */ - kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f); - if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ) - iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ); - kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) ); - hp100_devlist[i]->priv = NULL; - kfree_s(hp100_devlist[i], sizeof(struct device)); - hp100_devlist[i] = (struct device *) NULL; - } + /* Loop on all possible base addresses */ + i = -1; + while ((hp100_port[++i] != -1) && (i < 5)) { + /* Create device and set basics args */ + hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); + memset(hp100_devlist[i], 0x00, sizeof(struct device)); + hp100_devlist[i]->name = hp100_name[i]; + hp100_devlist[i]->base_addr = hp100_port[i]; + hp100_devlist[i]->init = &hp100_probe; + + /* Try to create the device */ + if (register_netdev(hp100_devlist[i]) != 0) { + /* DeAllocate everything */ + /* Note: if dev->priv is mallocated, there is no way to fail */ + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + ret = -EIO; + } + } /* Loop over all devices */ + + return ret; } -#endif /* MODULE */ +void cleanup_module(void) +{ + int i; + /* TODO: Check if all skb's are released/freed. */ + for (i = 0; i < 5; i++) + if (hp100_devlist[i] != (struct device *) NULL) { + unregister_netdev(hp100_devlist[i]); + release_region(hp100_devlist[i]->base_addr, HP100_REGION_SIZE); + if (((struct hp100_private *) hp100_devlist[i]->priv)->mode == 1) /* busmaster */ + kfree_s(((struct hp100_private *) hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE + 0x0f); + if (((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt) + iounmap(((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt); + kfree_s(hp100_devlist[i]->priv, sizeof(struct hp100_private)); + hp100_devlist[i]->priv = NULL; + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + } +} +#endif /* MODULE */ + + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c" diff -u --recursive --new-file v2.1.66/linux/drivers/net/hp100.h linux/drivers/net/hp100.h --- v2.1.66/linux/drivers/net/hp100.h Sat May 24 09:10:23 1997 +++ linux/drivers/net/hp100.h Sat Nov 29 10:33:19 1997 @@ -1,7 +1,7 @@ /* * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. * - * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $ + * $Id: hp100.h,v 1.4 1997/05/26 21:09:19 davem Exp $ * * Authors: Jaroslav Kysela, * Siegfried Loeffler diff -u --recursive --new-file v2.1.66/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v2.1.66/linux/drivers/net/hydra.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/hydra.c Sat Nov 29 10:33:19 1997 @@ -87,7 +87,7 @@ u16 rx_page_stop; u16 next_pkt; struct net_device_stats stats; - int key; + unsigned int key; }; static int hydra_open(struct device *dev); @@ -161,15 +161,15 @@ { struct hydra_private *priv; u32 board; - int key; - struct ConfigDev *cd; + unsigned int key; + const struct ConfigDev *cd; int j; #ifdef HYDRA_DEBUG printk("hydra_probe(%x)\n", dev); #endif - if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) + if ((key = zorro_find(ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET, 0, 0))) { cd = zorro_get_board(key); if((board = (u32) cd->cd_BoardAddr)) @@ -206,7 +206,7 @@ return(0); } } - return(ENODEV); + return(-ENODEV); } diff -u --recursive --new-file v2.1.66/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.1.66/linux/drivers/net/ibmtr.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/ibmtr.c Sat Nov 29 10:33:19 1997 @@ -267,6 +267,7 @@ struct tok_info *ti=0; __u32 cd_chanid; unsigned char *tchanid, ctemp; + unsigned long timeout; #ifndef MODULE dev = init_trdev(dev,0); @@ -406,10 +407,14 @@ irq=10; if (intr==3) irq=11; - /* - * FIXME: this wait should have a timeout - */ - while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)); + + timeout = jiffies + TR_SPIN_INTERVAL; + while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) + if (jiffies > timeout) { + DPRINTK("Hardware timeout during initialization.\n"); + kfree_s(ti, sizeof(struct tok_info)); + return -ENODEV; + } ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12); ti->global_int_enable=PIOaddr+ADAPTINTREL; ti->adapter_int_enable=PIOaddr+ADAPTINTREL; @@ -1474,12 +1479,6 @@ DPRINTK("Arrg. Transmitter busy.\n"); dev->trans_start+=5; /* we fake the transmission start time... */ return 1; - } - - /* Donald does this, so we do too. */ - if (skb==NULL) { - dev_tint(dev); - return 0; } if (test_and_set_bit(0,(void *)&dev->tbusy)!=0) diff -u --recursive --new-file v2.1.66/linux/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h --- v2.1.66/linux/drivers/net/ibmtr.h Fri Apr 4 08:52:21 1997 +++ linux/drivers/net/ibmtr.h Sat Nov 29 10:33:19 1997 @@ -6,6 +6,7 @@ #define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */ #define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */ #define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ +#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ #define TR_ISA 1 #define TR_MCA 2 @@ -227,7 +228,7 @@ /* DIR_OPEN_ADAPTER options */ #define OPEN_PASS_BCON_MAC 0x0100 -#define NUM_RCV_BUF 3 +#define NUM_RCV_BUF 2 #define RCV_BUF_LEN 1024 #define DHB_LENGTH 2048 #define NUM_DHB 2 diff -u --recursive --new-file v2.1.66/linux/drivers/net/iow.h linux/drivers/net/iow.h --- v2.1.66/linux/drivers/net/iow.h Sun Jan 2 21:39:17 1994 +++ linux/drivers/net/iow.h Wed Dec 31 16:00:00 1969 @@ -1,6 +0,0 @@ -#ifndef _ASM_IOW_H -#define _ASM_IOW_H - -/* no longer used */ - -#endif diff -u --recursive --new-file v2.1.66/linux/drivers/net/ipddp.c linux/drivers/net/ipddp.c --- v2.1.66/linux/drivers/net/ipddp.c Tue Sep 23 16:48:48 1997 +++ linux/drivers/net/ipddp.c Sat Nov 29 10:33:19 1997 @@ -1,3 +1,5 @@ +#warning "Needs new networking merges before it will work" +#if 0 /* * ipddp.c: IP-over-DDP driver for Linux * @@ -46,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -118,7 +121,6 @@ dev->rebuild_header = ipddp_rebuild_header; dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ - dev->family = AF_INET; dev->mtu = 585; dev->flags |= IFF_NOARP; @@ -307,3 +309,4 @@ } #endif /* MODULE */ +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c --- v2.1.66/linux/drivers/net/lapbether.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/lapbether.c Sat Nov 29 10:33:19 1997 @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -109,9 +108,6 @@ return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5) -#ifdef CONFIG_NET_ALIAS - && !net_alias_is(dev) -#endif ); } @@ -468,17 +464,7 @@ dev->get_stats = lapbeth_get_stats; dev->do_ioctl = lapbeth_ioctl; - /* preset with reasonable values */ - dev->flags = 0; - dev->family = AF_INET; - -#ifdef CONFIG_INET - dev->pa_addr = in_aton("192.168.0.1"); - dev->pa_brdaddr = in_aton("192.168.0.255"); - dev->pa_mask = in_aton("255.255.255.0"); - dev->pa_alen = 4; -#endif dev->type = ARPHRD_X25; dev->hard_header_len = 3; diff -u --recursive --new-file v2.1.66/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.1.66/linux/drivers/net/loopback.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/loopback.c Sat Nov 29 10:33:19 1997 @@ -28,7 +28,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include #include #include @@ -129,14 +128,7 @@ dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ dev->rebuild_header = eth_rebuild_header; dev->open = loopback_open; - dev->flags = IFF_LOOPBACK|IFF_BROADCAST; - dev->family = AF_INET; -#ifdef CONFIG_INET - dev->pa_addr = in_aton("127.0.0.1"); - dev->pa_brdaddr = in_aton("127.255.255.255"); - dev->pa_mask = in_aton("255.0.0.0"); - dev->pa_alen = 4; -#endif + dev->flags = IFF_LOOPBACK; dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; diff -u --recursive --new-file v2.1.66/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.66/linux/drivers/net/ltpc.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/ltpc.c Sat Nov 29 10:33:19 1997 @@ -249,6 +249,12 @@ static unsigned char *ltdmabuf; static unsigned char *ltdmacbuf; +struct ltpc_private +{ + struct net_device_stats stats; + struct at_addr my_addr; +}; + struct xmitQel { struct xmitQel *next; unsigned char *cbuf; @@ -650,7 +656,7 @@ static struct timer_list ltpc_timer; static int ltpc_xmit(struct sk_buff *skb, struct device *dev); -static struct enet_statistics *ltpc_get_stats(struct device *dev); +static struct net_device_stats *ltpc_get_stats(struct device *dev); static int ltpc_open(struct device *dev) { @@ -691,7 +697,7 @@ int dnode, snode, llaptype, len; int sklen; struct sk_buff *skb; - struct net_device_stats *stats = (struct enet_statistics *)dev->priv; + struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf; if (ltc->command != LT_RCVLAP) { @@ -786,7 +792,7 @@ { struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr; /* we'll keep the localtalk node address in dev->pa_addr */ - struct at_addr *aa = (struct at_addr *) &dev->pa_addr; + struct at_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr; struct lt_init c; int ltflags; @@ -851,14 +857,14 @@ dev->hard_start_xmit = ltpc_xmit; dev->hard_header = ltpc_hard_header; - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL); if(!dev->priv) { printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name); return -ENOMEM; } - memset(dev->priv, 0, sizeof(struct net_device_stats)); + memset(dev->priv, 0, sizeof(struct ltpc_private)); dev->get_stats = ltpc_get_stats; dev->open = ltpc_open; @@ -915,7 +921,7 @@ * and skb->len is the length of the ddp data + ddp header */ - struct net_device_stats *stats = (struct enet_statistics *)dev->priv; + struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; int i; struct lt_sendlap cbuf; @@ -951,7 +957,7 @@ static struct net_device_stats *ltpc_get_stats(struct device *dev) { - struct net_device_stats *stats = (struct net_device_stats *) dev->priv; + struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats; return stats; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.1.66/linux/drivers/net/mace.c Mon Aug 18 18:19:46 1997 +++ linux/drivers/net/mace.c Sat Nov 29 10:33:19 1997 @@ -45,6 +45,7 @@ unsigned char tx_bad_runt; struct net_device_stats stats; struct timer_list tx_timeout; + int timeout_active; }; /* @@ -165,6 +166,8 @@ memset(&mp->stats, 0, sizeof(mp->stats)); memset((char *) mp->tx_cmds, 0, (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); + init_timer(&mp->tx_timeout); + mp->timeout_active = 0; mace_reset(dev); @@ -346,11 +349,18 @@ static inline void mace_set_timeout(struct device *dev) { struct mace_data *mp = (struct mace_data *) dev->priv; + unsigned long flags; + save_flags(flags); + cli(); + if (mp->timeout_active) + del_timer(&mp->tx_timeout); mp->tx_timeout.expires = jiffies + TX_TIMEOUT; mp->tx_timeout.function = mace_tx_timeout; mp->tx_timeout.data = (unsigned long) dev; add_timer(&mp->tx_timeout); + mp->timeout_active = 1; + restore_flags(flags); } static int mace_xmit_start(struct sk_buff *skb, struct device *dev) @@ -524,6 +534,7 @@ mp->tx_bad_runt = 0; mb->xmtfc = AUTO_PAD_XMIT; del_timer(&mp->tx_timeout); + mp->timeout_active = 0; continue; } dstat = ld_le32(&td->status); @@ -597,17 +608,18 @@ mace_last_fs = fs; mace_last_xcount = xcount; del_timer(&mp->tx_timeout); + mp->timeout_active = 0; } - mp->tx_empty = i; - i += mp->tx_active; - if (i >= N_TX_RING) - i -= N_TX_RING; - if (i != mp->tx_fill && mp->tx_fullup) { + if (i != mp->tx_empty && mp->tx_fullup) { mp->tx_fullup = 0; dev->tbusy = 0; mark_bh(NET_BH); } + mp->tx_empty = i; + i += mp->tx_active; + if (i >= N_TX_RING) + i -= N_TX_RING; if (!mp->tx_bad_runt && i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE) { do { /* set up the next one */ @@ -636,6 +648,7 @@ save_flags(flags); cli(); + mp->timeout_active = 0; if (mp->tx_active == 0 && !mp->tx_bad_runt) goto out; diff -u --recursive --new-file v2.1.66/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c --- v2.1.66/linux/drivers/net/mkiss.c Thu May 29 21:53:07 1997 +++ linux/drivers/net/mkiss.c Sat Nov 29 10:33:19 1997 @@ -489,9 +489,6 @@ ax->xleft = 0; ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */ - /* Needed because address '0' is special */ - if (dev->pa_addr == 0) - dev->pa_addr = ntohl(0xC0A80001); dev->tbusy = 0; dev->start = 1; @@ -632,7 +629,12 @@ return; mkiss = ax->mode; - dev_close(ax->dev); + if (ax->dev->flags & IFF_UP) + { + dev_lock_wait(); + dev_close(ax->dev); + dev_unlock_list(); + } tty->disc_data = 0; ax->tty = NULL; @@ -910,14 +912,6 @@ /* New-style flags. */ dev->flags = 0; - dev->family = AF_INET; - -#ifdef CONFIG_INET - dev->pa_addr = in_aton("192.168.0.1"); - dev->pa_brdaddr = in_aton("192.168.0.255"); - dev->pa_mask = in_aton("255.255.255.0"); - dev->pa_alen = 4; -#endif return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.66/linux/drivers/net/myri_sbus.c Thu Sep 4 17:07:30 1997 +++ linux/drivers/net/myri_sbus.c Sat Nov 29 10:33:19 1997 @@ -594,12 +594,6 @@ } } - if(skb == NULL || skb->len <= 0) { - DTX(("skb is null, aieee... returning 0\n")); - dev_tint(dev); - return 0; - } - if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { DTX(("tbusy, maybe a race? returning 1\n")); printk("%s: Transmitter access conflict.\n", dev->name); @@ -1089,7 +1083,7 @@ dev->hard_start_xmit = &myri_start_xmit; dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; - dev->irq = (unsigned char) sdev->irqs[0].pri; + dev->irq = sdev->irqs[0].pri; dev->dma = 0; /* Register interrupt handler now. */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c --- v2.1.66/linux/drivers/net/ni5010.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ni5010.c Sat Nov 29 10:33:19 1997 @@ -0,0 +1,835 @@ +/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard. + * + * Copyright 1996,1997 Jan-Pascal van Best and Andreas Mohr. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * The authors may be reached as: + * jvbest@wi.leidenuniv.nl a.mohr@mailto.de + * or by snail mail as + * Jan-Pascal van Best Andreas Mohr + * Klikspaanweg 58-4 Stauferstr. 6 + * 2324 LZ Leiden D-71272 Renningen + * The Netherlands Germany + * + * Sources: + * Donald Becker's "skeleton.c" + * Crynwr ni5010 packet driver + * + * Changes: + * v0.0: First test version + * v0.1: First working version + * v0.2: + * v0.3->v0.90: Now demand setting io and irq when loading as module + * 970430 v0.91: modified for Linux 2.1.14 + * v0.92: Implemented Andreas' (better) NI5010 probe + * 970503 v0.93: Fixed auto-irq failure on warm reboot (JB) + * 970623 v1.00: First kernel version (AM) + * 970814 v1.01: Added detection of onboard receive buffer size (AM) + * Bugs: + * - None known... + * - Note that you have to patch ifconfig for the new /proc/net/dev + * format. It gives incorrect stats otherwise. + * + * To do: + * Fix all bugs :-) + * Move some stuff to chipset_init() + * Handle xmt errors other than collisions + * Complete merge with Andreas' driver + * Implement ring buffers (Is this useful? You can't squeeze + * too many packet in a 2k buffer!) + * Implement DMA (Again, is this useful? Some docs says DMA is + * slower than programmed I/O) + * + * Compile with: + * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \ + * -DMODULE -c ni5010.c + * + * Insert with e.g.: + * insmod ni5010.o io=0x300 irq=5 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ni5010.h" + +static const char *boardname = "NI5010"; +static char *version = + "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n"; + +/* bufsize_rcv == 0 means autoprobing */ +unsigned int bufsize_rcv = 0; + +#define jumpered_interrupts /* IRQ line jumpered on board */ +#undef jumpered_dma /* No DMA used */ +#undef FULL_IODETECT /* Only detect in portlist */ + +#ifndef FULL_IODETECT +/* A zero-terminated list of I/O addresses to be probed. */ +static unsigned int ni5010_portlist[] __initdata = + { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; +#endif + +/* Use 0 for production, 1 for verification, >2 for debug */ +#ifndef NI5010_DEBUG +#define NI5010_DEBUG 0 +#endif + +/* Information that needs to be kept for each board. */ +struct ni5010_local { + struct net_device_stats stats; + int o_pkt_size; + int i_pkt_size; +}; + +/* Index to functions, as function prototypes. */ + +extern int ni5010_probe(struct device *dev); +static int ni5010_probe1(struct device *dev, int ioaddr); +static int ni5010_open(struct device *dev); +static int ni5010_send_packet(struct sk_buff *skb, struct device *dev); +static void ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void ni5010_rx(struct device *dev); +static int ni5010_close(struct device *dev); +static struct net_device_stats *ni5010_get_stats(struct device *dev); +static void ni5010_set_multicast_list(struct device *dev); +static void reset_receiver(struct device *dev); + +static int process_xmt_interrupt(struct device *dev); +#define tx_done(dev) 1 +extern void hardware_send_packet(struct device *dev, char *buf, int length); +extern void chipset_init(struct device *dev, int startp); +static void dump_packet(void *buf, int len); +static void show_registers(struct device *dev); + + +__initfunc(int ni5010_probe(struct device *dev)) +{ + int *port; + + int base_addr = dev ? dev->base_addr : 0; + + PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return ni5010_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + +#ifdef FULL_IODETECT + for (int ioaddr=0x200; ioaddr<0x400; ioaddr+=0x20) { + if (check_region(ioaddr, NI5010_IO_EXTENT)) + continue; + if (ni5010_probe1(dev, ioaddr) == 0) + return 0; + } +#else + for (port = ni5010_portlist; *port; port++) { + int ioaddr = *port; + if (check_region(ioaddr, NI5010_IO_EXTENT)) + continue; + if (ni5010_probe1(dev, ioaddr) == 0) + return 0; + } +#endif /* FULL_IODETECT */ + return -ENODEV; +} + +static inline int rd_port(int ioaddr) +{ + inb(IE_RBUF); + return inb(IE_SAPROM); +} + +__initfunc(void trigger_irq(int ioaddr)) +{ + outb(0x00, EDLC_RESET); /* Clear EDLC hold RESET state */ + outb(0x00, IE_RESET); /* Board reset */ + outb(0x00, EDLC_XMASK); /* Disable all Xmt interrupts */ + outb(0x00, EDLC_RMASK); /* Disable all Rcv interrupt */ + outb(0xff, EDLC_XCLR); /* Clear all pending Xmt interrupts */ + outb(0xff, EDLC_RCLR); /* Clear all pending Rcv interrupts */ + /* + * Transmit packet mode: Ignore parity, Power xcvr, + * Enable loopback + */ + outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE); + outb(RMD_BROADCAST, EDLC_RMODE); /* Receive normal&broadcast */ + outb(XM_ALL, EDLC_XMASK); /* Enable all Xmt interrupts */ + udelay(50); /* FIXME: Necessary? */ + outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */ +} + +/* + * 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. + */ + +__initfunc(static int ni5010_probe1(struct device *dev, int ioaddr)) +{ + static unsigned version_printed = 0; + int i; + unsigned int data; + int boguscount = 40; + + /* + * This is no "official" probe method, I've rather tested which + * probe works best with my seven NI5010 cards + * (they have very different serial numbers) + * Suggestions or failure reports are very, very welcome ! + * But I think it is a relatively good probe method + * since it doesn't use any "outb" + * It should be nearly 100% reliable ! + * well-known WARNING: this probe method (like many others) + * will hang the system if a NE2000 card region is probed ! + * + * - Andreas + */ + + PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n", + dev->name, ioaddr)); + + if (inb(ioaddr+0) == 0xff) return -ENODEV; + + while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & + rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff) + { + if (boguscount-- == 0) return -ENODEV; + } + + PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name)); + + for (i=0; i<32; i++) + if ( (data = rd_port(ioaddr)) != 0xff) break; + if (data==0xff) return -ENODEV; + + PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name)); + + if ( (data == SA_ADDR0) && + (rd_port(ioaddr) == SA_ADDR1) && + (rd_port(ioaddr) == SA_ADDR2) ) { + for (i=0; i<4; i++) rd_port(ioaddr); + if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || + (rd_port(ioaddr) != NI5010_MAGICVAL2) ) { + return -ENODEV; + } + } else return -ENODEV; + + PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name)); + + if (dev == NULL) { + dev = init_etherdev(0,0); + if (dev == NULL) { + printk(KERN_WARNING "%s: Failed to allocate device memory\n", boardname); + return -ENOMEM; + } + } + + if (NI5010_DEBUG && version_printed++ == 0) + printk(KERN_INFO "%s", version); + + printk("NI5010 ethercard probe at 0x%x: ", ioaddr); + + dev->base_addr = ioaddr; + + for (i=0; i<6; i++) { + outw(i, IE_GP); + printk("%2.2x ", dev->dev_addr[i] = inb(IE_SAPROM)); + } + + PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name)); + +#ifdef jumpered_interrupts + if (dev->irq == 0xff) + ; + else if (dev->irq < 2) { + PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name)); + + autoirq_setup(0); + trigger_irq(ioaddr); + dev->irq = autoirq_report(2); + + PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name)); + + if (dev->irq == 0) { + printk(KERN_WARNING "%s: no IRQ found!\n", dev->name); + return -EAGAIN; + } + PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name)); + } else if (dev->irq == 2) { + dev->irq = 9; + } +#endif /* jumpered_irq */ + PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); + + /* DMA is not supported (yet?), so no use detecting it */ + + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct ni5010_local), GFP_KERNEL|GFP_DMA); + if (dev->priv == NULL) { + printk(KERN_WARNING "%s: Failed to allocate private memory\n", dev->name); + return -ENOMEM; + } + } + + PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name)); + +/* get the size of the onboard receive buffer + * higher addresses than bufsize are wrapped into real buffer + * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer + */ + if (!bufsize_rcv) { + outb(1, IE_MMODE); /* Put Rcv buffer on system bus */ + outw(0, IE_GP); /* Point GP at start of packet */ + outb(0, IE_RBUF); /* set buffer byte 0 to 0 */ + for (i = 1; i < 0xff; i++) { + outw(i << 8, IE_GP); /* Point GP at packet size to be tested */ + outb(i, IE_RBUF); + outw(0x0, IE_GP); /* Point GP at start of packet */ + data = inb(IE_RBUF); + if (data == i) break; + } + bufsize_rcv = i << 8; + outw(0, IE_GP); /* Point GP at start of packet */ + outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */ + } + printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); + memset(dev->priv, 0, sizeof(struct ni5010_local)); + + /* Grab the region so we can find another board if autoIRQ fails. */ + request_region(ioaddr, NI5010_IO_EXTENT, boardname); + + dev->open = ni5010_open; + dev->stop = ni5010_close; + dev->hard_start_xmit = ni5010_send_packet; + dev->get_stats = ni5010_get_stats; + dev->set_multicast_list = &ni5010_set_multicast_list; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 0; + + dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ + + /* Shut up the ni5010 */ + outb(0, EDLC_RMASK); /* Mask all receive interrupts */ + outb(0, EDLC_XMASK); /* Mask all xmit interrupts */ + outb(0xff, EDLC_RCLR); /* Kill all pending rcv interrupts */ + outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */ + + printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq); + if (dev->dma) printk(" & DMA %d", dev->dma); + printk(".\n"); + + printk(KERN_INFO "Join the NI5010 driver development team!\n"); + printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n"); + return 0; +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ + +static int ni5010_open(struct device *dev) +{ + int ioaddr = dev->base_addr; + int i; + + PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name)); + + if (request_irq(dev->irq, &ni5010_interrupt, 0, boardname, dev)) { + printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq); + return -EAGAIN; + } + PRINTK3((KERN_DEBUG "%s: passed open() #1\n", dev->name)); + /* + * Always allocate the DMA channel after the IRQ, + * and clean up on failure. + */ +#ifdef jumpered_dma + if (request_dma(dev->dma, cardname)) { + printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma); + free_irq(dev->irq, NULL); + return -EAGAIN; + } +#endif /* jumpered_dma */ + + PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name)); + /* Reset the hardware here. Don't forget to set the station address. */ + + outb(RS_RESET, EDLC_RESET); /* Hold up EDLC_RESET while configing board */ + outb(0, IE_RESET); /* Hardware reset of ni5010 board */ + outb(XMD_LBC, EDLC_XMODE); /* Only loopback xmits */ + + PRINTK3((KERN_DEBUG "%s: passed open() #3\n", dev->name)); + /* Set the station address */ + for(i = 0;i < 6; i++) { + outb(dev->dev_addr[i], EDLC_ADDR + i); + } + + PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name)); + outb(0, EDLC_XMASK); /* No xmit interrupts for now */ + outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE); + /* Normal packet xmit mode */ + outb(0xff, EDLC_XCLR); /* Clear all pending xmit interrupts */ + outb(RMD_BROADCAST, EDLC_RMODE); + /* Receive broadcast and normal packets */ + reset_receiver(dev); /* Ready ni5010 for receiving packets */ + + outb(0, EDLC_RESET); /* Un-reset the ni5010 */ + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + if (NI5010_DEBUG) show_registers(dev); + + MOD_INC_USE_COUNT; + PRINTK((KERN_DEBUG "%s: open successful\n", dev->name)); + return 0; +} + +static void reset_receiver(struct device *dev) +{ + int ioaddr = dev->base_addr; + + PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name)); + outw(0, IE_GP); /* Receive packet at start of buffer */ + outb(0xff, EDLC_RCLR); /* Clear all pending rcv interrupts */ + outb(0, IE_MMODE); /* Put EDLC to rcv buffer */ + outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */ + outb(0xff, EDLC_RMASK); /* Enable all rcv interrupts */ +} + +static int ni5010_send_packet(struct sk_buff *skb, struct device *dev) +{ + PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name)); + if (dev->tbusy) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk("tbusy\n"); + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + /* FIXME: Give it a real kick here */ + chipset_init(dev, 1); + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but test_and_set_bit() works as well. + */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + return 1; + } else { + int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + + hardware_send_packet(dev, (unsigned char *)skb->data, length); + dev->trans_start = jiffies; + } + dev_kfree_skb (skb, FREE_WRITE); + + return 0; +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void +ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = dev_id; + struct ni5010_local *lp; + int ioaddr, status; + int xmit_was_error = 0; + + if (dev == NULL || dev->irq != irq) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", + boardname, irq); + return; + } + + if (dev->interrupt) printk(KERN_WARNING "%s: Reentering IRQ-handler!\n", dev->name); + dev->interrupt = 1; + + PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name)); + + ioaddr = dev->base_addr; + lp = (struct ni5010_local *)dev->priv; + + status = inb(IE_ISTAT); + PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status)); + + if ((status & IS_R_INT) == 0) ni5010_rx(dev); + + if ((status & IS_X_INT) == 0) { + xmit_was_error = process_xmt_interrupt(dev); + } + + if ((status & IS_DMA_INT) == 0) { + PRINTK((KERN_DEBUG "%s: DMA complete (???)\n", dev->name)); + outb(0, IE_DMA_RST); /* Reset DMA int */ + } + + if (!xmit_was_error) + reset_receiver(dev); + + dev->interrupt = 0; + return; +} + + +static void dump_packet(void *buf, int len) +{ + int i; + + printk(KERN_DEBUG "Packet length = %#4x\n", len); + for (i = 0; i < len; i++){ + if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i); + if (i % 2 == 0) printk(" "); + printk("%2.2x", ((unsigned char *)buf)[i]); + if (i % 16 == 15) printk("\n"); + } + printk("\n"); + + return; +} + +/* We have a good packet, get it out of the buffer. */ +static void +ni5010_rx(struct device *dev) +{ + struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + int ioaddr = dev->base_addr; + unsigned char rcv_stat; + struct sk_buff *skb; + + PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name)); + + rcv_stat = inb(EDLC_RSTAT); + PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat)); + + if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) { + PRINTK((KERN_INFO "%s: receive error.\n", dev->name)); + lp->stats.rx_errors++; + if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++; + if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++; + if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++; + if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++; + outb(0xff, EDLC_RCLR); /* Clear the interrupt */ + return; + } + + outb(0xff, EDLC_RCLR); /* Clear the interrupt */ + + lp->i_pkt_size = inw(IE_RCNT); + if (lp->i_pkt_size > ETH_FRAME_LEN || lp->i_pkt_size < 10 ) { + PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", + dev->name, lp->i_pkt_size)); + lp->stats.rx_errors++; + lp->stats.rx_length_errors++; + return; + } + + /* Malloc up new buffer. */ + skb = dev_alloc_skb(lp->i_pkt_size + 3); + if (skb == NULL) { + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return; + } + + skb->dev = dev; + skb_reserve(skb, 2); + + /* Read packet into buffer */ + outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ + outw(0, IE_GP); /* Seek to beginning of packet */ + insb(IE_RBUF, skb_put(skb, lp->i_pkt_size), lp->i_pkt_size); + + if (NI5010_DEBUG >= 4) + dump_packet(skb->data, skb->len); + + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes += lp->i_pkt_size; + + PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", + dev->name, lp->i_pkt_size)); + +} + +static int process_xmt_interrupt(struct device *dev) +{ + struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + int ioaddr = dev->base_addr; + int xmit_stat; + + PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name)); + + xmit_stat = inb(EDLC_XSTAT); + PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat)); + + outb(0, EDLC_XMASK); /* Disable xmit IRQ's */ + outb(0xff, EDLC_XCLR); /* Clear all pending xmit IRQ's */ + + if (xmit_stat & XS_COLL){ + printk("ether collision\n"); /* FIXME: remove */ + PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n", + dev->name)); + outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP); + /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */ + outb(MM_EN_XMT | MM_MUX, IE_MMODE); + outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */ + lp->stats.collisions++; + return 1; + } + + /* FIXME: handle other xmt error conditions */ + + lp->stats.tx_packets++; + lp->stats.tx_bytes += lp->o_pkt_size; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + + PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n", + dev->name, lp->o_pkt_size)); + + return 0; +} + +/* The inverse routine to ni5010_open(). */ +static int +ni5010_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + + PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name)); +#ifdef jumpered_interrupts + free_irq(dev->irq, NULL); +#endif + /* Put card in held-RESET state */ + outb(0, IE_MMODE); + outb(RS_RESET, EDLC_RESET); + + dev->tbusy = 1; + dev->start = 0; + + MOD_DEC_USE_COUNT; + PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname)); + return 0; + +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats * +ni5010_get_stats(struct device *dev) +{ + struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + + PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name)); + + if (NI5010_DEBUG) show_registers(dev); + + /* cli(); */ + /* Update the statistics from the device registers. */ + /* We do this in the interrupt handler */ + /* sti(); */ + + return &lp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. +*/ +static void +ni5010_set_multicast_list(struct device *dev) +{ + short ioaddr = dev->base_addr; + + PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name)); + + if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) { + dev->flags |= IFF_PROMISC; + outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */ + PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name)); + } else if (dev->mc_list) { + /* Sorry, multicast not supported */ + PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name)); + outb(RMD_BROADCAST, EDLC_RMODE); + } else { + PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name)); + outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */ + } +} + +extern void hardware_send_packet(struct device *dev, char *buf, int length) +{ + struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + unsigned int buf_offs; + + PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name)); + + if (length > ETH_FRAME_LEN) { + PRINTK((KERN_WARNING "%s: packet too large, not possible\n", + dev->name)); + return; + } + + if (NI5010_DEBUG) show_registers(dev); + + if (inb(IE_ISTAT) & IS_EN_XMT) { + PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n", + dev->name)); + return; + } + + if (NI5010_DEBUG > 3) dump_packet(buf, length); + + buf_offs = NI5010_BUFSIZE - length; + lp->o_pkt_size = length; + + save_flags(flags); + cli(); + + outb(0, EDLC_RMASK); /* Mask all receive interrupts */ + outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ + outb(0xff, EDLC_RCLR); /* Clear out pending rcv interrupts */ + + outw(buf_offs, IE_GP); /* Point GP at start of packet */ + outsb(IE_XBUF, buf, length); /* Put data in buffer */ + outw(buf_offs, IE_GP); /* Rewrite where packet starts */ + + /* should work without that outb() (Crynwr used it) */ + /*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */ + outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */ + outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */ + + restore_flags(flags); + + if (NI5010_DEBUG) show_registers(dev); +} + +extern void chipset_init(struct device *dev, int startp) +{ + /* FIXME: Move some stuff here */ + PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name)); +} + +static void show_registers(struct device *dev) +{ + int ioaddr = dev->base_addr; + + PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT))); + PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK))); + PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT))); + PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK))); + PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE))); + PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE))); + PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT))); +} + +#ifdef MODULE +static struct device dev_ni5010 = { + " ", + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, ni5010_probe }; + +int io = 0; +int irq = 0; + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); + +int init_module(void) +{ + int result; + + PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname)); + /* + if(io <= 0 || irq == 0){ + printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname); + printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname); + return -EINVAL; + } + */ + if (io <= 0){ + printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname); + } + + PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io)); + dev_ni5010.irq=irq; + dev_ni5010.base_addr=io; + if ((result = register_netdev(&dev_ni5010)) != 0) { + PRINTK((KERN_WARNING "%s: register_netdev returned %d.\n", + boardname, result)); + return -EIO; + } + return 0; +} + +void +cleanup_module(void) +{ + PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname)); + + unregister_netdev(&dev_ni5010); + + release_region(dev_ni5010.base_addr, NI5010_IO_EXTENT); + if (dev_ni5010.priv != NULL){ + kfree(dev_ni5010.priv); + dev_ni5010.priv = NULL; + } +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ni5010.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/ni5010.h linux/drivers/net/ni5010.h --- v2.1.66/linux/drivers/net/ni5010.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ni5010.h Sat Nov 29 10:33:19 1997 @@ -0,0 +1,144 @@ +/* + * Racal-Interlan ni5010 Ethernet definitions + * + * This is an extension to the Linux operating system, and is covered by the + * same Gnu Public License that covers that work. + * + * copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl) + * + * I have done a look in the following sources: + * crynwr-packet-driver by Russ Nelson + */ + +#define NI5010_BUFSIZE 2048 /* number of bytes in a buffer */ + +#define NI5010_MAGICVAL0 0x00 /* magic-values for ni5010 card */ +#define NI5010_MAGICVAL1 0x55 +#define NI5010_MAGICVAL2 0xAA + +#define SA_ADDR0 0x02 +#define SA_ADDR1 0x07 +#define SA_ADDR2 0x01 + +/* The number of low I/O ports used by the ni5010 ethercard. */ +#define NI5010_IO_EXTENT 32 + +#define PRINTK(x) if (NI5010_DEBUG) printk x +#define PRINTK2(x) if (NI5010_DEBUG>=2) printk x +#define PRINTK3(x) if (NI5010_DEBUG>=3) printk x + +/* The various IE command registers */ +#define EDLC_XSTAT (ioaddr + 0x00) /* EDLC transmit csr */ +#define EDLC_XCLR (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */ +#define EDLC_XMASK (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */ +#define EDLC_RSTAT (ioaddr + 0x02) /* EDLC receive csr */ +#define EDLC_RCLR (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */ +#define EDLC_RMASK (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */ +#define EDLC_XMODE (ioaddr + 0x04) /* EDLC transmit Mode */ +#define EDLC_RMODE (ioaddr + 0x05) /* EDLC receive Mode */ +#define EDLC_RESET (ioaddr + 0x06) /* EDLC RESET register */ +#define EDLC_TDR1 (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */ +#define EDLC_ADDR (ioaddr + 0x08) /* EDLC station address, 6 bytes */ + /* 0x0E doesn't exist for r/w */ +#define EDLC_TDR2 (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */ +#define IE_GP (ioaddr + 0x10) /* GP pointer (word register) */ + /* 0x11 is 2nd byte of GP Pointer */ +#define IE_RCNT (ioaddr + 0x10) /* Count of bytes in rcv'd packet */ + /* 0x11 is 2nd byte of "Byte Count" */ +#define IE_MMODE (ioaddr + 0x12) /* Memory Mode register */ +#define IE_DMA_RST (ioaddr + 0x13) /* IE DMA Reset. write only */ +#define IE_ISTAT (ioaddr + 0x13) /* IE Interrupt Status. read only */ +#define IE_RBUF (ioaddr + 0x14) /* IE Receive Buffer port */ +#define IE_XBUF (ioaddr + 0x15) /* IE Transmit Buffer port */ +#define IE_SAPROM (ioaddr + 0x16) /* window on station addr prom */ +#define IE_RESET (ioaddr + 0x17) /* any write causes Board Reset */ + +/* bits in EDLC_XSTAT, interrupt clear on write, status when read */ +#define XS_TPOK 0x80 /* transmit packet successful */ +#define XS_CS 0x40 /* carrier sense */ +#define XS_RCVD 0x20 /* transmitted packet received */ +#define XS_SHORT 0x10 /* transmission media is shorted */ +#define XS_UFLW 0x08 /* underflow. iff failed board */ +#define XS_COLL 0x04 /* collision occurred */ +#define XS_16COLL 0x02 /* 16th collision occurred */ +#define XS_PERR 0x01 /* parity error */ + +#define XS_CLR_UFLW 0x08 /* clear underflow */ +#define XS_CLR_COLL 0x04 /* clear collision */ +#define XS_CLR_16COLL 0x02 /* clear 16th collision */ +#define XS_CLR_PERR 0x01 /* clear parity error */ + +/* bits in EDLC_XMASK, mask/enable transmit interrupts. register is r/w */ +#define XM_TPOK 0x80 /* =1 to enable Xmt Pkt OK interrupts */ +#define XM_RCVD 0x20 /* =1 to enable Xmt Pkt Rcvd ints */ +#define XM_UFLW 0x08 /* =1 to enable Xmt Underflow ints */ +#define XM_COLL 0x04 /* =1 to enable Xmt Collision ints */ +#define XM_COLL16 0x02 /* =1 to enable Xmt 16th Coll ints */ +#define XM_PERR 0x01 /* =1 to enable Xmt Parity Error ints */ + /* note: always clear this bit */ +#define XM_ALL (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16) + +/* bits in EDLC_RSTAT, interrupt clear on write, status when read */ +#define RS_PKT_OK 0x80 /* received good packet */ +#define RS_RST_PKT 0x10 /* RESET packet received */ +#define RS_RUNT 0x08 /* Runt Pkt rcvd. Len < 64 Bytes */ +#define RS_ALIGN 0x04 /* Alignment error. not 8 bit aligned */ +#define RS_CRC_ERR 0x02 /* Bad CRC on rcvd pkt */ +#define RS_OFLW 0x01 /* overflow for rcv FIFO */ +#define RS_VALID_BITS ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW ) + /* all valid RSTAT bits */ + +#define RS_CLR_PKT_OK 0x80 /* clear rcvd packet interrupt */ +#define RS_CLR_RST_PKT 0x10 /* clear RESET packet received */ +#define RS_CLR_RUNT 0x08 /* clear Runt Pckt received */ +#define RS_CLR_ALIGN 0x04 /* clear Alignment error */ +#define RS_CLR_CRC_ERR 0x02 /* clear CRC error */ +#define RS_CLR_OFLW 0x01 /* clear rcv FIFO Overflow */ + +/* bits in EDLC_RMASK, mask/enable receive interrupts. register is r/w */ +#define RM_PKT_OK 0x80 /* =1 to enable rcvd good packet ints */ +#define RM_RST_PKT 0x10 /* =1 to enable RESET packet ints */ +#define RM_RUNT 0x08 /* =1 to enable Runt Pkt rcvd ints */ +#define RM_ALIGN 0x04 /* =1 to enable Alignment error ints */ +#define RM_CRC_ERR 0x02 /* =1 to enable Bad CRC error ints */ +#define RM_OFLW 0x01 /* =1 to enable overflow error ints */ + +/* bits in EDLC_RMODE, set Receive Packet mode. register is r/w */ +#define RMD_TEST 0x80 /* =1 for Chip testing. normally 0 */ +#define RMD_ADD_SIZ 0x10 /* =1 5-byte addr match. normally 0 */ +#define RMD_EN_RUNT 0x08 /* =1 enable runt rcv. normally 0 */ +#define RMD_EN_RST 0x04 /* =1 to rcv RESET pkt. normally 0 */ + +#define RMD_PROMISC 0x03 /* receive *all* packets. unusual */ +#define RMD_MULTICAST 0x02 /* receive multicasts too. unusual */ +#define RMD_BROADCAST 0x01 /* receive broadcasts & normal. usual */ +#define RMD_NO_PACKETS 0x00 /* don't receive any packets. unusual */ + +/* bits in EDLC_XMODE, set Transmit Packet mode. register is r/w */ +#define XMD_COLL_CNT 0xf0 /* coll's since success. read-only */ +#define XMD_IG_PAR 0x08 /* =1 to ignore parity. ALWAYS set */ +#define XMD_T_MODE 0x04 /* =1 to power xcvr. ALWAYS set this */ +#define XMD_LBC 0x02 /* =1 for loopbakc. normally set */ +#define XMD_DIS_C 0x01 /* =1 disables contention. normally 0 */ + +/* bits in EDLC_RESET, write only */ +#define RS_RESET 0x80 /* =1 to hold EDLC in reset state */ + +/* bits in IE_MMODE, write only */ +#define MM_EN_DMA 0x80 /* =1 begin DMA xfer, Cplt clrs it */ +#define MM_EN_RCV 0x40 /* =1 allows Pkt rcv. clr'd by rcv */ +#define MM_EN_XMT 0x20 /* =1 begin Xmt pkt. Cplt clrs it */ +#define MM_BUS_PAGE 0x18 /* =00 ALWAYS. Used when MUX=1 */ +#define MM_NET_PAGE 0x06 /* =00 ALWAYS. Used when MUX=0 */ +#define MM_MUX 0x01 /* =1 means Rcv Buff on system bus */ + /* =0 means Xmt Buff on system bus */ + +/* bits in IE_ISTAT, read only */ +#define IS_TDIAG 0x80 /* =1 if Diagnostic problem */ +#define IS_EN_RCV 0x20 /* =1 until frame is rcv'd cplt */ +#define IS_EN_XMT 0x10 /* =1 until frame is xmt'd cplt */ +#define IS_EN_DMA 0x08 /* =1 until DMA is cplt or aborted */ +#define IS_DMA_INT 0x04 /* =0 iff DMA done interrupt. */ +#define IS_R_INT 0x02 /* =0 iff unmasked Rcv interrupt */ +#define IS_X_INT 0x01 /* =0 iff unmasked Xmt interrupt */ + diff -u --recursive --new-file v2.1.66/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.1.66/linux/drivers/net/ni52.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/ni52.c Sat Nov 29 10:33:19 1997 @@ -1155,14 +1155,6 @@ return 0; } - if(skb == NULL) - { - dev_tint(dev); - return 0; - } - - if (skb->len <= 0) - return 0; if(skb->len > XMIT_BUFF_SIZE) { printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); diff -u --recursive --new-file v2.1.66/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.1.66/linux/drivers/net/pcnet32.c Tue May 13 22:41:09 1997 +++ linux/drivers/net/pcnet32.c Sat Nov 29 10:33:19 1997 @@ -577,14 +577,6 @@ return 0; } - if (skb == NULL) { - dev_tint(dev); - return 0; - } - - if (skb->len <= 0) - return 0; - if (pcnet32_debug > 3) { outw(0x0000, ioaddr+PCNET32_ADDR); printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, diff -u --recursive --new-file v2.1.66/linux/drivers/net/pi2.c linux/drivers/net/pi2.c --- v2.1.66/linux/drivers/net/pi2.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/pi2.c Sat Nov 29 10:33:19 1997 @@ -1413,12 +1413,6 @@ /* New-style flags. */ dev->flags = 0; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; - return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.66/linux/drivers/net/plip.c Sat Oct 25 02:44:16 1997 +++ linux/drivers/net/plip.c Sat Nov 29 10:33:19 1997 @@ -1,3 +1,5 @@ +#warning This wont work until we merge the networking changes +#if 0 /* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ */ /* PLIP: A parallel port "network" driver for Linux. */ /* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */ @@ -99,6 +101,7 @@ #include #include +#include #include #include @@ -258,6 +261,7 @@ dev->do_ioctl = plip_ioctl; dev->tx_queue_len = 10; dev->flags = IFF_POINTOPOINT|IFF_NOARP; + memset(dev->dev_addr, 0xfc, ETH_ALEN); /* Set the private structure */ dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL); @@ -857,32 +861,12 @@ struct device *dev = skb->dev; struct net_local *nl = (struct net_local *)dev->priv; struct ethhdr *eth = (struct ethhdr *)skb->data; - int i; if ((dev->flags & IFF_NOARP)==0) return nl->orig_rebuild_header(skb); - if (eth->h_proto != __constant_htons(ETH_P_IP) -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - && eth->h_proto != __constant_htons(ETH_P_IPV6) -#endif - ) { - printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - return 0; - } - - for (i=0; i < ETH_ALEN - sizeof(u32); i++) - eth->h_dest[i] = 0xfc; -#if 0 - *(u32 *)(eth->h_dest+i) = dst; -#else - /* Do not want to include net/route.h here. - * In any case, it is TOP of silliness to emulate - * hardware addresses on PtP link. --ANK - */ - *(u32 *)(eth->h_dest+i) = 0; -#endif + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + memcpy(eth->h_dest, dev->broadcast, dev->addr_len); return 0; } @@ -902,14 +886,6 @@ nl->port_owner = 1; } - /* If some higher layer thinks we've missed an tx-done interrupt - we are passed NULL. Caution: dev_tint() handles the cli()/sti() - itself. */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; @@ -950,7 +926,7 @@ plip_open(struct device *dev) { struct net_local *nl = (struct net_local *)dev->priv; - int i; + struct in_device *in_dev; /* Grab the port */ if (!nl->port_owner) { @@ -973,11 +949,23 @@ nl->is_deferred = 0; /* Fill in the MAC-level header. */ - for (i=0; i < ETH_ALEN - sizeof(u32); i++) - dev->dev_addr[i] = 0xfc; - /* Ugh, this is like death. */ - *(u32 *)(dev->dev_addr+i) = dev->pa_addr; + memset(dev->dev_addr, 0xfc, ETH_ALEN); + + /* Now PLIP doesnt have a real mac addr which is a pain.. + we need to create one, and to be DOS compatible its a good + idea to use the same rules. Layering purists please look away */ + + if((in_dev=dev->ip_ptr)!=NULL) + { + /* + * Any address wil do - we take the first + */ + struct in_ifaddr *ifa=in_dev->ifa_list; + if(ifa!=NULL) + memcpy(dev->dev_addr+2,&ifa->ifa_local,4); + } + dev->interrupt = 0; dev->start = 1; dev->tbusy = 0; @@ -1117,7 +1105,7 @@ return 0; } -static int parport[PLIP_MAX] = { -1, }; +static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 }; static int timid = 0; MODULE_PARM(parport, "1-" __MODULE_STRING(PLIP_MAX) "i"); @@ -1250,3 +1238,4 @@ * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c" * End: */ +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.66/linux/drivers/net/ppp.c Sat Oct 25 02:44:16 1997 +++ linux/drivers/net/ppp.c Sat Nov 29 10:33:20 1997 @@ -405,11 +405,6 @@ /* New-style flags */ dev->flags = IFF_POINTOPOINT; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; /* sizeof (__u32) */ return 0; } @@ -687,9 +682,9 @@ if (tty != NULL && tty->disc_data == ppp) tty->disc_data = NULL; /* Break the tty->ppp link */ + /* Strong layering violation. */ if (dev && dev->flags & IFF_UP) { dev_close (dev); /* close the device properly */ - dev->flags = 0; /* prevent recursion */ } ppp_free_buf (ppp->rbuf); @@ -2401,7 +2396,7 @@ sizeof (struct ppp_idle)); if (error == 0) { struct ppp_idle cur_ddinfo; - __u32 cur_jiffies = jiffies; + unsigned long cur_jiffies = jiffies; /* change absolute times to relative times. */ cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ; @@ -2622,9 +2617,6 @@ { struct ppp *ppp = dev2ppp (dev); - /* reset POINTOPOINT every time, since dev_close zaps it! */ - dev->flags |= IFF_POINTOPOINT; - if (ppp2tty (ppp) == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR @@ -3019,12 +3011,16 @@ printk (KERN_WARNING "ppp_dev_xmit: null packet!\n"); return 0; } + /* * Avoid timing problem should tty hangup while data is queued to be sent */ if (!ppp->inuse) { dev_kfree_skb (skb, FREE_WRITE); + printk("I am dying to know, are you still alive?\n"); +#ifdef main_got_it_is_something dev_close (dev); +#endif return 0; } /* diff -u --recursive --new-file v2.1.66/linux/drivers/net/ppp_deflate.c linux/drivers/net/ppp_deflate.c --- v2.1.66/linux/drivers/net/ppp_deflate.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ppp_deflate.c Sat Nov 29 10:33:20 1997 @@ -0,0 +1,660 @@ +/* + * ==FILEVERSION 971001== + * + * ppp_deflate.c - interface the zlib procedures for Deflate compression + * and decompression (as used by gzip) to the PPP code. + * This version is for use with Linux kernel 1.3.X. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* to get the struct task_struct */ +#include /* used in new tty drivers */ +#include /* used in new tty drivers */ + +#include + +#include +#include +#include +#include + +#include + +#undef PACKETPTR +#define PACKETPTR 1 +#include +#undef PACKETPTR + +#include "zlib.c" + +/* + * State for a Deflate (de)compressor. + */ +struct ppp_deflate_state { + int seqno; + int w_size; + int unit; + int mru; + int debug; + z_stream strm; + struct compstat stats; +}; + +#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ + +static void *zalloc __P((void *, unsigned int items, unsigned int size)); +static void *zalloc_init __P((void *, unsigned int items, + unsigned int size)); +static void zfree __P((void *, void *ptr)); +static void *z_comp_alloc __P((unsigned char *options, int opt_len)); +static void *z_decomp_alloc __P((unsigned char *options, int opt_len)); +static void z_comp_free __P((void *state)); +static void z_decomp_free __P((void *state)); +static int z_comp_init __P((void *state, unsigned char *options, + int opt_len, + int unit, int hdrlen, int debug)); +static int z_decomp_init __P((void *state, unsigned char *options, + int opt_len, + int unit, int hdrlen, int mru, int debug)); +static int z_compress __P((void *state, unsigned char *rptr, + unsigned char *obuf, + int isize, int osize)); +static void z_incomp __P((void *state, unsigned char *ibuf, int icnt)); +static int z_decompress __P((void *state, unsigned char *ibuf, + int isize, unsigned char *obuf, int osize)); +static void z_comp_reset __P((void *state)); +static void z_decomp_reset __P((void *state)); +static void z_comp_stats __P((void *state, struct compstat *stats)); + +struct chunk_header { + int valloced; /* allocated with valloc, not kmalloc */ + int guard; /* check for overwritten header */ +}; + +#define GUARD_MAGIC 0x77a8011a +#define MIN_VMALLOC 2048 /* use kmalloc for blocks < this */ + +/* + * Space allocation and freeing routines for use by zlib routines. + */ +void +zfree(arg, ptr) + void *arg; + void *ptr; +{ + struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1; + + if (hdr->guard != GUARD_MAGIC) { + printk(KERN_WARNING "zfree: header corrupted (%x %x) at %p\n", + hdr->valloced, hdr->guard, hdr); + return; + } + if (hdr->valloced) + vfree(hdr); + else + kfree(hdr); +} + +void * +zalloc(arg, items, size) + void *arg; + unsigned int items, size; +{ + struct chunk_header *hdr; + unsigned nbytes; + + nbytes = items * size + sizeof(*hdr); + hdr = kmalloc(nbytes, GFP_ATOMIC); + if (hdr == 0) + return 0; + hdr->valloced = 0; + hdr->guard = GUARD_MAGIC; + return (void *) (hdr + 1); +} + +void * +zalloc_init(arg, items, size) + void *arg; + unsigned int items, size; +{ + struct chunk_header *hdr; + unsigned nbytes; + + nbytes = items * size + sizeof(*hdr); + if (nbytes >= MIN_VMALLOC) + hdr = vmalloc(nbytes); + else + hdr = kmalloc(nbytes, GFP_KERNEL); + if (hdr == 0) + return 0; + hdr->valloced = nbytes >= MIN_VMALLOC; + hdr->guard = GUARD_MAGIC; + return (void *) (hdr + 1); +} + +static void +z_comp_free(arg) + void *arg; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + if (state) { + deflateEnd(&state->strm); + kfree(state); + MOD_DEC_USE_COUNT; + } +} + +/* + * Allocate space for a compressor. + */ +static void * +z_comp_alloc(options, opt_len) + unsigned char *options; + int opt_len; +{ + struct ppp_deflate_state *state; + int w_size; + + if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE + || options[1] != CILEN_DEFLATE + || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL + || options[3] != DEFLATE_CHK_SEQUENCE) + return NULL; + w_size = DEFLATE_SIZE(options[2]); + if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) + return NULL; + + state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return NULL; + + MOD_INC_USE_COUNT; + memset (state, 0, sizeof (struct ppp_deflate_state)); + state->strm.next_in = NULL; + state->strm.zalloc = zalloc_init; + state->strm.zfree = zfree; + state->w_size = w_size; + + if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, + DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) + != Z_OK) { + z_comp_free(state); + return NULL; + } + + state->strm.zalloc = zalloc; + return (void *) state; +} + +static int +z_comp_init(arg, options, opt_len, unit, hdrlen, debug) + void *arg; + unsigned char *options; + int opt_len, unit, hdrlen, debug; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE + || options[1] != CILEN_DEFLATE + || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL + || DEFLATE_SIZE(options[2]) != state->w_size + || options[3] != DEFLATE_CHK_SEQUENCE) + return 0; + + state->seqno = 0; + state->unit = unit; + state->debug = debug; + + deflateReset(&state->strm); + + return 1; +} + +static void +z_comp_reset(arg) + void *arg; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + state->seqno = 0; + deflateReset(&state->strm); +} + +int +z_compress(arg, rptr, obuf, isize, osize) + void *arg; + unsigned char *rptr; /* uncompressed packet (in) */ + unsigned char *obuf; /* compressed packet (out) */ + int isize, osize; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + int r, proto, off, olen; + unsigned char *wptr; + + /* + * Check that the protocol is in the range we handle. + */ + proto = PPP_PROTOCOL(rptr); + if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) + return 0; + + /* Don't generate compressed packets which are larger than + the uncompressed packet. */ + if (osize > isize) + osize = isize; + + wptr = obuf; + + /* + * Copy over the PPP header and store the 2-byte sequence number. + */ + wptr[0] = PPP_ADDRESS(rptr); + wptr[1] = PPP_CONTROL(rptr); + wptr[2] = PPP_COMP >> 8; + wptr[3] = PPP_COMP; + wptr += PPP_HDRLEN; + wptr[0] = state->seqno >> 8; + wptr[1] = state->seqno; + wptr += 2; + state->strm.next_out = wptr; + state->strm.avail_out = osize - (PPP_HDRLEN + 2); + ++state->seqno; + + off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */ + rptr += off; + state->strm.next_in = rptr; + state->strm.avail_in = (isize - off); + + olen = 0; + for (;;) { + r = deflate(&state->strm, Z_PACKET_FLUSH); + if (r != Z_OK) { + if (state->debug) + printk(KERN_DEBUG "z_compress: deflate returned %d (%s)\n", + r, (state->strm.msg? state->strm.msg: "")); + break; + } + if (state->strm.avail_out == 0) { + olen += osize; + state->strm.next_out = NULL; + state->strm.avail_out = 1000000; + } else { + break; /* all done */ + } + } + if (olen < osize) + olen += osize - state->strm.avail_out; + + /* + * See if we managed to reduce the size of the packet. + */ + if (olen < isize) { + state->stats.comp_bytes += olen; + state->stats.comp_packets++; + } else { + state->stats.inc_bytes += isize; + state->stats.inc_packets++; + olen = 0; + } + state->stats.unc_bytes += isize; + state->stats.unc_packets++; + + return olen; +} + +static void +z_comp_stats(arg, stats) + void *arg; + struct compstat *stats; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + *stats = state->stats; +} + +static void +z_decomp_free(arg) + void *arg; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + if (state) { + inflateEnd(&state->strm); + kfree(state); + MOD_DEC_USE_COUNT; + } +} + +/* + * Allocate space for a decompressor. + */ +static void * +z_decomp_alloc(options, opt_len) + unsigned char *options; + int opt_len; +{ + struct ppp_deflate_state *state; + int w_size; + + if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE + || options[1] != CILEN_DEFLATE + || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL + || options[3] != DEFLATE_CHK_SEQUENCE) + return NULL; + w_size = DEFLATE_SIZE(options[2]); + if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) + return NULL; + + state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return NULL; + + MOD_INC_USE_COUNT; + memset (state, 0, sizeof (struct ppp_deflate_state)); + state->w_size = w_size; + state->strm.next_out = NULL; + state->strm.zalloc = zalloc_init; + state->strm.zfree = zfree; + + if (inflateInit2(&state->strm, -w_size) != Z_OK) { + z_decomp_free(state); + return NULL; + } + + state->strm.zalloc = zalloc; + return (void *) state; +} + +static int +z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) + void *arg; + unsigned char *options; + int opt_len, unit, hdrlen, mru, debug; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE + || options[1] != CILEN_DEFLATE + || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL + || DEFLATE_SIZE(options[2]) != state->w_size + || options[3] != DEFLATE_CHK_SEQUENCE) + return 0; + + state->seqno = 0; + state->unit = unit; + state->debug = debug; + state->mru = mru; + + inflateReset(&state->strm); + + return 1; +} + +static void +z_decomp_reset(arg) + void *arg; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + state->seqno = 0; + inflateReset(&state->strm); +} + +/* + * Decompress a Deflate-compressed packet. + * + * Because of patent problems, we return DECOMP_ERROR for errors + * found by inspecting the input data and for system problems, but + * DECOMP_FATALERROR for any errors which could possibly be said to + * be being detected "after" decompression. For DECOMP_ERROR, + * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be + * infringing a patent of Motorola's if we do, so we take CCP down + * instead. + * + * Given that the frame has the correct sequence number and a good FCS, + * errors such as invalid codes in the input most likely indicate a + * bug, so we return DECOMP_FATALERROR for them in order to turn off + * compression, even though they are detected by inspecting the input. + */ +int +z_decompress(arg, ibuf, isize, obuf, osize) + void *arg; + unsigned char *ibuf; + int isize; + unsigned char *obuf; + int osize; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + int olen, seq, r; + int decode_proto, overflow; + unsigned char overflow_buf[1]; + + if (isize <= PPP_HDRLEN + DEFLATE_OVHD) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n", + state->unit, isize); + return DECOMP_ERROR; + } + + /* Check the sequence number. */ + seq = (ibuf[PPP_HDRLEN] << 8) + ibuf[PPP_HDRLEN+1]; + if (seq != state->seqno) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n", + state->unit, seq, state->seqno); + return DECOMP_ERROR; + } + ++state->seqno; + + /* + * Fill in the first part of the PPP header. The protocol field + * comes from the decompressed data. + */ + obuf[0] = PPP_ADDRESS(ibuf); + obuf[1] = PPP_CONTROL(ibuf); + obuf[2] = 0; + + /* + * Set up to call inflate. We set avail_out to 1 initially so we can + * look at the first byte of the output and decide whether we have + * a 1-byte or 2-byte protocol field. + */ + state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD; + state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD); + state->strm.next_out = obuf + 3; + state->strm.avail_out = 1; + decode_proto = 1; + overflow = 0; + + /* + * Call inflate, supplying more input or output as needed. + */ + for (;;) { + r = inflate(&state->strm, Z_PACKET_FLUSH); + if (r != Z_OK) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n", + state->unit, r, (state->strm.msg? state->strm.msg: "")); + return DECOMP_FATALERROR; + } + if (state->strm.avail_out != 0) + break; /* all done */ + if (decode_proto) { + state->strm.avail_out = osize - PPP_HDRLEN; + if ((obuf[3] & 1) == 0) { + /* 2-byte protocol field */ + obuf[2] = obuf[3]; + --state->strm.next_out; + ++state->strm.avail_out; + } + decode_proto = 0; + } else if (!overflow) { + /* + * We've filled up the output buffer; the only way to + * find out whether inflate has any more characters + * left is to give it another byte of output space. + */ + state->strm.next_out = overflow_buf; + state->strm.avail_out = 1; + overflow = 1; + } else { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: ran out of mru\n", + state->unit); + return DECOMP_FATALERROR; + } + } + + if (decode_proto) + return DECOMP_ERROR; + + olen = osize + overflow - state->strm.avail_out; + state->stats.unc_bytes += olen; + state->stats.unc_packets++; + state->stats.comp_bytes += isize; + state->stats.comp_packets++; + + return olen; +} + +/* + * Incompressible data has arrived - add it to the history. + */ +static void +z_incomp(arg, ibuf, icnt) + void *arg; + unsigned char *ibuf; + int icnt; +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + int proto, r; + + /* + * Check that the protocol is one we handle. + */ + proto = PPP_PROTOCOL(ibuf); + if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) + return; + + ++state->seqno; + + /* + * We start at the either the 1st or 2nd byte of the protocol field, + * depending on whether the protocol value is compressible. + */ + state->strm.next_in = ibuf + 3; + state->strm.avail_in = icnt - 3; + if (proto > 0xff) { + --state->strm.next_in; + ++state->strm.avail_in; + } + + r = inflateIncomp(&state->strm); + if (r != Z_OK) { + /* gak! */ + if (state->debug) { + printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n", + state->unit, r, (state->strm.msg? state->strm.msg: "")); + } + return; + } + + /* + * Update stats. + */ + state->stats.inc_bytes += icnt; + state->stats.inc_packets++; + state->stats.unc_bytes += icnt; + state->stats.unc_packets++; +} + +/************************************************************* + * Module interface table + *************************************************************/ + +/* These are in ppp.c */ +extern int ppp_register_compressor (struct compressor *cp); +extern void ppp_unregister_compressor (struct compressor *cp); + +/* + * Procedures exported to if_ppp.c. + */ +struct compressor ppp_deflate = { + CI_DEFLATE, /* compress_proto */ + z_comp_alloc, /* comp_alloc */ + z_comp_free, /* comp_free */ + z_comp_init, /* comp_init */ + z_comp_reset, /* comp_reset */ + z_compress, /* compress */ + z_comp_stats, /* comp_stat */ + z_decomp_alloc, /* decomp_alloc */ + z_decomp_free, /* decomp_free */ + z_decomp_init, /* decomp_init */ + z_decomp_reset, /* decomp_reset */ + z_decompress, /* decompress */ + z_incomp, /* incomp */ + z_comp_stats, /* decomp_stat */ +}; + +#ifdef MODULE +/************************************************************* + * Module support routines + *************************************************************/ + +int +init_module(void) +{ + int answer = ppp_register_compressor (&ppp_deflate); + if (answer == 0) + printk (KERN_INFO + "PPP Deflate Compression module registered\n"); + return answer; +} + +void +cleanup_module(void) +{ + if (MOD_IN_USE) + printk (KERN_INFO + "Deflate Compression module busy, remove delayed\n"); + else + ppp_unregister_compressor (&ppp_deflate); +} +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/net/pt.c linux/drivers/net/pt.c --- v2.1.66/linux/drivers/net/pt.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/pt.c Sat Nov 29 10:33:20 1997 @@ -484,7 +484,7 @@ { 0x230, 0x240, 0x250, 0x260, 0x270, 0x280, 0x290, 0x2a0, 0x2b0, 0x300, 0x330, 0x3f0, 0}; - printk(KERN_INFO "PT: 0.41 ALPHA 07 October 1995 Craig Small (vk2xlz@vk2xlz.ampr.org)\n"); + printk(KERN_INFO "PT: 0.41 ALPHA 07 October 1995 Craig Small (csmall@small.dropbear.id.au)\n"); for (port = &ports[0]; *port && !card_type; port++) { ioaddr = *port; @@ -866,11 +866,6 @@ /* New style flags */ dev->flags = 0; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); return 0; } /* pt_probe() */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c --- v2.1.66/linux/drivers/net/ptifddi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ptifddi.c Sat Nov 29 10:33:20 1997 @@ -0,0 +1,268 @@ +/* $Id: ptifddi.c,v 1.5 1997/04/16 10:27:27 jj Exp $ + * ptifddi.c: Network driver for Performance Technologies single-attach + * and dual-attach FDDI sbus cards. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +static char *version = + "ptifddi.c:v1.0 10/Dec/96 David S. Miller (davem@caipfs.rutgers.edu)\n"; + +#include + +#include "ptifddi.h" + +#include "ptifddi_asm.h" + +#ifdef MODULE +static struct ptifddi *root_pti_dev = NULL; +#endif + +static inline void pti_reset(struct ptifddi *pp) +{ + pp->reset = 1; +} + +static inline void pti_unreset(struct ptifddi *pp) +{ + pp->unreset = 1; +} + +static inline void pti_load_code_base(struct dfddi_ram *rp, unsigned short addr) +{ + rp->loader_addr = ((addr << 8) & 0xff00) | ((addr >> 8) & 0x00ff); +} + +static inline void pti_clear_dpram(struct ptifddi *pp) +{ + memset(pp->dpram, 0, DPRAM_SIZE); +} + +#define CARD_TEST_TIMEOUT 100000 + +static inline int pti_card_test(struct ptifddi *pp) +{ + struct dfddi_ram *rp = pp->dpram; + unsigned char *code = &rp->loader; + unsigned char *status = (unsigned char *) rp; + int clicks = CARD_TEST_TIMEOUT; + + /* Clear it out. */ + pti_clear_dpram(pp); + + /* Load test data. */ + for(i = 0; i < test_firmware_size; i++) + code[i] = test_firmware[i]; + + /* Tell card where to execute the code. */ + pti_load_code_base(pp, test_firmware_dev_addr); + + /* Clear test run status in dpram. */ + *status = 0; + + /* Reset single attach state machine before the test. */ + rp->reset = 1; + + /* Unreset, to get the test code running. */ + pti_unreset(pp); + + /* Wait for dpram status to become 5, else fail if we time out. */ + while(--clicks) { + if(*status == 5) { + pti_reset(pp); + return 0; + } + udelay(20); + } + return 1; +} + +static inline void pti_init_firmware_loader(struct ptifddi *pp) +{ + struct dfddi_ram *rp = pp->dpram; + int i; + + for(i = 0; i < firmware_loader_size; i++) + rp->loader.loader_firmware[i] = firmware_loader[i]; +} + +static inline void pti_load_main_firmware(struct ptifddi *pp) +{ + struct dfddi_ram *rp = pp->dpram; + struct dpram_loader *lp = &rp.loader; + int i; + + +} + +static void pti_init_rings(struct ptifddi *pp, int from_irq) +{ +} + +static int pti_init(struct ptifddi *pp, int from_irq) +{ +} + +static void pti_is_not_so_happy(struct ptifddi *pp) +{ +} + +static inline void pti_tx(struct ptifddi *pp, struct device *dev) +{ +} + +static inline void myri_rx(struct ptifddi *pp, struct device *dev) +{ +} + +static void pti_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct ptifddi *pp = (struct ptifddi *) dev->priv; + +} + +static int pti_open(struct device *dev) +{ + struct ptifddi *pp = (struct ptifddi *) dev->priv; + + return pti_init(pp, in_interrupt()); +} + +static int pti_close(struct device *dev) +{ + struct ptifddi *pp = (struct ptifddi *) dev->priv; + + return 0; +} + +static int pti_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct ptifddi *pp = (struct ptifddi *) dev->priv; +} + +static struct enet_statistics *pti_get_stats(struct device *dev) +{ return &(((struct ptifddi *)dev->priv)->enet_stats); } + +static void pti_set_multicast(struct device *dev) +{ +} + +static inline int pti_fddi_init(struct device *dev, struct linux_sbus_device *sdev, int num) +{ + static unsigned version_printed = 0; + struct ptifddi *pp; + int i; + + dev = init_fddidev(0, sizeof(struct ptifddi)); + + if(version_printed++ == 0) + printk(version); + + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); + + /* Register 0 mapping contains DPRAM. */ + pp->dpram = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + sdev->reg_addrs[0].reg_size, + "PTI FDDI DPRAM", + sdev->reg_addrs[0].which_io, 0); + if(!pp->dpram) { + printk("ptiFDDI: Cannot map DPRAM I/O area.\n"); + return ENODEV; + } + + /* Next, register 1 contains reset byte. */ + pp->reset = sparc_alloc_io(sdev->reg_addrs[1].phys_addr, 0, + sdev->reg_addrs[1].reg_size, + "PTI FDDI RESET Byte", + sdev->reg_addrs[1].which_io, 0); + if(!pp->reset) { + printk("ptiFDDI: Cannot map RESET byte.\n"); + return ENODEV; + } + + /* Register 2 contains unreset byte. */ + pp->unreset = sparc_alloc_io(sdev->reg_addrs[2].phys_addr, 0, + sdev->reg_addrs[2].reg_size, + "PTI FDDI UNRESET Byte", + sdev->reg_addrs[2].which_io, 0); + if(!pp->unreset) { + printk("ptiFDDI: Cannot map UNRESET byte.\n"); + return ENODEV; + } + + /* Reset the card. */ + pti_reset(pp); + + /* Run boot-up card tests. */ + i = pti_card_test(pp); + if(i) { + printk("ptiFDDI: Bootup card test fails.\n"); + return ENODEV; + } + + /* Clear DPRAM, start afresh. */ + pti_clear_dpram(pp); + + /* Init the firmware loader. */ + pti_init_firmware_loader(pp); + + /* Now load main card FDDI firmware, using the loader. */ + pti_load_main_firmware(pp); +} + +__initfunc(int ptifddi_sbus_probe(struct device *dev)) +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev = 0; + static int called = 0; + int cards = 0, v; + + if(called) + return ENODEV; + called++; + + for_each_sbus(bus) { + for_each_sbusdev(sdev, bus) { + if(cards) dev = NULL; + if(!strcmp(sdev->prom_name, "PTI,sbs600") || + !strcmp(sdev->prom_name, "DPV,fddid")) { + cards++; + DET(("Found PTI FDDI as %s\n", sdev->prom_name)); + if((v = pti_fddi_init(dev, sdev, (cards - 1)))) + return v; + } + } + } + if(!cards) + return ENODEV; + return 0; +} + + +#ifdef MODULE + +int +init_module(void) +{ + root_pti_dev = NULL; + return ptifddi_sbus_probe(NULL); +} + +void +cleanup_module(void) +{ + struct ptifddi *pp; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_pti_dev) { + pp = root_pti_dev->next_module; + + unregister_netdev(root_pti_dev->dev); + kfree(root_pti_dev->dev); + root_pti_dev = mp; + } +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/ptifddi.h linux/drivers/net/ptifddi.h --- v2.1.66/linux/drivers/net/ptifddi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ptifddi.h Sat Nov 29 10:33:20 1997 @@ -0,0 +1,77 @@ +/* $Id: ptifddi.h,v 1.2 1996/12/16 06:15:15 davem Exp $ + * ptifddi.c: Defines for Performance Technologies FDDI sbus cards. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _PTIFDDI_H +#define _PTIFDDI_H + +struct dpram_loader { + volatile unsigned char dpram_stat; + volatile unsigned char _unused; + volatile unsigned char addr_low; + volatile unsigned char addr_hi; + volatile unsigned char num_bytes; + volatile unsigned char data[0x3b]; + + volatile unsigned char loader_firmware[0xc0]; +}; + +struct dfddi_ram { +/*0x000*/ unsigned char _unused0[0x100]; +/*0x100*/ struct dpram_loader loader; +/*0x200*/ unsigned char instructions[0x400]; +/*0x600*/ unsigned char msg_in[0x20]; +/*0x620*/ unsigned char msg_out[0x20]; +/*0x640*/ unsigned char _unused2[0x50]; +/*0x690*/ unsigned char smsg_in[0x20]; +/*0x6b0*/ unsigned char _unused3[0x30]; +/*0x6e0*/ unsigned char beacom_frame[0x20]; +/*0x700*/ unsigned char re_sync; +/*0x701*/ unsigned char _unused4; +/*0x702*/ unsigned short tswitch; +/*0x704*/ unsigned char evq_lost; +/*0x705*/ unsigned char _unused6; +/*0x706*/ unsigned char signal_lost; +/*0x707*/ unsigned char _unused7; +/*0x708*/ unsigned char lerror; +/*0x709*/ unsigned char _unused8; +/*0x70a*/ unsigned char rstate; +/*0x70b*/ unsigned char _unused9[0x13]; +/*0x716*/ unsigned short dswitch; +/*0x718*/ unsigned char _unused10[0x48]; +/*0x750*/ unsigned char cbusy; +/*0x751*/ unsigned char hbusy; +/*0x752*/ unsigned short istat; +/*0x754*/ unsigned char _unused11[]; +/*0x756*/ unsigned char disable; +/*0x757*/ unsigned char _unused12[]; +/*0x78e*/ unsigned char ucvalid; +/*0x78f*/ unsigned char _unused13; +/*0x790*/ unsigned int u0addr; +/*0x794*/ unsigned char _unused14[]; +/*0x7a8*/ unsigned int P_player; +/*0x7ac*/ unsigned int Q_player; +/*0x7b0*/ unsigned int macsi; +/*0x7b4*/ unsigned char _unused15[]; +/*0x7be*/ unsigned short reset; +/*0x7c0*/ unsigned char _unused16[]; +/*0x7fc*/ unsigned short iack; +/*0x7fe*/ unsigned short loader_addr; +}; + +#define DPRAM_SIZE 0x800 + +#define DPRAM_STAT_VALID 0x80 +#define DPRAM_STAT_EMPTY 0x00 + +struct ptifddi { + struct dfddi_ram *dpram; + unsigned char *reset; + unsigned char *unreset; + struct device *dev; + struct ptifddi *next_module; +}; + +#endif /* !(_PTIFDDI_H) */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/ptifddi_asm.h linux/drivers/net/ptifddi_asm.h --- v2.1.66/linux/drivers/net/ptifddi_asm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ptifddi_asm.h Sat Nov 29 10:33:20 1997 @@ -0,0 +1,2543 @@ +/* $Id: ptifddi_asm.h,v 1.3 1997/04/16 10:27:28 jj Exp $ */ +#ifndef _PTIFDDI_ASM_H +#define _PTIFDDI_ASM_H + +/* This is the code for the DPRAM firmware loader. */ +const unsigned short firmware_loader_code_addr = 0x140; /* Offset from dpram base. */ +const unsigned short firmware_loader_dev_addr = 0xf940; /* Offset as seen by device. */ +const unsigned short firmware_loader_size = 0x6f; /* Size of fware loader code.*/ + +static unsigned char firmware_loader[] __initdata = { + 0xb7, 0x01, 0xc0, 0xc4, 0x97, 0x14, 0xc0, 0xb7, 0xf9, 0x02, 0x12, 0x03, 0x30, + 0x2c, 0x8b, 0x0d, 0x30, 0x28, 0x8b, 0x0c, 0x30, 0x24, 0x8b, 0x11, 0x82, 0x00, + 0x11, 0xdc, 0x56, 0x30, 0x1b, 0x86, 0xff, 0xfc, 0x0c, 0xfc, 0x49, 0x86, 0xff, + 0xfd, 0x0c, 0xfc, 0x43, 0xad, 0x0c, 0x8b, 0xa9, 0x0c, 0x8a, 0x11, 0x75, 0x83, + 0x00, 0xf9, 0x00, 0xab, 0x95, 0x31, 0x03, 0x40, 0xb6, 0xf9, 0x00, 0xa8, 0x96, + 0xc8, 0x17, 0x41, 0x68, 0xad, 0x12, 0x88, 0xa9, 0x12, 0x86, 0xf9, 0x16, 0x12, + 0xfc, 0x47, 0x86, 0xf9, 0x16, 0x12, 0xfd, 0x41, 0x3c, 0x83, 0x00, 0xf9, 0x00, + 0xab, 0xb7, 0xf9, 0x02, 0x12, 0x3c, 0x83, 0x00, 0xf9, 0x00, 0xab, 0xb7, 0xf9, + 0x02, 0x12, 0x03, 0x95, 0x2f +}; + +/* This is test code which we run at boot time to go and verify the proper + * functioning of the PTI fddi card. + */ +const unsigned short test_firmware_code_addr = 0x100; /* Offset from dpram base. */ +const unsigned short test_firmware_dev_addr = 0xfa00; /* Offset as seen by device. */ +const unsigned short test_firmware_size = 0x414; /* Size of card test code. */ + +static unsigned char test_firmware[] __initdata = { + 0x97, 0x00, 0xd0, 0x90, 0x01, 0x8b, 0xd4, 0x8b, 0xf4, 0x97, 0x1f, 0xe2, 0x97, + 0x1f, 0xf2, 0x97, 0x14, 0xc0, 0xb7, 0x01, 0xc0, 0xc4, 0x00, 0x8b, 0x0b, 0x00, + 0x8b, 0x03, 0x8b, 0x0a, 0xab, 0x08, 0x90, 0x00, 0x8b, 0x04, 0x90, 0x40, 0x8b, + 0x05, 0x90, 0xff, 0x8b, 0x06, 0x90, 0xf7, 0x8b, 0x07, 0x90, 0x00, 0x8b, 0x0c, + 0x33, 0x8d, 0x82, 0x00, 0x0a, 0xdd, 0x94, 0x57, 0x89, 0x0c, 0x89, 0x0b, 0x33, + 0x81, 0x82, 0x00, 0x0a, 0xdd, 0x94, 0x4b, 0x89, 0x0c, 0x33, 0x77, 0x82, 0x00, + 0x0a, 0xdd, 0x94, 0x41, 0x91, 0x01, 0x30, 0xc4, 0x00, 0x30, 0xd2, 0x9c, 0x00, + 0x91, 0x02, 0x9d, 0x00, 0x91, 0x42, 0x30, 0xb7, 0xb6, 0x01, 0x04, 0x88, 0x96, + 0xc8, 0x10, 0x41, 0x4e, 0x90, 0x01, 0x30, 0xbb, 0x9c, 0x00, 0x91, 0x03, 0x9d, + 0x00, 0x91, 0x43, 0x30, 0xa0, 0x31, 0x97, 0x9c, 0x00, 0x91, 0x04, 0x9d, 0x00, + 0x91, 0x44, 0x30, 0x94, 0x32, 0x6b, 0x9c, 0x00, 0x91, 0x05, 0x9d, 0x00, 0x91, + 0x45, 0x30, 0x88, 0x60, 0x91, 0x41, 0x95, 0x41, 0xab, 0xce, 0xe1, 0x41, 0x3c, + 0x82, 0x02, 0x0c, 0xdc, 0x49, 0xa8, 0xce, 0x03, 0xf7, 0x07, 0xb8, 0x00, 0x01, + 0x72, 0xa8, 0xcc, 0x75, 0xab, 0xce, 0xc1, 0x41, 0x3c, 0x82, 0x02, 0x0c, 0xdc, + 0x4b, 0xa8, 0xce, 0x03, 0xf7, 0x96, 0xc9, 0x10, 0xb8, 0x00, 0x01, 0x74, 0xa8, + 0xcc, 0x77, 0xab, 0xce, 0xe0, 0x41, 0x3c, 0x96, 0xce, 0xfc, 0x42, 0x30, 0x46, + 0x82, 0x02, 0x0c, 0xdc, 0x4b, 0xae, 0xce, 0x03, 0xf7, 0x07, 0xb8, 0x00, 0x01, + 0xae, 0xce, 0x78, 0xac, 0xcc, 0xce, 0x7c, 0xab, 0xce, 0xc0, 0x41, 0x3c, 0xaf, + 0xc8, 0x96, 0xce, 0xfb, 0x99, 0xff, 0x9c, 0x00, 0x45, 0x3f, 0xc8, 0x30, 0x1b, + 0x42, 0x3f, 0xc8, 0x82, 0x02, 0x0c, 0xdc, 0x4e, 0xae, 0xce, 0x03, 0xf7, 0x96, + 0xc9, 0x10, 0xb8, 0x00, 0x01, 0xae, 0xce, 0x95, 0x25, 0xac, 0xcc, 0xce, 0x95, + 0x2a, 0x97, 0x01, 0x0a, 0x3c, 0x97, 0x01, 0x0a, 0x3c, 0x82, 0x05, 0xca, 0xfd, + 0x46, 0xa1, 0xca, 0xf8, 0x00, 0x8b, 0x3c, 0xa1, 0xca, 0xf8, 0x00, 0x8b, 0x60, + 0xb7, 0x20, 0x00, 0x10, 0x9d, 0x00, 0xb7, 0x28, 0x00, 0x10, 0xac, 0x10, 0xcc, + 0x97, 0x37, 0x12, 0x30, 0x64, 0xac, 0x10, 0xcc, 0x97, 0x37, 0x12, 0x30, 0x87, + 0x30, 0x0a, 0x82, 0x00, 0x0a, 0xdd, 0x42, 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xac, + 0x10, 0xcc, 0x97, 0x00, 0x12, 0x97, 0x01, 0x03, 0x44, 0xeb, 0x58, 0x24, 0x3c, + 0xb7, 0xfb, 0x5b, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, + 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x15, 0xa9, 0xcc, 0xa9, 0xcc, + 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfb, 0x5f, 0x14, + 0xfc, 0x3c, 0x95, 0x25, 0xc4, 0x88, 0x12, 0xc6, 0xc4, 0x96, 0x12, 0xdc, 0x3c, + 0x80, 0x12, 0xce, 0xab, 0xa9, 0xcc, 0x34, 0x87, 0xae, 0xcc, 0x05, 0xae, 0xcc, + 0x3c, 0xb7, 0xfb, 0x5b, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, + 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x40, 0xa9, 0xcc, 0xa9, + 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfb, 0x5f, + 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfb, 0x5b, 0x14, 0x91, 0x01, 0xad, 0x14, + 0x88, 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, + 0x1c, 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, + 0x14, 0x86, 0xfb, 0x5f, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xc4, 0x88, 0x12, 0xc6, + 0x89, 0x12, 0x3c, 0xc4, 0x96, 0x12, 0xdc, 0x4d, 0x80, 0x12, 0xce, 0xab, 0xa9, + 0xcc, 0x34, 0xf7, 0xae, 0xcc, 0x05, 0xae, 0xcc, 0x89, 0x12, 0x3c, 0xb2, 0x10, + 0x00, 0x00, 0xc6, 0xb2, 0x10, 0x00, 0x97, 0x55, 0x12, 0x30, 0x61, 0xb2, 0x10, + 0x00, 0x97, 0x55, 0x12, 0x30, 0x84, 0x82, 0x00, 0x0a, 0xdd, 0x44, 0x30, 0x05, + 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xb2, 0x10, 0x00, 0x97, 0x00, 0x12, 0x97, 0x01, + 0x03, 0x58, 0x02, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x5e, 0xef, + 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0xfc, 0x3e, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, + 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x34, 0xe0, 0xa9, 0xcc, 0xa9, 0xcc, + 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfc, 0x56, 0x14, + 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfc, 0x3e, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, + 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x40, + 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, + 0x86, 0xfc, 0x56, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfc, 0x3e, 0x14, 0x91, + 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, + 0x9d, 0x00, 0x30, 0x1c, 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, + 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfc, 0x56, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xc4, + 0x88, 0x12, 0xc6, 0x89, 0x12, 0x3c, 0xc4, 0x96, 0x12, 0xdc, 0x4d, 0x80, 0x12, + 0xce, 0xab, 0xa9, 0xcc, 0x35, 0xd7, 0xae, 0xcc, 0x05, 0xae, 0xcc, 0x89, 0x12, + 0x3c, 0xb2, 0x12, 0x00, 0x00, 0xc6, 0xb2, 0x12, 0x00, 0x97, 0x55, 0x12, 0x30, + 0x51, 0xb2, 0x12, 0x00, 0x97, 0x55, 0x12, 0x30, 0x74, 0x82, 0x00, 0x0a, 0xdd, + 0x48, 0x30, 0x09, 0x82, 0x00, 0x0a, 0xdc, 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xb2, + 0x12, 0x00, 0x97, 0x00, 0x12, 0x97, 0x01, 0x03, 0x44, 0x02, 0xa8, 0x0f, 0x80, + 0xb7, 0xfd, 0x22, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, + 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x35, 0xb0, 0xa9, 0xcc, 0xa9, 0xcc, + 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfd, 0x26, 0x14, + 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfd, 0x22, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, + 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x40, + 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, + 0x86, 0xfd, 0x26, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfd, 0x22, 0x14, 0x91, + 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, + 0x9d, 0x00, 0x30, 0x1c, 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, + 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfd, 0x26, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xc4, + 0x88, 0x12, 0xc6, 0x89, 0x12, 0x3c, 0xc4, 0x96, 0x12, 0xdc, 0x4d, 0x80, 0x12, + 0xce, 0xab, 0xa9, 0xcc, 0x36, 0xa7, 0xae, 0xcc, 0x05, 0xae, 0xcc, 0x89, 0x12, + 0x3c, 0xac, 0x04, 0xcc, 0xac, 0x06, 0xca, 0xb0, 0xff, 0x7f, 0x82, 0x00, 0x0c, + 0xdc, 0xb0, 0x04, 0x01, 0x82, 0x02, 0x0c, 0xdc, 0x90, 0x05, 0x82, 0x00, 0x0b, + 0xdc, 0x37, 0x30, 0x82, 0x00, 0x0b, 0xdd, 0x37, 0x4c, 0x00, 0xaa, 0xc8, 0x62, + 0xaa, 0xc8, 0x62, 0xaa, 0xc8, 0x62, 0xac, 0x04, 0xcc, 0xac, 0x06, 0xca, 0xb0, + 0xff, 0x7f, 0x82, 0x00, 0x0c, 0xdc, 0xb0, 0x04, 0x01, 0x82, 0x02, 0x0c, 0xdc, + 0x90, 0x05, 0x82, 0x00, 0x0b, 0xdc, 0x37, 0x25, 0x82, 0x00, 0x0b, 0xdd, 0x37, + 0x4a,0x3c +}; + +/* This is the main firmware which implements the FDDI PHY transactions and talks + * to the MAC chipsets. + */ +const unsigned short main_firmware_dev_addr = 0xf000; /* Offset as seen by device. */ +const unsigned short main_firmware_size = 0x1000; /* Size of main firmware. */ + +static unsigned char main_firmware[] __initdata = { + 0x00, 0xaa, 0xc8, 0x62, 0xab, 0x00, 0xab, 0xbe, 0x8b, 0xba, 0x97, 0x3c, 0xd0, + 0x90, 0x01, 0x8b, 0xd4, 0x8b, 0xf4, 0xb7, 0x02, 0x03, 0xe2, 0xb7, 0x02, 0x03, + 0xf2, 0x97, 0x14, 0xc0, 0xb2, 0x20, 0x3c, 0xb3, 0x01, 0x52, 0x00, 0xf3, 0xa7, + 0x01, 0x92, 0x01, 0x82, 0x90, 0x0c, 0xe3, 0xb0, 0xcc, 0xcc, 0xf6, 0xe6, 0xb6, + 0x01, 0x5c, 0x08, 0xf1, 0xb0, 0x88, 0xcc, 0xe3, 0xb0, 0x21, 0x52, 0xe3, 0x00, + 0x05, 0xe3, 0x63, 0x8f, 0x08, 0x8d, 0x00, 0x07, 0xe4, 0x04, 0xe6, 0xb3, 0xff, + 0x80, 0xf1, 0x00, 0xaa, 0xca, 0x64, 0xb7, 0x3e, 0x80, 0xb6, 0x91, 0x16, 0xf1, + 0xa8, 0xb6, 0x82, 0x80, 0xb7, 0xdb, 0xaa, 0xca, 0x69, 0xb0, 0x3f, 0xff, 0xf1, + 0xf0, 0xb2, 0x20, 0x3c, 0xb7, 0x01, 0xc0, 0xc4, 0xb6, 0xff, 0xfe, 0xa8, 0x27, + 0x90, 0xf7, 0x92, 0xba, 0x17, 0x20, 0x1f, 0x00, 0x8b, 0xd2, 0xab, 0xaa, 0x05, + 0xf3, 0x9c, 0x00, 0x55, 0xb6, 0x01, 0x04, 0x10, 0x9a, 0x04, 0xab, 0xbe, 0x83, + 0x01, 0xff, 0x16, 0xab, 0x96, 0xc8, 0x12, 0x83, 0x02, 0xff, 0x16, 0xab, 0x90, + 0x01, 0xb6, 0x01, 0x04, 0x11, 0x04, 0xb6, 0xff, 0x02, 0xab, 0x92, 0xce, 0xb3, + 0x20, 0x30, 0x30, 0x26, 0xb3, 0x28, 0x30, 0x96, 0xbe, 0x12, 0x30, 0x1e, 0xb2, + 0x20, 0x2e, 0x30, 0x06, 0xb6, 0xff, 0x00, 0x89, 0x94, 0x2b, 0x00, 0xc6, 0xc4, + 0x99, 0x01, 0x9d, 0x00, 0x4a, 0x90, 0x40, 0xc6, 0xa8, 0xe2, 0xb9, 0xfd, 0xff, + 0xab, 0xe2, 0x3c, 0xd4, 0x9d, 0x11, 0x3c, 0xc7, 0x0e, 0x90, 0x01, 0x06, 0xd6, + 0x0b, 0x09, 0x8f, 0x0e, 0x3c, 0xb6, 0xff, 0x8e, 0xae, 0xb6, 0xff, 0x8c, 0xab, + 0x0e, 0x96, 0xd0, 0x18, 0xb6, 0x01, 0x20, 0x11, 0x26, 0x92, 0xaa, 0x18, 0x13, + 0x25, 0xb6, 0xff, 0x8e, 0xa8, 0xda, 0x8b, 0xab, 0xdb, 0xe7, 0xe7, 0xb8, 0xff, + 0x90, 0xab, 0xb4, 0xab, 0xce, 0xf0, 0xab, 0xac, 0x8f, 0xfb, 0x05, 0xbd, 0x7f, + 0xfe, 0x94, 0x40, 0xa8, 0xac, 0xbd, 0x3f, 0xff, 0xb4, 0x01, 0x8a, 0x04, 0xab, + 0xb2, 0x05, 0xe7, 0xe7, 0xab, 0xce, 0xf0, 0xab, 0xae, 0xf4, 0xab, 0xb0, 0xb3, + 0xff, 0x82, 0xf0, 0xe7, 0x07, 0x28, 0x92, 0xba, 0x16, 0x24, 0x92, 0xaa, 0xa8, + 0xb0, 0xbd, 0x7f, 0xff, 0xb4, 0x01, 0x9d, 0xbd, 0x07, 0xff, 0xb4, 0x01, 0xf0, + 0x9d, 0x08, 0xb4, 0x02, 0xbf, 0xb4, 0x01, 0x06, 0xa8, 0xb2, 0xad, 0xb4, 0xab, + 0x92, 0xaa, 0x90, 0x08, 0xdd, 0x96, 0xd0, 0x08, 0x95, 0x6f, 0x90, 0x08, 0x2d, + 0x97, 0xfb, 0xd2, 0xb3, 0x10, 0x5e, 0xb2, 0x12, 0x0a, 0x00, 0xd5, 0x8b, 0xb6, + 0x00, 0xc5, 0x96, 0xbe, 0x10, 0x5a, 0x8b, 0xb7, 0xb3, 0x18, 0x5e, 0xb2, 0x1a, + 0x0a, 0x00, 0xd5, 0x8b, 0xb8, 0x00, 0xc5, 0xc5, 0x88, 0xb8, 0xd5, 0xb2, 0x12, + 0x0a, 0xb3, 0x10, 0x5e, 0x88, 0xb7, 0xc5, 0x88, 0xb6, 0xd5, 0x92, 0xaa, 0x57, + 0x90, 0x06, 0x2d, 0xb3, 0x20, 0x06, 0x00, 0xd5, 0xd5, 0x4d, 0x90, 0x07, 0x2d, + 0xb3, 0x28, 0x06, 0x6a, 0x90, 0x05, 0x42, 0x90, 0x09, 0x2d, 0x1e, 0xa5, 0xff, + 0x8c, 0xff, 0x8e, 0xab, 0x3c, 0xab, 0xca, 0xb9, 0x07, 0xff, 0xbd, 0x03, 0xff, + 0x41, 0x5a, 0x92, 0xcb, 0x97, 0x7c, 0xc9, 0xe7, 0x11, 0x43, 0x10, 0x46, 0x3c, + 0x10, 0x47, 0xad, 0xc8, 0xa9, 0xad, 0xc8, 0xa8, 0x50, 0xab, 0xcc, 0xe4, 0x05, + 0xe6, 0x04, 0x49, 0x1e, 0x17, 0x42, 0x94, 0x59, 0x1f, 0x16, 0x67, 0x57, 0x92, + 0xc9, 0xbd, 0x03, 0xff, 0x6d, 0xbd, 0x02, 0xdf, 0x94, 0x29, 0xe7, 0x12, 0x51, + 0x11, 0x48, 0xe7, 0x11, 0x0b, 0x10, 0x0c, 0x0e, 0xc7, 0x53, 0xbd, 0x03, 0xbe, + 0x53, 0xb8, 0xfa, 0x00, 0xb8, 0x14, 0x00, 0x10, 0x41, 0x46, 0x96, 0xc8, 0x17, + 0xb8, 0x00, 0x80, 0x96, 0xaa, 0x08, 0x3c, 0xc7, 0xb8, 0x2e, 0x40, 0x68, 0x10, + 0x55, 0x96, 0xc8, 0x14, 0x4d, 0xbd, 0x02, 0xe0, 0xb0, 0x34, 0x00, 0xbc, 0x02, + 0xe0, 0xb0, 0x30, 0x00, 0x7b, 0xb8, 0xfd, 0xc9, 0x4a, 0x96, 0xc8, 0x17, 0x43, + 0x99, 0x7f, 0x6b, 0xb8, 0x1c, 0x80, 0xe7, 0x3c, 0xa8, 0xae, 0x96, 0xc9, 0x17, + 0x41, 0x3c, 0x2b, 0xab, 0xcc, 0xc4, 0x96, 0xaa, 0x10, 0x41, 0xe4, 0xae, 0xca, + 0x88, 0xc9, 0xe7, 0x3b, 0x99, 0x0f, 0x96, 0xca, 0xf8, 0x3c, 0xcc, 0x09, 0x1c, + 0x0d, 0x16, 0x38, 0x37, 0x4d, 0x63, 0x6e, 0xa1, 0xae, 0xff, 0xbe, 0xab, 0x2f, + 0x17, 0x4a, 0x0f, 0xa5, 0xff, 0x8e, 0xff, 0x8a, 0xab, 0x44, 0x17, 0x41, 0x5d, + 0x1f, 0x2a, 0xab, 0xcc, 0x99, 0x0f, 0x9d, 0x0b, 0x4a, 0x9c, 0x0b, 0xb6, 0xff, + 0x8a, 0xa8, 0xb6, 0xff, 0x8e, 0xab, 0xa8, 0xcc, 0x82, 0x02, 0xb0, 0xdc, 0xb6, + 0xff, 0xfc, 0xab, 0xb4, 0xfe, 0xbd, 0x2a, 0xae, 0xb2, 0x92, 0xaa, 0x15, 0x96, + 0xc9, 0x0e, 0x96, 0xb0, 0x10, 0x0d, 0xaf, 0xc8, 0x96, 0xb3, 0x16, 0x41, 0x76, + 0xa8, 0xb2, 0x2c, 0x3f, 0xc8, 0x92, 0xc9, 0x17, 0x4c, 0x16, 0x43, 0x96, 0xaa, + 0x1d, 0x1e, 0xab, 0xb2, 0x95, 0x28, 0xe7, 0xe7, 0x92, 0xaa, 0xaf, 0xc8, 0x3c, + 0x2a, 0x92, 0xc9, 0x1f, 0x16, 0x0f, 0xa0, 0xc8, 0xb2, 0xf8, 0x95, 0x3b, 0x88, + 0xaf, 0x97, 0x7c, 0xc9, 0xe7, 0xad, 0xc8, 0xaa, 0xad, 0xc8, 0xa8, 0x9c, 0x00, + 0x95, 0x4b, 0x94, 0x4a, 0x96, 0xb1, 0x16, 0x08, 0x2b, 0x92, 0xaa, 0xab, 0xce, + 0x10, 0x41, 0xf4, 0xd4, 0x93, 0xb6, 0xf6, 0x88, 0xaf, 0x96, 0xb1, 0x16, 0x4a, + 0x97, 0x7c, 0xc9, 0xe7, 0xad, 0xc8, 0xa8, 0x10, 0x99, 0xff, 0x8d, 0xb8, 0x00, + 0xe6, 0x88, 0xb1, 0x3b, 0x99, 0x03, 0xcc, 0x04, 0x07, 0x0a, 0x0d, 0xf4, 0xfc, + 0x4e, 0x50, 0xf4, 0xfd, 0x4a, 0x4c, 0xf4, 0xfd, 0x46, 0x6a, 0xf4, 0xf9, 0x9d, + 0x00, 0x43, 0x96, 0xca, 0x0b, 0x88, 0xb1, 0x96, 0xca, 0xf9, 0x9c, 0x00, 0x4c, + 0x88, 0xae, 0x96, 0xc8, 0x17, 0xba, 0xff, 0x00, 0xa0, 0xc8, 0xb2, 0xf8, 0xb4, + 0xfe, 0x18, 0x2b, 0xab, 0xce, 0xab, 0xb6, 0x88, 0xb1, 0x9d, 0x77, 0x46, 0x92, + 0xb8, 0xac, 0xae, 0xb8, 0x4f, 0x96, 0xaf, 0x17, 0x76, 0xa8, 0xae, 0xbd, 0x77, + 0xff, 0x6f, 0x2b, 0xab, 0xcc, 0x88, 0xaf, 0xe7, 0x3b, 0x99, 0x0f, 0x96, 0xaa, + 0x10, 0x96, 0xc8, 0x0c, 0x02, 0xcc, 0x4f, 0x1f, 0x20, 0x22, 0x24, 0x28, 0x2a, + 0x2d, 0x2f, 0x31, 0x33, 0x36, 0x3a, 0x3c, 0x3e, 0x40, 0x77, 0x47, 0x48, 0x4a, + 0x4c, 0x4e, 0x50, 0x53, 0x55, 0x59, 0x5b, 0x5e, 0x62, 0x64, 0x66, 0x68, 0xe4, + 0x4d, 0xf4, 0xe5, 0x4a, 0xf4, 0xf8, 0x47, 0xf4, 0xf8, 0x00, 0xf7, 0x42, 0xf4, + 0xeb, 0x58, 0xe4, 0x8f, 0xeb, 0x54, 0xf4, 0xfe, 0x5b, 0xf4, 0xfe, 0x49, 0xf4, + 0xff, 0x55, 0xe4, 0x8f, 0xff, 0x51, 0xf4, 0xff, 0xa8, 0xce, 0x4c, 0xf4, 0xf9, + 0x4c, 0xf4, 0xfa, 0x49, 0xf4, 0xfb, 0x46, 0xf4, 0x23, 0x43, 0xac, 0xb6, 0xce, + 0xf6, 0x94, 0x36, 0xc4, 0x4b, 0xd4, 0xc5, 0x48, 0xd4, 0xd8, 0x45, 0xd4, 0xd8, + 0x4c, 0xd4, 0xcb, 0x5a, 0xc4, 0x8f, 0xcb, 0x56, 0xd4, 0xde, 0x5d, 0xd4, 0xde, + 0x88, 0xc9, 0x58, 0xd4, 0xdf, 0x55, 0xc4, 0x8f, 0xdf, 0x51, 0xd4, 0xdf, 0xa8, + 0xce, 0x4c, 0xd4, 0xd9, 0x4c, 0xd4, 0xda, 0x49, 0xd4, 0xdb, 0x46, 0xd4, 0x23, + 0x43, 0xac, 0xb6, 0xce, 0xd6, 0xb4, 0xfd, 0x5c, 0xae, 0xca, 0xc4, 0x99, 0x0f, + 0xae, 0xca, 0x82, 0x00, 0xca, 0xfc, 0x3c, 0x14, 0x45, 0xe7, 0xaa, 0xca, 0x63, + 0x3c, 0xc7, 0xaa, 0xca, 0x63, 0x3c, 0xbd, 0x03, 0xff, 0x5e, 0x92, 0xc9, 0xb3, + 0x12, 0x10, 0x10, 0xb3, 0x1a, 0x10, 0x96, 0xc8, 0x17, 0x94, 0x72, 0xa8, 0xae, + 0x17, 0x4c, 0x16, 0x94, 0x5e, 0x15, 0x94, 0x3f, 0x9c, 0x80, 0x94, 0x1f, 0x9d, + 0x00, 0xb4, 0xfd, 0x1f, 0xa8, 0xce, 0xb8, 0xff, 0x2e, 0xab, 0xcc, 0x9a, 0x28, + 0xab, 0xca, 0xb8, 0xfe, 0xf2, 0xab, 0xce, 0x00, 0xe1, 0x62, 0x00, 0xd6, 0x97, + 0x38, 0xce, 0xd6, 0x7c, 0xa8, 0xce, 0xb8, 0xfe, 0x80, 0xab, 0xcc, 0x9a, 0x0c, + 0xab, 0xca, 0x22, 0x97, 0xb0, 0xcc, 0x97, 0xfe, 0xca, 0x22, 0x74, 0x00, 0x96, + 0xcc, 0x14, 0x05, 0xe1, 0x66, 0x3c, 0x04, 0x97, 0x7c, 0xc9, 0xe7, 0xab, 0xcc, + 0x91, 0x04, 0xe2, 0xab, 0xb8, 0xe4, 0xab, 0xb6, 0x97, 0x04, 0xce, 0x00, 0xf1, + 0x92, 0xb9, 0xc2, 0xd6, 0xaa, 0xca, 0x64, 0x4b, 0xac, 0xce, 0xcc, 0x97, 0x04, + 0xce, 0x99, 0x1f, 0xd6, 0x18, 0x10, 0x5c, 0x62, 0x3b, 0x99, 0xf0, 0x8b, 0xb6, + 0x2a, 0x96, 0xc9, 0x10, 0x96, 0xb6, 0x08, 0xac, 0xce, 0xcc, 0x97, 0x1a, 0xce, + 0x11, 0x41, 0x62, 0xd6, 0xf3, 0x88, 0xb6, 0xd6, 0x19, 0xb4, 0xfc, 0xa2, 0x8d, + 0xab, 0xb2, 0xc0, 0x3b, 0x3c, 0xe7, 0x07, 0x45, 0x82, 0x06, 0xb0, 0xfd, 0x3c, + 0xe7, 0xf4, 0x07, 0x2c, 0xb6, 0xff, 0x86, 0xa8, 0xb9, 0x03, 0xff, 0xe7, 0xe7, + 0xe7, 0xba, 0x60, 0x00, 0xab, 0xce, 0x29, 0x3b, 0x3b, 0x97, 0x80, 0xc8, 0xf1, + 0xe0, 0x62, 0xb6, 0xff, 0x86, 0xa9, 0x3c, 0x20, 0x21, 0x27, 0x9c, 0xf6, 0x65, + 0x92, 0xba, 0x9d, 0xef, 0x4f, 0x93, 0xbd, 0x9d, 0x2f, 0x9d, 0x3f, 0x42, 0x9a, + 0xf0, 0xd3, 0x20, 0x21, 0xd5, 0x94, 0x69, 0xac, 0xbc, 0xce, 0x99, 0x0f, 0xcc, + 0x44, 0x2a, 0x38, 0x33, 0x2e, 0x1c, 0x3e, 0x09, 0x12, 0x0f, 0x10, 0x0d, 0x30, + 0x37, 0x36, 0x35, 0x0f, 0x1c, 0xa1, 0xce, 0xff, 0xbe, 0xab, 0x2f, 0x0d, 0x41, + 0x1d, 0x0e, 0x96, 0xc8, 0x11, 0x41, 0x3c, 0x90, 0xf0, 0x96, 0xaa, 0x14, 0x4a, + 0x96, 0xaa, 0x0b, 0x3c, 0x90, 0xf1, 0x20, 0x21, 0x8e, 0xbb, 0x55, 0x88, 0xbb, + 0xd5, 0x51, 0x88, 0xbb, 0xd6, 0x4d, 0xd4, 0x4b, 0x1e, 0x14, 0x3f, 0xc8, 0x1c, + 0x90, 0xfc, 0x43, 0x29, 0x92, 0xba, 0x5b, 0x1b, 0x0c, 0x90, 0x0a, 0xb6, 0xff, + 0x8e, 0xae, 0xb6, 0xff, 0x88, 0xab, 0xa1, 0xbc, 0xff, 0xb8, 0xab, 0x2e, 0x1c, + 0xa5, 0xff, 0x88, 0xff, 0x8e, 0xab, 0x90, 0xf5, 0xb6, 0x01, 0x20, 0x10, 0x41, + 0x65, 0xb6, 0x01, 0x26, 0x8b, 0x3c, 0xb6, 0x01, 0x20, 0x11, 0x41, 0x65, 0xb6, + 0x01, 0x24, 0x88, 0x3c, 0x15, 0x45, 0x82, 0x06, 0xb0, 0xfd, 0x3c, 0x0c, 0x90, + 0x80, 0x20, 0x21, 0x9c, 0xff, 0x42, 0x26, 0x69, 0x1c, 0x29, 0x20, 0x21, 0xc0, + 0x63, 0x3c, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x3c, + 0x3c, 0x91, 0x00, 0xb6, 0x12, 0x08, 0x88, 0x96, 0xc8, 0x13, 0x30, 0x55, 0x96, + 0xc8, 0x14, 0x30, 0x41, 0x96, 0xc8, 0x16, 0x94, 0x2b, 0x96, 0xc8, 0x17, 0x5c, + 0xa8, 0xca, 0x96, 0xc8, 0x13, 0x30, 0x2b, 0x00, 0xb6, 0x12, 0x08, 0x8b, 0xb6, + 0x10, 0x5c, 0x88, 0x96, 0xc8, 0x10, 0x30, 0x5d, 0x82, 0x00, 0xca, 0xfc, 0x3c, + 0x94, 0x77, 0x00, 0xb6, 0x12, 0x0e, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x95, 0x25, + 0x00, 0xb6, 0x12, 0x16, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x95, 0x30, 0x00, 0xb6, + 0x12, 0x0a, 0x8b, 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x1c, 0x88, 0x99, 0x55, 0xb6, + 0x12, 0x1c, 0x8b, 0xae, 0xce, 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x28, 0x88, 0x96, + 0xc8, 0x10, 0x54, 0x96, 0xc8, 0x14, 0x50, 0x96, 0xc8, 0x12, 0x4c, 0x83, 0x00, + 0x12, 0x2a, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0xae, 0xce, 0x3c, 0x99, 0xea, 0xb6, + 0x12, 0x28, 0x8b, 0x82, 0x02, 0xca, 0xfa, 0xae, 0xce, 0x3c, 0xb6, 0x10, 0x1c, + 0x88, 0xb6, 0xff, 0x0a, 0x8b, 0xb6, 0x10, 0x20, 0x88, 0x99, 0xfc, 0xb6, 0x10, + 0x20, 0x8b, 0xb6, 0x10, 0x5c, 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x5c, 0x8b, 0x82, + 0x04, 0xca, 0xfa, 0x3c, 0xb3, 0xff, 0x50, 0xa2, 0x01, 0xce, 0x88, 0x9d, 0x00, + 0x66, 0x90, 0x01, 0xd6, 0xa2, 0x01, 0xce, 0x88, 0x9d, 0x00, 0x5b, 0xb6, 0xff, + 0x52, 0xa8, 0x96, 0xca, 0xfa, 0xb6, 0xff, 0x52, 0xab, 0xb6, 0xff, 0xfc, 0xa8, + 0x83, 0x00, 0xff, 0x56, 0xfd, 0xb6, 0xff, 0xfc, 0xab, 0x00, 0xd6, 0x3c, 0x00, + 0xd6, 0x95, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xfe, + 0x93, 0x40, 0xb4, 0xfe, 0x8e, 0x40, 0xb4, 0xfe, 0x8c, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xf9, 0x01, + 0x12, 0x30, 0x1f, 0x8b, 0x11, 0x30, 0x1b, 0x8b, 0x0d, 0x30, 0x17, 0x8b, 0x0c, + 0x82, 0x00, 0x11, 0xdc, 0x4a, 0x30, 0x0e, 0xad, 0x0c, 0x8b, 0xa9, 0x0c, 0x8a, + 0x11, 0x69, 0x83, 0x00, 0xf9, 0x00, 0xab, 0x3c, 0xb6, 0xf9, 0x00, 0xa8, 0x96, + 0xc8, 0x17, 0x41, 0x68, 0xad, 0x12, 0x88, 0xa9, 0x12, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf5, 0x68, 0xf5, 0x5c, 0xf4, 0xf1, 0xf3, + 0x73, 0xf5, 0x42, 0xf5, 0xdc, 0xf4, 0x6e, 0xf5, 0xb1, 0xf4, 0xab, 0xf4, 0x37, + 0xf2, 0xb2, 0xf1, 0xb7, 0xf2, 0xe2, 0xf0, 0xeb, 0xf0, 0x0a, 0xf0, 0x0a, 0xf0, + 0xa7, 0xf1, 0xa4, 0xf1, 0x9d, 0xf1, 0x93, 0xf1, 0x5c, 0xf1, 0x00, 0x00, 0x00, + 0xf0 +}; + +/* This is the FDDI station management firmware. */ +const unsigned short smt_firmware_dev_addr = 0x4000; /* Offset as seen by device. */ +const unsigned short smt_firmware_size = 0x72b0; /* Size of SMT firmware. */ + +static unsigned char smt_firmware[] __initdata = { + 0x94, 0xaa, 0x00, 0x00, 0x94, 0x5d, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x94, 0x2c, + 0x00, 0x00, 0xb4, 0x5d, 0xfa, 0x00, 0x94, 0xc4, 0x00, 0x00, 0x94, 0xc8, 0x00, 0x00, + 0x94, 0xcc, 0x00, 0x00, 0xb4, 0x01, 0xbc, 0x00, 0x00, 0x00, 0xb2, 0xfe, 0x20, 0xc4, + 0x96, 0xc8, 0x17, 0x41, 0x3c, 0xb5, 0x56, 0xa7, 0xb2, 0xfe, 0x20, 0x00, 0xe6, 0xb4, + 0x04, 0x1a, 0x83, 0x00, 0xfe, 0x94, 0xab, 0xb2, 0xfe, 0x20, 0xe4, 0x96, 0xc8, 0x17, + 0x41, 0x45, 0x99, 0x3f, 0x9c, 0x03, 0x46, 0x83, 0x00, 0xfe, 0x20, 0xab, 0x3c, 0x82, + 0x02, 0xcc, 0xf8, 0xb3, 0xfe, 0x90, 0xb5, 0x3b, 0x12, 0x83, 0xe0, 0xfe, 0x94, 0xab, + 0x75, 0xac, 0x74, 0xce, 0x92, 0x00, 0xb5, 0x35, 0xdf, 0x92, 0x0e, 0xb6, 0x10, 0x00, + 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x00, 0x8b, 0xb5, 0x35, 0xc3, 0x90, 0x01, 0xb5, 0x35, + 0xd8, 0xb5, 0x35, 0x1e, 0xb6, 0x10, 0x00, 0x88, 0x9a, 0x01, 0xb6, 0x10, 0x00, 0x8b, + 0x89, 0x7d, 0xac, 0x6e, 0x02, 0xac, 0x70, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0x74, + 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0x00, 0xb5, 0x2c, 0xf0, 0x90, 0x01, 0xb5, 0x34, 0x80, + 0xb5, 0x34, 0xf5, 0x3c, 0xa7, 0xb8, 0x00, 0xda, 0xda, 0x00, 0xe1, 0x62, 0x8d, 0x02, + 0x80, 0x00, 0xe1, 0x62, 0xa8, 0xbe, 0x99, 0x0c, 0xc7, 0xc7, 0x04, 0x8b, 0x7e, 0xb7, + 0xb8, 0x0c, 0x72, 0xb7, 0xb8, 0x44, 0x74, 0xb7, 0xb8, 0xa4, 0x76, 0xb7, 0xba, 0x8a, + 0x78, 0xb5, 0x02, 0xf4, 0xb4, 0x03, 0x1b, 0x3c, 0xb5, 0x2e, 0xf4, 0xb4, 0x03, 0x74, + 0x40, 0x40, 0xb7, 0x00, 0x00, 0x08, 0xb2, 0x20, 0x00, 0x4c, 0x82, 0x01, 0x7e, 0xdc, + 0x3c, 0xb7, 0x00, 0x01, 0x08, 0xb2, 0x28, 0x00, 0xa2, 0x04, 0xcc, 0x88, 0xa2, 0x06, + 0xcc, 0xd9, 0x8b, 0x0a, 0x99, 0x60, 0x9c, 0x00, 0x94, 0x56, 0xa8, 0x08, 0xb5, 0x33, + 0x33, 0xab, 0xca, 0x99, 0x20, 0x9c, 0x00, 0x57, 0xb7, 0x02, 0x0a, 0x02, 0xac, 0xca, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, 0xb5, 0x04, 0x98, 0x90, 0x20, 0x01, 0xa0, + 0xc8, 0xca, 0xf9, 0xa8, 0xca, 0x99, 0x02, 0x9c, 0x00, 0x57, 0xa8, 0x08, 0xb5, 0x02, + 0xed, 0xa2, 0x4e, 0x76, 0xa8, 0x9c, 0x03, 0x4b, 0xaf, 0xca, 0xa8, 0x08, 0x91, 0x02, + 0xb5, 0x33, 0x86, 0x3f, 0xca, 0x82, 0x00, 0xca, 0xfc, 0x50, 0xb7, 0x02, 0x09, 0x02, + 0xac, 0xca, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, 0xb5, 0x04, 0x5e, 0x88, 0x0a, + 0x99, 0x10, 0x9c, 0x00, 0x55, 0xa8, 0x08, 0x32, 0x11, 0xb7, 0x05, 0x05, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, 0xb5, 0x04, 0x42, 0x90, 0x80, + 0xa2, 0x04, 0xcc, 0x8e, 0xb4, 0x02, 0xd3, 0x00, 0xb6, 0xff, 0x44, 0xa9, 0xb6, 0x12, + 0x0e, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x94, 0x6d, 0x00, 0xb6, 0xff, 0x42, 0xa9, 0xb6, + 0x12, 0x16, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x94, 0x5e, 0x00, 0xb6, 0x12, 0x0a, 0x8b, + 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x1c, 0x88, 0x99, 0x55, 0xb6, 0x12, 0x1c, 0x8b, 0xae, + 0xce, 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x28, 0x88, 0x96, 0xc8, 0x10, 0x54, 0x96, 0xc8, + 0x14, 0x50, 0x96, 0xc8, 0x12, 0x4c, 0x83, 0x00, 0x12, 0x2a, 0x8b, 0x82, 0x08, 0xca, + 0xfa, 0xae, 0xce, 0x3c, 0x99, 0xea, 0xb6, 0x12, 0x28, 0x8b, 0x82, 0x02, 0xca, 0xfa, + 0xae, 0xce, 0x3c, 0xb7, 0x00, 0x00, 0x0c, 0x91, 0x00, 0xb6, 0x12, 0x08, 0x88, 0x96, + 0xc8, 0x13, 0x34, 0x38, 0x96, 0xc8, 0x14, 0x34, 0x4c, 0x96, 0xc8, 0x16, 0x95, 0x66, + 0x96, 0xc8, 0x17, 0x95, 0x7a, 0xa8, 0xca, 0x96, 0xc8, 0x13, 0x34, 0x63, 0x00, 0xb6, + 0x12, 0x08, 0x8b, 0xac, 0xca, 0x0c, 0x97, 0x00, 0x09, 0xb6, 0x10, 0x5c, 0x88, 0xb6, + 0x10, 0x5e, 0xd9, 0x8b, 0x0a, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x7f, 0xb6, 0x10, 0x24, + 0x88, 0x99, 0x23, 0x9c, 0x00, 0x94, 0x3f, 0xab, 0xca, 0x99, 0x20, 0x9c, 0x00, 0x46, + 0x97, 0x01, 0x09, 0x97, 0x20, 0x08, 0xa8, 0xca, 0x99, 0x02, 0x9c, 0x00, 0x47, 0x82, + 0x02, 0x09, 0xda, 0x97, 0x02, 0x08, 0xa8, 0xca, 0x99, 0x01, 0x9c, 0x00, 0x48, 0x82, + 0x04, 0x09, 0xda, 0x82, 0x01, 0x08, 0xda, 0xa8, 0xca, 0x01, 0xab, 0xca, 0xb6, 0x10, + 0x26, 0x88, 0x96, 0xca, 0xf9, 0xb6, 0x10, 0x26, 0x8b, 0x00, 0xb6, 0x10, 0x24, 0x8b, + 0xb6, 0x10, 0x20, 0x88, 0x99, 0x03, 0x9c, 0x00, 0x94, 0x2c, 0xb6, 0x10, 0x1c, 0x88, + 0x99, 0x80, 0x9c, 0x00, 0x48, 0x90, 0x40, 0xb5, 0x5b, 0x18, 0x90, 0x80, 0x41, 0x00, + 0xb6, 0xff, 0x0a, 0x8b, 0x82, 0x04, 0x0c, 0xfa, 0xb7, 0x04, 0x03, 0x02, 0xab, 0x04, + 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb6, 0x10, 0x20, 0x8b, 0xb5, 0x03, 0x1c, 0x88, 0x0a, + 0x99, 0x02, 0x9c, 0x00, 0x94, 0x3f, 0xb6, 0x10, 0x28, 0x88, 0x99, 0x10, 0x9c, 0x00, + 0x5a, 0x82, 0x08, 0x09, 0xda, 0x90, 0x10, 0x01, 0xab, 0xca, 0xb6, 0x10, 0x2a, 0x88, + 0x96, 0xca, 0xf9, 0xb6, 0x10, 0x2a, 0x8b, 0x00, 0xb6, 0x10, 0x28, 0x8b, 0x40, 0xb6, + 0x10, 0x28, 0x88, 0x99, 0x40, 0x9c, 0x00, 0x53, 0xb5, 0x33, 0x96, 0x90, 0x40, 0x01, + 0xab, 0xca, 0xb6, 0x10, 0x2a, 0x88, 0x96, 0xca, 0xf9, 0xb6, 0x10, 0x2a, 0x8b, 0x88, + 0x0a, 0x99, 0x08, 0x9c, 0x00, 0x47, 0x30, 0x40, 0x00, 0xb6, 0x10, 0x38, 0x8b, 0x00, + 0xb6, 0x10, 0x5c, 0x8e, 0x82, 0x00, 0x09, 0xdc, 0x50, 0xb7, 0x04, 0x04, 0x02, 0x80, + 0x09, 0x04, 0xab, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb5, 0x02, 0xad, 0x82, 0x00, 0x0c, + 0xfc, 0xb4, 0x01, 0x40, 0xac, 0x0c, 0xca, 0xb5, 0xb3, 0x29, 0xb4, 0x01, 0x37, 0x88, + 0x09, 0x9a, 0x20, 0x8b, 0x09, 0xb6, 0x10, 0x20, 0x88, 0x99, 0xbf, 0xb6, 0x10, 0x20, + 0x8b, 0x3c, 0xb2, 0x10, 0x38, 0x00, 0xc5, 0xab, 0xca, 0x93, 0x5a, 0x96, 0xca, 0x10, + 0x30, 0x36, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x11, 0x30, 0x2d, 0x82, 0x02, 0xce, + 0xf8, 0x96, 0xca, 0x12, 0x30, 0x24, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x13, 0x30, + 0x1b, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x14, 0x30, 0x12, 0x82, 0x02, 0xce, 0xf8, + 0x96, 0xca, 0x15, 0x30, 0x09, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x16, 0x30, 0x00, + 0xf4, 0xb8, 0x00, 0x10, 0xf6, 0x3c, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, + 0xe7, 0x99, 0x02, 0x93, 0x54, 0xa0, 0xc8, 0xce, 0xf8, 0xf4, 0x9c, 0x00, 0x4f, 0x9d, + 0xff, 0x90, 0xff, 0x02, 0xf5, 0x8f, 0xeb, 0xf5, 0xa2, 0x2a, 0xcc, 0x8e, 0x00, 0x3c, + 0x90, 0x64, 0xa2, 0x2a, 0xcc, 0x8e, 0x90, 0x01, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x80, + 0x01, 0x43, 0x00, 0x80, 0x00, 0x80, 0x01, 0x43, 0x00, 0x80, 0x08, 0x80, 0x01, 0x43, + 0x00, 0x80, 0x0c, 0x00, 0xb5, 0x00, 0x7d, 0xb5, 0x00, 0x80, 0xb7, 0x00, 0x01, 0x02, + 0x82, 0x00, 0x02, 0xfc, 0x4b, 0xa8, 0x02, 0xb5, 0x28, 0x06, 0xae, 0x02, 0x05, 0xae, + 0x02, 0x6f, 0xb5, 0x5a, 0x0d, 0xb5, 0x01, 0x16, 0xb5, 0x29, 0x45, 0x3c, 0x90, 0x00, + 0xb6, 0xb8, 0x00, 0xab, 0xb5, 0x01, 0x33, 0xb5, 0x59, 0xfa, 0xb5, 0x00, 0x53, 0xb5, + 0x29, 0x51, 0xb5, 0x27, 0xe1, 0xb5, 0x59, 0x84, 0x30, 0x04, 0xb5, 0xfc, 0xce, 0x3c, + 0x3c, 0x40, 0x96, 0x7a, 0xdc, 0x3c, 0x8b, 0x7a, 0xb7, 0xb8, 0x44, 0x74, 0x04, 0xaa, + 0xc8, 0x41, 0x3c, 0x82, 0x60, 0x74, 0xf8, 0x68, 0x96, 0x7b, 0xdc, 0x3c, 0x8b, 0x7b, + 0xb7, 0xb8, 0xa4, 0x76, 0x04, 0xaa, 0xc8, 0x41, 0x3c, 0x82, 0xa2, 0x76, 0xf8, 0x68, + 0x96, 0x7c, 0xdc, 0x3c, 0x8b, 0x7c, 0xb7, 0xba, 0x8a, 0x78, 0x04, 0xaa, 0xc8, 0x41, + 0x3c, 0x82, 0x16, 0x78, 0xf8, 0x68, 0xb7, 0xb8, 0x0c, 0x72, 0x3c, 0x00, 0x97, 0x00, + 0x43, 0x3c, 0x82, 0x00, 0x43, 0xdd, 0x3c, 0xa2, 0x0e, 0x72, 0x88, 0x9c, 0x00, 0x94, + 0x4f, 0x97, 0x01, 0x43, 0x56, 0x88, 0xd2, 0x96, 0xc8, 0x12, 0x94, 0x4c, 0x96, 0xc8, + 0x15, 0x94, 0x65, 0x96, 0xc8, 0x13, 0x94, 0x68, 0x96, 0xc8, 0x14, 0x94, 0x74, 0xb5, + 0x00, 0xe4, 0xbc, 0x03, 0x01, 0x94, 0x29, 0xb0, 0x44, 0x65, 0xaf, 0xc8, 0xa8, 0x44, + 0xb9, 0xff, 0x00, 0xbc, 0x01, 0x00, 0xb4, 0x0d, 0x5a, 0xbc, 0x02, 0x00, 0xb4, 0x60, + 0xbb, 0xbc, 0x04, 0x00, 0xb4, 0x3d, 0x1a, 0xbc, 0x03, 0x00, 0xb4, 0x23, 0xc1, 0xbc, + 0x05, 0x00, 0xb4, 0x06, 0x02, 0x3c, 0x97, 0x00, 0x43, 0x3c, 0xb5, 0x00, 0xaf, 0xbc, + 0x03, 0x01, 0x6a, 0x67, 0xb5, 0xfb, 0x65, 0x97, 0xfb, 0xd2, 0x00, 0xb6, 0x12, 0x0a, + 0x8e, 0xab, 0xca, 0x00, 0xb6, 0x10, 0x5e, 0x8e, 0xb6, 0x10, 0x5e, 0x8e, 0xae, 0xca, + 0xb6, 0x12, 0x0a, 0x8e, 0x95, 0x6f, 0x97, 0xdf, 0xd2, 0xb5, 0xfb, 0x38, 0x95, 0x77, + 0xb5, 0xfb, 0x37, 0x97, 0xf7, 0xd2, 0x00, 0xb6, 0x20, 0x06, 0x8e, 0xb6, 0x20, 0x06, + 0x8e, 0x95, 0x72, 0xb5, 0xfb, 0x2a, 0x97, 0xef, 0xd2, 0x00, 0xb6, 0x28, 0x06, 0x8e, + 0xb6, 0x28, 0x06, 0x8e, 0x95, 0x83, 0x00, 0xab, 0x4e, 0xab, 0x50, 0xb1, 0x01, 0xf4, + 0xb2, 0xba, 0xb6, 0x00, 0xe6, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xab, 0xa2, + 0x06, 0xcc, 0xab, 0xa2, 0x08, 0xcc, 0xab, 0xae, 0xca, 0xaa, 0xc8, 0x41, 0x3c, 0xae, + 0xca, 0x82, 0x0a, 0xcc, 0xf8, 0x7d, 0xb1, 0x01, 0xf4, 0xb2, 0xba, 0xb6, 0x00, 0xa1, + 0x08, 0xb8, 0x00, 0xfc, 0x41, 0x51, 0xe6, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, + 0xab, 0xa2, 0x06, 0xcc, 0xab, 0xa2, 0x08, 0xcc, 0xab, 0xae, 0xca, 0xaa, 0xc8, 0x41, + 0x3c, 0xae, 0xca, 0x82, 0x0a, 0xcc, 0xf8, 0x95, 0x24, 0xa8, 0x4e, 0x96, 0x50, 0xfc, + 0x42, 0x00, 0x3c, 0x90, 0x01, 0x63, 0x34, 0x0b, 0x9c, 0x00, 0x44, 0xb0, 0x03, 0x01, + 0x3c, 0xa8, 0xc4, 0xb6, 0xff, 0x38, 0xab, 0xb2, 0xba, 0xb6, 0xa0, 0x4e, 0xcc, 0xf8, + 0xe4, 0xab, 0x44, 0xb6, 0xff, 0x32, 0xab, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x46, 0xb6, + 0xff, 0x34, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0xab, 0x48, 0xb6, 0xff, 0x36, 0xab, 0xa2, + 0x06, 0xcc, 0xa8, 0xab, 0x4a, 0xa2, 0x08, 0xcc, 0xa8, 0xab, 0x4c, 0xa8, 0x4e, 0xb6, + 0xff, 0x30, 0xab, 0xbc, 0x13, 0x7e, 0x47, 0xb8, 0x00, 0x0a, 0xab, 0x4e, 0x00, 0x3c, + 0xb7, 0x00, 0x00, 0x4e, 0x66, 0x83, 0x00, 0xb8, 0x00, 0xab, 0xac, 0xcc, 0x28, 0xac, + 0xca, 0x2a, 0xab, 0xca, 0xa8, 0x50, 0xb8, 0x00, 0x0a, 0x96, 0x4e, 0xfc, 0x94, 0x2e, + 0xb2, 0xba, 0xb6, 0xa0, 0x50, 0xcc, 0xf8, 0xa8, 0x02, 0xe6, 0xa8, 0xca, 0xa2, 0x02, + 0xcc, 0xab, 0xa8, 0x04, 0xa2, 0x04, 0xcc, 0xab, 0xa8, 0x06, 0xa2, 0x06, 0xcc, 0xab, + 0xa8, 0x50, 0xb8, 0x00, 0x0a, 0xbc, 0x13, 0x7e, 0x00, 0xab, 0x50, 0xac, 0x28, 0xcc, + 0xac, 0x2a, 0xca, 0x3c, 0xb6, 0xff, 0x06, 0xa9, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0xc5, 0x2f, 0x14, 0x2b, 0x02, 0x45, 0x00, 0x0e, 0x00, + 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, + 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x80, 0x38, 0x01, 0x00, + 0x00, 0x35, 0x0c, 0x00, 0x00, 0x12, 0x7a, 0x00, 0x00, 0xb4, 0xc4, 0x04, 0x00, 0x08, + 0xaf, 0x2f, 0x0a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, + 0x10, 0x27, 0x00, 0x00, 0xa0, 0x86, 0x01, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x80, 0x96, + 0x98, 0x00, 0x00, 0xe1, 0xf5, 0x05, 0x00, 0xca, 0x9a, 0x3b, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xaf, 0x02, 0xb7, 0x00, 0x00, 0x02, 0x82, 0x0b, 0x02, 0xfc, + 0x94, 0x20, 0xae, 0xca, 0xa2, 0x02, 0xcc, 0xfc, 0x53, 0xa2, 0x02, 0xcc, 0xfd, 0x41, + 0x53, 0xae, 0xca, 0xa9, 0x02, 0xa9, 0xcc, 0xa9, 0xcc, 0xa9, 0xcc, 0xa9, 0xcc, 0x7f, + 0xae, 0xca, 0xfc, 0x6e, 0xfd, 0x70, 0xa8, 0x02, 0x3f, 0x02, 0x3c, 0x90, 0x00, 0xa2, + 0x76, 0xce, 0xab, 0x90, 0x00, 0xb5, 0x32, 0x51, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xac, 0xce, 0xcc, 0x82, 0x70, 0xcc, 0xf8, + 0xb4, 0x26, 0xc8, 0xb7, 0x00, 0x00, 0x02, 0xac, 0xce, 0xcc, 0x82, 0x7a, 0xcc, 0xf8, + 0x82, 0x05, 0x02, 0xfc, 0x55, 0x00, 0xe6, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, + 0xab, 0xa2, 0x06, 0xcc, 0xab, 0xa9, 0x02, 0x82, 0x08, 0xcc, 0xf8, 0x79, 0x00, 0xa2, + 0x78, 0xce, 0x8b, 0x90, 0x01, 0xa2, 0x76, 0xce, 0xab, 0xa2, 0x10, 0xce, 0x88, 0xe7, + 0xb8, 0x46, 0x00, 0xad, 0xc8, 0xa8, 0xa2, 0x72, 0xce, 0xab, 0xb5, 0x31, 0x9c, 0x90, + 0x01, 0xb5, 0x31, 0xf3, 0xb7, 0x5e, 0x10, 0x02, 0xb7, 0x00, 0x5f, 0x04, 0xb7, 0x05, + 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x70, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb4, + 0x26, 0x67, 0xb5, 0x31, 0xb1, 0xab, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xa2, 0x72, 0xce, + 0xa8, 0x02, 0x96, 0x02, 0xeb, 0xab, 0x02, 0x90, 0x00, 0x96, 0x04, 0xeb, 0xab, 0x04, + 0xa2, 0x10, 0xce, 0x88, 0xe7, 0xb8, 0x46, 0x00, 0xad, 0xc8, 0xa8, 0xa2, 0x72, 0xce, + 0xab, 0xb5, 0x31, 0x51, 0xaf, 0x02, 0xaf, 0x04, 0xb7, 0x5e, 0x10, 0x02, 0xb7, 0x00, + 0x5f, 0x04, 0xb7, 0x05, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x70, 0xcc, 0xf8, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0x26, 0x1d, 0x3f, 0x04, 0x3f, 0x02, 0xac, 0x76, 0xce, 0xb7, + 0x00, 0x00, 0x06, 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, 0x0a, 0xb7, 0x00, 0x00, + 0x0c, 0xb7, 0x00, 0x00, 0x0e, 0xac, 0xce, 0xcc, 0x82, 0x7a, 0xcc, 0xf8, 0x82, 0x05, + 0x0e, 0xfc, 0x94, 0x2b, 0xe4, 0x03, 0x96, 0x06, 0xf8, 0xab, 0x06, 0xa2, 0x02, 0xcc, + 0xa8, 0x96, 0x08, 0xe8, 0xab, 0x08, 0xa2, 0x04, 0xcc, 0xa8, 0x03, 0x96, 0x0a, 0xf8, + 0xab, 0x0a, 0xa2, 0x06, 0xcc, 0xa8, 0x96, 0x0c, 0xe8, 0xab, 0x0c, 0xa9, 0x0e, 0x82, + 0x08, 0xcc, 0xf8, 0x95, 0x2f, 0xa2, 0x78, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x9e, 0x08, + 0xac, 0xcc, 0xce, 0xa0, 0xc8, 0xcc, 0xf8, 0x82, 0x7a, 0xcc, 0xf8, 0xe4, 0xa2, 0x02, + 0xcc, 0xf8, 0x9d, 0x00, 0x94, 0x88, 0xa2, 0x06, 0xcc, 0xa8, 0x9d, 0x1e, 0x94, 0x53, + 0x9c, 0x1e, 0x94, 0x41, 0xe4, 0xa2, 0x02, 0xcc, 0xfa, 0x9d, 0x00, 0x94, 0x73, 0xa8, + 0x02, 0x96, 0x04, 0xfa, 0x9c, 0x00, 0x94, 0x6a, 0x96, 0xc9, 0x17, 0x94, 0x65, 0xa2, + 0x06, 0xcc, 0xa8, 0x9d, 0x00, 0x94, 0x30, 0x9c, 0x00, 0x41, 0x4c, 0xa2, 0x04, 0xcc, + 0xa8, 0x9c, 0x40, 0x94, 0x24, 0x9d, 0x40, 0x94, 0x20, 0xa8, 0x0c, 0x9d, 0x00, 0x5b, + 0x9c, 0x00, 0x42, 0x94, 0x43, 0xa8, 0x0a, 0xbd, 0x02, 0x00, 0x50, 0x94, 0x3b, 0xa2, + 0x04, 0xcc, 0xa8, 0xbc, 0x84, 0x80, 0x46, 0xbd, 0x84, 0x80, 0x42, 0x95, 0x4d, 0xa2, + 0x78, 0xce, 0x88, 0x04, 0x9c, 0x05, 0x00, 0x9d, 0x05, 0x00, 0xa2, 0x78, 0xce, 0x8b, + 0xac, 0xce, 0xcc, 0x9e, 0x08, 0xac, 0xcc, 0xce, 0xa0, 0xc8, 0xcc, 0xf8, 0x82, 0x7a, + 0xcc, 0xf8, 0x00, 0xa2, 0x04, 0xcc, 0xab, 0xa2, 0x06, 0xcc, 0xab, 0xe6, 0xa2, 0x02, + 0xcc, 0xab, 0xe4, 0x03, 0x96, 0x02, 0xf8, 0xe6, 0xa2, 0x02, 0xcc, 0xa8, 0x96, 0x04, + 0xe8, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0x03, 0xb8, 0x00, 0x04, 0xa2, + 0x04, 0xcc, 0xab, 0xa2, 0x06, 0xcc, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x06, 0xcc, + 0xab, 0xa8, 0x06, 0x03, 0x96, 0x02, 0xf8, 0xab, 0x06, 0xa8, 0x08, 0x96, 0x04, 0xe8, + 0xab, 0x08, 0xa8, 0x0a, 0x03, 0xb8, 0x00, 0x04, 0xab, 0x0a, 0xa8, 0x0c, 0x82, 0x00, + 0xc8, 0xe8, 0xab, 0x0c, 0xa2, 0x74, 0xce, 0x88, 0xab, 0x0e, 0xa8, 0x06, 0xac, 0x08, + 0xca, 0xb2, 0x46, 0x4c, 0x36, 0x4c, 0xab, 0x10, 0xa8, 0x0a, 0xac, 0x0c, 0xca, 0xb2, + 0x46, 0x20, 0x36, 0x58, 0xab, 0x12, 0x02, 0x96, 0x10, 0xeb, 0xb8, 0x00, 0x06, 0xa2, + 0x74, 0xce, 0x8b, 0xa2, 0x11, 0xce, 0x88, 0xa2, 0x74, 0xce, 0xdd, 0x94, 0xe9, 0xa2, + 0x74, 0xce, 0xdc, 0x94, 0xe3, 0xa8, 0x02, 0x96, 0x04, 0xfa, 0x9c, 0x00, 0x94, 0x23, + 0xa2, 0x6c, 0xce, 0xa8, 0x03, 0x96, 0x02, 0xf8, 0xa2, 0x6c, 0xce, 0xab, 0xa2, 0x6e, + 0xce, 0xa8, 0x96, 0x04, 0xe8, 0xa2, 0x6e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, + 0x18, 0xb0, 0x40, 0x35, 0xb5, 0x40, 0x59, 0xa8, 0x0e, 0xa2, 0x74, 0xce, 0xdc, 0x4c, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x33, 0xb5, 0x40, 0x46, 0xa2, 0x10, + 0xce, 0x88, 0xa2, 0x74, 0xce, 0xdd, 0x94, 0x46, 0xa2, 0x74, 0xce, 0xdc, 0x94, 0x40, + 0xa2, 0x11, 0xce, 0x88, 0xa2, 0x74, 0xce, 0xdd, 0x5e, 0xa2, 0x74, 0xce, 0xdc, 0x59, + 0xa2, 0x12, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xa2, 0x12, 0xce, 0x8b, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x40, 0xb4, 0x40, 0x0f, 0xa2, 0x12, 0xce, + 0x88, 0x9d, 0x00, 0x7f, 0x90, 0x01, 0xa2, 0x12, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, + 0xab, 0x18, 0xb0, 0x40, 0x40, 0xb4, 0x3f, 0xf6, 0x90, 0x01, 0xa2, 0x40, 0xce, 0x8b, + 0xb6, 0xff, 0x08, 0xa9, 0xa2, 0x68, 0xce, 0xa8, 0x03, 0xb8, 0x00, 0x01, 0xa2, 0x68, + 0xce, 0xab, 0xa2, 0x6a, 0xce, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x6a, 0xce, 0xab, + 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xfc, 0x07, 0xb7, 0x02, 0x11, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, + 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xfb, 0xf4, 0xa2, 0x22, 0xce, 0x88, + 0xab, 0x18, 0xb0, 0x40, 0x34, 0xb4, 0x3f, 0xa2, 0x90, 0x00, 0x96, 0x08, 0xfd, 0x4e, + 0x96, 0x08, 0xfc, 0x42, 0x95, 0xed, 0x90, 0x05, 0x96, 0x06, 0xfd, 0x42, 0x95, 0xf5, + 0x90, 0x0f, 0xa2, 0x11, 0xce, 0xdd, 0x47, 0xa2, 0x74, 0xce, 0x8b, 0xb4, 0xfe, 0xfb, + 0xa2, 0x11, 0xce, 0x88, 0x04, 0x6c, 0xa2, 0x6c, 0x76, 0xa8, 0x03, 0xa2, 0x72, 0x76, + 0xf8, 0xa2, 0x6c, 0x76, 0xab, 0xa2, 0x6e, 0x76, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, + 0x6e, 0x76, 0xab, 0xa2, 0x10, 0x76, 0x88, 0xa2, 0x74, 0x76, 0x8b, 0xa2, 0x22, 0x76, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x35, 0xb5, 0x3f, 0x4d, 0xa2, 0x22, 0x76, 0x88, 0xab, + 0x18, 0xb0, 0x40, 0x33, 0xb5, 0x3f, 0x41, 0x90, 0x01, 0xa2, 0x40, 0x76, 0x8b, 0xa2, + 0x68, 0x76, 0xa8, 0x03, 0xb8, 0x00, 0x01, 0xa2, 0x68, 0x76, 0xab, 0xa2, 0x6a, 0x76, + 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x6a, 0x76, 0xab, 0xb7, 0x05, 0x02, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0x76, 0x88, 0xb5, 0xfb, 0x56, + 0xb7, 0x02, 0x11, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0x76, 0x88, 0xb5, 0xfb, 0x43, 0xa2, 0x22, 0x76, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x34, + 0xb4, 0x3e, 0xf1, 0x90, 0x03, 0xb5, 0x2e, 0x21, 0x90, 0x01, 0xb5, 0x2e, 0x78, 0xa2, + 0x0c, 0x76, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x4a, 0xa2, 0x0f, 0x72, 0x88, 0x9c, 0x00, + 0x43, 0xb5, 0x2e, 0xab, 0x90, 0x02, 0xa2, 0x76, 0x76, 0xab, 0x90, 0x01, 0xa2, 0x42, + 0x76, 0x8b, 0x3c, 0xa8, 0x46, 0xb5, 0xf9, 0x70, 0xa8, 0x44, 0xbc, 0x05, 0xff, 0x53, + 0xac, 0x76, 0xce, 0xa2, 0x76, 0x76, 0xa8, 0x9c, 0x00, 0x59, 0x9c, 0x01, 0x94, 0x23, + 0x9c, 0x02, 0x94, 0x33, 0x3c, 0xa2, 0x70, 0x76, 0xa8, 0x96, 0x48, 0xfc, 0x41, 0x3c, + 0x00, 0xa2, 0x70, 0x76, 0xab, 0x95, 0x21, 0xa8, 0x44, 0xbc, 0x05, 0x01, 0xb4, 0xfb, + 0xe8, 0xbc, 0x05, 0x03, 0x95, 0x63, 0x3c, 0xa8, 0x44, 0xbc, 0x05, 0x02, 0xb4, 0xfb, + 0xb8, 0xbc, 0x05, 0x05, 0x95, 0xfa, 0xbc, 0x05, 0xff, 0xb4, 0xfc, 0x30, 0x3c, 0xa8, + 0x44, 0xbc, 0x05, 0x05, 0x49, 0xbc, 0x05, 0x02, 0x50, 0xbc, 0x05, 0x04, 0x4c, 0x3c, + 0x90, 0x00, 0xa2, 0x42, 0x76, 0x8b, 0x90, 0x00, 0xb4, 0x2d, 0xee, 0xb5, 0xfb, 0x8f, + 0xa2, 0x0c, 0x76, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x4a, 0xa2, 0x0f, 0x72, 0x88, 0x9c, + 0x00, 0x43, 0xb5, 0x2e, 0x1f, 0xa8, 0x44, 0xbc, 0x05, 0x04, 0x41, 0x3c, 0xa2, 0x42, + 0x76, 0x88, 0x9c, 0x00, 0x4e, 0x00, 0xa2, 0x40, 0x76, 0x8b, 0xa2, 0x30, 0x76, 0xab, + 0xa2, 0x32, 0x76, 0xab, 0x3c, 0xa2, 0x30, 0x76, 0xa8, 0x03, 0xb8, 0x00, 0x01, 0xa2, + 0x30, 0x76, 0xab, 0xa2, 0x32, 0x76, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x32, 0x76, + 0xab, 0xa2, 0x22, 0x76, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x2a, 0xb4, 0x3e, 0x07, 0x00, + 0xab, 0xca, 0xa2, 0x15, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0xa8, 0xca, 0xa2, 0x14, 0x72, + 0x8b, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2b, 0xb5, 0x3d, 0xed, 0xb7, 0x02, 0x12, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x10, 0x72, 0x88, 0xb5, + 0xfa, 0x20, 0xb7, 0x02, 0x12, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xfa, 0x0d, 0xb7, 0x00, 0x00, 0x08, 0x82, 0x01, 0x08, + 0xfc, 0x3c, 0xa8, 0x08, 0xb5, 0xf8, 0x53, 0xa2, 0x00, 0x74, 0xa8, 0x9c, 0x00, 0x51, + 0xb7, 0x04, 0x0c, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, + 0xb5, 0xf9, 0xe7, 0xa9, 0x08, 0x95, 0x24, 0xac, 0x02, 0x0a, 0xac, 0x04, 0x0c, 0xb7, + 0x00, 0x00, 0x10, 0xa8, 0x02, 0xb5, 0xf8, 0x28, 0xa8, 0x04, 0x9c, 0x02, 0x94, 0x40, + 0xa8, 0x0a, 0xb5, 0xf8, 0x31, 0xa2, 0x66, 0x76, 0xa8, 0x9c, 0x00, 0x52, 0x9c, 0x04, + 0x55, 0x9c, 0x02, 0x5a, 0x9c, 0x01, 0x5d, 0x9c, 0x05, 0x94, 0x1f, 0x9c, 0x03, 0x5c, + 0x94, 0x49, 0xb7, 0x00, 0x01, 0x10, 0x94, 0x43, 0xa2, 0x0a, 0x76, 0xa8, 0xab, 0x0e, + 0x94, 0x3b, 0xb7, 0x00, 0x02, 0x0e, 0x94, 0x35, 0xb7, 0x00, 0x01, 0x0e, 0x94, 0x2f, + 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x72, 0x6d, 0xa2, 0x56, 0x74, 0xa8, 0x9c, 0x00, + 0x5b, 0x9c, 0x04, 0x51, 0x9c, 0x02, 0x49, 0x9c, 0x01, 0x41, 0x56, 0xb7, 0x00, 0x01, + 0x0e, 0x51, 0xb7, 0x00, 0x02, 0x0e, 0x4c, 0xa2, 0x06, 0x74, 0xa8, 0xab, 0x0e, 0x45, + 0xb7, 0x00, 0x01, 0x10, 0x40, 0x82, 0x00, 0x10, 0xfd, 0x94, 0xf1, 0xa8, 0x0e, 0x05, + 0xab, 0x12, 0x82, 0x02, 0x0c, 0xfc, 0x5c, 0xa8, 0x12, 0x9e, 0x04, 0xac, 0x76, 0xcc, + 0x82, 0x1a, 0xcc, 0xf8, 0xa0, 0xc8, 0xcc, 0xf8, 0xa2, 0x02, 0xcc, 0x88, 0xab, 0x0a, + 0xa2, 0x03, 0xcc, 0x88, 0xab, 0x0c, 0x5b, 0xa8, 0x12, 0x9e, 0x04, 0xac, 0x74, 0xcc, + 0x82, 0x58, 0xcc, 0xf8, 0xa0, 0xc8, 0xcc, 0xf8, 0xa2, 0x02, 0xcc, 0x88, 0xab, 0x0a, + 0xa2, 0x03, 0xcc, 0x88, 0xab, 0x0c, 0x82, 0x02, 0x0c, 0xfc, 0x94, 0x71, 0xa8, 0x0a, + 0xb5, 0xf7, 0x7d, 0xa2, 0x66, 0x76, 0xa8, 0x9c, 0x00, 0x5a, 0x9c, 0x04, 0x51, 0x9c, + 0x02, 0x5a, 0x9c, 0x01, 0x94, 0x20, 0x9c, 0x05, 0x94, 0x26, 0x9c, 0x03, 0x94, 0x45, + 0x95, 0x6b, 0xa8, 0x0e, 0xa2, 0x0a, 0x76, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0x77, + 0x82, 0x02, 0x0e, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0x81, 0x82, 0x01, 0x0e, 0xfc, + 0xb7, 0x00, 0x01, 0x10, 0x95, 0x8b, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x4b, 0x82, + 0x02, 0x0e, 0xfc, 0x51, 0xb7, 0x00, 0x02, 0x0e, 0x95, 0x9d, 0x82, 0x01, 0x0e, 0xfc, + 0x46, 0xb7, 0x00, 0x01, 0x0e, 0x95, 0xa8, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xae, 0x90, + 0x03, 0x02, 0x96, 0x0e, 0xeb, 0x9d, 0x00, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xbc, 0xa8, + 0x0a, 0xb5, 0xf6, 0xf8, 0xa2, 0x56, 0x74, 0xa8, 0x9c, 0x00, 0x95, 0xc9, 0x9c, 0x04, + 0x48, 0x9c, 0x02, 0x52, 0x9c, 0x01, 0x59, 0x95, 0xd4, 0xa2, 0x06, 0x74, 0xa8, 0x96, + 0x0e, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xe1, 0x82, 0x02, 0x0e, 0xfc, 0xb7, 0x00, + 0x01, 0x10, 0x95, 0xeb, 0x82, 0x01, 0x0e, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xf5, + 0xac, 0x0a, 0x06, 0xac, 0x0c, 0x08, 0x3c, 0xab, 0x22, 0xb5, 0xf6, 0xcc, 0xa2, 0x54, + 0x76, 0x88, 0x9c, 0x00, 0x5e, 0xa2, 0x32, 0x72, 0xa8, 0x05, 0xa2, 0x32, 0x72, 0xab, + 0x90, 0x00, 0xa2, 0x54, 0x76, 0x8b, 0xb7, 0x00, 0x00, 0x06, 0xac, 0x76, 0xcc, 0x82, + 0x52, 0xcc, 0xf8, 0x00, 0xb5, 0x20, 0x10, 0xa2, 0x30, 0x72, 0xa8, 0x02, 0xa2, 0x32, + 0x72, 0xeb, 0x9c, 0x00, 0x3c, 0x96, 0xc9, 0x17, 0x3c, 0xab, 0x0a, 0xa8, 0x22, 0x96, + 0x7e, 0xdd, 0xb0, 0xff, 0xff, 0x04, 0xab, 0x0c, 0xb7, 0x00, 0x00, 0x0e, 0x80, 0x7e, + 0x0e, 0xfc, 0x3c, 0x82, 0x00, 0x0a, 0xfc, 0x3c, 0xa8, 0x0c, 0xb5, 0xf6, 0x77, 0xa2, + 0x0e, 0x76, 0xa8, 0x9c, 0x00, 0x94, 0x2c, 0xa2, 0x55, 0x76, 0x88, 0x9c, 0x00, 0x94, + 0x24, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x03, 0x41, 0x5c, 0x90, 0x00, 0xa2, 0x55, 0x76, + 0x8b, 0xb7, 0x02, 0x14, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, + 0x0c, 0xb5, 0xf7, 0xe0, 0xa8, 0x0a, 0x05, 0xab, 0x0a, 0xa8, 0x0c, 0x96, 0x7e, 0xdd, + 0xb0, 0xff, 0xff, 0x04, 0xab, 0x0c, 0x95, 0x4e, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, + 0x94, 0x44, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x04, 0x94, 0x3c, 0xb5, 0x23, 0x0b, 0x9c, + 0x00, 0x94, 0x2f, 0x90, 0x02, 0xa2, 0x1e, 0x72, 0x8b, 0x00, 0x96, 0x7e, 0xdc, 0x94, + 0x29, 0xab, 0x0a, 0xb5, 0xf6, 0x22, 0xa2, 0x12, 0x78, 0xa8, 0x9c, 0x00, 0x52, 0x90, + 0x00, 0xa2, 0x12, 0x78, 0xab, 0xb0, 0x32, 0x0e, 0xa2, 0x10, 0x78, 0x88, 0xab, 0x18, + 0xb5, 0x3b, 0x47, 0xa8, 0x0a, 0x04, 0x95, 0x26, 0x90, 0x03, 0xa2, 0x1e, 0x72, 0x8b, + 0x90, 0x00, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb4, + 0x3b, 0x2c, 0x90, 0x01, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, + 0x18, 0xb5, 0x3b, 0x1c, 0x90, 0x01, 0x36, 0xec, 0xb7, 0x00, 0x00, 0x0a, 0x82, 0x01, + 0x0a, 0xfc, 0x94, 0x2b, 0xa8, 0x0a, 0xb5, 0xf5, 0xa3, 0xa2, 0x00, 0x74, 0xa8, 0x9c, + 0x00, 0x5b, 0xb7, 0x04, 0x0e, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa8, 0x0a, 0xb5, 0xf7, 0x37, 0xaf, 0x0a, 0xac, 0x74, 0xce, 0xb5, 0x18, 0xa3, 0x3f, + 0x0a, 0xa9, 0x0a, 0x95, 0x2f, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, + 0xa8, 0x0a, 0xb5, 0xf5, 0x83, 0xa2, 0x0e, 0x76, 0xa8, 0x9c, 0x00, 0x51, 0xb7, 0x02, + 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x0a, 0xb5, 0xf7, + 0x03, 0xa9, 0x0a, 0x95, 0x24, 0x90, 0x02, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, + 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x3a, 0xa9, 0xa2, 0x02, 0x72, 0xa8, 0xab, 0x02, 0xa2, + 0x04, 0x72, 0xa8, 0xab, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, + 0xcc, 0xf8, 0x00, 0xb4, 0x1e, 0xad, 0x90, 0x03, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, + 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x3a, 0x7e, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, + 0x0a, 0xfc, 0x94, 0x21, 0xa8, 0x0a, 0xb5, 0xf5, 0x1d, 0xa2, 0x0e, 0x76, 0xa8, 0x9c, + 0x00, 0x51, 0xb7, 0x02, 0x04, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa8, 0x0a, 0xb5, 0xf6, 0x9d, 0xa9, 0x0a, 0x95, 0x25, 0xb7, 0x00, 0x00, 0x0a, 0x82, + 0x01, 0x0a, 0xfc, 0x94, 0x21, 0xa8, 0x0a, 0xb5, 0xf4, 0xde, 0xa2, 0x00, 0x74, 0xa8, + 0x9c, 0x00, 0x51, 0xb7, 0x04, 0x0e, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa8, 0x0a, 0xb5, 0xf6, 0x72, 0xa9, 0x0a, 0x95, 0x25, 0xb7, 0x1e, 0x84, 0x02, + 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, 0xcc, + 0xf8, 0x00, 0xb4, 0x1e, 0x30, 0x90, 0x04, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, + 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x3a, 0x01, 0x90, 0x01, 0xa2, 0x1e, 0x72, 0x8b, 0xb5, + 0x21, 0x8e, 0x9c, 0x00, 0x94, 0x3b, 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x02, 0x04, + 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb5, 0xf6, 0x2a, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, + 0x0a, 0xfc, 0x3c, 0xa8, 0x0a, 0xb5, 0xf4, 0x98, 0xa2, 0x12, 0x78, 0xa8, 0x9c, 0x00, + 0x52, 0x90, 0x00, 0xa2, 0x12, 0x78, 0xab, 0xb0, 0x32, 0x0e, 0xa2, 0x10, 0x78, 0x88, + 0xab, 0x18, 0xb5, 0x39, 0xbd, 0xa9, 0x0a, 0x95, 0x25, 0xb7, 0x01, 0x04, 0x02, 0xb7, + 0x00, 0x03, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xf5, 0xef, 0x90, 0x05, 0xa2, + 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x39, 0x99, 0x90, + 0x00, 0xb5, 0x22, 0xc4, 0xb7, 0xf4, 0x24, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x01, + 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, 0xcc, 0xf8, 0x00, 0xb4, 0x1d, 0x9c, 0xa2, + 0x1e, 0x72, 0x88, 0x9c, 0x02, 0x42, 0x95, 0x9b, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x02, + 0x49, 0x90, 0x00, 0xa2, 0x16, 0x72, 0x8b, 0xb4, 0xfe, 0x38, 0x90, 0x06, 0xa2, 0x2e, + 0xce, 0xf9, 0x9d, 0x00, 0x94, 0x33, 0xa2, 0x16, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0x90, + 0x41, 0xa2, 0x2e, 0xce, 0xf9, 0x9c, 0x00, 0x50, 0x90, 0x02, 0xa2, 0x2e, 0xcc, 0xf9, + 0x9c, 0x00, 0x47, 0x90, 0x01, 0xa2, 0x16, 0x72, 0x8b, 0x3c, 0x90, 0x02, 0xa2, 0x2e, + 0xce, 0xf9, 0x9c, 0x00, 0x3c, 0x90, 0x41, 0xa2, 0x2e, 0xcc, 0xf9, 0x9c, 0x00, 0x3c, + 0x79, 0x90, 0x06, 0xa2, 0x2e, 0xcc, 0xf9, 0x9c, 0x00, 0x95, 0x3b, 0x90, 0x00, 0xa2, + 0x16, 0x72, 0x8b, 0xb4, 0xfd, 0xe8, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x06, 0x50, 0x90, + 0x06, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x38, + 0xfd, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xf3, 0xa4, 0xac, 0x76, 0x24, 0xa2, 0x11, 0x72, + 0x88, 0xb5, 0xf3, 0x9a, 0xac, 0x76, 0x26, 0xa2, 0x0e, 0x24, 0xa8, 0x9c, 0x00, 0x57, + 0xa2, 0x22, 0x24, 0x88, 0xb5, 0x23, 0xa5, 0xa2, 0x2e, 0x24, 0xab, 0xa2, 0x22, 0x24, + 0x88, 0xb5, 0x23, 0x9a, 0xa2, 0x2e, 0x24, 0xab, 0x46, 0x90, 0x02, 0xa2, 0x2e, 0x24, + 0xab, 0xa2, 0x0e, 0x26, 0xa8, 0x9c, 0x00, 0x56, 0xa2, 0x22, 0x26, 0x88, 0xb5, 0x23, + 0x81, 0xa2, 0x2e, 0x26, 0xab, 0xa2, 0x22, 0x26, 0x88, 0xb5, 0x23, 0x76, 0xa2, 0x2e, + 0x26, 0xab, 0x90, 0x02, 0xa2, 0x2e, 0x26, 0xab, 0xac, 0x24, 0xce, 0xac, 0x26, 0xcc, + 0x34, 0xe1, 0xa2, 0x16, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0xc4, 0xb4, 0x02, 0xb7, + 0x00, 0x04, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, 0xcc, 0xf8, + 0x00, 0xb4, 0x1c, 0x9b, 0x90, 0x07, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, + 0x00, 0x00, 0x18, 0xb5, 0x38, 0x6c, 0x90, 0x01, 0xb5, 0x21, 0x97, 0xb7, 0x98, 0x96, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, + 0xcc, 0xf8, 0x00, 0xb4, 0x1c, 0x6f, 0x82, 0x02, 0x04, 0xfc, 0x42, 0x94, 0x22, 0xa8, + 0x02, 0xb5, 0xf2, 0xde, 0xa2, 0x54, 0x74, 0xa8, 0xaf, 0xc8, 0xb5, 0xf2, 0xfd, 0xa2, + 0x12, 0x78, 0xa8, 0x9a, 0x01, 0xa2, 0x12, 0x78, 0xab, 0x3f, 0xc8, 0xab, 0x18, 0xb0, + 0x32, 0x0e, 0xb5, 0x38, 0x27, 0xb5, 0xfa, 0x87, 0x82, 0x02, 0x08, 0xfc, 0x94, 0x32, + 0xa8, 0x06, 0xb5, 0xf2, 0xc7, 0xa2, 0x64, 0x76, 0xa8, 0xaf, 0xc8, 0xb5, 0xf2, 0xd2, + 0xa2, 0x12, 0x78, 0xa8, 0x9a, 0x02, 0xa2, 0x12, 0x78, 0xab, 0x3f, 0xc8, 0xab, 0x18, + 0xb0, 0x32, 0x0e, 0xb5, 0x37, 0xfc, 0xb7, 0x02, 0x03, 0x02, 0xac, 0x08, 0x04, 0xa8, + 0x06, 0xb7, 0x00, 0x00, 0x06, 0xb4, 0xf4, 0x32, 0xa8, 0x06, 0xb5, 0xf2, 0x81, 0xa2, + 0x54, 0x74, 0xa8, 0xaf, 0xc8, 0xb5, 0xf2, 0xa0, 0xa2, 0x12, 0x78, 0xa8, 0x9a, 0x04, + 0xa2, 0x12, 0x78, 0xab, 0x3f, 0xc8, 0xab, 0x18, 0xb0, 0x32, 0x0e, 0xb5, 0x37, 0xca, + 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, + 0xf4, 0x00, 0x36, 0xd4, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, 0xa8, + 0x0a, 0xb5, 0xf2, 0x6c, 0x90, 0x03, 0xa2, 0x12, 0x78, 0xf9, 0x9d, 0x00, 0x43, 0xa9, + 0x0a, 0x75, 0xa2, 0x12, 0x78, 0xa8, 0x9a, 0x08, 0xa2, 0x12, 0x78, 0xab, 0xa2, 0x10, + 0x78, 0x88, 0xab, 0x18, 0xb0, 0x32, 0x0e, 0xb5, 0x37, 0x88, 0x79, 0xa8, 0x44, 0xbc, + 0x01, 0x04, 0xb4, 0x01, 0xd8, 0xa8, 0x44, 0xbc, 0x01, 0xff, 0xb4, 0x01, 0xc0, 0xa2, + 0x20, 0x72, 0xa8, 0x9c, 0x00, 0xb4, 0x01, 0x8e, 0x9c, 0x01, 0xb4, 0x01, 0x0a, 0x9c, + 0x02, 0x94, 0xc3, 0x9c, 0x03, 0x51, 0x9c, 0x04, 0x94, 0x98, 0x9c, 0x05, 0x94, 0x6e, + 0x9c, 0x06, 0x94, 0x43, 0x9c, 0x07, 0x94, 0x75, 0x3c, 0xa8, 0x44, 0xbc, 0x01, 0xff, + 0x4a, 0xbc, 0x01, 0x01, 0x5b, 0xbc, 0x01, 0x02, 0x94, 0x20, 0x3c, 0xa2, 0x1e, 0x72, + 0x88, 0x9c, 0x04, 0xb4, 0xfd, 0x27, 0xa2, 0x00, 0x72, 0x88, 0x9c, 0x00, 0xb4, 0xfb, + 0xa7, 0xb4, 0xfe, 0xb0, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, 0xb4, 0xfb, 0xf7, 0x3c, + 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x04, 0x41, 0x3c, 0x90, 0x05, 0xa2, 0x1e, 0x72, 0x8b, + 0x3c, 0xa8, 0x44, 0xbc, 0x01, 0xff, 0xb4, 0xfd, 0xf7, 0xbc, 0x01, 0x02, 0xb4, 0xfe, + 0x89, 0x3c, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xf1, 0xab, 0xaf, 0x76, 0xa2, 0x11, 0x72, + 0x88, 0xb5, 0xf1, 0xa2, 0xac, 0x76, 0xcc, 0x3f, 0xce, 0xb4, 0xfd, 0x6f, 0xa8, 0x44, + 0xbc, 0x01, 0xff, 0xb4, 0xfd, 0xd0, 0xbc, 0x01, 0x02, 0xb4, 0xfe, 0x62, 0x3c, 0xa8, + 0x44, 0xbc, 0x01, 0xff, 0xb4, 0xfb, 0x4d, 0xbc, 0x01, 0x01, 0x41, 0x3c, 0xa2, 0x1e, + 0x72, 0x88, 0x9c, 0x02, 0xb4, 0xfd, 0x1e, 0x3c, 0xa8, 0x44, 0xbc, 0x01, 0x04, 0x45, + 0xbc, 0x01, 0x02, 0x4e, 0x3c, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x03, 0x46, 0x9c, 0x02, + 0xb4, 0xfb, 0x83, 0x3c, 0xa2, 0x00, 0x72, 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0x29, 0xb4, + 0xfb, 0x1a, 0xa8, 0x44, 0xbc, 0x01, 0x03, 0x53, 0xbc, 0x01, 0x02, 0x58, 0xbc, 0x01, + 0x04, 0x5d, 0xbc, 0x01, 0xff, 0x94, 0x22, 0xbc, 0x01, 0x07, 0x94, 0x26, 0x3c, 0xac, + 0x46, 0x02, 0xac, 0x48, 0x04, 0xb4, 0xfe, 0x30, 0x90, 0x05, 0xa2, 0x1e, 0x72, 0x8b, + 0xb4, 0xfb, 0xe9, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x04, 0xb4, 0xfb, 0xe0, 0x3c, 0x90, + 0x04, 0xa2, 0x1e, 0x72, 0x8b, 0xb4, 0xfe, 0xaa, 0xa8, 0x46, 0xb4, 0xfa, 0x3c, 0xa8, + 0x44, 0xbc, 0x01, 0x06, 0x94, 0x26, 0xbc, 0x01, 0x03, 0x57, 0xbc, 0x01, 0x02, 0x50, + 0xbc, 0x01, 0x07, 0x47, 0xbc, 0x01, 0x04, 0xb4, 0xfb, 0xb8, 0x3c, 0xa8, 0x46, 0xb4, + 0xfa, 0x1d, 0xb4, 0xfb, 0xaf, 0xac, 0x46, 0x02, 0xac, 0x48, 0x04, 0x36, 0x19, 0xb4, + 0xfb, 0x79, 0xa2, 0x14, 0x72, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x15, 0x72, 0x88, 0x9c, + 0x00, 0x56, 0xa2, 0x1a, 0x72, 0x88, 0x9d, 0x00, 0x4f, 0xa2, 0x1c, 0x72, 0x88, 0x9d, + 0x00, 0x48, 0xa2, 0x22, 0x72, 0xa8, 0x9c, 0x0c, 0x94, 0x29, 0xa2, 0x14, 0x72, 0x88, + 0x9d, 0x00, 0x3c, 0xa2, 0x15, 0x72, 0x88, 0x9c, 0x00, 0x4e, 0xa2, 0x1a, 0x72, 0x88, + 0x9c, 0x00, 0x4c, 0xa2, 0x1c, 0x72, 0x88, 0x9c, 0x00, 0x45, 0x90, 0x01, 0xb4, 0xf7, + 0xe7, 0xa2, 0x22, 0x72, 0xa8, 0x9c, 0x0c, 0x3c, 0x6c, 0x90, 0x00, 0xb4, 0xf7, 0xda, + 0xa8, 0x44, 0xbc, 0x01, 0x01, 0x4f, 0xbc, 0x01, 0x04, 0x41, 0x3c, 0xa2, 0x1e, 0x72, + 0x88, 0x9c, 0x04, 0xb4, 0xfa, 0x44, 0x3c, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, 0x41, + 0x3c, 0xa2, 0x00, 0x72, 0x88, 0x9c, 0x00, 0xb4, 0xfa, 0x8e, 0xb4, 0xfc, 0x0e, 0xa8, + 0x48, 0xa2, 0x18, 0x72, 0xfc, 0x41, 0x3c, 0x00, 0xa2, 0x18, 0x72, 0xab, 0xb4, 0xfe, + 0x30, 0xa8, 0x48, 0xa2, 0x1e, 0x72, 0x8b, 0xb4, 0xfe, 0x1f, 0xaf, 0xce, 0xac, 0x74, + 0xce, 0xb6, 0xb8, 0x02, 0x88, 0x99, 0x05, 0x9c, 0x00, 0x5a, 0xa2, 0x52, 0xce, 0xa8, + 0x9c, 0x03, 0x41, 0x52, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x21, 0xbd, 0x90, 0x05, 0x01, + 0xb6, 0xb8, 0x02, 0xd9, 0xb6, 0xb8, 0x02, 0x8b, 0xb6, 0xb8, 0x02, 0x88, 0x99, 0x06, + 0x9c, 0x00, 0x5a, 0xa2, 0x52, 0xce, 0xa8, 0x9c, 0x02, 0x41, 0x52, 0xa2, 0x22, 0xce, + 0x88, 0xb5, 0x21, 0x9a, 0x90, 0x06, 0x01, 0xb6, 0xb8, 0x02, 0xd9, 0xb6, 0xb8, 0x02, + 0x8b, 0xb6, 0xb8, 0x02, 0x88, 0x99, 0x08, 0x9c, 0x00, 0x94, 0x1f, 0xa2, 0x52, 0xce, + 0xa8, 0x9c, 0x01, 0x41, 0x57, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x21, 0x76, 0x90, 0x08, + 0x01, 0xb6, 0xb8, 0x02, 0xd9, 0xb6, 0xb8, 0x02, 0x8b, 0x00, 0xb6, 0xb8, 0x04, 0xab, + 0x3f, 0xce, 0x3c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x05, 0x00, + 0x01, 0x09, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x09, 0x0a, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, 0xa8, + 0x0a, 0xb5, 0xef, 0xb0, 0xa2, 0x14, 0x78, 0x88, 0x9c, 0x00, 0x4b, 0x90, 0x00, 0xa2, + 0x14, 0x78, 0x8b, 0xa8, 0x0a, 0xb5, 0x24, 0xb5, 0xa9, 0x0a, 0x7e, 0x90, 0x00, 0xa2, + 0x66, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x62, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, + 0x18, 0xb0, 0x40, 0x10, 0xb5, 0x34, 0xc1, 0x90, 0x04, 0xa2, 0x28, 0xce, 0x8b, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x0d, 0xb4, 0x34, 0xaf, 0x90, 0x01, 0xa2, + 0x66, 0xce, 0xab, 0x90, 0x03, 0xa2, 0x62, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x64, 0xce, + 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb5, 0x34, 0x91, 0xa2, + 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x41, 0x3c, 0xa2, 0x28, 0x72, 0xa8, 0xa2, 0x28, 0x72, + 0xa9, 0x9c, 0x01, 0xb4, 0x13, 0x33, 0x3c, 0x90, 0x02, 0xa2, 0x66, 0xce, 0xab, 0x90, + 0x02, 0xa2, 0x62, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x64, 0xce, 0xab, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb5, 0x34, 0x5d, 0xa2, 0x06, 0xce, 0xa8, 0x9c, + 0x03, 0x41, 0x3c, 0xa2, 0x2a, 0x72, 0xa8, 0xa2, 0x2a, 0x72, 0xa9, 0x9c, 0x01, 0xb4, + 0x12, 0xff, 0x3c, 0x90, 0x03, 0xa2, 0x66, 0xce, 0xab, 0x90, 0x05, 0xa2, 0x62, 0xce, + 0xab, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, 0x64, 0xce, 0xab, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb4, 0x34, 0x22, 0x90, 0x01, + 0x72, 0x90, 0x04, 0xa2, 0x66, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x62, 0xce, 0xab, 0xa2, + 0x0a, 0xce, 0xa8, 0x05, 0xa2, 0x64, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, + 0xb0, 0x40, 0x10, 0xb4, 0x33, 0xfe, 0x90, 0x05, 0xa2, 0x66, 0xce, 0xab, 0x90, 0x04, + 0xa2, 0x62, 0xce, 0xab, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, + 0x64, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb4, 0x33, + 0xd9, 0x90, 0x01, 0x72, 0xa2, 0x54, 0xce, 0xa8, 0xb5, 0xee, 0x91, 0xa2, 0x0c, 0x78, + 0xa8, 0xa2, 0x42, 0x74, 0xab, 0xa2, 0x0e, 0x78, 0xa8, 0xa2, 0x44, 0x74, 0xab, 0xa2, + 0x08, 0x78, 0xa8, 0xa2, 0x3e, 0x74, 0xab, 0xa2, 0x0a, 0x78, 0xa8, 0xa2, 0x40, 0x74, + 0xab, 0xa2, 0x04, 0x78, 0xa8, 0xa2, 0x46, 0x74, 0xab, 0xa2, 0x06, 0x78, 0xa8, 0xa2, + 0x48, 0x74, 0xab, 0xa2, 0x10, 0xce, 0xa8, 0xa2, 0x44, 0xce, 0xfd, 0x94, 0x52, 0xa2, + 0x44, 0xce, 0xfc, 0x94, 0x2f, 0xa2, 0x0c, 0xce, 0xa8, 0xa2, 0x40, 0xce, 0xfd, 0x94, + 0x3b, 0xa2, 0x40, 0xce, 0xfc, 0x94, 0x2a, 0xa2, 0x24, 0xce, 0xa8, 0xab, 0xca, 0x90, + 0x00, 0xa2, 0x24, 0xce, 0xab, 0x96, 0xca, 0xfc, 0x94, 0x31, 0xa2, 0x22, 0xce, 0x88, + 0xab, 0x18, 0xb0, 0x2f, 0x07, 0xb5, 0x33, 0x62, 0x94, 0x23, 0xa2, 0x0e, 0xce, 0xa8, + 0xa2, 0x42, 0xce, 0xfd, 0x54, 0x95, 0x38, 0xa2, 0x0a, 0xce, 0xa8, 0xa2, 0x3e, 0xce, + 0xfd, 0x42, 0x95, 0x33, 0x90, 0x02, 0xa2, 0x24, 0xce, 0xab, 0x46, 0x90, 0x01, 0xa2, + 0x24, 0xce, 0xab, 0xa2, 0x24, 0xce, 0xa8, 0x9c, 0x00, 0x3c, 0xb7, 0x04, 0x02, 0x02, + 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, + 0x69, 0xb7, 0x04, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xef, 0x56, 0x90, 0x00, 0xa2, 0x56, 0xce, 0xab, 0x90, 0x00, + 0xa2, 0x52, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x07, 0xb4, + 0x32, 0xf8, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x2b, 0xb7, 0x04, 0x01, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x18, 0x90, 0x00, + 0xa2, 0x56, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x52, 0xce, 0xab, 0xa2, 0x24, 0xce, 0xa8, + 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, 0x24, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, + 0x18, 0xb0, 0x2f, 0x07, 0xb5, 0x32, 0xad, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, + 0x20, 0x17, 0xb4, 0x32, 0xa1, 0x90, 0x01, 0xa2, 0x56, 0xce, 0xab, 0x90, 0x03, 0xa2, + 0x52, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x54, 0xce, 0xab, 0x35, 0x47, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x20, 0x17, 0xb5, 0x32, 0x81, 0xa2, 0x52, 0xce, 0xa8, 0x9c, + 0x03, 0x41, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xee, 0xac, 0xa2, 0x2c, 0x72, 0xa8, 0xa2, 0x2c, + 0x72, 0xa9, 0x9c, 0x01, 0xb4, 0x11, 0x10, 0x3c, 0x90, 0x02, 0xa2, 0x56, 0xce, 0xab, + 0x90, 0x02, 0xa2, 0x52, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x54, 0xce, 0xab, 0x35, 0x90, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x17, 0xb5, 0x32, 0x38, 0xa2, 0x52, + 0xce, 0xa8, 0x9c, 0x02, 0x41, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x01, 0x04, + 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xee, 0x63, 0xa2, 0x2e, 0x72, + 0xa8, 0xa2, 0x2e, 0x72, 0xa9, 0x9c, 0x01, 0xb4, 0x10, 0xc7, 0x3c, 0x90, 0x04, 0xa2, + 0x56, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x52, 0xce, 0xab, 0xa2, 0x06, 0xce, 0xa8, 0x05, + 0xa2, 0x54, 0xce, 0xab, 0x35, 0xdc, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, + 0x17, 0xb5, 0x31, 0xec, 0xa2, 0x52, 0xce, 0xa8, 0x9c, 0x01, 0x41, 0x3c, 0xb7, 0x04, + 0x01, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, + 0xb4, 0xee, 0x17, 0xa2, 0x66, 0xcc, 0xa8, 0xaf, 0xce, 0x9e, 0x06, 0x3f, 0xce, 0xab, + 0xca, 0xa2, 0x66, 0xce, 0xa8, 0x96, 0xca, 0xf8, 0xb8, 0x54, 0x54, 0xad, 0xc8, 0x88, + 0xab, 0x0c, 0xa2, 0x22, 0x72, 0xab, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2a, 0xb5, + 0x31, 0xa8, 0xb7, 0x00, 0x00, 0x0a, 0xa2, 0x29, 0xce, 0x88, 0x9c, 0x02, 0x42, 0x94, + 0x25, 0x82, 0x05, 0x0c, 0xfc, 0x4b, 0x82, 0x09, 0x0c, 0xfc, 0x46, 0x82, 0x07, 0x0c, + 0xfc, 0x41, 0x55, 0xb7, 0x00, 0x01, 0x0a, 0x57, 0x82, 0x06, 0x0c, 0xfc, 0x69, 0x82, + 0x0a, 0x0c, 0xfc, 0x6e, 0x82, 0x07, 0x0c, 0xfc, 0x73, 0x47, 0xa2, 0x29, 0xcc, 0x88, + 0x9c, 0x02, 0x76, 0xa2, 0x27, 0x72, 0x88, 0xa0, 0xc8, 0x0a, 0xfc, 0x50, 0xa8, 0x0a, + 0xa2, 0x27, 0x72, 0x8b, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2e, 0xb5, 0x31, 0x56, + 0xa2, 0x15, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xed, 0x85, 0xa2, 0x66, 0xce, 0xa8, 0xb8, + 0x54, 0x4e, 0xad, 0xc8, 0x88, 0xa2, 0x22, 0x72, 0xab, 0xab, 0x0a, 0xb7, 0x00, 0x00, + 0x18, 0xb0, 0x10, 0x2a, 0xb5, 0x31, 0x25, 0xb7, 0x00, 0x00, 0x0c, 0xa2, 0x29, 0xce, + 0x88, 0x9c, 0x02, 0x57, 0xa2, 0x27, 0x72, 0x88, 0x9c, 0x0c, 0x3c, 0xa8, 0x0c, 0xa2, + 0x27, 0x72, 0x8b, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2e, 0xb4, 0x31, 0x03, 0xa2, + 0x28, 0xce, 0x88, 0x9c, 0x02, 0x7d, 0x82, 0x08, 0x0a, 0xfc, 0x47, 0x82, 0x0b, 0x0a, + 0xfc, 0x42, 0x95, 0x28, 0xb7, 0x00, 0x01, 0x0c, 0x95, 0x2e, 0xa2, 0x66, 0xce, 0xa8, + 0x9c, 0x00, 0x56, 0x9c, 0x02, 0x94, 0xaa, 0x9c, 0x03, 0xb4, 0x01, 0x0c, 0x9c, 0x04, + 0xb4, 0x01, 0x66, 0x9c, 0x05, 0xb4, 0x01, 0x8d, 0xb4, 0x01, 0xf4, 0xa2, 0x3a, 0xce, + 0x88, 0x9c, 0x00, 0x56, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x4f, 0x37, 0xbc, 0xb6, + 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0xd7, 0xa2, 0x3a, + 0xce, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x56, 0xce, 0x88, 0x9c, 0x00, 0x56, 0xa2, 0x3a, + 0xcc, 0x88, 0x9c, 0x00, 0x4f, 0x37, 0xac, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, + 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0xb3, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x5e, 0xa2, + 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x57, 0x37, 0xa1, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x08, + 0xb6, 0xb8, 0x02, 0x8b, 0xa2, 0x0a, 0xce, 0xa8, 0xb6, 0xb8, 0x04, 0xab, 0xb4, 0x01, + 0x8e, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0x01, 0x85, 0xa2, 0x58, 0xce, 0x88, + 0x9c, 0x00, 0xb4, 0x01, 0x7c, 0x37, 0xa9, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x04, 0xb6, + 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0x6d, 0x90, 0x01, 0xb5, 0xeb, 0x03, 0x90, 0x01, 0xa2, + 0x14, 0x78, 0x8b, 0xb5, 0xfb, 0x5f, 0xb4, 0x01, 0x5c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, + 0x00, 0x77, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x7e, 0xa2, 0x3a, 0xce, 0x88, 0x9c, + 0x00, 0x94, 0x1f, 0xa2, 0x56, 0xce, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x3a, 0xcc, 0x88, + 0x9c, 0x00, 0x51, 0x90, 0x01, 0xb5, 0xea, 0xce, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, + 0xb5, 0xfb, 0xbc, 0xb4, 0x01, 0x27, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0x01, + 0x1e, 0xa2, 0x58, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0x01, 0x15, 0xb5, 0xfb, 0xed, 0xb6, + 0xb8, 0x02, 0x88, 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0x05, 0x90, 0x01, + 0xb5, 0xea, 0x9b, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0xf7, 0x94, 0xf5, + 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x76, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x7d, + 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x57, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x50, + 0x90, 0x01, 0xb5, 0xea, 0x6f, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfb, 0x29, + 0x94, 0xc9, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0xc1, 0xa2, 0x58, 0xce, 0x88, + 0x9c, 0x00, 0x94, 0xb9, 0x90, 0x01, 0xb5, 0xea, 0x4f, 0x90, 0x01, 0xa2, 0x14, 0x78, + 0x8b, 0xb5, 0xfb, 0x86, 0x94, 0xa9, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xb5, 0xea, 0x3c, + 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x98, 0x94, 0x96, 0xa2, 0x39, 0xce, + 0x88, 0x9c, 0x00, 0x79, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x20, 0x94, 0x85, + 0x90, 0x00, 0xb5, 0xea, 0x1b, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, + 0xea, 0x10, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x6c, 0x94, 0x6a, 0xa2, + 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x21, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x95, + 0x29, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x22, 0xa2, 0x57, 0xce, 0x88, 0x9c, + 0x00, 0x5b, 0x90, 0x00, 0xb5, 0xe9, 0xe1, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, + 0x01, 0xb5, 0xe9, 0xd6, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x90, 0x94, + 0x30, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x28, 0xa2, 0x56, 0xce, 0x88, 0x9c, + 0x00, 0x94, 0x20, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x59, 0x90, 0x00, 0xb5, 0xe9, + 0xaf, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe9, 0xa4, 0x90, 0x01, + 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x92, 0xa2, 0x66, 0xcc, 0xa8, 0x9c, 0x00, 0x54, + 0x9c, 0x01, 0x94, 0xae, 0x9c, 0x03, 0xb4, 0x01, 0x0e, 0x9c, 0x04, 0xb4, 0x01, 0x69, + 0x9c, 0x05, 0xb4, 0x01, 0x90, 0x3c, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, + 0x57, 0xcc, 0x88, 0x9c, 0x00, 0x51, 0xac, 0xcc, 0xce, 0xb5, 0xf9, 0xfb, 0xb6, 0xb8, + 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, + 0x00, 0x94, 0x1f, 0xa2, 0x56, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x3a, 0xce, 0x88, + 0x9c, 0x00, 0x51, 0xac, 0xcc, 0xce, 0xb5, 0xfa, 0x3c, 0xb6, 0xb8, 0x02, 0x88, 0x9a, + 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, 0x39, 0xcc, 0x88, 0x9c, 0x00, 0x94, 0x20, + 0xa2, 0x5e, 0xcc, 0x88, 0x9c, 0x00, 0x59, 0xac, 0xcc, 0xce, 0xb5, 0xfa, 0x44, 0xb6, + 0xb8, 0x02, 0x88, 0x9a, 0x08, 0xb6, 0xb8, 0x02, 0x8b, 0xa2, 0x0a, 0xcc, 0xa8, 0xb6, + 0xb8, 0x04, 0xab, 0x3c, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x58, 0xcc, + 0x88, 0x9c, 0x00, 0x3c, 0xac, 0xcc, 0xce, 0xb5, 0xfa, 0x3e, 0xb6, 0xb8, 0x02, 0x88, + 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0x90, 0x00, 0xb5, 0xe8, 0xee, 0x90, 0x01, + 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf9, 0x47, 0xa2, 0x3a, 0xcc, 0x88, + 0x9c, 0x00, 0x77, 0xa2, 0x3c, 0xcc, 0x88, 0x9d, 0x00, 0x7e, 0xa2, 0x3a, 0xcc, 0x88, + 0x9c, 0x00, 0x94, 0x1f, 0xa2, 0x56, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x3a, 0xce, + 0x88, 0x9c, 0x00, 0x51, 0x90, 0x00, 0xb5, 0xe8, 0xb9, 0x90, 0x01, 0xa2, 0x14, 0x78, + 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf9, 0xa4, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, + 0xa2, 0x58, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0xcc, 0xce, 0xb5, 0xf9, 0xd9, 0xb6, + 0xb8, 0x02, 0x88, 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0x90, 0x00, 0xb5, 0xe8, + 0x89, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0xe2, 0xa2, + 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x77, 0xa2, 0x3c, 0xcc, 0x88, 0x9d, 0x00, 0x7e, 0xa2, + 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x57, 0xcc, 0x88, 0x9c, 0x00, 0x51, 0x90, + 0x00, 0xb5, 0xe8, 0x5c, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, + 0xf8, 0xdf, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x58, 0xcc, 0x88, 0x9c, + 0x00, 0x3c, 0x90, 0x00, 0xb5, 0xe8, 0x3d, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, + 0xcc, 0xce, 0xb4, 0xf9, 0x71, 0xa2, 0x0a, 0xcc, 0xa8, 0x05, 0xb5, 0xe8, 0x29, 0x90, + 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0x82, 0xa2, 0x39, 0xcc, + 0x88, 0x9c, 0x00, 0x7a, 0xa2, 0x5e, 0xcc, 0x88, 0x9c, 0x00, 0x95, 0x21, 0x3c, 0x90, + 0x00, 0xb5, 0xe8, 0x08, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe7, + 0xfd, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0x56, 0xa2, + 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x95, 0x22, 0xa2, 0x3c, 0xcc, 0x88, 0x9d, 0x00, 0x95, + 0x2a, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x94, 0x23, 0xa2, 0x57, 0xcc, 0x88, 0x9c, + 0x00, 0x5c, 0x90, 0x00, 0xb5, 0xe7, 0xcd, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, + 0x01, 0xb5, 0xe7, 0xc2, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, + 0xf8, 0x45, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x56, 0xcc, 0x88, 0x9c, + 0x00, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xb5, 0xe7, 0x9c, + 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe7, 0x91, 0x90, 0x01, 0xa2, + 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0x7c, 0xa2, 0x66, 0xce, 0xa8, 0x9c, + 0x00, 0x4e, 0x9c, 0x01, 0x94, 0x84, 0x9c, 0x02, 0x94, 0xd9, 0x9c, 0x04, 0xb4, 0x01, + 0x1a, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x55, 0xa2, 0x59, 0xce, 0x88, 0x9c, + 0x00, 0x4e, 0xb5, 0xf7, 0xee, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, + 0x8b, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x55, 0xa2, 0x5a, 0xce, 0x88, 0x9c, + 0x00, 0x4e, 0xb5, 0xf8, 0x06, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, 0xb8, 0x02, + 0x8b, 0x3c, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x5e, 0xce, 0x88, 0x9c, + 0x00, 0x3c, 0xb5, 0xf8, 0x46, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x08, 0xb6, 0xb8, 0x02, + 0x8b, 0xa2, 0x0a, 0xce, 0xa8, 0xb6, 0xb8, 0x04, 0xab, 0x3c, 0x90, 0x00, 0xb5, 0xe7, + 0x0f, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf7, 0x6b, 0xa2, 0x28, 0x72, 0xa8, + 0x05, 0xa2, 0x28, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x0a, 0xec, 0x3c, 0xa2, 0x3a, + 0xce, 0x88, 0x9c, 0x00, 0x95, 0x24, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x95, 0x2c, + 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x5a, 0xce, 0x88, 0x9c, 0x00, 0x3c, + 0xb5, 0xf7, 0x98, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, 0xb8, 0x02, 0x8b, 0xa2, + 0x28, 0x72, 0xa8, 0x05, 0xa2, 0x28, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x0a, 0xb1, + 0x3c, 0x90, 0x01, 0xb5, 0xe6, 0xb6, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf7, + 0x12, 0xa2, 0x2a, 0x72, 0xa8, 0x05, 0xa2, 0x2a, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, + 0x0a, 0x93, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x24, 0xa2, 0x3c, 0xce, + 0x88, 0x9d, 0x00, 0x95, 0x2c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x59, + 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x01, 0xb5, 0xe6, 0x7a, 0x90, 0x01, 0xa2, 0x14, + 0x78, 0x8b, 0xb5, 0xf7, 0x00, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, + 0x8b, 0xa2, 0x2a, 0x72, 0xa8, 0x05, 0xa2, 0x2a, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, + 0x0a, 0x4d, 0x3c, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x48, 0xa2, 0x5e, 0xce, 0x88, + 0x9c, 0x00, 0x41, 0x3c, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xb5, 0xe6, 0x40, 0x90, 0x01, + 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf6, 0x9c, 0xa2, 0x66, 0xce, 0xa8, 0x9c, 0x00, 0x4d, + 0x9c, 0x01, 0x94, 0x73, 0x9c, 0x04, 0x94, 0x99, 0x9c, 0x05, 0x94, 0xce, 0x3c, 0xa2, + 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x55, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x4e, 0xb5, + 0xf6, 0xa1, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, + 0x39, 0xce, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x56, 0xb5, + 0xf7, 0x15, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x08, 0xb6, 0xb8, 0x02, 0x8b, 0xa2, 0x0a, + 0xce, 0xa8, 0xb6, 0xb8, 0x04, 0xab, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, + 0xa2, 0x58, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb5, 0xf7, 0x12, 0xb6, 0xb8, 0x02, 0x88, + 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0x90, 0x00, 0xb5, 0xe5, 0xc2, 0x90, 0x01, + 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf6, 0x1e, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x74, + 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x7b, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, + 0xa2, 0x58, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb5, 0xf6, 0xda, 0xb6, 0xb8, 0x02, 0x88, + 0x9a, 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x48, + 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x41, 0x3c, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xb5, + 0xe5, 0x78, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf5, 0xd4, 0x90, 0x00, 0xb5, + 0xe5, 0x6a, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe5, 0x5f, 0x90, + 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf5, 0xbb, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, + 0x7f, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x95, 0x26, 0xa2, 0x3a, 0xce, 0x88, 0x9c, + 0x00, 0x3c, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xb5, 0xe5, 0x34, + 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe5, 0x29, 0x90, 0x01, 0xa2, + 0x14, 0x78, 0x8b, 0xb4, 0xf5, 0xaf, 0xa2, 0x56, 0xce, 0xa8, 0x9c, 0x00, 0x4e, 0x9c, + 0x01, 0x94, 0x28, 0x9c, 0x02, 0xb4, 0x01, 0x19, 0x9c, 0x04, 0x94, 0x9a, 0x3c, 0xa2, + 0x4a, 0xce, 0x88, 0x9c, 0x00, 0x43, 0xb4, 0xf7, 0x9e, 0xa2, 0x4b, 0xce, 0x88, 0x9c, + 0x00, 0x43, 0xb4, 0xf7, 0xdd, 0xa2, 0x4c, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb4, 0xf8, + 0x1c, 0xa2, 0x4a, 0xce, 0x88, 0xa2, 0x4b, 0xce, 0xda, 0x9c, 0x00, 0x94, 0x51, 0xa2, + 0x4b, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, + 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xe6, 0x4b, 0x90, 0x00, 0xb5, + 0xe4, 0xc2, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf7, 0x9f, 0xa2, 0x2c, 0x72, + 0xa8, 0x05, 0xa2, 0x2c, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb5, 0x08, 0x9f, 0xa2, 0x2f, + 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x1a, 0x72, 0xa8, 0x05, 0xa2, 0x1a, 0x72, 0xab, + 0xa2, 0x1c, 0x72, 0xa8, 0x04, 0xa2, 0x1c, 0x72, 0xab, 0x3c, 0x90, 0x00, 0xb5, 0xe4, + 0x8b, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf6, 0xc8, 0xa2, 0x2c, 0x72, 0xa8, + 0x05, 0xa2, 0x2c, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x08, 0x68, 0x3c, 0xa2, 0x4a, + 0xce, 0x88, 0xa2, 0x4b, 0xce, 0xda, 0x9c, 0x00, 0x94, 0x51, 0xa2, 0x4a, 0xce, 0x88, + 0x9c, 0x00, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xe5, 0xd0, 0x90, 0x01, 0xb5, 0xe4, 0x47, 0x90, + 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf6, 0xdb, 0xa2, 0x2e, 0x72, 0xa8, 0x05, 0xa2, + 0x2e, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb5, 0x08, 0x24, 0xa2, 0x2f, 0xce, 0x88, 0x9c, + 0x00, 0x3c, 0xa2, 0x1a, 0x72, 0xa8, 0x04, 0xa2, 0x1a, 0x72, 0xab, 0xa2, 0x1c, 0x72, + 0xa8, 0x05, 0xa2, 0x1c, 0x72, 0xab, 0x3c, 0x90, 0x01, 0xb5, 0xe4, 0x10, 0x90, 0x01, + 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf6, 0xed, 0xa2, 0x2e, 0x72, 0xa8, 0x05, 0xa2, 0x2e, + 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x07, 0xed, 0x3c, 0xa2, 0x4c, 0xce, 0x88, 0x9d, + 0x00, 0x3c, 0xa2, 0x06, 0xce, 0xa8, 0x05, 0xb5, 0xe3, 0xe8, 0x90, 0x01, 0xa2, 0x14, + 0x78, 0x8b, 0xb4, 0xf6, 0x25, 0x00, 0xb6, 0xb8, 0x02, 0x8b, 0xb6, 0xb8, 0x04, 0xab, + 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0xb4, 0x05, 0x1e, 0x9c, 0x01, 0xb4, 0x05, 0x19, + 0x9c, 0x02, 0xb4, 0x03, 0x4d, 0x9c, 0x03, 0xb4, 0x06, 0x18, 0xa2, 0x06, 0xce, 0xa8, + 0x9c, 0x00, 0x4e, 0x9c, 0x01, 0x4b, 0x9c, 0x02, 0xb4, 0x02, 0x1a, 0x9c, 0x03, 0xb4, + 0x02, 0xa1, 0x3c, 0xa2, 0x26, 0x72, 0x88, 0x9c, 0x00, 0x59, 0xa2, 0x3a, 0x0c, 0x88, + 0x9c, 0x00, 0x52, 0x90, 0x01, 0xa2, 0x56, 0x0a, 0x8b, 0x90, 0x00, 0xa2, 0x58, 0x0a, + 0x8b, 0xa2, 0x57, 0x0a, 0x8b, 0x94, 0xa2, 0xa2, 0x5b, 0x0c, 0x88, 0x9c, 0x00, 0x5b, + 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x54, 0x94, 0x2f, 0x90, 0x00, 0xa2, 0x56, 0x0a, + 0x8b, 0xa2, 0x57, 0x0a, 0x8b, 0x90, 0x01, 0xa2, 0x58, 0x0a, 0x8b, 0x94, 0x80, 0xa2, + 0x5b, 0x0a, 0x88, 0x9d, 0x00, 0x78, 0xa2, 0x5f, 0x0a, 0x88, 0x9c, 0x00, 0x4f, 0xa2, + 0x5f, 0x0c, 0x88, 0x9c, 0x00, 0x94, 0x20, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x59, + 0xa2, 0x5b, 0x0c, 0x88, 0x9c, 0x00, 0x48, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x41, + 0x5c, 0xa2, 0x5d, 0x0a, 0x88, 0x9d, 0x00, 0x94, 0x3b, 0x94, 0x22, 0xa2, 0x5c, 0x0c, + 0x88, 0x9c, 0x00, 0x95, 0x4e, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x95, 0x56, 0x95, + 0x29, 0x90, 0x00, 0xa2, 0x56, 0x0a, 0x8b, 0xa2, 0x58, 0x0a, 0x8b, 0xa2, 0x57, 0x0a, + 0x8b, 0x94, 0x28, 0xa2, 0x61, 0x0a, 0x88, 0x9c, 0x00, 0x76, 0xa2, 0x5f, 0x0c, 0x88, + 0x9c, 0x00, 0x49, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x42, 0x95, 0x25, 0x90, 0x00, + 0xa2, 0x56, 0x0a, 0x8b, 0xa2, 0x58, 0x0a, 0x8b, 0x90, 0x01, 0xa2, 0x57, 0x0a, 0x8b, + 0x40, 0xa2, 0x3c, 0x0a, 0x88, 0xab, 0x0e, 0xa2, 0x56, 0x0a, 0x88, 0xa2, 0x57, 0x0a, + 0xda, 0xa2, 0x58, 0x0a, 0xda, 0x9c, 0x00, 0x94, 0x3b, 0x90, 0x00, 0xa2, 0x3c, 0x0a, + 0x8b, 0x96, 0x0e, 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa2, 0x22, 0x0a, 0x88, 0xb5, 0xe4, 0x3a, 0xa2, 0x26, 0x72, 0x88, 0x9c, 0x00, + 0x5d, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, 0x00, 0x56, 0x90, 0x01, 0xa2, 0x56, 0x0c, 0x8b, + 0x90, 0x00, 0xa2, 0x58, 0x0c, 0x8b, 0xa2, 0x57, 0x0c, 0x8b, 0x94, 0x90, 0x90, 0x01, + 0x95, 0x3b, 0xa2, 0x5b, 0x0c, 0x88, 0x9d, 0x00, 0x58, 0xa2, 0x5f, 0x0c, 0x88, 0x9c, + 0x00, 0x94, 0x30, 0xa2, 0x5b, 0x0a, 0x88, 0x9c, 0x00, 0x5b, 0xa2, 0x3a, 0x0a, 0x88, + 0x9c, 0x00, 0x54, 0x94, 0x20, 0x90, 0x00, 0xa2, 0x56, 0x0c, 0x8b, 0xa2, 0x57, 0x0c, + 0x8b, 0x90, 0x01, 0xa2, 0x58, 0x0c, 0x8b, 0x94, 0x5b, 0xa2, 0x5d, 0x0a, 0x88, 0x9c, + 0x00, 0x78, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, 0x00, 0x7f, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, + 0x00, 0x48, 0xa2, 0x5b, 0x0a, 0x88, 0x9c, 0x00, 0x41, 0x5e, 0xa2, 0x5c, 0x0c, 0x88, + 0x9d, 0x00, 0x94, 0x25, 0xa2, 0x60, 0x0c, 0x88, 0x9c, 0x00, 0x4f, 0xa2, 0x5f, 0x0a, + 0x88, 0x9c, 0x00, 0x57, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, 0x00, 0x50, 0x40, 0x90, 0x00, + 0xa2, 0x56, 0x0c, 0x8b, 0xa2, 0x58, 0x0c, 0x8b, 0xa2, 0x57, 0x0c, 0x8b, 0x51, 0x90, + 0x00, 0xa2, 0x56, 0x0c, 0x8b, 0xa2, 0x58, 0x0c, 0x8b, 0x90, 0x01, 0xa2, 0x57, 0x0c, + 0x8b, 0x40, 0xa2, 0x3c, 0x0c, 0x88, 0xab, 0x0e, 0xa2, 0x56, 0x0c, 0x88, 0xa2, 0x57, + 0x0c, 0xda, 0xa2, 0x58, 0x0c, 0xda, 0x9c, 0x00, 0x94, 0x57, 0x90, 0x00, 0xa2, 0x3c, + 0x0c, 0x8b, 0x96, 0x0e, 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa2, 0x22, 0x0c, 0x88, 0xb5, 0xe3, 0x59, 0xa2, 0x66, 0x0a, 0xa8, 0xaf, + 0xc8, 0xa2, 0x66, 0x0c, 0xa8, 0xaf, 0xc8, 0xac, 0x0a, 0xce, 0xac, 0x0c, 0xcc, 0xb5, + 0xf6, 0x14, 0x3f, 0xc8, 0xa2, 0x66, 0x0c, 0xfc, 0x58, 0x3f, 0xc8, 0xac, 0x0a, 0xce, + 0xac, 0x0c, 0xcc, 0xb5, 0xf5, 0x1b, 0xb5, 0xf1, 0xed, 0xa2, 0x22, 0x72, 0xa8, 0xb5, + 0x10, 0x93, 0xb4, 0xf1, 0x41, 0x3f, 0xc8, 0xa2, 0x66, 0x0a, 0xfc, 0x3c, 0x7d, 0x90, + 0x01, 0x95, 0x57, 0xa2, 0x5b, 0xce, 0x88, 0xa2, 0x5f, 0xce, 0xda, 0x9c, 0x00, 0x4e, + 0x90, 0x01, 0xa2, 0x58, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x57, 0xce, 0x8b, 0x94, 0x22, + 0xa2, 0x5c, 0xce, 0x88, 0xa2, 0x60, 0xce, 0xda, 0x9c, 0x00, 0x4d, 0x90, 0x00, 0xa2, + 0x58, 0xce, 0x8b, 0x90, 0x01, 0xa2, 0x57, 0xce, 0x8b, 0x4a, 0x90, 0x00, 0xa2, 0x58, + 0xce, 0x8b, 0xa2, 0x57, 0xce, 0x8b, 0xa2, 0x3c, 0xce, 0x88, 0xab, 0x0e, 0xa2, 0x57, + 0xce, 0x88, 0xa2, 0x58, 0xce, 0xda, 0x9c, 0x00, 0x94, 0x3b, 0x90, 0x00, 0xa2, 0x3c, + 0xce, 0x8b, 0x96, 0x0e, 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xe2, 0xb1, 0xa2, 0x66, 0xce, 0xa8, 0xaf, + 0xc8, 0xb5, 0xfa, 0xed, 0x3f, 0xc8, 0xa2, 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xf5, 0x19, + 0xb5, 0xf1, 0x59, 0xa2, 0x22, 0x72, 0xa8, 0xb5, 0x0f, 0xff, 0xb4, 0xf0, 0xad, 0x90, + 0x01, 0x95, 0x3b, 0xa2, 0x5c, 0xce, 0x88, 0x9d, 0x00, 0x4e, 0xa2, 0x60, 0xce, 0x88, + 0x9c, 0x00, 0x55, 0xa2, 0x5d, 0xce, 0x88, 0x9d, 0x00, 0x4e, 0x90, 0x01, 0xa2, 0x59, + 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x5a, 0xce, 0x8b, 0x94, 0x22, 0xa2, 0x5d, 0xce, 0x88, + 0xa2, 0x61, 0xce, 0xda, 0x9c, 0x00, 0x4d, 0x90, 0x00, 0xa2, 0x59, 0xce, 0x8b, 0x90, + 0x01, 0xa2, 0x5a, 0xce, 0x8b, 0x4a, 0x90, 0x00, 0xa2, 0x59, 0xce, 0x8b, 0xa2, 0x5a, + 0xce, 0x8b, 0xa2, 0x3c, 0xce, 0x88, 0xab, 0x0e, 0xa2, 0x59, 0xce, 0x88, 0xa2, 0x5a, + 0xce, 0xda, 0x9c, 0x00, 0x94, 0x38, 0x90, 0x00, 0xa2, 0x3c, 0xce, 0x8b, 0x96, 0x0e, + 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xe2, 0x1b, 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xb5, 0xf9, 0x09, + 0x3f, 0xc8, 0xa2, 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xf0, 0xc6, 0xa2, 0x22, 0xce, 0x88, + 0xb5, 0x05, 0x95, 0xb4, 0xf0, 0x1a, 0x90, 0x01, 0x95, 0x38, 0x90, 0x00, 0xa2, 0x26, + 0x72, 0x8b, 0xa2, 0x2c, 0x72, 0xa8, 0x9c, 0x00, 0xb4, 0x01, 0x9c, 0x90, 0x00, 0xa2, + 0x24, 0x72, 0x8b, 0xa2, 0x2e, 0x72, 0xa8, 0x9c, 0x00, 0xb4, 0x01, 0x9b, 0x90, 0x00, + 0xa2, 0x25, 0x72, 0x8b, 0xa1, 0xce, 0xb8, 0x0a, 0xab, 0x30, 0x0b, 0x30, 0x4f, 0x30, + 0x93, 0x30, 0xc5, 0x31, 0x5f, 0xb4, 0xfc, 0x82, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, + 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x32, 0xa2, 0x17, 0xce, + 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, 0x28, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, + 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x40, 0x9c, 0x00, 0x57, 0xa2, 0x24, 0x72, 0x88, + 0x9c, 0x00, 0x47, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x49, 0x90, 0x01, 0xa2, 0x5b, + 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0x90, 0x00, 0x69, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, + 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x32, 0xa2, 0x17, 0xce, + 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, 0x28, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, + 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x08, 0x9c, 0x00, 0x57, 0xa2, 0x24, 0x72, 0x88, + 0x9c, 0x00, 0x47, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x49, 0x90, 0x01, 0xa2, 0x5f, + 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0x90, 0x00, 0x69, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, + 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x5b, 0xa8, 0xce, 0xb8, 0x00, + 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x20, 0x9c, 0x00, 0x4a, 0xa2, + 0x24, 0x72, 0x88, 0x9d, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x5c, 0xce, + 0x8b, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, 0xab, 0xa2, 0x17, 0xce, + 0x88, 0x99, 0x01, 0x9c, 0x00, 0x5b, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, + 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x4a, 0xa2, 0x24, 0x72, 0x88, 0x9d, + 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x60, 0xce, 0x8b, 0x3f, 0xce, 0x3c, + 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x02, 0x9c, + 0x00, 0x5b, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, + 0x99, 0x10, 0x9c, 0x00, 0x4a, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x43, 0x90, 0x01, + 0x42, 0x90, 0x00, 0xa2, 0x5d, 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xa4, 0xb8, + 0x0a, 0xce, 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x5b, 0xa8, 0xce, + 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x02, 0x9c, 0x00, + 0x4a, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, + 0x61, 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, 0xab, 0xa2, + 0x17, 0xce, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x5e, 0xce, 0x8b, + 0x3f, 0xce, 0x3c, 0xa2, 0x28, 0x72, 0xa8, 0x9d, 0x00, 0xb4, 0xfe, 0x5b, 0x90, 0x01, + 0xb4, 0xfe, 0x58, 0xa2, 0x2a, 0x72, 0xa8, 0x9d, 0x00, 0xb4, 0xfe, 0x5c, 0x90, 0x01, + 0xb4, 0xfe, 0x59, 0x9c, 0x00, 0x4e, 0xac, 0xce, 0x0c, 0xa2, 0x10, 0x72, 0x88, 0xb5, + 0xde, 0x8e, 0xac, 0x76, 0x0a, 0x4d, 0xac, 0xce, 0x0a, 0xa2, 0x11, 0x72, 0x88, 0xb5, + 0xde, 0x80, 0xac, 0x76, 0x0c, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xde, 0x76, 0xa8, 0x76, + 0xb6, 0xb8, 0x06, 0xab, 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xde, 0x69, 0xa8, 0x76, 0xb6, + 0xb8, 0x08, 0xab, 0xa2, 0x17, 0x0a, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x53, 0xa2, + 0x17, 0x0c, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x49, 0xa2, 0x17, 0x0a, 0x88, 0x99, + 0x02, 0x9c, 0x00, 0x94, 0x3f, 0xa2, 0x17, 0x0c, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, + 0x35, 0xa2, 0x29, 0x0a, 0x88, 0x9c, 0x02, 0x42, 0x94, 0x2c, 0xa2, 0x29, 0x0c, 0x88, + 0x9c, 0x02, 0x42, 0x94, 0x23, 0xa8, 0x0a, 0xb8, 0x00, 0x13, 0xb8, 0x00, 0x02, 0xad, + 0xc8, 0x88, 0x99, 0x80, 0x9c, 0x00, 0x53, 0xa8, 0x0c, 0xb8, 0x00, 0x13, 0xb8, 0x00, + 0x02, 0xad, 0xc8, 0x88, 0x99, 0x80, 0x9c, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, + 0xa2, 0x26, 0x72, 0x8b, 0x40, 0xa2, 0x2c, 0x72, 0xa8, 0x9c, 0x00, 0x43, 0x90, 0x00, + 0x51, 0xa2, 0x28, 0x72, 0xa8, 0x9c, 0x00, 0x41, 0x6a, 0xa2, 0x26, 0x72, 0x88, 0x9d, + 0x00, 0x71, 0x90, 0x01, 0xa2, 0x24, 0x72, 0x8b, 0xa2, 0x2e, 0x72, 0xa8, 0x9c, 0x00, + 0x43, 0x90, 0x00, 0x51, 0xa2, 0x2a, 0x72, 0xa8, 0x9c, 0x00, 0x41, 0x6a, 0xa2, 0x26, + 0x72, 0x88, 0x9d, 0x00, 0x71, 0x90, 0x01, 0xa2, 0x25, 0x72, 0x8b, 0xb6, 0xb8, 0x06, + 0xa8, 0xb6, 0xb8, 0x0a, 0xab, 0x36, 0x73, 0x36, 0x2f, 0x35, 0xeb, 0x35, 0xb9, 0x35, + 0x87, 0x35, 0x55, 0x35, 0x23, 0xb6, 0xb8, 0x08, 0xa8, 0xb6, 0xb8, 0x0a, 0xab, 0x36, + 0x89, 0x36, 0x45, 0x36, 0x01, 0x35, 0xcf, 0x35, 0x9d, 0x35, 0x6b, 0x35, 0x39, 0xb4, + 0xf9, 0xe8, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, + 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x20, 0x9c, 0x00, 0x43, + 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x5c, 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, + 0x01, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, + 0xc8, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x60, + 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, + 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x10, 0x9c, 0x00, 0x43, + 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x5d, 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, + 0x02, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, + 0xc8, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x61, + 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, + 0x5e, 0xce, 0x8b, 0xb4, 0xf9, 0x4a, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, + 0x4b, 0xa2, 0x08, 0xce, 0x88, 0x99, 0x20, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x4d, + 0xce, 0x8b, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x4b, 0xa2, 0x08, 0xce, + 0x88, 0x99, 0x04, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x50, 0xce, 0x8b, 0xa2, 0x1e, + 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x4b, 0xa2, 0x08, 0xce, 0x88, 0x99, 0x10, 0x9c, + 0x00, 0x42, 0x90, 0x01, 0xa2, 0x4e, 0xce, 0x8b, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x02, + 0x9c, 0x00, 0x4b, 0xa2, 0x08, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x42, 0x90, 0x01, + 0xa2, 0x51, 0xce, 0x8b, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x4b, 0xa2, + 0x08, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x4f, 0xce, 0x8b, + 0xa2, 0x28, 0xce, 0x88, 0x9c, 0x00, 0x57, 0xa2, 0x4d, 0xce, 0x88, 0x9d, 0x00, 0x94, + 0x62, 0xa2, 0x50, 0xce, 0x88, 0x9c, 0x00, 0x48, 0xa2, 0x4e, 0xce, 0x88, 0x9c, 0x00, + 0x94, 0x53, 0xa2, 0x28, 0xce, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x4e, 0xce, 0x88, 0xa2, + 0x51, 0xce, 0xda, 0x9c, 0x00, 0x52, 0x90, 0x01, 0xa2, 0x4b, 0xce, 0x8b, 0x90, 0x00, + 0xa2, 0x4a, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0x8b, 0x94, 0x40, 0xa2, 0x28, 0xce, 0x88, + 0x9c, 0x00, 0x59, 0xa2, 0x4f, 0xce, 0x88, 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, 0x4a, + 0xce, 0x8b, 0xa2, 0x4b, 0xce, 0x8b, 0x90, 0x01, 0xa2, 0x4c, 0xce, 0x8b, 0x94, 0x20, + 0x90, 0x00, 0xa2, 0x4a, 0xce, 0x8b, 0xa2, 0x4b, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0x8b, + 0x51, 0x90, 0x01, 0xa2, 0x4a, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x4b, 0xce, 0x8b, 0xa2, + 0x4c, 0xce, 0x8b, 0x40, 0xb4, 0xf6, 0xeb, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x44, + 0x9c, 0x02, 0x51, 0x3c, 0xa2, 0x12, 0x72, 0x88, 0x9c, 0x02, 0x3c, 0xb5, 0xdb, 0xe2, + 0xac, 0x76, 0xce, 0xb4, 0xf8, 0x11, 0xa2, 0x10, 0x72, 0x88, 0x9c, 0x02, 0x49, 0xb5, + 0xdb, 0xd2, 0xac, 0x76, 0xce, 0xb4, 0xf8, 0x01, 0xa2, 0x11, 0x72, 0x88, 0x9c, 0x02, + 0x3c, 0xb5, 0xdb, 0xc2, 0xac, 0x76, 0xce, 0xb4, 0xf7, 0xf1, 0x00, 0xb6, 0xb8, 0x02, + 0x8b, 0xb6, 0xb8, 0x04, 0xab, 0xa8, 0x46, 0xb5, 0xdb, 0xae, 0xa8, 0x44, 0xbc, 0x03, + 0x02, 0x58, 0xbc, 0x03, 0x01, 0x5b, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x03, 0x5c, 0x9c, + 0x02, 0x94, 0x38, 0x9c, 0x00, 0x94, 0x57, 0x9c, 0x01, 0x94, 0x53, 0x3c, 0xa8, 0x48, + 0xa2, 0x3a, 0x76, 0x8b, 0x7a, 0xa8, 0x48, 0xa2, 0x39, 0x76, 0x8b, 0x95, 0x21, 0xac, + 0x76, 0xce, 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xb5, 0xf4, 0x04, 0x3f, 0xc8, 0xa2, + 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xeb, 0xc1, 0xac, 0x76, 0xce, 0xa8, 0x46, 0x30, 0x90, + 0xb4, 0xeb, 0x15, 0xac, 0x76, 0xce, 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xb5, 0xf5, + 0x32, 0x3f, 0xc8, 0xa2, 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xef, 0x5e, 0xb5, 0xeb, 0x9e, + 0xa2, 0x22, 0x72, 0xa8, 0xb5, 0x0a, 0x44, 0xb4, 0xea, 0xf2, 0xa8, 0x44, 0xbc, 0x03, + 0x02, 0x94, 0x51, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x94, 0x4f, 0xac, 0x76, 0xcc, + 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xdb, 0x25, 0xac, 0x76, 0xce, 0x43, 0xac, 0x76, 0xcc, + 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xa2, 0x66, 0xcc, 0xa8, 0xaf, 0xc8, 0xaf, 0xce, + 0xaf, 0xcc, 0xb5, 0xef, 0x73, 0x3f, 0xcc, 0x3f, 0xce, 0x3f, 0xc8, 0xa2, 0x66, 0xce, + 0xfc, 0x52, 0x3f, 0xc8, 0xb5, 0xee, 0x7c, 0xb5, 0xeb, 0x4e, 0xa2, 0x22, 0x72, 0xa8, + 0xb5, 0x09, 0xf4, 0xb4, 0xea, 0xa2, 0x3f, 0xc8, 0xa2, 0x66, 0xcc, 0xfc, 0x3c, 0x77, + 0xac, 0x76, 0xce, 0xb4, 0xf7, 0x15, 0xac, 0x76, 0xce, 0xa2, 0x11, 0x72, 0x88, 0xb5, + 0xda, 0xd6, 0x95, 0x4b, 0xaf, 0xc8, 0xa2, 0x66, 0xce, 0xa8, 0xb5, 0x09, 0x9c, 0xa2, + 0x30, 0x72, 0x88, 0x3f, 0xca, 0x9c, 0x00, 0x3c, 0xb7, 0x01, 0x07, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0xca, 0xb4, 0xdc, 0x49, 0x00, 0x90, 0x00, + 0xf6, 0x90, 0x00, 0xa2, 0x02, 0xce, 0x8b, 0xa2, 0x04, 0xce, 0xab, 0x90, 0x03, 0xa2, + 0x06, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x08, 0xce, 0x8b, 0x90, 0x04, 0xa2, 0x20, 0xce, + 0xab, 0xb7, 0x00, 0x00, 0x0a, 0xac, 0xce, 0xcc, 0x82, 0x58, 0xcc, 0xf8, 0xa8, 0x0a, + 0x96, 0x7e, 0xdc, 0x5a, 0xa2, 0x22, 0xce, 0x88, 0xc6, 0xa2, 0x02, 0xcc, 0x8b, 0x90, + 0x02, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x03, 0xcc, 0x8b, 0x82, 0x04, 0xcc, 0xf8, 0xa9, + 0x0a, 0x7f, 0x00, 0xa2, 0x26, 0xce, 0x8b, 0xa2, 0x27, 0xce, 0x8b, 0xa2, 0x28, 0xce, + 0x8b, 0x90, 0x00, 0xa2, 0x3a, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x24, 0xce, 0xab, 0x3c, + 0x00, 0xa2, 0x0a, 0xce, 0xab, 0xa2, 0x0c, 0xce, 0xab, 0xa2, 0x0e, 0xce, 0xab, 0xa2, + 0x10, 0xce, 0xab, 0xac, 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb1, 0x43, 0xb1, 0x33, + 0x11, 0xac, 0xce, 0xcc, 0x82, 0x18, 0xcc, 0xf8, 0xb1, 0x43, 0xb1, 0x33, 0x05, 0x90, + 0x00, 0xa2, 0x1e, 0xce, 0x8b, 0x00, 0xa2, 0x29, 0xce, 0x8b, 0xa2, 0x2a, 0xce, 0x8b, + 0xa2, 0x2b, 0xce, 0x8b, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, 0x2d, 0xce, 0x8b, 0xa2, 0x2e, + 0xce, 0x8b, 0xa2, 0x30, 0xce, 0x8b, 0xa2, 0x31, 0xce, 0x8b, 0xa2, 0x32, 0xce, 0x8b, + 0xa2, 0x33, 0xce, 0x8b, 0xa2, 0x34, 0xce, 0xab, 0xa2, 0x36, 0xce, 0xab, 0xa2, 0x38, + 0xce, 0xab, 0x90, 0x01, 0xa2, 0x2f, 0xce, 0x8b, 0x00, 0xa2, 0x4a, 0xce, 0x8b, 0xa2, + 0x4b, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0x8b, 0xa2, 0x4d, 0xce, 0x8b, 0xa2, 0x4e, 0xce, + 0x8b, 0xa2, 0x4f, 0xce, 0x8b, 0xa2, 0x50, 0xce, 0x8b, 0xa2, 0x51, 0xce, 0x8b, 0xa2, + 0x54, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x52, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x56, 0xce, + 0xab, 0x3c, 0x00, 0xf6, 0xa2, 0x02, 0xce, 0xab, 0x90, 0x02, 0xa2, 0x04, 0xce, 0xab, + 0x90, 0x04, 0xa2, 0x06, 0xce, 0xab, 0x00, 0xa2, 0x08, 0xce, 0xab, 0x90, 0x03, 0xa2, + 0x0a, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x0c, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x0e, 0xce, + 0xab, 0x90, 0x07, 0xa2, 0x10, 0xce, 0x8b, 0x90, 0x08, 0xa2, 0x11, 0xce, 0x8b, 0xac, + 0xce, 0xcc, 0x82, 0x13, 0xcc, 0xf8, 0x90, 0x00, 0xc6, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, + 0x02, 0xcc, 0x8b, 0xb7, 0x00, 0x00, 0x0a, 0xac, 0xce, 0xcc, 0x82, 0x1a, 0xcc, 0xf8, + 0xa8, 0x0a, 0x96, 0x7e, 0xdc, 0x3c, 0xa2, 0x22, 0xce, 0x88, 0xc6, 0xa2, 0x02, 0xcc, + 0x8b, 0x90, 0x04, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x03, 0xcc, 0x8b, 0x82, 0x04, 0xcc, + 0xf8, 0xa9, 0x0a, 0x7f, 0x90, 0x00, 0xa2, 0x17, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x18, + 0xce, 0x8b, 0x00, 0xa2, 0x24, 0xce, 0xab, 0xa2, 0x26, 0xce, 0xab, 0x90, 0x04, 0xa2, + 0x28, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x29, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x2a, 0xce, + 0x8b, 0x90, 0x00, 0xa2, 0x2c, 0xce, 0xab, 0x00, 0xa2, 0x2e, 0xce, 0xab, 0xa2, 0x30, + 0xce, 0xab, 0xa2, 0x32, 0xce, 0xab, 0xa2, 0x34, 0xce, 0x8b, 0xa2, 0x35, 0xce, 0x8b, + 0xa2, 0x36, 0xce, 0x8b, 0xa2, 0x37, 0xce, 0x8b, 0xa2, 0x38, 0xce, 0x8b, 0xa2, 0x39, + 0xce, 0x8b, 0xa2, 0x3a, 0xce, 0x8b, 0xa2, 0x3b, 0xce, 0x8b, 0xa2, 0x3c, 0xce, 0x8b, + 0xa2, 0x3d, 0xce, 0x8b, 0xa2, 0x3e, 0xce, 0x8b, 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x40, + 0xce, 0x8b, 0xa2, 0x41, 0xce, 0x8b, 0xa2, 0x42, 0xce, 0x8b, 0xa2, 0x44, 0xce, 0xab, + 0xa2, 0x46, 0xce, 0xab, 0xa2, 0x48, 0xce, 0xab, 0xa2, 0x4a, 0xce, 0xab, 0xa2, 0x4c, + 0xce, 0xab, 0x90, 0x00, 0xa2, 0x4e, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x50, 0xce, 0xab, + 0x90, 0x00, 0xa2, 0x54, 0xce, 0x8b, 0xa2, 0x55, 0xce, 0x8b, 0xa2, 0x57, 0xce, 0x8b, + 0xa2, 0x58, 0xce, 0x8b, 0xa2, 0x59, 0xce, 0x8b, 0xa2, 0x5a, 0xce, 0x8b, 0xa2, 0x5b, + 0xce, 0x8b, 0xa2, 0x5c, 0xce, 0x8b, 0xa2, 0x5d, 0xce, 0x8b, 0xa2, 0x5e, 0xce, 0x8b, + 0xa2, 0x5f, 0xce, 0x8b, 0xa2, 0x60, 0xce, 0x8b, 0xa2, 0x61, 0xce, 0x8b, 0xa2, 0x64, + 0xce, 0xab, 0x90, 0x00, 0xa2, 0x62, 0xce, 0xab, 0x90, 0x04, 0xa2, 0x66, 0xce, 0xab, + 0x00, 0xa2, 0x68, 0xce, 0xab, 0xa2, 0x6a, 0xce, 0xab, 0xa2, 0x6c, 0xce, 0xab, 0xa2, + 0x6e, 0xce, 0xab, 0xa2, 0x70, 0xce, 0xab, 0xa2, 0x72, 0xce, 0xab, 0xa2, 0x74, 0xce, + 0x8b, 0x90, 0x00, 0xa2, 0x76, 0xce, 0xab, 0x3c, 0xb0, 0xe4, 0x9c, 0xa2, 0x02, 0x72, + 0xab, 0x90, 0xa6, 0xa2, 0x04, 0x72, 0xab, 0x90, 0x00, 0xa2, 0x06, 0x72, 0xab, 0xb0, + 0xff, 0xff, 0xa2, 0x08, 0x72, 0xab, 0xb0, 0xff, 0xff, 0xa2, 0x36, 0x72, 0xab, 0x00, + 0xa2, 0x0a, 0x72, 0x8b, 0xa2, 0x0b, 0x72, 0x8b, 0xa2, 0x0c, 0x72, 0x8b, 0x90, 0x00, + 0xa2, 0x0d, 0x72, 0x8b, 0x00, 0xa2, 0x0e, 0x72, 0x8b, 0xa2, 0x0f, 0x72, 0x8b, 0x90, + 0x02, 0xa2, 0x10, 0x72, 0x8b, 0xa2, 0x11, 0x72, 0x8b, 0xa2, 0x12, 0x72, 0x8b, 0x90, + 0x01, 0xa2, 0x14, 0x72, 0x8b, 0x90, 0x00, 0xa2, 0x00, 0x72, 0x8b, 0xa2, 0x15, 0x72, + 0x8b, 0xa2, 0x16, 0x72, 0x8b, 0xa2, 0x18, 0x72, 0x8b, 0xa2, 0x1a, 0x72, 0x8b, 0xa2, + 0x1c, 0x72, 0x8b, 0x90, 0x02, 0xa2, 0x1e, 0x72, 0x8b, 0x90, 0x00, 0xa2, 0x20, 0x72, + 0xab, 0x90, 0x00, 0xa2, 0x22, 0x72, 0xab, 0x90, 0x01, 0xa2, 0x24, 0x72, 0x8b, 0xa2, + 0x25, 0x72, 0x8b, 0x90, 0x00, 0xa2, 0x26, 0x72, 0x8b, 0xa2, 0x27, 0x72, 0x8b, 0xa2, + 0x28, 0x72, 0xab, 0xa2, 0x2a, 0x72, 0xab, 0xa2, 0x2c, 0x72, 0xab, 0xa2, 0x2e, 0x72, + 0xab, 0xb7, 0x00, 0x00, 0x0c, 0xa8, 0x0c, 0x9c, 0x01, 0x56, 0xb5, 0xd7, 0x7d, 0xa8, + 0x0c, 0xa2, 0x22, 0x74, 0x8b, 0xac, 0x74, 0xce, 0x37, 0x28, 0xac, 0x74, 0xce, 0x36, + 0xc9, 0xa9, 0x0c, 0x7a, 0xb7, 0x00, 0x00, 0x0c, 0xa8, 0x0c, 0x96, 0x7e, 0xdc, 0x94, + 0x34, 0xb5, 0xd7, 0x84, 0xa8, 0x0c, 0xa2, 0x10, 0x78, 0xab, 0x00, 0xa2, 0x00, 0x78, + 0xab, 0xa2, 0x02, 0x78, 0xab, 0xa2, 0x04, 0x78, 0xab, 0xa2, 0x06, 0x78, 0xab, 0xa2, + 0x08, 0x78, 0xab, 0xa2, 0x0a, 0x78, 0xab, 0xa2, 0x0c, 0x78, 0xab, 0xa2, 0x0e, 0x78, + 0xab, 0x90, 0x00, 0xa2, 0x12, 0x78, 0xab, 0xa9, 0x0c, 0x95, 0x39, 0xb7, 0x00, 0x00, + 0x0c, 0xa8, 0x0c, 0x9c, 0x03, 0x56, 0xb5, 0xd7, 0x33, 0xa8, 0x0c, 0xa2, 0x22, 0x76, + 0x8b, 0xac, 0x76, 0xce, 0x36, 0x86, 0xac, 0x76, 0xce, 0x36, 0x19, 0xa9, 0x0c, 0x7a, + 0x00, 0x3c, 0xad, 0xca, 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, 0x88, 0xc6, + 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, + 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, + 0xad, 0xca, 0x88, 0xc6, 0x3c, 0x00, 0xb7, 0x00, 0x00, 0x2e, 0xb7, 0x00, 0x00, 0x30, + 0xb7, 0x00, 0x00, 0x2c, 0x91, 0x00, 0xb2, 0xce, 0x3e, 0x00, 0xe6, 0x82, 0x0e, 0xcc, + 0xf8, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x6b, 0x3c, 0x91, 0x00, 0xb2, 0xce, 0x3e, + 0x00, 0xfc, 0xb6, 0xb8, 0x00, 0xa8, 0xa2, 0x0c, 0xcc, 0xfc, 0x4c, 0x82, 0x0e, 0xcc, + 0xf8, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x75, 0x3c, 0xa0, 0x30, 0xca, 0xfc, 0x4c, + 0x00, 0xe6, 0xa2, 0x0c, 0xcc, 0xab, 0xa8, 0x2e, 0x05, 0xab, 0x2e, 0x7c, 0x00, 0xa2, + 0x06, 0xcc, 0xab, 0x95, 0x22, 0x83, 0x00, 0xb8, 0x00, 0xab, 0x48, 0xb7, 0x00, 0x00, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0xab, 0x3c, 0xac, 0xce, 0x3e, 0xa8, 0xcc, 0xae, 0xce, + 0xb7, 0xff, 0xff, 0x38, 0xb7, 0xff, 0xff, 0x3a, 0x82, 0x00, 0x2e, 0xfd, 0x5e, 0x32, + 0x0f, 0x00, 0xab, 0x34, 0xab, 0x36, 0xb2, 0xce, 0x3e, 0xa0, 0x30, 0xcc, 0xf8, 0x94, + 0x52, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x34, 0xa2, 0x04, 0xcc, 0xa8, 0xab, 0x36, 0x94, + 0x44, 0x31, 0xfe, 0xab, 0x34, 0xac, 0xcc, 0x36, 0x31, 0xea, 0xb2, 0xce, 0x3e, 0xa0, + 0x30, 0xcc, 0xf8, 0xa8, 0x36, 0xa2, 0x04, 0xcc, 0xfd, 0x95, 0x24, 0xa2, 0x04, 0xcc, + 0xfc, 0x41, 0x4e, 0xa8, 0x34, 0xa2, 0x02, 0xcc, 0xfd, 0x95, 0x32, 0xa2, 0x02, 0xcc, + 0xfc, 0x95, 0x38, 0xa2, 0x02, 0xcc, 0xa8, 0x02, 0x96, 0x34, 0xeb, 0xab, 0x34, 0xa2, + 0x04, 0xcc, 0xa8, 0x96, 0x36, 0xeb, 0xab, 0x36, 0x96, 0x37, 0x17, 0x95, 0x50, 0x97, + 0x00, 0x42, 0xa8, 0x02, 0x96, 0x04, 0xfa, 0x9d, 0x00, 0x97, 0x01, 0x42, 0xa8, 0xcc, + 0xae, 0xce, 0xab, 0xcc, 0x00, 0xe5, 0xab, 0x32, 0x82, 0x00, 0x42, 0xdd, 0x5d, 0xa8, + 0xcc, 0xae, 0xce, 0xab, 0xcc, 0x91, 0x00, 0xb2, 0xce, 0x3e, 0xb7, 0x00, 0x00, 0x40, + 0xa8, 0x32, 0x9c, 0x00, 0x94, 0x50, 0xa2, 0x0a, 0xcc, 0xfc, 0x94, 0x39, 0x94, 0x48, + 0xa8, 0x04, 0x9d, 0x00, 0x95, 0x21, 0x9c, 0x00, 0x41, 0x46, 0xa8, 0x02, 0x9d, 0x00, + 0x95, 0x2b, 0x90, 0x00, 0xaa, 0xc8, 0x62, 0xa8, 0x2c, 0x04, 0xbd, 0x7f, 0xff, 0x90, + 0x01, 0xab, 0x2c, 0xab, 0x04, 0xe6, 0xac, 0x06, 0x02, 0x82, 0xff, 0x02, 0xfa, 0xa8, + 0x3c, 0xb7, 0x00, 0x00, 0x06, 0xb5, 0xd7, 0x44, 0x97, 0x00, 0x42, 0x95, 0x52, 0xc4, + 0x9c, 0x00, 0x4d, 0x00, 0xc6, 0xa2, 0x06, 0xcc, 0x8b, 0xab, 0x32, 0xa8, 0x2e, 0x05, + 0xab, 0x2e, 0xc4, 0x9c, 0x00, 0x94, 0x9d, 0x02, 0xa2, 0x02, 0xcc, 0xa8, 0x96, 0x34, + 0xeb, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0x96, 0x36, 0xeb, 0xa2, 0x04, + 0xcc, 0xab, 0xa2, 0x05, 0xcc, 0x17, 0x94, 0x38, 0xa2, 0x04, 0xcc, 0xa8, 0x9d, 0x00, + 0x4e, 0x9c, 0x00, 0x42, 0x94, 0x2c, 0xa2, 0x02, 0xcc, 0xa8, 0x9d, 0x00, 0x42, 0x94, + 0x23, 0x00, 0xdc, 0x4e, 0xa8, 0x3a, 0xa2, 0x04, 0xcc, 0xfd, 0x94, 0x4f, 0xa2, 0x04, + 0xcc, 0xfc, 0x94, 0x40, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x94, 0x95, 0x82, 0x0e, + 0x40, 0xf8, 0x82, 0x0e, 0xcc, 0xf8, 0x95, 0xae, 0xa2, 0x0a, 0xcc, 0xa8, 0xaf, 0x04, + 0xab, 0x04, 0xa2, 0x06, 0xcc, 0xa8, 0xaf, 0x02, 0x9a, 0xff, 0xab, 0x02, 0xaf, 0x06, + 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x08, 0xcc, 0xa8, 0xb5, 0xd6, 0xb5, 0x3f, 0x06, 0x3f, + 0x02, 0x3f, 0x04, 0x00, 0xc6, 0xa8, 0x2e, 0x05, 0xab, 0x2e, 0x95, 0x4f, 0xa8, 0x38, + 0xa2, 0x02, 0xcc, 0xfd, 0x42, 0x95, 0x47, 0xac, 0x40, 0x30, 0xa2, 0x02, 0xcc, 0xa8, + 0xab, 0x38, 0xa2, 0x04, 0xcc, 0xa8, 0xab, 0x3a, 0x95, 0x58, 0x96, 0x42, 0xdc, 0x95, + 0x6e, 0xa8, 0x02, 0xa2, 0x02, 0xcc, 0xab, 0xa8, 0x04, 0xa2, 0x04, 0xcc, 0xab, 0x90, + 0x01, 0xc6, 0xa8, 0x06, 0xa2, 0x06, 0xcc, 0xab, 0xa8, 0x3c, 0xa2, 0x08, 0xcc, 0xab, + 0xa8, 0x2c, 0x04, 0xbd, 0x7f, 0xff, 0x90, 0x01, 0xab, 0x2c, 0xa2, 0x0a, 0xcc, 0xab, + 0xae, 0xce, 0xae, 0xcc, 0xae, 0xce, 0xe6, 0xae, 0xce, 0xab, 0xcc, 0xa8, 0x2e, 0x04, + 0xab, 0x2e, 0x00, 0x8b, 0x42, 0x95, 0xac, 0xa8, 0x2e, 0x9c, 0x00, 0x4e, 0xa8, 0x38, + 0x96, 0x3a, 0xfa, 0x9c, 0x00, 0x46, 0x30, 0x1c, 0xac, 0x3e, 0xce, 0x3c, 0xac, 0x3e, + 0xce, 0x3c, 0x83, 0x44, 0x01, 0x91, 0x8b, 0x40, 0x40, 0x83, 0xcc, 0x01, 0x91, 0x8b, + 0x40, 0x40, 0x83, 0x44, 0x01, 0x91, 0x8b, 0x3c, 0x34, 0x14, 0xa1, 0x38, 0x01, 0x8c, + 0xab, 0xa1, 0x3a, 0x01, 0x88, 0xab, 0x87, 0xff, 0xff, 0x01, 0x8a, 0xab, 0x87, 0xff, + 0xff, 0x01, 0x86, 0xab, 0x83, 0x01, 0x01, 0x91, 0x8b, 0x3c, 0x34, 0x32, 0x83, 0x00, + 0x01, 0x88, 0xab, 0x83, 0x00, 0x01, 0x8c, 0xab, 0x3c, 0xb6, 0x01, 0x8c, 0xa8, 0xa4, + 0x01, 0x88, 0xcc, 0xab, 0x3c, 0x82, 0x00, 0x2e, 0xfc, 0x94, 0xdc, 0xb2, 0xce, 0x3e, + 0xa0, 0x30, 0xcc, 0xf8, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x34, 0xa2, 0x04, 0xcc, 0xa8, + 0xab, 0x36, 0xb7, 0xff, 0xff, 0x38, 0xb7, 0xff, 0xff, 0x3a, 0xb2, 0xce, 0x3e, 0x91, + 0x00, 0xb7, 0x00, 0x00, 0x40, 0x00, 0xdc, 0x94, 0x93, 0xa8, 0x36, 0xa2, 0x04, 0xcc, + 0xfd, 0x48, 0xa2, 0x04, 0xcc, 0xfc, 0x94, 0x37, 0x94, 0x43, 0xa2, 0x06, 0xcc, 0xa8, + 0x9c, 0x00, 0x94, 0x23, 0xac, 0x02, 0x3c, 0xac, 0x04, 0x3e, 0xa8, 0x50, 0xa2, 0x06, + 0xcc, 0xa8, 0x9a, 0xff, 0xab, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, 0xab, 0x04, 0xa2, 0x08, + 0xcc, 0xa8, 0xb5, 0xd5, 0x87, 0xac, 0x3c, 0x02, 0xac, 0x3e, 0x04, 0x90, 0x00, 0xc6, + 0xa8, 0x2e, 0x05, 0xab, 0x2e, 0x94, 0x4f, 0xa8, 0x34, 0xa2, 0x02, 0xcc, 0xfd, 0x95, + 0x3b, 0xa2, 0x02, 0xcc, 0xfc, 0x95, 0x41, 0x02, 0xa2, 0x02, 0xcc, 0xa8, 0x96, 0x34, + 0xeb, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0x96, 0x36, 0xeb, 0xa2, 0x04, + 0xcc, 0xab, 0xa2, 0x05, 0xcc, 0x17, 0x95, 0x5e, 0xa8, 0x3a, 0xa2, 0x04, 0xcc, 0xfd, + 0x4e, 0xa2, 0x04, 0xcc, 0xfc, 0x41, 0x57, 0xa8, 0x38, 0xa2, 0x02, 0xcc, 0xfd, 0x41, + 0x4f, 0xac, 0x40, 0x30, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x38, 0xa2, 0x04, 0xcc, 0xa8, + 0xab, 0x3a, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x4a, 0x82, 0x0e, 0x40, 0xf8, 0x82, + 0x0e, 0xcc, 0xf8, 0x95, 0xa6, 0xa8, 0x2e, 0x9c, 0x00, 0x4b, 0xa8, 0x3a, 0x96, 0x38, + 0xfa, 0x9c, 0x00, 0x43, 0x35, 0x14, 0x3c, 0x35, 0x2b, 0x3c, 0xb6, 0xf9, 0xfa, 0xa8, + 0xb6, 0xf9, 0xfc, 0xfc, 0x5d, 0xb6, 0xf9, 0xfa, 0xa9, 0xb3, 0x01, 0x84, 0xf2, 0xf6, + 0xb3, 0x01, 0x90, 0x90, 0x40, 0xd6, 0x40, 0x40, 0x90, 0xc8, 0xd6, 0x40, 0x40, 0x97, + 0xdf, 0xd2, 0x90, 0x98, 0xd6, 0x3c, 0xb6, 0xf9, 0xfe, 0x88, 0x96, 0xc8, 0x10, 0x47, + 0x30, 0x0a, 0x91, 0x01, 0xb4, 0x85, 0x58, 0x99, 0xfe, 0x9c, 0xa4, 0x51, 0xb3, 0x01, + 0x90, 0x90, 0x40, 0xd6, 0x40, 0x40, 0x90, 0xc8, 0xd6, 0x40, 0x40, 0x97, 0xdf, 0xd2, + 0x3c, 0x00, 0xb6, 0xf9, 0xfa, 0xab, 0x34, 0x43, 0x95, 0x22, 0xb6, 0xff, 0x20, 0xa9, + 0x90, 0x01, 0xb6, 0x10, 0x00, 0x8e, 0x8b, 0x03, 0xaf, 0xcc, 0xaf, 0xce, 0xa2, 0x0a, + 0x72, 0x88, 0x9d, 0x01, 0x53, 0xa2, 0x12, 0x72, 0x88, 0xb5, 0xd2, 0xfa, 0xac, 0x76, + 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x20, 0x00, 0x94, 0x30, 0xa2, 0x10, 0x72, 0x88, + 0xb5, 0xd2, 0xe7, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, + 0x00, 0xb2, 0x20, 0x00, 0xaf, 0xcc, 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xd2, 0xcf, 0xac, + 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb3, 0x28, 0x00, 0x9c, 0x00, 0xb3, 0x20, 0x00, + 0x3f, 0xcc, 0x90, 0x52, 0xa2, 0x02, 0xcc, 0x8e, 0x8b, 0x02, 0xa2, 0x0a, 0x72, 0x88, + 0x9c, 0x01, 0x48, 0x90, 0x10, 0xa2, 0x02, 0xce, 0x8e, 0xab, 0x04, 0xc4, 0x9a, 0x04, + 0xc6, 0x90, 0x00, 0xa2, 0x08, 0xcc, 0x8e, 0xab, 0x06, 0x31, 0x03, 0x9c, 0x00, 0x94, + 0xa4, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x52, 0x90, 0xdb, 0xa2, 0x02, 0xcc, 0x8e, + 0x90, 0x52, 0xa2, 0x02, 0xce, 0x8e, 0x30, 0xea, 0x9c, 0x00, 0x94, 0xac, 0x33, 0xf8, + 0x90, 0x10, 0xb6, 0x10, 0x04, 0x8b, 0x91, 0x00, 0xb6, 0x10, 0x20, 0x88, 0x99, 0x08, + 0x9c, 0x00, 0x94, 0x60, 0x91, 0x00, 0xb6, 0x10, 0x24, 0x88, 0x99, 0x20, 0x9c, 0x00, + 0x94, 0x5a, 0x90, 0x08, 0xb6, 0x10, 0x04, 0x8b, 0x91, 0x00, 0xb6, 0x10, 0x20, 0x88, + 0x99, 0x04, 0x9c, 0x00, 0x94, 0x3c, 0x91, 0x00, 0xb6, 0x10, 0x24, 0x88, 0x99, 0x02, + 0x9c, 0x00, 0x94, 0x2a, 0xc4, 0x99, 0xfb, 0xc6, 0xa8, 0x06, 0xa2, 0x08, 0xcc, 0x8e, + 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x46, 0xa8, 0x04, 0xa2, 0x02, 0xce, 0x8e, 0x88, + 0x02, 0xa2, 0x02, 0xcc, 0x8e, 0x88, 0x03, 0xb6, 0x10, 0x00, 0x8b, 0x90, 0x01, 0x3f, + 0xce, 0x3f, 0xcc, 0x3c, 0x30, 0x16, 0x94, 0x4c, 0x95, 0x38, 0x30, 0x10, 0x94, 0x46, + 0x95, 0x4a, 0x30, 0x0a, 0x94, 0x40, 0x95, 0x6e, 0x30, 0x04, 0x94, 0x3a, 0x95, 0x68, + 0xae, 0xca, 0x05, 0xae, 0xca, 0x82, 0x00, 0xca, 0xfc, 0x3c, 0x3d, 0xa2, 0x0a, 0x72, + 0x88, 0x9c, 0x01, 0x4d, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xd1, 0xe3, 0x00, 0xa2, 0x0e, + 0x76, 0xab, 0x5e, 0xa2, 0x12, 0x72, 0x88, 0xb5, 0xd1, 0xd6, 0x00, 0xa2, 0x0e, 0x76, + 0xab, 0x51, 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xd1, 0xc9, 0x00, 0xa2, 0x0e, 0x76, 0xab, + 0x00, 0xa2, 0x00, 0x74, 0xab, 0xc4, 0x99, 0xfb, 0xc6, 0xa8, 0x06, 0xa2, 0x08, 0xcc, + 0x8e, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x46, 0xa8, 0x04, 0xa2, 0x02, 0xce, 0x8e, + 0x88, 0x02, 0xa2, 0x02, 0xcc, 0x8e, 0x88, 0x03, 0xb6, 0x10, 0x00, 0x8b, 0x00, 0x3f, + 0xce, 0x3f, 0xcc, 0x3c, 0x33, 0x12, 0x91, 0x00, 0xae, 0xca, 0xaa, 0xc8, 0x41, 0x3c, + 0xae, 0xca, 0xb6, 0x10, 0x1c, 0x88, 0x96, 0xc8, 0x17, 0x41, 0x70, 0x9a, 0x01, 0x3c, + 0xaf, 0xcc, 0x9c, 0x00, 0x94, 0x21, 0xb2, 0x20, 0x2e, 0x30, 0x0f, 0xa2, 0x0a, 0x72, + 0x88, 0x9c, 0x01, 0x45, 0xb2, 0x28, 0x2e, 0x30, 0x03, 0x3f, 0xcc, 0x3c, 0x90, 0x40, + 0x01, 0xd9, 0xc6, 0xa8, 0xe2, 0xba, 0x02, 0x00, 0xab, 0xe2, 0x3c, 0xb2, 0x20, 0x2e, + 0x30, 0x0f, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x7b, 0xb2, 0x28, 0x2e, 0x30, 0x03, + 0x3f, 0xcc, 0x3c, 0x90, 0x40, 0xda, 0xc6, 0xa8, 0xe2, 0xb9, 0xfd, 0xff, 0xab, 0xe2, + 0x3c, 0xb2, 0x20, 0x2e, 0xc4, 0x01, 0x99, 0x01, 0x3c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, + 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x82, 0x02, 0xcc, + 0xf8, 0x82, 0x00, 0xca, 0xfc, 0x50, 0x82, 0x01, 0xca, 0xfc, 0x4e, 0x82, 0x02, 0xca, + 0xfc, 0x4c, 0x90, 0x00, 0xc5, 0x3f, 0xcc, 0x3c, 0x90, 0x53, 0x66, 0x90, 0x71, 0x69, + 0x90, 0x71, 0x6c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, + 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x82, 0x02, 0xcc, 0xf8, 0xa2, 0x0a, 0x72, 0x88, 0x9d, + 0x01, 0x55, 0x82, 0x00, 0xca, 0xfc, 0x4a, 0x82, 0x08, 0xca, 0xfc, 0x48, 0x41, 0xc5, + 0x3f, 0xcc, 0x3c, 0x90, 0x5e, 0x66, 0x90, 0x61, 0x69, 0x82, 0x00, 0xca, 0xfc, 0x94, + 0x26, 0x82, 0x05, 0xca, 0xfc, 0x94, 0x25, 0x82, 0x09, 0xca, 0xfc, 0x94, 0x24, 0x82, + 0x06, 0xca, 0xfc, 0x94, 0x23, 0x82, 0x0a, 0xca, 0xfc, 0x5e, 0x82, 0x07, 0xca, 0xfc, + 0x94, 0x22, 0x82, 0x0c, 0xca, 0xfc, 0x94, 0x21, 0x3f, 0xcc, 0x3c, 0x91, 0x52, 0x90, + 0xdb, 0x5d, 0x90, 0x61, 0x91, 0x10, 0x58, 0x90, 0xf9, 0x91, 0x52, 0x53, 0x90, 0xdb, + 0x91, 0x61, 0x4e, 0x90, 0xdb, 0x91, 0xed, 0x49, 0x90, 0xdb, 0x91, 0x61, 0x44, 0x90, + 0xf9, 0x91, 0x61, 0xb2, 0x20, 0x02, 0xc5, 0xb2, 0x28, 0x02, 0xa8, 0xca, 0xc5, 0x3f, + 0xcc, 0x3c, 0xab, 0xca, 0xaf, 0xcc, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, + 0x00, 0xb2, 0x20, 0x00, 0x82, 0x00, 0xcc, 0xf8, 0x82, 0x00, 0xca, 0xfc, 0x47, 0xc4, + 0x9a, 0x20, 0xc6, 0x3f, 0xcc, 0x3c, 0x90, 0x20, 0x01, 0xd9, 0xc6, 0x3f, 0xcc, 0x3c, + 0xab, 0xca, 0xaf, 0xcc, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, + 0x20, 0x00, 0xa8, 0xca, 0x99, 0x08, 0x9c, 0x00, 0x4b, 0xa2, 0x18, 0xcc, 0x88, 0x9a, + 0x40, 0xa2, 0x18, 0xcc, 0x8b, 0x4b, 0x90, 0x40, 0x01, 0xa2, 0x18, 0xcc, 0xd9, 0xa2, + 0x18, 0xcc, 0x8b, 0x94, 0x30, 0xae, 0xca, 0x91, 0x00, 0xaf, 0xc8, 0x99, 0x01, 0x9d, + 0x00, 0x82, 0x02, 0xca, 0xfa, 0x3f, 0xc8, 0xaf, 0xc8, 0x99, 0x02, 0x9d, 0x00, 0x82, + 0x04, 0xca, 0xfa, 0x3f, 0xc8, 0xaf, 0xc8, 0x99, 0x04, 0x9d, 0x00, 0x82, 0x08, 0xca, + 0xfa, 0x3f, 0xc8, 0x99, 0x10, 0x9d, 0x00, 0x82, 0x20, 0xca, 0xfa, 0xa2, 0x16, 0xcc, + 0x88, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xe7, 0xab, 0xca, 0x82, 0x68, 0xca, 0xf8, 0xb2, + 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x00, 0xa2, 0x12, 0xcc, 0x8e, 0x8b, 0x10, + 0x00, 0xa2, 0x14, 0xcc, 0x8e, 0x8b, 0x11, 0x96, 0x10, 0x11, 0x96, 0x10, 0x0a, 0x82, + 0x2e, 0x10, 0xd9, 0x82, 0x40, 0x11, 0xd9, 0x88, 0x10, 0x96, 0x11, 0xda, 0xad, 0xca, + 0xfa, 0xab, 0x12, 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x07, 0x9c, 0x01, 0xa2, 0x10, 0xcc, + 0x88, 0x99, 0x07, 0x9c, 0x01, 0x4e, 0x9c, 0x02, 0x51, 0x9c, 0x06, 0x4e, 0x9c, 0x04, + 0x48, 0x9c, 0x05, 0x4b, 0x00, 0x4f, 0x90, 0x40, 0x49, 0x90, 0x08, 0x46, 0x90, 0x02, + 0x43, 0x90, 0x04, 0x40, 0xad, 0xca, 0xab, 0xa0, 0xc8, 0x12, 0xfa, 0xad, 0xca, 0xa8, + 0x99, 0x02, 0x9c, 0x00, 0x55, 0x90, 0x03, 0x01, 0xab, 0xca, 0xa2, 0x16, 0xcc, 0x88, + 0x96, 0xca, 0xf9, 0xa2, 0x16, 0xcc, 0x8b, 0x3f, 0xcc, 0xa8, 0x12, 0x3c, 0xa2, 0x16, + 0xcc, 0x88, 0x9a, 0x03, 0x6f, 0xaf, 0xcc, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, + 0x00, 0x82, 0x02, 0xca, 0xfc, 0x58, 0x82, 0x04, 0xca, 0xfc, 0x56, 0x82, 0x01, 0xca, + 0xfc, 0x54, 0x82, 0x08, 0xca, 0xfc, 0x52, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x4f, 0x3f, + 0xcc, 0x3c, 0x90, 0x06, 0x4b, 0x90, 0x05, 0x48, 0x90, 0x01, 0x45, 0x90, 0x04, 0x42, + 0x90, 0x00, 0xab, 0xca, 0x9c, 0x06, 0x30, 0x17, 0x90, 0x07, 0x01, 0xa2, 0x08, 0xcc, + 0xd9, 0x96, 0xca, 0xfa, 0xa2, 0x08, 0xcc, 0x8b, 0x82, 0x06, 0xca, 0xfc, 0x30, 0x08, + 0x3f, 0xcc, 0x3c, 0xc4, 0x9a, 0x40, 0xc6, 0x3c, 0x90, 0x40, 0x01, 0xd9, 0xc6, 0x3c, + 0xaf, 0xcc, 0xb2, 0x10, 0x00, 0xab, 0xca, 0xa2, 0x22, 0xcc, 0x88, 0x8b, 0x12, 0xa2, + 0x26, 0xcc, 0x88, 0x8b, 0x10, 0xa2, 0x2a, 0xcc, 0x88, 0x8b, 0x11, 0x82, 0x03, 0x12, + 0xda, 0x90, 0x20, 0x01, 0xa0, 0xc8, 0x10, 0xd9, 0x82, 0x00, 0xca, 0xfd, 0x82, 0x20, + 0x10, 0xda, 0x90, 0x02, 0x01, 0xa0, 0xc8, 0x10, 0xd9, 0x82, 0x00, 0xca, 0xfd, 0x82, + 0x02, 0x10, 0xda, 0x90, 0x01, 0x01, 0xa0, 0xc8, 0x10, 0xd9, 0x82, 0x00, 0xca, 0xfd, + 0x82, 0x01, 0x10, 0xda, 0x90, 0x10, 0x01, 0xa0, 0xc8, 0x11, 0xd9, 0x82, 0x00, 0xca, + 0xfd, 0x82, 0x10, 0x11, 0xda, 0x00, 0xa2, 0x24, 0xcc, 0x8e, 0x00, 0xa2, 0x28, 0xcc, + 0x8e, 0x88, 0x12, 0xa2, 0x22, 0xcc, 0x8b, 0x88, 0x10, 0xa2, 0x26, 0xcc, 0x8b, 0x88, + 0x11, 0xa2, 0x2a, 0xcc, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0x90, 0x04, 0xb2, 0x10, + 0x04, 0xc6, 0xc4, 0x96, 0xc8, 0x12, 0x64, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0x90, 0x04, + 0xb2, 0x10, 0x04, 0xc6, 0xc4, 0x96, 0xc8, 0x12, 0x64, 0xb6, 0x10, 0x00, 0x88, 0x9a, + 0x01, 0xb6, 0x10, 0x00, 0x8b, 0x90, 0x10, 0xc6, 0x3f, 0xcc, 0x3c, 0xc4, 0xa2, 0x01, + 0xcc, 0xda, 0xa2, 0x02, 0xcc, 0xda, 0xa2, 0x03, 0xcc, 0xda, 0xa2, 0x04, 0xcc, 0xda, + 0xa2, 0x05, 0xcc, 0xda, 0x9c, 0x00, 0x94, 0x85, 0xc4, 0xb6, 0xfe, 0xe0, 0x8b, 0xa2, + 0x01, 0xcc, 0x88, 0xb6, 0xfe, 0xe1, 0x8b, 0xa2, 0x02, 0xcc, 0x88, 0xb6, 0xfe, 0xe2, + 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xb6, 0xfe, 0xe3, 0x8b, 0xa2, 0x04, 0xcc, 0x88, 0xb6, + 0xfe, 0xe4, 0x8b, 0xa2, 0x05, 0xcc, 0x88, 0xb6, 0xfe, 0xe5, 0x8b, 0xa8, 0x02, 0xb6, + 0xfe, 0xe6, 0x8b, 0xa8, 0x0a, 0xb6, 0xfe, 0xe7, 0x8b, 0xa8, 0x04, 0xb6, 0xfe, 0xe8, + 0xab, 0xa8, 0x06, 0xb6, 0xfe, 0xea, 0xab, 0xa8, 0x08, 0xb6, 0xfe, 0xec, 0xab, 0x3c, + 0xab, 0x6e, 0xae, 0xca, 0xab, 0x70, 0x91, 0x10, 0xb4, 0x80, 0x06, 0xb6, 0x11, 0x26, + 0x88, 0x8b, 0x6c, 0xa8, 0xcc, 0xb6, 0x11, 0x26, 0x8b, 0x3c, 0xb6, 0x10, 0x3a, 0x88, + 0x8b, 0x6d, 0xa8, 0xcc, 0xb6, 0x10, 0x3a, 0x8b, 0x3c, 0xab, 0xca, 0x90, 0x08, 0x01, + 0xb6, 0x10, 0x02, 0xd9, 0x82, 0x00, 0xca, 0xfd, 0x9a, 0x08, 0xb6, 0x10, 0x02, 0x8b, + 0x3c, 0x82, 0x00, 0x7d, 0xdc, 0x3c, 0x00, 0x8b, 0x7d, 0x34, 0xd3, 0xb6, 0x10, 0x00, + 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x00, 0x8b, 0x00, 0x80, 0x6c, 0xcc, 0xab, 0x34, 0x47, + 0x80, 0x6d, 0xcc, 0xab, 0x34, 0x40, 0x00, 0x34, 0x36, 0xb6, 0x10, 0x00, 0x88, 0x9a, + 0x01, 0xb6, 0x10, 0x00, 0x8b, 0x34, 0xf9, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0xac, 0x74, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0x00, 0xb5, + 0xf6, 0xe1, 0x91, 0x20, 0xb4, 0x7f, 0x8c, 0x90, 0x04, 0x3c, 0xb6, 0x10, 0x00, 0x88, + 0xb7, 0x00, 0x00, 0x12, 0x96, 0xc8, 0x10, 0x30, 0x40, 0xb1, 0x10, 0x80, 0xc4, 0xad, + 0xca, 0x8b, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x02, 0xca, 0x8b, 0xa2, 0x02, 0xcc, 0x88, + 0xa2, 0x04, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xa2, 0x06, 0xca, 0x8b, 0xa2, 0x04, + 0xcc, 0x88, 0xa2, 0x08, 0xca, 0x8b, 0xa2, 0x05, 0xcc, 0x88, 0xa2, 0x0a, 0xca, 0x8b, + 0x82, 0x00, 0x12, 0xfc, 0x4a, 0xb6, 0x10, 0x00, 0x88, 0x9a, 0x01, 0xb6, 0x10, 0x00, + 0x8b, 0x00, 0x3c, 0xb6, 0x10, 0x00, 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x00, 0x8b, 0xb7, + 0x00, 0x01, 0x12, 0x3c, 0x3c, 0xaf, 0xcc, 0xb2, 0x10, 0x00, 0xc4, 0xab, 0xca, 0x82, + 0x01, 0x02, 0xfc, 0x94, 0x25, 0x82, 0x00, 0x7d, 0xdd, 0x46, 0xa8, 0xca, 0xc6, 0x3f, + 0xcc, 0x3c, 0xaf, 0xca, 0x34, 0xc7, 0x3f, 0xca, 0x90, 0x40, 0x01, 0xb6, 0x10, 0x2a, + 0xd9, 0xb6, 0x10, 0x2a, 0x8b, 0x90, 0x01, 0x01, 0x96, 0xca, 0xf9, 0xab, 0xca, 0x7f, + 0x00, 0xc5, 0x40, 0xad, 0x0a, 0xa8, 0xb6, 0xda, 0xd6, 0xab, 0xa2, 0xa6, 0xcc, 0x8b, + 0x8c, 0xc9, 0xc8, 0xa2, 0xa4, 0xcc, 0x8b, 0xa2, 0x02, 0x0a, 0xa8, 0xb6, 0xda, 0xd8, + 0xab, 0xa2, 0xa2, 0xcc, 0x8b, 0x8c, 0xc9, 0xc8, 0xa2, 0xa0, 0xcc, 0x8b, 0xb7, 0x02, + 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xa6, 0x01, 0x2e, 0xcc, 0x88, 0x9c, 0x00, 0x4e, + 0xae, 0x02, 0x03, 0xe7, 0xae, 0x02, 0xae, 0x04, 0xf7, 0xae, 0x04, 0xaa, 0xc8, 0x6d, + 0xa8, 0x02, 0x01, 0x03, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa8, 0x04, 0x01, 0x82, 0x00, + 0xc8, 0xe8, 0xab, 0x04, 0xa2, 0x02, 0x06, 0xfd, 0x94, 0x61, 0xa2, 0x02, 0x06, 0xfc, + 0x94, 0x53, 0xad, 0x06, 0xa8, 0x01, 0x03, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa2, 0x02, + 0x06, 0xa8, 0x01, 0x82, 0x00, 0xc8, 0xe8, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x82, + 0x0f, 0x06, 0xfc, 0x94, 0x2c, 0xb7, 0x02, 0x00, 0x10, 0xb7, 0x00, 0x00, 0x12, 0xa8, + 0x06, 0xae, 0x10, 0x03, 0xe7, 0xae, 0x10, 0xae, 0x12, 0xf7, 0xae, 0x12, 0xaa, 0xc8, + 0x6d, 0xa0, 0x04, 0x12, 0xfd, 0x4f, 0xa0, 0x04, 0x12, 0xfc, 0x44, 0xa9, 0x06, 0x95, + 0x2a, 0xa0, 0x02, 0x10, 0xfd, 0x41, 0x69, 0xa8, 0x06, 0xa6, 0x01, 0x2e, 0xcc, 0x8b, + 0x48, 0xa8, 0x02, 0xad, 0x06, 0xfd, 0x42, 0x95, 0x59, 0xb7, 0x02, 0x00, 0x10, 0xb7, + 0x00, 0x00, 0x12, 0xa6, 0x01, 0x26, 0xcc, 0x88, 0x9c, 0x00, 0x4e, 0xae, 0x10, 0x03, + 0xe7, 0xae, 0x10, 0xae, 0x12, 0xf7, 0xae, 0x12, 0xaa, 0xc8, 0x6d, 0xa8, 0x10, 0x03, + 0x01, 0xb8, 0x00, 0x01, 0xab, 0x10, 0xa8, 0x12, 0x01, 0x82, 0x00, 0xc8, 0xe8, 0xab, + 0x12, 0xa2, 0x02, 0x08, 0xfd, 0x94, 0x58, 0xa2, 0x02, 0x08, 0xfc, 0x94, 0x59, 0xad, + 0x08, 0xa8, 0x03, 0x01, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa2, 0x02, 0x08, 0xa8, 0x01, + 0x82, 0x00, 0xc8, 0xe8, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x0a, 0x82, 0x0f, 0x0a, 0xfc, + 0x94, 0x2c, 0xb7, 0x02, 0x00, 0x06, 0xb7, 0x00, 0x00, 0x08, 0xa8, 0x0a, 0xae, 0x06, + 0x03, 0xe7, 0xae, 0x06, 0xae, 0x08, 0xf7, 0xae, 0x08, 0xaa, 0xc8, 0x6d, 0xa0, 0x04, + 0x08, 0xfd, 0x4f, 0xa0, 0x04, 0x08, 0xfc, 0x44, 0xa9, 0x0a, 0x95, 0x2a, 0xa0, 0x02, + 0x06, 0xfd, 0x41, 0x69, 0xa8, 0x0a, 0xa6, 0x01, 0x26, 0xcc, 0x8b, 0x82, 0x01, 0xca, + 0xfa, 0xb4, 0xfe, 0x8c, 0xa8, 0x10, 0xad, 0x08, 0xfd, 0x6c, 0x95, 0x5f, 0x90, 0x00, + 0x3c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, 0x22, 0xce, 0x88, 0xe7, 0xb8, 0x00, 0x54, 0xae, + 0xca, 0xad, 0xca, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, + 0x20, 0x00, 0xad, 0xca, 0xa8, 0x9d, 0xff, 0x90, 0xff, 0xa2, 0x2a, 0xcc, 0x8b, 0xab, + 0xcc, 0xad, 0xca, 0xa8, 0x02, 0x96, 0xcc, 0xeb, 0xad, 0xca, 0xab, 0x3f, 0xcc, 0x3c, + 0xaf, 0xcc, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, + 0xa2, 0x2c, 0xcc, 0x88, 0xab, 0xca, 0xa2, 0x22, 0xce, 0x88, 0xe7, 0xb8, 0x00, 0x54, + 0xad, 0xc8, 0xa8, 0x96, 0xca, 0xf8, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, + 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x82, 0x01, 0xca, + 0xfc, 0x5c, 0x90, 0x10, 0x82, 0x00, 0xca, 0xfc, 0x4b, 0xa2, 0x06, 0xcc, 0xda, 0xa2, + 0x06, 0xcc, 0x8b, 0x3f, 0xcc, 0x3c, 0x01, 0xa2, 0x06, 0xcc, 0xd9, 0xa2, 0x06, 0xcc, + 0x8b, 0x6c, 0xa2, 0x2a, 0xcc, 0x88, 0xa2, 0x2a, 0xcc, 0x8b, 0x90, 0x10, 0x01, 0xa2, + 0x04, 0xcc, 0xd9, 0xa2, 0x04, 0xcc, 0x8b, 0x95, 0x2f, 0x3c, 0x3c, 0xaf, 0xcc, 0xab, + 0xca, 0xb7, 0x00, 0x00, 0x10, 0xb7, 0x00, 0x00, 0x12, 0x80, 0x7e, 0x12, 0xfc, 0x94, + 0x4f, 0xa8, 0x12, 0xb5, 0xca, 0xbe, 0xa2, 0x4e, 0x76, 0xa8, 0x9c, 0x08, 0x43, 0xa9, + 0x12, 0x74, 0xa2, 0x64, 0x76, 0xa8, 0x96, 0xca, 0xfc, 0x4f, 0x90, 0x02, 0x96, 0xca, + 0xfd, 0x41, 0x71, 0xa2, 0x62, 0x76, 0xa8, 0x9c, 0x04, 0x41, 0x79, 0x91, 0x01, 0xa2, + 0x22, 0x76, 0x88, 0xb5, 0xfb, 0x3d, 0xb7, 0x15, 0x5c, 0x02, 0xb7, 0x00, 0x00, 0x04, + 0xb7, 0x02, 0x00, 0x06, 0xac, 0x76, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, 0xa2, 0x22, 0x76, + 0x88, 0xb5, 0xf3, 0xeb, 0xb7, 0x00, 0x01, 0x10, 0x95, 0x41, 0x82, 0x00, 0x10, 0xfd, + 0x4c, 0x00, 0xb5, 0xca, 0x57, 0xa2, 0x54, 0x74, 0xa8, 0x96, 0xca, 0xfc, 0x43, 0x3f, + 0xcc, 0x3c, 0xb5, 0xfb, 0xeb, 0x66, 0x97, 0x00, 0xd0, 0x83, 0x44, 0x01, 0x91, 0x8b, + 0x40, 0x40, 0x83, 0xcc, 0x01, 0x91, 0x8b, 0x83, 0x00, 0x01, 0x86, 0xab, 0x83, 0x00, + 0x01, 0x8a, 0xab, 0x83, 0x00, 0x01, 0x88, 0xab, 0x83, 0x00, 0x01, 0x8c, 0xab, 0x83, + 0x44, 0x01, 0x91, 0x8b, 0x96, 0xd0, 0x0d, 0xa8, 0xbe, 0x99, 0x03, 0x9c, 0x00, 0x94, + 0x4c, 0xb2, 0x10, 0x00, 0x00, 0xc5, 0xb2, 0x10, 0x04, 0x90, 0x04, 0xc6, 0xc4, 0x96, + 0xc8, 0x12, 0x64, 0xb2, 0x10, 0x5e, 0x90, 0x0b, 0xc5, 0xb2, 0x10, 0x22, 0x90, 0x03, + 0xc5, 0xb2, 0x10, 0x26, 0x90, 0x23, 0xc5, 0xb2, 0x10, 0x2a, 0x90, 0x10, 0xc5, 0xb2, + 0x10, 0x3a, 0x90, 0x3f, 0xc5, 0xb2, 0x10, 0x32, 0x90, 0x20, 0xc5, 0x91, 0x20, 0xb2, + 0x11, 0x7e, 0x00, 0xc5, 0x02, 0x82, 0x02, 0xcc, 0xeb, 0xaa, 0xca, 0x69, 0xb2, 0x10, + 0x00, 0x90, 0x01, 0xc6, 0x96, 0xd0, 0x0a, 0xb0, 0x07, 0xef, 0x9e, 0x32, 0x03, 0xae, + 0xce, 0xd7, 0xae, 0xce, 0xd7, 0x03, 0xae, 0xce, 0xd7, 0xae, 0xce, 0xd7, 0xab, 0x58, + 0xa8, 0xbe, 0x99, 0x0c, 0xc7, 0xc7, 0x99, 0x03, 0x04, 0xab, 0xca, 0xb2, 0x20, 0x00, + 0x96, 0xd0, 0x1b, 0x96, 0xd0, 0x1c, 0x97, 0xe7, 0xd2, 0xb7, 0x00, 0x00, 0x02, 0xac, + 0xca, 0x04, 0xa8, 0xcc, 0x30, 0x51, 0xa9, 0x02, 0xb2, 0x28, 0x00, 0xac, 0x04, 0xca, + 0xaa, 0xca, 0x71, 0x96, 0xd0, 0x0b, 0xa8, 0xbe, 0x99, 0x0c, 0x9d, 0x00, 0x96, 0xd0, + 0x0c, 0xb0, 0x50, 0x06, 0xb6, 0xff, 0xa6, 0xab, 0x05, 0xb6, 0xff, 0xa4, 0xab, 0xb0, + 0x50, 0x07, 0xb6, 0xff, 0xaa, 0xab, 0x05, 0xb6, 0xff, 0xa8, 0xab, 0xb0, 0x50, 0x08, + 0xb6, 0xff, 0xae, 0xab, 0x05, 0xb6, 0xff, 0xac, 0xab, 0xb0, 0x50, 0x09, 0xb6, 0xff, + 0xb2, 0xab, 0x05, 0xb6, 0xff, 0xb0, 0xab, 0x3c, 0xae, 0xca, 0x05, 0x9c, 0x00, 0x59, + 0xae, 0xca, 0x4e, 0xab, 0xca, 0x00, 0xc5, 0xaf, 0xca, 0x91, 0xff, 0x90, 0x01, 0xa2, + 0x3c, 0xcc, 0x8e, 0xa2, 0x3c, 0xcc, 0x88, 0x96, 0xc8, 0x10, 0x7e, 0x3f, 0xca, 0xac, + 0xcc, 0xce, 0x82, 0x30, 0xce, 0xf8, 0x92, 0xce, 0xd4, 0x9d, 0x11, 0x4a, 0xc7, 0x0e, + 0x90, 0x01, 0x06, 0xd6, 0x0b, 0x09, 0x8f, 0x0e, 0xac, 0xca, 0xcc, 0xb6, 0xff, 0x02, + 0xa8, 0x9c, 0x02, 0x54, 0xa2, 0x78, 0xcc, 0x88, 0x9a, 0x08, 0xa2, 0x78, 0xcc, 0x8b, + 0xa2, 0x76, 0xcc, 0x88, 0x9a, 0x08, 0xa2, 0x76, 0xcc, 0x8b, 0x00, 0xa2, 0x4c, 0xcc, + 0x8b, 0x88, 0x59, 0x99, 0x7f, 0xa2, 0x1a, 0xcc, 0x8e, 0x90, 0xff, 0xa2, 0x1c, 0xcc, + 0x8e, 0x88, 0x59, 0xa2, 0x22, 0xcc, 0x8e, 0x90, 0xff, 0xa2, 0x24, 0xcc, 0x8e, 0xa8, + 0x02, 0xb5, 0xf9, 0x00, 0x90, 0x2f, 0xa2, 0x16, 0xcc, 0x8e, 0x00, 0xa2, 0x18, 0xcc, + 0x8e, 0x00, 0xa2, 0x12, 0xcc, 0x8e, 0x00, 0xa2, 0x14, 0xcc, 0x8e, 0x00, 0xa2, 0x04, + 0xcc, 0x8e, 0x90, 0x60, 0xa2, 0x06, 0xcc, 0x8e, 0x90, 0xa6, 0xa2, 0x08, 0xcc, 0x8e, + 0x90, 0x98, 0xa2, 0x02, 0xcc, 0x8e, 0xc4, 0x9a, 0x21, 0xc5, 0x3c, 0xa2, 0x06, 0xcc, + 0xa8, 0xb2, 0x10, 0x00, 0x91, 0x5a, 0xbc, 0x20, 0x33, 0xb4, 0x01, 0x28, 0xbc, 0x20, + 0x35, 0xb4, 0x01, 0x30, 0xbc, 0x20, 0x48, 0x94, 0x69, 0xbc, 0x20, 0x47, 0x94, 0x47, + 0xbc, 0x20, 0x34, 0x94, 0x20, 0xbc, 0x20, 0x36, 0xb4, 0x01, 0x22, 0xbc, 0x20, 0x49, + 0x94, 0x72, 0xbc, 0x20, 0x4a, 0x94, 0x8b, 0xbc, 0x20, 0x51, 0x94, 0xa4, 0xbc, 0x20, + 0x52, 0x94, 0xbd, 0xbc, 0x20, 0x54, 0x94, 0xd6, 0x3c, 0xa6, 0x01, 0x36, 0xcc, 0x88, + 0xd6, 0xa6, 0x01, 0x34, 0xcc, 0x88, 0xa2, 0x01, 0xce, 0x8b, 0xa6, 0x01, 0x32, 0xcc, + 0x88, 0xa2, 0x02, 0xce, 0x8b, 0xa6, 0x01, 0x30, 0xcc, 0x88, 0xa2, 0x03, 0xce, 0x8b, + 0x3c, 0xa6, 0x01, 0x46, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x44, 0xcc, 0x88, 0x8b, + 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x42, 0xcc, 0x88, 0x99, 0x0f, 0xad, 0xca, 0xfa, + 0xf1, 0x3c, 0xa6, 0x01, 0x5e, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x5c, 0xcc, 0x88, + 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x5a, 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x06, + 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x6e, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x6c, + 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x6a, 0xcc, 0x88, 0x99, 0x0f, + 0xa2, 0x0a, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x76, 0xcc, 0x88, 0xab, 0x02, 0xa6, + 0x01, 0x74, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x72, 0xcc, 0x88, + 0x99, 0x0f, 0xa2, 0x0c, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x4e, 0xcc, 0x88, 0xab, + 0x02, 0xa6, 0x01, 0x4c, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x4a, + 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x02, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x56, 0xcc, + 0x88, 0xab, 0x02, 0xa6, 0x01, 0x54, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, + 0x01, 0x52, 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x04, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, + 0x66, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x64, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, + 0xf1, 0xa6, 0x01, 0x62, 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x08, 0xca, 0xfa, 0xf1, 0x3c, + 0xb6, 0xda, 0xd6, 0xa8, 0xb9, 0xff, 0x00, 0xf1, 0xb6, 0xda, 0xd8, 0xa8, 0xf1, 0x3c, + 0xa6, 0x01, 0x26, 0xcc, 0x88, 0xf1, 0x3c, 0xa6, 0x01, 0x2e, 0xcc, 0x88, 0xf1, 0x3c, + 0xb7, 0x02, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0x9c, 0x00, 0x4e, 0xae, 0x02, 0x03, + 0xe7, 0xae, 0x02, 0xae, 0x04, 0xf7, 0xae, 0x04, 0xaa, 0xc8, 0x6d, 0xa8, 0x02, 0x01, + 0x03, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa8, 0x04, 0x01, 0x82, 0x00, 0xc8, 0xe8, 0xab, + 0x04, 0x3c, 0xa2, 0x2f, 0xce, 0xdc, 0x3c, 0xa2, 0x2f, 0xce, 0x8b, 0xab, 0xca, 0xa2, + 0x54, 0xce, 0xa8, 0x9c, 0x00, 0x94, 0x26, 0x9c, 0x01, 0x41, 0x3c, 0xa2, 0x1c, 0x72, + 0xa8, 0x82, 0x00, 0xca, 0xfd, 0x04, 0x82, 0x00, 0xca, 0xfc, 0x05, 0xa2, 0x1c, 0x72, + 0xab, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, + 0xb4, 0xc8, 0x93, 0xa2, 0x1a, 0x72, 0xa8, 0x82, 0x00, 0xca, 0xfd, 0x04, 0x82, 0x00, + 0xca, 0xfc, 0x05, 0xa2, 0x1a, 0x72, 0xab, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xc8, 0x71, 0xa2, 0x15, 0x72, 0x88, 0x9c, + 0x00, 0x4d, 0xa2, 0x2f, 0xce, 0x88, 0x9d, 0x00, 0x46, 0x90, 0x01, 0xb5, 0xf7, 0xcc, + 0x45, 0x90, 0x00, 0xb5, 0xf7, 0xc6, 0xb7, 0x62, 0x5a, 0x02, 0xb7, 0x00, 0x02, 0x04, + 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, + 0x88, 0xb4, 0xf0, 0x17, 0xa2, 0x32, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x25, 0xa2, 0x54, + 0xce, 0xa8, 0xb5, 0xc6, 0xab, 0xa2, 0x00, 0x78, 0xa8, 0xab, 0x02, 0xa2, 0x02, 0x78, + 0xa8, 0xab, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, + 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xef, 0xea, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, + 0xce, 0x88, 0xb4, 0xef, 0xd0, 0xa2, 0x2d, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x1f, 0xb7, + 0xbc, 0x20, 0x02, 0xb7, 0x00, 0xbe, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, + 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0xae, 0x90, 0x01, 0xb4, + 0xf7, 0x3e, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x04, 0x00, 0x06, + 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x8f, + 0x7f, 0xa2, 0x2d, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x1f, 0xb7, 0xbc, 0x20, 0x02, 0xb7, + 0x00, 0xbe, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, + 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x6c, 0x90, 0x01, 0xb4, 0xf6, 0xfc, 0xb7, 0x9a, + 0xca, 0x02, 0xb7, 0x00, 0x3b, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, + 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x4d, 0x7f, 0x90, 0x00, 0xb5, + 0xf8, 0xca, 0xb7, 0x00, 0x00, 0x02, 0xac, 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, + 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf7, 0x5f, 0x90, 0x29, 0xa2, 0x3a, 0xce, 0xab, + 0xb0, 0xd2, 0x4d, 0x91, 0x08, 0xb5, 0xf7, 0xb6, 0x3c, 0xb7, 0x00, 0x00, 0x02, 0xac, + 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf7, + 0x2e, 0x90, 0x2a, 0xa2, 0x3a, 0xce, 0xab, 0xb0, 0xf4, 0x7d, 0x91, 0x01, 0xb5, 0xf7, + 0x85, 0x3c, 0xaf, 0xc8, 0xb7, 0x00, 0x01, 0x02, 0xa2, 0x54, 0xce, 0xa8, 0xab, 0x04, + 0xac, 0xce, 0x06, 0x82, 0x42, 0x06, 0xf8, 0xac, 0xce, 0x08, 0x82, 0x3e, 0x08, 0xf8, + 0xac, 0xce, 0x0a, 0x82, 0x3e, 0x0a, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf8, 0x41, + 0x90, 0x01, 0xa2, 0x2b, 0xce, 0x8b, 0x3f, 0xc8, 0x9c, 0x02, 0x95, 0x99, 0x95, 0x65, + 0xb7, 0x01, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, + 0xc6, 0xc6, 0xac, 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb5, 0xf7, 0xb9, 0x9d, 0x00, + 0x94, 0x2c, 0xa2, 0x54, 0xce, 0xa8, 0xb5, 0xfa, 0x44, 0xa2, 0x2c, 0xce, 0x88, 0x9c, + 0x00, 0x52, 0x90, 0x00, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, + 0xb0, 0x20, 0x70, 0xb5, 0x0a, 0x52, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, + 0x29, 0xb4, 0x0a, 0x46, 0x9c, 0x02, 0x95, 0x82, 0x9c, 0x03, 0x95, 0x86, 0x95, 0x52, + 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0x06, 0x82, 0x0e, 0x06, + 0xf8, 0xac, 0xce, 0x08, 0x82, 0x0a, 0x08, 0xf8, 0xac, 0xce, 0x0a, 0x82, 0x0a, 0x0a, + 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf7, 0xbb, 0x90, 0x00, 0xa2, 0x27, 0xce, 0x8b, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x74, 0xb5, 0x0a, 0x06, 0x90, 0x00, + 0xa2, 0x26, 0xce, 0x8b, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, 0x33, 0xce, 0x8b, 0xa2, 0x22, + 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x09, 0xec, 0x90, 0x01, 0x36, 0x9c, + 0x90, 0x00, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, + 0x6f, 0xb5, 0x09, 0xd6, 0x90, 0x00, 0xb4, 0xf5, 0x85, 0xb7, 0x00, 0x01, 0x02, 0xa2, + 0x54, 0xce, 0xa8, 0xab, 0x04, 0xac, 0xce, 0x06, 0x82, 0x42, 0x06, 0xf8, 0xac, 0xce, + 0x08, 0x82, 0x3e, 0x08, 0xf8, 0xac, 0xce, 0x0a, 0x82, 0x46, 0x0a, 0xf8, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xf7, 0x4e, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf5, 0xd0, 0xb4, 0xf5, + 0xdd, 0x90, 0x00, 0xa2, 0x27, 0xce, 0x8b, 0xa2, 0x26, 0xce, 0x8b, 0xa2, 0x33, 0xce, + 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x74, 0xb5, 0x09, 0x87, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x09, 0x7b, 0x90, 0x01, 0xa2, + 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x09, + 0x69, 0xa2, 0x2e, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfd, 0x35, 0x40, 0x90, 0x00, 0x37, + 0x29, 0xa2, 0x29, 0xce, 0x88, 0x9c, 0x00, 0x46, 0x90, 0x01, 0xa2, 0x26, 0xce, 0x8b, + 0xa2, 0x2a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x26, 0x90, 0x01, 0xa2, 0x33, 0xce, 0x8b, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x09, 0x34, 0xa2, 0x02, + 0xce, 0x88, 0xa2, 0x27, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, + 0x74, 0xb5, 0x09, 0x20, 0x90, 0x02, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, + 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x09, 0x0e, 0x90, 0x00, 0xb5, 0xf4, 0xbd, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xf8, 0x34, 0xa2, 0x32, 0xce, 0x8b, 0xb4, 0xfd, 0x03, 0x90, + 0x03, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, + 0xb5, 0x08, 0xe9, 0xa2, 0x2e, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfd, 0x2f, 0x95, 0x7f, + 0xa2, 0x2c, 0xce, 0x88, 0x9d, 0x00, 0x52, 0x90, 0x01, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, 0xb5, 0x08, 0xc5, 0x90, 0x00, 0xa2, + 0x2d, 0xce, 0x8b, 0xa2, 0x2b, 0xce, 0x8b, 0xa2, 0x20, 0xce, 0xa8, 0x9c, 0x01, 0xb4, + 0xfe, 0x32, 0x9c, 0x04, 0xb4, 0xfe, 0x1d, 0xb4, 0xfd, 0xe4, 0xa2, 0x2b, 0xce, 0x88, + 0x9c, 0x00, 0x4c, 0xa2, 0x20, 0xce, 0xa8, 0x9c, 0x02, 0xb4, 0xfd, 0x6d, 0xb4, 0xfd, + 0xa0, 0x90, 0x01, 0x37, 0xf1, 0xa2, 0x20, 0xce, 0xa8, 0x9c, 0x01, 0xb4, 0xfe, 0x0a, + 0x9c, 0x04, 0xb4, 0xfd, 0xf5, 0xb4, 0xfd, 0xbc, 0x90, 0x04, 0xa2, 0x3a, 0xce, 0xab, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x08, 0x70, 0xa2, 0x2e, + 0xce, 0x88, 0x9d, 0x00, 0x95, 0xf5, 0xb4, 0xfc, 0xf6, 0x90, 0x05, 0xa2, 0x3a, 0xce, + 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x08, 0x53, 0x90, + 0x00, 0xb5, 0xf4, 0x02, 0xb5, 0xf7, 0x7d, 0xa2, 0x32, 0xce, 0x8b, 0xb4, 0xfc, 0x4c, + 0xb7, 0x00, 0x01, 0x02, 0xb2, 0x43, 0xb7, 0xa2, 0x18, 0xce, 0xa8, 0xab, 0x04, 0xa2, + 0x1a, 0xce, 0xa8, 0xab, 0x06, 0xa2, 0x1c, 0xce, 0xa8, 0xab, 0x08, 0xb7, 0x00, 0x06, + 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf4, 0x79, 0x90, 0x06, 0xa2, 0x3a, 0xce, 0xab, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x08, 0x0e, 0xb0, 0xd2, + 0x4d, 0x91, 0x08, 0xb5, 0xf4, 0xc4, 0x3c, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xec, 0x0a, 0x90, 0x07, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x07, 0xd9, 0x90, 0x00, 0xb5, 0xf3, 0x88, + 0xb7, 0x01, 0x03, 0x02, 0xb7, 0x00, 0x02, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0xce, 0x88, 0xb4, 0xc4, 0x07, 0xb5, 0xf3, 0xea, 0xb4, 0xf3, 0xf7, 0xa8, 0x46, 0xb5, + 0xc2, 0x50, 0xa2, 0x00, 0x74, 0xa8, 0x9c, 0x00, 0x3c, 0xa8, 0x44, 0xbc, 0x04, 0x01, + 0x94, 0xbf, 0xbc, 0x04, 0x02, 0x94, 0xc2, 0xbc, 0x04, 0x0e, 0x94, 0xc5, 0xa2, 0x3a, + 0x74, 0xa8, 0x9c, 0x00, 0x54, 0xa2, 0x29, 0x74, 0x88, 0x9d, 0x00, 0x4d, 0xa2, 0x2a, + 0x74, 0x88, 0x9d, 0x00, 0x46, 0xac, 0x74, 0xce, 0xb4, 0xfd, 0x47, 0xa8, 0x44, 0xbc, + 0x04, 0x03, 0x94, 0xaf, 0xbc, 0x04, 0xff, 0x94, 0x3a, 0xa2, 0x3a, 0x74, 0xa8, 0x9c, + 0x00, 0x94, 0xae, 0x9c, 0x01, 0x94, 0xcb, 0x9c, 0x02, 0xb4, 0x01, 0x67, 0x9c, 0x03, + 0xb4, 0x02, 0x1a, 0x9c, 0x04, 0xb4, 0x02, 0xec, 0x9c, 0x05, 0xb4, 0x03, 0x96, 0x9c, + 0x06, 0xb4, 0x04, 0x40, 0x9c, 0x07, 0xb4, 0x04, 0x8f, 0x9c, 0x29, 0xb4, 0x04, 0x8b, + 0x9c, 0x2a, 0xb4, 0x04, 0xa0, 0x9c, 0x2b, 0xb4, 0x04, 0xd6, 0x3c, 0xa2, 0x3a, 0x74, + 0xa8, 0x9c, 0x03, 0x50, 0xa2, 0x34, 0x74, 0xa8, 0x96, 0x48, 0xfc, 0x41, 0x3c, 0x00, + 0xa2, 0x34, 0x74, 0xab, 0x95, 0x4f, 0xa2, 0x36, 0x74, 0xa8, 0x96, 0x48, 0xfc, 0x94, + 0x23, 0xa2, 0x38, 0x74, 0xa8, 0x96, 0x48, 0xfc, 0x42, 0x95, 0x21, 0xa2, 0x2d, 0x74, + 0x88, 0x9d, 0x00, 0x95, 0x6a, 0x90, 0x01, 0xa2, 0x31, 0x74, 0x8b, 0x00, 0xa2, 0x38, + 0x74, 0xab, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0x49, 0x90, 0x01, 0xa2, 0x30, 0x74, 0x8b, + 0x00, 0xa2, 0x36, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0x38, 0xa8, 0x48, 0xa2, + 0x29, 0x74, 0x8b, 0x95, 0xbb, 0xa8, 0x48, 0xa2, 0x2a, 0x74, 0x8b, 0x95, 0xc3, 0xa8, + 0x48, 0xa2, 0x28, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xe4, 0x87, 0xa8, 0x48, 0x9d, + 0x00, 0x90, 0x01, 0xa2, 0x2e, 0x74, 0x8b, 0x95, 0xb4, 0xa8, 0x44, 0xbc, 0x04, 0x01, + 0x45, 0xbc, 0x04, 0x02, 0x41, 0x3c, 0xa2, 0x29, 0x74, 0x88, 0x9d, 0x00, 0x47, 0xa2, + 0x2a, 0x74, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0x37, 0x2c, 0xb4, 0xfc, 0xff, + 0xa8, 0x44, 0xbc, 0x04, 0x03, 0x4a, 0xbc, 0x04, 0xff, 0x53, 0xbc, 0x04, 0x04, 0x94, + 0x79, 0x3c, 0xa2, 0x2e, 0x74, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0x36, 0xd9, + 0x3c, 0x90, 0x00, 0xa2, 0x27, 0x74, 0x8b, 0xa2, 0x26, 0x74, 0x8b, 0xa2, 0x33, 0x74, + 0x8b, 0xa2, 0x2d, 0x74, 0x8b, 0xa2, 0x30, 0x74, 0x8b, 0xa2, 0x31, 0x74, 0x8b, 0xa2, + 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x74, 0xb5, 0x06, 0x5d, 0xa2, 0x22, 0x74, + 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x06, 0x51, 0xb7, 0x00, 0x00, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xac, 0x74, 0xcc, 0x82, 0x36, 0xcc, 0xf8, + 0x00, 0xb5, 0xea, 0x59, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xac, 0x74, 0xcc, 0x82, 0x38, 0xcc, 0xf8, 0x00, 0xb5, 0xea, 0x42, 0x90, + 0x01, 0xac, 0x74, 0xce, 0xb5, 0xf9, 0x95, 0xb4, 0xfd, 0x1d, 0xa2, 0x2f, 0x74, 0x88, + 0x9d, 0x00, 0x3c, 0xa8, 0x48, 0x99, 0x0e, 0x9c, 0x00, 0x3c, 0x90, 0x01, 0xac, 0x74, + 0xce, 0xb5, 0xf9, 0x7c, 0xb4, 0xf9, 0xd4, 0xa8, 0x44, 0xbc, 0x04, 0x03, 0x54, 0xbc, + 0x04, 0x06, 0x5e, 0xbc, 0x04, 0x04, 0x94, 0x54, 0xbc, 0x04, 0xff, 0x94, 0x82, 0xbc, + 0x04, 0x0d, 0x94, 0x93, 0x3c, 0xa2, 0x2e, 0x74, 0x88, 0x9d, 0x00, 0x46, 0xac, 0x74, + 0xce, 0xb4, 0xfc, 0x37, 0x3c, 0xa8, 0x48, 0x9c, 0x02, 0x41, 0x3c, 0x90, 0x00, 0xa2, + 0x27, 0x74, 0x8b, 0xa2, 0x26, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, + 0x20, 0x74, 0xb5, 0x05, 0xbb, 0xa2, 0x2c, 0x74, 0x88, 0x9d, 0x00, 0x52, 0x90, 0x01, + 0xa2, 0x2c, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, 0xb5, + 0x05, 0xa2, 0xac, 0x74, 0xce, 0xb4, 0xfd, 0x37, 0xa8, 0x48, 0x99, 0x10, 0x9c, 0x00, + 0x3c, 0xa2, 0x54, 0x74, 0xa8, 0xb5, 0xc0, 0x50, 0xa2, 0x00, 0x78, 0xa8, 0xa2, 0x02, + 0x78, 0xfa, 0x9c, 0x00, 0x4c, 0x90, 0x01, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, 0xce, + 0xb4, 0xf9, 0x7f, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, 0xce, 0x36, 0x53, + 0xb4, 0xfb, 0xc8, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xa8, 0x46, 0xb5, 0xf4, 0x90, + 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0x36, 0x69, 0xb4, 0xfb, 0xb2, 0xa8, 0x48, 0xa2, + 0x02, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0xe8, 0xa8, 0x44, 0xbc, 0x04, 0x03, + 0x4a, 0xbc, 0x04, 0x04, 0x54, 0xbc, 0x04, 0xff, 0x94, 0xb4, 0x3c, 0xa2, 0x2e, 0x74, + 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb5, 0xfb, 0xcb, 0x3c, 0xa8, 0x48, 0x99, + 0x01, 0x9c, 0x00, 0x48, 0xa2, 0x30, 0x74, 0x88, 0x9d, 0x00, 0x94, 0x4b, 0xa8, 0x48, + 0x99, 0x02, 0x9c, 0x00, 0x48, 0xa2, 0x31, 0x74, 0x88, 0x9d, 0x00, 0x94, 0x3c, 0xa8, + 0x48, 0x99, 0x20, 0x9d, 0x00, 0x94, 0x34, 0xa8, 0x48, 0x99, 0x03, 0x9c, 0x00, 0x94, + 0x35, 0xa2, 0x2d, 0x74, 0x88, 0x9c, 0x00, 0x94, 0x2d, 0x90, 0x00, 0xa2, 0x2d, 0x74, + 0x8b, 0xb7, 0x15, 0xa4, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, + 0x74, 0xcc, 0x82, 0x38, 0xcc, 0xf8, 0xa8, 0x46, 0xb5, 0xe8, 0xf4, 0xac, 0x74, 0xce, + 0xb4, 0xf9, 0x1e, 0xac, 0x74, 0xce, 0xb5, 0xfb, 0xeb, 0xb4, 0xfc, 0x44, 0xa8, 0x48, + 0x99, 0x08, 0x9c, 0x00, 0x94, 0x32, 0xa2, 0x2d, 0x74, 0x88, 0x9d, 0x00, 0x94, 0x2a, + 0xb7, 0x15, 0xa4, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0x74, + 0xcc, 0x82, 0x36, 0xcc, 0xf8, 0xa8, 0x46, 0xb5, 0xe8, 0xbd, 0x90, 0x01, 0xa2, 0x2d, + 0x74, 0x8b, 0x90, 0x00, 0xa2, 0x31, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xf8, 0xdb, + 0x90, 0x00, 0xac, 0x74, 0xce, 0xb4, 0xf0, 0x38, 0xa2, 0x2a, 0x74, 0x88, 0x9c, 0x00, + 0x3c, 0xa2, 0x2d, 0x74, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb4, 0xfc, 0x2c, + 0xa8, 0x44, 0xbc, 0x04, 0x0b, 0x50, 0xbc, 0x04, 0x04, 0x94, 0x2f, 0xbc, 0x04, 0x03, + 0x94, 0x5e, 0xbc, 0x04, 0xff, 0x94, 0x7d, 0x3c, 0xa8, 0x48, 0xa2, 0x2c, 0x74, 0xdc, + 0x50, 0xa2, 0x2c, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, + 0xb5, 0x04, 0x43, 0xa2, 0x2c, 0x74, 0x88, 0x9d, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb4, + 0xfa, 0x95, 0xa8, 0x48, 0x99, 0x06, 0x9c, 0x00, 0x53, 0xa2, 0x2d, 0x74, 0x88, 0x9c, + 0x00, 0x4c, 0x90, 0x00, 0xa2, 0x2d, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xf8, 0xad, + 0xa8, 0x48, 0x99, 0x08, 0x9c, 0x00, 0x3c, 0xa2, 0x2d, 0x74, 0x88, 0x9d, 0x00, 0x3c, + 0x90, 0x01, 0xa2, 0x2d, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xf8, 0x93, 0xa2, 0x2e, + 0x74, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xac, 0x74, 0xce, 0xb5, 0xf7, 0x6d, 0x90, + 0x01, 0xa2, 0x33, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, + 0xb5, 0x03, 0xe1, 0xb4, 0xfb, 0x79, 0xa2, 0x2d, 0x74, 0x88, 0x9d, 0x00, 0x49, 0xac, + 0x74, 0xce, 0xb5, 0xfb, 0x27, 0xb4, 0xf8, 0x5f, 0xa2, 0x2a, 0x74, 0x88, 0x9c, 0x00, + 0x3c, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0x7d, 0xa8, 0x44, 0xbc, 0x04, 0x06, 0x50, 0xbc, + 0x04, 0x03, 0x94, 0x32, 0xbc, 0x04, 0x04, 0x94, 0x54, 0xbc, 0x04, 0xff, 0x94, 0x83, + 0x3c, 0xa8, 0x48, 0x9c, 0x01, 0x41, 0x3c, 0xac, 0x74, 0xce, 0xa2, 0x2c, 0x74, 0x88, + 0x9d, 0x00, 0x30, 0x04, 0xb5, 0xfa, 0x38, 0x3c, 0x90, 0x00, 0xa2, 0x2c, 0x74, 0x8b, + 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, 0xb4, 0x03, 0x84, 0xa2, 0x2e, + 0x74, 0x88, 0x9d, 0x00, 0x3c, 0x90, 0x00, 0xa2, 0x2b, 0x74, 0x8b, 0xa2, 0x2d, 0x74, + 0x8b, 0xa2, 0x33, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, + 0xb5, 0x03, 0x63, 0xac, 0x74, 0xce, 0xb4, 0xfa, 0xdb, 0xa8, 0x48, 0x99, 0x10, 0x9c, + 0x00, 0x3c, 0xa2, 0x54, 0x74, 0xa8, 0xb5, 0xbe, 0x11, 0xa2, 0x00, 0x74, 0xa8, 0xa2, + 0x00, 0x74, 0xfa, 0x9c, 0x00, 0x4c, 0x90, 0x01, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, + 0xce, 0xb4, 0xf7, 0x40, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb5, + 0xfb, 0x6b, 0xb4, 0xfa, 0xa7, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xa8, 0x46, 0xb5, + 0xf2, 0x50, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb5, 0xfb, 0x54, 0xb4, 0xfa, 0x90, + 0xa8, 0x44, 0xbc, 0x04, 0x04, 0x4b, 0xbc, 0x04, 0x0c, 0x94, 0x32, 0xbc, 0x04, 0xff, + 0x94, 0x2d, 0x3c, 0xa8, 0x48, 0x99, 0x06, 0x9c, 0x00, 0x3c, 0xa2, 0x2c, 0x74, 0x88, + 0x9d, 0x00, 0x4f, 0xb5, 0xef, 0xe7, 0x90, 0x00, 0xa2, 0x2d, 0x74, 0x8b, 0xac, 0x74, + 0xce, 0xb4, 0xf9, 0xe9, 0xb5, 0xef, 0xd8, 0x90, 0x00, 0xa2, 0x2d, 0x74, 0x8b, 0xac, + 0x74, 0xce, 0xb4, 0xfa, 0x53, 0xb5, 0xef, 0xc9, 0xa2, 0x14, 0x72, 0x88, 0x9c, 0x00, + 0x3c, 0xa2, 0x34, 0x74, 0xa8, 0x9d, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb4, 0xfa, 0xb9, + 0x3c, 0xa8, 0x44, 0xbc, 0x04, 0xff, 0x41, 0x3c, 0x90, 0x01, 0xac, 0x74, 0xce, 0xb5, + 0xf0, 0x50, 0xb5, 0xef, 0xa2, 0xa8, 0x46, 0xb5, 0xee, 0xd2, 0xb4, 0xfa, 0x21, 0xa8, + 0x44, 0xbc, 0x04, 0xff, 0x41, 0x3c, 0xb5, 0xef, 0x90, 0xb7, 0x00, 0x00, 0x02, 0xac, + 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xee, + 0xd0, 0xb0, 0xd2, 0x4d, 0x91, 0x08, 0xb5, 0xef, 0x2d, 0x90, 0x2b, 0xa2, 0x3a, 0x74, + 0xab, 0x3c, 0xa8, 0x44, 0xbc, 0x04, 0xff, 0x41, 0x3c, 0xb5, 0xef, 0x55, 0xac, 0x74, + 0xce, 0xb4, 0xf9, 0xd6, 0xa2, 0x28, 0xce, 0x88, 0xab, 0xca, 0x90, 0x01, 0x82, 0x00, + 0xca, 0xfc, 0x44, 0xe7, 0xaa, 0xca, 0x63, 0xab, 0x02, 0xa2, 0x06, 0xce, 0xa8, 0xe7, + 0xe7, 0xab, 0xca, 0xa8, 0x02, 0x82, 0x00, 0xca, 0xfc, 0x44, 0xe7, 0xaa, 0xca, 0x63, + 0xab, 0x02, 0xa2, 0x08, 0x72, 0xa8, 0x96, 0x02, 0xf9, 0x9c, 0x00, 0x42, 0x00, 0x3c, + 0x90, 0x01, 0x3c, 0xab, 0xca, 0x9c, 0x03, 0xb4, 0x01, 0x80, 0x05, 0xab, 0x02, 0xb7, + 0x00, 0x04, 0x04, 0x92, 0x00, 0xb7, 0x00, 0x00, 0x06, 0x82, 0x00, 0x06, 0xfd, 0xb4, + 0x01, 0x69, 0x82, 0x04, 0x04, 0xfc, 0xb4, 0x01, 0x46, 0xaf, 0xcc, 0xa8, 0x02, 0xe7, + 0xe7, 0xa0, 0xc8, 0xcc, 0xf8, 0x82, 0x58, 0xcc, 0xf8, 0xa2, 0x01, 0xcc, 0x88, 0xab, + 0x04, 0xc4, 0xab, 0x08, 0x3f, 0xcc, 0x82, 0x04, 0x04, 0xfc, 0x94, 0x41, 0xa8, 0x08, + 0xb5, 0xbc, 0x75, 0xac, 0x74, 0xcc, 0x82, 0x01, 0xca, 0xfc, 0x4c, 0x82, 0x02, 0xca, + 0xfc, 0x54, 0x82, 0x03, 0xca, 0xfc, 0x57, 0x95, 0x44, 0xa2, 0x4a, 0xcc, 0x88, 0x9c, + 0x00, 0x72, 0xb7, 0x00, 0x02, 0x06, 0x95, 0x51, 0xa2, 0x4b, 0xcc, 0x88, 0x9c, 0x00, + 0x7a, 0x6d, 0xa2, 0x4c, 0xcc, 0x88, 0x9c, 0x00, 0x95, 0x61, 0xa2, 0x06, 0xcc, 0xa8, + 0x05, 0x96, 0x02, 0xfc, 0x7e, 0x95, 0x6c, 0xa8, 0x08, 0xb5, 0xbc, 0x48, 0xac, 0x76, + 0xce, 0x82, 0x01, 0xca, 0xfc, 0x4e, 0x82, 0x02, 0xca, 0xfc, 0x94, 0x5d, 0x82, 0x03, + 0xca, 0xfc, 0x94, 0x76, 0x95, 0x87, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x4d, 0x9c, + 0x01, 0x58, 0x9c, 0x02, 0x94, 0x2b, 0x9c, 0x03, 0x94, 0x39, 0x95, 0x9b, 0xa2, 0x56, + 0xce, 0x88, 0x9c, 0x00, 0x95, 0xa3, 0xb7, 0x00, 0x04, 0x06, 0x95, 0xa9, 0xa2, 0x57, + 0xce, 0x88, 0x9d, 0x00, 0x6c, 0xa2, 0x58, 0xce, 0x88, 0x9d, 0x00, 0x73, 0xa2, 0x56, + 0xce, 0x88, 0x9d, 0x00, 0x7a, 0x95, 0xc0, 0xa2, 0x57, 0xce, 0x88, 0x9d, 0x00, 0x95, + 0x23, 0xa2, 0x58, 0xce, 0x88, 0x9d, 0x00, 0x95, 0x2b, 0x95, 0xd2, 0xa2, 0x59, 0xce, + 0x88, 0x9c, 0x00, 0x95, 0xda, 0x95, 0x37, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x95, + 0x39, 0x9c, 0x01, 0x95, 0x2f, 0x9c, 0x02, 0x95, 0x22, 0x9c, 0x03, 0x42, 0x95, 0xf1, + 0xa2, 0x5a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0xf9, 0x95, 0x56, 0xa2, 0x0a, 0xce, 0xa8, + 0x05, 0x96, 0x02, 0xfc, 0x43, 0xb4, 0xfe, 0xf7, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, + 0x94, 0x26, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfe, 0xe6, 0xa2, 0x56, 0xce, + 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0xdd, 0xa2, 0x57, 0xce, 0x88, 0x9d, 0x00, 0xb4, 0xfe, + 0xd4, 0xa2, 0x58, 0xce, 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0xcb, 0x95, 0x90, 0xa2, 0x5e, + 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfe, 0xc0, 0xa2, 0x59, 0xce, 0x88, 0x9d, 0x00, 0xb4, + 0xfe, 0xb7, 0xa2, 0x5a, 0xce, 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0xae, 0x95, 0xad, 0xaf, + 0xce, 0xa8, 0x02, 0xe7, 0xe7, 0xa0, 0xc8, 0xce, 0xf8, 0x82, 0x1a, 0xce, 0xf8, 0xa2, + 0x01, 0xce, 0x88, 0xab, 0x04, 0xd4, 0xab, 0x08, 0x3f, 0xce, 0xb4, 0xfe, 0xb7, 0xa8, + 0x06, 0x3c, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xab, 0x02, 0xb4, 0xfe, 0x79, 0xb7, 0x00, + 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x94, 0x24, + 0x9c, 0x01, 0x94, 0x47, 0x9c, 0x02, 0x94, 0x43, 0x9c, 0x03, 0x94, 0x59, 0x82, 0x00, + 0x04, 0xfc, 0x50, 0xaf, 0xce, 0xa8, 0x04, 0x35, 0xb6, 0x3f, 0xce, 0x9c, 0x02, 0x42, + 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xa8, 0x02, 0x3c, 0xa2, 0x5b, 0xce, 0x88, 0xa2, 0x5f, + 0xce, 0xda, 0xa2, 0x5d, 0xce, 0xda, 0xa2, 0x61, 0xce, 0xda, 0x9c, 0x00, 0x46, 0xb7, + 0x00, 0x02, 0x04, 0x95, 0x2f, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x37, 0xb7, + 0x00, 0x03, 0x04, 0x95, 0x3d, 0xa2, 0x5b, 0xce, 0x88, 0xa2, 0x5f, 0xce, 0xda, 0xa2, + 0x5c, 0xce, 0xda, 0xa2, 0x60, 0xce, 0xda, 0x9c, 0x00, 0x95, 0x20, 0xb7, 0x00, 0x01, + 0x04, 0x95, 0x57, 0xa2, 0x59, 0xce, 0x88, 0x9c, 0x00, 0x46, 0xb7, 0x00, 0x01, 0x04, + 0x95, 0x64, 0xa2, 0x5a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x3b, 0xb7, 0x00, 0x02, 0x04, + 0x95, 0x72, 0xab, 0x1a, 0xbc, 0x10, 0x29, 0x94, 0x80, 0xbc, 0x10, 0x2a, 0x94, 0x86, + 0xbc, 0x10, 0x2b, 0x94, 0x86, 0xbc, 0x10, 0x2e, 0x94, 0xad, 0xbc, 0x20, 0x17, 0x94, + 0xae, 0xbc, 0x20, 0x6f, 0x94, 0xb4, 0xbc, 0x20, 0x70, 0x94, 0xba, 0xbc, 0x20, 0x74, + 0x94, 0xc5, 0xbc, 0x20, 0x29, 0x94, 0xca, 0xbc, 0x2f, 0x07, 0x94, 0xe3, 0xbc, 0x2f, + 0x05, 0x94, 0xe9, 0xbc, 0x32, 0x0e, 0x94, 0xef, 0xbc, 0x40, 0x0d, 0xb4, 0x01, 0x00, + 0xbc, 0x40, 0x0f, 0xb4, 0x01, 0x11, 0xbc, 0x40, 0x10, 0xb4, 0x01, 0x4f, 0xbc, 0x40, + 0x21, 0xb4, 0x01, 0x61, 0xbc, 0x40, 0x2a, 0xb4, 0x01, 0x72, 0xbc, 0x40, 0x33, 0xb4, + 0x01, 0x8d, 0xbc, 0x40, 0x40, 0xb4, 0x01, 0x9f, 0xbc, 0x40, 0x34, 0xb4, 0x01, 0xb1, + 0xbc, 0x40, 0x35, 0xb4, 0x01, 0xcc, 0xbc, 0x40, 0x3d, 0xb4, 0x01, 0xe7, 0xbc, 0x40, + 0x3e, 0xb4, 0x01, 0xf9, 0xbc, 0x40, 0x3f, 0xb4, 0x02, 0x0b, 0x3c, 0xa2, 0x20, 0x72, + 0xa8, 0xab, 0x1c, 0x90, 0x02, 0xb4, 0x02, 0x17, 0xa2, 0x22, 0x72, 0xa8, 0x6b, 0xa2, + 0x14, 0x72, 0x88, 0x9c, 0x00, 0x43, 0x90, 0x00, 0x75, 0xb7, 0x00, 0x00, 0x1c, 0xa2, + 0x1a, 0x72, 0xa8, 0x9c, 0x00, 0x46, 0x90, 0x01, 0xa0, 0xc8, 0x1c, 0xfa, 0xa2, 0x1c, + 0x72, 0xa8, 0x9c, 0x00, 0x46, 0x90, 0x02, 0xa0, 0xc8, 0x1c, 0xfa, 0xa8, 0x1c, 0x95, + 0x36, 0xa2, 0x27, 0x72, 0x88, 0x94, 0x1f, 0xa8, 0x18, 0xb5, 0xb9, 0xcc, 0xa2, 0x52, + 0x74, 0xa8, 0x95, 0x47, 0xa8, 0x18, 0xb5, 0xb9, 0xc1, 0xa2, 0x3a, 0x74, 0xa8, 0x95, + 0x52, 0xa8, 0x18, 0xb5, 0xb9, 0xb6, 0xa2, 0x2c, 0x74, 0x88, 0xab, 0x1c, 0x90, 0x01, + 0xb4, 0x01, 0xba, 0xa8, 0x18, 0xb5, 0xb9, 0xa6, 0xa2, 0x27, 0x74, 0x88, 0x70, 0xa8, + 0x18, 0xb5, 0xb9, 0x9c, 0xaf, 0xcc, 0xaf, 0xca, 0xac, 0x74, 0xca, 0x82, 0x12, 0xca, + 0xf8, 0x92, 0x1c, 0xb5, 0xe2, 0x82, 0x3f, 0xca, 0x3f, 0xcc, 0x90, 0x06, 0xb4, 0x01, + 0x92, 0xa8, 0x18, 0xb5, 0xb9, 0x7e, 0xa2, 0x24, 0x74, 0xa8, 0x95, 0x95, 0xa8, 0x18, + 0xb5, 0xb9, 0x73, 0xa2, 0x33, 0x74, 0x88, 0x95, 0x43, 0x8c, 0x7c, 0x3c, 0xac, 0x78, + 0x3e, 0xa8, 0x18, 0xb5, 0xb9, 0x8a, 0xa2, 0x12, 0x78, 0xa8, 0x8c, 0x3c, 0x7c, 0xac, + 0x3e, 0x78, 0x95, 0xb7, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb9, + 0x5f, 0xa2, 0x28, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0x95, 0xce, 0x8c, + 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb9, 0x48, 0xaf, 0xcc, 0xaf, 0xce, + 0xac, 0x76, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, 0x09, 0xb5, 0x21, 0xe6, 0x94, 0x20, + 0x00, 0xab, 0x1c, 0xac, 0x76, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x09, 0xb5, 0x21, + 0xd5, 0x54, 0x00, 0x96, 0x1c, 0xfa, 0x3f, 0xce, 0x3f, 0xcc, 0x8c, 0x3c, 0x7b, 0xac, + 0x3e, 0x76, 0x95, 0xae, 0x90, 0x02, 0x95, 0x21, 0x90, 0x01, 0x75, 0x8c, 0x7b, 0x3c, + 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb9, 0x04, 0xa2, 0x62, 0x76, 0xa8, 0x8c, 0x3c, + 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfe, 0xd4, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, + 0x18, 0xb5, 0xb8, 0xec, 0xa2, 0x3f, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, + 0x95, 0xe4, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0xd5, 0xa2, + 0x30, 0x76, 0xa8, 0xab, 0x1c, 0xa2, 0x32, 0x76, 0xa8, 0xab, 0x1e, 0x8c, 0x3c, 0x7b, + 0xac, 0x3e, 0x76, 0x90, 0x04, 0x94, 0xba, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, + 0x18, 0xb5, 0xb8, 0xb4, 0xa2, 0x74, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, + 0xb4, 0xfe, 0xe1, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x9c, + 0xa2, 0x12, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfe, 0xc9, 0x8c, + 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x84, 0xa2, 0x68, 0x76, 0xa8, + 0xab, 0x1c, 0xa2, 0x6a, 0x76, 0xa8, 0xab, 0x1e, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, + 0x90, 0x04, 0x94, 0x69, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, + 0x63, 0xa2, 0x6c, 0x76, 0xa8, 0xab, 0x1c, 0xa2, 0x6e, 0x76, 0xa8, 0xab, 0x1e, 0x8c, + 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0x90, 0x04, 0x94, 0x48, 0x8c, 0x7b, 0x3c, 0xac, 0x76, + 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x42, 0xa2, 0x2c, 0x76, 0xa8, 0x8c, 0x3c, 0x7b, 0xac, + 0x3e, 0x76, 0xb4, 0xfe, 0x12, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, + 0xb8, 0x2a, 0xa2, 0x4e, 0x76, 0xa8, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfd, + 0xfa, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x12, 0xa2, 0x2a, + 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfd, 0xe2, 0x9a, 0x20, 0xb4, + 0x11, 0x76, 0xa2, 0x06, 0xcc, 0xa8, 0xbc, 0x10, 0x1a, 0x94, 0x8b, 0xbc, 0x10, 0x1b, + 0x94, 0xa9, 0xbc, 0x10, 0x1f, 0x94, 0xed, 0xbc, 0x1f, 0x07, 0xb4, 0x00, 0xff, 0xbc, + 0x1f, 0x08, 0xb4, 0x01, 0x02, 0xbc, 0x20, 0x20, 0xb4, 0x01, 0x05, 0xbc, 0x20, 0x76, + 0xb4, 0x01, 0x47, 0xbc, 0x20, 0x18, 0xb4, 0x01, 0x56, 0xbc, 0x20, 0x1d, 0xb4, 0x01, + 0x6d, 0xbc, 0x2f, 0x01, 0xb4, 0x01, 0x7c, 0xbc, 0x2f, 0x03, 0xb4, 0x01, 0x86, 0xbc, + 0x32, 0x15, 0xb4, 0x01, 0xba, 0xbc, 0x32, 0x16, 0xb4, 0x01, 0xb4, 0xbc, 0x32, 0x17, + 0xb4, 0x01, 0xae, 0xbc, 0x32, 0x13, 0xb4, 0x02, 0x21, 0xbc, 0x40, 0x0e, 0xb4, 0x02, + 0x3a, 0xbc, 0x40, 0x11, 0xb4, 0x02, 0x44, 0xbc, 0x40, 0x3a, 0xb4, 0x02, 0x69, 0xbc, + 0x40, 0x3b, 0xb4, 0x02, 0x73, 0xbc, 0x40, 0x15, 0xb4, 0x02, 0x7d, 0xbc, 0x40, 0x1f, + 0xb4, 0x02, 0x96, 0xbc, 0x4f, 0x02, 0xb4, 0x02, 0xca, 0xbc, 0x60, 0x00, 0x41, 0x3c, + 0xb5, 0xed, 0x17, 0x90, 0x01, 0xa2, 0x0e, 0x72, 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, + 0x99, 0x01, 0xa2, 0x15, 0x72, 0x8b, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, + 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb5, 0xb8, 0xea, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x06, + 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x08, 0x72, 0xab, 0xb7, 0x00, 0x00, + 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, 0xa8, 0x0a, 0xb5, 0xb7, 0x33, 0xa2, 0x4e, 0x76, + 0xa8, 0x9c, 0x00, 0x4d, 0x9c, 0x01, 0x4a, 0x9c, 0x02, 0x47, 0x9c, 0x03, 0x44, 0x9c, + 0x09, 0x41, 0x44, 0xa9, 0x0a, 0x95, 0x20, 0xac, 0x76, 0xce, 0xb5, 0xfa, 0x0f, 0x9d, + 0x00, 0x6c, 0xb7, 0x02, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa8, 0x0a, 0xb5, 0xb8, 0x99, 0x7e, 0xa2, 0x10, 0xcc, 0xa8, 0xab, 0xca, 0xa2, 0x0e, + 0xcc, 0xa8, 0xb5, 0x10, 0x45, 0xa2, 0x02, 0x72, 0xab, 0xa8, 0xca, 0xa2, 0x04, 0x72, + 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x34, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, + 0x88, 0xa2, 0x30, 0x72, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb6, 0xbb, 0xa2, + 0x0e, 0xcc, 0x88, 0xa2, 0x08, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb5, 0xd9, 0xcd, 0xa2, + 0x12, 0x72, 0x88, 0x9c, 0x02, 0x4a, 0xb5, 0xb6, 0xb7, 0xac, 0x76, 0xce, 0xb5, 0xd2, + 0xe6, 0x3c, 0xa2, 0x10, 0x72, 0x88, 0x9c, 0x02, 0x4a, 0xb5, 0xb6, 0xa6, 0xac, 0x76, + 0xce, 0xb5, 0xd2, 0xd5, 0x3c, 0xa2, 0x11, 0x72, 0x88, 0x9c, 0x02, 0x3c, 0xb5, 0xb6, + 0x95, 0xac, 0x76, 0xce, 0xb5, 0xd2, 0xc4, 0x3c, 0xb7, 0x04, 0x0d, 0x02, 0xa2, 0x0e, + 0xcc, 0x88, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xb8, + 0x11, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb6, 0x5e, 0xac, 0xcc, 0xca, 0xaf, 0xcc, 0xac, + 0x74, 0xcc, 0x82, 0x18, 0xcc, 0xf8, 0x82, 0x0e, 0xca, 0xf8, 0xb5, 0xdf, 0x41, 0x3f, + 0xcc, 0x3c, 0xb7, 0x04, 0x06, 0x02, 0xa2, 0x0e, 0xcc, 0xa8, 0xab, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xb7, 0xdf, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, + 0xb6, 0x2c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x20, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, + 0xa8, 0xb5, 0xb6, 0x1c, 0xa2, 0x06, 0x74, 0xa8, 0xa2, 0x0e, 0xcc, 0xfc, 0x3c, 0xa2, + 0x06, 0x74, 0xab, 0xa2, 0x52, 0x74, 0xa8, 0x9c, 0x03, 0x44, 0x9d, 0x03, 0x41, 0x3c, + 0xa2, 0x1e, 0x74, 0xa8, 0xaf, 0xc8, 0x90, 0x00, 0xa2, 0x1e, 0x74, 0xab, 0xac, 0x74, + 0xce, 0xb5, 0xd9, 0x12, 0x3f, 0xc8, 0xa2, 0x1e, 0x74, 0xab, 0xb4, 0xd9, 0x09, 0xa2, + 0x0a, 0xcc, 0xa8, 0xb5, 0xb6, 0x0a, 0xb7, 0x00, 0x00, 0x0c, 0x82, 0x01, 0x0c, 0xfc, + 0x3c, 0xa8, 0x0c, 0xb5, 0xb5, 0xd4, 0xa2, 0x54, 0x74, 0xa8, 0xa2, 0x0a, 0xcc, 0xfc, + 0x43, 0xa9, 0x0c, 0x75, 0xa2, 0x0c, 0x78, 0xa8, 0xa2, 0x42, 0x74, 0xab, 0xa2, 0x0e, + 0x78, 0xa8, 0xa2, 0x44, 0x74, 0xab, 0xa2, 0x08, 0x78, 0xa8, 0xa2, 0x3e, 0x74, 0xab, + 0xa2, 0x0a, 0x78, 0xa8, 0xa2, 0x40, 0x74, 0xab, 0xa2, 0x04, 0x78, 0xa8, 0xa2, 0x46, + 0x74, 0xab, 0xa2, 0x04, 0x78, 0xa8, 0xa2, 0x46, 0x74, 0xab, 0x90, 0x01, 0xab, 0x02, + 0xa2, 0x54, 0x74, 0xa8, 0xab, 0x04, 0xac, 0x74, 0x06, 0x82, 0x42, 0x06, 0xf8, 0xac, + 0x74, 0x08, 0x82, 0x3e, 0x08, 0xf8, 0xac, 0x74, 0x0a, 0x82, 0x46, 0x0a, 0xf8, 0xa2, + 0x22, 0x74, 0x88, 0xb5, 0xe8, 0x7b, 0x95, 0x59, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, + 0x91, 0xa2, 0x10, 0xcc, 0xa8, 0xab, 0xca, 0xa2, 0x0e, 0xcc, 0xa8, 0xb5, 0x0e, 0xc2, + 0xa2, 0x00, 0x78, 0xab, 0xa8, 0xca, 0xa2, 0x02, 0x78, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, + 0xa8, 0xb5, 0xb5, 0x5e, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0c, 0x76, 0xab, 0x3c, 0xa2, + 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x4e, 0xac, 0xcc, 0xce, 0x82, 0x0e, 0xce, 0xf8, 0xa9, + 0xce, 0xd4, 0xa2, 0x13, 0x76, 0x8b, 0xa2, 0x01, 0xce, 0x88, 0xa2, 0x14, 0x76, 0x8b, + 0xa2, 0x02, 0xce, 0x88, 0xa2, 0x15, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xd1, 0x5f, + 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x23, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x10, 0x76, + 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x13, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, + 0x11, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x03, 0xa2, 0x10, 0xcc, + 0xa8, 0xab, 0xca, 0xa2, 0x0e, 0xcc, 0xa8, 0xb5, 0x0e, 0x48, 0xa2, 0x00, 0x76, 0xab, + 0xa8, 0xca, 0xa2, 0x02, 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb4, 0xe4, + 0xa2, 0x0e, 0xcc, 0x88, 0x91, 0x00, 0x9c, 0x00, 0x91, 0x02, 0x9c, 0x01, 0x91, 0x01, + 0x9c, 0x02, 0x91, 0x08, 0x9c, 0x03, 0x91, 0x04, 0x9c, 0x04, 0xb1, 0x01, 0x00, 0xa8, + 0xca, 0xa2, 0x04, 0x76, 0xab, 0xb7, 0x02, 0x02, 0x02, 0xac, 0xca, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xb6, 0x49, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, + 0xb4, 0xaa, 0xa2, 0x0a, 0x76, 0xa8, 0xa2, 0x0e, 0xcc, 0xfc, 0x3c, 0xa2, 0x0e, 0xcc, + 0xa8, 0xa2, 0x0a, 0x76, 0xab, 0xa2, 0x62, 0x76, 0xa8, 0x9d, 0x03, 0x44, 0x9c, 0x03, + 0x41, 0x3c, 0xa2, 0x17, 0x76, 0xa8, 0xaf, 0xc8, 0x90, 0x00, 0xa2, 0x17, 0x76, 0xab, + 0xac, 0x76, 0xce, 0xb5, 0xd0, 0xb1, 0x3f, 0xc8, 0xa2, 0x17, 0x76, 0xab, 0xb4, 0xd0, + 0xa8, 0xa2, 0x0c, 0xcc, 0xa8, 0xb6, 0xb8, 0x00, 0xab, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, + 0xb4, 0x50, 0xa2, 0x04, 0xcc, 0xa8, 0xbc, 0x13, 0x13, 0x53, 0xbc, 0x13, 0x14, 0xb4, + 0x01, 0x5c, 0xbc, 0x13, 0x15, 0xb4, 0x01, 0xc3, 0xbc, 0x13, 0x16, 0xb4, 0x02, 0xf5, + 0x3c, 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x04, 0x74, 0xa8, 0x9d, 0x00, + 0x3c, 0xd4, 0xa2, 0x08, 0x74, 0x8b, 0xa2, 0x02, 0xce, 0x88, 0xab, 0xca, 0xa2, 0x01, + 0xce, 0x88, 0x8c, 0xca, 0xc9, 0xa2, 0x04, 0x74, 0xab, 0xa2, 0x03, 0xce, 0x88, 0xa2, + 0x02, 0x74, 0x8b, 0xa2, 0x04, 0xce, 0xa8, 0xa2, 0x20, 0x74, 0xab, 0xa2, 0x06, 0xce, + 0xa8, 0xa2, 0x06, 0x74, 0xab, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xaf, 0xce, 0xac, + 0x74, 0xcc, 0x82, 0x58, 0xcc, 0xf8, 0x82, 0x08, 0xce, 0xf8, 0x80, 0x7e, 0x02, 0xfc, + 0x94, 0xf1, 0xd4, 0xc6, 0xa2, 0x01, 0xce, 0x88, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x02, + 0xce, 0x88, 0xa2, 0x02, 0xcc, 0x8b, 0xa2, 0x03, 0xce, 0x88, 0xa2, 0x03, 0xcc, 0x8b, + 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x22, 0x74, 0xdc, 0x94, 0x74, 0xa2, 0x01, 0xcc, 0x88, + 0x9c, 0x02, 0x94, 0xa0, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xc4, 0xb5, 0xb3, 0xbe, + 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, + 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x22, 0x74, + 0x88, 0xa2, 0x02, 0xca, 0x8b, 0x90, 0x02, 0xa2, 0x03, 0xca, 0x8b, 0xa2, 0x03, 0xcc, + 0x88, 0x9c, 0x02, 0x94, 0x3f, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, + 0x88, 0xb5, 0xb3, 0x82, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, + 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, + 0x76, 0xa2, 0x22, 0x74, 0x88, 0xad, 0xca, 0x8b, 0x90, 0x02, 0xa2, 0x01, 0xca, 0x8b, + 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, 0x04, 0xce, 0xf8, 0x95, 0xa8, 0xaf, 0x74, + 0x88, 0x7a, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xb3, 0x2f, 0xac, 0x74, 0xca, + 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, + 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x3f, 0xaf, 0x74, 0x88, 0x7a, + 0xaf, 0xc8, 0xc4, 0xb5, 0xb3, 0x0a, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, + 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, + 0x7a, 0x3f, 0x74, 0x95, 0xa0, 0x3f, 0xce, 0x3f, 0xcc, 0xa2, 0x0c, 0x72, 0x89, 0x3c, + 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x04, 0x74, 0xa8, 0x9c, 0x00, 0x3c, + 0x90, 0x01, 0xa2, 0x00, 0x74, 0x8b, 0xf4, 0xa2, 0x0a, 0x74, 0xab, 0xa2, 0x02, 0xce, + 0xa8, 0xa2, 0x0c, 0x74, 0xab, 0xa2, 0x04, 0xce, 0xa8, 0xa2, 0x0e, 0x74, 0xab, 0xa2, + 0x06, 0xce, 0xa8, 0xa2, 0x10, 0x74, 0xab, 0xa2, 0x08, 0xce, 0x88, 0xa2, 0x1e, 0x74, + 0x8b, 0xac, 0xce, 0xca, 0x82, 0x09, 0xca, 0xf8, 0xaf, 0xcc, 0xac, 0x74, 0xcc, 0x82, + 0x12, 0xcc, 0xf8, 0xb5, 0xdb, 0x90, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x3c, + 0xb7, 0x04, 0x0e, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0x74, 0x88, 0xb5, 0xb4, 0x2b, 0xac, 0x74, 0xce, 0xb4, 0xd5, 0x99, 0x90, 0x01, 0xa2, + 0x00, 0x74, 0xab, 0xa2, 0x52, 0x74, 0xa8, 0x9c, 0x03, 0xb4, 0x00, 0xff, 0x9c, 0x02, + 0xb4, 0x01, 0x0f, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xac, 0xcc, 0xce, 0x82, 0x16, + 0xcc, 0xf8, 0xac, 0x74, 0xcc, 0x82, 0x58, 0xcc, 0xf8, 0x82, 0x08, 0xce, 0xf8, 0x80, + 0x7e, 0x02, 0xfc, 0x94, 0xd4, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x22, 0x74, 0xdc, 0x94, + 0x71, 0x9c, 0x02, 0x94, 0xa1, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xc4, 0xb5, 0xb2, + 0x43, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, + 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x02, + 0xcc, 0x88, 0xa2, 0x02, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xa2, 0x03, 0xca, 0x8b, + 0xa2, 0x03, 0xcc, 0x88, 0x9c, 0x02, 0x94, 0x3e, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, + 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xb2, 0x05, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, + 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, + 0x8b, 0x7b, 0x3f, 0x76, 0xc4, 0xad, 0xca, 0x8b, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x01, + 0xca, 0x8b, 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, 0x04, 0xce, 0xf8, 0x95, 0x8b, + 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xb1, 0xb3, 0xac, + 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, + 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x3e, 0xaf, 0x74, + 0x88, 0x7a, 0xaf, 0xc8, 0xc4, 0xb5, 0xb1, 0x8e, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, + 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, + 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0xa1, 0x3f, 0xcc, 0xac, 0x74, 0xce, 0xb4, 0xd7, + 0x33, 0xa2, 0x2c, 0x72, 0xa8, 0x05, 0xa2, 0x2c, 0x72, 0xab, 0x04, 0x9d, 0x00, 0xb4, + 0xfe, 0xf7, 0xb5, 0xd5, 0x76, 0xb4, 0xfe, 0xf1, 0xa2, 0x2e, 0x72, 0xa8, 0x05, 0xa2, + 0x2e, 0x72, 0xab, 0x04, 0x9d, 0x00, 0xb4, 0xfe, 0xe2, 0xb5, 0xd5, 0x61, 0xb4, 0xfe, + 0xdc, 0xac, 0x74, 0xce, 0xb5, 0xd6, 0x9f, 0xa2, 0x0c, 0x72, 0x88, 0x05, 0xa2, 0x0c, + 0x72, 0x8b, 0x3c, 0xa2, 0x0c, 0xcc, 0xa8, 0xb6, 0xb8, 0x00, 0xab, 0xa2, 0x0a, 0xcc, + 0xa8, 0xb5, 0xb1, 0x36, 0xa2, 0x04, 0xcc, 0xa8, 0xbc, 0x13, 0x17, 0x53, 0xbc, 0x13, + 0x18, 0xb4, 0x02, 0x2c, 0xbc, 0x13, 0x19, 0xb4, 0x02, 0x48, 0xbc, 0x13, 0x1a, 0xb4, + 0x02, 0x85, 0x3c, 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x08, 0x76, 0xa8, + 0x9d, 0x00, 0x3c, 0xf4, 0xa2, 0x06, 0x76, 0xab, 0x9c, 0x00, 0x4e, 0x9c, 0x01, 0x94, + 0x3c, 0x9c, 0x02, 0x94, 0x6a, 0x9c, 0x03, 0x94, 0x98, 0x94, 0xb6, 0xaf, 0xcc, 0xac, + 0x76, 0xcc, 0xa2, 0x03, 0xce, 0x88, 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, 0xa2, 0x04, + 0xce, 0x88, 0x99, 0x5b, 0xa2, 0x14, 0xcc, 0x8b, 0xa2, 0x05, 0xce, 0x88, 0x99, 0xdb, + 0xa2, 0x15, 0xcc, 0x8b, 0xa2, 0x0a, 0x72, 0x89, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x10, + 0x72, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xac, 0x76, 0xcc, 0xa2, 0x03, 0xce, 0x88, + 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, 0xa2, 0x04, 0xce, 0x88, 0x99, 0x6d, 0xa2, 0x14, + 0xcc, 0x8b, 0xa2, 0x05, 0xce, 0x88, 0x99, 0xed, 0xa2, 0x15, 0xcc, 0x8b, 0xa2, 0x0a, + 0x72, 0x89, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x11, 0x72, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, + 0xcc, 0xac, 0x76, 0xcc, 0xa2, 0x03, 0xce, 0x88, 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, + 0xa2, 0x04, 0xce, 0x88, 0x99, 0x6d, 0xa2, 0x14, 0xcc, 0x8b, 0xa2, 0x05, 0xce, 0x88, + 0x99, 0x6d, 0xa2, 0x15, 0xcc, 0x8b, 0xa2, 0x0a, 0x72, 0x89, 0xa2, 0x22, 0x76, 0x88, + 0xa2, 0x12, 0x72, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xac, 0x76, 0xcc, 0xa2, 0x03, + 0xce, 0x88, 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, 0xa2, 0x04, 0xce, 0x88, 0x99, 0x37, + 0xa2, 0x14, 0xcc, 0x8b, 0xa2, 0x0b, 0x72, 0x89, 0x3f, 0xcc, 0x3c, 0xa2, 0x06, 0xce, + 0xa8, 0xa2, 0x08, 0x76, 0xab, 0xa2, 0x08, 0xce, 0x88, 0xa2, 0x10, 0x76, 0x8b, 0xa2, + 0x09, 0xce, 0x88, 0xa2, 0x11, 0x76, 0x8b, 0xa2, 0x0a, 0xce, 0xa8, 0xa2, 0x0a, 0x76, + 0xab, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xaf, 0xce, 0xac, 0x76, 0xcc, 0x82, 0x1a, + 0xcc, 0xf8, 0x82, 0x0c, 0xce, 0xf8, 0x80, 0x7e, 0x02, 0xfc, 0x94, 0xef, 0xd4, 0xc6, + 0xa2, 0x01, 0xce, 0x88, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x02, 0xce, 0x88, 0xa2, 0x02, + 0xcc, 0x8b, 0xa2, 0x03, 0xce, 0x88, 0xa2, 0x03, 0xcc, 0x8b, 0xa2, 0x01, 0xcc, 0x88, + 0xa2, 0x22, 0x76, 0xdc, 0x94, 0xbf, 0x9c, 0x02, 0x94, 0x96, 0xaf, 0x76, 0x88, 0x7b, + 0xaf, 0xc8, 0xc4, 0xb5, 0xaf, 0xd6, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, + 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, + 0x7b, 0x3f, 0x76, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x02, 0xca, 0x8b, 0x90, 0x04, 0xa2, + 0x03, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0x9c, 0x02, 0x94, 0x35, 0xaf, 0x76, 0x88, + 0x7b, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xaf, 0x9a, 0xac, 0x76, 0xca, 0x82, + 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, + 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x22, 0x76, 0x88, 0xad, 0xca, 0x8b, + 0x90, 0x04, 0xa2, 0x01, 0xca, 0x8b, 0x94, 0x4d, 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, + 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xaf, 0x51, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, + 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, + 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x35, 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, 0xc4, 0xb5, + 0xaf, 0x2c, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, + 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, + 0x96, 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, 0x04, 0xce, 0xf8, 0x95, 0xf3, 0x3f, + 0xce, 0x3f, 0xcc, 0xa2, 0x14, 0xce, 0xa8, 0xa2, 0x00, 0x76, 0xab, 0xa2, 0x16, 0xce, + 0xa8, 0xa2, 0x02, 0x76, 0xab, 0xa2, 0x18, 0xce, 0xa8, 0xa2, 0x04, 0x76, 0xab, 0x3c, + 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x08, 0x76, 0xa8, 0x9c, 0x00, 0x3c, + 0x90, 0x01, 0xa2, 0x0e, 0x76, 0xab, 0xd4, 0xa2, 0x17, 0x76, 0x8b, 0xa2, 0x01, 0xce, + 0x88, 0xa2, 0x18, 0x76, 0x8b, 0x3c, 0x90, 0x00, 0xa2, 0x0e, 0x76, 0xab, 0xa2, 0x06, + 0x76, 0xa8, 0x9c, 0x03, 0x46, 0xac, 0x76, 0xce, 0xb4, 0xd5, 0x89, 0xa2, 0x62, 0x76, + 0xa8, 0x9c, 0x03, 0x44, 0x9c, 0x02, 0x53, 0x70, 0xa2, 0x28, 0x72, 0xa8, 0x05, 0xa2, + 0x28, 0x72, 0xab, 0x04, 0x9d, 0x00, 0x7d, 0xb5, 0xd2, 0xb5, 0x95, 0x21, 0xa2, 0x2a, + 0x72, 0xa8, 0x05, 0xa2, 0x2a, 0x72, 0xab, 0x04, 0x9d, 0x00, 0x95, 0x2f, 0xb5, 0xd2, + 0xa2, 0x95, 0x34, 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x06, 0x76, 0xa8, + 0x9c, 0x00, 0x4d, 0x9c, 0x01, 0x5b, 0x9c, 0x02, 0x94, 0x27, 0x9c, 0x03, 0x94, 0x33, + 0x94, 0x3a, 0x88, 0x7e, 0xa2, 0x10, 0x72, 0x8b, 0xa2, 0x0a, 0x72, 0x88, 0x05, 0xa2, + 0x0a, 0x72, 0x8b, 0x94, 0x29, 0x88, 0x7e, 0xa2, 0x11, 0x72, 0x8b, 0xa2, 0x0a, 0x72, + 0x88, 0x05, 0xa2, 0x0a, 0x72, 0x8b, 0x59, 0x88, 0x7e, 0xa2, 0x12, 0x72, 0x8b, 0xa2, + 0x0a, 0x72, 0x88, 0x05, 0xa2, 0x0a, 0x72, 0x8b, 0x49, 0xa2, 0x0b, 0x72, 0x88, 0x05, + 0xa2, 0x0b, 0x72, 0x8b, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xaf, 0xce, 0xac, 0x76, + 0xcc, 0x82, 0x1a, 0xcc, 0xf8, 0x82, 0x0c, 0xce, 0xf8, 0x80, 0x7e, 0x02, 0xfc, 0x94, + 0xd6, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x22, 0x76, 0xdc, 0x94, 0xc0, 0x9c, 0x02, 0x94, + 0x97, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xc4, 0xb5, 0xae, 0x11, 0xac, 0x76, 0xca, + 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, + 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x02, 0xcc, 0x88, 0xa2, 0x02, + 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xa2, 0x03, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, + 0x9c, 0x02, 0x94, 0x34, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, + 0xb5, 0xad, 0xd3, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, + 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, + 0xc4, 0xad, 0xca, 0x8b, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x01, 0xca, 0x8b, 0x94, 0x4d, + 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xad, 0x8b, 0xac, + 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, + 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x34, 0xaf, 0x74, + 0x88, 0x7a, 0xaf, 0xc8, 0xc4, 0xb5, 0xad, 0x66, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, + 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, + 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x97, 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, + 0x04, 0xce, 0xf8, 0x95, 0xda, 0x3f, 0xce, 0x3f, 0xcc, 0xac, 0x76, 0xce, 0xb4, 0xd3, + 0x99, 0xa2, 0x0c, 0xcc, 0xa8, 0xb6, 0xb8, 0x00, 0xab, 0x91, 0x00, 0xe4, 0x99, 0x3f, + 0x82, 0x02, 0xcc, 0xf8, 0x9c, 0x01, 0xb4, 0x01, 0xe0, 0xa2, 0x04, 0xcc, 0xa8, 0xbc, + 0x13, 0x11, 0x94, 0x35, 0xbc, 0x13, 0x13, 0x94, 0x33, 0xbc, 0x13, 0x14, 0x94, 0x2e, + 0xbc, 0x13, 0x15, 0x94, 0x29, 0xbc, 0x13, 0x16, 0x94, 0x24, 0xbc, 0x13, 0x17, 0x94, + 0x22, 0xbc, 0x13, 0x18, 0x5e, 0xbc, 0x13, 0x19, 0x5a, 0xbc, 0x13, 0x1a, 0x56, 0xbc, + 0x24, 0x11, 0x55, 0xbc, 0x24, 0x12, 0x3c, 0xbc, 0x24, 0x13, 0x94, 0xb6, 0xb4, 0x01, + 0xa1, 0xb4, 0xf4, 0xf2, 0xb4, 0xf8, 0x7c, 0xb4, 0xfb, 0xa7, 0xa2, 0x06, 0xcc, 0xa8, + 0x9c, 0x00, 0x55, 0x9c, 0x01, 0x94, 0x21, 0x9c, 0x02, 0x94, 0x2d, 0x9c, 0x04, 0x94, + 0x39, 0x9c, 0x05, 0x94, 0x57, 0x9c, 0x06, 0x94, 0x65, 0x3c, 0xb7, 0x01, 0x01, 0x02, + 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xae, 0x58, 0xb7, 0x01, + 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xae, 0x48, + 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, + 0xae, 0x38, 0xa2, 0x10, 0x72, 0x88, 0xab, 0xca, 0xb5, 0xac, 0x97, 0xa2, 0x29, 0x76, + 0x88, 0x9c, 0x02, 0x41, 0x3c, 0xb7, 0x02, 0x10, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, + 0x00, 0x00, 0x06, 0xa8, 0xca, 0xb4, 0xae, 0x16, 0xa2, 0x11, 0x72, 0x88, 0xab, 0xca, + 0xb5, 0xac, 0x75, 0xa2, 0x29, 0x76, 0x88, 0x9c, 0x02, 0x95, 0x20, 0x3c, 0xb7, 0x00, + 0x00, 0x02, 0x80, 0x7e, 0x02, 0xfc, 0x3c, 0xa8, 0x02, 0xb5, 0xac, 0x5e, 0xa2, 0x06, + 0x76, 0xa8, 0x9c, 0x03, 0x43, 0xa9, 0x02, 0x73, 0xb7, 0x02, 0x10, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x02, 0xb5, 0xad, 0xdb, 0x74, 0xa2, 0x06, + 0xcc, 0xa8, 0x9c, 0x00, 0x51, 0x9c, 0x01, 0x94, 0x7e, 0x9c, 0x02, 0x94, 0x8d, 0x9c, + 0x03, 0x94, 0x9c, 0x9c, 0x04, 0x94, 0xb3, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0x9c, 0x00, + 0x51, 0x9c, 0x01, 0x5d, 0x9c, 0x02, 0x94, 0x28, 0x9c, 0x03, 0x94, 0x32, 0x9c, 0x04, + 0x94, 0x3c, 0x94, 0x48, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xac, 0x0b, 0x90, 0x02, 0xa2, + 0x04, 0x76, 0xab, 0x94, 0x39, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xfc, 0x90, 0x01, + 0xa2, 0x04, 0x76, 0xab, 0x94, 0x2a, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xed, 0x90, + 0x08, 0xa2, 0x04, 0x76, 0xab, 0x5c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xdf, 0x90, + 0x04, 0xa2, 0x04, 0x76, 0xab, 0x4e, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xd1, 0xb0, + 0x01, 0x00, 0xa2, 0x04, 0x76, 0xab, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, + 0x02, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xad, 0x51, 0xb7, 0x00, 0x00, 0x04, 0xb7, + 0x00, 0x00, 0x06, 0xb7, 0x02, 0x0f, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xad, 0x3e, + 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, 0x10, 0x02, 0xa2, 0x0a, + 0xcc, 0xa8, 0xb4, 0xad, 0x2b, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x3c, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, 0x01, 0x02, 0xa2, 0x0a, 0xcc, + 0xa8, 0xb4, 0xad, 0x10, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x3c, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, 0x04, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, + 0xb4, 0xac, 0xf5, 0x90, 0x00, 0xa2, 0x0c, 0xcc, 0xab, 0xb4, 0xfe, 0x0b, 0x3c, 0xa2, + 0x02, 0xcc, 0xa8, 0xbc, 0x10, 0x15, 0xb4, 0x01, 0x40, 0xbc, 0x10, 0x16, 0xb4, 0x01, + 0x43, 0xbc, 0x10, 0x17, 0xb4, 0x01, 0x46, 0xbc, 0x10, 0x18, 0xb4, 0x01, 0x49, 0xbc, + 0x10, 0x1a, 0xb4, 0x01, 0x4c, 0xbc, 0x10, 0x1b, 0xb4, 0x01, 0x4f, 0xbc, 0x10, 0x22, + 0xb4, 0x01, 0x52, 0xbc, 0x10, 0x1f, 0xb4, 0x01, 0x5e, 0xbc, 0xf4, 0x07, 0xb4, 0x01, + 0x70, 0xbc, 0xf4, 0x08, 0xb4, 0x01, 0x73, 0xbc, 0x20, 0x20, 0xb4, 0x01, 0x7c, 0xbc, + 0x20, 0x22, 0xb4, 0x01, 0x88, 0xbc, 0x20, 0x75, 0xb4, 0x01, 0x92, 0xbc, 0x20, 0x76, + 0xb4, 0x01, 0x9c, 0xbc, 0xf4, 0x01, 0x94, 0x83, 0xbc, 0xf4, 0x04, 0xb4, 0x03, 0xd6, + 0xbc, 0x20, 0x0d, 0xb4, 0x01, 0x9b, 0xbc, 0x20, 0x0e, 0xb4, 0x01, 0xad, 0xbc, 0x20, + 0x16, 0xb4, 0x01, 0xbf, 0xbc, 0x20, 0x29, 0x94, 0x86, 0xbc, 0x32, 0x15, 0xb4, 0x01, + 0xe1, 0xbc, 0x32, 0x16, 0xb4, 0x01, 0xf3, 0xbc, 0x32, 0x17, 0xb4, 0x02, 0x05, 0xbc, + 0x32, 0x13, 0xb4, 0x02, 0x17, 0xbc, 0x40, 0x0c, 0xb4, 0x02, 0x29, 0xbc, 0x40, 0x0e, + 0xb4, 0x02, 0x33, 0xbc, 0x40, 0x11, 0xb4, 0x02, 0x3d, 0xbc, 0x40, 0x1d, 0xb4, 0x02, + 0xdc, 0xbc, 0x40, 0x3a, 0xb4, 0x02, 0xe6, 0xbc, 0x40, 0x3b, 0xb4, 0x02, 0xf0, 0xbc, + 0x40, 0x41, 0xb4, 0x02, 0xfa, 0xbc, 0x40, 0x15, 0xb4, 0x03, 0x04, 0xbc, 0xf4, 0x02, + 0x94, 0x29, 0xbc, 0x40, 0x1f, 0xb4, 0x03, 0x23, 0xbc, 0x40, 0x13, 0xb4, 0x03, 0x46, + 0xbc, 0x40, 0x17, 0xb4, 0x03, 0x50, 0xbc, 0xf4, 0x03, 0xb4, 0x03, 0x90, 0x3c, 0xa2, + 0x0a, 0xcc, 0xa8, 0xb5, 0xaa, 0x58, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x20, 0x74, 0x8b, + 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xaa, 0x5c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0a, + 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xaa, 0x38, 0xaf, 0xcc, 0xac, 0xcc, + 0xca, 0x82, 0x0e, 0xca, 0xf8, 0xac, 0x74, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb5, 0xd3, + 0x1b, 0xac, 0x74, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xac, 0x74, 0xce, 0xb5, 0xdc, 0xc4, + 0xb2, 0x12, 0x10, 0xa8, 0xcc, 0xb8, 0xfe, 0x80, 0xab, 0xcc, 0x9a, 0x0c, 0xab, 0xca, + 0x30, 0x0b, 0x97, 0xb0, 0xcc, 0x97, 0xfe, 0xca, 0x30, 0x03, 0x3f, 0xcc, 0x3c, 0x00, + 0x96, 0xcc, 0x14, 0x05, 0xe1, 0x66, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0c, 0x72, + 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0a, 0x72, 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, + 0x88, 0xa2, 0x0b, 0x72, 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0d, 0x72, 0x8b, + 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x06, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, + 0xa2, 0x08, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x00, 0x72, 0x8b, 0x9d, + 0x00, 0xb5, 0xd8, 0x8f, 0xa2, 0x00, 0x72, 0x8b, 0x3c, 0xa2, 0x10, 0xcc, 0xa8, 0xab, + 0xca, 0xa2, 0x0e, 0xcc, 0xa8, 0xb5, 0x03, 0x06, 0xa2, 0x02, 0x72, 0xab, 0xa8, 0xca, + 0xa2, 0x04, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x34, 0x72, 0x8b, 0x3c, + 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x30, 0x72, 0xab, 0x90, 0x00, 0xa2, 0x0f, 0x72, 0x8b, + 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x76, 0xa2, 0x0e, 0xcc, 0x88, 0x99, 0x37, + 0xa2, 0x08, 0x74, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x64, 0xa2, 0x0e, + 0xcc, 0xa8, 0xa2, 0x04, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x54, + 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x00, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, + 0xa9, 0x44, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x02, 0x74, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, + 0xa8, 0xb5, 0xa9, 0x34, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0a, 0x74, 0xab, 0xa2, 0x10, + 0xcc, 0xa8, 0xa2, 0x0c, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x1c, + 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0e, 0x74, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x10, + 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x04, 0xa2, 0x0e, 0xcc, 0x88, + 0xa2, 0x1e, 0x74, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0xf4, 0xaf, 0xcc, + 0xac, 0xcc, 0xca, 0x82, 0x0e, 0xcc, 0xf8, 0xac, 0x74, 0xca, 0x82, 0x12, 0xca, 0xf8, + 0xb5, 0xd1, 0xd7, 0x3f, 0xcc, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0xff, 0xa2, + 0x0e, 0xcc, 0xa8, 0xa2, 0x0c, 0x78, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x0e, 0x78, + 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0xe7, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, + 0x08, 0x78, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x0a, 0x78, 0xab, 0x3c, 0xa2, 0x0a, + 0xcc, 0xa8, 0xb5, 0xa8, 0xcf, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x04, 0x78, 0xab, 0xa2, + 0x10, 0xcc, 0xa8, 0xa2, 0x06, 0x78, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, + 0xb7, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x00, 0x78, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, + 0x02, 0x78, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0x8b, 0xa2, 0x0e, 0xcc, + 0xa8, 0xa2, 0x06, 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0x7b, 0xa2, + 0x0e, 0xcc, 0x88, 0xa2, 0x0c, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, + 0x6b, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x4d, 0x9c, 0x01, 0x94, 0x30, 0x9c, 0x02, + 0x94, 0x53, 0x9c, 0x03, 0x94, 0x76, 0x3c, 0xa2, 0x0f, 0xcc, 0x88, 0x99, 0x01, 0xa2, + 0x13, 0x76, 0x8b, 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x5b, 0xa2, 0x14, 0x76, 0x8b, 0xa2, + 0x11, 0xcc, 0x88, 0x99, 0xdb, 0xa2, 0x15, 0x76, 0x8b, 0xa2, 0x22, 0x76, 0x88, 0xa2, + 0x10, 0x72, 0x8b, 0x3c, 0xa2, 0x0f, 0xcc, 0x88, 0x99, 0x01, 0xa2, 0x13, 0x76, 0x8b, + 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x6d, 0xa2, 0x14, 0x76, 0x8b, 0xa2, 0x11, 0xcc, 0x88, + 0x99, 0xed, 0xa2, 0x15, 0x76, 0x8b, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x11, 0x72, 0x8b, + 0x3c, 0xa2, 0x0f, 0xcc, 0x88, 0x99, 0x01, 0xa2, 0x13, 0x76, 0x8b, 0xa2, 0x10, 0xcc, + 0x88, 0x99, 0x6d, 0xa2, 0x14, 0x76, 0x8b, 0xa2, 0x11, 0xcc, 0x88, 0x99, 0x6d, 0xa2, + 0x15, 0x76, 0x8b, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x12, 0x72, 0x8b, 0x3c, 0xa2, 0x0f, + 0xcc, 0x88, 0x99, 0x01, 0xa2, 0x13, 0x76, 0x8b, 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x37, + 0xa2, 0x14, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0xc6, 0xa2, 0x0e, + 0xcc, 0xa8, 0xa2, 0x08, 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0xb6, + 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x10, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, + 0xa7, 0xa6, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x11, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, + 0xa8, 0xb5, 0xa7, 0x96, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0e, 0x76, 0xab, 0x3c, 0xa2, + 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0x86, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x00, 0x76, 0xab, + 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x02, 0x76, 0xab, 0xa2, 0x0e, 0xcc, 0xfa, 0x9d, 0x00, + 0x3c, 0x90, 0x02, 0x01, 0xa2, 0x0c, 0x76, 0xd9, 0xa2, 0x0c, 0x76, 0x8b, 0x3c, 0xa2, + 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0x5c, 0x91, 0x02, 0xa2, 0x0e, 0xcc, 0x88, 0x9c, 0x00, + 0x91, 0x02, 0x9c, 0x01, 0x91, 0x01, 0x9c, 0x02, 0x91, 0x08, 0x9c, 0x03, 0x91, 0x04, + 0x9c, 0x04, 0xb1, 0x01, 0x00, 0xa8, 0xca, 0xa2, 0x04, 0x76, 0xab, 0x3c, 0xa2, 0x0a, + 0xcc, 0xa8, 0xb5, 0xa7, 0x33, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x17, 0x76, 0x8b, 0x3c, + 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0x23, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x18, 0x76, + 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa6, 0xff, 0xac, 0x74, 0xce, 0x82, 0x58, + 0xce, 0xf8, 0xa2, 0x12, 0xcc, 0x88, 0xe7, 0xe7, 0xa0, 0xc8, 0xce, 0xf8, 0xa2, 0x0e, + 0xcc, 0x88, 0xd6, 0xa2, 0x0f, 0xcc, 0x88, 0xa2, 0x01, 0xce, 0x8b, 0xa2, 0x10, 0xcc, + 0x88, 0xa2, 0x02, 0xce, 0x8b, 0xa2, 0x11, 0xcc, 0x88, 0xa2, 0x03, 0xce, 0x8b, 0x3c, + 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa6, 0xdd, 0xac, 0x76, 0xce, 0x82, 0x1a, 0xce, 0xf8, + 0xa2, 0x12, 0xcc, 0x88, 0xe7, 0xe7, 0xa0, 0xc8, 0xce, 0xf8, 0xa2, 0x0e, 0xcc, 0x88, + 0xd6, 0xa2, 0x0f, 0xcc, 0x88, 0xa2, 0x01, 0xce, 0x8b, 0xa2, 0x10, 0xcc, 0x88, 0xa2, + 0x02, 0xce, 0x8b, 0xa2, 0x11, 0xcc, 0x88, 0xa2, 0x03, 0xce, 0x8b, 0x3c, 0x03, 0xae, + 0xca, 0xd7, 0xae, 0xca, 0xd7, 0x03, 0xae, 0xca, 0xd7, 0xae, 0xca, 0xd7, 0x03, 0xae, + 0xca, 0xd7, 0xae, 0xca, 0xd7, 0x3c, 0x00, 0xb6, 0xfe, 0x20, 0xab, 0xb6, 0xfe, 0x00, + 0xab, 0xb6, 0xfe, 0x90, 0xab, 0x3c, 0xac, 0xcc, 0x28, 0xac, 0xce, 0x2a, 0xab, 0xce, + 0xa8, 0x16, 0xb8, 0x00, 0x0a, 0x96, 0x14, 0xfc, 0x94, 0x45, 0xb2, 0xcf, 0x1e, 0xa0, + 0x16, 0xcc, 0xf8, 0xa8, 0x1a, 0xa2, 0x02, 0xcc, 0xab, 0xa8, 0x18, 0xa2, 0x01, 0xcc, + 0x8b, 0xa8, 0xce, 0xc6, 0xa8, 0x1c, 0xa2, 0x04, 0xcc, 0xab, 0xa8, 0x1e, 0xa2, 0x06, + 0xcc, 0xab, 0xa8, 0x20, 0xa2, 0x08, 0xcc, 0xab, 0xa8, 0x16, 0xb8, 0x00, 0x0a, 0xbc, + 0x0b, 0xae, 0x00, 0xab, 0x16, 0xaf, 0xca, 0xb1, 0x04, 0x00, 0xb5, 0x58, 0x5e, 0x3f, + 0xca, 0x00, 0xac, 0x28, 0xcc, 0xac, 0x2a, 0xce, 0x3c, 0xb6, 0xff, 0x04, 0xa9, 0x76, + 0x00, 0xab, 0x14, 0xab, 0x16, 0xa7, 0xcf, 0x1e, 0xda, 0xd6, 0x00, 0xe1, 0x62, 0x3c, + 0xa8, 0x14, 0x96, 0x16, 0xfc, 0x42, 0x00, 0x3c, 0x90, 0x01, 0x63, 0x34, 0x0b, 0x9c, + 0x00, 0x44, 0xb0, 0xf0, 0x00, 0x3c, 0xb6, 0xfe, 0x00, 0x88, 0x96, 0xc8, 0x17, 0x94, + 0x35, 0xaf, 0xce, 0xaf, 0xcc, 0xa7, 0xfe, 0x00, 0xfe, 0x0e, 0xb3, 0xcf, 0x1e, 0xa0, + 0x14, 0xce, 0xf8, 0xf0, 0xb9, 0xff, 0x7f, 0xe1, 0xf0, 0xe1, 0xf0, 0xe1, 0xf0, 0xe1, + 0xf0, 0xe1, 0xa8, 0x14, 0xb8, 0x00, 0x0a, 0xbc, 0x0b, 0xae, 0x00, 0xab, 0x14, 0xb3, + 0xfe, 0x00, 0xd4, 0x9a, 0x80, 0xd6, 0x3f, 0xcc, 0x3f, 0xce, 0x00, 0x3c, 0xb0, 0xf0, + 0x01, 0x3c, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, + 0x48, 0xcc, 0xf8, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xcf, 0x24, 0xa2, 0x35, 0xce, + 0x88, 0x9c, 0x00, 0x94, 0x22, 0xa2, 0x3f, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x23, 0xb7, + 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, + 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xce, 0xfa, 0xb7, 0x1e, 0x84, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0x7a, 0xb7, 0x31, 0x2d, 0x02, 0xb7, 0x00, 0x01, 0x04, + 0x95, 0x23, 0xa2, 0x35, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0x09, 0xc4, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, 0xb7, 0x02, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xce, 0xc6, 0xb7, 0x62, 0x5a, 0x08, 0xb7, 0x00, 0x02, + 0x0a, 0xa2, 0x35, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x35, 0xa2, 0x36, 0xce, 0x88, 0x9c, + 0x00, 0x94, 0x77, 0xa2, 0x38, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x25, 0xa2, 0x37, 0xce, + 0x88, 0x9d, 0x00, 0x5e, 0xa2, 0x34, 0xce, 0x88, 0x9c, 0x07, 0x4a, 0xf4, 0xab, 0x08, + 0xa2, 0x02, 0xce, 0xa8, 0xab, 0x0a, 0x4d, 0xa2, 0x24, 0xce, 0xa8, 0xab, 0x08, 0xa2, + 0x26, 0xce, 0xa8, 0xab, 0x0a, 0x40, 0xa2, 0x54, 0xce, 0x88, 0x9c, 0x00, 0x47, 0xa2, + 0x34, 0xce, 0x88, 0x9c, 0x07, 0x58, 0xac, 0x08, 0x02, 0xac, 0x0a, 0x04, 0xac, 0xce, + 0xcc, 0x82, 0x48, 0xcc, 0xf8, 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, + 0xce, 0x5b, 0x86, 0x12, 0x60, 0x08, 0xfc, 0x41, 0x7e, 0x86, 0x04, 0xa8, 0x0a, 0xfc, + 0x42, 0x95, 0x25, 0xb7, 0x01, 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa6, 0x60, 0x95, 0x3a, 0xb7, 0x00, 0x4e, 0x08, + 0xb7, 0x00, 0x00, 0x0a, 0x95, 0x52, 0xa2, 0x35, 0xce, 0x88, 0x9c, 0x00, 0x5a, 0xb7, + 0x00, 0x4e, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, + 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xce, 0x0c, 0xb7, 0x62, 0x5a, + 0x02, 0xb7, 0x00, 0x02, 0x04, 0x7a, 0x95, 0x2a, 0x95, 0x2c, 0xa2, 0x35, 0xce, 0x88, + 0x9c, 0x00, 0x94, 0x21, 0xa2, 0x3a, 0xce, 0x88, 0x9d, 0x00, 0x5a, 0xb7, 0x00, 0x4e, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, 0xb7, 0x02, + 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xcd, 0xd6, 0xa2, 0x35, 0xce, 0x88, 0x9c, + 0x00, 0x4a, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0x95, 0x21, 0xb7, 0x62, + 0x5a, 0x02, 0xb7, 0x00, 0x02, 0x04, 0x95, 0x2b, 0x90, 0x00, 0xa2, 0x50, 0xce, 0xab, + 0xb5, 0xd3, 0xf7, 0x90, 0x00, 0xb5, 0xd3, 0xca, 0x91, 0x02, 0xa2, 0x22, 0xce, 0x88, + 0xb5, 0xd4, 0xdc, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa5, 0xb8, 0xb7, 0x03, 0x02, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa5, 0xa5, 0x90, + 0x00, 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x21, + 0xb5, 0xe9, 0x4d, 0x90, 0x00, 0xa2, 0x2a, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, + 0x18, 0xb0, 0x40, 0x3f, 0xb5, 0xe9, 0x3b, 0x90, 0x00, 0xa2, 0x2c, 0xce, 0xab, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3d, 0xb5, 0xe9, 0x29, 0x90, 0x00, 0xa2, + 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe9, + 0x17, 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xa5, 0x4a, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, + 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, + 0xf8, 0xb5, 0xcd, 0x09, 0xb4, 0xfd, 0xcb, 0x90, 0x00, 0xb5, 0xd3, 0x1e, 0x91, 0x02, + 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd4, 0x30, 0x90, 0x07, 0xa2, 0x50, 0xce, 0xab, 0xb5, + 0xd3, 0x34, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa5, 0x03, 0xb7, 0x03, 0x02, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa4, 0xf0, 0x90, 0x00, + 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, + 0xb0, 0x40, 0x21, 0xb5, 0xe8, 0x94, 0x90, 0x00, 0xa2, 0x29, 0xce, 0x8b, 0xa2, 0x54, + 0xce, 0x88, 0x9c, 0x00, 0x94, 0x1f, 0xa2, 0x34, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x44, + 0xa2, 0x22, 0xce, 0x88, 0xb7, 0x01, 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa4, 0xad, 0xa2, 0x2a, 0xce, 0x88, 0x9c, + 0x00, 0x94, 0x42, 0x90, 0x01, 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, + 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe8, 0x4d, 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa4, 0x80, 0xb7, 0x00, + 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, + 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, 0xb5, 0xcc, 0x3f, 0xb4, 0xfd, 0x18, 0xa2, + 0x2c, 0xce, 0xa8, 0x9c, 0x01, 0x95, 0x48, 0x90, 0x01, 0xa2, 0x2c, 0xce, 0xab, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3d, 0xb5, 0xe8, 0x03, 0x95, 0x5c, 0xa2, + 0x14, 0x72, 0x88, 0x9d, 0x00, 0x95, 0xec, 0x90, 0x01, 0xa2, 0x41, 0xce, 0x8b, 0x3c, + 0x90, 0x30, 0x01, 0xab, 0xca, 0xa2, 0x50, 0xce, 0xa8, 0x96, 0xca, 0xf9, 0xa2, 0x50, + 0xce, 0xab, 0xb5, 0xd2, 0x43, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x02, 0xa2, 0x4e, + 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe7, 0xc8, + 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xa3, 0xfb, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, + 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, + 0xb5, 0xcb, 0xba, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd2, 0x5e, 0xa2, 0x2e, 0xce, 0xab, + 0xab, 0xca, 0x99, 0x06, 0x9c, 0x00, 0x48, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, 0x94, + 0x2c, 0x82, 0x08, 0xca, 0xf9, 0x82, 0x00, 0xca, 0xfc, 0x94, 0x32, 0xa2, 0x3b, 0xce, + 0x88, 0x9d, 0x00, 0x94, 0x2a, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xb7, 0x01, 0x03, + 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, + 0xa3, 0x9c, 0x50, 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0x00, 0xb5, 0xa3, 0x8b, 0x91, 0x08, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd2, 0x93, + 0x3c, 0x90, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x21, 0xb5, 0xe7, 0x25, 0x90, 0x08, 0xa2, 0x50, 0xce, + 0xfa, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xd1, 0x7c, 0x90, 0x03, 0xa2, 0x4e, 0xce, 0xab, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe7, 0x06, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xd1, 0xc9, 0xa2, 0x2e, 0xce, 0xab, 0xab, 0xca, 0x99, 0x04, 0x9d, + 0x00, 0x5c, 0x82, 0x40, 0xca, 0xf9, 0x82, 0x00, 0xca, 0xfd, 0xb4, 0xfe, 0x02, 0x90, + 0x01, 0xb5, 0xd1, 0x20, 0x91, 0x04, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd2, 0x32, 0xb4, + 0xfc, 0x10, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0x77, 0x00, 0xa2, 0x35, 0xce, 0x8b, + 0xa2, 0x36, 0xce, 0x8b, 0xa2, 0x37, 0xce, 0x8b, 0xa2, 0x38, 0xce, 0x8b, 0x90, 0x04, + 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, + 0xe6, 0xae, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd1, 0x71, 0xa2, 0x2e, 0xce, 0xab, 0x99, + 0x40, 0x9c, 0x00, 0x54, 0x90, 0x08, 0x01, 0xa2, 0x50, 0xce, 0xf9, 0xa2, 0x50, 0xce, + 0xab, 0xb5, 0xd0, 0xf4, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, + 0xb5, 0xd1, 0x4d, 0xa2, 0x2e, 0xce, 0xab, 0x99, 0x02, 0x9d, 0x00, 0xb4, 0xfd, 0x91, + 0xa2, 0x34, 0xce, 0x88, 0x9d, 0x04, 0x4c, 0x91, 0x01, 0xa2, 0x22, 0xce, 0x88, 0xb5, + 0xd1, 0xbf, 0xb4, 0xfb, 0xbe, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x72, 0xac, 0xce, + 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0x09, 0xae, 0x42, 0x95, 0x20, 0x90, + 0x05, 0xb5, 0x09, 0xa6, 0x42, 0x95, 0x28, 0x90, 0x03, 0xb5, 0x09, 0x9e, 0xb4, 0xfd, + 0x58, 0x95, 0x32, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x05, 0xa2, 0x4e, 0xce, 0xab, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe6, 0x26, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xd0, 0xe9, 0xa2, 0x2e, 0xce, 0xab, 0xab, 0xca, 0x99, 0x04, 0x9c, + 0x00, 0x94, 0x40, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xac, 0xce, 0xcc, 0x82, 0x46, + 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0xb5, 0x09, 0x4b, 0xac, 0xce, 0xcc, 0x82, 0x44, + 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0xb5, 0x09, 0x4d, 0x5a, 0x91, 0x08, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xd1, 0x3e, 0xb5, 0xfb, 0xd6, 0x90, 0x08, 0xa2, 0x50, 0xce, 0xfa, + 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xd0, 0x3b, 0x3c, 0x91, 0x04, 0x7a, 0x82, 0x08, 0xca, + 0xf9, 0x82, 0x00, 0xca, 0xfc, 0x95, 0x34, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xac, + 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0xb5, 0x09, 0x09, 0x95, + 0x4a, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x42, 0x94, 0x3e, 0xa2, 0x30, 0x72, 0xa8, + 0x9c, 0x00, 0x94, 0x36, 0xa2, 0x54, 0xce, 0x88, 0x9d, 0x00, 0x94, 0x2e, 0xa2, 0x24, + 0xce, 0xa8, 0xbc, 0x12, 0x60, 0x42, 0x94, 0x24, 0xa2, 0x26, 0xce, 0xa8, 0xbc, 0x04, + 0xa8, 0x41, 0x5b, 0xa2, 0x30, 0x72, 0xa8, 0xa2, 0x32, 0x72, 0xfd, 0x43, 0xb4, 0xfc, + 0x94, 0xa2, 0x32, 0x72, 0xa8, 0x04, 0xa2, 0x32, 0x72, 0xab, 0x90, 0x01, 0xa2, 0x54, + 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x06, 0xa2, 0x4e, 0xce, 0xab, + 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe5, 0x54, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xd0, 0x17, 0xa2, 0x2e, 0xce, 0xab, 0x99, 0x04, 0x9d, 0x00, 0x59, + 0x90, 0x08, 0xa2, 0x50, 0xce, 0xfa, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xcf, 0x9b, 0x91, + 0x04, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd0, 0x85, 0xb4, 0xfb, 0x47, 0x90, 0x01, 0xa2, + 0x35, 0xce, 0x8b, 0x7f, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x07, 0xa2, 0x4e, 0xce, + 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe5, 0x0d, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xcf, 0xd0, 0xa2, 0x2e, 0xce, 0xab, 0xab, 0xca, 0x99, 0x08, + 0x9d, 0x00, 0x4c, 0x82, 0x40, 0xca, 0xf9, 0x82, 0x00, 0xca, 0xfc, 0x4a, 0xb4, 0xfc, + 0x08, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0x40, 0x91, 0x08, 0xa2, 0x22, 0xce, 0x88, + 0xb5, 0xd0, 0x36, 0xb4, 0xfa, 0xfa, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x3b, 0xce, + 0x8b, 0x90, 0x03, 0xa2, 0x2c, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, + 0x40, 0x3d, 0xb5, 0xe4, 0xc1, 0x00, 0xa2, 0x41, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0xab, + 0x90, 0x08, 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, + 0x3e, 0xb5, 0xe4, 0xa6, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcf, 0x69, 0xa2, 0x2e, 0xce, + 0xab, 0x99, 0x40, 0x9c, 0x00, 0x54, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x08, + 0x01, 0xa2, 0x50, 0xce, 0xf9, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xce, 0xe6, 0x91, 0x01, + 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcf, 0xd0, 0xb4, 0xfa, 0x96, 0x90, 0x00, 0xa2, 0x50, + 0xce, 0xab, 0xb5, 0xce, 0xd1, 0x90, 0x09, 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe4, 0x5b, 0xa2, 0x04, 0xce, 0xa8, 0x9c, + 0x02, 0x94, 0x2c, 0x90, 0x01, 0xb5, 0xce, 0x8a, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x02, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xc8, 0x53, 0xa2, 0x04, 0xce, 0xa8, 0xab, 0xca, 0xa2, 0x22, + 0xce, 0x88, 0xb4, 0xcf, 0x7e, 0x90, 0x00, 0xb5, 0xce, 0x5e, 0x95, 0x2c, 0xa8, 0x46, + 0xb5, 0x9e, 0xc9, 0xa2, 0x0e, 0x76, 0xa8, 0x9c, 0x00, 0x3c, 0xa8, 0x44, 0xbc, 0x02, + 0x09, 0x55, 0xbc, 0x02, 0xff, 0x59, 0xbc, 0x02, 0x01, 0x94, 0x46, 0xbc, 0x02, 0x04, + 0x94, 0x4e, 0xbc, 0x02, 0x10, 0x94, 0x79, 0x94, 0xb2, 0xa8, 0x48, 0xa2, 0x2e, 0x76, + 0xab, 0x94, 0xaa, 0xa8, 0x48, 0xa2, 0x48, 0x76, 0xfc, 0x94, 0x23, 0xa2, 0x4a, 0x76, + 0xfc, 0x46, 0xa2, 0x4c, 0x76, 0xfc, 0x4d, 0x3c, 0xb0, 0x02, 0x0b, 0xab, 0x44, 0x00, + 0xa2, 0x4a, 0x76, 0xab, 0x94, 0x8b, 0xb0, 0x02, 0x0d, 0xab, 0x44, 0x00, 0xa2, 0x4c, + 0x76, 0xab, 0x94, 0x7f, 0x00, 0xa2, 0x48, 0x76, 0xab, 0x94, 0x78, 0xa2, 0x4e, 0x76, + 0xa8, 0x9c, 0x09, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xfa, 0xcb, 0xa2, 0x4e, 0x76, 0xa8, + 0x9c, 0x09, 0x3c, 0xac, 0x76, 0xce, 0xb5, 0xfa, 0x09, 0xa2, 0x54, 0x76, 0x88, 0x9c, + 0x00, 0x3c, 0xa2, 0x34, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x43, 0xac, 0x76, 0xce, 0xb7, + 0x01, 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb4, + 0x9f, 0xc8, 0xac, 0x76, 0xce, 0xb5, 0xf9, 0xe0, 0xa2, 0x54, 0x76, 0x88, 0x9c, 0x00, + 0x5c, 0xa2, 0x34, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x43, 0xac, 0x76, 0xce, 0xb7, 0x01, + 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb5, 0x9f, + 0x9f, 0x90, 0x09, 0xa2, 0x4e, 0x76, 0xab, 0xa2, 0x22, 0x76, 0x88, 0xab, 0x18, 0xb0, + 0x40, 0x3e, 0xb4, 0xe3, 0x47, 0xa2, 0x4e, 0x76, 0xa8, 0x9c, 0x00, 0x94, 0x2b, 0x9c, + 0x01, 0x94, 0x3a, 0x9c, 0x02, 0x94, 0x93, 0x9c, 0x03, 0x94, 0xec, 0x9c, 0x04, 0xb4, + 0x01, 0x74, 0x9c, 0x05, 0xb4, 0x02, 0xad, 0x9c, 0x06, 0xb4, 0x03, 0x42, 0x9c, 0x07, + 0xb4, 0x03, 0xba, 0x9c, 0x08, 0xb4, 0x04, 0x1f, 0x9c, 0x09, 0xb4, 0x06, 0x44, 0x3c, + 0xa8, 0x44, 0xbc, 0x02, 0x02, 0x41, 0x3c, 0xa8, 0x48, 0xa2, 0x04, 0x76, 0xab, 0xac, + 0x76, 0xce, 0xb4, 0xfe, 0x8b, 0xa8, 0x44, 0xbc, 0x02, 0xff, 0x46, 0xbc, 0x02, 0x09, + 0x94, 0x35, 0x3c, 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0x4f, 0x90, 0x01, 0xa2, 0x3f, + 0x76, 0x8b, 0xac, 0x46, 0x18, 0xb0, 0x40, 0x21, 0xb4, 0xe2, 0xdf, 0x90, 0x01, 0xa2, + 0x35, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcd, 0x99, 0xa2, + 0x2e, 0x76, 0xab, 0x99, 0x06, 0x9c, 0x00, 0xb4, 0xf7, 0xbf, 0xb4, 0xfb, 0x86, 0xa2, + 0x35, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, + 0xcd, 0x7a, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x06, 0x9c, 0x00, 0x3c, 0xb4, 0xfb, 0x69, + 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x41, 0x3c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x06, 0x9c, + 0x00, 0x4f, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x48, 0xa2, 0x1e, 0x72, 0x88, 0x9c, + 0x02, 0x94, 0x2e, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x3c, 0xa2, 0x35, + 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xa2, 0x3b, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0x90, 0x01, + 0xa2, 0x35, 0x76, 0x8b, 0xb7, 0x01, 0x03, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa8, 0x46, 0xb4, 0x9e, 0x9d, 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0x9e, 0x8d, 0xa8, 0x44, 0xbc, 0x02, 0x09, + 0x4b, 0xbc, 0x02, 0x14, 0x94, 0x31, 0xbc, 0x02, 0xff, 0x94, 0x33, 0x3c, 0xa2, 0x35, + 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x4c, + 0x90, 0x01, 0xa2, 0x35, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xf7, 0x52, 0xa2, 0x2e, + 0x76, 0xa8, 0x99, 0x40, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf9, 0x24, 0xa2, + 0x48, 0x76, 0xa8, 0x9d, 0x00, 0x3c, 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xa2, + 0x06, 0x76, 0xa8, 0x9c, 0x03, 0x4b, 0x00, 0xa2, 0x34, 0x76, 0x8b, 0xac, 0x76, 0xce, + 0xb4, 0xfb, 0x1a, 0xa2, 0x30, 0x72, 0x88, 0x9c, 0x00, 0x71, 0xa2, 0x30, 0x72, 0xa8, + 0xa2, 0x32, 0x72, 0xfd, 0x47, 0x90, 0x01, 0xa2, 0x55, 0x76, 0x8b, 0x3c, 0xa2, 0x32, + 0x72, 0xa8, 0x04, 0xa2, 0x32, 0x72, 0xab, 0x90, 0x01, 0xa2, 0x55, 0x76, 0x8b, 0x00, + 0xa2, 0x34, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xfa, 0xe9, 0xa8, 0x44, 0xbc, 0x02, + 0x09, 0x94, 0x3c, 0xbc, 0x02, 0xff, 0x94, 0x92, 0xbc, 0x02, 0x06, 0x4e, 0xbc, 0x02, + 0x05, 0x5a, 0xbc, 0x02, 0x07, 0x5c, 0xbc, 0x02, 0x13, 0x94, 0xf0, 0x3c, 0xb1, 0x01, + 0x00, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcc, 0xe6, 0xb4, 0xf6, 0xe5, + 0xac, 0x76, 0xce, 0xb4, 0xfb, 0x49, 0xac, 0x76, 0xce, 0xa2, 0x3c, 0x76, 0x88, 0x9d, + 0x00, 0xb4, 0xf8, 0x93, 0xb4, 0xfb, 0xc4, 0xac, 0x76, 0xce, 0xa2, 0x2e, 0x76, 0xa8, + 0x99, 0x02, 0x9d, 0x00, 0xb4, 0xf8, 0x82, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x40, 0x9c, + 0x00, 0x5e, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x57, 0x90, 0x08, 0x01, 0xa2, 0x50, + 0x76, 0xf9, 0xa2, 0x50, 0x76, 0xab, 0xb5, 0xcb, 0xaf, 0x90, 0x01, 0xa2, 0x35, 0x76, + 0x8b, 0xb4, 0xf6, 0x9b, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x0c, 0x9c, 0x00, 0x3c, 0xa2, + 0x38, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x37, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0x90, + 0x01, 0xa2, 0x37, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb5, 0x04, 0x87, 0xb4, 0xf6, 0x75, + 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x4d, 0xa2, 0x34, 0x76, 0x88, 0x9c, 0x00, 0x3c, + 0xac, 0x76, 0xce, 0xb4, 0xf8, 0x21, 0xac, 0x76, 0xce, 0xa2, 0x36, 0xce, 0x88, 0x9d, + 0x00, 0x94, 0x36, 0x90, 0x01, 0xa2, 0x36, 0xce, 0x8b, 0xb5, 0x07, 0x8e, 0xb5, 0xf6, + 0x4a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcb, 0xb4, 0xa2, 0x2e, 0xce, 0xab, 0x99, 0x0c, + 0x9c, 0x00, 0x3c, 0xa2, 0x38, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x37, 0xce, 0x88, + 0x9d, 0x00, 0x3c, 0x90, 0x01, 0xa2, 0x37, 0xce, 0x8b, 0xb5, 0x04, 0x32, 0xb4, 0xf6, + 0x20, 0xa2, 0x38, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x37, 0xce, 0x88, 0x9d, 0x00, + 0x3c, 0x90, 0x01, 0xa2, 0x37, 0xce, 0x8b, 0xb5, 0x04, 0x18, 0xb4, 0xf6, 0x06, 0xa2, + 0x34, 0x76, 0x88, 0x9d, 0x04, 0x41, 0x3c, 0xa2, 0x3c, 0x76, 0x88, 0x9d, 0x00, 0x3c, + 0xac, 0x76, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0x03, 0xee, 0x41, 0x3c, + 0x90, 0x05, 0xb5, 0x03, 0xe7, 0x41, 0x3c, 0x90, 0x03, 0xb5, 0x03, 0xe0, 0x41, 0x3c, + 0xac, 0x76, 0xce, 0xb4, 0xf7, 0x95, 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x46, 0xbc, 0x02, + 0xff, 0x94, 0x77, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x02, 0x9d, + 0x00, 0xb4, 0xf7, 0x7b, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xa2, 0x2e, 0x76, + 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x94, 0x27, 0x90, 0x01, 0xa2, 0x35, 0x76, 0x8b, 0xa2, + 0x34, 0x76, 0x88, 0xac, 0x76, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0xb5, 0x03, 0x89, 0xa2, + 0x50, 0x76, 0xa8, 0x9a, 0x08, 0xa2, 0x50, 0x76, 0xab, 0xac, 0x76, 0xce, 0xb5, 0xca, + 0x91, 0xb5, 0xf6, 0x1c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x3c, 0x90, + 0x01, 0xa2, 0x35, 0x76, 0x8b, 0xa2, 0x34, 0x76, 0x88, 0xac, 0x76, 0xcc, 0x82, 0x46, + 0xcc, 0xf8, 0xb5, 0x03, 0x61, 0xa2, 0x50, 0x76, 0xa8, 0x9a, 0x08, 0xa2, 0x50, 0x76, + 0xab, 0xac, 0x76, 0xce, 0xb5, 0xca, 0x61, 0xb4, 0xf5, 0xec, 0xac, 0x76, 0xce, 0xa2, + 0x35, 0x76, 0x88, 0x9c, 0x00, 0xb4, 0xf7, 0x07, 0xa2, 0x34, 0x76, 0x88, 0x04, 0xa2, + 0x34, 0x76, 0x8b, 0xb4, 0xf9, 0x11, 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x4b, 0xbc, 0x02, + 0xff, 0x94, 0x4d, 0xbc, 0x02, 0x13, 0x94, 0x60, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x2e, + 0x76, 0xa8, 0x99, 0x02, 0x9d, 0x00, 0xb4, 0xf6, 0xdc, 0xa2, 0x35, 0x76, 0x88, 0x9d, + 0x00, 0x55, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x4c, 0x90, 0x01, 0xa2, + 0x35, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xf5, 0xc3, 0xac, 0x76, 0xce, 0xa2, 0x22, + 0xce, 0x88, 0xb5, 0xca, 0x67, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x40, 0x9c, 0x00, 0x3c, + 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xb4, 0xf6, 0xa3, 0xac, 0x76, 0xce, 0xa2, + 0x35, 0x76, 0x88, 0x9c, 0x00, 0xb4, 0xf6, 0x97, 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, + 0xb4, 0xfa, 0x51, 0xb4, 0xf6, 0x8b, 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, + 0x76, 0xce, 0xb4, 0xf6, 0x7e, 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x4b, 0xbc, 0x02, 0xff, + 0x94, 0x3a, 0xbc, 0x02, 0x13, 0x94, 0x4d, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x2e, 0x76, + 0xa8, 0x99, 0x02, 0x9c, 0x00, 0x43, 0xb4, 0xf6, 0x5e, 0xa2, 0x35, 0x76, 0x88, 0x9d, + 0x00, 0x3c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x49, 0x90, 0x01, 0xa2, + 0x35, 0x76, 0x8b, 0xb4, 0xf5, 0x4a, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x40, 0x9c, 0x00, + 0x3c, 0xb4, 0xf6, 0x39, 0xac, 0x76, 0xce, 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0xb4, + 0xf6, 0x2d, 0xa2, 0x3c, 0x76, 0x88, 0x9d, 0x00, 0xb4, 0xf6, 0x24, 0xb4, 0xfa, 0x2c, + 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf6, 0x14, 0xa8, + 0x44, 0xbc, 0x02, 0xff, 0x94, 0x36, 0xbc, 0x02, 0x09, 0x94, 0x98, 0xbc, 0x02, 0x03, + 0xb4, 0x01, 0x6e, 0xbc, 0x02, 0x0a, 0xb4, 0x01, 0x6e, 0xbc, 0x02, 0x0b, 0xb4, 0x01, + 0x75, 0xbc, 0x02, 0x06, 0xb4, 0x01, 0x93, 0xbc, 0x02, 0x13, 0xb4, 0x01, 0xc2, 0xbc, + 0x02, 0x0d, 0xb4, 0x01, 0xc9, 0xbc, 0x02, 0x11, 0xb4, 0x01, 0xda, 0xbc, 0x02, 0x12, + 0xb4, 0x01, 0xe1, 0x3c, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x4d, 0xa2, 0x3b, 0x76, + 0x88, 0x9d, 0x00, 0x46, 0xac, 0x76, 0xce, 0xb4, 0xf6, 0xa9, 0xa2, 0x35, 0x76, 0x88, + 0x9c, 0x00, 0x3c, 0xa2, 0x3a, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xc9, 0x5c, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x08, 0x9c, 0x00, + 0x4d, 0xa2, 0x3b, 0x76, 0x88, 0x9d, 0x00, 0x46, 0xb5, 0xf5, 0x98, 0xb4, 0xf4, 0x9c, + 0xb7, 0x03, 0x02, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, + 0xb5, 0x9a, 0xb1, 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa8, 0x46, 0xb5, 0x9a, 0xa0, 0xb4, 0xf4, 0x77, 0xa2, 0x3b, 0x76, 0x88, 0x9d, + 0x00, 0x51, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x48, 0xac, 0x76, 0xce, + 0xb5, 0xf5, 0x5a, 0x94, 0x50, 0xa2, 0x3b, 0x76, 0x88, 0x9d, 0x00, 0x51, 0xa2, 0x2e, + 0x76, 0xa8, 0x99, 0x02, 0x9c, 0x00, 0x48, 0xac, 0x76, 0xce, 0xb5, 0xf6, 0x28, 0x94, + 0x38, 0xa2, 0x3a, 0x76, 0x88, 0x9c, 0x00, 0x94, 0x58, 0xa2, 0x3b, 0x76, 0x88, 0x9d, + 0x00, 0x94, 0x50, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x94, 0x46, 0x90, + 0x01, 0xa2, 0x3b, 0x76, 0x8b, 0xb7, 0x01, 0x03, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, + 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb5, 0x9a, 0x3c, 0xac, 0x76, 0xce, 0xb5, 0xf4, 0x10, + 0x40, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x20, 0x9c, 0x00, 0x3c, 0xa2, 0x4a, 0x76, 0xa8, + 0x9d, 0x00, 0x3c, 0xb7, 0x07, 0xef, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x02, 0x00, + 0x06, 0xac, 0x76, 0xcc, 0x82, 0x4a, 0xcc, 0xf8, 0xa8, 0x46, 0xb4, 0xc1, 0xe6, 0xa2, + 0x2e, 0x76, 0xa8, 0x99, 0x40, 0x9c, 0x00, 0x95, 0x30, 0xa2, 0x4a, 0x76, 0xa8, 0x9c, + 0x00, 0x57, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xac, 0x76, 0xcc, 0x82, 0x4a, 0xcc, 0xf8, 0x00, 0xb5, 0xc1, 0xbe, 0xa2, 0x35, 0x76, + 0x88, 0x9d, 0x00, 0x95, 0x56, 0x90, 0x01, 0xa2, 0x35, 0x76, 0x8b, 0x90, 0x08, 0x01, + 0xa2, 0x50, 0x76, 0xf9, 0xa2, 0x50, 0x76, 0xab, 0xac, 0x76, 0xce, 0xb5, 0xc7, 0xe4, + 0xb5, 0xf3, 0x9d, 0x95, 0x72, 0xac, 0x76, 0xce, 0xb4, 0xf5, 0x83, 0xa2, 0x3b, 0x76, + 0x88, 0x9d, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf5, 0x67, 0xac, 0x76, 0xce, 0xa2, + 0x22, 0xce, 0x88, 0xb5, 0xc8, 0x28, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x41, 0x9d, 0x00, + 0x3c, 0xb7, 0x02, 0x0a, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, + 0x46, 0xb4, 0x99, 0x8a, 0xa2, 0x4c, 0x76, 0xa8, 0x9d, 0x00, 0x3c, 0xb1, 0x01, 0x00, + 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xc8, 0x87, 0x90, 0x30, 0xa2, 0x50, + 0x76, 0xfa, 0xa2, 0x50, 0x76, 0xab, 0xb5, 0xc7, 0x87, 0xb7, 0x05, 0x01, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb5, 0x99, 0x58, 0xb4, 0xf3, + 0x2f, 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf4, 0x1b, + 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, + 0xb5, 0x99, 0x37, 0xac, 0x76, 0xce, 0xb4, 0xf3, 0x0b, 0xa2, 0x3b, 0x76, 0x88, 0x9d, + 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf4, 0xdd, 0xa2, 0x41, 0x76, 0x88, 0x9c, 0x00, + 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf3, 0xea, 0xa8, 0x44, 0xbc, 0x02, 0x02, 0x45, 0xbc, + 0x02, 0x0f, 0x4d, 0x3c, 0xa8, 0x48, 0xa2, 0x04, 0x76, 0xab, 0xac, 0x76, 0xce, 0xb4, + 0xf8, 0x44, 0xac, 0x76, 0xce, 0xb4, 0xf3, 0x18, 0xaf, 0xce, 0xab, 0xce, 0x39, 0x3f, + 0xce, 0x3c, 0xaf, 0xce, 0xab, 0xce, 0x38, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xab, 0xce, + 0x3a, 0x43, 0x3f, 0xce, 0x3d, 0x3f, 0xce, 0x3c, 0xa2, 0x34, 0xce, 0x88, 0x9c, 0x00, + 0x94, 0x2a, 0x9c, 0x01, 0x94, 0x42, 0x9c, 0x02, 0x94, 0x79, 0x9c, 0x03, 0x94, 0xb0, + 0x9c, 0x04, 0x94, 0xe2, 0x9c, 0x05, 0xb4, 0x01, 0x89, 0x9c, 0x06, 0xb4, 0x01, 0x97, + 0x9c, 0x07, 0xb4, 0x01, 0xd0, 0x9c, 0x08, 0xb4, 0x02, 0x45, 0x9c, 0x09, 0xb4, 0x02, + 0x81, 0x3c, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x34, 0x4d, 0xb7, 0x02, 0x05, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, + 0x98, 0x90, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x02, 0x94, 0x24, 0x9c, 0x03, 0x94, 0x20, + 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x34, 0x79, 0xb7, + 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, + 0x88, 0xb4, 0x98, 0x64, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, + 0xf8, 0x34, 0xa1, 0x95, 0x20, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x01, 0x94, 0x24, 0x9c, + 0x03, 0x94, 0x20, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, + 0x34, 0xb4, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x98, 0x29, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, + 0x82, 0x44, 0xcc, 0xf8, 0x34, 0xdc, 0x95, 0x20, 0xb5, 0xd9, 0x79, 0x9c, 0x00, 0x94, + 0x20, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x34, 0xf2, + 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, + 0xce, 0x88, 0xb4, 0x97, 0xf3, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, + 0xcc, 0xf8, 0x35, 0x0a, 0x95, 0x20, 0xa2, 0x2a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x44, + 0xa2, 0x2c, 0xce, 0xa8, 0x9c, 0x02, 0x94, 0x26, 0x53, 0xb7, 0x02, 0x05, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x97, 0xc0, + 0x90, 0x02, 0xa2, 0x2c, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, + 0x3d, 0xb5, 0xdb, 0x68, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, + 0x88, 0x35, 0x57, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0x5e, 0x95, 0x39, 0xa2, 0x2c, + 0xce, 0xa8, 0x9c, 0x02, 0x52, 0x90, 0x01, 0xa2, 0x2c, 0xce, 0xab, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3d, 0xb5, 0xdb, 0x39, 0xa2, 0x40, 0xce, 0x88, 0x9c, + 0x00, 0x56, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x35, + 0x8d, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0x8c, 0x95, 0x6f, 0xac, 0xce, 0xcc, 0x82, + 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x35, 0x9b, 0xa2, 0x30, 0xce, 0xa8, 0xa2, + 0x32, 0xce, 0xfa, 0x9c, 0x00, 0x49, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0xb5, 0x95, + 0x90, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0xb6, 0x95, 0x99, 0xb7, 0x02, 0x05, 0x02, + 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x97, + 0x25, 0xa2, 0x0c, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x55, 0xa2, 0x0f, 0x72, 0x88, + 0x9c, 0x00, 0x4e, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, + 0x35, 0xf0, 0x4d, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, + 0x35, 0xf6, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x96, 0xe7, 0xaf, 0xce, 0xb7, 0x05, 0x04, 0x44, 0xb7, + 0x00, 0x00, 0x48, 0xb7, 0x00, 0x00, 0x4a, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x46, 0xb5, + 0x9b, 0xc3, 0x3f, 0xce, 0x90, 0x20, 0x01, 0xab, 0xca, 0xa2, 0x50, 0xce, 0xa8, 0x96, + 0xca, 0xf9, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc4, 0xd9, 0xb7, 0x03, 0x01, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x96, 0xa8, + 0xa2, 0x30, 0xce, 0xa8, 0xa2, 0x32, 0xce, 0xfa, 0x9c, 0x00, 0x94, 0x20, 0xac, 0xce, + 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x36, 0x69, 0xb7, 0x02, 0x05, + 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, + 0x96, 0x7c, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x36, + 0x81, 0x95, 0x20, 0xa2, 0x0c, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, 0x28, 0xa2, + 0x0f, 0x72, 0x88, 0x9c, 0x00, 0x94, 0x20, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, + 0xa2, 0x34, 0xce, 0x88, 0x36, 0xaa, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, + 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x96, 0x3b, 0xac, 0xce, 0xcc, + 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x36, 0xc2, 0x95, 0x20, 0xb7, 0x03, + 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, + 0xb5, 0x96, 0x19, 0x90, 0x20, 0x01, 0xab, 0xca, 0xa2, 0x50, 0xce, 0xa8, 0x96, 0xca, + 0xf9, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc4, 0x24, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, + 0x94, 0x30, 0xa2, 0x2a, 0xce, 0x88, 0x9c, 0x00, 0x42, 0x94, 0x27, 0xb5, 0xd9, 0x1c, + 0x9c, 0x00, 0x94, 0x33, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, + 0x88, 0x37, 0x17, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, + 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x95, 0xce, 0xb7, 0x02, 0x01, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x95, 0xbb, 0xac, + 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x37, 0x42, 0x95, 0x33, + 0xa2, 0x34, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x2d, 0x9c, 0x01, 0x94, 0x2c, 0x9c, 0x02, + 0x94, 0x2b, 0x9c, 0x03, 0x94, 0x2a, 0x9c, 0x04, 0x94, 0x5b, 0x9c, 0x05, 0x94, 0xcb, + 0x9c, 0x06, 0x94, 0xca, 0x9c, 0x07, 0xb4, 0x01, 0x65, 0x9c, 0x08, 0xb4, 0x01, 0xc1, + 0x9c, 0x09, 0xb4, 0x01, 0xec, 0x9c, 0x0a, 0xb4, 0x02, 0x4d, 0x3c, 0xb4, 0xfc, 0x96, + 0xb4, 0xfc, 0x93, 0xb4, 0xfc, 0x90, 0xac, 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, + 0x01, 0x37, 0x85, 0x4c, 0x90, 0x02, 0x37, 0x8a, 0x94, 0x20, 0x90, 0x00, 0x4a, 0x90, + 0x03, 0x47, 0x90, 0x02, 0x37, 0x96, 0x67, 0x90, 0x02, 0xa2, 0x28, 0xce, 0x8b, 0xa2, + 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x0d, 0xb5, 0xd8, 0xf9, 0xb4, 0xfc, 0x5e, + 0x90, 0x01, 0x75, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x5c, 0xac, 0xce, 0xcc, 0x82, + 0x44, 0xcc, 0xf8, 0x90, 0x03, 0x37, 0xc1, 0x94, 0x30, 0xac, 0xce, 0xcc, 0x82, 0x46, + 0xcc, 0xf8, 0x90, 0x03, 0x37, 0xce, 0x94, 0x23, 0x94, 0x4e, 0xa2, 0x28, 0xce, 0x88, + 0x9c, 0x03, 0x42, 0x95, 0x23, 0x90, 0x01, 0xa2, 0x2a, 0xce, 0x8b, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3f, 0xb5, 0xd8, 0xb5, 0xb4, 0xfc, 0x1a, 0x90, 0x01, + 0x50, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x69, 0xa2, 0x28, 0xce, 0x88, 0x9c, 0x03, + 0x70, 0x90, 0x02, 0xa2, 0x29, 0xce, 0x8b, 0xaf, 0xce, 0xb5, 0xaf, 0x79, 0x3f, 0xce, + 0xa2, 0x3c, 0xce, 0x88, 0x9c, 0x00, 0x48, 0x90, 0x03, 0xa2, 0x2a, 0xce, 0x8b, 0x95, + 0x3a, 0x90, 0x00, 0x68, 0x90, 0x02, 0x6b, 0xb4, 0xfb, 0xe4, 0xac, 0xce, 0xcc, 0x82, + 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0xcc, 0x94, 0x48, 0xac, 0xce, 0xcc, 0x82, + 0x46, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0xbe, 0x94, 0x3a, 0xac, 0xce, 0xcc, 0x82, + 0x44, 0xcc, 0xf8, 0x90, 0x05, 0xb5, 0xfb, 0xb0, 0x5d, 0xac, 0xce, 0xcc, 0x82, 0x46, + 0xcc, 0xf8, 0x90, 0x05, 0xb5, 0xfb, 0xa3, 0x50, 0xb0, 0x2b, 0xc4, 0xa2, 0x24, 0xce, + 0xab, 0x90, 0x01, 0xa2, 0x26, 0xce, 0xab, 0xb4, 0xfb, 0x9e, 0xb0, 0xe6, 0x59, 0xa2, + 0x24, 0xce, 0xab, 0x90, 0x0b, 0xa2, 0x26, 0xce, 0xab, 0xb4, 0xfb, 0x8e, 0xac, 0xce, + 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0x76, 0x94, 0x23, 0xac, 0xce, + 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0x68, 0x90, 0x05, 0xb5, 0xfb, + 0x63, 0x59, 0x40, 0xb0, 0x35, 0x20, 0xa2, 0x24, 0xce, 0xab, 0x90, 0x77, 0xa2, 0x26, + 0xce, 0xab, 0xb4, 0xfb, 0x5d, 0x90, 0x05, 0xb5, 0xfb, 0x4c, 0x42, 0x95, 0x29, 0xb0, + 0x12, 0x60, 0xa2, 0x24, 0xce, 0xab, 0xb0, 0x04, 0xa8, 0xa2, 0x26, 0xce, 0xab, 0xb4, + 0xfb, 0x44, 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x94, 0x0f, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, + 0x90, 0x06, 0xb5, 0xfb, 0x19, 0x41, 0x53, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x01, + 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x93, 0xee, 0xaf, 0xce, + 0xb7, 0x05, 0x03, 0x44, 0xb7, 0x00, 0x00, 0x48, 0xb7, 0x00, 0x00, 0x4a, 0xa2, 0x22, + 0xce, 0x88, 0xab, 0x46, 0xb5, 0x98, 0xca, 0x3f, 0xce, 0xa2, 0x50, 0xce, 0xa8, 0x9a, + 0x20, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc1, 0xe6, 0x90, 0x01, 0xa2, 0x38, 0xce, 0x8b, + 0x3c, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x07, 0xb5, 0xfa, 0xcb, 0x50, + 0xac, 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, 0x07, 0xb5, 0xfa, 0xbe, 0x43, 0xb4, + 0xfa, 0xc6, 0xb7, 0x02, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, + 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x93, 0x91, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, + 0x90, 0x08, 0xb5, 0xfa, 0x9b, 0x50, 0xac, 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, + 0x08, 0xb5, 0xfa, 0x8e, 0x43, 0xb4, 0xfa, 0x96, 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, + 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x93, 0x61, 0xac, + 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x08, 0xb5, 0xfa, 0x6b, 0x54, 0xa2, 0x50, + 0xce, 0xa8, 0x9a, 0x20, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc1, 0x65, 0x90, 0x01, 0xa2, + 0x38, 0xce, 0x8b, 0x3c, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, + 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x93, 0x2d, 0x95, 0x27, 0xa2, 0x22, 0xce, + 0x88, 0xab, 0x18, 0xb0, 0x40, 0x0f, 0xb5, 0xd6, 0xd9, 0xb7, 0x02, 0x07, 0x02, 0xb7, + 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x93, 0x0c, + 0x00, 0x00 +}; + +#endif /* !(_PTIFDDI_ASM_H) */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/scc.c linux/drivers/net/scc.c --- v2.1.66/linux/drivers/net/scc.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/scc.c Sat Nov 29 10:33:20 1997 @@ -1590,11 +1590,6 @@ memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); dev->flags = 0; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; dev->type = ARPHRD_AX25; dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; diff -u --recursive --new-file v2.1.66/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.1.66/linux/drivers/net/sdla.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/sdla.c Sat Nov 29 10:33:20 1997 @@ -1293,7 +1293,6 @@ { case ARPHRD_FRAD: dev->type = ifr->ifr_flags; - dev->family = AF_UNSPEC; break; default: return(-ENOPROTOOPT); @@ -1643,12 +1642,6 @@ dev->change_mtu = sdla_change_mtu; dev->type = 0xFFFF; - dev->family = AF_UNSPEC; - dev->pa_alen = 0; - dev->pa_addr = 0; - dev->pa_dstaddr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = SDLA_MAX_MTU; diff -u --recursive --new-file v2.1.66/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.66/linux/drivers/net/sdla_fr.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/sdla_fr.c Sat Nov 29 10:33:20 1997 @@ -78,37 +78,35 @@ /****** Defines & Macros ****************************************************/ -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#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 FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ /* Q.922 frame types */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* ??? */ /****** 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; /* logical channel number */ - unsigned cir; /* committed information rate */ - char state; /* channel state */ +typedef struct fr_channel { + char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + char state; /* channel state */ unsigned long state_tick; /* time of the last state change */ - sdla_t* card; /* -> owner */ - struct enet_statistics ifstats; /* interface statistics */ + sdla_t *card; /* -> owner */ + struct enet_statistics ifstats; /* interface statistics */ } fr_channel_t; -typedef struct dlci_status -{ - unsigned short dlci PACKED; - unsigned char state PACKED; +typedef struct dlci_status { + unsigned short dlci PACKED; + unsigned char state PACKED; } dlci_status_t; static char TracingEnabled; @@ -117,60 +115,60 @@ /****** 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); +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_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); +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); /* 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); +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 wpf_poll(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_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_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); /* 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); -static unsigned int dec_to_uint (unsigned char* str, int len); +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); +static unsigned int dec_to_uint(unsigned char *str, int len); /****** Public Functions ****************************************************/ @@ -186,36 +184,31 @@ * Return: 0 o.k. * < 0 failure. */ -__initfunc(int wpf_init (sdla_t* card, wandev_conf_t* conf)) +__initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf)) { - union - { + union { char str[80]; fr_conf_t cfg; } u; /* 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) - { + 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->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; 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; @@ -230,10 +223,9 @@ */ 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); @@ -241,93 +233,83 @@ /* Configure adapter firmware */ memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.mtu = conf->mtu; - u.cfg.t391 = 10; - u.cfg.t392 = 15; - u.cfg.n391 = 6; - u.cfg.n392 = 3; - u.cfg.n393 = 4; - u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = 16; + u.cfg.mtu = conf->mtu; + u.cfg.t391 = 10; + u.cfg.t392 = 15; + u.cfg.n391 = 6; + u.cfg.n392 = 3; + u.cfg.n393 = 4; + u.cfg.kbps = conf->bps / 1000; + u.cfg.cir_fwd = 16; u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd; - u.cfg.options = 0x0081; /* direct Rx, no CIR check */ - switch (conf->u.fr.signalling) - { - case WANOPT_FR_Q933: u.cfg.options |= 0x0200; break; - case WANOPT_FR_LMI: u.cfg.options |= 0x0400; break; + u.cfg.options = 0x0081; /* direct Rx, no CIR check */ + switch (conf->u.fr.signalling) { + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; + break; + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; + break; } - if (conf->station == WANOPT_CPE) - { + if (conf->station == WANOPT_CPE) { u.cfg.options |= 0x8000; /* auto config DLCI */ - } - else - { + } else { u.cfg.station = 1; /* switch emulation mode */ card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16; - card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); } 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) - ; + u.cfg.t391 = min(conf->u.fr.t391, 30); if (conf->u.fr.t392) - u.cfg.t392 = min(conf->u.fr.t392, 30) - ; + u.cfg.t392 = min(conf->u.fr.t392, 30); if (conf->u.fr.n391) - u.cfg.n391 = min(conf->u.fr.n391, 255) - ; + u.cfg.n391 = min(conf->u.fr.n391, 255); if (conf->u.fr.n392) - u.cfg.n392 = min(conf->u.fr.n392, 10) - ; + u.cfg.n392 = min(conf->u.fr.n392, 10); if (conf->u.fr.n393) - u.cfg.n393 = min(conf->u.fr.n393, 10) - ; + u.cfg.n393 = min(conf->u.fr.n393, 10); 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) - ; + 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) - ; + (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) - ; + (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) - ; + (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.udp_port = conf->udp_port; - TracingEnabled = '0'; - return 0; + 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.udp_port = conf->udp_port; + TracingEnabled = '0'; + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -335,20 +317,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); @@ -368,61 +350,48 @@ * 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 - { + } else { printk(KERN_ERR - "%s: invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name) - ; + "%s: invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name); err = -EINVAL; } - } - else - { + } else { printk(KERN_ERR - "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + if (err) { kfree(chan); return err; } - /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; @@ -433,10 +402,9 @@ /*============================================================================ * 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; } @@ -448,21 +416,20 @@ /*============================================================================ * 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))) + 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 (copy_from_user((void *) &mbox->data, u_data, cmd.length)) return -EFAULT; if (sdla_exec(mbox)) err = mbox->cmd.result; @@ -472,10 +439,10 @@ while (err && retry-- && fr_event(card, err, mbox)); /* return result */ - if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) + 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; } @@ -489,43 +456,42 @@ * 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; int i; /* 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->family = AF_INET; /* address family */ - 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->family = AF_INET; /* address family */ + 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); /* Initialize hardware parameters (just for reference) */ - 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 = 30; - + 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 = 30; + /* Initialize socket buffers */ for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]) - ; + skb_queue_head_init(&dev->buffs[i]); set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -537,41 +503,34 @@ * * 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; + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; 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->open_cnt) - { + if (!card->open_cnt) { if ((fr_comm_enable(card)) || - (fr_set_intr_mode(card, 0x03, card->wandev.mtu))) - { + (fr_set_intr_mode(card, 0x03, card->wandev.mtu))) { err = -EIO; goto done; } wanpipe_set_state(card, WAN_CONNECTED); - if (card->wandev.station == WANOPT_CPE) - { + if (card->wandev.station == WANOPT_CPE) { /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); - } - else /* FR switch: activate DLCI(s) */ - { + } else { /* FR switch: activate DLCI(s) */ fr_add_dlci(card, - card->u.f.node_dlci, card->u.f.dlci_num) - ; + card->u.f.node_dlci, card->u.f.dlci_num); fr_activate_dlci(card, - card->u.f.node_dlci, card->u.f.dlci_num) - ; + card->u.f.node_dlci, card->u.f.dlci_num); } } dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); @@ -581,7 +540,7 @@ wanpipe_open(card); update_chan_state(dev); -done: + done: card->wandev.critical = 0; return err; } @@ -591,18 +550,17 @@ * 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; + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->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); - if (!card->open_cnt) - { + if (!card->open_cnt) { wanpipe_set_state(card, WAN_DISCONNECTED); fr_set_intr_mode(card, 0, 0); fr_comm_disable(card); @@ -621,15 +579,14 @@ * * 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 = wan_encapsulate(skb, dev); - if (hdr_len < 0) - { + if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } @@ -645,14 +602,13 @@ * 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) { - fr_channel_t* chan = skb->dev->priv; - sdla_t* card = chan->card; + fr_channel_t *chan = skb->dev->priv; + sdla_t *card = chan->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, skb->dev->name) - ; + card->devname, skb->dev->name); return 1; } @@ -674,84 +630,62 @@ * 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; + int retry = 0, err; struct device *dev2; - - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + + if (test_and_set_bit(0, (void *) &card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", - card->devname) - ; + card->devname); #endif dev_kfree_skb(skb, FREE_WRITE); return 0; } - - if (test_and_set_bit(0, (void*)&dev->tbusy)) - { + if (test_and_set_bit(0, (void *) &dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", - card->devname, dev->name) - ; + card->devname, dev->name); #endif ++chan->ifstats.collisions; ++card->wandev.stats.collisions; retry = 1; - if(card->wandev.tx_int_enabled) - { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - dev2->tbusy = 1; - } + if (card->wandev.tx_int_enabled) { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + dev2->tbusy = 1; + } } - } - else if (card->wandev.state != WAN_CONNECTED) - { + } else if (card->wandev.state != WAN_CONNECTED) { ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } - else if (chan->state != WAN_CONNECTED) - { + } else if (chan->state != WAN_CONNECTED) { update_chan_state(dev); ++chan->ifstats.tx_dropped; ++card->wandev.stats.tx_dropped; - } - else if (!is_tx_ready(card)) - { + } else if (!is_tx_ready(card)) { retry = 1; - if(card->wandev.tx_int_enabled) - { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - dev2->tbusy = 1; - } + if (card->wandev.tx_int_enabled) { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { + dev2->tbusy = 1; + } } - } - else - { - 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) - { + } else { + 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) { ++chan->ifstats.tx_errors; ++card->wandev.stats.tx_errors; - } - else - { + } else { ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; } } - if (!retry) - { + if (!retry) { dev_kfree_skb(skb, FREE_WRITE); dev->tbusy = 0; } @@ -764,9 +698,9 @@ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ -static struct enet_statistics* if_stats (struct device* dev) +static struct enet_statistics *if_stats(struct device *dev) { - fr_channel_t* chan = dev->priv; + fr_channel_t *chan = dev->priv; return &chan->ifstats; } @@ -776,17 +710,16 @@ /*============================================================================ * S502 frame relay interrupt service routine. */ -static void fr502_isr (sdla_t* card) +static void fr502_isr(sdla_t * card) { - fr502_flags_t* flags = card->flags; + fr502_flags_t *flags = card->flags; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ + switch (flags->iflag) { + case 0x01: /* receive interrupt */ fr502_rx_intr(card); break; - case 0x02: /* transmit interrupt */ + case 0x02: /* transmit interrupt */ flags->imask &= ~0x02; tx_intr(card); break; @@ -800,28 +733,26 @@ /*============================================================================ * 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; - - if(int_occur){ + fr508_flags_t *flags = card->flags; + fr_buf_ctl_t *bctl; + + if (int_occur) { #ifdef _DEBUG_ - printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n",card->devname); + printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n", card->devname); #endif return; } - int_occur=1; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ + int_occur = 1; + switch (flags->iflag) { + case 0x01: /* receive interrupt */ fr508_rx_intr(card); break; - case 0x02: /* transmit interrupt */ - bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase) - ; + case 0x02: /* transmit interrupt */ + bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); bctl->flag = 0x90; /* disable further Tx interrupts */ tx_intr(card); break; @@ -836,48 +767,41 @@ /*============================================================================ * Receive interrupt handler. */ -static void fr502_rx_intr (sdla_t* card) +static void fr502_rx_intr(sdla_t * card) { - fr_mbox_t* mbox = card->rxmb; + fr_mbox_t *mbox = card->rxmb; struct sk_buff *skb; struct device *dev; fr_channel_t *chan; unsigned dlci, len; - void* buf; - + void *buf; + sdla_mapmem(&card->hw, FR502_RX_VECTOR); dlci = mbox->cmd.dlci; - len = mbox->cmd.length; + len = mbox->cmd.length; /* Find network interface for this packet */ dev = find_channel(card, dlci); - if (dev == NULL) - { + if (dev == NULL) { /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci) - ; + card->devname, dlci); goto rx_done; } chan = dev->priv; - if (!dev->start) - { + if (!dev->start) { ++chan->ifstats.rx_dropped; goto rx_done; } - /* Allocate socket buffer */ skb = dev_alloc_skb(len); - if (skb == NULL) - { + if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname) - ; + card->devname); ++chan->ifstats.rx_dropped; goto rx_done; } - /* Copy data to the socket buffer */ buf = skb_put(skb, len); memcpy(buf, mbox->data, len); @@ -886,77 +810,64 @@ /* Decapsulate packet and pass it up the protocol stack */ skb->dev = dev; buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wan_type_trans(skb, dev)) - { + if (!wan_type_trans(skb, dev)) { /* can't decapsulate packet */ dev_kfree_skb(skb, FREE_READ); ++chan->ifstats.rx_errors; ++card->wandev.stats.rx_errors; - } - else - { + } else { netif_rx(skb); ++chan->ifstats.rx_packets; ++card->wandev.stats.rx_packets; } -rx_done: + rx_done: sdla_mapmem(&card->hw, FR_MB_VECTOR); } /*============================================================================ * Receive interrupt handler. */ -static void fr508_rx_intr (sdla_t* card) +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; + fr_buf_ctl_t *frbuf = card->rxmb; + struct sk_buff *skb; + struct device *dev; + fr_channel_t *chan; unsigned dlci, len, offs; - void* buf; - - if (frbuf->flag != 0x01) - { + void *buf; + + if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", - card->devname, (unsigned)frbuf) - ; + card->devname, (unsigned) frbuf); return; } - len = frbuf->length; + len = frbuf->length; dlci = frbuf->dlci; offs = frbuf->offset; /* Find network interface for this packet */ dev = find_channel(card, dlci); - if (dev == NULL) - { + if (dev == NULL) { /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci) - ; + card->devname, dlci); goto rx_done; } chan = dev->priv; - if (!dev->start) - { + if (!dev->start) { ++chan->ifstats.rx_dropped; goto rx_done; } - /* Allocate socket buffer */ skb = dev_alloc_skb(len); - if (skb == NULL) - { + if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname) - ; + card->devname); ++chan->ifstats.rx_dropped; goto rx_done; } - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) - { + if ((offs + len) > card->u.f.rx_top + 1) { unsigned tmp = card->u.f.rx_top - offs + 1; buf = skb_put(skb, tmp); @@ -965,30 +876,27 @@ len -= tmp; } buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); + sdla_peek(&card->hw, offs, buf, len); /* Decapsulate packet and pass it up the protocol stack */ skb->dev = dev; buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wan_type_trans(skb, dev)) - { + if (!wan_type_trans(skb, dev)) { /* can't decapsulate packet */ dev_kfree_skb(skb, FREE_READ); ++chan->ifstats.rx_errors; ++card->wandev.stats.rx_errors; - } - else - { + } else { netif_rx(skb); ++chan->ifstats.rx_packets; ++card->wandev.stats.rx_packets; } -rx_done: + rx_done: /* 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) + if ((void *) frbuf > card->u.f.rxmb_last) card->rxmb = card->u.f.rxmb_base - ; + ; } /*============================================================================ @@ -997,19 +905,23 @@ * o * If number of spurious interrupts exceeded some limit, then ??? */ -static void tx_intr (sdla_t* card) +static void tx_intr(sdla_t * card) { - struct device* dev = card->wandev.dev; + struct device *dev = card->wandev.dev; + int v = 0; - for (; dev; dev = dev->slave) { - if( !dev || !dev->start ) continue; - dev->tbusy = 0; - dev_tint(dev); - } - card->wandev.tx_int_enabled = 0; + for (; dev; dev = dev->slave) { + if (!dev || !dev->start) + continue; + v += dev->tbusy; + dev->tbusy = 0; + } + card->wandev.tx_int_enabled = 0; + if (v) + mark_bh(NET_BH); /* - printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); -*/ + printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); + */ } /*============================================================================ @@ -1018,7 +930,7 @@ * 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); } @@ -1036,25 +948,25 @@ * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ -static void wpf_poll (sdla_t* card) +static void wpf_poll(sdla_t * card) { static unsigned long last_poll; - fr502_flags_t* flags; + fr502_flags_t *flags; if ((jiffies - last_poll) < HZ) return - ; + ; flags = card->flags; - if (flags->event) - { - fr_mbox_t* mbox = card->mbox; + 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); + if (err) + fr_event(card, err, mbox); } last_poll = jiffies; } @@ -1065,25 +977,23 @@ * 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; } @@ -1091,25 +1001,24 @@ /*============================================================================ * 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 = card->u.f.node_dlci; 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] = dlci + i - ; + if (dlci_num) + for (i = 0; i < dlci_num; ++i) + ((fr_conf_t *) mbox->data)->dlci[i] = 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)); @@ -1119,32 +1028,28 @@ /*============================================================================ * 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) { - 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)); - if (card->hw.fwid == SFID_FR502) - { - fr502_intr_ctl_t* ictl = (void*)mbox->data; + 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->mode = mode; ictl->tx_len = mtu; mbox->cmd.length = sizeof(fr502_intr_ctl_t); - } - else - { - fr508_intr_ctl_t* ictl = (void*)mbox->data; + } else { + fr508_intr_ctl_t *ictl = (void *) mbox->data; memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; + ictl->mode = mode; ictl->tx_len = mtu; - ictl->irq = card->hw.irq; + ictl->irq = card->hw.irq; mbox->cmd.length = sizeof(fr508_intr_ctl_t); } mbox->cmd.command = FR_SET_INTR_MODE; @@ -1157,14 +1062,13 @@ /*============================================================================ * 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; @@ -1176,14 +1080,13 @@ /*============================================================================ * 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 - { + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_DISABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1195,28 +1098,26 @@ /*============================================================================ * 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 - { + 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; + 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; @@ -1225,28 +1126,26 @@ /*============================================================================ * 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; + 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 - ; + stats->rx_dropped + stats->rx_dropped2 + ; } return err; } @@ -1254,21 +1153,20 @@ /*============================================================================ * Add DLCI(s) (Access Node only!). */ -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 - { - unsigned short* dlci_list = (void*)mbox->data; + do { + unsigned short *dlci_list = (void *) mbox->data; memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); for (i = 0; i < num; ++i) dlci_list[i] = 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; } @@ -1279,21 +1177,20 @@ /*============================================================================ * Activate DLCI(s) (Access Node only!). */ -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; + do { + unsigned short *dlci_list = (void *) mbox->data; memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); for (i = 0; i < num; ++i) dlci_list[i] = 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; } @@ -1304,17 +1201,16 @@ /*============================================================================ * 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 - { + 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; } @@ -1325,19 +1221,18 @@ /*============================================================================ * Send a frame (S502 version). */ -static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf) +static int fr502_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 - { + 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.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; mbox->cmd.command = FR_WRITE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } @@ -1348,28 +1243,25 @@ /*============================================================================ * 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 - { + 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) - ; + if (!err) { + fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); unsigned long flags; save_flags(flags); @@ -1390,10 +1282,9 @@ * * 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) { - switch (event) - { + switch (event) { case FRRES_MODEM_FAILURE: return fr_modem_failure(card, mbox); @@ -1414,14 +1305,12 @@ case CMD_TIMEOUT: printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command) - ; + card->devname, mbox->cmd.command); 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; } @@ -1431,13 +1320,11 @@ * * 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; @@ -1450,35 +1337,27 @@ * * 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); - for (; cnt; --cnt, ++status) - { + for (; cnt; --cnt, ++status) { unsigned short dlci = status->dlci; - struct device* dev = find_channel(card, dlci); + struct device *dev = find_channel(card, dlci); - if (status->state & 0x01) - { + if (status->state & 0x01) { printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci) - ; + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); if (dev && dev->start) - set_chan_state(dev, WAN_DISCONNECTED) - ; - } - else if (status->state & 0x02) - { + set_chan_state(dev, WAN_DISCONNECTED); + } else if (status->state & 0x02) { printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci) - ; + "%s: DLCI %u becomes active!\n", + card->devname, dlci); if (dev && dev->start) - set_chan_state(dev, WAN_CONNECTED) - ; + set_chan_state(dev, WAN_CONNECTED); } } return 1; @@ -1489,32 +1368,28 @@ /*============================================================================ * 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; - 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)); - 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) - { - set_chan_state(dev, WAN_CONNECTED); + for (; cnt; --cnt, ++list) { + if (*list == chan->dlci) { + set_chan_state(dev, WAN_CONNECTED); break; } } @@ -1525,34 +1400,29 @@ /*============================================================================ * 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) - ; + printk(KERN_INFO "%s: interface %s connected!\n", + 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; @@ -1564,13 +1434,14 @@ /*============================================================================ * 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) break - ; + if (((fr_channel_t *) dev->priv)->dlci == dlci) + break + ; return dev; } @@ -1581,22 +1452,21 @@ * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ -static int is_tx_ready (sdla_t* card) +static int is_tx_ready(sdla_t * card) { - if (card->hw.fwid == SFID_FR508) - { - fr508_flags_t* flags = card->flags; + if (card->hw.fwid == SFID_FR508) { + fr508_flags_t *flags = card->flags; unsigned char sb = inb(card->hw.port); - if (sb & 0x02) return 1; + if (sb & 0x02) + return 1; flags->imask |= 0x02; - card->wandev.tx_int_enabled = 1; - } - else - { - fr502_flags_t* flags = card->flags; + card->wandev.tx_int_enabled = 1; + } else { + fr502_flags_t *flags = card->flags; - if (flags->tx_ready) return 1; + if (flags->tx_ready) + return 1; flags->imask |= 0x02; } return 0; @@ -1606,14 +1476,14 @@ * 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) len = strlen(str); + 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; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.66/linux/drivers/net/sdla_ppp.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/sdla_ppp.c Sat Nov 29 10:33:20 1997 @@ -49,7 +49,7 @@ #include #define _GNUC_ -#include /* PPP firmware API definitions */ +#include /* PPP firmware API definitions */ /****** Defines & Macros ****************************************************/ @@ -59,63 +59,63 @@ #define STATIC static #endif -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ +#define CMD_OK 0 /* normal firmware return code */ +#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#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 */ /****** 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_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); +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); /* 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_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); +static void tx_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 void show_disc_cause (sdla_t* card, unsigned cause); -static unsigned char bps_to_speed_code (unsigned long bps); +static int config502(sdla_t * card); +static int config508(sdla_t * card); +static void show_disc_cause(sdla_t * card, unsigned cause); +static unsigned char bps_to_speed_code(unsigned long bps); static char TracingEnabled; /****** Public Functions ****************************************************/ @@ -132,33 +132,28 @@ * Return: 0 o.k. * < 0 failure. */ -__initfunc(int wpp_init (sdla_t* card, wandev_conf_t* conf)) +__initfunc(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) - { + 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) - { + 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); + 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); + card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); + card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); break; default: @@ -172,28 +167,27 @@ */ 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) - ; + 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; - TracingEnabled = '0'; + 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; + TracingEnabled = '0'; return 0; } @@ -202,20 +196,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; ppp_get_err_stats(card); @@ -235,21 +229,18 @@ * 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; + sdla_t *card = wandev->private; if (wandev->ndev) return -EEXIST - ; - 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; } - /* initialize data */ strcpy(card->u.p.if_name, conf->name); @@ -263,7 +254,7 @@ /*============================================================================ * 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) { return 0; } @@ -273,30 +264,28 @@ /*============================================================================ * Execute adapter interface command. */ -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) { - ppp_mbox_t* mbox = card->mbox; + 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 (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)) - return -EFAULT; + if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + return -EFAULT; return 0; } @@ -309,40 +298,39 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init (struct device* dev) +static int if_init(struct device *dev) { - sdla_t* card = dev->priv; - wan_device_t* wandev = &card->wandev; + sdla_t *card = dev->priv; + wan_device_t *wandev = &card->wandev; int i; /* 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->family = AF_INET; /* address family */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + dev->family = AF_INET; /* address family */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + 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 = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 30; - + 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 = 30; + /* Initialize socket buffers */ for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]) - ; + skb_queue_head_init(&dev->buffs[i]); return 0; } @@ -353,69 +341,53 @@ * * Return 0 if O.k. or errno. */ -static int if_open (struct device* dev) +static int if_open(struct device *dev) { - sdla_t* card = dev->priv; + sdla_t *card = dev->priv; 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 ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { err = -EIO; goto split; } - /* Initialize Rx/Tx buffer control fields */ - 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) - ; - } - 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) - ; + 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); + } 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); 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; - if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card)) - { + if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card)) { err = -EIO; goto split; } @@ -426,7 +398,7 @@ dev->tbusy = 0; dev->start = 1; -split: + split: card->wandev.critical = 0; return err; } @@ -436,11 +408,11 @@ * 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) { - sdla_t* card = dev->priv; + sdla_t *card = dev->priv; - 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; @@ -461,11 +433,10 @@ * * 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) { - switch (type) - { + switch (type) { case ETH_P_IP: case ETH_P_IPX: skb->protocol = type; @@ -483,13 +454,12 @@ * 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) { - sdla_t* card = skb->dev->priv; + sdla_t *card = skb->dev->priv; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, skb->dev->name) - ; + card->devname, skb->dev->name); return 1; } @@ -510,47 +480,40 @@ * 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) { - sdla_t* card = dev->priv; + sdla_t *card = dev->priv; int retry = 0; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + if (test_and_set_bit(0, (void *) &card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", - card->devname) - ; + card->devname); #endif return 1; } - - if (test_and_set_bit(0, (void*)&dev->tbusy)) - { + if (test_and_set_bit(0, (void *) &dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", - card->devname, dev->name) - ; + card->devname, dev->name); #endif ++card->wandev.stats.collisions; retry = 1; } else if (card->wandev.state != WAN_CONNECTED) ++card->wandev.stats.tx_dropped - ; + ; else if (!skb->protocol) ++card->wandev.stats.tx_errors - ; - else if (ppp_send(card, skb->data, skb->len, skb->protocol)) - { - ppp_flags_t* flags = card->flags; + ; + else if (ppp_send(card, skb->data, skb->len, skb->protocol)) { + ppp_flags_t *flags = card->flags; flags->imask |= 0x02; /* unmask Tx interrupts */ retry = 1; - } - else ++card->wandev.stats.tx_packets; + } else + ++card->wandev.stats.tx_packets; - if (!retry) - { + if (!retry) { dev_kfree_skb(skb, FREE_WRITE); dev->tbusy = 0; } @@ -563,9 +526,9 @@ * Return a pointer to struct enet_statistics. */ -static struct enet_statistics* if_stats (struct device* dev) +static struct enet_statistics *if_stats(struct device *dev) { - sdla_t* card = dev->priv; + sdla_t *card = dev->priv; return &card->wandev.stats; } @@ -576,17 +539,17 @@ * 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; + 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) - { + if (err != CMD_OK) + ppp_error(card, err, mb); + else if (str) { int len = mb->cmd.length; memcpy(str, mb->data, len); @@ -598,37 +561,36 @@ /*============================================================================ * Configure PPP firmware. */ -static int ppp_configure (sdla_t* card, void* data) +static int ppp_configure(sdla_t * card, void *data) { - ppp_mbox_t* mb = card->mbox; + ppp_mbox_t *mb = card->mbox; int data_len = (card->hw.fwid == SFID_PPP502) ? - sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t) - ; + 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.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); + 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) +static int ppp_set_intr_mode(sdla_t * card, unsigned mode) { - ppp_mbox_t* mb = card->mbox; + ppp_mbox_t *mb = card->mbox; int err; memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->data[0] = mode; - switch (card->hw.fwid) - { + switch (card->hw.fwid) { case SFID_PPP502: - mb->cmd.length = 1; + mb->cmd.length = 1; break; case SFID_PPP508: @@ -638,62 +600,64 @@ } mb->cmd.command = PPP_SET_INTR_FLAGS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) ppp_error(card, err, mb); + 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; + 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) ppp_error(card, err, mb); + 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; + 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) ppp_error(card, err, mb); + 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; + 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; + 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; card->wandev.stats.tx_aborted_errors = stats->tx_abort; - } - else ppp_error(card, err, mb); + } else + ppp_error(card, err, mb); return err; } @@ -702,34 +666,34 @@ * 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; + ppp_buf_ctl_t *txbuf = card->u.p.txbuf; unsigned long addr, cpu_flags; if (txbuf->flag) return 1 - ; + ; if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0] - ; - else addr = txbuf->buf.ptr; + addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; + else + addr = txbuf->buf.ptr; save_flags(cpu_flags); cli(); sdla_poke(&card->hw, addr, data, len); restore_flags(cpu_flags); - txbuf->length = len; /* frame length */ + txbuf->length = len; /* frame length */ if (proto == ETH_P_IPX) txbuf->proto = 0x01 /* protocol ID */ - ; - txbuf->flag = 1; /* start transmission */ + ; + 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; } @@ -742,22 +706,19 @@ * * 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) - { + switch (err) { case CMD_TIMEOUT: printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd) - ; + card->devname, cmd); break; default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err) - ; + card->devname, cmd, err); } return 0; } @@ -767,25 +728,23 @@ /*============================================================================ * PPP interrupt service routine. */ -STATIC void wpp_isr (sdla_t* card) +STATIC void wpp_isr(sdla_t * card) { - ppp_flags_t* flags = card->flags; + ppp_flags_t *flags = card->flags; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ + switch (flags->iflag) { + case 0x01: /* receive interrupt */ rx_intr(card); break; - case 0x02: /* transmit interrupt */ + case 0x02: /* transmit interrupt */ flags->imask &= ~0x02; tx_intr(card); break; - default: /* unexpected interrupt */ + default: /* unexpected interrupt */ printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag) - ; + card->devname, flags->iflag); } flags->iflag = 0; } @@ -793,52 +752,42 @@ /*============================================================================ * 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; - struct sk_buff* skb; + ppp_buf_ctl_t *rxbuf = card->rxmb; + struct device *dev = card->wandev.dev; + struct sk_buff *skb; unsigned len; - void* buf; - - if (rxbuf->flag != 0x01) - { + void *buf; + + if (rxbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", - card->devname, (unsigned)rxbuf) - ; + card->devname, (unsigned) rxbuf); return; } - if (!dev || !dev->start) goto rx_done - ; - len = rxbuf->length; + ; + len = rxbuf->length; /* Allocate socket buffer */ skb = dev_alloc_skb(len); - if (skb == NULL) - { + if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname) - ; + card->devname); ++card->wandev.stats.rx_dropped; goto rx_done; } - /* 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]; + if (card->hw.fwid == SFID_PPP502) { + 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 - { + } else { unsigned addr = rxbuf->buf.ptr; - if ((addr + len) > card->u.p.rx_top + 1) - { + if ((addr + len) > card->u.p.rx_top + 1) { unsigned tmp = card->u.p.rx_top - addr + 1; buf = skb_put(skb, tmp); @@ -851,8 +800,7 @@ } /* Decapsulate packet */ - switch (rxbuf->proto) - { + switch (rxbuf->proto) { case 0x00: skb->protocol = htons(ETH_P_IP); break; @@ -866,27 +814,26 @@ skb->dev = dev; netif_rx(skb); ++card->wandev.stats.rx_packets; -rx_done: + rx_done: /* 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) +static void tx_intr(sdla_t * card) { - struct device* dev = card->wandev.dev; + struct device *dev = card->wandev.dev; if (!dev || !dev->start) - return - ; + return; dev->tbusy = 0; - dev_tint(dev); + mark_bh(NET_BH); } /****** Background Polling Routines ****************************************/ @@ -900,10 +847,9 @@ * 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) { - switch(card->wandev.state) - { + switch (card->wandev.state) { case WAN_CONNECTED: poll_active(card); break; @@ -921,12 +867,11 @@ /*============================================================================ * Monitor active link phase. */ -static void poll_active (sdla_t* card) +static void poll_active(sdla_t * card) { - ppp_flags_t* flags = card->flags; + ppp_flags_t *flags = card->flags; - if (flags->disc_cause & 0x03) - { + if (flags->disc_cause & 0x03) { wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); } @@ -936,16 +881,13 @@ * 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; + ppp_flags_t *flags = card->flags; - if (flags->lcp_state == 0x09) - { + if (flags->lcp_state == 0x09) { wanpipe_set_state(card, WAN_CONNECTED); - } - else if (flags->disc_cause & 0x03) - { + } else if (flags->disc_cause & 0x03) { wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); } @@ -956,13 +898,12 @@ * 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; + struct device *dev = card->wandev.dev; if (dev && dev->start && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) - { + ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { wanpipe_set_state(card, WAN_CONNECTING); ppp_comm_enable(card); } @@ -973,7 +914,7 @@ /*============================================================================ * Configure S502 adapter. */ -static int config502 (sdla_t* card) +static int config502(sdla_t * card) { ppp502_conf_t cfg; @@ -981,35 +922,34 @@ 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.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; -*/ + 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(sdla_t * card) { ppp508_conf_t cfg; @@ -1018,95 +958,108 @@ 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 = 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 |= 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 = 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.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; -*/ + cfg.ip_local = dev->pa_addr; + cfg.ip_remote = dev->pa_dstaddr; + */ 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) 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) 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) printk(KERN_INFO - "%s: failed to negotiate peer's LCP options\n", - 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) - ; + 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) + 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) + printk(KERN_INFO + "%s: failed to negotiate peer's LCP options\n", + 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); } /*============================================================================ * Convert line speed in bps to a number used by S502 code. */ -static unsigned char bps_to_speed_code (unsigned long bps) +static unsigned char bps_to_speed_code(unsigned long bps) { - unsigned char number; + 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; + 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; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c --- v2.1.66/linux/drivers/net/sgiseeq.c Mon Nov 3 13:04:26 1997 +++ linux/drivers/net/sgiseeq.c Sat Nov 29 10:33:20 1997 @@ -1,4 +1,4 @@ -/* $Id: sgiseeq.c,v 1.1 1997/06/09 08:34:30 ralf Exp $ +/* $Id: sgiseeq.c,v 1.3 1997/11/16 13:57:45 alan Exp $ * sgiseeq.c: Seeq8003 ethernet driver for SGI machines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -507,17 +507,7 @@ sgiseeq_reset(dev); return 0; } - /* Is the skippy buf even reasonable? */ - if(skb == NULL) { - dev_tint(dev); - printk("%s: skb is NULL\n", dev->name); - return -1; - } - if(skb->len <= 0) { - printk("%s: skb len is %ld\n", dev->name, skb->len); - return -1; - } /* Are we getting in someone else's way? */ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); diff -u --recursive --new-file v2.1.66/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.1.66/linux/drivers/net/shaper.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/shaper.c Sat Nov 29 10:33:20 1997 @@ -598,11 +598,6 @@ dev->addr_len = 0; dev->tx_queue_len = 10; dev->flags = 0; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; /* * Shaper is ok diff -u --recursive --new-file v2.1.66/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.1.66/linux/drivers/net/slhc.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/slhc.c Sat Nov 29 10:33:20 1997 @@ -246,6 +246,14 @@ struct iphdr *ip; struct tcphdr *th, *oth; + + /* + * Don't play with runt packets. + */ + + if(isizeihl*4 + th->doff*4; /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or - * some other control bit is set). + * some other control bit is set). Also uncompressible if + * its a runt. */ - if(th->syn || th->fin || th->rst || + if(hlen > isize || th->syn || th->fin || th->rst || ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; @@ -697,7 +706,7 @@ void slhc_i_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%ld Cmp, %ld Uncmp, %ld Bad, %ld Tossed\n", + printk("\t%d Cmp, %d Uncmp, %d Bad, %d Tossed\n", comp->sls_i_compressed, comp->sls_i_uncompressed, comp->sls_i_error, @@ -709,12 +718,12 @@ void slhc_o_status(struct slcompress *comp) { if (comp != NULLSLCOMPR) { - printk("\t%ld Cmp, %ld Uncmp, %ld AsIs, %ld NotTCP\n", + printk("\t%d Cmp, %d Uncmp, %d AsIs, %d NotTCP\n", comp->sls_o_compressed, comp->sls_o_uncompressed, comp->sls_o_tcp, comp->sls_o_nontcp); - printk("\t%10ld Searches, %10ld Misses\n", + printk("\t%10d Searches, %10d Misses\n", comp->sls_o_searches, comp->sls_o_misses); } diff -u --recursive --new-file v2.1.66/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.1.66/linux/drivers/net/slip.c Thu Sep 4 17:07:30 1997 +++ linux/drivers/net/slip.c Sat Nov 29 10:33:20 1997 @@ -589,12 +589,7 @@ sl->outfill_timer.data=(unsigned long)sl; sl->outfill_timer.function=sl_outfill; #endif - /* Needed because address '0' is special */ - if (dev->pa_addr == 0) { - dev->pa_addr=ntohl(0xC0A80001); - } dev->tbusy = 0; -/* dev->flags |= IFF_UP; */ dev->start = 1; return 0; @@ -626,8 +621,6 @@ dev->tbusy = 1; dev->start = 0; -/* dev->flags &= ~IFF_UP; */ - return 0; } @@ -740,7 +733,11 @@ return; } - (void) dev_close(sl->dev); + if (sl->dev->flags & IFF_UP) + { + /* STRONG layering violation! --ANK */ + (void) dev_close(sl->dev); + } tty->disc_data = 0; sl->tty = NULL; @@ -752,7 +749,6 @@ (void)del_timer (&sl->outfill_timer); #endif sl_free(sl); - unregister_netdev(sl->dev); MOD_DEC_USE_COUNT; } @@ -1237,12 +1233,7 @@ dev_init_buffers(dev); /* New-style flags. */ - dev->flags = IFF_NOARP|IFF_MULTICAST; - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; + dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/sonic.c linux/drivers/net/sonic.c --- v2.1.66/linux/drivers/net/sonic.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/sonic.c Sat Nov 29 10:33:20 1997 @@ -390,16 +390,6 @@ dev->trans_start = jiffies; } - /* - * If some higher layer thinks we've missed an tx-done interrupt - * we are passed NULL. Caution: dev_tint() handles the cli()/sti() - * itself. - */ - if (skb == NULL) { - dev_tint(dev); - return 0; - } - /* * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. diff -u --recursive --new-file v2.1.66/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.1.66/linux/drivers/net/strip.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/strip.c Sat Nov 29 10:33:20 1997 @@ -1,3 +1,5 @@ +#warning "will not compile until the networking is merged" +#if 0 /* * Copyright 1996 The Board of Trustees of The Leland Stanford * Junior University. All Rights Reserved. @@ -106,6 +108,7 @@ #include #include #include +#include #include #include #include @@ -1505,16 +1508,18 @@ memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) && *strip_info->dev.broadcast!=0xFF) { + struct in_device *in_dev = strip_info->dev.ip_ptr; /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", strip_info->dev.name, strip_info->arp_interval / HZ);*/ strip_info->gratuitous_arp = jiffies + strip_info->arp_interval; strip_info->arp_interval *= 2; if (strip_info->arp_interval > MaxARPInterval) strip_info->arp_interval = MaxARPInterval; + if (in_dev && in_dev->ifa_list) arp_send(ARPOP_REPLY, ETH_P_ARP, - strip_info->dev.pa_addr, /* Target address of ARP packet is our address */ + in_dev->ifa_list->ifa_address,/* Target address of ARP packet is our address */ &strip_info->dev, /* Device to send packet on */ - strip_info->dev.pa_addr, /* Source IP address this ARP packet comes from */ + in_dev->ifa_list->ifa_address,/* Source IP address this ARP packet comes from */ NULL, /* Destination HW address is NULL (broadcast it) */ strip_info->dev.dev_addr, /* Source HW address is our HW address */ strip_info->dev.dev_addr); /* Target HW address is our HW address (redundant) */ @@ -2430,7 +2435,6 @@ dev->tx_queue_len = 30; /* Drop after 30 frames queued */ dev->flags = 0; - dev->family = AF_INET; dev->metric = 0; dev->mtu = DEFAULT_STRIP_MTU; dev->type = ARPHRD_METRICOM; /* dtang */ @@ -2442,10 +2446,6 @@ *(MetricomAddress*)&dev->broadcast = broadcast_address; dev->dev_addr[0] = 0; dev->addr_len = sizeof(MetricomAddress); - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); /* * Pointer to the interface buffers. @@ -2634,7 +2634,6 @@ if (!strip_info || strip_info->magic != STRIP_MAGIC) return; - dev_close(&strip_info->dev); unregister_netdev(&strip_info->dev); tty->disc_data = 0; @@ -2783,3 +2782,4 @@ printk(KERN_INFO "STRIP: Module Unloaded\n"); } #endif /* MODULE */ +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.66/linux/drivers/net/sunhme.c Thu Sep 4 17:07:31 1997 +++ linux/drivers/net/sunhme.c Sat Nov 29 10:33:20 1997 @@ -974,16 +974,20 @@ /* Because we reserve afterwards. */ skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); +#ifdef CONFIG_PCI if(hp->happy_flags & HFLAG_PCI) { pcihme_write_rxd(&hb->happy_meal_rxd[i], (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), (u32)virt_to_bus((volatile void *)skb->data)); } else { +#endif hb->happy_meal_rxd[i].rx_addr = (u32)((unsigned long) skb->data); hb->happy_meal_rxd[i].rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); +#ifdef CONFIG_PCI } +#endif skb_reserve(skb, RX_OFFSET); } @@ -2301,12 +2305,6 @@ } } - if(skb == NULL || skb->len <= 0) { - printk("%s: skb is NULL\n", dev->name); - dev_tint(dev); - return 0; - } - if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("happy meal: Transmitter access conflict.\n"); return 1; @@ -2547,7 +2545,7 @@ dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; - dev->irq = (unsigned char) sdev->irqs[0].pri; + dev->irq = sdev->irqs[0].pri; dev->dma = 0; ether_setup(dev); #ifdef MODULE diff -u --recursive --new-file v2.1.66/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.1.66/linux/drivers/net/tlan.c Wed Sep 3 20:52:42 1997 +++ linux/drivers/net/tlan.c Wed Nov 26 16:21:54 1997 @@ -27,10 +27,8 @@ #include - #include "tlan.h" - #include #include #include @@ -39,1143 +37,1347 @@ +typedef u32 (TLanIntVectorFunc)( struct device *, u16 ); + #ifdef MODULE - static struct device *TLanDevices = NULL; - static int TLanDevicesInstalled = 0; + +static struct device *TLanDevices = NULL; +static int TLanDevicesInstalled = 0; + #endif - static int debug = 0; - static int aui = 0; - static u8 *TLanPadBuffer; - static char TLanSignature[] = "TLAN"; - static int TLanVersionMajor = 0; - static int TLanVersionMinor = 32; - - static TLanPciId TLanDeviceList[] = { - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10, "Compaq Netelligent 10" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, "Compaq Netelligent 10/100" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, "Compaq Integrated NetFlex-3/P" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P, "Compaq NetFlex-3/P" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3P_BNC, "Compaq NetFlex-3/P w/ BNC" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, "Compaq ProLiant Netelligent 10/100" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, "Compaq Dual Port Netelligent 10/100" }, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_DESKPRO_4000_5233MMX, "Compaq Deskpro 4000 5233MMX" }, - { 0, 0, NULL } /* End of List */ - }; - static int TLan_MiiReadReg(u16, u16, u16, u16 *); - static void TLan_MiiSendData( u16, u32, unsigned ); - static void TLan_MiiSync(u16); - static void TLan_MiiWriteReg(u16, u16, u16, u16); +static int debug = 0; +static int aui = 0; +static u8 *TLanPadBuffer; +static char TLanSignature[] = "TLAN"; +static int TLanVersionMajor = 0; +static int TLanVersionMinor = 38; + + +static TLanPciId TLanDeviceList[] = { + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETELLIGENT_10, + "Compaq Netelligent 10" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETELLIGENT_10_100, + "Compaq Netelligent 10/100" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED, + "Compaq Integrated NetFlex-3/P" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETFLEX_3P, + "Compaq NetFlex-3/P" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETFLEX_3P_BNC, + "Compaq NetFlex-3/P" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, + "Compaq ProLiant Netelligent 10/100" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL, + "Compaq Dual Port Netelligent 10/100" + }, + { PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_DESKPRO_4000_5233MMX, + "Compaq Deskpro 4000 5233MMX" + }, + { 0, + 0, + NULL + } /* End of List */ +}; + + +static int TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * ); +static int TLan_Init( struct device * ); +static int TLan_Open(struct device *dev); +static int TLan_StartTx(struct sk_buff *, struct device *); +static void TLan_HandleInterrupt(int, void *, struct pt_regs *); +static int TLan_Close(struct device *); +static struct net_device_stats *TLan_GetStats( struct device * ); +static void TLan_SetMulticastList( struct device * ); + +static u32 TLan_HandleInvalid( struct device *, u16 ); +static u32 TLan_HandleTxEOF( struct device *, u16 ); +static u32 TLan_HandleStatOverflow( struct device *, u16 ); +static u32 TLan_HandleRxEOF( struct device *, u16 ); +static u32 TLan_HandleDummy( struct device *, u16 ); +static u32 TLan_HandleTxEOC( struct device *, u16 ); +static u32 TLan_HandleStatusCheck( struct device *, u16 ); +static u32 TLan_HandleRxEOC( struct device *, u16 ); + +static void TLan_Timer( unsigned long ); + +static void TLan_ResetLists( struct device * ); +static void TLan_PrintDio( u16 ); +static void TLan_PrintList( TLanList *, char *, int ); +static void TLan_ReadAndClearStats( struct device *, int ); +static int TLan_Reset( struct device * ); +static void TLan_SetMac( struct device *, int areg, char *mac ); + +static int TLan_PhyNop( struct device * ); +static void TLan_PhyPrint( struct device * ); +static void TLan_PhySelect( struct device * ); +static int TLan_PhyInternalCheck( struct device * ); +static int TLan_PhyInternalService( struct device * ); +static int TLan_PhyDp83840aCheck( struct device * ); + +static int TLan_MiiReadReg(u16, u16, u16, u16 *); +static void TLan_MiiSendData( u16, u32, unsigned ); +static void TLan_MiiSync(u16); +static void TLan_MiiWriteReg(u16, u16, u16, u16); + +static void TLan_EeSendStart( u16 ); +static int TLan_EeSendByte( u16, u8, int ); +static void TLan_EeReceiveByte( u16, u8 *, int ); +static int TLan_EeReadByte( u16, u8, u8 * ); + + +static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { + TLan_HandleInvalid, + TLan_HandleTxEOF, + TLan_HandleStatOverflow, + TLan_HandleRxEOF, + TLan_HandleDummy, + TLan_HandleTxEOC, + TLan_HandleStatusCheck, + TLan_HandleRxEOC +}; /***************************************************************************** ****************************************************************************** - ThunderLAN Driver MII Routines + ThunderLAN Driver Primary Functions - These routines are based on the information in Chap. 2 of the - "ThunderLAN Programmer's Guide", pp. 15-24. + These functions are more or less common to all Linux network drivers. ****************************************************************************** *****************************************************************************/ - /************************************************************************* - * TLan_MiiReadReg - * - * Returns: 0 if ack received ok, 1 otherwise. - * Parms: base_port The base IO port of the adapter in question. - * dev The address of the PHY to be queried. - * reg The register whose contents are to be - * retreived. - * val A pointer to a variable to store the retrieved - * value. - * - * This function uses the TLAN's MII bus to retreive the contents of a - * given register on a PHY. It sends the appropriate info and then - * reads the 16-bit register value from the MII bus via the TLAN SIO - * register. - * - ************************************************************************/ - - int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val) - { - u8 nack; - u16 sio, tmp; - u32 i; - int err; - int minten; - - err = FALSE; - outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); - sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - - cli(); - - TLan_MiiSync(base_port); - - minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); - if ( minten ) - TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio); - - TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */ - TLan_MiiSendData( base_port, 0x2, 2 ); /* Read ( 10b ) */ - TLan_MiiSendData( base_port, dev, 5 ); /* Device # */ - TLan_MiiSendData( base_port, reg, 5 ); /* Register # */ - +#ifdef MODULE - TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */ + /*************************************************************** + * init_module + * + * Returns: + * 0 if module installed ok, non-zero if not. + * Parms: + * None + * + * This function begins the setup of the driver creating a + * pad buffer, finding all TLAN devices (matching + * TLanDeviceList entries), and creating and initializing a + * device structure for each adapter. + * + **************************************************************/ + +extern int init_module(void) +{ + TLanPrivateInfo *priv; + u8 bus; + struct device *dev; + size_t dev_size; + u8 dfn; + u32 dl_ix; + int failed; + int found; + u32 io_base; + u8 irq; + u8 rev; + + printk( "TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n", + TLanVersionMajor, + TLanVersionMinor + ); + TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, + ( GFP_KERNEL | GFP_DMA ) + ); + if ( TLanPadBuffer == NULL ) { + printk( "TLAN: Could not allocate memory for pad buffer.\n" ); + return -ENOMEM; + } + + memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); + + dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo); + + while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) ) + { + dev = (struct device *) kmalloc( dev_size, GFP_KERNEL ); + if ( dev == NULL ) { + printk( "TLAN: Could not allocate memory for device.\n" ); + continue; + } + memset( dev, 0, dev_size ); + + dev->priv = priv = ( (void *) dev ) + sizeof(struct device); + dev->name = priv->devName; + strcpy( priv->devName, " " ); + dev->base_addr = io_base; + dev->irq = irq; + dev->init = TLan_Init; + + priv->pciBus = bus; + priv->pciDeviceFn = dfn; + priv->pciRevision = rev; + priv->pciEntry = dl_ix; + + ether_setup( dev ); + + failed = register_netdev( dev ); + + if ( failed ) { + printk( "TLAN: Could not register network device. Freeing struct.\n" ); + kfree( dev ); + } else { + priv->nextDevice = TLanDevices; + TLanDevices = dev; + TLanDevicesInstalled++; + printk("TLAN: %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLan +DeviceList[dl_ix].deviceName ); + } + } + + // printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock through Idle bit */ - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Use this to wait 300ns */ + return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV ); - nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */ - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK clock cycle */ - if (nack) { /* No ACK, so fake it */ - for (i = 0; i < 16; i++) { - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); - } - tmp = 0xffff; - err = TRUE; - } else { /* ACKed, so read data */ - for (tmp = 0, i = 0x8000; i; i >>= 1) { - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); - if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio)) - tmp |= i; - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); - } - } +} /* init_module */ - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */ - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); - if ( minten ) - TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); - *val = tmp; + /*************************************************************** + * cleanup_module + * + * Returns: + * Nothing + * Parms: + * None + * + * Goes through the TLanDevices list and frees the device + * structs and memory associated with each device (lists + * and buffers). It also ureserves the IO port regions + * associated with this device. + * + **************************************************************/ + +extern void cleanup_module(void) +{ + struct device *dev; + TLanPrivateInfo *priv; + + while (TLanDevicesInstalled) { + dev = TLanDevices; + priv = (TLanPrivateInfo *) dev->priv; + if ( priv->dmaStorage ) + kfree( priv->dmaStorage ); + release_region( dev->base_addr, 0x10 ); + unregister_netdev( dev ); + TLanDevices = priv->nextDevice; + kfree( dev ); + TLanDevicesInstalled--; + } + kfree( TLanPadBuffer ); - sti(); +} /* cleanup_module */ - return err; - } /* TLan_MiiReadReg */ +#else /* MODULE */ - /************************************************************************* - * TLan_MiiSendData - * - * Returns: Nothing - * Parms: base_port The base IO port of the adapter in question. - * dev The address of the PHY to be queried. - * data The value to be placed on the MII bus. - * num_bits The number of bits in data that are to be - * placed on the MII bus. + /*************************************************************** + * tlan_probe * - * This function sends on sequence of bits on the MII configuration - * bus. + * Returns: + * 0 on success, error code on error + * Parms: + * dev device struct to use if adapter is + * found. + * + * The name is lower case to fit in with all the rest of + * the netcard_probe names. This function looks for a/ + * another TLan based adapter, setting it up with the + * provided device struct if one is found. * - ************************************************************************/ + **************************************************************/ + +extern int tlan_probe( struct device *dev ) +{ + static int pad_allocated = 0; + int found; + TLanPrivateInfo *priv; + u8 bus, dfn, irq, rev; + u32 io_base, dl_ix; + + found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ); + if ( found ) { + dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL ); + if ( dev->priv == NULL ) { + printk( "TLAN: Could not allocate memory for device.\n" ); + } + memset( dev->priv, 0, sizeof(TLanPrivateInfo) ); + priv = (TLanPrivateInfo *) dev->priv; + + dev->name = priv->devName; + strcpy( priv->devName, " " ); + + dev = init_etherdev( dev, sizeof(TLanPrivateInfo) ); + + dev->base_addr = io_base; + dev->irq = irq; + + priv->pciBus = bus; + priv->pciDeviceFn = dfn; + priv->pciRevision = rev; + priv->pciEntry = dl_ix; - void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits ) - { - u16 sio; - u32 i; - - if ( num_bits == 0 ) - return; - - outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); - sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - TLan_SetBit( TLAN_NET_SIO_MTXEN, sio ); - - for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) { - TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); - TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); - if ( data & i ) - TLan_SetBit( TLAN_NET_SIO_MDATA, sio ); - else - TLan_ClearBit( TLAN_NET_SIO_MDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); - TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + if ( ! pad_allocated ) { + TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA ); + if ( TLanPadBuffer == NULL ) { + printk( "TLAN: Could not allocate memory for pad buffer.\n" ); + } else { + pad_allocated = 1; + memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); } + } + printk("TLAN %d.%d: %s irq=%2d io=%04x, %s\n",TLanVersionMajor, + TLanVersionMinor, + dev->name, + (int) irq, + io_base, + TLanDeviceList[dl_ix].deviceName ); + TLan_Init( dev ); + } + + return ( ( found ) ? 0 : -ENODEV ); - } /* TLan_MiiSendData */ +} /* tlan_probe */ +#endif /* MODULE */ - /************************************************************************* - * TLan_MiiSync - * - * Returns: Nothing - * Parms: base_port The base IO port of the adapter in question. + + + /*************************************************************** + * TLan_PciProbe * - * This functions syncs all PHYs in terms of the MII configuration bus. + * Returns: + * 1 if another TLAN card was found, 0 if not. + * Parms: + * pci_bus The PCI bus the card was found + * on. + * pci_dfn The PCI whatever the card was + * found at. + * pci_irq The IRQ of the found adapter. + * pci_rev The revision of the adapter. + * pci_io_base The first IO port used by the + * adapter. + * dl_ix The index in the device list + * of the adapter. + * + * This function searches for an adapter with PCI vendor + * and device IDs matching those in the TLanDeviceList. + * The function 'remembers' the last device it found, + * and so finds a new device (if anymore are to be found) + * each time the function is called. It then looks up + * pertinent PCI info and returns it to the caller. * - ************************************************************************/ + **************************************************************/ - void TLan_MiiSync( u16 base_port ) - { - int i; - u16 sio; +int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_ +io_base, u32 *dl_ix ) +{ + static int dl_index = 0; + static int pci_index = 0; + + int not_found; + u8 pci_latency; + u16 pci_command; + int reg; + + + if ( ! pcibios_present() ) { + printk( "TLAN: PCI Bios not present.\n" ); + return 0; + } + + for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) { + + not_found = pcibios_find_device( + TLanDeviceList[dl_index].vendorId, + TLanDeviceList[dl_index].deviceId, + pci_index, + pci_bus, + pci_dfn + ); + + if ( ! not_found ) { + + TLAN_DBG( + TLAN_DEBUG_GNRL, + "TLAN: found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", + TLanDeviceList[dl_index].vendorId, + TLanDeviceList[dl_index].deviceId + ); + + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev); + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq); + pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command); + pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_ba +se); + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_laten +cy); + + if (pci_latency < 0x10) { + pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff); + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Setting latency timer to max.\n"); + } + + for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) { + pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base); + if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { + *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pc +i_io_base); + break; + } else { + *pci_io_base = 0; + } + } - outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); - sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + if ( *pci_io_base == 0 ) + printk("TLAN: IO mapping not available, ignoring device.\n"); - TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio ); - for ( i = 0; i < 32; i++ ) { - TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); - TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + if (pci_command & PCI_COMMAND_MASTER) { + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Bus mastering is active.\n"); } - } /* TLan_MiiSync */ + pci_index++; + if ( *pci_io_base ) { + *dl_ix = dl_index; + return 1; + } + } else { + pci_index = 0; + } + } + return 0; - /************************************************************************* - * TLan_MiiWriteReg - * - * Returns: Nothing - * Parms: base_port The base IO port of the adapter in question. - * dev The address of the PHY to be written to. - * reg The register whose contents are to be - * written. - * val The value to be written to the register. - * - * This function uses the TLAN's MII bus to write the contents of a - * given register on a PHY. It sends the appropriate info and then - * writes the 16-bit register value from the MII configuration bus - * via the TLAN SIO register. - * - ************************************************************************/ +} /* TLan_PciProbe */ - void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val) - { - u16 sio; - int minten; - outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); - sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - cli(); - TLan_MiiSync( base_port ); - - minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); - if ( minten ) - TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio ); + /*************************************************************** + * TLan_Init + * + * Returns: + * 0 on success, error code otherwise. + * Parms: + * dev The structure of the device to be + * init'ed. + * + * This function completes the initialization of the + * device structure and driver. It reserves the IO + * addresses, allocates memory for the lists and bounce + * buffers, retrieves the MAC address from the eeprom + * and assignes the device's methods. + * + **************************************************************/ - TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */ - TLan_MiiSendData( base_port, 0x1, 2 ); /* Write ( 01b ) */ - TLan_MiiSendData( base_port, dev, 5 ); /* Device # */ - TLan_MiiSendData( base_port, reg, 5 ); /* Register # */ +int TLan_Init( struct device *dev ) +{ + int dma_size; + int err; + int i; + TLanPrivateInfo *priv; + + priv = (TLanPrivateInfo *) dev->priv; + + err = check_region( dev->base_addr, 0x10 ); + if ( err ) { + printk( "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", + dev->name, + dev->base_addr, + 0x10 ); + return -EIO; + } + request_region( dev->base_addr, 0x10, TLanSignature ); + + dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) + * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); + priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA ); + if ( priv->dmaStorage == NULL ) { + printk( "TLAN: Could not allocate lists and buffers for %s.\n", + dev->name ); + return -ENOMEM; + } + memset( priv->dmaStorage, 0, dma_size ); + priv->rxList = (TLanList *) + ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); + priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; + priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); + priv->txBuffer = priv->rxBuffer + + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + + err = 0; + for ( i = 0; i < 6 ; i++ ) + err |= TLan_EeReadByte( dev->base_addr, + (u8) 0x83 + i, + (u8 *) &dev->dev_addr[i] ); + if ( err ) + printk( "TLAN: %s: Error reading MAC from eeprom: %d\n", + dev->name, + err ); + dev->addr_len = 6; + + dev->open = &TLan_Open; + dev->hard_start_xmit = &TLan_StartTx; + dev->stop = &TLan_Close; + dev->get_stats = &TLan_GetStats; + dev->set_multicast_list = &TLan_SetMulticastList; - TLan_MiiSendData( base_port, 0x2, 2 ); /* Send ACK */ - TLan_MiiSendData( base_port, val, 16 ); /* Send Data */ +#ifndef MODULE - TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */ - TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + aui = dev->mem_start & 0x01; + debug = dev->mem_end; - if ( minten ) - TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); +#endif /* MODULE */ - sti(); + return 0; - } /* TLan_MiiWriteReg */ +} /* TLan_Init */ -/***************************************************************************** -****************************************************************************** + /*************************************************************** + * TLan_Open + * + * Returns: + * 0 on success, error code otherwise. + * Parms: + * dev Structure of device to be opened. + * + * This routine puts the driver and TLAN adapter in a + * state where it is ready to send and receive packets. + * It allocates the IRQ, resets and brings the adapter + * out of reset, and allows interrupts. It also delays + * the startup for autonegotiation or sends a Rx GO + * command to the adapter, as appropriate. + * + **************************************************************/ + +int TLan_Open( struct device *dev ) +{ + int err; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); + err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev + ); + if ( err ) { + printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name +, dev->irq ); + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* NOTE: It might not be necessary to read the stats before a + reset if you don't care what the values are. + */ + TLan_ResetLists( dev ); + TLan_ReadAndClearStats( dev, TLAN_IGNORE ); + TLan_Reset( dev ); + TLan_Reset( dev ); + TLan_SetMac( dev, 0, dev->dev_addr ); + outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); + if ( debug >= 1 ) + outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); + + init_timer( &priv->timer ); + priv->timer.data = (unsigned long) dev; + priv->timer.function = &TLan_Timer; + if ( priv->phyFlags & TLAN_PHY_AUTONEG ) { + priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY; + priv->timerSetAt = jiffies; + priv->timerType = TLAN_TIMER_LINK; + add_timer( &priv->timer ); + } else { + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + } + + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s opened. Revision = %x\n", dev->na +me, priv->tlanRev ); - ThunderLAN Driver PHY Layer Routines + return 0; - The TLAN chip can drive any number of PHYs (physical devices). Rather - than having lots of 'if' or '#ifdef' statements, I have created a - second driver layer for the PHYs. Each PHY can be identified from its - id in registers 2 and 3, and can be given a Check and Service routine - that will be called when the adapter is reset and when the adapter - receives a Network Status interrupt, respectively. - -****************************************************************************** -*****************************************************************************/ +} /* TLan_Open */ - static int TLan_PhyNop( struct device * ); - static void TLan_PhyPrint( struct device * ); - static void TLan_PhySelect( struct device * ); - static int TLan_PhyInternalCheck( struct device * ); - static int TLan_PhyInternalService( struct device * ); - static int TLan_PhyDp83840aCheck( struct device * ); + /*************************************************************** + * TLan_StartTx + * + * Returns: + * 0 on success, non-zero on failure. + * Parms: + * skb A pointer to the sk_buff containing the + * frame to be sent. + * dev The device to send the data on. + * + * This function adds a frame to the Tx list to be sent + * ASAP. First it verifies that the adapter is ready and + * there is room in the queue. Then it sets up the next + * available list, copies the frame to the corresponding + * buffer. If the adapter Tx channel is idle, it gives + * the adapter a Tx Go command on the list, otherwise it + * sets the forward address of the previous list to point + * to this one. Then it frees the sk_buff. + * + **************************************************************/ + +int TLan_StartTx( struct sk_buff *skb, struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanList *tail_list; + u8 *tail_buffer; + int pad; + + if ( ! priv->phyOnline ) { + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name ); + dev_kfree_skb( skb, FREE_WRITE ); + return 0; + } + + tail_list = priv->txList + priv->txTail; + if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev +->name, priv->txHead, priv->txTail ); + dev->tbusy = 1; + priv->txBusyCount++; + return 1; + } + tail_list->forward = 0; + tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); + memcpy( tail_buffer, skb->data, skb->len ); + pad = TLAN_MIN_FRAME_SIZE - skb->len; + if ( pad > 0 ) { + tail_list->frameSize = (u16) skb->len + pad; + tail_list->buffer[0].count = (u32) skb->len; + tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; + tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer ); + } else { + tail_list->frameSize = (u16) skb->len; + tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; + tail_list->buffer[1].count = 0; + tail_list->buffer[1].address = 0; + } + // are we transferring? + cli(); + tail_list->cStat = TLAN_CSTAT_READY; + if ( ! priv->txInProgress ) { + priv->txInProgress = 1; + outw( 0x4, dev->base_addr + TLAN_HOST_INT ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Starting TX on buffer %d\n", priv->t +xTail ); + outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); + } else { + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", p +riv->txTail ); + if ( priv->txTail == 0 ) + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_lis +t ); + else + ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); + } + sti(); + priv->txTail++; + if ( priv->txTail >= TLAN_NUM_TX_LISTS ) + priv->txTail = 0; + + dev_kfree_skb( skb, FREE_WRITE ); + + dev->trans_start = jiffies; + return 0; - static TLanPhyIdEntry TLanPhyIdTable[] = { - { 0x4000, 0x5014, &TLan_PhyInternalCheck, &TLan_PhyInternalService, TLAN_PHY_ACTIVITY }, - { 0x4000, 0x5015, &TLan_PhyInternalCheck, &TLan_PhyInternalService, TLAN_PHY_ACTIVITY }, - { 0x2000, 0x5C01, &TLan_PhyDp83840aCheck, &TLan_PhyNop, TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG }, - { 0x0000, 0x0000, NULL, NULL, 0 } - }; +} /* TLan_StartTx */ - /************************************************************************* - * TLan_PhyPrint + /*************************************************************** + * TLan_HandleInterrupt + * + * Returns: + * Nothing + * Parms: + * irq The line on which the interrupt + * occurred. + * dev_id A pointer to the device assigned to + * this irq line. + * regs ??? * - * Returns: Nothing - * Parms: dev A pointer to the device structure of the adapter - * which the desired PHY is located. - * - * This function prints the registers a PHY. - * - ************************************************************************/ + * This function handles an interrupt generated by its + * assigned TLAN adapter. The function deactivates + * interrupts on its adapter, records the type of + * interrupt, executes the appropriate subhandler, and + * acknowdges the interrupt to the adapter (thus + * re-enabling adapter interrupts. + * + **************************************************************/ - void TLan_PhyPrint( struct device *dev ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u16 i, data0, data1, data2, data3, phy; - u32 io; - - phy = priv->phyAddr; - io = dev->base_addr; - - if ( ( phy > 0 ) || ( phy <= TLAN_PHY_MAX_ADDR ) ) { - printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy ); - printk( "TLAN: Off. +0 +1 +2 +3 \n" ); - for ( i = 0; i < 0x20; i+= 4 ) { - TLan_MiiReadReg( io, phy, i, &data0 ); - TLan_MiiReadReg( io, phy, i + 1, &data1 ); - TLan_MiiReadReg( io, phy, i + 2, &data2 ); - TLan_MiiReadReg( io, phy, i + 3, &data3 ); - printk( "TLAN: 0x%02x 0x%04hx 0x%04hx 0x%04hx 0x%04hx\n", i, data0, data1, data2, data3 ); - } - } else { - printk( "TLAN: Device %s, PHY 0x%02x (Invalid).\n", dev->name, phy ); - } - - } /* TLan_PhyPrint */ +void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 ack; + struct device *dev; + u32 host_cmd; + u16 host_int; + int type; + dev = (struct device *) dev_id; + if ( dev->interrupt ) + printk( "TLAN: Re-entering interrupt handler for %s: %d.\n" , dev->name, dev +->interrupt ); + dev->interrupt++; + cli(); - /************************************************************************* - * TLan_PhySelect - * - * Returns: Nothing - * Parms: dev A pointer to the device structure of the adapter - * for which the PHY needs determined. - * - * This function decides which PHY amoung those attached to the TLAN chip - * is to be used. The TLAN chip can be attached to multiple PHYs, and - * the driver needs to decide which one to talk to. Currently this - * routine picks the PHY with the lowest address as the internal PHY - * address is 0x1F, the highest possible. This strategy assumes that - * there can be only one other PHY, and, if it exists, it is the one to - * be used. If token ring PHYs are ever supported, this routine will - * become a little more interesting... - * - ************************************************************************/ - - void TLan_PhySelect( struct device *dev ) - { - int err; - int phy; - int entry; - u16 id_hi; - u16 id_lo; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u16 val; - - priv->phyCheck = &TLan_PhyNop; // Make absolutely sure these aren't NULL - priv->phyService = &TLan_PhyNop; - - for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { - err = TLan_MiiReadReg( dev->base_addr, phy, 0, &val ); - if ( ! err ) { - TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &id_hi ); - TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &id_lo ); - entry = 0; - while ( ( TLanPhyIdTable[entry].idHi != 0 ) && ( TLanPhyIdTable[entry].idLo != 0 ) ) { - if ( ( TLanPhyIdTable[entry].idHi == id_hi ) && ( TLanPhyIdTable[entry].idLo == id_lo ) ) { - priv->phyAddr = phy; - priv->phyEntry = entry; - priv->phyCheck = TLanPhyIdTable[entry].check; - priv->phyService = TLanPhyIdTable[entry].service; - priv->phyFlags = TLanPhyIdTable[entry].flags; - break; - } - entry++; - } - break; - } - } + host_int = inw( dev->base_addr + TLAN_HOST_INT ); + outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints - } /* TLan_PhySelect */ + type = ( host_int & TLAN_HI_IT_MASK ) >> 2; + ack = TLanIntVector[type]( dev, host_int ); + sti(); + if ( ack ) { + host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); + outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + } - /************************************************************************* - * TLan_PhyNop - * - * Returns: Nothing - * Parms: dev A pointer to a device structure. - * - * This function does nothing and is meant as a stand-in for when - * a Check or Service function would be meaningless. - * - ************************************************************************/ + dev->interrupt--; - int TLan_PhyNop( struct device *dev ) - { - dev = NULL; - return 0; +} /* TLan_HandleInterrupts */ - } /* TLan_PhyNop */ - - /************************************************************************* - * TLan_PhyInternalCheck - * - * Returns: Nothing - * Parms: dev A pointer to a device structure of the adapter - * holding the PHY to be checked. + /*************************************************************** + * TLan_Close + * + * Returns: + * An error code. + * Parms: + * dev The device structure of the device to + * close. * - * This function resets the internal PHY on a TLAN chip. See Chap. 7, - * "Physical Interface (PHY)" of "ThunderLAN Programmer's Guide" - * - ************************************************************************/ - - int TLan_PhyInternalCheck( struct device *dev ) - { - u16 gen_ctl; - u32 io; - u16 phy; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u16 value; - u8 sio; - - io = dev->base_addr; - phy = priv->phyAddr; - - TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); - if ( gen_ctl & MII_GC_PDOWN ) { - TLan_MiiSync( io ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); - udelay(50000); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); - TLan_MiiSync( io ); - } + * This function shuts down the adapter. It records any + * stats, puts the adapter into reset state, deactivates + * its time as needed, and frees the irq it is using. + * + **************************************************************/ - TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); - while ( value & MII_GC_RESET ) - TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); - - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); - - udelay(500000); - - TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); - if ( aui ) - value |= TLAN_TC_AUISEL; - else - value &= ~TLAN_TC_AUISEL; - TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); - - // Read Possible Latched Link Status - TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); - // Read Real Link Status - TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); - if ( ( value & MII_GS_LINK ) || aui ) { - priv->phyOnline = 1; - TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); - } else { - priv->phyOnline = 0; - TLan_DioWrite8( io, TLAN_LED_REG, 0 ); - } +int TLan_Close(struct device *dev) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - // Enable Interrupts - TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); - value |= TLAN_TC_INTEN; - TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); - - sio = TLan_DioRead8( io, TLAN_NET_SIO ); - sio |= TLAN_NET_SIO_MINTEN; - TLan_DioWrite8( io, TLAN_NET_SIO, sio ); - - return 0; + dev->start = 0; + dev->tbusy = 1; - } /* TLanPhyInternalCheck */ + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + if ( priv->timerSetAt != 0 ) + del_timer( &priv->timer ); + free_irq( dev->irq, dev ); + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s closed.\n", dev->name ); + MOD_DEC_USE_COUNT; + return 0; +} /* TLan_Close */ - /************************************************************************* - * TLan_PhyInternalService - * - * Returns: Nothing - * Parms: dev A pointer to a device structure of the adapter - * holding the PHY to be serviced. - * - * This function services an interrupt generated by the internal PHY. - * It can turn on/off the link LED. See Chap. 7, - * "Physical Interface (PHY)" of "ThunderLAN Programmer's Guide". - * - ************************************************************************/ - - int TLan_PhyInternalService( struct device *dev ) - { - u16 tlphy_sts; - u16 gen_sts; - u16 an_exp; - u32 io; - u16 phy; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - - io = dev->base_addr; - phy = priv->phyAddr; - - TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts ); - TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); - TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); - if ( ( gen_sts & MII_GS_LINK ) || aui ) { - priv->phyOnline = 1; - TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); - } else { - priv->phyOnline = 0; - TLan_DioWrite8( io, TLAN_LED_REG, 0 ); - } - return 0; - } /* TLan_PhyInternalService */ + /*************************************************************** + * TLan_GetStats + * + * Returns: + * A pointer to the device's statistics structure. + * Parms: + * dev The device structure to return the + * stats for. + * + * This function updates the devices statistics by reading + * the TLAN chip's onboard registers. Then it returns the + * address of the statistics structure. + * + **************************************************************/ + +struct net_device_stats *TLan_GetStats( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int i; + + /* Should only read stats if open ? */ + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: %s EOC count = %d\n", dev->name, priv- +>rxEocCount ); + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s Busy count = %d\n", dev->name, pri +v->txBusyCount ); + if ( debug & TLAN_DEBUG_GNRL ) { + TLan_PrintDio( dev->base_addr ); + TLan_PhyPrint( dev ); + } + if ( debug & TLAN_DEBUG_LIST ) { + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) + TLan_PrintList( priv->rxList + i, "RX", i ); + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) + TLan_PrintList( priv->txList + i, "TX", i ); + } + + return ( &( (TLanPrivateInfo *) dev->priv )->stats ); +} /* TLan_GetStats */ - /************************************************************************* - * TLan_PhyDp83840aCheck - * - * Returns: Nothing - * Parms: dev A pointer to a device structure of the adapter - * holding the PHY to be reset. - * - * This function resets a National Semiconductor DP83840A 10/100 Mb/s - * PHY device. See National Semiconductor's data sheet for more info. - * This PHY is used on Compaq Netelligent 10/100 cards. - * - ************************************************************************/ - - static int TLan_PhyDp83840aCheck( struct device *dev ) - { - u16 gen_ctl; - int i; - u32 io; - u16 phy; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u16 value; - u8 sio; - - io = dev->base_addr; - phy = priv->phyAddr; - - TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); - if ( gen_ctl & MII_GC_PDOWN ) { - TLan_MiiSync( io ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); - for ( i = 0; i < 500000; i++ ) - SLOW_DOWN_IO; - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); - TLan_MiiSync( io ); - } - TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); - while ( value & MII_GC_RESET ) - TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); - - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); - // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 ); - TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 ); - for ( i = 0; i < 50000; i++ ) - SLOW_DOWN_IO; - -/* - // Read Possible Latched Link Status - TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); - // Read Real Link Status - TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); - if ( value & MII_GS_LINK ) { - priv->phyOnline = 1; - TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); - } else { - priv->phyOnline = 0; - TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + /*************************************************************** + * TLan_SetMulticastList + * + * Returns: + * Nothing + * Parms: + * dev The device structure to set the + * multicast list for. + * + * This function sets the TLAN adaptor to various receive + * modes. If the IFF_PROMISC flag is set, promiscuous + * mode is acitviated. Otherwise, promiscuous mode is + * turned off. If the IFF_ALLMULTI flag is set, then + * the hash table is set to receive all group addresses. + * Otherwise, the first three multicast addresses are + * stored in AREG_1-3, and the rest are selected via the + * hash table, as necessary. + * + **************************************************************/ + +void TLan_SetMulticastList( struct device *dev ) +{ + struct dev_mc_list *dmi = dev->mc_list; + u32 hash1 = 0; + u32 hash2 = 0; + int i; + u32 offset; + u8 tmp; + + if ( dev->flags & IFF_PROMISC ) { + tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); + } else { + tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); + if ( dev->flags & IFF_ALLMULTI ) { + for ( i = 0; i < 3; i++ ) + TLan_SetMac( dev, i + 1, NULL ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); + } else { + for ( i = 0; i < dev->mc_count; i++ ) { + if ( i < 3 ) { + TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); + } else { + offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); + if ( offset < 32 ) + hash1 |= ( 1 << offset ); + else + hash2 |= ( 1 << ( offset - 32 ) ); + } + dmi = dmi->next; } + for ( ; i < 3; i++ ) + TLan_SetMac( dev, i + 1, NULL ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 ); + } + } - // Enable Interrupts - TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); - value |= TLAN_TC_INTEN; - TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); -*/ - sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO ); - sio &= ~TLAN_NET_SIO_MINTEN; - TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio ); - priv->phyOnline = 1; - - return 0; - - } /* TLan_PhyDp83840aCheck */ - +} /* TLan_SetMulticastList */ /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Adapter Related Routines + ThunderLAN Driver Interrupt Vectors and Table + + Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN + Programmer's Guide" for more informations on handling interrupts + generated by TLAN based adapters. ****************************************************************************** *****************************************************************************/ + /*************************************************************** + * TLan_HandleInvalid + * + * Returns: + * 0 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles invalid interrupts. This should + * never happen unless some other adapter is trying to use + * the IRQ line assigned to the device. + * + **************************************************************/ - static void TLan_ResetLists( struct device * ); - static void TLan_PrintDio( u16 ); - static void TLan_PrintList( TLanList *, char *, int ); - static void TLan_ReadAndClearStats( struct device *, int ); - static int TLan_Reset( struct device * ); - static void TLan_SetMac( struct device *, int areg, char *mac ); - - - - - /************************************************************************* - * TLan_ResetLists - * - * Returns: Nothing - * Parms: dev The device structure with the list stuctures to - * be reset. - * - * This routine sets the variables associated with managing the TLAN - * lists to their initial values. - * - ************************************************************************/ - - void TLan_ResetLists( struct device *dev ) - { - int i; - TLanList *list; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - - priv->txHead = 0; - priv->txTail = 0; - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { - list = priv->txList + i; - list->cStat = TLAN_CSTAT_UNUSED; - list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); - list->buffer[2].count = 0; - list->buffer[2].address = 0; - } - - priv->rxHead = 0; - priv->rxTail = TLAN_NUM_RX_LISTS - 1; - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { - list = priv->rxList + i; - list->cStat = TLAN_CSTAT_READY; - list->frameSize = TLAN_MAX_FRAME_SIZE; - list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); - list->buffer[1].count = 0; - list->buffer[1].address = 0; - if ( i < TLAN_NUM_RX_LISTS - 1 ) - list->forward = virt_to_bus( list + 1 ); - else - list->forward = 0; - } - - } /* TLan_ResetLists */ - +u32 TLan_HandleInvalid( struct device *dev, u16 host_int ) +{ + host_int = 0; + // printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); + return 0; +} /* TLan_HandleInvalid */ - /************************************************************************* - * TLan_PrintDio - * - * Returns: Nothing - * Parms: io_base Base IO port of the device of which to print - * DIO registers. - * - * This function prints out all the the internal (DIO) registers of a - * TLAN chip. - * - ************************************************************************/ - - void TLan_PrintDio( u16 io_base ) - { - u32 data0, data1; - int i; - - printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); - printk( "TLAN: Off. +0 +4\n" ); - for ( i = 0; i < 0x4C; i+= 8 ) { - data0 = TLan_DioRead32( io_base, i ); - data1 = TLan_DioRead32( io_base, i + 0x4 ); - printk( "TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1 ); - } - } /* TLan_PrintDio */ + /*************************************************************** + * TLan_HandleTxEOF + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles Tx EOF interrupts which are raised + * by the adapter when it has completed sending the + * contents of a buffer. If detemines which list/buffer + * was completed and resets it. If the buffer was the last + * in the channel (EOC), then the function checks to see if + * another buffer is ready to send, and if so, sends a Tx + * Go command. Finally, the driver activates/continues the + * activity LED. + * + **************************************************************/ + +u32 TLan_HandleTxEOF( struct device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int eoc = 0; + TLanList *head_list; + u32 ack = 1; + + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", + priv->txHead, priv->txTail ); + host_int = 0; + head_list = priv->txList + priv->txHead; + if ( head_list->cStat & TLAN_CSTAT_EOC ) + eoc = 1; + if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { + printk( "TLAN: Received interrupt for uncompleted TX frame.\n" ); + } + // printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); +#if LINUX_KERNEL_VERSION > 0x20100 + priv->stats->tx_bytes += head_list->frameSize; +#endif + head_list->cStat = TLAN_CSTAT_UNUSED; + dev->tbusy = 0; + priv->txHead++; + if ( priv->txHead >= TLAN_NUM_TX_LISTS ) + priv->txHead = 0; + if ( eoc ) { + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n" +, priv->txHead, priv->txTail ); + head_list = priv->txList + priv->txHead; + if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO; + } else { + priv->txInProgress = 0; + } + } + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { + if ( priv->timerSetAt == 0 ) { + // printk("TxEOF Starting timer...\n"); + priv->timerSetAt = jiffies; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timerType = TLAN_TIMER_ACT; + add_timer( &priv->timer ); + } else if ( priv->timerType == TLAN_TIMER_ACT ) { + priv->timerSetAt = jiffies; + // printk("TxEOF continuing timer...\n"); + } + } - /************************************************************************* - * TLan_PrintList - * - * Returns: Nothing - * Parms: list A pointer to the TLanList structure to be printed. - * type A string to designate type of list, "Rx" or "Tx". - * num The index of the list. - * - * This function prints out the contents of the list pointed to by the - * list parameter. - * - ************************************************************************/ - - void TLan_PrintList( TLanList *list, char *type, int num) - { - int i; - - printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); - printk( "TLAN: Forward = 0x%08x\n", list->forward ); - printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); - printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); - // for ( i = 0; i < 10; i++ ) { - for ( i = 0; i < 2; i++ ) { - printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); - } + return ack; - } /* TLan_PrintList */ +} /* TLan_HandleTxEOF */ - /************************************************************************* - * TLan_ReadAndClearStats + /*************************************************************** + * TLan_HandleStatOverflow * - * Returns: Nothing - * Parms: dev Pointer to device structure of adapter to which - * to read stats. - * record Flag indicating whether to add - * - * This functions reads all the internal status registers of the TLAN - * chip, which clears them as a side effect. It then either adds the - * values to the device's status struct, or discards them, depending - * on whether record is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). - * - ************************************************************************/ - - void TLan_ReadAndClearStats( struct device *dev, int record ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u32 tx_good, tx_under; - u32 rx_good, rx_over; - u32 def_tx, crc, code; - u32 multi_col, single_col; - u32 excess_col, late_col, loss; - - outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR ); - tx_good = inb( dev->base_addr + TLAN_DIO_DATA ); - tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; - tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); - - outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR ); - rx_good = inb( dev->base_addr + TLAN_DIO_DATA ); - rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; - rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); - - outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR ); - def_tx = inb( dev->base_addr + TLAN_DIO_DATA ); - def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); - code = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); - - outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); - multi_col = inb( dev->base_addr + TLAN_DIO_DATA ); - multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - single_col = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); - single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8; - - outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); - excess_col = inb( dev->base_addr + TLAN_DIO_DATA ); - late_col = inb( dev->base_addr + TLAN_DIO_DATA + 1 ); - loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); - - if ( record ) { - priv->stats.rx_packets += rx_good; - priv->stats.rx_errors += rx_over + crc + code; - priv->stats.tx_packets += tx_good; - priv->stats.tx_errors += tx_under + loss; - priv->stats.collisions += multi_col + single_col + excess_col + late_col; - - priv->stats.rx_over_errors += rx_over; - priv->stats.rx_crc_errors += crc; - priv->stats.rx_frame_errors += code; - - priv->stats.tx_aborted_errors += tx_under; - priv->stats.tx_carrier_errors += loss; - } - - } /* TLan_ReadAndClearStats */ - - - - - /************************************************************************* - * TLan_Reset + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. * - * Returns: 0 - * Parms: dev Pointer to device structure of adapter to be - * reset. - * - * This function resets the adapter and it's physical device. See - * Chap. 3, pp. 9-10 of the "ThunderLAN Programmer's Guide" for details. - * The routine tries to implement what is detailed there, though - * adjustments have been made. - * - ************************************************************************/ - - int TLan_Reset( struct device *dev ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - int i; - u32 data; - u8 data8; - - // 1. Assume Stat registers have been dealt with. - // 2. Assert reset bit. - data = inl(dev->base_addr + TLAN_HOST_CMD); - data |= TLAN_HC_AD_RST; - outl(data, dev->base_addr + TLAN_HOST_CMD); - // 3. Turn off interrupts. - data = inl(dev->base_addr + TLAN_HOST_CMD); - data |= TLAN_HC_INT_OFF; - outl(data, dev->base_addr + TLAN_HOST_CMD); - // 4. Setup AREGs and HASHs. - for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) - TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); - // 5. Setup NetConfig register. - outw(TLAN_NET_CONFIG, dev->base_addr + TLAN_DIO_ADR); - outw(TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN, dev->base_addr + TLAN_DIO_DATA); - // 6. Setup BSIZE register. - // Accept defaults, 0x22, for now. - // 7. Setup TX commit in Acommit. - // Allow it to manage itself. - // 8. Load Ld_Tmr in HOST_CMD. - // I don't know what this value should be. I'll try 3. - outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); - // 9. Load Ld_Thr in HOST_CMD. - // Try 1 for now. - outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD ); - // 10. Unreset the MII by setting NMRST (in NetSio) to 1. - outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); - TLan_SetBit( TLAN_NET_SIO_NMRST, dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO ); - // 10a. Other. - // 12. Setup the NetMask register. - if ( priv->tlanRev >= 0x30 ) - TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, TLAN_ID_TX_EOC | TLAN_ID_RX_EOC ); - //TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP | TLAN_NET_CMD_DUPLEX | TLAN_NET_CMD_CAF ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP ); - // 11. Initialize PHYs. - TLan_PhySelect( dev ); - (*priv->phyCheck)( dev ); - - //data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK6 | TLAN_NET_MASK_MASK7; - data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK7; - TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 ); - TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, 1550 ); - /* - * 13. Turn on interrupts to host. - * I don't want any interrupts, yet. - */ - /* - data = inl(base_port + TLAN_HOST_CMD); - data |= TLAN_HC_INT_ON; - outl(data, base_port + TLAN_HOST_CMD); - */ - - return 0; - - } /* TLan_Reset */ - - - - - /************************************************************************* - * TLan_SetMac + * This function handles the Statistics Overflow interrupt + * which means that one or more of the TLAN statistics + * registers has reached 1/2 capacity and needs to be read. * - * Returns: Nothing - * Parms: dev Pointer to device structure of adapter on which to - * change the AREG. - * areg The AREG to set the address in (0 - 3). - * mac A pointer to an array of chars. Each element - * stores one byte of the address. IE, it isn't - * in ascii. - * - * This function transfers a MAC address to one of the TLAN AREGs - * (address registers). The TLAN chip locks the register on writing to - * offset 0 and unlocks the register after writing to offset 5. If NULL - * is passed in mac, then the AREG is filled with 0's. - * - ************************************************************************/ - - void TLan_SetMac( struct device *dev, int areg, char *mac ) - { - int i; - - areg *= 6; + **************************************************************/ - if ( mac != NULL ) { - for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] ); - } else { - for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 ); - } +u32 TLan_HandleStatOverflow( struct device *dev, u16 host_int ) +{ + host_int = 0; + TLan_ReadAndClearStats( dev, TLAN_RECORD ); - } /* TLan_SetMac */ + return 1; +} /* TLan_HandleStatOverflow */ -/***************************************************************************** -****************************************************************************** - ThunderLAN Driver Eeprom routines + /*************************************************************** + * TLan_HandleRxEOF + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Rx EOF interrupt which + * indicates a frame has been received by the adapter from + * the net and the frame has been transferred to memory. + * The function determines the bounce buffer the frame has + * been loaded into, creates a new sk_buff big enough to + * hold the frame, and sends it to protocol stack. It + * then resets the used buffer and appends it to the end + * of the list. If the frame was the last in the Rx + * channel (EOC), the function restarts the receive channel + * by sending an Rx Go command to the adapter. Then it + * activates/continues the the activity LED. + * + **************************************************************/ + +u32 TLan_HandleRxEOF( struct device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u32 ack = 1; + int eoc = 0; + u8 *head_buffer; + TLanList *head_list; + struct sk_buff *skb; + TLanList *tail_list; + void *t; + + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", +priv->rxHead, priv->rxTail ); + host_int = 0; + head_list = priv->rxList + priv->rxHead; + tail_list = priv->rxList + priv->rxTail; + if ( head_list->cStat & TLAN_CSTAT_EOC ) + eoc = 1; + if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { + printk( "TLAN: Received interrupt for uncompleted RX frame.\n" ); + } else { + skb = dev_alloc_skb( head_list->frameSize + 7 ); + if ( skb == NULL ) { + printk( "TLAN: Couldn't allocate memory for received data.\n" ); + } else { + head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE ); + skb->dev = dev; + skb_reserve( skb, 2 ); + t = (void *) skb_put( skb, head_list->frameSize ); + // printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); - The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A EEPROM. - These functions are based on information in Microchip's data sheet. I - don't know how well this functions will work with other EEPROMs. +#if LINUX_KERNEL_VERSION > 0x20100 + priv->stats->rx_bytes += head_list->frameSize; +#endif -****************************************************************************** -*****************************************************************************/ + memcpy( t, head_buffer, head_list->frameSize ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + } + } + head_list->forward = 0; + head_list->frameSize = TLAN_MAX_FRAME_SIZE; + head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; + tail_list->forward = virt_to_bus( head_list ); + priv->rxHead++; + if ( priv->rxHead >= TLAN_NUM_RX_LISTS ) + priv->rxHead = 0; + priv->rxTail++; + if ( priv->rxTail >= TLAN_NUM_RX_LISTS ) + priv->rxTail = 0; + if ( eoc ) { + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", + priv->rxHead, priv->rxTail ); + head_list = priv->rxList + priv->rxHead; + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO | TLAN_HC_RT; + priv->rxEocCount++; + } + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { + if ( priv->timerSetAt == 0 ) { + // printk("RxEOF Starting timer...\n"); + priv->timerSetAt = jiffies; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timerType = TLAN_TIMER_ACT; + add_timer( &priv->timer ); + } else if ( priv->timerType == TLAN_TIMER_ACT ) { + // printk("RxEOF tarting continuing timer...\n"); + priv->timerSetAt = jiffies; + } + } + dev->last_rx = jiffies; - static void TLan_EeSendStart( u16 ); - static int TLan_EeSendByte( u16, u8, int ); - static void TLan_EeReceiveByte( u16, u8 *, int ); - static int TLan_EeReadByte( u16, u8, u8 * ); + return ack; +} /* TLan_HandleRxEOF */ - /************************************************************************* - * TLan_EeSendStart + + /*************************************************************** + * TLan_HandleDummy * - * Returns: Nothing - * Parms: io_base The IO port base address for the TLAN device - * with the EEPROM to use. + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. * - * This function sends a start cycle to an EEPROM attached to a TLAN - * chip. + * This function handles the Dummy interrupt, which is + * raised whenever a test interrupt is generated by setting + * the Req_Int bit of HOST_CMD to 1. * - ************************************************************************/ + **************************************************************/ - void TLan_EeSendStart( u16 io_base ) - { - u16 sio; +u32 TLan_HandleDummy( struct device *dev, u16 host_int ) +{ + host_int = 0; + printk( "TLAN: Dummy interrupt on %s.\n", dev->name ); + return 1; - outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); - sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; +} /* TLan_HandleDummy */ - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); - // - // FIXME: Do I really need these SLOW_DOWN_IOs? - // - SLOW_DOWN_IO; - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); - SLOW_DOWN_IO; - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - SLOW_DOWN_IO; - } /* TLan_EeSendStart */ + /*************************************************************** + * TLan_HandleTxEOC + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This driver is structured to determine EOC occurances by + * reading the CSTAT member of the list structure. Tx EOC + * interrupts are disabled via the DIO INTDIS register. + * However, TLAN chips before revision 3.0 didn't have this + * functionality, so process EOC events if this is the + * case. + * + **************************************************************/ +u32 TLan_HandleTxEOC( struct device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanList *head_list; + u32 ack = 1; - /************************************************************************* - * TLan_EeSendByte - * - * Returns: If the correct ack was received, 0, otherwise 1 - * Parms: io_base The IO port base address for the TLAN device - * with the EEPROM to use. - * data The 8 bits of information to send to the - * EEPROM. - * stop If TLAN_EEPROM_STOP is passed, a stop cycle is - * sent after the byte is sent after the ack is - * read. - * - * This function sends a byte on the serial EEPROM line, driving the - * clock to send each bit. The function then reverses transmission - * direction and reads an acknowledge bit. - * - ************************************************************************/ - - int TLan_EeSendByte( u16 io_base, u8 data, int stop ) - { - int err; - u8 place; - u16 sio; - - outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); - sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; - - // Assume clock is low, tx is enabled; - for ( place = 0x80; place; place >>= 1 ) { - if ( place & data ) - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); - else - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - } - TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); - - if ( ( ! err ) && stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is high - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); - } + host_int = 0; + if ( priv->tlanRev < 0x30 ) { + TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- + IRQ\n", priv->txHead, priv->txTail ); + head_list = priv->txList + priv->txHead; + if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO; + } else { + priv->txInProgress = 0; + } + } - return ( err ); + return ack; - } /* TLan_EeSendByte */ +} /* TLan_HandleTxEOC */ - /************************************************************************* - * TLan_EeReceiveByte + /*************************************************************** + * TLan_HandleStatusCheck * - * Returns: Nothing - * Parms: io_base The IO port base address for the TLAN device - * with the EEPROM to use. - * data An address to a char to hold the data sent - * from the EEPROM. - * stop If TLAN_EEPROM_STOP is passed, a stop cycle is - * sent after the byte is received, and no ack is - * sent. - * - * This function receives 8 bits of data from the EEPROM over the serial - * link. It then sends and ack bit, or no ack and a stop bit. This - * function is used to retrieve data after the address of a byte in the - * EEPROM has been sent. - * - ************************************************************************/ - - void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) - { - u8 place; - u16 sio; - - outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); - sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; - *data = 0; - - // Assume clock is low, tx is enabled; - TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); - for ( place = 0x80; place; place >>= 1 ) { - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) ) - *data |= place; - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - } + * Returns: + * 0 if Adapter check, 1 if Network Status check. + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles Adapter Check/Network Status + * interrupts generated by the adapter. It checks the + * vector in the HOST_INT register to determine if it is + * an Adapter Check interrupt. If so, it resets the + * adapter. Otherwise it clears the status registers + * and services the PHY. + * + **************************************************************/ - TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); - if ( ! stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // Ack = 0 - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); +u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int ) +{ + u32 ack; + u32 error; + u8 net_sts; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + ack = 1; + if ( host_int & TLAN_HI_IV_MASK ) { + error = inl( dev->base_addr + TLAN_CH_PARM ); + printk( "TLAN: Adaptor Check on device %s err = 0x%x\n", dev->name, error ); + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + TLan_ResetLists( dev ); + TLan_Reset( dev ); + dev->tbusy = 0; + TLan_SetMac( dev, 0, dev->dev_addr ); + if ( priv->timerType == 0 ) { + if ( priv->phyFlags & TLAN_PHY_AUTONEG ) { + priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY; + priv->timerSetAt = jiffies; + priv->timerType = TLAN_TIMER_LINK; + add_timer( &priv->timer ); } else { - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); // No ack = 1 (?) - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is high - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + //printk( " RX GO---->\n" ); + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); } + } + ack = 0; + } else { + net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); + if ( net_sts ) + TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); + if ( net_sts & TLAN_NET_STS_MIRQ ) { + (*priv->phyService)( dev ); + if (debug) { + TLan_PhyPrint( dev ); + } + } + TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, +(unsigned) net_sts ); + } - } /* TLan_EeReceiveByte */ + return ack; +} /* TLan_HandleStatusCheck */ - /************************************************************************* - * TLan_EeReadByte - * - * Returns: No error = 0, else, the stage at which the error occured. - * Parms: io_base The IO port base address for the TLAN device - * with the EEPROM to use. - * ee_addr The address of the byte in the EEPROM whose - * contents are to be retrieved. - * data An address to a char to hold the data obtained - * from the EEPROM. - * - * This function reads a byte of information from an byte cell in the - * EEPROM. - * - ************************************************************************/ - - int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data ) - { - int err; - - cli(); - - TLan_EeSendStart( io_base ); - err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK ); - if (err) - return 1; - err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK ); - if (err) - return 2; - TLan_EeSendStart( io_base ); - err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK ); - if (err) - return 3; - TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP ); - sti(); + /*************************************************************** + * TLan_HandleRxEOC + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This driver is structured to determine EOC occurances by + * reading the CSTAT member of the list structure. Rx EOC + * interrupts are disabled via the DIO INTDIS register. + * However, TLAN chips before revision 3.0 didn't have this + * CSTAT member or a INTDIS register, so if this chip is + * pre-3.0, process EOC interrupts normally. + * + **************************************************************/ + +u32 TLan_HandleRxEOC( struct device *dev, u16 host_int ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanList *head_list; + u32 ack = 1; + + host_int = 0; + if ( priv->tlanRev < 0x30 ) { + TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- +IRQ\n", priv->rxHead, priv->rxTail ); + head_list = priv->rxList + priv->rxHead; + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO | TLAN_HC_RT; + priv->rxEocCount++; + } - return 0; + return ack; - } /* TLan_EeReadByte */ +} /* TLan_HandleRxEOC */ @@ -1183,422 +1385,427 @@ /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Interrupt Vectors and Table - - Please see Chap. 4, "Interrupt Handling" of the - "ThunderLAN Programmer's Guide" for more informations on handling - interrupts generated by TLAN based adapters. + ThunderLAN Driver Timer Function ****************************************************************************** *****************************************************************************/ - static u32 TLan_HandleInvalid( struct device *, u16 ); - static u32 TLan_HandleTxEOF( struct device *, u16 ); - static u32 TLan_HandleStatOverflow( struct device *, u16 ); - static u32 TLan_HandleRxEOF( struct device *, u16 ); - static u32 TLan_HandleDummy( struct device *, u16 ); - static u32 TLan_HandleTxEOC( struct device *, u16 ); - static u32 TLan_HandleStatusCheck( struct device *, u16 ); - static u32 TLan_HandleRxEOC( struct device *, u16 ); - - - - - typedef u32 (TLanIntVectorFunc)( struct device *, u16 ); - - - - - /************************************************************************* - * TLan_HandleInvalid - * - * Returns: 0 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This function handles invalid interrupts. This should never happen - * unless some other adapter is trying to use the IRQ line assigned to - * the device. - * - ************************************************************************/ - - u32 TLan_HandleInvalid( struct device *dev, u16 host_int ) - { - host_int = 0; - // printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); - return 0; - } /* TLan_HandleInvalid */ - - - /************************************************************************* - * TLan_HandleTxEOF + /*************************************************************** + * TLan_Timer * - * Returns: 1 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This function handles Tx EOF interrupts which are raised by the - * adapter when it has completed sending the contents of a buffer. If - * detemines which list/buffer was completed and resets it. If the - * buffer was the last in the channel (EOC), then the function checks - * to see if another buffer is ready to send, and if so, sends a Tx Go - * command. Finally, the driver activates/continues the activity LED. - * - ************************************************************************/ - - u32 TLan_HandleTxEOF( struct device *dev, u16 host_int ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - int eoc = 0; - TLanList *head_list; - u32 ack = 1; - - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); - host_int = 0; - head_list = priv->txList + priv->txHead; - if ( head_list->cStat & TLAN_CSTAT_EOC ) - eoc = 1; - if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { - printk( "TLAN: Received interrupt for uncompleted TX frame.\n" ); - } - // printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); - -#if LINUX_KERNEL_VERSION > 0x20100 - priv->stats->tx_bytes += head_list->frameSize; -#endif - - head_list->cStat = TLAN_CSTAT_UNUSED; - dev->tbusy = 0; - priv->txHead++; - if ( priv->txHead >= TLAN_NUM_TX_LISTS ) - priv->txHead = 0; - if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); - head_list = priv->txList + priv->txHead; - if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); - ack |= TLAN_HC_GO; - } else { - priv->txInProgress = 0; - } + * Returns: + * Nothing + * Parms: + * data A value given to add timer when + * add_timer was called. + * + * This function handles timed functionality for the + * TLAN driver. The two current timer uses are for + * delaying for autonegotionation and driving the ACT LED. + * - Autonegotiation requires being allowed about + * 2 1/2 seconds before attempting to transmit a + * packet. It would be a very bad thing to hang + * the kernel this long, so the driver doesn't + * allow transmission 'til after this time, for + * certain PHYs. It would be much nicer if all + * PHYs were interrupt-capable like the internal + * PHY. + * - The ACT LED, which shows adapter activity, is + * driven by the driver, and so must be left on + * for a short period to power up the LED so it + * can be seen. This delay can be changed by + * changing the TLAN_TIMER_ACT_DELAY in tlan.h, + * if desired. 10 jiffies produces a slightly + * sluggish response. + * + **************************************************************/ + +void TLan_Timer( unsigned long data ) +{ + struct device *dev = (struct device *) data; + u16 gen_sts; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + // printk( "TLAN: %s Entered Timer, type = %d\n", dev->name, priv->timerType ) +; + + switch ( priv->timerType ) { + case TLAN_TIMER_LINK: + TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts ); + if ( gen_sts & MII_GS_LINK ) { + priv->phyOnline = 1; + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + priv->timerSetAt = 0; + priv->timerType = 0; + } else { + priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 ); + add_timer( &priv->timer ); } - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); - if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { - if ( priv->timerSetAt == 0 ) { - // printk("TxEOF Starting timer...\n"); - priv->timerSetAt = jiffies; - priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; - priv->timerType = TLAN_TIMER_ACT; - add_timer( &priv->timer ); - } else if ( priv->timerType == TLAN_TIMER_ACT ) { - priv->timerSetAt = jiffies; - // printk("TxEOF continuing timer...\n"); - } + break; + case TLAN_TIMER_ACT: + if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) { + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + priv->timerSetAt = 0; + priv->timerType = 0; + } else { + priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; + add_timer( &priv->timer ); } + break; + default: + break; + } - return ack; +} /* TLan_Timer */ - } /* TLan_HandleTxEOF */ +/***************************************************************************** +****************************************************************************** - /************************************************************************* - * TLan_HandleStatOverflow - * - * Returns: 1 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This function handles the Statistics Overflow interrupt which means - * that one or more of the TLAN statistics registers has reached 1/2 - * capacity and needs to be read. - * - ************************************************************************/ + ThunderLAN Driver Adapter Related Routines + +****************************************************************************** +*****************************************************************************/ - u32 TLan_HandleStatOverflow( struct device *dev, u16 host_int ) - { - host_int = 0; - TLan_ReadAndClearStats( dev, TLAN_RECORD ); - return 1; + /*************************************************************** + * TLan_ResetLists + * + * Returns: + * Nothing + * Parms: + * dev The device structure with the list + * stuctures to be reset. + * + * This routine sets the variables associated with managing + * the TLAN lists to their initial values. + * + **************************************************************/ + +void TLan_ResetLists( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int i; + TLanList *list; + + priv->txHead = 0; + priv->txTail = 0; + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { + list = priv->txList + i; + list->cStat = TLAN_CSTAT_UNUSED; + list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_S +IZE ) ); + list->buffer[2].count = 0; + list->buffer[2].address = 0; + } + + priv->rxHead = 0; + priv->rxTail = TLAN_NUM_RX_LISTS - 1; + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { + list = priv->rxList + i; + list->cStat = TLAN_CSTAT_READY; + list->frameSize = TLAN_MAX_FRAME_SIZE; + list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; + list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_S +IZE ) ); + list->buffer[1].count = 0; + list->buffer[1].address = 0; + if ( i < TLAN_NUM_RX_LISTS - 1 ) + list->forward = virt_to_bus( list + 1 ); + else + list->forward = 0; + } - } /* TLan_HandleStatOverflow */ +} /* TLan_ResetLists */ - /************************************************************************* - * TLan_HandleRxEOF + /*************************************************************** + * TLan_PrintDio + * + * Returns: + * Nothing + * Parms: + * io_base Base IO port of the device of + * which to print DIO registers. * - * Returns: 1 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This function handles the Rx EOF interrupt which indicates a frame - * has been received by the adapter from the net and the frame has been - * transferred to memory. The function determines the bounce buffer - * the frame has been loaded into, creates a new sk_buff big enough to - * hold the frame, and sends it to protocol stack. It then resets the - * used buffer and appends it to the end of the list. If the frame was - * the last in the Rx channel (EOC), the function restarts the receive - * channel by sending an Rx Go command to the adapter. Then it activates/ - * continues the the activity LED. - * - ************************************************************************/ - - u32 TLan_HandleRxEOF( struct device *dev, u16 host_int ) - { - u32 ack = 1; - int eoc = 0; - u8 *head_buffer; - TLanList *head_list; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - struct sk_buff *skb; - TLanList *tail_list; - void *t; - - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); - host_int = 0; - head_list = priv->rxList + priv->rxHead; - tail_list = priv->rxList + priv->rxTail; - if ( head_list->cStat & TLAN_CSTAT_EOC ) - eoc = 1; - if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { - printk( "TLAN: Received interrupt for uncompleted RX frame.\n" ); - } else { - skb = dev_alloc_skb( head_list->frameSize + 7 ); - if ( skb == NULL ) { - printk( "TLAN: Couldn't allocate memory for received data.\n" ); - } else { - head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE ); - skb->dev = dev; - skb_reserve( skb, 2 ); - t = (void *) skb_put( skb, head_list->frameSize ); - // printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); - -#if LINUX_KERNEL_VERSION > 0x20100 - priv->stats->rx_bytes += head_list->frameSize; -#endif + * This function prints out all the the internal (DIO) + * registers of a TLAN chip. + * + **************************************************************/ - memcpy( t, head_buffer, head_list->frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } - } - head_list->forward = 0; - head_list->frameSize = TLAN_MAX_FRAME_SIZE; - head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - tail_list->forward = virt_to_bus( head_list ); - priv->rxHead++; - if ( priv->rxHead >= TLAN_NUM_RX_LISTS ) - priv->rxHead = 0; - priv->rxTail++; - if ( priv->rxTail >= TLAN_NUM_RX_LISTS ) - priv->rxTail = 0; - if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); - head_list = priv->rxList + priv->rxHead; - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); - ack |= TLAN_HC_GO | TLAN_HC_RT; - priv->rxEocCount++; - } - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); - if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { - if ( priv->timerSetAt == 0 ) { - // printk("RxEOF Starting timer...\n"); - priv->timerSetAt = jiffies; - priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; - priv->timerType = TLAN_TIMER_ACT; - add_timer( &priv->timer ); - } else if ( priv->timerType == TLAN_TIMER_ACT ) { - // printk("RxEOF tarting continuing timer...\n"); - priv->timerSetAt = jiffies; - } - } - dev->last_rx = jiffies; +void TLan_PrintDio( u16 io_base ) +{ + u32 data0, data1; + int i; - return ack; + printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_bas +e ); + printk( "TLAN: Off. +0 +4\n" ); + for ( i = 0; i < 0x4C; i+= 8 ) { + data0 = TLan_DioRead32( io_base, i ); + data1 = TLan_DioRead32( io_base, i + 0x4 ); + printk( "TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1 ); + } - } /* TLan_HandleRxEOF */ +} /* TLan_PrintDio */ - /************************************************************************* - * TLan_HandleDummy - * - * Returns: 1 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. + /*************************************************************** + * TLan_PrintList + * + * Returns: + * Nothing + * Parms: + * list A pointer to the TLanList structure to + * be printed. + * type A string to designate type of list, + * "Rx" or "Tx". + * num The index of the list. * - * This function handles the Dummy interrupt, which is raised whenever - * a test interrupt is generated by setting the Req_Int bit of HOST_CMD - * to 1. + * This function prints out the contents of the list + * pointed to by the list parameter. * - ************************************************************************/ + **************************************************************/ - u32 TLan_HandleDummy( struct device *dev, u16 host_int ) - { - host_int = 0; - printk( "TLAN: Dummy interrupt on %s.\n", dev->name ); - return 1; +void TLan_PrintList( TLanList *list, char *type, int num) +{ + int i; - } /* TLan_HandleDummy */ + printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); + printk( "TLAN: Forward = 0x%08x\n", list->forward ); + printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); + printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); + // for ( i = 0; i < 10; i++ ) { + for ( i = 0; i < 2; i++ ) { + printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffe +r[i].count, list->buffer[i].address ); + } +} /* TLan_PrintList */ - /************************************************************************* - * TLan_HandleTxEOC - * - * Returns: 1 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This driver is structured to determine EOC occurances by reading the - * CSTAT member of the list structure. Tx EOC interrupts are disabled - * via the DIO INTDIS register. However, TLAN chips before revision 3.0 - * didn't have this functionality, so process EOC events if this is the - * case. - * - ************************************************************************/ - u32 TLan_HandleTxEOC( struct device *dev, u16 host_int ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - TLanList *head_list; - u32 ack = 1; - - host_int = 0; - if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); - head_list = priv->txList + priv->txHead; - if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); - ack |= TLAN_HC_GO; - } else { - priv->txInProgress = 0; - } - } - return ack; - - } /* TLan_HandleTxEOC */ + /*************************************************************** + * TLan_ReadAndClearStats + * + * Returns: + * Nothing + * Parms: + * dev Pointer to device structure of adapter + * to which to read stats. + * record Flag indicating whether to add + * + * This functions reads all the internal status registers + * of the TLAN chip, which clears them as a side effect. + * It then either adds the values to the device's status + * struct, or discards them, depending on whether record + * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). + * + **************************************************************/ + +void TLan_ReadAndClearStats( struct device *dev, int record ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u32 tx_good, tx_under; + u32 rx_good, rx_over; + u32 def_tx, crc, code; + u32 multi_col, single_col; + u32 excess_col, late_col, loss; + + outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR ); + tx_good = inb( dev->base_addr + TLAN_DIO_DATA ); + tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; + tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR ); + rx_good = inb( dev->base_addr + TLAN_DIO_DATA ); + rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; + rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR ); + def_tx = inb( dev->base_addr + TLAN_DIO_DATA ); + def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + code = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); + multi_col = inb( dev->base_addr + TLAN_DIO_DATA ); + multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + single_col = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8; + + outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); + excess_col = inb( dev->base_addr + TLAN_DIO_DATA ); + late_col = inb( dev->base_addr + TLAN_DIO_DATA + 1 ); + loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + + if ( record ) { + priv->stats.rx_packets += rx_good; + priv->stats.rx_errors += rx_over + crc + code; + priv->stats.tx_packets += tx_good; + priv->stats.tx_errors += tx_under + loss; + priv->stats.collisions += multi_col + single_col + excess_col + late_col; + + priv->stats.rx_over_errors += rx_over; + priv->stats.rx_crc_errors += crc; + priv->stats.rx_frame_errors += code; + + priv->stats.tx_aborted_errors += tx_under; + priv->stats.tx_carrier_errors += loss; + } + +} /* TLan_ReadAndClearStats */ - /************************************************************************* - * TLan_HandleStatusCheck - * - * Returns: 0 if Adapter check, 1 if Network Status check. - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This function handles Adapter Check/Network Status interrupts - * generated by the adapter. It checks the vector in the HOST_INT - * register to determine if it is an Adapter Check interrupt. If so, - * it resets the adapter. Otherwise it clears the status registers - * and services the PHY. + /*************************************************************** + * TLan_Reset * - ************************************************************************/ + * Returns: + * 0 + * Parms: + * dev Pointer to device structure of adapter + * to be reset. + * + * This function resets the adapter and it's physical + * device. See Chap. 3, pp. 9-10 of the "ThunderLAN + * Programmer's Guide" for details. The routine tries to + * implement what is detailed there, though adjustments + * have been made. + * + **************************************************************/ + +int TLan_Reset( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int i; + u32 addr; + u32 data; + u8 data8; + +// 1. Assert reset bit. + + data = inl(dev->base_addr + TLAN_HOST_CMD); + data |= TLAN_HC_AD_RST; + outl(data, dev->base_addr + TLAN_HOST_CMD); + +// 2. Turn off interrupts. ( Probably isn't necessary ) + + data = inl(dev->base_addr + TLAN_HOST_CMD); + data |= TLAN_HC_INT_OFF; + outl(data, dev->base_addr + TLAN_HOST_CMD); + +// 3. Clear AREGs and HASHs. + + for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) { + TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); + } + +// 4. Setup NetConfig register. + + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; + TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); + +// 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. + + outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD ); + +// 6. Unreset the MII by setting NMRST (in NetSio) to 1. + + outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); + addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; + TLan_SetBit( TLAN_NET_SIO_NMRST, addr ); + +// 7. Setup the remaining registers. + + if ( priv->tlanRev >= 0x30 ) { + data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; + TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 ); + } + TLan_PhySelect( dev ); + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; + if ( priv->phyFlags & TLAN_PHY_BIT_RATE ) { + data |= TLAN_NET_CFG_BIT; + if ( aui == 1 ) { + TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a ); + } else { + TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); + } + } + if ( priv->phyFlags & TLAN_PHY_INTERNAL ) { + data |= TLAN_NET_CFG_PHY_EN; + } + TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); + (*priv->phyCheck)( dev ); + data8 = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP; + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data8 ); + data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; + if ( priv->phyFlags & TLAN_PHY_INTS ) { + data8 |= TLAN_NET_MASK_MASK7; + } + TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 ); + TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE ); + + if ( priv->phyFlags & TLAN_PHY_UNMANAGED ) { + priv->phyOnline = 1; + } - u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int ) - { - u32 ack; - u32 error; - u8 net_sts; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - - ack = 1; - if ( host_int & TLAN_HI_IV_MASK ) { - error = inl( dev->base_addr + TLAN_CH_PARM ); - printk( "TLAN: Adaptor Check on device %s err = 0x%x\n", dev->name, error ); - TLan_ReadAndClearStats( dev, TLAN_RECORD ); - outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - TLan_ResetLists( dev ); - TLan_Reset( dev ); - dev->tbusy = 0; - TLan_SetMac( dev, 0, dev->dev_addr ); - if ( priv->timerType == 0 ) { - if ( priv->phyFlags & TLAN_PHY_AUTONEG ) { - priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY; - priv->timerSetAt = jiffies; - priv->timerType = TLAN_TIMER_LINK; - add_timer( &priv->timer ); - } else { - //printk( " RX GO---->\n" ); - outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); - } - } - ack = 0; - } else { - net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); - if ( net_sts ) - TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); - if ( net_sts & TLAN_NET_STS_MIRQ ) { - (*priv->phyService)( dev ); - if (debug) { - TLan_PhyPrint( dev ); - } - } - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts ); - } + return 0; - return ack; +} /* TLan_Reset */ - } /* TLan_HandleStatusCheck */ - - /************************************************************************* - * TLan_HandleRxEOC + /*************************************************************** + * TLan_SetMac * - * Returns: 1 - * Parms: dev Device assigned the IRQ that was raised. - * host_int The contents of the HOST_INT port. - * - * This driver is structured to determine EOC occurances by reading the - * CSTAT member of the list structure. Rx EOC interrupts are disabled - * via the DIO INTDIS register. However, TLAN chips before revision 3.0 - * didn't have this CSTAT member or a INTDIS register, so if this chip - * is pre-3.0, process EOC interrupts normally. - * - ************************************************************************/ - - u32 TLan_HandleRxEOC( struct device *dev, u16 host_int ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - TLanList *head_list; - u32 ack = 1; - - host_int = 0; - if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); - head_list = priv->rxList + priv->rxHead; - outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); - ack |= TLAN_HC_GO | TLAN_HC_RT; - priv->rxEocCount++; - } - return ack; - - } /* TLan_HandleRxEOC */ - + * Returns: + * Nothing + * Parms: + * dev Pointer to device structure of adapter + * on which to change the AREG. + * areg The AREG to set the address in (0 - 3). + * mac A pointer to an array of chars. Each + * element stores one byte of the address. + * IE, it isn't in ascii. + * + * This function transfers a MAC address to one of the + * TLAN AREGs (address registers). The TLAN chip locks + * the register on writing to offset 0 and unlocks the + * register after writing to offset 5. If NULL is passed + * in mac, then the AREG is filled with 0's. + * + **************************************************************/ + +void TLan_SetMac( struct device *dev, int areg, char *mac ) +{ + int i; + + areg *= 6; + if ( mac != NULL ) { + for ( i = 0; i < 6; i++ ) + TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] ); + } else { + for ( i = 0; i < 6; i++ ) + TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 ); + } - static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { - TLan_HandleInvalid, - TLan_HandleTxEOF, - TLan_HandleStatOverflow, - TLan_HandleRxEOF, - TLan_HandleDummy, - TLan_HandleTxEOC, - TLan_HandleStatusCheck, - TLan_HandleRxEOC - }; +} /* TLan_SetMac */ @@ -1606,774 +1813,923 @@ /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Timer Function + ThunderLAN Driver PHY Layer Routines + The TLAN chip can drive any number of PHYs (physical devices). Rather + than having lots of 'if' or '#ifdef' statements, I have created a + second driver layer for the PHYs. Each PHY can be identified from its + id in registers 2 and 3, and can be given a Check and Service routine + that will be called when the adapter is reset and when the adapter + receives a Network Status interrupt, respectively. + ****************************************************************************** *****************************************************************************/ - static void TLan_Timer( unsigned long ); - +static TLanPhyIdEntry TLanPhyIdTable[] = { + { 0x4000, + 0x5014, + &TLan_PhyInternalCheck, + &TLan_PhyInternalService, + TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL }, + { 0x4000, + 0x5015, + &TLan_PhyInternalCheck, + &TLan_PhyInternalService, + TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL }, + { 0x4000, + 0x5016, + &TLan_PhyInternalCheck, + &TLan_PhyInternalService, + TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL }, + { 0x2000, + 0x5C00, + &TLan_PhyDp83840aCheck, + &TLan_PhyNop, + TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG }, + { 0x2000, + 0x5C01, + &TLan_PhyDp83840aCheck, + &TLan_PhyNop, + TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG }, + { 0x7810, + 0x0000, + &TLan_PhyDp83840aCheck, + &TLan_PhyNop, + TLAN_PHY_AUTONEG }, + { 0x0000, + 0x0000, + NULL, + NULL, + 0 + } + }; - /************************************************************************* - * TLan_Timer + /********************************************************************* + * TLan_PhyPrint * - * Returns: Nothing - * Parms: data A value given to add timer when add_timer was - * called. - * - * This function handles timed functionality for the TLAN driver. The - * two current timer uses are for delaying for autonegotionation and - * driving the ACT LED. - * - Autonegotiation requires being allowed about 2 1/2 seconds before - * attempting to transmit a packet. It would be a very bad thing - * to hang the kernel this long, so the driver doesn't allow - * transmission 'til after this time, for certain PHYs. It would - * be much nicer if all PHYs were interrupt-capable like the - * internal PHY. - * - The ACT LED, which shows adapter activity, is driven by the driver, - * and so must be left on for a short period to power up the LED so - * it can be seen. This delay can be changed by changing the - * TLAN_TIMER_ACT_DELAY in tlan.h, if desired. 10 jiffies produces a - * slightly sluggish response. - * - ************************************************************************/ - - void TLan_Timer( unsigned long data ) - { - struct device *dev = (struct device *) data; - u16 gen_sts; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - - // printk( "TLAN: %s Entered Timer, type = %d\n", dev->name, priv->timerType ); - - switch ( priv->timerType ) { - case TLAN_TIMER_LINK: - TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts ); - if ( gen_sts & MII_GS_LINK ) { - priv->phyOnline = 1; - outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); - priv->timerSetAt = 0; - priv->timerType = 0; - } else { - priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 ); - add_timer( &priv->timer ); - } - break; - case TLAN_TIMER_ACT: - if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) { - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); - priv->timerSetAt = 0; - priv->timerType = 0; - } else { - priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; - add_timer( &priv->timer ); - } - break; - default: - break; - } - - } /* TLan_Timer */ - - - - -/***************************************************************************** -****************************************************************************** - - ThunderLAN Driver Primary Functions + * Returns: + * Nothing + * Parms: + * dev A pointer to the device structure of the adapter + * which the desired PHY is located. + * + * This function prints the registers a PHY. + * + ********************************************************************/ - These functions are more or less common to all Linux network drivers. +void TLan_PhyPrint( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 i, data0, data1, data2, data3, phy; + u32 io; + + phy = priv->phyAddr; + io = dev->base_addr; + + if ( ( phy > 0 ) && ( phy <= TLAN_PHY_MAX_ADDR ) ) { + printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy ); + printk( "TLAN: Off. +0 +1 +2 +3 \n" ); + for ( i = 0; i < 0x20; i+= 4 ) { + printk( "TLAN: 0x%02x", i ); + TLan_MiiReadReg( io, phy, i, &data0 ); + printk( " 0x%04hx", data0 ); + TLan_MiiReadReg( io, phy, i + 1, &data1 ); + printk( " 0x%04hx", data1 ); + TLan_MiiReadReg( io, phy, i + 2, &data2 ); + printk( " 0x%04hx", data2 ); + TLan_MiiReadReg( io, phy, i + 3, &data3 ); + printk( " 0x%04hx\n", data3 ); + } + } else { + printk( "TLAN: Device %s, PHY 0x%02x (Unmanaged/Unknown).\n", + dev->name, + phy + ); + } + +} /* TLan_PhyPrint */ -****************************************************************************** -*****************************************************************************/ - static int TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * ); - static int TLan_Init( struct device * ); - static int TLan_Open(struct device *dev); - static int TLan_StartTx(struct sk_buff *, struct device *); - static void TLan_HandleInterrupt(int, void *, struct pt_regs *); - static int TLan_Close(struct device *); - static struct net_device_stats *TLan_GetStats( struct device * ); - static void TLan_SetMulticastList( struct device * ); -#ifdef MODULE + /********************************************************************* + * TLan_PhySelect + * + * Returns: + * Nothing + * Parms: + * dev A pointer to the device structure of the adapter + * for which the PHY needs determined. + * + * This function decides which PHY amoung those attached to the + * TLAN chip is to be used. The TLAN chip can be attached to + * multiple PHYs, and the driver needs to decide which one to + * talk to. Currently this routine picks the PHY with the lowest + * address as the internal PHY address is 0x1F, the highest + * possible. This strategy assumes that there can be only one + * other PHY, and, if it exists, it is the one to be used. If + * token ring PHYs are ever supported, this routine will become + * a little more interesting... + * + ********************************************************************/ + +void TLan_PhySelect( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int phy; + int entry; + u16 id_hi[TLAN_PHY_MAX_ADDR + 1]; + u16 id_lo[TLAN_PHY_MAX_ADDR + 1]; + u16 hi; + u16 lo; + u16 vendor; + u16 device; - /************************************************************************* - * init_module - * - * Returns: 0 if module installed ok, non-zero if not. - * Parms: None - * - * This function begins the setup of the driver creating a pad buffer, - * finding all TLAN devices (matching TLanDeviceList entries), and - * creating and initializing a device structure for each adapter. - * - ************************************************************************/ - - extern int init_module(void) - { - int failed, found; - size_t dev_size; - struct device *dev; - TLanPrivateInfo *priv; - u8 bus, dfn, irq, rev; - u32 io_base, dl_ix; - - printk("TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n", - TLanVersionMajor, - TLanVersionMinor - ); + priv->phyCheck = &TLan_PhyNop; // Make sure these aren't ever NULL + priv->phyService = &TLan_PhyNop; + + vendor = TLanDeviceList[priv->pciEntry].vendorId; + device = TLanDeviceList[priv->pciEntry].deviceId; - TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA ); - if ( TLanPadBuffer == NULL ) { - printk( "TLAN: Could not allocate memory for pad buffer.\n" ); - return -ENOMEM; + // This is a bit uglier than I'd like, but the 0xF130 device must + // NOT be assigned a valid PHY as it uses an unmanaged, bit-rate + // PHY. It is simplest just to use another goto, rather than + // nesting the two for loops in the if statement. + + if ( ( vendor == PCI_VENDOR_ID_COMPAQ ) && + ( device == PCI_DEVICE_ID_NETFLEX_3P ) ) { + entry = 0; + phy = 0; + goto FINISH; + } + + for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { + hi = lo = 0; + TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &hi ); + TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &lo ); + id_hi[phy] = hi; + id_lo[phy] = lo; + TLAN_DBG( TLAN_DEBUG_GNRL, + "TLAN: Phy %2x, hi = %hx, lo = %hx\n", + phy, + hi, + lo + ); + } + + for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { + if ( ( aui == 1 ) && ( phy != TLAN_PHY_MAX_ADDR ) ) { + if ( id_hi[phy] != 0xFFFF ) { + TLan_MiiSync(dev->base_addr); + TLan_MiiWriteReg(dev->base_addr, + phy, + MII_GEN_CTL, + MII_GC_PDOWN | + MII_GC_LOOPBK | + MII_GC_ISOLATE ); + + } + continue; + } + for ( entry = 0; TLanPhyIdTable[entry].check; entry++) { + if ( ( id_hi[phy] == TLanPhyIdTable[entry].idHi ) && + ( id_lo[phy] == TLanPhyIdTable[entry].idLo ) ) { + TLAN_DBG( TLAN_DEBUG_GNRL, + "TLAN: Selected Phy %hx\n", + phy + ); + goto FINISH; } - memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); + } + } - dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo); - while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) ) { - dev = (struct device *) kmalloc( dev_size, GFP_KERNEL ); - if ( dev == NULL ) { - printk( "TLAN: Could not allocate memory for device.\n" ); - continue; - } - memset( dev, 0, dev_size ); + entry = 0; + phy = 0; - dev->priv = priv = ( (void *) dev ) + sizeof(struct device); - dev->name = priv->devName; - strcpy( priv->devName, " " ); - dev->base_addr = io_base; - dev->irq = irq; - dev->init = TLan_Init; - - priv->pciBus = bus; - priv->pciDeviceFn = dfn; - priv->pciRevision = rev; - priv->pciEntry = dl_ix; - - ether_setup( dev ); - - failed = register_netdev( dev ); - - if ( failed ) { - printk( "TLAN: Could not register network device. Freeing struct.\n" ); - kfree( dev ); - } else { - priv->nextDevice = TLanDevices; - TLanDevices = dev; - TLanDevicesInstalled++; - printk("TLAN: %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName ); - } - } +FINISH: + + if ( ( entry == 0 ) && ( phy == 0 ) ) { + priv->phyAddr = phy; + priv->phyEntry = entry; + priv->phyCheck = TLan_PhyNop; + priv->phyService = TLan_PhyNop; + priv->phyFlags = TLAN_PHY_BIT_RATE | + TLAN_PHY_UNMANAGED | + TLAN_PHY_ACTIVITY; + } else { + priv->phyAddr = phy; + priv->phyEntry = entry; + priv->phyCheck = TLanPhyIdTable[entry].check; + priv->phyService = TLanPhyIdTable[entry].service; + priv->phyFlags = TLanPhyIdTable[entry].flags; + } + +} /* TLan_PhySelect */ + + + + + /*************************************************************** + * TLan_PhyNop + * + * Returns: + * Nothing + * Parms: + * dev A pointer to a device structure. + * + * This function does nothing and is meant as a stand-in + * for when a Check or Service function would be + * meaningless. + * + **************************************************************/ + +int TLan_PhyNop( struct device *dev ) +{ + dev = NULL; + return 0; + +} /* TLan_PhyNop */ + + + + + /*************************************************************** + * TLan_PhyInternalCheck + * + * Returns: + * Nothing + * Parms: + * dev A pointer to a device structure of the + * adapter holding the PHY to be checked. + * + * This function resets the internal PHY on a TLAN chip. + * See Chap. 7, "Physical Interface (PHY)" of "ThunderLAN + * Programmer's Guide" + * + **************************************************************/ + +int TLan_PhyInternalCheck( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 gen_ctl; + u32 io; + u16 phy; + u16 value; + u8 sio; + + io = dev->base_addr; + phy = priv->phyAddr; + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); + if ( gen_ctl & MII_GC_PDOWN ) { + TLan_MiiSync( io ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ +ISOLATE ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); + udelay(50000); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); + TLan_MiiSync( io ); + } + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + while ( value & MII_GC_RESET ) + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); + + udelay(500000); + + TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); + if ( aui ) + value |= TLAN_TC_AUISEL; + else + value &= ~TLAN_TC_AUISEL; + TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); + + // Read Possible Latched Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + // Read Real Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + if ( ( value & MII_GS_LINK ) || aui ) { + priv->phyOnline = 1; + TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->phyOnline = 0; + TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + } + + // Enable Interrupts + TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); + value |= TLAN_TC_INTEN; + TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); + + sio = TLan_DioRead8( io, TLAN_NET_SIO ); + sio |= TLAN_NET_SIO_MINTEN; + TLan_DioWrite8( io, TLAN_NET_SIO, sio ); - // printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); - - return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV ); + return 0; - } /* init_module */ +} /* TLanPhyInternalCheck */ - /************************************************************************* - * cleanup_module - * - * Returns: Nothing - * Parms: None - * - * Goes through the TLanDevices list and frees the device structs and - * memory associated with each device (lists and buffers). It also - * ureserves the IO port regions associated with this device. - * - ************************************************************************/ - - extern void cleanup_module(void) - { - struct device *dev; - TLanPrivateInfo *priv; - - while (TLanDevicesInstalled) { - dev = TLanDevices; - priv = (TLanPrivateInfo *) dev->priv; - if ( priv->dmaStorage ) - kfree( priv->dmaStorage ); - release_region( dev->base_addr, 0x10 ); - unregister_netdev( dev ); - TLanDevices = priv->nextDevice; - kfree( dev ); - TLanDevicesInstalled--; - } - kfree( TLanPadBuffer ); - - } /* cleanup_module */ + /*************************************************************** + * TLan_PhyInternalService + * + * Returns: + * Nothing + * Parms: + * dev A pointer to a device structure of the + * adapter holding the PHY to be serviced. + * + * This function services an interrupt generated by the + * internal PHY. It can turn on/off the link LED. See + * Chap. 7, "Physical Interface (PHY)" of "ThunderLAN + * Programmer's Guide". + * + **************************************************************/ + +int TLan_PhyInternalService( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 tlphy_sts; + u16 gen_sts; + u16 an_exp; + u32 io; + u16 phy; + + io = dev->base_addr; + phy = priv->phyAddr; + + TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts ); + TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); + TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); + if ( ( gen_sts & MII_GS_LINK ) || aui ) { + priv->phyOnline = 1; + TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->phyOnline = 0; + TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + } + + if ( ( tlphy_sts & TLAN_TS_POLOK ) == 0) { + u16 value; + TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value); + value |= TLAN_TC_SWAPOL; + TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value); + } + + return 0; + +} /* TLan_PhyInternalService */ + + + + + /*************************************************************** + * TLan_PhyDp83840aCheck + * + * Returns: + * Nothing + * Parms: + * dev A pointer to a device structure of the + * adapter holding the PHY to be reset. + * + * This function resets a National Semiconductor DP83840A + * 10/100 Mb/s PHY device. See National Semiconductor's + * data sheet for more info. This PHY is used on Compaq + * Netelligent 10/100 cards. + * + **************************************************************/ + +static int TLan_PhyDp83840aCheck( struct device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 gen_ctl; + int i; + u32 io; + u16 phy; + u16 value; + u8 sio; + + io = dev->base_addr; + phy = priv->phyAddr; + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); + if ( gen_ctl & MII_GC_PDOWN ) { + TLan_MiiSync( io ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ +ISOLATE ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); + for ( i = 0; i < 500000; i++ ) + SLOW_DOWN_IO; + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); + TLan_MiiSync( io ); + } + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + while ( value & MII_GC_RESET ) + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); + TLan_MiiReadReg( io, phy, MII_AN_ADV, &value ); + value &= ~0x0140; + TLan_MiiWriteReg( io, phy, MII_AN_ADV, value ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 ); + for ( i = 0; i < 50000; i++ ) + SLOW_DOWN_IO; -#else /* MODULE */ +/* + // Read Possible Latched Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + // Read Real Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + if ( value & MII_GS_LINK ) { + priv->phyOnline = 1; + TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->phyOnline = 0; + TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + } + + // Enable Interrupts + TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); + value |= TLAN_TC_INTEN; + TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); +*/ + sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO ); + sio &= ~TLAN_NET_SIO_MINTEN; + TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio ); +// priv->phyOnline = 1; + + return 0; +} /* TLan_PhyDp83840aCheck */ - /************************************************************************* - * tlan_probe - * - * Returns: 0 on success, error code on error - * Parms: dev device struct to use if adapter is found. - * - * The name is lower case to fit in with all the rest of the - * netcard_probe names. This function looks for a/another TLan based - * adapter, setting it up with the provided device struct if one is - * found. - * - ************************************************************************/ - - extern int tlan_probe( struct device *dev ) - { - static int pad_allocated = 0; - int found; - TLanPrivateInfo *priv; - u8 bus, dfn, irq, rev; - u32 io_base, dl_ix; - - found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ); - if ( found ) { - dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL ); - if ( dev->priv == NULL ) { - printk( "TLAN: Could not allocate memory for device.\n" ); - } - memset( dev->priv, 0, sizeof(TLanPrivateInfo) ); - priv = (TLanPrivateInfo *) dev->priv; - dev->name = priv->devName; - strcpy( priv->devName, " " ); +/***************************************************************************** +****************************************************************************** - dev = init_etherdev( dev, sizeof(TLanPrivateInfo) ); + ThunderLAN Driver MII Routines - dev->base_addr = io_base; - dev->irq = irq; - - priv->pciBus = bus; - priv->pciDeviceFn = dfn; - priv->pciRevision = rev; - priv->pciEntry = dl_ix; - - if ( ! pad_allocated ) { - TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA ); - if ( TLanPadBuffer == NULL ) { - printk( "TLAN: Could not allocate memory for pad buffer.\n" ); - } else { - pad_allocated = 1; - memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); - } - } - printk("TLAN %d.%d: %s irq=%2d io=%04x, %s\n", TLanVersionMajor, - TLanVersionMinor, - dev->name, - (int) irq, - io_base, - TLanDeviceList[dl_ix].deviceName ); - TLan_Init( dev ); - } - - return ( ( found ) ? 0 : -ENODEV ); + These routines are based on the information in Chap. 2 of the + "ThunderLAN Programmer's Guide", pp. 15-24. - } /* tlan_probe */ +****************************************************************************** +*****************************************************************************/ -#endif /* MODULE */ + /*************************************************************** + * TLan_MiiReadReg + * + * Returns: + * 0 if ack received ok + * 1 otherwise. + * + * Parms: + * base_port The base IO port of the adapter in + * question. + * dev The address of the PHY to be queried. + * reg The register whose contents are to be + * retreived. + * val A pointer to a variable to store the + * retrieved value. + * + * This function uses the TLAN's MII bus to retreive the contents + * of a given register on a PHY. It sends the appropriate info + * and then reads the 16-bit register value from the MII bus via + * the TLAN SIO register. + * + **************************************************************/ + +int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val) +{ + u8 nack; + u16 sio, tmp; + u32 i; + int err; + int minten; + + err = FALSE; + outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + + cli(); + + TLan_MiiSync(base_port); + + minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); + if ( minten ) + TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio); + + TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */ + TLan_MiiSendData( base_port, 0x2, 2 ); /* Read ( 10b ) */ + TLan_MiiSendData( base_port, dev, 5 ); /* Device # */ + TLan_MiiSendData( base_port, reg, 5 ); /* Register # */ + + + TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */ + + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock Idle bit */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Wait 300ns */ + + nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK */ + if (nack) { /* No ACK, so fake it */ + for (i = 0; i < 16; i++) { + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + } + tmp = 0xffff; + err = TRUE; + } else { /* ACK, so read data */ + for (tmp = 0, i = 0x8000; i; i >>= 1) { + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); + if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio)) + tmp |= i; + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + } + } + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + if ( minten ) + TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); - /************************************************************************* - * TLan_PciProbe - * - * Returns: 1 if another TLAN card was found, 0 if not. - * Parms: pci_bus The PCI bus the card was found on. - * pci_dfn The PCI whatever the card was found at. - * pci_irq The IRQ of the found adapter. - * pci_rev The revision of the adapter. - * pci_io_base The first IO port used by the adapter. - * dl_ix The index in the device list of the adapter. - * - * This function searches for an adapter with PCI vendor and device - * IDs matching those in the TLanDeviceList. The function 'remembers' - * the last device it found, and so finds a new device (if anymore are - * to be found) each time the function is called. It then looks up - * pertinent PCI info and returns it to the caller. - * - ************************************************************************/ + *val = tmp; - int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) - { - static int dl_index = 0; - static int pci_index = 0; + sti(); - int not_found; - u8 pci_latency; - u16 pci_command; + return err; +} /* TLan_MiiReadReg */ - if ( ! pcibios_present() ) { - printk( "TLAN: PCI Bios not present.\n" ); - return 0; - } - for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) { - not_found = pcibios_find_device( TLanDeviceList[dl_index].vendorId, - TLanDeviceList[dl_index].deviceId, - pci_index, - pci_bus, - pci_dfn - ); - if ( ! not_found ) { - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", - TLanDeviceList[dl_index].vendorId, - TLanDeviceList[dl_index].deviceId - ); - - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq); - pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command); - pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 0x10) { - pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff); - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Setting latency timer to max.\n"); - } - - if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { - *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base); - } else { - *pci_io_base = 0; - printk("TLAN: IO mapping not available, ignoring device.\n"); - } - - if (pci_command & PCI_COMMAND_MASTER) { - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Bus mastering is active.\n"); - } - - pci_index++; - - if ( *pci_io_base ) { - *dl_ix = dl_index; - return 1; - } - } else { - pci_index = 0; - } - } - return 0; + /*************************************************************** + * TLan_MiiSendData + * + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. + * dev The address of the PHY to be queried. + * data The value to be placed on the MII bus. + * num_bits The number of bits in data that are to + * be placed on the MII bus. + * + * This function sends on sequence of bits on the MII + * configuration bus. + * + **************************************************************/ + +void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits ) +{ + u16 sio; + u32 i; + + if ( num_bits == 0 ) + return; + + outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + TLan_SetBit( TLAN_NET_SIO_MTXEN, sio ); + + for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) { + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); + TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + if ( data & i ) + TLan_SetBit( TLAN_NET_SIO_MDATA, sio ); + else + TLan_ClearBit( TLAN_NET_SIO_MDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + } - } /* TLan_PciProbe */ +} /* TLan_MiiSendData */ - /************************************************************************* - * TLan_Init + /*************************************************************** + * TLan_MiiSync * - * Returns: 0 on success, error code otherwise. - * Parms: dev The structure of the device to be init'ed. + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. * - * This function completes the initialization of the device structure - * and driver. It reserves the IO addresses, allocates memory for the - * lists and bounce buffers, retrieves the MAC address from the eeprom - * and assignes the device's methods. - * - ************************************************************************/ - - int TLan_Init( struct device *dev ) - { - int dma_size; - int err; - int i; - TLanPrivateInfo *priv; - - priv = (TLanPrivateInfo *) dev->priv; - - err = check_region( dev->base_addr, 0x10 ); - if ( err ) { - printk( "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", dev->name, dev->base_addr, 0x10 ); - return -EIO; - } - request_region( dev->base_addr, 0x10, TLanSignature ); - - dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); - priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA ); - if ( priv->dmaStorage == NULL ) { - printk( "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); - return -ENOMEM; - } - memset( priv->dmaStorage, 0, dma_size ); - priv->rxList = (TLanList *) ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); - priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; - priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); - priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + * This functions syncs all PHYs in terms of the MII configuration + * bus. + * + **************************************************************/ - err = 0; - for ( i = 0; i < 6 ; i++ ) - err |= TLan_EeReadByte( dev->base_addr, (u8) 0x83 + i, (u8 *) &dev->dev_addr[i] ); - if ( err ) - printk( "TLAN: %s: Error reading MAC Address from eeprom: %d\n", dev->name, err ); - dev->addr_len = 6; +void TLan_MiiSync( u16 base_port ) +{ + int i; + u16 sio; - dev->open = &TLan_Open; - dev->hard_start_xmit = &TLan_StartTx; - dev->stop = &TLan_Close; - dev->get_stats = &TLan_GetStats; - dev->set_multicast_list = &TLan_SetMulticastList; + outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - return 0; + TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio ); + for ( i = 0; i < 32; i++ ) { + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + } - } /* TLan_Init */ +} /* TLan_MiiSync */ - /************************************************************************* - * TLan_Open + /*************************************************************** + * TLan_MiiWriteReg * - * Returns: 0 on success, error code otherwise. - * Parms: dev Structure of device to be opened. + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. + * dev The address of the PHY to be written to. + * reg The register whose contents are to be + * written. + * val The value to be written to the register. * - * This routine puts the driver and TLAN adapter in a state where it is - * ready to send and receive packets. It allocates the IRQ, resets and - * brings the adapter out of reset, and allows interrupts. It also - * delays the startup for autonegotiation or sends a Rx GO command to - * the adapter, as appropriate. - * - ************************************************************************/ - - int TLan_Open( struct device *dev ) - { - int err; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - - priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); - err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); - if ( err ) { - printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); - return -EAGAIN; - } + * This function uses the TLAN's MII bus to write the contents of a + * given register on a PHY. It sends the appropriate info and then + * writes the 16-bit register value from the MII configuration bus + * via the TLAN SIO register. + * + **************************************************************/ - MOD_INC_USE_COUNT; +void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val) +{ + u16 sio; + int minten; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - /* NOTE: It might not be necessary to read the stats before a - reset if you don't care what the values are. - */ - TLan_ResetLists( dev ); - TLan_ReadAndClearStats( dev, TLAN_IGNORE ); - TLan_Reset( dev ); - TLan_Reset( dev ); - TLan_SetMac( dev, 0, dev->dev_addr ); - outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); - if ( debug >= 1 ) - outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); - - init_timer( &priv->timer ); - priv->timer.data = (unsigned long) dev; - priv->timer.function = &TLan_Timer; - if ( priv->phyFlags & TLAN_PHY_AUTONEG ) { - priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY; - priv->timerSetAt = jiffies; - priv->timerType = TLAN_TIMER_LINK; - add_timer( &priv->timer ); - } else { - outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); - } + outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s opened. Revision = %x\n", dev->name, priv->tlanRev ); + cli(); - return 0; + TLan_MiiSync( base_port ); - } /* TLan_Open */ + minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); + if ( minten ) + TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio ); + TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */ + TLan_MiiSendData( base_port, 0x1, 2 ); /* Write ( 01b ) */ + TLan_MiiSendData( base_port, dev, 5 ); /* Device # */ + TLan_MiiSendData( base_port, reg, 5 ); /* Register # */ + TLan_MiiSendData( base_port, 0x2, 2 ); /* Send ACK */ + TLan_MiiSendData( base_port, val, 16 ); /* Send Data */ + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */ + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); - /************************************************************************* - * TLan_StartTx - * - * Returns: 0 on success, non-zero on failure. - * Parms: skb A pointer to the sk_buff containing the frame to - * be sent. - * dev The device to send the data on. - * - * This function adds a frame to the Tx list to be sent ASAP. First it - * verifies that the adapter is ready and there is room in the queue. - * Then it sets up the next available list, copies the frame to the - * corresponding buffer. If the adapter Tx channel is idle, it gives - * adapter a Tx Go command on the list, otherwise it sets the forward - * address of the previous list to point to this one. Then it frees - * the sk_buff. - * - ************************************************************************/ - - int TLan_StartTx( struct sk_buff *skb, struct device *dev ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - TLanList *tail_list; - u8 *tail_buffer; - int pad; - - if ( ! priv->phyOnline ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name ); - dev_kfree_skb( skb, FREE_WRITE ); - return 0; - } + if ( minten ) + TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); - tail_list = priv->txList + priv->txTail; - if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); - dev->tbusy = 1; - priv->txBusyCount++; - return 1; - } - tail_list->forward = 0; - tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); - memcpy( tail_buffer, skb->data, skb->len ); - pad = TLAN_MIN_FRAME_SIZE - skb->len; - if ( pad > 0 ) { - tail_list->frameSize = (u16) skb->len + pad; - tail_list->buffer[0].count = (u32) skb->len; - tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; - tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer ); - } else { - tail_list->frameSize = (u16) skb->len; - tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; - tail_list->buffer[1].count = 0; - tail_list->buffer[1].address = 0; - } - // are we transferring? - cli(); - tail_list->cStat = TLAN_CSTAT_READY; - if ( ! priv->txInProgress ) { - priv->txInProgress = 1; - outw( 0x4, dev->base_addr + TLAN_HOST_INT ); - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); - outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); - } else { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); - if ( priv->txTail == 0 ) - ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); - else - ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); - } - sti(); - priv->txTail++; - if ( priv->txTail >= TLAN_NUM_TX_LISTS ) - priv->txTail = 0; + sti(); - dev_kfree_skb( skb, FREE_WRITE ); - - dev->trans_start = jiffies; - return 0; +} /* TLan_MiiWriteReg */ - } /* TLan_StartTx */ +/***************************************************************************** +****************************************************************************** + ThunderLAN Driver Eeprom routines + The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A + EEPROM. These functions are based on information in Microchip's + data sheet. I don't know how well this functions will work with + other EEPROMs. +****************************************************************************** +*****************************************************************************/ - /************************************************************************* - * TLan_HandleInterrupt - * - * Returns: Nothing - * Parms: irq The line on which the interrupt occurred. - * dev_id A pointer to the device assigned to this irq line. - * regs ??? + + /*************************************************************** + * TLan_EeSendStart * - * This function handles an interrupt generated by its assigned TLAN - * adapter. The function deactivates interrupts on its adapter, records - * the type of interrupt, executes the appropriate subhandler, and - * acknowdges the interrupt to the adapter (thus re-enabling adapter - * interrupts. + * Returns: + * Nothing + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. * - ************************************************************************/ + * This function sends a start cycle to an EEPROM attached + * to a TLAN chip. + * + **************************************************************/ - void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) - { - u32 ack; - struct device *dev; - u32 host_cmd; - u16 host_int; - int type; +void TLan_EeSendStart( u16 io_base ) +{ + u16 sio; - dev = (struct device *) dev_id; + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; - if ( dev->interrupt ) - printk( "TLAN: Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt ); - dev->interrupt++; + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - cli(); +} /* TLan_EeSendStart */ - host_int = inw( dev->base_addr + TLAN_HOST_INT ); - outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints - type = ( host_int & TLAN_HI_IT_MASK ) >> 2; - ack = TLanIntVector[type]( dev, host_int ); - sti(); + /*************************************************************** + * TLan_EeSendByte + * + * Returns: + * If the correct ack was received, 0, otherwise 1 + * Parms: io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * data The 8 bits of information to + * send to the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a + * stop cycle is sent after the + * byte is sent after the ack is + * read. + * + * This function sends a byte on the serial EEPROM line, + * driving the clock to send each bit. The function then + * reverses transmission direction and reads an acknowledge + * bit. + * + **************************************************************/ + +int TLan_EeSendByte( u16 io_base, u8 data, int stop ) +{ + int err; + u8 place; + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + + // Assume clock is low, tx is enabled; + for ( place = 0x80; place != 0; place >>= 1 ) { + if ( place & data ) + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + else + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } + TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); - if ( ack ) { - host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); - outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); - } + if ( ( ! err ) && stop ) { + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is h +igh + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + } - dev->interrupt--; + return ( err ); - } /* TLan_HandleInterrupts */ +} /* TLan_EeSendByte */ - /************************************************************************* - * TLan_Close - * - * Returns: An error code. - * Parms: dev The device structure of the device to close. - * - * This function shuts down the adapter. It records any stats, puts - * the adapter into reset state, deactivates its time as needed, and - * frees the irq it is using. + /*************************************************************** + * TLan_EeReceiveByte * - ************************************************************************/ - - int TLan_Close(struct device *dev) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - - dev->start = 0; - dev->tbusy = 1; - - TLan_ReadAndClearStats( dev, TLAN_RECORD ); - outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - if ( priv->timerSetAt != 0 ) - del_timer( &priv->timer ); - free_irq( dev->irq, dev ); - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s closed.\n", dev->name ); - - MOD_DEC_USE_COUNT; - - return 0; + * Returns: + * Nothing + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * data An address to a char to hold the + * data sent from the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a + * stop cycle is sent after the + * byte is received, and no ack is + * sent. + * + * This function receives 8 bits of data from the EEPROM + * over the serial link. It then sends and ack bit, or no + * ack and a stop bit. This function is used to retrieve + * data after the address of a byte in the EEPROM has been + * sent. + * + **************************************************************/ + +void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) +{ + u8 place; + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + *data = 0; + + // Assume clock is low, tx is enabled; + TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); + for ( place = 0x80; place; place >>= 1 ) { + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) ) + *data |= place; + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } + + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + if ( ! stop ) { + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // Ack = 0 + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } else { + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); // No ack = 1 (?) + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is h +igh + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + } - } /* TLan_Close */ +} /* TLan_EeReceiveByte */ - /************************************************************************* - * TLan_GetStats - * - * Returns: A pointer to the device's statistics structure. - * Parms: dev The device structure to return the stats for. + /*************************************************************** + * TLan_EeReadByte * - * This function updates the devices statistics by reading the TLAN - * chip's onboard registers. Then it returns the address of the - * statistics structure. - * - ************************************************************************/ - - struct net_device_stats *TLan_GetStats( struct device *dev ) - { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - int i; - - /* Should only read stats if open ? */ - TLan_ReadAndClearStats( dev, TLAN_RECORD ); - - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); - if ( debug & TLAN_DEBUG_GNRL ) { - TLan_PrintDio( dev->base_addr ); - TLan_PhyPrint( dev ); - } - if ( debug & TLAN_DEBUG_LIST ) { - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) - TLan_PrintList( priv->rxList + i, "RX", i ); - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) - TLan_PrintList( priv->txList + i, "TX", i ); - } - - return ( &( (TLanPrivateInfo *) dev->priv )->stats ); - - } /* TLan_GetStats */ + * Returns: + * No error = 0, else, the stage at which the error + * occured. + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * ee_addr The address of the byte in the + * EEPROM whose contents are to be + * retrieved. + * data An address to a char to hold the + * data obtained from the EEPROM. + * + * This function reads a byte of information from an byte + * cell in the EEPROM. + * + **************************************************************/ + +int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data ) +{ + int err; + + cli(); + + TLan_EeSendStart( io_base ); + err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK ); + if (err) + return 1; + err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK ); + if (err) + return 2; + TLan_EeSendStart( io_base ); + err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK ); + if (err) + return 3; + TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP ); + sti(); + return 0; +} /* TLan_EeReadByte */ - /************************************************************************* - * TLan_SetMulticastList - * - * Returns: Nothing - * Parms: dev The device structure to set the multicast list for. - * - * This function sets the TLAN adaptor to various receive modes. If the - * IFF_PROMISC flag is set, promiscuous mode is acitviated. Otherwise, - * promiscuous mode is turned off. If the IFF_ALLMULTI flag is set, then - * the hash table is set to receive all group addresses. Otherwise, the - * first three multicast addresses are stored in AREG_1-3, and the rest - * are selected via the hash table, as necessary. - * - ************************************************************************/ - - void TLan_SetMulticastList( struct device *dev ) - { - struct dev_mc_list *dmi = dev->mc_list; - u32 hash1 = 0; - u32 hash2 = 0; - int i; - u32 offset; - u8 tmp; - - if ( dev->flags & IFF_PROMISC ) { - tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); - } else { - tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); - if ( dev->flags & IFF_ALLMULTI ) { - for ( i = 0; i < 3; i++ ) - TLan_SetMac( dev, i + 1, NULL ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); - } else { - for ( i = 0; i < dev->mc_count; i++ ) { - if ( i < 3 ) { - TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); - } else { - offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); - if ( offset < 32 ) - hash1 |= ( 1 << offset ); - else - hash2 |= ( 1 << ( offset - 32 ) ); - } - dmi = dmi->next; - } - for ( ; i < 3; i++ ) - TLan_SetMac( dev, i + 1, NULL ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 ); - } - } - } /* TLan_SetRxMode */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.1.66/linux/drivers/net/tlan.h Wed Sep 3 20:52:42 1997 +++ linux/drivers/net/tlan.h Wed Nov 26 16:21:54 1997 @@ -1,6 +1,5 @@ #ifndef TLAN_H #define TLAN_H - /******************************************************************** * * Linux ThunderLAN Driver @@ -17,6 +16,7 @@ * ********************************************************************/ + #include #include #include @@ -33,23 +33,23 @@ * ****************************************************************/ - #define FALSE 0 - #define TRUE 1 +#define FALSE 0 +#define TRUE 1 - #define TLAN_MIN_FRAME_SIZE 64 - #define TLAN_MAX_FRAME_SIZE 1600 +#define TLAN_MIN_FRAME_SIZE 64 +#define TLAN_MAX_FRAME_SIZE 1600 - #define TLAN_NUM_RX_LISTS 4 - #define TLAN_NUM_TX_LISTS 8 +#define TLAN_NUM_RX_LISTS 4 +#define TLAN_NUM_TX_LISTS 8 - #define TLAN_IGNORE 0 - #define TLAN_RECORD 1 - - #define TLAN_DBG(lvl, format, args...) if ( debug & lvl ) printk( format, ##args ); - #define TLAN_DEBUG_GNRL 0x0001 - #define TLAN_DEBUG_TX 0x0002 - #define TLAN_DEBUG_RX 0x0004 - #define TLAN_DEBUG_LIST 0x0008 +#define TLAN_IGNORE 0 +#define TLAN_RECORD 1 + +#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk( format, ##args ); +#define TLAN_DEBUG_GNRL 0x0001 +#define TLAN_DEBUG_TX 0x0002 +#define TLAN_DEBUG_RX 0x0004 +#define TLAN_DEBUG_LIST 0x0008 @@ -59,22 +59,23 @@ * ****************************************************************/ - /* NOTE: These should be moved to pci.h someday */ - #define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34 - #define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32 - #define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35 - #define PCI_DEVICE_ID_NETFLEX_3P 0xF130 - #define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150 - #define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43 - #define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40 - #define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011 - - - typedef struct tlan_pci_id { - u16 vendorId; - u16 deviceId; - char *deviceName; - } TLanPciId; + /* NOTE: These have been moved to pci.h, will use them + eventually */ +#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34 +#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32 +#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35 +#define PCI_DEVICE_ID_NETFLEX_3P 0xF130 +#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150 +#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43 +#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40 +#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011 + + +typedef struct tlan_pci_id { + u16 vendorId; + u16 deviceId; + char *deviceName; +} TLanPciId; @@ -84,32 +85,32 @@ * ****************************************************************/ - #define TLAN_BUFFERS_PER_LIST 10 - #define TLAN_LAST_BUFFER 0x80000000 - #define TLAN_CSTAT_UNUSED 0x8000 - #define TLAN_CSTAT_FRM_CMP 0x4000 - #define TLAN_CSTAT_READY 0x3000 - #define TLAN_CSTAT_EOC 0x0800 - #define TLAN_CSTAT_RX_ERROR 0x0400 - #define TLAN_CSTAT_PASS_CRC 0x0200 - #define TLAN_CSTAT_DP_PR 0x0100 - - - typedef struct tlan_buffer_ref_tag { - u32 count; - u32 address; - } TLanBufferRef; - - - typedef struct tlan_list_tag { - u32 forward; - u16 cStat; - u16 frameSize; - TLanBufferRef buffer[TLAN_BUFFERS_PER_LIST]; - } TLanList; +#define TLAN_BUFFERS_PER_LIST 10 +#define TLAN_LAST_BUFFER 0x80000000 +#define TLAN_CSTAT_UNUSED 0x8000 +#define TLAN_CSTAT_FRM_CMP 0x4000 +#define TLAN_CSTAT_READY 0x3000 +#define TLAN_CSTAT_EOC 0x0800 +#define TLAN_CSTAT_RX_ERROR 0x0400 +#define TLAN_CSTAT_PASS_CRC 0x0200 +#define TLAN_CSTAT_DP_PR 0x0100 + + +typedef struct tlan_buffer_ref_tag { + u32 count; + u32 address; +} TLanBufferRef; + + +typedef struct tlan_list_tag { + u32 forward; + u16 cStat; + u16 frameSize; + TLanBufferRef buffer[TLAN_BUFFERS_PER_LIST]; +} TLanList; - typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; +typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; @@ -119,23 +120,26 @@ * ****************************************************************/ - #define TLAN_PHY_MAX_ADDR 0x1F - #define TLAN_PHY_INTERNAL 0x1F - - #define TLAN_PHY_ACTIVITY 0x00000001 - #define TLAN_PHY_AUTONEG 0x00000002 - - - typedef int (TLanPhyFunc)( struct device * ); - +#define TLAN_PHY_MAX_ADDR 0x1F - typedef struct tlan_phy_id_entry_tag { - u16 idHi; - u16 idLo; - TLanPhyFunc *check; - TLanPhyFunc *service; - u32 flags; - } TLanPhyIdEntry; +#define TLAN_PHY_ACTIVITY 0x00000001 +#define TLAN_PHY_AUTONEG 0x00000002 +#define TLAN_PHY_INTS 0x00000004 +#define TLAN_PHY_BIT_RATE 0x00000008 +#define TLAN_PHY_UNMANAGED 0x00000010 +#define TLAN_PHY_INTERNAL 0x00000020 + + +typedef int (TLanPhyFunc)( struct device * ); + + +typedef struct tlan_phy_id_entry_tag { + u16 idHi; + u16 idLo; + TLanPhyFunc *check; + TLanPhyFunc *service; + u32 flags; +} TLanPhyIdEntry; @@ -145,38 +149,38 @@ * ****************************************************************/ - typedef struct tlan_private_tag { - struct device *nextDevice; - void *dmaStorage; - u8 *padBuffer; - TLanList *rxList; - u8 *rxBuffer; - u32 rxHead; - u32 rxTail; - u32 rxEocCount; - TLanList *txList; - u8 *txBuffer; - u32 txHead; - u32 txInProgress; - u32 txTail; - u32 txBusyCount; - u32 phyAddr; - u32 phyEntry; - u32 phyOnline; - u32 phyFlags; - TLanPhyFunc *phyCheck; - TLanPhyFunc *phyService; - u32 timerSetAt; - u32 timerType; - struct timer_list timer; - struct net_device_stats stats; - u32 pciEntry; - u8 pciRevision; - u8 pciBus; - u8 pciDeviceFn; - u8 tlanRev; - char devName[8]; - } TLanPrivateInfo; +typedef struct tlan_private_tag { + struct device *nextDevice; + void *dmaStorage; + u8 *padBuffer; + TLanList *rxList; + u8 *rxBuffer; + u32 rxHead; + u32 rxTail; + u32 rxEocCount; + TLanList *txList; + u8 *txBuffer; + u32 txHead; + u32 txInProgress; + u32 txTail; + u32 txBusyCount; + u32 phyAddr; + u32 phyEntry; + u32 phyOnline; + u32 phyFlags; + TLanPhyFunc *phyCheck; + TLanPhyFunc *phyService; + u32 timerSetAt; + u32 timerType; + struct timer_list timer; + struct net_device_stats stats; + u32 pciEntry; + u8 pciRevision; + u8 pciBus; + u8 pciDeviceFn; + u8 tlanRev; + char devName[8]; +} TLanPrivateInfo; @@ -186,11 +190,11 @@ * ****************************************************************/ - #define TLAN_TIMER_LINK 1 - #define TLAN_TIMER_ACT 2 +#define TLAN_TIMER_LINK 1 +#define TLAN_TIMER_ACT 2 - #define TLAN_TIMER_LINK_DELAY 230 - #define TLAN_TIMER_ACT_DELAY 10 +#define TLAN_TIMER_LINK_DELAY 230 +#define TLAN_TIMER_ACT_DELAY 10 @@ -200,8 +204,8 @@ * ****************************************************************/ - #define TLAN_EEPROM_ACK 0 - #define TLAN_EEPROM_STOP 1 +#define TLAN_EEPROM_ACK 0 +#define TLAN_EEPROM_STOP 1 @@ -211,29 +215,29 @@ * ****************************************************************/ - #define TLAN_HOST_CMD 0x00 - #define TLAN_HC_GO 0x80000000 - #define TLAN_HC_STOP 0x40000000 - #define TLAN_HC_ACK 0x20000000 - #define TLAN_HC_CS_MASK 0x1FE00000 - #define TLAN_HC_EOC 0x00100000 - #define TLAN_HC_RT 0x00080000 - #define TLAN_HC_NES 0x00040000 - #define TLAN_HC_AD_RST 0x00008000 - #define TLAN_HC_LD_TMR 0x00004000 - #define TLAN_HC_LD_THR 0x00002000 - #define TLAN_HC_REQ_INT 0x00001000 - #define TLAN_HC_INT_OFF 0x00000800 - #define TLAN_HC_INT_ON 0x00000400 - #define TLAN_HC_AC_MASK 0x000000FF - #define TLAN_CH_PARM 0x04 - #define TLAN_DIO_ADR 0x08 - #define TLAN_DA_ADR_INC 0x8000 - #define TLAN_DA_RAM_ADR 0x4000 - #define TLAN_HOST_INT 0x0A - #define TLAN_HI_IV_MASK 0x1FE0 - #define TLAN_HI_IT_MASK 0x001C - #define TLAN_DIO_DATA 0x0C +#define TLAN_HOST_CMD 0x00 +#define TLAN_HC_GO 0x80000000 +#define TLAN_HC_STOP 0x40000000 +#define TLAN_HC_ACK 0x20000000 +#define TLAN_HC_CS_MASK 0x1FE00000 +#define TLAN_HC_EOC 0x00100000 +#define TLAN_HC_RT 0x00080000 +#define TLAN_HC_NES 0x00040000 +#define TLAN_HC_AD_RST 0x00008000 +#define TLAN_HC_LD_TMR 0x00004000 +#define TLAN_HC_LD_THR 0x00002000 +#define TLAN_HC_REQ_INT 0x00001000 +#define TLAN_HC_INT_OFF 0x00000800 +#define TLAN_HC_INT_ON 0x00000400 +#define TLAN_HC_AC_MASK 0x000000FF +#define TLAN_CH_PARM 0x04 +#define TLAN_DIO_ADR 0x08 +#define TLAN_DA_ADR_INC 0x8000 +#define TLAN_DA_RAM_ADR 0x4000 +#define TLAN_HOST_INT 0x0A +#define TLAN_HI_IV_MASK 0x1FE0 +#define TLAN_HI_IT_MASK 0x001C +#define TLAN_DIO_DATA 0x0C /* ThunderLAN Internal Register DIO Offsets */ @@ -479,19 +483,26 @@ { return ( ( a && ! b ) || ( ! a && b ) ); } -#define XOR8( a, b, c, d, e, f, g, h ) xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) +#define XOR8( a, b, c, d, e, f, g, h ) xor( a, xor( b, xor( c, xor( d, xor( e, x +or( f, xor( g, h ) ) ) ) ) ) ) #define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) inline u32 TLan_HashFunc( u8 *a ) { u32 hash; - hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) ); - hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1; - hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2; - hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3; - hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4; - hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5; + hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,3 +6), DA(a,42) ); + hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,3 +7), DA(a,43) ) << 1; + hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,3 +8), DA(a,44) ) << 2; + hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,3 +9), DA(a,45) ) << 3; + hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,4 +0), DA(a,46) ) << 4; + hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,4 +1), DA(a,47) ) << 5; return hash; diff -u --recursive --new-file v2.1.66/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.66/linux/drivers/net/tulip.c Thu Jul 17 10:06:05 1997 +++ linux/drivers/net/tulip.c Sat Nov 29 10:33:20 1997 @@ -368,7 +368,7 @@ u_char sign[EE_SIGNLEN]; }; -static int read_eeprom(int ioaddr, struct eeprom *eepp); +static int read_eeprom(unsigned long ioaddr, struct eeprom *eepp); static int tulip_open(struct device *dev); static void tulip_init_ring(struct device *dev); static int tulip_start_xmit(struct sk_buff *skb, struct device *dev); @@ -462,7 +462,7 @@ #define tio_read(port) inl(ioaddr + port) static void inline -tio_sia_write(u32 ioaddr, u32 val13, u32 val14, u32 val15) +tio_sia_write(unsigned long ioaddr, u32 val13, u32 val14, u32 val15) { tio_write(0,CSR13); tio_write(val15,CSR15); @@ -490,7 +490,7 @@ } __initfunc(static int -read_eeprom(int ioaddr, struct eeprom *eepp)) +read_eeprom(unsigned long ioaddr, struct eeprom *eepp)) { int i, n; unsigned short val = 0; @@ -524,8 +524,8 @@ /* Terminate the EEPROM access. */ tio_write(EE_ENB & ~EE_CS, CSR9); - *p ++ = val; - *p ++ = val >> 8; + *p ++ = le16_to_cpu(val); + *p ++ = le16_to_cpu(val) >> 8; } /* broken eeprom ? */ p = (u_char *)eepp; @@ -538,7 +538,7 @@ static int generic21040_fail(struct device *dev) { - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; return(tio_read(CSR12) & TSIAS_CONERROR); } @@ -546,7 +546,7 @@ static int generic21041_fail(struct device *dev) { - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; u32 csr12 = tio_read(CSR12); return((!(csr12 & TSIAS_CONERROR) @@ -556,7 +556,7 @@ static void generic21040_select(struct device *dev) { - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; const char *media; dev->if_port &= 3; @@ -587,7 +587,7 @@ static void generic_timer(struct device *dev, u32 count) { - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; tio_write(count, CSR11); while (tio_read(CSR11) & TGEPT_COUNT); @@ -597,7 +597,7 @@ static void generic21041_select(struct device *dev) { - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; u32 tsiac = TSIAC_C21041; u32 tsiax = TSIAX_10TP; u32 tsiag = TSIAG_10TP; @@ -627,7 +627,8 @@ static void auto21140_select(struct device *dev) { - int i, ioaddr = dev->base_addr; + int i; + unsigned long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; /* kick port */ @@ -647,7 +648,7 @@ static void cogent21140_select(struct device *dev) { - int ioaddr = dev->base_addr, csr6; + unsigned long ioaddr = dev->base_addr, csr6; struct tulip_private *tp = (struct tulip_private *)dev->priv; dev->if_port &= 1; csr6 = tio_read(CSR6) & @@ -667,7 +668,7 @@ static void generic21140_select(struct device *dev) { - int ioaddr = dev->base_addr, csr6; + unsigned long ioaddr = dev->base_addr, csr6; struct tulip_private *tp = (struct tulip_private *)dev->priv; dev->if_port &= 1; @@ -689,7 +690,7 @@ tulip_open(struct device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; int i; /* Reset the chip, holding bit 0 set at least 10 PCI cycles. */ @@ -713,20 +714,20 @@ int *setup_frm = tp->setup_frame, i; /* You must add the broadcast address when doing perfect filtering! */ - *setup_frm++ = 0xffff; - *setup_frm++ = 0xffff; - *setup_frm++ = 0xffff; + *setup_frm++ = cpu_to_le32(0xffff); + *setup_frm++ = cpu_to_le32(0xffff); + *setup_frm++ = cpu_to_le32(0xffff); /* Fill the rest of the accept table with our physical address. */ for (i = 1; i < 16; i++) { - *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; + *setup_frm++ = cpu_to_le32(eaddrs[0]); + *setup_frm++ = cpu_to_le32(eaddrs[1]); + *setup_frm++ = cpu_to_le32(eaddrs[2]); } /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = 0x08000000 | 192; - tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); - tp->tx_ring[0].buffer2 = 0; - tp->tx_ring[0].status = TRING_OWN; + tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); + tp->tx_ring[0].buffer1 = cpu_to_le32(virt_to_bus(tp->setup_frame)); + tp->tx_ring[0].buffer2 = cpu_to_le32(0); + tp->tx_ring[0].status = cpu_to_le32(TRING_OWN); barrier(); tp->cur_tx++, tp->dirty_tx++; } @@ -744,7 +745,7 @@ tio_write(TPOLL_TRIGGER, CSR1); sti(); for (i = 0; i < 1000; i++) { - if (tp->tx_ring[0].status >= 0) { + if (((s32)le32_to_cpu(tp->tx_ring[0].status)) >= 0) { break; } udelay(1000); @@ -788,19 +789,19 @@ tp->dirty_rx = tp->dirty_tx = 0; for (i = 0; i < RX_RING_SIZE; i++) { - tp->rx_ring[i].status = TRING_OWN; - tp->rx_ring[i].length = PKT_BUF_SZ; - tp->rx_ring[i].buffer1 = virt_to_bus(tp->rx_buffs[i]); - tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]); + tp->rx_ring[i].status = cpu_to_le32(TRING_OWN); + tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); + tp->rx_ring[i].buffer1 = cpu_to_le32(virt_to_bus(tp->rx_buffs[i])); + tp->rx_ring[i].buffer2 = cpu_to_le32(virt_to_bus(&tp->rx_ring[i+1])); } /* Mark the last entry as wrapping the ring. */ - tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000; - tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]); + tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | 0x02000000); + tp->rx_ring[i-1].buffer2 = cpu_to_le32(virt_to_bus(&tp->rx_ring[0])); /* The Tx buffer descriptor is filled in as needed, but we do need to clear the ownership bit. */ for (i = 0; i < TX_RING_SIZE; i++) { - tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].status = cpu_to_le32(0x00000000); } } @@ -808,7 +809,7 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; int entry, len; unsigned long daddr; @@ -827,16 +828,16 @@ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", dev->name, tio_read(CSR5), tio_read(CSR12), tio_read(CSR13), tio_read(CSR14), tio_read(CSR15)); -#ifndef __alpha__ +#if !defined(__alpha__) && !defined(__sparc_v9__) printk(" Rx ring %8.8x: ", (int)tp->rx_ring); #endif for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); -#ifndef __alpha__ + printk(" %8.8x", (unsigned int)le32_to_cpu(tp->rx_ring[i].status)); +#if !defined(__alpha__) && !defined(__sparc_v9__) printk("\n Tx ring %8.8x: ", (int)tp->tx_ring); #endif for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk(" %8.8x", (unsigned int)le32_to_cpu(tp->tx_ring[i].status)); printk("\n"); tp->stats.tx_errors++; @@ -853,13 +854,6 @@ return(0); } - if (skb == NULL || (skb != (struct sk_buff *) -1 && skb->len <= 0)) { - printk("%s: Obsolete driver layer request made: skbuff==NULL.\n", - dev->name); - dev_tint(dev); - return(0); - } - /* 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 this ever occurs the queue layer is doing something evil! */ @@ -880,7 +874,11 @@ */ if (skb == (struct sk_buff *) -1) { daddr = virt_to_bus((char *)tp->setup_frame); +#ifdef NO_ANK_FIX len = 192; +#else + len = 192 | 0x08000000; +#endif skb = NULL; } else { daddr = virt_to_bus(skb->data); @@ -888,11 +886,11 @@ tp->stats.tx_bytes+=len; } tp->tx_skbuff[entry] = skb; - tp->tx_ring[entry].length = len | - (entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000); - tp->tx_ring[entry].buffer1 = daddr; - tp->tx_ring[entry].buffer2 = 0; - tp->tx_ring[entry].status = TRING_OWN; /* Pass ownership to the chip. */ + tp->tx_ring[entry].length = cpu_to_le32(len | + (entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000)); + tp->tx_ring[entry].buffer1 = cpu_to_le32(daddr); + tp->tx_ring[entry].buffer2 = cpu_to_le32(0); + tp->tx_ring[entry].status = cpu_to_le32(TRING_OWN); /* Pass ownership to the chip. */ barrier(); tp->cur_tx++; @@ -911,7 +909,8 @@ { struct device *dev = (struct device *)dev_id; struct tulip_private *lp; - int csr5, ioaddr, boguscnt=10; + int csr5, boguscnt=10; + unsigned long ioaddr; if (dev == NULL) { printk ("tulip_interrupt(): irq %d for unknown device.\n", irq); @@ -940,7 +939,7 @@ while (dirty_tx < lp->cur_tx) { int entry = dirty_tx % TX_RING_SIZE; - int status = lp->tx_ring[entry].status; + int status = le32_to_cpu(lp->tx_ring[entry].status); if (status < 0) break; /* It still hasn't been Txed */ @@ -1034,8 +1033,8 @@ int i; /* If we own the next entry, it's a new packet. Send it up. */ - while (lp->rx_ring[entry].status >= 0) { - int status = lp->rx_ring[entry].status; + while (((s32)le32_to_cpu(lp->rx_ring[entry].status)) >= 0) { + int status = le32_to_cpu(lp->rx_ring[entry].status); if ((status & TRING_RxDESCMASK) != TRING_RxDESCMASK) { printk("%s: Ethernet frame spanned multiple buffers," @@ -1050,7 +1049,7 @@ } else { /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - short pkt_len = (lp->rx_ring[entry].status >> 16) - 4; + short pkt_len = (le32_to_cpu(lp->rx_ring[entry].status) >> 16) - 4; struct sk_buff *skb; skb = dev_alloc_skb(pkt_len + 2); @@ -1060,12 +1059,12 @@ /* Check that at least two ring entries are free. If not, free one and mark stats->rx_dropped++. */ for (i=0; i < RX_RING_SIZE; i++) - if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0) + if (((s32)le32_to_cpu(lp->rx_ring[(entry+i) % RX_RING_SIZE].status)) < 0) break; if (i > RX_RING_SIZE -2) { lp->stats.rx_dropped++; - lp->rx_ring[entry].status = TRING_OWN; + lp->rx_ring[entry].status = cpu_to_le32(TRING_OWN); lp->cur_rx++; } break; @@ -1081,7 +1080,7 @@ lp->stats.rx_bytes+=skb->len; } - lp->rx_ring[entry].status = TRING_OWN; + lp->rx_ring[entry].status = cpu_to_le32(TRING_OWN); entry = (++lp->cur_rx) % RX_RING_SIZE; } return(0); @@ -1090,7 +1089,7 @@ static int tulip_close(struct device *dev) { - int ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; dev->start = 0; @@ -1129,7 +1128,7 @@ static struct net_device_stats *tulip_get_stats(struct device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - /* short ioaddr = dev->base_addr;*/ + /* unsigned long ioaddr = dev->base_addr;*/ return(&tp->stats); } @@ -1140,7 +1139,7 @@ static void set_multicast_list(struct device *dev) { - short ioaddr = dev->base_addr; + unsigned long ioaddr = dev->base_addr; int csr6 = tio_read(CSR6) & ~(TCMOD_MODEMASK|TCMOD_FILTERMASK); if (dev->flags&IFF_PROMISC) @@ -1169,20 +1168,20 @@ for (i = 0; i < dev->mc_count; i ++) { eaddrs=(unsigned short *)dmi->dmi_addr; dmi=dmi->next; - *setup_frm++ = *eaddrs++; - *setup_frm++ = *eaddrs++; - *setup_frm++ = *eaddrs++; + *setup_frm++ = cpu_to_le32(*eaddrs++); + *setup_frm++ = cpu_to_le32(*eaddrs++); + *setup_frm++ = cpu_to_le32(*eaddrs++); } /* Fill the rest of the table with our physical address. */ eaddrs = (unsigned short *)dev->dev_addr; /* Always accept broadcast packets */ - *setup_frm++ = 0xffff; - *setup_frm++ = 0xffff; - *setup_frm++ = 0xffff; + *setup_frm++ = cpu_to_le32(0xffff); + *setup_frm++ = cpu_to_le32(0xffff); + *setup_frm++ = cpu_to_le32(0xffff); do { - *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; + *setup_frm++ = cpu_to_le32(eaddrs[0]); + *setup_frm++ = cpu_to_le32(eaddrs[1]); + *setup_frm++ = cpu_to_le32(eaddrs[2]); } while (++i < 15); /* Now add this frame to the Tx list. */ @@ -1191,7 +1190,7 @@ } __initfunc(int -tulip_hwinit(struct device *dev, int ioaddr, +tulip_hwinit(struct device *dev, unsigned long ioaddr, int irq, int device_id)) { /* See note below on the Znyx 315 etherarray. */ @@ -1203,7 +1202,7 @@ unsigned short sum, bitsum; if (check_region(ioaddr, TULIP_TOTAL_SIZE) != 0) { - printk("tulip_hwinit: region already allocated at %#3x.\n", + printk("tulip_hwinit: region already allocated at %#3lx.\n", ioaddr); return(-1); } @@ -1258,7 +1257,7 @@ } /* Make certain the data structures are quadword aligned. */ - mesgp += sprintf(mesgp, ") at %#3x, ", ioaddr); + mesgp += sprintf(mesgp, ") at %016lx, ", ioaddr); /* On the Zynx 315 etherarray boards only the first Tulip has an EEPROM. The addresses of the subsequent ports are derived from the first. */ @@ -1324,8 +1323,15 @@ __initfunc(int tulip_probe(struct device *dev)) { static struct device *tulip_head=NULL; - u_char pci_bus, pci_device_fn, pci_latency, pci_irq; - u_int pci_ioaddr; +#ifdef __sparc_v9__ + struct pci_dev *pdev; +#else + u_char btmp; + u_int itmp; +#endif + u_char pci_bus, pci_device_fn, pci_latency; + u_int pci_irq; + unsigned long pci_ioaddr; u_short pci_command, vendor_id, device_id; u_int pci_chips[] = { PCI_DEVICE_ID_DEC_TULIP, @@ -1336,27 +1342,48 @@ int num=0, cno; static int pci_index = 0; - if (!pcibios_present()) return(-ENODEV); + if (!pcibios_present()) + return(-ENODEV); for (; pci_index < 0xff; pci_index++) { if (pcibios_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; +#ifdef __sparc_v9__ + for(pdev = pci_devices; pdev; pdev = pdev->next) + if(pdev->bus->number == pci_bus && + pdev->devfn == pci_device_fn) + break; + if(!pdev) + panic("tulip: Cannot find pci_dev for [%x:%x]\n", + pci_bus, pci_device_fn); +#endif + /* get vendor id */ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor_id); - /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, - &pci_irq); - /* get device id */ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device_id); +#ifndef __sparc_v9__ /* get IO address */ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, - &pci_ioaddr); + &itmp); + pci_ioaddr = itmp; + + /* get IRQ */ + pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, + &btmp); + pci_irq = btmp; +#else + /* get IO address */ + pci_ioaddr = pdev->base_address[0]; + + /* get IRQ */ + pci_irq = pdev->irq; +#endif /* Remove I/O space marker in bit 0. */ pci_ioaddr &= ~3; diff -u --recursive --new-file v2.1.66/linux/drivers/net/tunnel.c linux/drivers/net/tunnel.c --- v2.1.66/linux/drivers/net/tunnel.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/tunnel.c Wed Dec 31 16:00:00 1969 @@ -1,305 +0,0 @@ -/* tunnel.c: an IP tunnel driver - - The purpose of this driver is to provide an IP tunnel through - which you can tunnel network traffic transparently across subnets. - - This was written by looking at Nick Holloway's dummy driver - Thanks for the great code! - - -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 - - Minor tweaks: - Cleaned up the code a little and added some pre-1.3.0 tweaks. - dev->hard_header/hard_header_len changed to use no headers. - Comments/bracketing tweaked. - Made the tunnels use dev->name not tunnel: when error reporting. - Added tx_dropped stat - - -Alan Cox (Alan.Cox@linux.org) 21 March 95 - - Reworked: - Changed to tunnel to destination gateway in addition to the - tunnel's pointopoint address - Almost completely rewritten - Note: There is currently no firewall or ICMP handling done. - - -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96 - -*/ - -/* Things I wish I had known when writing the tunnel driver: - - When the tunnel_xmit() function is called, the skb contains the - packet to be sent (plus a great deal of extra info), and dev - contains the tunnel device that _we_ are. - - When we are passed a packet, we are expected to fill in the - source address with our source IP address. - - What is the proper way to allocate, copy and free a buffer? - After you allocate it, it is a "0 length" chunk of memory - starting at zero. If you want to add headers to the buffer - later, you'll have to call "skb_reserve(skb, amount)" with - the amount of memory you want reserved. Then, you call - "skb_put(skb, amount)" with the amount of space you want in - the buffer. skb_put() returns a pointer to the top (#0) of - that buffer. skb->len is set to the amount of space you have - "allocated" with skb_put(). You can then write up to skb->len - bytes to that buffer. If you need more, you can call skb_put() - again with the additional amount of space you need. You can - find out how much more space you can allocate by calling - "skb_tailroom(skb)". - Now, to add header space, call "skb_push(skb, header_len)". - This creates space at the beginning of the buffer and returns - a pointer to this new space. If later you need to strip a - header from a buffer, call "skb_pull(skb, header_len)". - skb_headroom() will return how much space is left at the top - of the buffer (before the main data). Remember, this headroom - space must be reserved before the skb_put() function is called. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/*#define TUNNEL_DEBUG*/ - -/* - * Our header is a simple IP packet with no options - */ - -#define tunnel_hlen sizeof(struct iphdr) - -/* - * Okay, this needs to be high enough that we can fit a "standard" - * ethernet header and an IP tunnel header into the outgoing packet. - * [36 bytes] - */ - -#define TUNL_HLEN (((ETH_HLEN+15)&~15)+tunnel_hlen) - - -static int tunnel_open(struct device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int tunnel_close(struct device *dev) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -#ifdef TUNNEL_DEBUG -void print_ip(struct iphdr *ip) -{ - unsigned char *ipaddr; - - printk("IP packet:\n"); - printk("--- header len = %d\n", ip->ihl*4); - printk("--- ip version: %d\n", ip->version); - printk("--- ip protocol: %d\n", ip->protocol); - ipaddr=(unsigned char *)&ip->saddr; - printk("--- source address: %u.%u.%u.%u\n", - *ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3)); - ipaddr=(unsigned char *)&ip->daddr; - printk("--- destination address: %u.%u.%u.%u\n", - *ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3)); - printk("--- total packet len: %d\n", ntohs(ip->tot_len)); -} -#endif - -/* - * This function assumes it is being called from dev_queue_xmit() - * and that skb is filled properly by that function. - */ - -static int tunnel_xmit(struct sk_buff *skb, struct device *dev) -{ - struct net_device_stats *stats; /* This device's statistics */ - struct rtable *rt; /* Route to the other host */ - struct device *tdev; /* Device to other host */ - struct iphdr *iph; /* Our new IP header */ - int max_headroom; /* The extra header space needed */ - - stats = (struct net_device_stats *)dev->priv; - - /* - * First things first. Look up the destination address in the - * routing tables - */ - iph = skb->nh.iph; - - if (ip_route_output(&rt, dev->pa_dstaddr, dev->pa_addr, RT_TOS(iph->tos), NULL)) { - /* No route to host */ - printk ( KERN_INFO "%s: Can't reach target gateway!\n", dev->name); - stats->tx_errors++; - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - tdev = rt->u.dst.dev; - - if (tdev->type == ARPHRD_TUNNEL) { - /* Tunnel to tunnel? -- I don't think so. */ - printk ( KERN_INFO "%s: Packet targetted at myself!\n" , dev->name); - ip_rt_put(rt); - stats->tx_errors++; - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - - skb->h.ipiph = skb->nh.iph; - - /* - * Okay, now see if we can stuff it in the buffer as-is. - */ - max_headroom = (((tdev->hard_header_len+15)&~15)+tunnel_hlen); - - if (skb_headroom(skb) < max_headroom || skb_shared(skb)) { - struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); - if (!new_skb) { - ip_rt_put(rt); - stats->tx_dropped++; - dev_kfree_skb(skb, FREE_WRITE); - return 0; - } - dev_kfree_skb(skb, FREE_WRITE); - skb = new_skb; - } - - skb->nh.iph = (struct iphdr *) skb_push(skb, tunnel_hlen); - dst_release(skb->dst); - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - dst_release(skb->dst); - skb->dst = &rt->u.dst; - - /* - * Push down and install the IPIP header. - */ - - iph = skb->nh.iph; - iph->version = 4; - iph->tos = skb->h.ipiph->tos; - iph->ttl = skb->h.ipiph->ttl; - iph->frag_off = 0; - iph->daddr = dev->pa_dstaddr; - iph->saddr = dev->pa_addr; - iph->protocol = IPPROTO_IPIP; - iph->ihl = 5; - iph->tot_len = htons(skb->len); - iph->id = htons(ip_id_count++); /* Race condition here? */ - ip_send_check(iph); - - stats->tx_bytes+=skb->len; - - ip_send(skb); - - /* Record statistics and return */ - stats->tx_packets++; - return 0; -} - -static struct net_device_stats *tunnel_get_stats(struct device *dev) -{ - return((struct net_device_stats*) dev->priv); -} - -/* - * Called when a new tunnel device is initialized. - * The new tunnel device structure is passed to us. - */ - -__initfunc(int tunnel_init(struct device *dev)) -{ - /* Oh, just say we're here, in case anyone cares */ - static int tun_msg=0; - if(!tun_msg) - { - printk ( KERN_INFO "tunnel: version v0.2b2\n" ); - tun_msg=1; - } - - /* Add our tunnel functions to the device */ - dev->open = tunnel_open; - dev->stop = tunnel_close; - dev->hard_start_xmit = tunnel_xmit; - dev->get_stats = tunnel_get_stats; - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_device_stats)); - - /* Initialize the tunnel device structure */ - - dev_init_buffers(dev); - - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update= NULL; - - dev->type = ARPHRD_TUNNEL; - dev->hard_header_len = TUNL_HLEN; - dev->mtu = 1500-tunnel_hlen; /* eth_mtu */ - dev->addr_len = 0; /* Is this only for ARP? */ - dev->tx_queue_len = 2; /* Small queue */ - memset(dev->broadcast,0xFF, ETH_ALEN); - - /* New-style flags. */ - dev->flags = IFF_NOARP; /* Don't use ARP on this device */ - /* No broadcasting through a tunnel */ - dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; - - /* We're done. Have I forgotten anything? */ - return 0; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* Module specific interface */ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifdef MODULE - - -static char tunnel_name[16]; - -static struct device dev_tunnel = -{ - tunnel_name, - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, tunnel_init - }; - -int init_module(void) -{ - /* Find a name for this unit */ - int err=dev_alloc_name(&dev_tunnel, "tunl%d"); - if(err<0) - return err; - -#ifdef TUNNEL_DEBUG - printk("tunnel: registering device %s\n", dev_tunnel.name); -#endif - if (register_netdev(&dev_tunnel) != 0) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - unregister_netdev(&dev_tunnel); - kfree_s(dev_tunnel.priv,sizeof(struct net_device_stats)); - dev_tunnel.priv=NULL; -} -#endif /* MODULE */ - diff -u --recursive --new-file v2.1.66/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c --- v2.1.66/linux/drivers/net/x25_asy.c Tue Sep 23 16:48:48 1997 +++ linux/drivers/net/x25_asy.c Sat Nov 29 10:33:20 1997 @@ -662,7 +662,12 @@ if (!sl || sl->magic != X25_ASY_MAGIC) return; - (void) dev_close(sl->dev); + if (sl->dev->flags & IFF_UP) + { + dev_lock_wait(); + (void) dev_close(sl->dev); + dev_unlock_list(); + } tty->disc_data = 0; sl->tty = NULL; @@ -896,11 +901,6 @@ /* New-style flags. */ dev->flags = IFF_NOARP; - dev->family = AF_X25; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = 4; return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/net/zlib.c linux/drivers/net/zlib.c --- v2.1.66/linux/drivers/net/zlib.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/zlib.c Sat Nov 29 10:33:20 1997 @@ -0,0 +1,5380 @@ +/* + * This file is derived from various .h and .c files from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. See zlib.h for conditions of + * distribution and use. + * + * Changes that have been made include: + * - added Z_PACKET_FLUSH (see zlib.h for details) + * - added inflateIncomp and deflateOutputPending + * - changed DEBUG_ZLIB to DEBUG_ZLIB + * - use ZALLOC_INIT rather than ZALLOC for allocations during initialization + * - allow strm->next_out to be NULL, meaning discard the output + * + * $Id: zlib.c,v 1.2 1997/10/02 17:59:23 davem Exp $ + */ + +/* + * ==FILEVERSION 970501== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + +#define NO_DUMMY_DECL +#define NO_ZCFUNCS +#define MY_ZCALLOC + +#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */ +#endif + + +/* +++ zutil.h */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#if defined(KERNEL) || defined(_KERNEL) +/* Assume this is a *BSD kernel */ +#include +#include +#include +# define HAVE_MEMCPY +# define zmemcpy(d, s, n) bcopy((s), (d), (n)) +# define zmemzero bzero +# define zmemcmp bcmp + +#else +#if defined(__KERNEL__) +/* Assume this is a Linux kernel */ +#include +#define HAVE_MEMCPY +#define zmemcpy memcpy +#define zmemzero(dest, len) memset(dest, 0, len) +#define zmemcmp memcmp + +#else /* not kernel */ + +#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS) +# include +# include +#else + extern int errno; +#endif +#ifdef STDC +# include +# include +#endif +#endif /* __KERNEL__ */ +#endif /* _KERNEL || KERNEL */ + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# ifdef __TURBOC__ +# include +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define FOPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef MACOS +# define OS_CODE 0x07 +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef FOPEN +# define FOPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); + extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include +# ifndef verbose +# define verbose 0 +# endif + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ +/* --- zutil.h */ + +/* +++ deflate.h */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +/* #include "zutil.h" */ + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct deflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + ulg compressed_len; /* total bit length of compressed file */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG_ZLIB + ulg bits_sent; /* bit length of the compressed data */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_stored_type_only OF((deflate_state *)); + +#endif +/* --- deflate.h */ + +/* +++ deflate.c */ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */ + +/* #include "deflate.h" */ + +char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG_ZLIB +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int noheader = 0; + static char* my_version = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; +#ifndef NO_ZCFUNCS + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; +#endif + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + + s = (deflate_state *) strm->state; + if (s->status != INIT_STATE) return Z_STREAM_ERROR; + + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy((charf *)s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = (deflate_state *) strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + deflate_state *s = (deflate_state *) strm->state; + unsigned len = s->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + if (strm->next_out != NULL) { + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + } + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* ========================================================================= */ +int deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) strm->state; + + if ((strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush == Z_PACKET_FLUSH) { + /* Output just the 3-bit `stored' block type value, + but not a zero length. */ + _tr_stored_type_only(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int deflateEnd (strm) + z_streamp strm; +{ + int status; + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = (deflate_state *) strm->state; + + status = s->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, s->pending_buf); + TRY_FREE(strm, s->head); + TRY_FREE(strm, s->prev); + TRY_FREE(strm, s->window); + + ZFREE(strm, s); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + */ +int deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) + return Z_STREAM_ERROR; + ss = (deflate_state *) source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* ??? following zmemcpy doesn't work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +} + +/* =========================================================================== + * Return the number of bytes of output which are immediately available + * for output from the decompressor. + */ +int deflateOutputPending (strm) + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return 0; + + return ((deflate_state *)(strm->state))->pending; +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + charf *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!((deflate_state *)(strm->state))->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#ifdef DEBUG_ZLIB +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp((charf *)s->window + match, + (charf *)s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy((charf *)s->window, (charf *)s->window+wsize, + (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, + more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + bflush = _tr_tally(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + bflush = _tr_tally (s, 0, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + bflush = _tr_tally(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + if (_tr_tally (s, 0, s->window[s->strstart-1])) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally (s, 0, s->window[s->strstart-1]); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +/* --- deflate.c */ + +/* +++ trees.c */ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ + +/* #include "deflate.h" */ + +#ifdef DEBUG_ZLIB +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +local uch dist_code[512]; +/* distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +local uch length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +struct static_tree_desc_s { + ct_data *static_tree; /* static tree or NULL */ + intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifndef DEBUG_ZLIB +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG_ZLIB */ +# define send_code(s, c, tree) \ + { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +#define d_code(dist) \ + ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. dist_code[256] and dist_code[257] are never + * used. + */ + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG_ZLIB +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG_ZLIB */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG_ZLIB */ + + +#define MAX(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. In a multi-threaded environment, + * this function may be called by two threads concurrently, but this is + * harmless since both invocations do exactly the same thing. + */ +local void tr_static_init() +{ + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; +} + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->compressed_len = 0L; + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG_ZLIB + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + ct_data *stree = desc->stat_desc->static_tree; + intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* Send just the `stored block' type code without any length bytes or data. + */ +void _tr_stored_type_only(s) + deflate_state *s; +{ + send_bits(s, (STORED_BLOCK << 1), 3); + bi_windup(s); + s->compressed_len = (s->compressed_len + 3) & ~7L; +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length for the file so far. + */ +ulg _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + /* If compression failed and this is the first and last block, + * and if the .zip file can be seeked (to rewrite the local header), + * the whole file is transformed into a stored file: + */ +#ifdef STORED_FILE_OK +# ifdef FORCE_STORED_FILE + if (eof && s->compressed_len == 0L) { /* force stored file */ +# else + if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { +# endif + /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ + if (buf == (charf*)0) error ("block vanished"); + + copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ + s->compressed_len = stored_len << 3; + s->method = STORED; + } else +#endif /* STORED_FILE_OK */ + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); + s->compressed_len += 3 + s->static_len; + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); + s->compressed_len += 3 + s->opt_len; + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + init_block(s); + + if (eof) { + bi_windup(s); + s->compressed_len += 7; /* align on byte boundary */ + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); + + return s->compressed_len >> 3; +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + + /* Try to guess if it is profitable to stop the current block here */ + if (s->level > 2 && (s->last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG_ZLIB + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG_ZLIB + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG_ZLIB + s->bits_sent += (ulg)len<<3; +#endif + /* bundle up the put_byte(s, *buf++) calls */ + zmemcpy(&s->pending_buf[s->pending], buf, len); + s->pending += len; +} +/* --- trees.c */ + +/* +++ inflate.c */ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ + +/* +++ infblock.h */ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_addhistory OF(( + inflate_blocks_statef *, + z_streamp)); + +extern int inflate_packet_flush OF(( + inflate_blocks_statef *)); +/* --- infblock.h */ + +#ifndef NO_DUMMY_DECL +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ +#endif + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z) +z_streamp z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z) +z_streamp z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; +#ifndef NO_ZCFUNCS + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; +#endif + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) + r = inflate_packet_flush(z->state->blocks); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + + empty: + if (f != Z_PACKET_FLUSH) + return r; + z->state->mode = BAD; + z->msg = (char *)"need more for packet flush"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_DATA_ERROR; +} + + +int inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ + +int inflateIncomp(z) +z_stream *z; +{ + if (z->state->mode != BLOCKS) + return Z_DATA_ERROR; + return inflate_addhistory(z->state->blocks, z); +} + + +int inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + +#undef NEEDBYTE +#undef NEXTBYTE +/* --- inflate.c */ + +/* +++ infblock.c */ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "infblock.h" */ + +/* +++ inftrees.h */ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG_ZLIB + extern uInt inflate_hufts; +#endif + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +extern int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_streamp )); /* for zfree function */ + +/* --- inftrees.h */ + +/* +++ infcodes.h */ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* --- infcodes.h */ + +/* +++ infutil.h */ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONEB, /* finished last block, done */ + BADB} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl; + inflate_huft *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#endif +/* --- infutil.h */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +#ifdef DEBUG_ZLIB + extern uInt inflate_hufts; +#endif +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BADB; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BADB; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BADB; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BADB; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + inflate_trees_free(s->sub.trees.tb, z); + ZFREE(z, s->sub.trees.blens); + s->mode = BADB; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; +#ifdef DEBUG_ZLIB + inflate_hufts = 0; +#endif + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BADB; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", + inflate_hufts, sizeof(inflate_huft))); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONEB; + case DONEB: + r = Z_STREAM_END; + LEAVE + case BADB: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window); + ZFREE(z, s); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy((charf *)s->window, d, n); + s->read = s->write = s->window + n; +} + +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output (hence s->read equals s->write), and the state must + * be BLOCKS (i.e. we should be willing to see the start of a series of + * BLOCKS). On exit, the output will also be caught up, and the checksum + * will have been updated if need be. + */ +int inflate_addhistory(s, z) +inflate_blocks_statef *s; +z_stream *z; +{ + uLong b; /* bit buffer */ /* NOT USED HERE */ + uInt k; /* bits in bit buffer */ /* NOT USED HERE */ + uInt t; /* temporary storage */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + if (s->read != s->write) + return Z_STREAM_ERROR; + if (s->mode != TYPE) + return Z_DATA_ERROR; + + /* we're ready to rock */ + LOAD + /* while there is input ready, copy to output buffer, moving + * pointers as needed. + */ + while (n) { + t = n; /* how many to do */ + /* is there room until end of buffer? */ + if (t > m) t = m; + /* update check information */ + if (s->checkfn != Z_NULL) + s->check = (*s->checkfn)(s->check, q, t); + zmemcpy(q, p, t); + q += t; + p += t; + n -= t; + z->total_out += t; + s->read = q; /* drag read pointer forward */ +/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ + if (q == s->end) { + s->read = q = s->window; + m = WAVAIL; + } + } + UPDATE + return Z_OK; +} + + +/* + * At the end of a Deflate-compressed PPP packet, we expect to have seen + * a `stored' block type value but not the (zero) length bytes. + */ +int inflate_packet_flush(s) + inflate_blocks_statef *s; +{ + if (s->mode != LENS) + return Z_DATA_ERROR; + s->mode = TYPE; + return Z_OK; +} +/* --- infblock.c */ + +/* +++ inftrees.c */ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ + +char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_streamp )); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG_ZLIB + uInt inflate_hufts; +#endif + +local int huft_build(b, n, s, d, e, t, m, zs) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= N_MAX) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +const uIntf *d; /* list of base values for non-simple codes */ +const uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +z_streamp zs; /* for zalloc function */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } +#ifdef DEBUG_ZLIB + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +z_streamp z; /* for zfree function */ +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + inflate_trees_free(*tb, z); + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for zfree function */ +{ + int r; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc(q, n, s) +voidpf q; /* opaque pointer */ +uInt n; /* number of items */ +uInt s; /* size of item */ +{ + Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, + "inflate_trees falloc overflow"); + *(intf *)q -= n+s-s; /* s-s to avoid warning */ + return (voidpf)(fixed_mem + *(intf *)q); +} + + +int inflate_trees_fixed(bl, bd, tl, td) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +{ + /* build fixed tables if not already (multiple overlapped executions ok) */ + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + int f = FIXEDH; /* number of hufts left in fixed_mem */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = Z_NULL; + z.opaque = (voidpf)&f; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + Assert(f == 0, "invalid build of fixed tables"); + fixed_built = 1; + } + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +int inflate_trees_free(t, z) +inflate_huft *t; /* table to free */ +z_streamp z; /* for zfree function */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q, *r; + + /* Reverse linked list */ + p = Z_NULL; + q = t; + while (q != Z_NULL) + { + r = (q - 1)->next; + (q - 1)->next = p; + p = q; + q = r; + } + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z,p); + p = q; + } + return Z_OK; +} +/* --- inftrees.c */ + +/* +++ infcodes.c */ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ +/* #include "infblock.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ + +/* +++ inffast.h */ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); +/* --- inffast.h */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} +/* --- infcodes.c */ + +/* +++ infutil.c */ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "infblock.h" */ +/* #include "inftrees.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + if (p != NULL) { + zmemcpy(p, q, n); + p += n; + } + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + if (p != NULL) { + zmemcpy(p, q, n); + p += n; + } + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} +/* --- infutil.c */ + +/* +++ inffast.c */ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* #include "zutil.h" */ +/* #include "inftrees.h" */ +/* #include "infblock.h" */ +/* #include "infcodes.h" */ +/* #include "infutil.h" */ +/* #include "inffast.h" */ + +#ifndef NO_DUMMY_DECL +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} +/* --- inffast.c */ + +/* +++ zutil.c */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ + +#ifdef DEBUG_ZLIB +#include +#endif + +/* #include "zutil.h" */ + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char *zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG_ZLIB +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + Bytef* s1; + Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER < 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ +/* --- zutil.c */ + +/* +++ adler32.c */ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ + +/* #include "zlib.h" */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} +/* --- adler32.c */ diff -u --recursive --new-file v2.1.66/linux/drivers/net/zlib.h linux/drivers/net/zlib.h --- v2.1.66/linux/drivers/net/zlib.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/zlib.h Sat Nov 29 10:33:20 1997 @@ -0,0 +1,1010 @@ +/* $Id: zlib.h,v 1.1 1997/10/02 02:35:37 paulus Exp $ */ + +/* + * This file is derived from zlib.h and zconf.h from the zlib-0.95 + * distribution by Jean-loup Gailly and Mark Adler, with some additions + * by Paul Mackerras to aid in implementing Deflate compression and + * decompression for PPP packets. + */ + +/* + * ==FILEVERSION 970501== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. + */ + + +/* +++ zlib.h */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.0.4, Jul 24th, 1996. + + Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +++ zconf.h */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateReset z_inflateReset +# define compress z_compress +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC) +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + 1 << (windowBits+2) + 1 << (memLevel+9) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR __far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR __far +# endif +#endif +#ifndef FAR +# define FAR +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#if defined(__BORLANDC__) && defined(SMALL_MEDIUM) + /* Borland C/C++ ignores FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL) +# include +# define EXPORT WINAPI +#else +# define EXPORT +#endif + +#endif /* _ZCONF_H */ +/* --- zconf.h */ + +#define ZLIB_VERSION "1.0.4P" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms may be added later and will have the same + stream interface. + + For compression the application must provide the output buffer and + may optionally provide the input buffer for optimization. For decompression, + the application must provide the input buffer and may optionally provide + the output buffer for optimization. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library does not install any signal handler. It is recommended to + add at least a handler for SIGSEGV when decompressing; the library checks + the consistency of the input data whenever possible but may go nuts + for some forms of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_PACKET_FLUSH 2 +#define Z_SYNC_FLUSH 3 +#define Z_FULL_FLUSH 4 +#define Z_FINISH 5 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +extern const char * EXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +extern int EXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +extern int EXPORT deflate OF((z_streamp strm, int flush)); +/* + Performs one or both of the following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression + block is terminated and flushed to the output buffer so that the + decompressor can get all input data available so far. For method 9, a future + variant on method 8, the current block will be flushed but not terminated. + Z_SYNC_FLUSH has the same effect as partial flush except that the compressed + output is byte aligned (the compressor can clear its internal bit buffer) + and the current block is always terminated; this can be useful if the + compressor has to be restarted from scratch after an interruption (in which + case the internal state of the compressor may be lost). + If flush is set to Z_FULL_FLUSH, the compression block is terminated, a + special marker is output and the compression dictionary is discarded; this + is useful to allow the decompressor to synchronize if one compressed block + has been damaged (see inflateSync below). Flushing degrades compression and + so should be used only when necessary. Using Z_FULL_FLUSH too often can + seriously degrade the compression. If deflate returns with avail_out == 0, + this function must be called again with the same value of the flush + parameter and more output space (updated avail_out), until the flush is + complete (deflate returns with non-zero avail_out). + + If the parameter flush is set to Z_PACKET_FLUSH, the compression + block is terminated, and a zero-length stored block is output, + omitting the length bytes (the effect of this is that the 3-bit type + code 000 for a stored block is output, and the output is then + byte-aligned). This is designed for use at the end of a PPP packet. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. +*/ + + +extern int EXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +extern int EXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, inflateInit updates them to use default + allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_VERSION_ERROR if the zlib library version is incompatible + with the version assumed by the caller. msg is set to null if there is no + error message. inflateInit does not perform any decompression: this will be + done by inflate(). +*/ + + +extern int EXPORT inflate OF((z_streamp strm, int flush)); +/* + Performs one or both of the following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, + inflate flushes as much output as possible to the output buffer. The + flushing behavior of inflate is not specified for values of the flush + parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the + current implementation actually flushes as much output as possible + anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data + has been consumed, it is expecting to see the length field of a stored + block; if not, it returns Z_DATA_ERROR. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + inflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if the end of the + compressed data has been reached and all uncompressed output has been + produced, Z_NEED_DICT if a preset dictionary is needed at this point (see + inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted, + Z_STREAM_ERROR if the stream structure was inconsistent (for example if + next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in + the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the + application may then call inflateSync to look for a good compression block. + In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the + dictionary chosen by the compressor. +*/ + + +extern int EXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +extern int EXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. (Method 9 will allow a 64K history buffer and + partial block flushes.) + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library (the value 16 will be allowed for method 9). Larger + values of this parameter result in better compression at the expense of + memory usage. The default value is 15 if deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + If next_in is not null, the library will use this buffer to hold also + some history information; the buffer must either hold the entire input + data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in + is null, the library will allocate its own history buffer (and leave next_in + null). next_out need not be provided here but must be provided by the + application for the next call of deflate(). + + If the history buffer is provided by the application, next_in must + must never be changed by the application since the compressor maintains + information inside this buffer from call to call; the application + must provide more input only by increasing avail_in. next_in is always + reset by the library in this case. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was + not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as + an invalid method). msg is set to null if there is no error message. + deflateInit2 does not perform any compression: this will be done by + deflate(). +*/ + +extern int EXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary (history buffer) from the given + byte sequence without producing any compressed output. This function must + be called immediately after deflateInit or deflateInit2, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and + can be predicted with good accuracy; the data can then be compressed better + than with the default empty dictionary. In this version of the library, + only the last 32K bytes of the dictionary are used. + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state + is inconsistent (for example if deflate has already been called for this + stream). deflateSetDictionary does not perform any compression: this will + be done by deflate(). +*/ + +extern int EXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. If + the source stream is using an application-supplied history buffer, a new + buffer is allocated for the destination stream. The compressed output + buffer is always application-supplied. It's the responsibility of the + application to provide the correct values of next_out and avail_out for the + next call of deflate. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +extern int EXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy)); +/* + Dynamically update the compression level and compression strategy. + This can be used to switch between compression and straight copy of + the input data, or to switch to a different kind of input data requiring + a different strategy. If the compression level is changed, the input + available so far is compressed with the old level (and may be flushed); + the new level will take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +extern int EXPORT deflateOutputPending OF((z_streamp strm)); +/* + Returns the number of bytes of output which are immediately + available from the compressor (i.e. without any further input + or flush). +*/ + +/* +extern int EXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with more compression options. The + fields next_out, zalloc, zfree and opaque must be initialized before by + the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library (the value 16 will be allowed soon). The + default value is 15 if inflateInit is used instead. If a compressed stream + with a larger window size is given as input, inflate() will return with + the error code Z_DATA_ERROR instead of trying to allocate a larger window. + + If next_out is not null, the library will use this buffer for the history + buffer; the buffer must either be large enough to hold the entire output + data, or have at least 1<= 0) udelay(1000000); + while (--Seconds >= 0) { + int i = 1000; + do { + udelay(1000); + } while (--i); + } restore_flags(ProcessorFlags); } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v2.1.66/linux/drivers/sound/CHANGELOG Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/CHANGELOG Sat Nov 29 10:33:20 1997 @@ -1,3 +1,6 @@ +Note these changes relate to Hannu's code and don't include the changes +made outside of this for modularising the sound + Changelog for version 3.8o -------------------------- diff -u --recursive --new-file v2.1.66/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.66/linux/drivers/sound/Config.in Mon Nov 17 18:47:21 1997 +++ linux/drivers/sound/Config.in Sat Nov 29 10:33:20 1997 @@ -1,20 +1,22 @@ -bool 'ProAudioSpectrum 16 support' CONFIG_PAS -bool '100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB -bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB -bool 'Gravis Ultrasound support' CONFIG_GUS -bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 -bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS -bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 -bool 'GUS MAX support' CONFIG_GUSMAX -bool 'Microsoft Sound System support' CONFIG_MSS -bool 'Ensoniq SoundScape support' CONFIG_SSCAPE -bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX -bool 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 -bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 -bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI -bool 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 -bool 'SoftOSS software wave table engine' CONFIG_SOFTOSS -bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 +dep_tristate 'ProAudioSpectrum 16 support' CONFIG_PAS $CONFIG_SOUND +dep_tristate '100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND +dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB $CONFIG_SOUND +dep_tristate 'Gravis Ultrasound support' CONFIG_GUS $CONFIG_SOUND +dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 $CONFIG_SOUND +dep_tristate 'PSS (ECHO-ADI2111) support' CONFIG_PSS $CONFIG_SOUND +if [ "$CONFIG_GUS" != "n" ]; then + bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 + bool 'GUS MAX support' CONFIG_GUSMAX +fi +dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND +dep_tristate 'Ensoniq SoundScape support' CONFIG_SSCAPE $CONFIG_SOUND +dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_TRIX $CONFIG_SOUND +dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND +dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 $CONFIG_SOUND +dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI $CONFIG_SOUND +dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 $CONFIG_SOUND +dep_tristate 'SoftOSS software wave table engine' CONFIG_SOFTOSS $CONFIG_SOUND +dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND if [ "$CONFIG_AEDSP16" = "y" ]; then hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 @@ -309,8 +311,8 @@ bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then - bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER - bool 'AWE32 synth' CONFIG_AWE32_SYNTH + dep_tristate 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND + dep_tristate 'AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND bool 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 if [ "$CONFIG_AEDSP16" = "y" ]; then diff -u --recursive --new-file v2.1.66/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.66/linux/drivers/sound/Makefile Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/Makefile Sat Nov 29 10:33:20 1997 @@ -1,4 +1,4 @@ -BUILDCODE=o +BUILDCODE=s # Makefile for the Linux sound card driver # # Note 2! The CFLAGS definitions are now inherited from the @@ -32,108 +32,201 @@ kernelconfig: else -.PHONY: dummy -SUB_DIRS = lowlevel -VERSION = `head -1 .version` -TARGET_OS = linux -USRINCDIR = /usr/include -MODULEDIR = /lib/modules/misc - -FIXEDOBJS = soundcard.o dev_table.o sound_switch.o - -ifndef NO_LOWLEVEL - FIXEDOBJS := $(FIXEDOBJS) lowlevel/lowlevel.o -endif ifeq (.defines,$(wildcard .defines)) -include .defines +#include .defines include .objects endif +TARGET_OS=linux + ifndef TOPDIR TOPDIR=/usr/src/linux endif +SUB_DIRS := lowlevel +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := sound.a +M_OBJS := +L_OBJS := + +ifeq ($(CONFIG_SOUND),y) + L_OBJS += soundcard.o dev_table.o sound_switch.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o audio.o dmabuf.o +else + ifeq ($(CONFIG_SOUND),m) + M_OBJS += sound.o + MX_OBJS += sound_syms.o + endif +endif + +ifeq ($(CONFIG_MIDI),y) + L_OBJS += midibuf.o + LX_OBJS += midi_synth.o +endif + +ifeq ($(CONFIG_MIDI),y) + L_OBJS += midibuf.o + LX_OBJS += midi_synth.o +endif -ifndef HOSTCC -build: - @echo Compiling modularized sound driver - @make sound.o - @echo Sound module compiled. +#ifeq ($(CONFIG_AUDIO),y) +#L_OBJS += dmabuf.o +#endif -install: sound.o - cp sound.o $(MODULEDIR) +ifeq ($(CONFIG_YM3812),y) +LX_OBJS += opl3.o else + ifeq ($(CONFIG_YM3812),m) + MX_OBJS += opl3.o + endif endif -.c.o: - $(CC) $(CFLAGS) -c $< +ifeq ($(CONFIG_PAS),y) +L_OBJS += pas2_card.c pas2_midi.c pas2_mixer.c pas2_pcm.c +else + ifeq ($(CONFIG_PAS),m) + M_OBJS += pas2.o + endif +endif -ifeq ($(CONFIG_SOUND),y) +ifeq ($(CONFIG_GUS),y) +L_OBJS += gus_card.c gus_midi.c gus_vol.c gus_wave.c ics2101.c +else + ifeq ($(CONFIG_GUS),m) + M_OBJS += gus.o + endif +endif -all: local.h sound.a +ifeq ($(CONFIG_SB),y) +L_OBJS += sb_audio.o sb_common.o sb_midi.o sb_mixer.o +LX_OBJS += sb_card.o uart401.o +else + ifeq ($(CONFIG_SB),m) + M_OBJS += sb.o + MX_OBJS += sb_card.o uart401.o + endif +endif -OBJS += $(FIXEDOBJS) +ifeq ($(CONFIG_ADLIB),y) +LX_OBJS += ad1848.o +else + ifeq ($(CONFIG_ADLIB),m) + MX_OBJS += ad1848.o + endif +endif +ifeq ($(CONFIG_ADLIB),y) +LX_OBJS += adlib_card.o else -all: + ifeq ($(CONFIG_ADLIB),m) + MX_OBJS += adlib_card.o + endif endif -ifndef HOSTCC -# -# Running outside the kernel build. -# -CC = gcc -HOSTCC = gcc -CFLAGS = -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -pipe -m486 -USE_DEPEND=y +ifeq ($(CONFIG_MPU401),y) +LX_OBJS += mpu401.o else -include $(TOPDIR)/Rules.make + ifeq ($(CONFIG_MPU401),m) + MX_OBJS += mpu401.o + endif endif -sound.a: $(OBJS) - -rm -f sound.a - $(AR) rcs sound.a $(OBJS) - sync +ifeq ($(CONFIG_UART401),y) +LX_OBJS += uart401.o +else + ifeq ($(CONFIG_UART401),m) + MX_OBJS += uart401.o + endif +endif -clean: - rm -f core core.* *.o *.a tmp_make *~ x y z *% - rm -f configure - cd lowlevel;make clean +ifeq ($(CONFIG_UART6850),y) +LX_OBJS += uart6850.o +else + ifeq ($(CONFIG_UART6850),m) + MX_OBJS += uart6850.o + endif +endif -indent: - for n in *.c;do echo indent $$n;indent $$n;done +ifeq ($(CONFIG_PSS),y) +L_OBJS += pss.o +else + ifeq ($(CONFIG_PSS),m) + M_OBJS += pss.o + endif +endif -local.h: - $(MAKE) clean - $(MAKE) setup - $(MAKE) oldconfig - $(MAKE) dep - @echo - @echo - @echo - @echo NOTE! Object file dependencies may not be up to date. Run - @echo make again if kernel/driver doesn''t link properly. Restarting - @echo it now may save some time. - @echo - @echo - -config: configure - @$(MAKE) setup - @./configure > local.h - @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h - @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h -# @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h 2>/dev/null -# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null - @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h +ifeq ($(CONFIG_SSCAPE),y) +L_OBJS += sscape.o +else + ifeq ($(CONFIG_SSCAPE),m) + M_OBJS += sscape.o + endif +endif -oldconfig: setup configure - @./configure -o > local.h - @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h - @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h -# @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h 2>/dev/null -# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null - @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h +ifeq ($(CONFIG_TRIX),y) +L_OBJS += trix.o +else + ifeq ($(CONFIG_TRIX),m) + M_OBJS += trix.o + endif +endif + +ifeq ($(CONFIG_MAD16),y) +L_OBJS += mad16.o +else + ifeq ($(CONFIG_MAD16),m) + M_OBJS += mad16.o + endif +endif + +ifeq ($(CONFIG_CS4232),y) +LX_OBJS += cs4232.o +else + ifeq ($(CONFIG_CS4232),m) + MX_OBJS += cs4232.o + endif +endif + +ifeq ($(CONFIG_MAUI),y) +L_OBJS += maui.o +else + ifeq ($(CONFIG_MAUI),m) + M_OBJS += maui.o + endif +endif + +ifeq ($(CONFIG_SOFTOSS),y) +L_OBJS += softoss.o softoss_rs.o +else + ifeq ($(CONFIG_SOFTOSS),m) + M_OBJS += softoss2.o + endif +endif + +include $(TOPDIR)/Rules.make + +softoss2.o: softoss.o softoss_rs.o + ld -r -o softoss2.o softoss.o softoss_rs.o + +pas2.o: pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + ld -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + +sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o + ld -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o + +lowlevel/lowlevel.o: + cd lowlevel; make + +sound.o: soundcard.o dev_table.o sound_switch.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o + ld -r -o sound.o soundcard.o dev_table.o sound_switch.o audio.o dmabuf.o \ + sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \ + midi_synth.o midibuf.o sound_firmware.o + rm sound_syms.o + +gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o + ld -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o kernelconfig: setup rm -f configure @@ -146,49 +239,13 @@ # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h -mkscript: setup - rm -f configure - $(HOSTCC) -o configure configure.c - ./configure script > Config.in - cat lowlevel/Config.tmpl >> Config.in - ./configure fixedlocal > local.h - ./configure fixeddefines > .defines - -clrconf: - rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h maui_boot.h .defines - rm Config.in;cp Config.std Config.in - configure: configure.c $(HOSTCC) -o configure configure.c @cat .blurb -dep: - $(CPP) -M $(CFLAGS) -I. *.c > .depend - cd lowlevel;make dep - setup: @echo Compiling Sound Driver v $(VERSION) for Linux -sound.o: local.h $(FIXEDOBJS) sound.a - -rm -f sound.o - $(LD) -r -o sound.o $(FIXEDOBJS) sound.a - -modules: local.h sound.o - ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o - - -lowlevel/lowlevel.o: dummy - cd lowlevel;make CC="$(CC)" CFLAGS="$(CFLAGS)" - -contrib: - cd lowlevel;make clean;make module "CC=$(CC)" CFLAGS="$(CFLAGS)" +mkscript: -ifdef USE_DEPEND -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif -endif endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/README.FIRST linux/drivers/sound/README.FIRST --- v2.1.66/linux/drivers/sound/README.FIRST Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/README.FIRST Sat Nov 29 10:33:20 1997 @@ -0,0 +1,7 @@ +The modular sound driver patches where funded by Red Hat Software +(www.redhat.com). The sound driver here is thus a modified version of +Hannu's code. Please bear that in mind when considering the appropriate +forums for bug reporting. + +Alan Cox + diff -u --recursive --new-file v2.1.66/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.66/linux/drivers/sound/ad1848.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/ad1848.c Sat Nov 29 10:33:20 1997 @@ -21,8 +21,12 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include +#include +#include +#include "soundmodule.h" #define DEB(x) #define DEB1(x) @@ -34,23 +38,23 @@ typedef struct { - int base; - int irq; - int dma1, dma2; - int dual_dma; /* 1, when two DMA channels allocated */ - unsigned char MCE_bit; - unsigned char saved_regs[16]; - int debug_flag; - - int audio_flags; - int record_dev, playback_dev; - - int xfer_count; - int audio_mode; - int open_mode; - int intr_active; - char *chip_name, *name; - int model; + int base; + int irq; + int dma1, dma2; + int dual_dma; /* 1, when two DMA channels allocated */ + unsigned char MCE_bit; + unsigned char saved_regs[16]; + int debug_flag; + + int audio_flags; + int record_dev, playback_dev; + + int xfer_count; + int audio_mode; + int open_mode; + int intr_active; + char *chip_name, *name; + int model; #define MD_1848 1 #define MD_4231 2 #define MD_4231A 3 @@ -59,30 +63,30 @@ #define MD_C930 6 #define MD_IWAVE 7 - /* Mixer parameters */ - int recmask; - int supported_devices, orig_devices; - int supported_rec_devices, orig_rec_devices; - int *levels; - short mixer_reroute[32]; - int dev_no; - volatile unsigned long timer_ticks; - int timer_running; - int irq_ok; - mixer_ents *mix_devices; - int mixer_output_port; - int c930_password_port; + /* Mixer parameters */ + int recmask; + int supported_devices, orig_devices; + int supported_rec_devices, orig_rec_devices; + int *levels; + short mixer_reroute[32]; + int dev_no; + volatile unsigned long timer_ticks; + int timer_running; + int irq_ok; + mixer_ents *mix_devices; + int mixer_output_port; + int c930_password_port; } ad1848_info; typedef struct ad1848_port_info { - int open_mode; - int speed; - unsigned char speed_bits; - int channels; - int audio_format; - unsigned char format_bits; + int open_mode; + int speed; + unsigned char speed_bits; + int channels; + int audio_format; + unsigned char format_bits; } ad1848_port_info; @@ -98,14 +102,14 @@ static int ad_format_mask[8 /*devc->model */ ] = { - 0, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM + 0, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM }; static ad1848_info adev_info[MAX_AUDIO_DEV]; @@ -115,1958 +119,1897 @@ #define io_Status(d) ((d)->base+2) #define io_Polled_IO(d) ((d)->base+3) -static int ad1848_open (int dev, int mode); -static void ad1848_close (int dev); -static int ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg); -static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag); -static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag); -static int ad1848_prepare_for_output (int dev, int bsize, int bcount); -static int ad1848_prepare_for_input (int dev, int bsize, int bcount); -static void ad1848_halt (int dev); -static void ad1848_halt_input (int dev); -static void ad1848_halt_output (int dev); -static void ad1848_trigger (int dev, int bits); - -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) -static int ad1848_tmr_install (int dev); -static void ad1848_tmr_reprogram (int dev); +static int ad1848_open(int dev, int mode); +static void ad1848_close(int dev); +static int ad1848_ioctl(int dev, unsigned int cmd, caddr_t arg); +static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag); +static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag); +static int ad1848_prepare_for_output(int dev, int bsize, int bcount); +static int ad1848_prepare_for_input(int dev, int bsize, int bcount); +static void ad1848_halt(int dev); +static void ad1848_halt_input(int dev); +static void ad1848_halt_output(int dev); +static void ad1848_trigger(int dev, int bits); + +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +static int ad1848_tmr_install(int dev); +static void ad1848_tmr_reprogram(int dev); #endif static int -ad_read (ad1848_info * devc, int reg) +ad_read(ad1848_info * devc, int reg) { - unsigned long flags; - int x; - int timeout = 900000; - - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; - - save_flags (flags); - cli (); - outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc)); - x = inb (io_Indexed_Data (devc)); + unsigned long flags; + int x; + int timeout = 900000; + + while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; + + save_flags(flags); + cli(); + outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); + x = inb(io_Indexed_Data(devc)); /* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */ - restore_flags (flags); + restore_flags(flags); - return x; + return x; } static void -ad_write (ad1848_info * devc, int reg, int data) +ad_write(ad1848_info * devc, int reg, int data) { - unsigned long flags; - int timeout = 900000; + unsigned long flags; + int timeout = 900000; - while (timeout > 0 && - inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; - - save_flags (flags); - cli (); - outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc)); - outb (((unsigned char) (data & 0xff)), io_Indexed_Data (devc)); - /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */ - restore_flags (flags); + while (timeout > 0 && + inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; + + save_flags(flags); + cli(); + outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); + outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc)); + /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */ + restore_flags(flags); } static void -wait_for_calibration (ad1848_info * devc) +wait_for_calibration(ad1848_info * devc) { - int timeout = 0; + int timeout = 0; - /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on and then off. - */ - - timeout = 100000; - while (timeout > 0 && inb (devc->base) == 0x80) - timeout--; - if (inb (devc->base) & 0x80) - printk ("ad1848: Auto calibration timed out(1).\n"); - - timeout = 100; - while (timeout > 0 && !(ad_read (devc, 11) & 0x20)) - timeout--; - if (!(ad_read (devc, 11) & 0x20)) - return; - - timeout = 80000; - while (timeout > 0 && ad_read (devc, 11) & 0x20) - timeout--; - if (ad_read (devc, 11) & 0x20) - if (devc->model != MD_1845) - printk ("ad1848: Auto calibration timed out(3).\n"); + /* + * Wait until the auto calibration process has finished. + * + * 1) Wait until the chip becomes ready (reads don't return 0x80). + * 2) Wait until the ACI bit of I11 gets on and then off. + */ + + timeout = 100000; + while (timeout > 0 && inb(devc->base) == 0x80) + timeout--; + if (inb(devc->base) & 0x80) + printk("ad1848: Auto calibration timed out(1).\n"); + + timeout = 100; + while (timeout > 0 && !(ad_read(devc, 11) & 0x20)) + timeout--; + if (!(ad_read(devc, 11) & 0x20)) + return; + + timeout = 80000; + while (timeout > 0 && ad_read(devc, 11) & 0x20) + timeout--; + if (ad_read(devc, 11) & 0x20) + if (devc->model != MD_1845) + printk("ad1848: Auto calibration timed out(3).\n"); } static void -ad_mute (ad1848_info * devc) +ad_mute(ad1848_info * devc) { - int i; - unsigned char prev; + int i; + unsigned char prev; - /* - * Save old register settings and mute output channels - */ - for (i = 6; i < 8; i++) - { - prev = devc->saved_regs[i] = ad_read (devc, i); - } + /* + * Save old register settings and mute output channels + */ + for (i = 6; i < 8; i++) + { + prev = devc->saved_regs[i] = ad_read(devc, i); + } } static void -ad_unmute (ad1848_info * devc) +ad_unmute(ad1848_info * devc) { } static void -ad_enter_MCE (ad1848_info * devc) +ad_enter_MCE(ad1848_info * devc) { - unsigned long flags; - int timeout = 1000; - unsigned short prev; - - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; - - save_flags (flags); - cli (); - - devc->MCE_bit = 0x40; - prev = inb (io_Index_Addr (devc)); - if (prev & 0x40) - { - restore_flags (flags); - return; - } + unsigned long flags; + int timeout = 1000; + unsigned short prev; + + while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; + + save_flags(flags); + cli(); - outb ((devc->MCE_bit), io_Index_Addr (devc)); - restore_flags (flags); + devc->MCE_bit = 0x40; + prev = inb(io_Index_Addr(devc)); + if (prev & 0x40) + { + restore_flags(flags); + return; + } + outb((devc->MCE_bit), io_Index_Addr(devc)); + restore_flags(flags); } static void -ad_leave_MCE (ad1848_info * devc) +ad_leave_MCE(ad1848_info * devc) { - unsigned long flags; - unsigned char prev, acal; - int timeout = 1000; - - while (timeout > 0 && inb (devc->base) == 0x80) /*Are we initializing */ - timeout--; - - save_flags (flags); - cli (); - - acal = ad_read (devc, 9); - - devc->MCE_bit = 0x00; - prev = inb (io_Index_Addr (devc)); - outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */ - - if ((prev & 0x40) == 0) /* Not in MCE mode */ - { - restore_flags (flags); - return; - } - - outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */ - if (acal & 0x08) /* Auto calibration is enabled */ - wait_for_calibration (devc); - restore_flags (flags); + unsigned long flags; + unsigned char prev, acal; + int timeout = 1000; + + while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ + timeout--; + + save_flags(flags); + cli(); + + acal = ad_read(devc, 9); + + devc->MCE_bit = 0x00; + prev = inb(io_Index_Addr(devc)); + outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ + + if ((prev & 0x40) == 0) /* Not in MCE mode */ + { + restore_flags(flags); + return; + } + outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ + if (acal & 0x08) /* Auto calibration is enabled */ + wait_for_calibration(devc); + restore_flags(flags); } static int -ad1848_set_recmask (ad1848_info * devc, int mask) +ad1848_set_recmask(ad1848_info * devc, int mask) { - unsigned char recdev; - int i, n; + unsigned char recdev; + int i, n; - mask &= devc->supported_rec_devices; + mask &= devc->supported_rec_devices; - /* Rename the mixer bits if necessary */ - for (i = 0; i < 32; i++) - if (devc->mixer_reroute[i] != i) - if (mask & (1 << i)) - { - mask &= ~(1 << i); - mask |= (1 << devc->mixer_reroute[i]); - } + /* Rename the mixer bits if necessary */ + for (i = 0; i < 32; i++) + if (devc->mixer_reroute[i] != i) + if (mask & (1 << i)) + { + mask &= ~(1 << i); + mask |= (1 << devc->mixer_reroute[i]); + } + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) /* Too many devices selected */ + { + mask &= ~devc->recmask; /* Filter out active settings */ - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - if (n == 0) - mask = SOUND_MASK_MIC; - else if (n != 1) /* Too many devices selected */ - { - mask &= ~devc->recmask; /* Filter out active settings */ - - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - if (n != 1) - mask = SOUND_MASK_MIC; - } - - switch (mask) - { - case SOUND_MASK_MIC: - recdev = 2; - break; - - case SOUND_MASK_LINE: - case SOUND_MASK_LINE3: - recdev = 0; - break; - - case SOUND_MASK_CD: - case SOUND_MASK_LINE1: - recdev = 1; - break; - - case SOUND_MASK_IMIX: - recdev = 3; - break; - - default: - mask = SOUND_MASK_MIC; - recdev = 2; - } - - recdev <<= 6; - ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev); - ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev); - - /* Rename the mixer bits back if necessary */ - for (i = 0; i < 32; i++) - if (devc->mixer_reroute[i] != i) - if (mask & (1 << devc->mixer_reroute[i])) - { - mask &= ~(1 << devc->mixer_reroute[i]); - mask |= (1 << i); - } + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; - devc->recmask = mask; - return mask; + if (n != 1) + mask = SOUND_MASK_MIC; + } + switch (mask) + { + case SOUND_MASK_MIC: + recdev = 2; + break; + + case SOUND_MASK_LINE: + case SOUND_MASK_LINE3: + recdev = 0; + break; + + case SOUND_MASK_CD: + case SOUND_MASK_LINE1: + recdev = 1; + break; + + case SOUND_MASK_IMIX: + recdev = 3; + break; + + default: + mask = SOUND_MASK_MIC; + recdev = 2; + } + + recdev <<= 6; + ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); + ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + + /* Rename the mixer bits back if necessary */ + for (i = 0; i < 32; i++) + if (devc->mixer_reroute[i] != i) + if (mask & (1 << devc->mixer_reroute[i])) + { + mask &= ~(1 << devc->mixer_reroute[i]); + mask |= (1 << i); + } + devc->recmask = mask; + return mask; } static void -change_bits (ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) +change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) { - unsigned char mask; - int shift; - int mute; - int mutemask; - int set_mute_bit; - - set_mute_bit = (newval == 0); - - if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ - newval = 100 - newval; - - mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; - shift = devc->mix_devices[dev][chn].bitpos; - - if (devc->mix_devices[dev][chn].mutepos == 8) - { /* if there is no mute bit */ - mute = 0; /* No mute bit; do nothing special */ - mutemask = ~0; /* No mute bit; do nothing special */ - } - else - { - mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); - mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); - } - - newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ - *regval |= ((newval & mask) << shift) | mute; /* Set new value */ + unsigned char mask; + int shift; + int mute; + int mutemask; + int set_mute_bit; + + set_mute_bit = (newval == 0); + + if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ + newval = 100 - newval; + + mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; + shift = devc->mix_devices[dev][chn].bitpos; + + if (devc->mix_devices[dev][chn].mutepos == 8) + { /* if there is no mute bit */ + mute = 0; /* No mute bit; do nothing special */ + mutemask = ~0; /* No mute bit; do nothing special */ + } else + { + mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); + mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); + } + + newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ + *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ + *regval |= ((newval & mask) << shift) | mute; /* Set new value */ } static int -ad1848_mixer_get (ad1848_info * devc, int dev) +ad1848_mixer_get(ad1848_info * devc, int dev) { - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; + if (!((1 << dev) & devc->supported_devices)) + return -EINVAL; - dev = devc->mixer_reroute[dev]; + dev = devc->mixer_reroute[dev]; - return devc->levels[dev]; + return devc->levels[dev]; } static int -ad1848_mixer_set (ad1848_info * devc, int dev, int value) +ad1848_mixer_set(ad1848_info * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retvol; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int retvol; - int regoffs; - unsigned char val; + int regoffs; + unsigned char val; - if (dev > 31) - return -EINVAL; + if (dev > 31) + return -EINVAL; - if (!(devc->supported_devices & (1 << dev))) - return -EINVAL; + if (!(devc->supported_devices & (1 << dev))) + return -EINVAL; - dev = devc->mixer_reroute[dev]; + dev = devc->mixer_reroute[dev]; - if (left > 100) - left = 100; - if (right > 100) - right = 100; + if (left > 100) + left = 100; + if (right > 100) + right = 100; - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ - right = left; + if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ + right = left; - retvol = left | (right << 8); + retvol = left | (right << 8); - /* Scale volumes */ - left = mix_cvt[left]; - right = mix_cvt[right]; + /* Scale volumes */ + left = mix_cvt[left]; + right = mix_cvt[right]; - /* Scale it again */ - left = mix_cvt[left]; - right = mix_cvt[right]; + /* Scale it again */ + left = mix_cvt[left]; + right = mix_cvt[right]; - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; + if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) + return -EINVAL; - devc->levels[dev] = retvol; + devc->levels[dev] = retvol; - /* - * Set the left channel - */ + /* + * Set the left channel + */ - regoffs = devc->mix_devices[dev][LEFT_CHN].regno; - val = ad_read (devc, regoffs); - change_bits (devc, &val, dev, LEFT_CHN, left); - ad_write (devc, regoffs, val); - devc->saved_regs[regoffs] = val; + regoffs = devc->mix_devices[dev][LEFT_CHN].regno; + val = ad_read(devc, regoffs); + change_bits(devc, &val, dev, LEFT_CHN, left); + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; - /* - * Set the right channel - */ + /* + * Set the right channel + */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - return retvol; /* Was just a mono channel */ + if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) + return retvol; /* Was just a mono channel */ - regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; - val = ad_read (devc, regoffs); - change_bits (devc, &val, dev, RIGHT_CHN, right); - ad_write (devc, regoffs, val); - devc->saved_regs[regoffs] = val; + regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; + val = ad_read(devc, regoffs); + change_bits(devc, &val, dev, RIGHT_CHN, right); + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; - return retvol; + return retvol; } static void -ad1848_mixer_reset (ad1848_info * devc) +ad1848_mixer_reset(ad1848_info * devc) { - int i; - char name[32]; + int i; + char name[32]; - devc->mix_devices = &(ad1848_mix_devices[0]); + devc->mix_devices = &(ad1848_mix_devices[0]); - sprintf (name, "%s_%d", devc->chip_name, nr_ad1848_devs); + sprintf(name, "%s_%d", devc->chip_name, nr_ad1848_devs); - for (i = 0; i < 32; i++) - devc->mixer_reroute[i] = i; - - switch (devc->model) - { - case MD_4231: - case MD_4231A: - case MD_1845: - devc->supported_devices = MODE2_MIXER_DEVICES; - break; - - case MD_C930: - devc->supported_devices = C930_MIXER_DEVICES; - devc->mix_devices = &(c930_mix_devices[0]); - break; - - case MD_IWAVE: - devc->supported_devices = MODE3_MIXER_DEVICES; - devc->mix_devices = &(iwave_mix_devices[0]); - break; - - case MD_4232: - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - - default: - devc->supported_devices = MODE1_MIXER_DEVICES; - } - - devc->supported_rec_devices = MODE1_REC_DEVICES; - devc->orig_devices = devc->supported_devices; - devc->orig_rec_devices = devc->supported_rec_devices; - - devc->levels = load_mixer_volumes (name, default_mixer_levels, 1); - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (devc->supported_devices & (1 << i)) - ad1848_mixer_set (devc, i, devc->levels[i]); - ad1848_set_recmask (devc, SOUND_MASK_MIC); - devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; - if (devc->mixer_output_port & AUDIO_SPEAKER) - ad_write (devc, 26, ad_read (devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write (devc, 26, ad_read (devc, 26) | 0x40); /* Mute mono out */ -} + for (i = 0; i < 32; i++) + devc->mixer_reroute[i] = i; -static int -ad1848_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) -{ - ad1848_info *devc = mixer_devs[dev]->devc; + switch (devc->model) + { + case MD_4231: + case MD_4231A: + case MD_1845: + devc->supported_devices = MODE2_MIXER_DEVICES; + break; - if (cmd == SOUND_MIXER_PRIVATE1) - { - int val; + case MD_C930: + devc->supported_devices = C930_MIXER_DEVICES; + devc->mix_devices = &(c930_mix_devices[0]); + break; - val = *(int *) arg; + case MD_IWAVE: + devc->supported_devices = MODE3_MIXER_DEVICES; + devc->mix_devices = &(iwave_mix_devices[0]); + break; - if (val == 0xffff) - return (*(int *) arg = devc->mixer_output_port); + case MD_4232: + devc->supported_devices = MODE3_MIXER_DEVICES; + break; - val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); + default: + devc->supported_devices = MODE1_MIXER_DEVICES; + } - devc->mixer_output_port = val; - val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ - devc->mixer_output_port = val; + devc->supported_rec_devices = MODE1_REC_DEVICES; + devc->orig_devices = devc->supported_devices; + devc->orig_rec_devices = devc->supported_rec_devices; + + devc->levels = load_mixer_volumes(name, default_mixer_levels, 1); + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (devc->supported_devices & (1 << i)) + ad1848_mixer_set(devc, i, devc->levels[i]); + ad1848_set_recmask(devc, SOUND_MASK_MIC); + devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; + if (devc->mixer_output_port & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ +} - if (val & AUDIO_SPEAKER) - ad_write (devc, 26, ad_read (devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write (devc, 26, ad_read (devc, 26) | 0x40); /* Mute mono out */ +static int +ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + ad1848_info *devc = mixer_devs[dev]->devc; - return (*(int *) arg = devc->mixer_output_port); - } + if (cmd == SOUND_MIXER_PRIVATE1) + { + int val; - if (((cmd >> 8) & 0xff) == 'M') - { - int val; + val = *(int *) arg; - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - val = *(int *) arg; - return (*(int *) arg = ad1848_set_recmask (devc, val)); - break; + if (val == 0xffff) + return (*(int *) arg = devc->mixer_output_port); - default: - val = *(int *) arg; - return (*(int *) arg = ad1848_mixer_set (devc, cmd & 0xff, val)); - } - else - switch (cmd & 0xff) /* - * Return parameters - */ - { + val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); - case SOUND_MIXER_RECSRC: - return (*(int *) arg = devc->recmask); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = devc->supported_devices); - break; - - case SOUND_MIXER_STEREODEVS: - if (devc->model == MD_C930) - return (*(int *) arg = devc->supported_devices); - else - return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = devc->supported_rec_devices); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = SOUND_CAP_EXCL_INPUT); - break; + devc->mixer_output_port = val; + val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ + devc->mixer_output_port = val; - default: - return (*(int *) arg = ad1848_mixer_get (devc, cmd & 0xff)); + if (val & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + + return (*(int *) arg = devc->mixer_output_port); } - } - else - return -EINVAL; + if (((cmd >> 8) & 0xff) == 'M') + { + int val; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + val = *(int *) arg; + return (*(int *) arg = ad1848_set_recmask(devc, val)); + break; + + default: + val = *(int *) arg; + return (*(int *) arg = ad1848_mixer_set(devc, cmd & 0xff, val)); + } else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = devc->recmask); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = devc->supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + if (devc->model == MD_C930) + return (*(int *) arg = devc->supported_devices); + else + return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = devc->supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = SOUND_CAP_EXCL_INPUT); + break; + + default: + return (*(int *) arg = ad1848_mixer_get(devc, cmd & 0xff)); + } + } else + return -EINVAL; } static int -ad1848_set_speed (int dev, int arg) +ad1848_set_speed(int dev, int arg) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - /* - * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other - * three bits select the divisor (indirectly): - * - * The available speeds are in the following table. Keep the speeds in - * the increasing order. - */ - typedef struct - { - int speed; - unsigned char bits; - } - speed_struct; + /* + * The sampling speed is encoded in the least significant nibble of I8. The + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other + * three bits select the divisor (indirectly): + * + * The available speeds are in the following table. Keep the speeds in + * the increasing order. + */ + typedef struct + { + int speed; + unsigned char bits; + } + speed_struct; - static speed_struct speed_table[] = - { - {5510, (0 << 1) | 1}, - {5510, (0 << 1) | 1}, - {6620, (7 << 1) | 1}, - {8000, (0 << 1) | 0}, - {9600, (7 << 1) | 0}, - {11025, (1 << 1) | 1}, - {16000, (1 << 1) | 0}, - {18900, (2 << 1) | 1}, - {22050, (3 << 1) | 1}, - {27420, (2 << 1) | 0}, - {32000, (3 << 1) | 0}, - {33075, (6 << 1) | 1}, - {37800, (4 << 1) | 1}, - {44100, (5 << 1) | 1}, - {48000, (6 << 1) | 0} - }; - - int i, n, selected = -1; - - n = sizeof (speed_table) / sizeof (speed_struct); - - if (arg <= 0) - return portc->speed; - - if (devc->model == MD_1845) /* AD1845 has different timer than others */ - { - if (arg < 4000) - arg = 4000; - if (arg > 50000) - arg = 50000; - - portc->speed = arg; - portc->speed_bits = speed_table[3].bits; - return portc->speed; - } - - if (arg < speed_table[0].speed) - selected = 0; - if (arg > speed_table[n - 1].speed) - selected = n - 1; - - for (i = 1 /*really */ ; selected == -1 && i < n; i++) - if (speed_table[i].speed == arg) - selected = i; - else if (speed_table[i].speed > arg) - { - int diff1, diff2; + static speed_struct speed_table[] = + { + {5510, (0 << 1) | 1}, + {5510, (0 << 1) | 1}, + {6620, (7 << 1) | 1}, + {8000, (0 << 1) | 0}, + {9600, (7 << 1) | 0}, + {11025, (1 << 1) | 1}, + {16000, (1 << 1) | 0}, + {18900, (2 << 1) | 1}, + {22050, (3 << 1) | 1}, + {27420, (2 << 1) | 0}, + {32000, (3 << 1) | 0}, + {33075, (6 << 1) | 1}, + {37800, (4 << 1) | 1}, + {44100, (5 << 1) | 1}, + {48000, (6 << 1) | 0} + }; - diff1 = arg - speed_table[i - 1].speed; - diff2 = speed_table[i].speed - arg; + int i, n, selected = -1; - if (diff1 < diff2) - selected = i - 1; - else - selected = i; - } + n = sizeof(speed_table) / sizeof(speed_struct); + + if (arg <= 0) + return portc->speed; - if (selected == -1) - { - printk ("ad1848: Can't find speed???\n"); - selected = 3; - } - - portc->speed = speed_table[selected].speed; - portc->speed_bits = speed_table[selected].bits; - return portc->speed; + if (devc->model == MD_1845) /* AD1845 has different timer than others */ + { + if (arg < 4000) + arg = 4000; + if (arg > 50000) + arg = 50000; + + portc->speed = arg; + portc->speed_bits = speed_table[3].bits; + return portc->speed; + } + if (arg < speed_table[0].speed) + selected = 0; + if (arg > speed_table[n - 1].speed) + selected = n - 1; + + for (i = 1 /*really */ ; selected == -1 && i < n; i++) + if (speed_table[i].speed == arg) + selected = i; + else if (speed_table[i].speed > arg) + { + int diff1, diff2; + + diff1 = arg - speed_table[i - 1].speed; + diff2 = speed_table[i].speed - arg; + + if (diff1 < diff2) + selected = i - 1; + else + selected = i; + } + if (selected == -1) + { + printk("ad1848: Can't find speed???\n"); + selected = 3; + } + portc->speed = speed_table[selected].speed; + portc->speed_bits = speed_table[selected].bits; + return portc->speed; } static short -ad1848_set_channels (int dev, short arg) +ad1848_set_channels(int dev, short arg) { - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - if (arg != 1 && arg != 2) - return portc->channels; + if (arg != 1 && arg != 2) + return portc->channels; - portc->channels = arg; - return arg; + portc->channels = arg; + return arg; } static unsigned int -ad1848_set_bits (int dev, unsigned int arg) +ad1848_set_bits(int dev, unsigned int arg) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - static struct format_tbl - { - int format; - unsigned char bits; - } - format2bits[] = - { - { - 0, 0 - } - , - { - AFMT_MU_LAW, 1 - } - , - { - AFMT_A_LAW, 3 - } - , - { - AFMT_IMA_ADPCM, 5 - } - , - { - AFMT_U8, 0 - } - , - { - AFMT_S16_LE, 2 - } - , - { - AFMT_S16_BE, 6 - } - , - { - AFMT_S8, 0 - } - , - { - AFMT_U16_LE, 0 - } - , - { - AFMT_U16_BE, 0 - } - }; - int i, n = sizeof (format2bits) / sizeof (struct format_tbl); - - if (arg == 0) - return portc->audio_format; - - if (!(arg & ad_format_mask[devc->model])) - arg = AFMT_U8; - - portc->audio_format = arg; - - for (i = 0; i < n; i++) - if (format2bits[i].format == arg) - { - if ((portc->format_bits = format2bits[i].bits) == 0) - return portc->audio_format = AFMT_U8; /* Was not supported */ + static struct format_tbl + { + int format; + unsigned char bits; + } + format2bits[] = + { + { + 0, 0 + } + , + { + AFMT_MU_LAW, 1 + } + , + { + AFMT_A_LAW, 3 + } + , + { + AFMT_IMA_ADPCM, 5 + } + , + { + AFMT_U8, 0 + } + , + { + AFMT_S16_LE, 2 + } + , + { + AFMT_S16_BE, 6 + } + , + { + AFMT_S8, 0 + } + , + { + AFMT_U16_LE, 0 + } + , + { + AFMT_U16_BE, 0 + } + }; + int i, n = sizeof(format2bits) / sizeof(struct format_tbl); - return arg; - } + if (arg == 0) + return portc->audio_format; + + if (!(arg & ad_format_mask[devc->model])) + arg = AFMT_U8; - /* Still hanging here. Something must be terribly wrong */ - portc->format_bits = 0; - return portc->audio_format = AFMT_U8; + portc->audio_format = arg; + + for (i = 0; i < n; i++) + if (format2bits[i].format == arg) + { + if ((portc->format_bits = format2bits[i].bits) == 0) + return portc->audio_format = AFMT_U8; /* Was not supported */ + + return arg; + } + /* Still hanging here. Something must be terribly wrong */ + portc->format_bits = 0; + return portc->audio_format = AFMT_U8; } static struct audio_driver ad1848_audio_driver = { - ad1848_open, - ad1848_close, - ad1848_output_block, - ad1848_start_input, - ad1848_ioctl, - ad1848_prepare_for_input, - ad1848_prepare_for_output, - ad1848_halt, - NULL, - NULL, - ad1848_halt_input, - ad1848_halt_output, - ad1848_trigger, - ad1848_set_speed, - ad1848_set_bits, - ad1848_set_channels + ad1848_open, + ad1848_close, + ad1848_output_block, + ad1848_start_input, + ad1848_ioctl, + ad1848_prepare_for_input, + ad1848_prepare_for_output, + ad1848_halt, + NULL, + NULL, + ad1848_halt_input, + ad1848_halt_output, + ad1848_trigger, + ad1848_set_speed, + ad1848_set_bits, + ad1848_set_channels }; static struct mixer_operations ad1848_mixer_operations = { - "SOUNDPORT", - "AD1848/CS4248/CS4231", - ad1848_mixer_ioctl + "SOUNDPORT", + "AD1848/CS4248/CS4231", + ad1848_mixer_ioctl }; static int -ad1848_open (int dev, int mode) +ad1848_open(int dev, int mode) { - ad1848_info *devc = NULL; - ad1848_port_info *portc; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (ad1848_info *) audio_devs[dev]->devc; - portc = (ad1848_port_info *) audio_devs[dev]->portc; - - save_flags (flags); - cli (); - if (portc->open_mode || (devc->open_mode & mode)) - { - restore_flags (flags); - return -EBUSY; - } - - devc->dual_dma = 0; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - devc->dual_dma = 1; - } - - devc->intr_active = 0; - devc->audio_mode = 0; - devc->open_mode |= mode; - portc->open_mode = mode; - ad1848_trigger (dev, 0); - - if (mode & OPEN_READ) - devc->record_dev = dev; - if (mode & OPEN_WRITE) - devc->playback_dev = dev; - restore_flags (flags); + ad1848_info *devc = NULL; + ad1848_port_info *portc; + unsigned long flags; + + if (dev < 0 || dev >= num_audiodevs) + return -ENXIO; + + devc = (ad1848_info *) audio_devs[dev]->devc; + portc = (ad1848_port_info *) audio_devs[dev]->portc; + + save_flags(flags); + cli(); + if (portc->open_mode || (devc->open_mode & mode)) + { + restore_flags(flags); + return -EBUSY; + } + devc->dual_dma = 0; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { + devc->dual_dma = 1; + } + devc->intr_active = 0; + devc->audio_mode = 0; + devc->open_mode |= mode; + portc->open_mode = mode; + ad1848_trigger(dev, 0); + + if (mode & OPEN_READ) + devc->record_dev = dev; + if (mode & OPEN_WRITE) + devc->playback_dev = dev; + restore_flags(flags); /* * Mute output until the playback really starts. This decreases clicking (hope so). */ - ad_mute (devc); + ad_mute(devc); - return 0; + return 0; } static void -ad1848_close (int dev) +ad1848_close(int dev) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - DEB (printk ("ad1848_close(void)\n")); + DEB(printk("ad1848_close(void)\n")); - save_flags (flags); - cli (); + save_flags(flags); + cli(); - devc->intr_active = 0; - ad1848_halt (dev); + devc->intr_active = 0; + ad1848_halt(dev); - devc->audio_mode = 0; - devc->open_mode &= ~portc->open_mode; - portc->open_mode = 0; + devc->audio_mode = 0; + devc->open_mode &= ~portc->open_mode; + portc->open_mode = 0; - ad_unmute (devc); - restore_flags (flags); + ad_unmute(devc); + restore_flags(flags); } static int -ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg) +ad1848_ioctl(int dev, unsigned int cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -ad1848_output_block (int dev, unsigned long buf, int count, int intrflag) +ad1848_output_block(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags, cnt; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - cnt = count; - - if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } - else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } - if (portc->channels > 1) - cnt >>= 1; - cnt--; - - if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - return; /* + unsigned long flags, cnt; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + + cnt = count; + + if (portc->audio_format == AFMT_IMA_ADPCM) + { + cnt /= 4; + } else + { + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } + if (portc->channels > 1) + cnt >>= 1; + cnt--; + + if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == devc->xfer_count) + { + devc->audio_mode |= PCM_ENABLE_OUTPUT; + devc->intr_active = 1; + return; /* * Auto DMA mode on. No need to react */ - } - save_flags (flags); - cli (); - - ad_write (devc, 15, (unsigned char) (cnt & 0xff)); - ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - - devc->xfer_count = cnt; - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - restore_flags (flags); + } + save_flags(flags); + cli(); + + ad_write(devc, 15, (unsigned char) (cnt & 0xff)); + ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); + + devc->xfer_count = cnt; + devc->audio_mode |= PCM_ENABLE_OUTPUT; + devc->intr_active = 1; + restore_flags(flags); } static void -ad1848_start_input (int dev, unsigned long buf, int count, int intrflag) +ad1848_start_input(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags, cnt; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - cnt = count; - if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } - else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } - if (portc->channels > 1) - cnt >>= 1; - cnt--; - - if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - return; /* + unsigned long flags, cnt; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + + cnt = count; + if (portc->audio_format == AFMT_IMA_ADPCM) + { + cnt /= 4; + } else + { + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } + if (portc->channels > 1) + cnt >>= 1; + cnt--; + + if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == devc->xfer_count) + { + devc->audio_mode |= PCM_ENABLE_INPUT; + devc->intr_active = 1; + return; /* * Auto DMA mode on. No need to react */ - } - save_flags (flags); - cli (); - - if (devc->model == MD_1848) - { - ad_write (devc, 15, (unsigned char) (cnt & 0xff)); - ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - } - else - { - ad_write (devc, 31, (unsigned char) (cnt & 0xff)); - ad_write (devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); - } - - ad_unmute (devc); - - devc->xfer_count = cnt; - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - restore_flags (flags); + } + save_flags(flags); + cli(); + + if (devc->model == MD_1848) + { + ad_write(devc, 15, (unsigned char) (cnt & 0xff)); + ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); + } else + { + ad_write(devc, 31, (unsigned char) (cnt & 0xff)); + ad_write(devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); + } + + ad_unmute(devc); + + devc->xfer_count = cnt; + devc->audio_mode |= PCM_ENABLE_INPUT; + devc->intr_active = 1; + restore_flags(flags); } static int -ad1848_prepare_for_output (int dev, int bsize, int bcount) +ad1848_prepare_for_output(int dev, int bsize, int bcount) { - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - ad_mute (devc); - - save_flags (flags); - cli (); - fs = portc->speed_bits | (portc->format_bits << 5); - - if (portc->channels > 1) - fs |= 0x10; - - ad_enter_MCE (devc); /* Enables changes to the format select reg */ - - if (devc->model == MD_1845) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ - - ad_write (devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write (devc, 23, portc->speed & 0xff); /* Speed LSB */ - } - - old_fs = ad_read (devc, 8); - - if (devc->model == MD_4232) - { - tmp = ad_read (devc, 16); - ad_write (devc, 16, tmp | 0x30); - } - - if (devc->model == MD_IWAVE) - ad_write (devc, 17, 0xc2); /* Disable variable frequency select */ - - ad_write (devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; + int timeout; + unsigned char fs, old_fs, tmp = 0; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + + ad_mute(devc); + + save_flags(flags); + cli(); + fs = portc->speed_bits | (portc->format_bits << 5); + + if (portc->channels > 1) + fs |= 0x10; + + ad_enter_MCE(devc); /* Enables changes to the format select reg */ + + if (devc->model == MD_1845) /* Use alternate speed select registers */ + { + fs &= 0xf0; /* Mask off the rate select bits */ - if (devc->model == MD_4232) - ad_write (devc, 16, tmp & ~0x30); + ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ + ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ + } + old_fs = ad_read(devc, 8); + + if (devc->model == MD_4232) + { + tmp = ad_read(devc, 16); + ad_write(devc, 16, tmp | 0x30); + } + if (devc->model == MD_IWAVE) + ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ - ad_leave_MCE (devc); /* + ad_write(devc, 8, fs); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + + if (devc->model == MD_4232) + ad_write(devc, 16, tmp & ~0x30); + + ad_leave_MCE(devc); /* * Starts the calibration process. */ - restore_flags (flags); - devc->xfer_count = 0; + restore_flags(flags); + devc->xfer_count = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (dev == timer_installed && devc->timer_running) - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram (dev); - } +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + if (dev == timer_installed && devc->timer_running) + if ((fs & 0x01) != (old_fs & 0x01)) + { + ad1848_tmr_reprogram(dev); + } #endif - ad1848_halt_output (dev); - return 0; + ad1848_halt_output(dev); + return 0; } static int -ad1848_prepare_for_input (int dev, int bsize, int bcount) +ad1848_prepare_for_input(int dev, int bsize, int bcount) { - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - - if (devc->audio_mode) - return 0; - - save_flags (flags); - cli (); - fs = portc->speed_bits | (portc->format_bits << 5); - - if (portc->channels > 1) - fs |= 0x10; - - ad_enter_MCE (devc); /* Enables changes to the format select reg */ - - if (devc->model == MD_1845) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ - - ad_write (devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write (devc, 23, portc->speed & 0xff); /* Speed LSB */ - } - - if (devc->model == MD_4232) - { - tmp = ad_read (devc, 16); - ad_write (devc, 16, tmp | 0x30); - } - - if (devc->model == MD_IWAVE) - ad_write (devc, 17, 0xc2); /* Disable variable frequency select */ - - /* - * If mode >= 2 (CS4231), set I28. It's the capture format register. - */ - if (devc->model != MD_1848) - { - old_fs = ad_read (devc, 28); - ad_write (devc, 28, fs); - - /* - * Write to I28 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; + int timeout; + unsigned char fs, old_fs, tmp = 0; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - if (devc->model != MD_1848 && devc->model != MD_1845) - { - /* - * CS4231 compatible devices don't have separate sampling rate selection - * register for recording an playback. The I8 register is shared so we have to - * set the speed encoding bits of it too. - */ - unsigned char tmp = portc->speed_bits | (ad_read (devc, 8) & 0xf0); - - ad_write (devc, 8, tmp); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; - } - } - else - { /* For AD1848 set I8. */ - - old_fs = ad_read (devc, 8); - ad_write (devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; - } + if (devc->audio_mode) + return 0; + + save_flags(flags); + cli(); + fs = portc->speed_bits | (portc->format_bits << 5); + + if (portc->channels > 1) + fs |= 0x10; + + ad_enter_MCE(devc); /* Enables changes to the format select reg */ + + if (devc->model == MD_1845) /* Use alternate speed select registers */ + { + fs &= 0xf0; /* Mask off the rate select bits */ + + ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ + ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ + } + if (devc->model == MD_4232) + { + tmp = ad_read(devc, 16); + ad_write(devc, 16, tmp | 0x30); + } + if (devc->model == MD_IWAVE) + ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ + + /* + * If mode >= 2 (CS4231), set I28. It's the capture format register. + */ + if (devc->model != MD_1848) + { + old_fs = ad_read(devc, 28); + ad_write(devc, 28, fs); + + /* + * Write to I28 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + + if (devc->model != MD_1848 && devc->model != MD_1845) + { + /* + * CS4231 compatible devices don't have separate sampling rate selection + * register for recording an playback. The I8 register is shared so we have to + * set the speed encoding bits of it too. + */ + unsigned char tmp = portc->speed_bits | (ad_read(devc, 8) & 0xf0); + + ad_write(devc, 8, tmp); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + } + } else + { /* For AD1848 set I8. */ - if (devc->model == MD_4232) - ad_write (devc, 16, tmp & ~0x30); + old_fs = ad_read(devc, 8); + ad_write(devc, 8, fs); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + } + + if (devc->model == MD_4232) + ad_write(devc, 16, tmp & ~0x30); - ad_leave_MCE (devc); /* + ad_leave_MCE(devc); /* * Starts the calibration process. */ - restore_flags (flags); - devc->xfer_count = 0; + restore_flags(flags); + devc->xfer_count = 0; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (dev == timer_installed && devc->timer_running) - if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram (dev); - } + if (dev == timer_installed && devc->timer_running) + if ((fs & 0x01) != (old_fs & 0x01)) + { + ad1848_tmr_reprogram(dev); + } #endif - ad1848_halt_input (dev); - return 0; + ad1848_halt_input(dev); + return 0; } static void -ad1848_halt (int dev) +ad1848_halt(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - unsigned char bits = ad_read (devc, 9); + unsigned char bits = ad_read(devc, 9); - if (bits & 0x01 && portc->open_mode & OPEN_WRITE) - ad1848_halt_output (dev); + if (bits & 0x01 && portc->open_mode & OPEN_WRITE) + ad1848_halt_output(dev); - if (bits & 0x02 && portc->open_mode & OPEN_READ) - ad1848_halt_input (dev); - devc->audio_mode = 0; + if (bits & 0x02 && portc->open_mode & OPEN_READ) + ad1848_halt_input(dev); + devc->audio_mode = 0; } static void -ad1848_halt_input (int dev) +ad1848_halt_input(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; - if (!(ad_read (devc, 9) & 0x02)) - return; /* Capture not enabled */ + if (!(ad_read(devc, 9) & 0x02)) + return; /* Capture not enabled */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - ad_mute (devc); + ad_mute(devc); - { - int tmout; + { + int tmout; - disable_dma (audio_devs[dev]->dmap_in->dma); + disable_dma(audio_devs[dev]->dmap_in->dma); - for (tmout = 0; tmout < 100000; tmout++) - if (ad_read (devc, 11) & 0x10) - break; - ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */ + for (tmout = 0; tmout < 100000; tmout++) + if (ad_read(devc, 11) & 0x10) + break; + ad_write(devc, 9, ad_read(devc, 9) & ~0x02); /* Stop capture */ - enable_dma (audio_devs[dev]->dmap_in->dma); - devc->audio_mode &= ~PCM_ENABLE_INPUT; - } + enable_dma(audio_devs[dev]->dmap_in->dma); + devc->audio_mode &= ~PCM_ENABLE_INPUT; + } - outb ((0), io_Status (devc)); /* Clear interrupt status */ - outb ((0), io_Status (devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ - devc->audio_mode &= ~PCM_ENABLE_INPUT; + devc->audio_mode &= ~PCM_ENABLE_INPUT; - restore_flags (flags); + restore_flags(flags); } static void -ad1848_halt_output (int dev) +ad1848_halt_output(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; - if (!(ad_read (devc, 9) & 0x01)) - return; /* Playback not enabled */ + if (!(ad_read(devc, 9) & 0x01)) + return; /* Playback not enabled */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - ad_mute (devc); - { - int tmout; + ad_mute(devc); + { + int tmout; - disable_dma (audio_devs[dev]->dmap_out->dma); + disable_dma(audio_devs[dev]->dmap_out->dma); - for (tmout = 0; tmout < 100000; tmout++) - if (ad_read (devc, 11) & 0x10) - break; - ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */ + for (tmout = 0; tmout < 100000; tmout++) + if (ad_read(devc, 11) & 0x10) + break; + ad_write(devc, 9, ad_read(devc, 9) & ~0x01); /* Stop playback */ - enable_dma (audio_devs[dev]->dmap_out->dma); - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - } + enable_dma(audio_devs[dev]->dmap_out->dma); + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + } - outb ((0), io_Status (devc)); /* Clear interrupt status */ - outb ((0), io_Status (devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ + outb((0), io_Status(devc)); /* Clear interrupt status */ - devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; - restore_flags (flags); + restore_flags(flags); } static void -ad1848_trigger (int dev, int state) +ad1848_trigger(int dev, int state) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; - unsigned long flags; - unsigned char tmp, old; - - save_flags (flags); - cli (); - state &= devc->audio_mode; - - tmp = old = ad_read (devc, 9); - - if (portc->open_mode & OPEN_READ) - { - if (state & PCM_ENABLE_INPUT) - tmp |= 0x02; - else - tmp &= ~0x02; - } - - if (portc->open_mode & OPEN_WRITE) - { - if (state & PCM_ENABLE_OUTPUT) - tmp |= 0x01; - else - tmp &= ~0x01; - } - - /* ad_mute(devc); */ - if (tmp != old) - { - ad_write (devc, 9, tmp); - ad_unmute (devc); - } + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; + unsigned long flags; + unsigned char tmp, old; + + save_flags(flags); + cli(); + state &= devc->audio_mode; - restore_flags (flags); + tmp = old = ad_read(devc, 9); + + if (portc->open_mode & OPEN_READ) + { + if (state & PCM_ENABLE_INPUT) + tmp |= 0x02; + else + tmp &= ~0x02; + } + if (portc->open_mode & OPEN_WRITE) + { + if (state & PCM_ENABLE_OUTPUT) + tmp |= 0x01; + else + tmp &= ~0x01; + } + /* ad_mute(devc); */ + if (tmp != old) + { + ad_write(devc, 9, tmp); + ad_unmute(devc); + } + restore_flags(flags); } static void -ad1848_init_hw (ad1848_info * devc) +ad1848_init_hw(ad1848_info * devc) { - int i; + int i; - /* - * Initial values for the indirect registers of CS4248/AD1848. - */ - static int init_values[] = - { - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, + /* + * Initial values for the indirect registers of CS4248/AD1848. + */ + static int init_values[] = + { + 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, + + /* Positions 16 to 31 just for CS4231/2 and ad1845 */ + 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; - /* Positions 16 to 31 just for CS4231/2 and ad1845 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + for (i = 0; i < 16; i++) + ad_write(devc, i, init_values[i]); - for (i = 0; i < 16; i++) - ad_write (devc, i, init_values[i]); + ad_mute(devc); /* Initialize some variables */ + ad_unmute(devc); /* Leave it unmuted now */ - ad_mute (devc); /* Initialize some variables */ - ad_unmute (devc); /* Leave it unmuted now */ + if (devc->model > MD_1848) + { + ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - if (devc->model > MD_1848) - { - ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ + if (devc->model == MD_IWAVE) + ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - if (devc->model == MD_IWAVE) - ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + for (i = 16; i < 32; i++) + ad_write(devc, i, init_values[i]); - for (i = 16; i < 32; i++) - ad_write (devc, i, init_values[i]); + if (devc->model == MD_IWAVE) + ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ - if (devc->model == MD_IWAVE) - ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */ + } + if (devc->model > MD_1848) + { + if (devc->audio_flags & DMA_DUPLEX) + ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */ + else + ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ - } + if (devc->model == MD_1845) + ad_write(devc, 27, ad_read(devc, 27) | 0x08); /* Alternate freq select enabled */ - if (devc->model > MD_1848) - { - if (devc->audio_flags & DMA_DUPLEX) - ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */ - else - ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ + if (devc->model == MD_IWAVE) + { /* Some magic Interwave specific initialization */ + ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ + ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ + ad_write(devc, 17, 0xc2); /* Alternate feature enable */ + } + } else + { + devc->audio_flags &= ~DMA_DUPLEX; + ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ + } - if (devc->model == MD_1845) - ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */ + outb((0), io_Status(devc)); /* Clear pending interrupts */ - if (devc->model == MD_IWAVE) - { /* Some magic Interwave specific initialization */ - ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ - ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */ - ad_write (devc, 17, 0xc2); /* Alternate feature enable */ - } - } - else - { - devc->audio_flags &= ~DMA_DUPLEX; - ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ - } - - outb ((0), io_Status (devc)); /* Clear pending interrupts */ - - /* - * Toggle the MCE bit. It completes the initialization phase. - */ + /* + * Toggle the MCE bit. It completes the initialization phase. + */ - ad_enter_MCE (devc); /* In case the bit was off */ - ad_leave_MCE (devc); + ad_enter_MCE(devc); /* In case the bit was off */ + ad_leave_MCE(devc); - ad1848_mixer_reset (devc); + ad1848_mixer_reset(devc); } int -ad1848_detect (int io_base, int *ad_flags, int *osp) +ad1848_detect(int io_base, int *ad_flags, int *osp) { - unsigned char tmp; - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - unsigned char tmp1 = 0xff, tmp2 = 0xff; - int optiC930 = 0; /* OPTi 82C930 flag */ - int interwave = 0; - int ad1847_flag = 0; - int cs4248_flag = 0; + unsigned char tmp; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; + unsigned char tmp1 = 0xff, tmp2 = 0xff; + int optiC930 = 0; /* OPTi 82C930 flag */ + int interwave = 0; + int ad1847_flag = 0; + int cs4248_flag = 0; - int i; + int i; - DDB (printk ("ad1848_detect(%x)\n", io_base)); + DDB(printk("ad1848_detect(%x)\n", io_base)); - if (ad_flags) - { - if (*ad_flags == 0x12345678) - { - interwave = 1; - *ad_flags = 0; - } - - if (*ad_flags == 0x12345677) - { - cs4248_flag = 1; - *ad_flags = 0; - } - } - - if (nr_ad1848_devs >= MAX_AUDIO_DEV) - { - printk ("ad1848 - Too many audio devices\n"); - return 0; - } - if (check_region (io_base, 4)) - { - printk ("ad1848.c: Port %x not free.\n", io_base); - return 0; - } - - devc->base = io_base; - devc->irq_ok = 0; - devc->timer_running = 0; - devc->MCE_bit = 0x40; - devc->irq = 0; - devc->open_mode = 0; - devc->chip_name = devc->name = "AD1848"; - devc->model = MD_1848; /* AD1848 or CS4248 */ - devc->levels = NULL; - devc->c930_password_port = 0; - devc->debug_flag = 0; - - /* - * Check that the I/O address is in use. - * - * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power on initialization. Just assume - * this has happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. - */ - - if (inb (devc->base) == 0xff) - { - DDB (printk ("ad1848_detect: The base I/O address appears to be dead\n")); - } + if (ad_flags) + { + if (*ad_flags == 0x12345678) + { + interwave = 1; + *ad_flags = 0; + } + if (*ad_flags == 0x12345677) + { + cs4248_flag = 1; + *ad_flags = 0; + } + } + if (nr_ad1848_devs >= MAX_AUDIO_DEV) + { + printk("ad1848 - Too many audio devices\n"); + return 0; + } + if (check_region(io_base, 4)) + { + printk("ad1848.c: Port %x not free.\n", io_base); + return 0; + } + devc->base = io_base; + devc->irq_ok = 0; + devc->timer_running = 0; + devc->MCE_bit = 0x40; + devc->irq = 0; + devc->open_mode = 0; + devc->chip_name = devc->name = "AD1848"; + devc->model = MD_1848; /* AD1848 or CS4248 */ + devc->levels = NULL; + devc->c930_password_port = 0; + devc->debug_flag = 0; + + /* + * Check that the I/O address is in use. + * + * The bit 0x80 of the base I/O port is known to be 0 after the + * chip has performed its power on initialization. Just assume + * this has happened before the OS is starting. + * + * If the I/O address is unused, it typically returns 0xff. + */ + if (inb(devc->base) == 0xff) + { + DDB(printk("ad1848_detect: The base I/O address appears to be dead\n")); + } /* * Wait for the device to stop initialization */ - DDB (printk ("ad1848_detect() - step 0\n")); + DDB(printk("ad1848_detect() - step 0\n")); - for (i = 0; i < 10000000; i++) - { - unsigned char x = inb (devc->base); - - if (x == 0xff || !(x & 0x80)) - break; - } - - DDB (printk ("ad1848_detect() - step A\n")); - - if (inb (devc->base) == 0x80) /* Not ready. Let's wait */ - ad_leave_MCE (devc); - - if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */ - { - DDB (printk ("ad1848 detect error - step A (%02x)\n", (int) inb (devc->base))); - return 0; - } - - /* - * Test if it's possible to change contents of the indirect registers. - * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only - * so try to avoid using it. - */ - - DDB (printk ("ad1848_detect() - step B\n")); - ad_write (devc, 0, 0xaa); - ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ - - if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) - if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ - ad1847_flag = 1; - else - { - DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); - return 0; - } + for (i = 0; i < 10000000; i++) + { + unsigned char x = inb(devc->base); - DDB (printk ("ad1848_detect() - step C\n")); - ad_write (devc, 0, 0x45); - ad_write (devc, 1, 0xaa); - - if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) - if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ - ad1847_flag = 1; - else - { - DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); - return 0; - } + if (x == 0xff || !(x & 0x80)) + break; + } - /* - * The indirect register I12 has some read only bits. Lets - * try to change them. - */ - - DDB (printk ("ad1848_detect() - step D\n")); - tmp = ad_read (devc, 12); - ad_write (devc, 12, (~tmp) & 0x0f); - - if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f)) - { - DDB (printk ("ad1848 detect error - step D (%x)\n", tmp1)); - return 0; - } - - /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB and 0x0A=RevC. - */ - - /* - * The original AD1848/CS4248 has just 15 indirect registers. This means - * that I0 and I16 should return the same value (etc.). - * However this doesn't work with CS4248. Actually it seems to be impossible - * to detect if the chip is a CS4231 or CS4248. - * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with CS4231. - */ + DDB(printk("ad1848_detect() - step A\n")); + + if (inb(devc->base) == 0x80) /* Not ready. Let's wait */ + ad_leave_MCE(devc); + + if ((inb(devc->base) & 0x80) != 0x00) /* Not a AD1848 */ + { + DDB(printk("ad1848 detect error - step A (%02x)\n", (int) inb(devc->base))); + return 0; + } + /* + * Test if it's possible to change contents of the indirect registers. + * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only + * so try to avoid using it. + */ + + DDB(printk("ad1848_detect() - step B\n")); + ad_write(devc, 0, 0xaa); + ad_write(devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ + + if ((tmp1 = ad_read(devc, 0)) != 0xaa || (tmp2 = ad_read(devc, 1)) != 0x45) + if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB(printk("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); + return 0; + } + DDB(printk("ad1848_detect() - step C\n")); + ad_write(devc, 0, 0x45); + ad_write(devc, 1, 0xaa); + + if ((tmp1 = ad_read(devc, 0)) != 0x45 || (tmp2 = ad_read(devc, 1)) != 0xaa) + if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB(printk("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); + return 0; + } + /* + * The indirect register I12 has some read only bits. Lets + * try to change them. + */ + + DDB(printk("ad1848_detect() - step D\n")); + tmp = ad_read(devc, 12); + ad_write(devc, 12, (~tmp) & 0x0f); + + if ((tmp & 0x0f) != ((tmp1 = ad_read(devc, 12)) & 0x0f)) + { + DDB(printk("ad1848 detect error - step D (%x)\n", tmp1)); + return 0; + } + /* + * NOTE! Last 4 bits of the reg I12 tell the chip revision. + * 0x01=RevB and 0x0A=RevC. + */ + + /* + * The original AD1848/CS4248 has just 15 indirect registers. This means + * that I0 and I16 should return the same value (etc.). + * However this doesn't work with CS4248. Actually it seems to be impossible + * to detect if the chip is a CS4231 or CS4248. + * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails + * with CS4231. + */ /* * OPTi 82C930 has mode2 control bit in another place. This test will fail * with it. Accept this situation as a possible indication of this chip. */ - DDB (printk ("ad1848_detect() - step F\n")); - ad_write (devc, 12, 0); /* Mode2=disabled */ - - for (i = 0; i < 16; i++) - if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) - { - DDB (printk ("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); - if (!ad1847_flag) - optiC930 = 1; - break; - } - - /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). - * The bit 0x80 is always 1 in CS4248 and CS4231. - */ - - DDB (printk ("ad1848_detect() - step G\n")); - - if (ad_flags && *ad_flags == 400) - *ad_flags = 0; - else - ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ - - - if (ad_flags) - *ad_flags = 0; - - tmp1 = ad_read (devc, 12); - if (tmp1 & 0x80) - { - if (ad_flags) - *ad_flags |= AD_F_CS4248; - - devc->chip_name = "CS4248"; /* Our best knowledge just now */ - } - - if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) - { - /* - * CS4231 detected - is it? - * - * Verify that setting I0 doesn't change I16. - */ - DDB (printk ("ad1848_detect() - step H\n")); - ad_write (devc, 16, 0); /* Set I16 to known value */ + DDB(printk("ad1848_detect() - step F\n")); + ad_write(devc, 12, 0); /* Mode2=disabled */ - ad_write (devc, 0, 0x45); - if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */ - { - - ad_write (devc, 0, 0xaa); - if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */ - { - DDB (printk ("ad1848 detect error - step H(%x)\n", tmp1)); - return 0; - } - - /* - * Verify that some bits of I25 are read only. - */ - - DDB (printk ("ad1848_detect() - step I\n")); - tmp1 = ad_read (devc, 25); /* Original bits */ - ad_write (devc, 25, ~tmp1); /* Invert all bits */ - if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7)) - { - int id, full_id; - - /* - * It's at least CS4231 - */ - devc->chip_name = "CS4231"; - - devc->model = MD_4231; - - /* - * It could be an AD1845 or CS4231A as well. - * CS4231 and AD1845 report the same revision info in I25 - * while the CS4231A reports different. - */ - - id = ad_read (devc, 25) & 0xe7; - full_id = ad_read (devc, 25); - if (id == 0x80) /* Device busy??? */ - id = ad_read (devc, 25) & 0xe7; - if (id == 0x80) /* Device still busy??? */ - id = ad_read (devc, 25) & 0xe7; - DDB (printk ("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read (devc, 25))); - - switch (id) - { - - case 0xa0: - devc->chip_name = "CS4231A"; - devc->model = MD_4231A; - break; + for (i = 0; i < 16; i++) + if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) + { + DDB(printk("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); + if (!ad1847_flag) + optiC930 = 1; + break; + } + /* + * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). + * The bit 0x80 is always 1 in CS4248 and CS4231. + */ - case 0xa2: - devc->chip_name = "CS4232"; - devc->model = MD_4232; - break; + DDB(printk("ad1848_detect() - step G\n")); - case 0xb2: - devc->chip_name = "CS4232A"; - devc->model = MD_4232; - break; + if (ad_flags && *ad_flags == 400) + *ad_flags = 0; + else + ad_write(devc, 12, 0x40); /* Set mode2, clear 0x80 */ - case 0x03: - case 0x83: - devc->chip_name = "CS4236"; - devc->model = MD_4232; - break; - case 0x41: - devc->chip_name = "CS4236B"; - devc->model = MD_4232; - break; + if (ad_flags) + *ad_flags = 0; - case 0x80: - { - /* - * It must be a CS4231 or AD1845. The register I23 of - * CS4231 is undefined and it appears to be read only. - * AD1845 uses I23 for setting sample rate. Assume - * the chip is AD1845 if I23 is changeable. - */ - - unsigned char tmp = ad_read (devc, 23); - - ad_write (devc, 23, ~tmp); - if (interwave) - { - devc->model = MD_IWAVE; - devc->chip_name = "IWave"; - } - else if (ad_read (devc, 23) != tmp) /* AD1845 ? */ - { - devc->chip_name = "AD1845"; - devc->model = MD_1845; - } - else if (cs4248_flag) - { - if (ad_flags) + tmp1 = ad_read(devc, 12); + if (tmp1 & 0x80) + { + if (ad_flags) *ad_flags |= AD_F_CS4248; - devc->chip_name = "CS4248"; - devc->model = MD_1848; - ad_write (devc, 12, ad_read (devc, 12) & ~0x40); /* Mode2 off */ - } - - ad_write (devc, 23, tmp); /* Restore */ - } - break; + devc->chip_name = "CS4248"; /* Our best knowledge just now */ + } + if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) + { + /* + * CS4231 detected - is it? + * + * Verify that setting I0 doesn't change I16. + */ + DDB(printk("ad1848_detect() - step H\n")); + ad_write(devc, 16, 0); /* Set I16 to known value */ - default: /* Assume CS4231 or OPTi 82C930 */ - DDB (printk ("ad1848: I25 = %02x/%02x\n", ad_read (devc, 25), ad_read (devc, 25) & 0xe7)); - if (optiC930) + ad_write(devc, 0, 0x45); + if ((tmp1 = ad_read(devc, 16)) != 0x45) /* No change -> CS4231? */ { - devc->chip_name = "82C930"; - devc->model = MD_C930; - } - else - { - devc->model = MD_4231; + + ad_write(devc, 0, 0xaa); + if ((tmp1 = ad_read(devc, 16)) == 0xaa) /* Rotten bits? */ + { + DDB(printk("ad1848 detect error - step H(%x)\n", tmp1)); + return 0; + } + /* + * Verify that some bits of I25 are read only. + */ + + DDB(printk("ad1848_detect() - step I\n")); + tmp1 = ad_read(devc, 25); /* Original bits */ + ad_write(devc, 25, ~tmp1); /* Invert all bits */ + if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) + { + int id, full_id; + + /* + * It's at least CS4231 + */ + devc->chip_name = "CS4231"; + + devc->model = MD_4231; + + /* + * It could be an AD1845 or CS4231A as well. + * CS4231 and AD1845 report the same revision info in I25 + * while the CS4231A reports different. + */ + + id = ad_read(devc, 25) & 0xe7; + full_id = ad_read(devc, 25); + if (id == 0x80) /* Device busy??? */ + id = ad_read(devc, 25) & 0xe7; + if (id == 0x80) /* Device still busy??? */ + id = ad_read(devc, 25) & 0xe7; + DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25))); + + switch (id) + { + + case 0xa0: + devc->chip_name = "CS4231A"; + devc->model = MD_4231A; + break; + + case 0xa2: + devc->chip_name = "CS4232"; + devc->model = MD_4232; + break; + + case 0xb2: + devc->chip_name = "CS4232A"; + devc->model = MD_4232; + break; + + case 0x03: + case 0x83: + devc->chip_name = "CS4236"; + devc->model = MD_4232; + break; + + case 0x41: + devc->chip_name = "CS4236B"; + devc->model = MD_4232; + break; + + case 0x80: + { + /* + * It must be a CS4231 or AD1845. The register I23 of + * CS4231 is undefined and it appears to be read only. + * AD1845 uses I23 for setting sample rate. Assume + * the chip is AD1845 if I23 is changeable. + */ + + unsigned char tmp = ad_read(devc, 23); + + ad_write(devc, 23, ~tmp); + if (interwave) + { + devc->model = MD_IWAVE; + devc->chip_name = "IWave"; + } else if (ad_read(devc, 23) != tmp) /* AD1845 ? */ + { + devc->chip_name = "AD1845"; + devc->model = MD_1845; + } else if (cs4248_flag) + { + if (ad_flags) + *ad_flags |= AD_F_CS4248; + + devc->chip_name = "CS4248"; + devc->model = MD_1848; + ad_write(devc, 12, ad_read(devc, 12) & ~0x40); /* Mode2 off */ + } + ad_write(devc, 23, tmp); /* Restore */ + } + break; + + default: /* Assume CS4231 or OPTi 82C930 */ + DDB(printk("ad1848: I25 = %02x/%02x\n", ad_read(devc, 25), ad_read(devc, 25) & 0xe7)); + if (optiC930) + { + devc->chip_name = "82C930"; + devc->model = MD_C930; + } else + { + devc->model = MD_4231; + } + + } + } + ad_write(devc, 25, tmp1); /* Restore bits */ + + DDB(printk("ad1848_detect() - step K\n")); } + } + DDB(printk("ad1848_detect() - step L\n")); + if (ad_flags) + { + if (devc->model != MD_1848) + *ad_flags |= AD_F_CS4231; + } + DDB(printk("ad1848_detect() - Detected OK\n")); - } - } - ad_write (devc, 25, tmp1); /* Restore bits */ + if (devc->model == MD_1848 && ad1847_flag) + devc->chip_name = "AD1847"; - DDB (printk ("ad1848_detect() - step K\n")); - } - } - DDB (printk ("ad1848_detect() - step L\n")); - if (ad_flags) - { - if (devc->model != MD_1848) - *ad_flags |= AD_F_CS4231; - } + return 1; +} + +int +ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) +{ + /* + * NOTE! If irq < 0, there is another driver which has allocated the IRQ + * so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). + */ + + + int my_dev; + char dev_name[100]; + int e; + + ad1848_info *devc = &adev_info[nr_ad1848_devs]; + + ad1848_port_info *portc = NULL; + + devc->irq = (irq > 0) ? irq : 0; + devc->open_mode = 0; + devc->timer_ticks = 0; + devc->dma1 = dma_playback; + devc->dma2 = dma_capture; + devc->audio_flags = DMA_AUTOMODE; + devc->playback_dev = devc->record_dev = 0; + if (name != NULL) + devc->name = name; + + if (name != NULL && name[0] != 0) + sprintf(dev_name, + "%s (%s)", name, devc->chip_name); + else + sprintf(dev_name, + "Generic audio codec (%s)", devc->chip_name); - DDB (printk ("ad1848_detect() - Detected OK\n")); + request_region(devc->base, 4, devc->name); - if (devc->model == MD_1848 && ad1847_flag) - devc->chip_name = "AD1847"; + conf_printf2(dev_name, + devc->base, devc->irq, dma_playback, dma_capture); + if (devc->model == MD_1848 || devc->model == MD_C930) + devc->audio_flags |= DMA_HARDSTOP; - return 1; -} + if (devc->model > MD_1848) + { + if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) + devc->audio_flags &= ~DMA_DUPLEX; + else + devc->audio_flags |= DMA_DUPLEX; + } + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + dev_name, + &ad1848_audio_driver, + sizeof(struct audio_driver), + devc->audio_flags, + ad_format_mask[devc->model], + devc, + dma_playback, + dma_capture)) < 0) + { + return -1; + } + portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info))); + sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info); + if (sound_nblocks < 1024) + sound_nblocks++;; + audio_devs[my_dev]->portc = portc; + memset((char *) portc, 0, sizeof(*portc)); -void -ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) -{ - /* - * NOTE! If irq < 0, there is another driver which has allocated the IRQ - * so that this driver doesn't need to allocate/deallocate it. - * The actually used IRQ is ABS(irq). - */ - - - int my_dev; - char dev_name[100]; - - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - - ad1848_port_info *portc = NULL; - - devc->irq = (irq > 0) ? irq : 0; - devc->open_mode = 0; - devc->timer_ticks = 0; - devc->dma1 = dma_playback; - devc->dma2 = dma_capture; - devc->audio_flags = DMA_AUTOMODE; - devc->playback_dev = devc->record_dev = 0; - if (name != NULL) - devc->name = name; - - if (name != NULL && name[0] != 0) - sprintf (dev_name, - "%s (%s)", name, devc->chip_name); - else - sprintf (dev_name, - "Generic audio codec (%s)", devc->chip_name); - - request_region (devc->base, 4, devc->name); - - conf_printf2 (dev_name, - devc->base, devc->irq, dma_playback, dma_capture); - - if (devc->model == MD_1848 || devc->model == MD_C930) - devc->audio_flags |= DMA_HARDSTOP; - - if (devc->model > MD_1848) - { - if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) - devc->audio_flags &= ~DMA_DUPLEX; - else - devc->audio_flags |= DMA_DUPLEX; - } - - if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - dev_name, - &ad1848_audio_driver, - sizeof (struct audio_driver), - devc->audio_flags, - ad_format_mask[devc->model], - devc, - dma_playback, - dma_capture)) < 0) - { - return; - } - - - portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (ad1848_port_info))); - sound_mem_sizes[sound_nblocks] = sizeof (ad1848_port_info); - if (sound_nblocks < 1024) - sound_nblocks++;; - audio_devs[my_dev]->portc = portc; - memset ((char *) portc, 0, sizeof (*portc)); - - nr_ad1848_devs++; - - ad1848_init_hw (devc); - - if (irq > 0) - { - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler (devc->irq, adintr, - devc->name, - NULL) < 0) - { - printk ("ad1848: IRQ in use\n"); - } + nr_ad1848_devs++; - if (devc->model != MD_1848 && devc->model != MD_C930) - { - int x; - unsigned char tmp = ad_read (devc, 16); + ad1848_init_hw(devc); - devc->timer_ticks = 0; + if (irq > 0) + { + irq2dev[irq] = devc->dev_no = my_dev; + if (snd_set_irq_handler(devc->irq, adintr, + devc->name, + NULL) < 0) + { + printk(KERN_WARNING "ad1848: IRQ in use\n"); + } + if (devc->model != MD_1848 && devc->model != MD_C930) + { + int x; + unsigned char tmp = ad_read(devc, 16); - ad_write (devc, 21, 0x00); /* Timer MSB */ - ad_write (devc, 20, 0x10); /* Timer LSB */ + devc->timer_ticks = 0; - ad_write (devc, 16, tmp | 0x40); /* Enable timer */ - for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); - ad_write (devc, 16, tmp & ~0x40); /* Disable timer */ - - if (devc->timer_ticks == 0) - printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); - else - { - DDB (printk ("Interrupt test OK\n")); - devc->irq_ok = 1; - } - } - else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ - } - else if (irq < 0) - irq2dev[-irq] = devc->dev_no = my_dev; + ad_write(devc, 21, 0x00); /* Timer MSB */ + ad_write(devc, 20, 0x10); /* Timer LSB */ -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (devc->model != MD_1848 && - devc->model != MD_C930 && devc->irq_ok) - ad1848_tmr_install (my_dev); + ad_write(devc, 16, tmp | 0x40); /* Enable timer */ + for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); + ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ + + if (devc->timer_ticks == 0) + printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); + else + { + DDB(printk("Interrupt test OK\n")); + devc->irq_ok = 1; + } + } else + devc->irq_ok = 1; /* Couldn't test. assume it's OK */ + } else if (irq < 0) + irq2dev[-irq] = devc->dev_no = my_dev; + +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + if (devc->model != MD_1848 && + devc->model != MD_C930 && devc->irq_ok) + ad1848_tmr_install(my_dev); #endif - if (!share_dma) - { - if (sound_alloc_dma (dma_playback, devc->name)) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma (dma_capture, devc->name)) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture); - } - - if (sound_install_mixer (MIXER_DRIVER_VERSION, - dev_name, - &ad1848_mixer_operations, - sizeof (struct mixer_operations), - devc) >= 0) - { - audio_devs[my_dev]->mixer_dev = num_mixers - 1; - } + if (!share_dma) + { + if (sound_alloc_dma(dma_playback, devc->name)) + printk("ad1848.c: Can't allocate DMA%d\n", dma_playback); + if (dma_capture != dma_playback) + if (sound_alloc_dma(dma_capture, devc->name)) + printk("ad1848.c: Can't allocate DMA%d\n", dma_capture); + } + if ((e = sound_install_mixer(MIXER_DRIVER_VERSION, + dev_name, + &ad1848_mixer_operations, + sizeof(struct mixer_operations), + devc)) >= 0) + { + audio_devs[my_dev]->mixer_dev = e; + } + MOD_INC_USE_COUNT; + return my_dev; } -void -ad1848_control (int cmd, int arg) +void ad1848_control(int cmd, int arg) { - ad1848_info *devc; + ad1848_info *devc; - if (nr_ad1848_devs < 1) - return; + if (nr_ad1848_devs < 1) + return; + + devc = &adev_info[nr_ad1848_devs - 1]; + + switch (cmd) + { + case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ + if (devc->model != MD_1845) + return; + ad_enter_MCE(devc); + ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); + ad_leave_MCE(devc); + break; - devc = &adev_info[nr_ad1848_devs - 1]; + case AD1848_MIXER_REROUTE: + { + int o = (arg >> 8) & 0xff; + int n = arg & 0xff; - switch (cmd) - { - case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845) + if (n == SOUND_MIXER_NONE) + { /* Just hide this control */ + ad1848_mixer_set(devc, o, 0); /* Shut up it */ + devc->supported_devices &= ~(1 << o); + devc->supported_rec_devices &= ~(1 << o); + return; + } + /* Make the mixer control identified by o to appear as n */ + + if (o < 0 || o > SOUND_MIXER_NRDEVICES) + return; + if (n < 0 || n > SOUND_MIXER_NRDEVICES) + return; + if (!(devc->supported_devices & (1 << o))) + return; /* Not supported */ + + devc->mixer_reroute[n] = o; /* Rename the control */ + devc->supported_devices &= ~(1 << o); + devc->supported_devices |= (1 << n); + if (devc->supported_rec_devices & (1 << o)) + devc->supported_rec_devices |= (1 << n); + devc->supported_rec_devices &= ~(1 << o); + } + break; + } return; - ad_enter_MCE (devc); - ad_write (devc, 29, (ad_read (devc, 29) & 0x1f) | (arg << 5)); - ad_leave_MCE (devc); - break; - - case AD1848_MIXER_REROUTE: - { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; - - if (n == SOUND_MIXER_NONE) - { /* Just hide this control */ - ad1848_mixer_set (devc, o, 0); /* Shut up it */ - devc->supported_devices &= ~(1 << o); - devc->supported_rec_devices &= ~(1 << o); - return; - } - - /* Make the mixer control identified by o to appear as n */ - - if (o < 0 || o > SOUND_MIXER_NRDEVICES) - return; - if (n < 0 || n > SOUND_MIXER_NRDEVICES) - return; - if (!(devc->supported_devices & (1 << o))) - return; /* Not supported */ - - devc->mixer_reroute[n] = o; /* Rename the control */ - devc->supported_devices &= ~(1 << o); - devc->supported_devices |= (1 << n); - if (devc->supported_rec_devices & (1 << o)) - devc->supported_rec_devices |= (1 << n); - devc->supported_rec_devices &= ~(1 << o); - } - break; - } } void -ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma) +ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) { - int i, dev = 0; - ad1848_info *devc = NULL; + int i, dev = 0; + ad1848_info *devc = NULL; - for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) - if (adev_info[i].base == io_base) - { - devc = &adev_info[i]; - dev = devc->dev_no; - } - - if (devc != NULL) - { - release_region (devc->base, 4); + for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) + if (adev_info[i].base == io_base) + { + devc = &adev_info[i]; + dev = devc->dev_no; + } + if (devc != NULL) + { + release_region(devc->base, 4); - if (!share_dma) - { - if (irq > 0) - snd_release_irq (devc->irq); + if (!share_dma) + { + if (irq > 0) + snd_release_irq(devc->irq); - sound_free_dma (audio_devs[dev]->dmap_out->dma); + sound_free_dma(audio_devs[dev]->dmap_out->dma); - if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma) - sound_free_dma (audio_devs[dev]->dmap_in->dma); - } - } - else - printk ("ad1848: Can't find device to be unloaded. Base=%x\n", io_base); + if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma) + sound_free_dma(audio_devs[dev]->dmap_in->dma); + } + } else + printk("ad1848: Can't find device to be unloaded. Base=%x\n", io_base); + MOD_DEC_USE_COUNT; } -void -adintr (int irq, void *dev_id, struct pt_regs *dummy) +void adintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char status; - ad1848_info *devc; - int dev; - int alt_stat = 0xff; - unsigned char c930_stat = 0; - int cnt = 0; - - if (irq < 0 || irq > 15) - { - dev = -1; - } - else - dev = irq2dev[irq]; - - if (dev < 0 || dev >= num_audiodevs) - { - for (irq = 0; irq < 17; irq++) - if (irq2dev[irq] != -1) - break; + unsigned char status; + ad1848_info *devc; + int dev; + int alt_stat = 0xff; + unsigned char c930_stat = 0; + int cnt = 0; - if (irq > 15) - { - /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ - return; - } + if (irq < 0 || irq > 15) + { + dev = -1; + } else + dev = irq2dev[irq]; - dev = irq2dev[irq]; - devc = (ad1848_info *) audio_devs[dev]->devc; - } - else - devc = (ad1848_info *) audio_devs[dev]->devc; - -interrupt_again: /* Jump back here if int status doesn't reset */ - - status = inb (io_Status (devc)); - - if (status == 0x80) - printk ("adintr: Why?\n"); - if (devc->model == MD_1848) - outb ((0), io_Status (devc)); /* Clear interrupt status */ - - if (status & 0x01) - { - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - - save_flags (flags); - cli (); - - alt_stat = 0; - - if (devc->c930_password_port) - outb ((0xe4), devc->c930_password_port); /* Password */ - outb ((11), 0xe0e); - c930_stat = inb (0xe0f); - - if (c930_stat & 0x04) - alt_stat |= 0x10; /* Playback intr */ - if (c930_stat & 0x08) - alt_stat |= 0x20; /* Playback intr */ - restore_flags (flags); - } - else if (devc->model != MD_1848) - alt_stat = ad_read (devc, 24); + if (dev < 0 || dev >= num_audiodevs) + { + for (irq = 0; irq < 17; irq++) + if (irq2dev[irq] != -1) + break; - /* Acknowledge the intr before proceeding */ - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - - save_flags (flags); - cli (); - - if (devc->c930_password_port) - outb ((0xe4), devc->c930_password_port); /* Password */ - outb ((11), 0xe0e); - outb ((~c930_stat), 0xe0f); - restore_flags (flags); - } - else if (devc->model != MD_1848) - ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat); /* Selective ack */ + if (irq > 15) + { + /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ + return; + } + dev = irq2dev[irq]; + devc = (ad1848_info *) audio_devs[dev]->devc; + } else + devc = (ad1848_info *) audio_devs[dev]->devc; - if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) - { - DMAbuf_inputintr (devc->record_dev); - } + interrupt_again: /* Jump back here if int status doesn't reset */ - if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT && - alt_stat & 0x10) - { - DMAbuf_outputintr (devc->playback_dev, 1); - } + status = inb(io_Status(devc)); - if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ - { - devc->timer_ticks++; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (timer_installed == dev && devc->timer_running) - sound_timer_interrupt (); -#endif - } - } + if (status == 0x80) + printk("adintr: Why?\n"); + if (devc->model == MD_1848) + outb((0), io_Status(devc)); /* Clear interrupt status */ + + if (status & 0x01) + { + if (devc->model == MD_C930) + { /* 82C930 has interrupt status register in MAD16 register MC11 */ + unsigned long flags; + + save_flags(flags); + cli(); + + alt_stat = 0; + + if (devc->c930_password_port) + outb((0xe4), devc->c930_password_port); /* Password */ + outb((11), 0xe0e); + c930_stat = inb(0xe0f); + + if (c930_stat & 0x04) + alt_stat |= 0x10; /* Playback intr */ + if (c930_stat & 0x08) + alt_stat |= 0x20; /* Playback intr */ + restore_flags(flags); + } else if (devc->model != MD_1848) + alt_stat = ad_read(devc, 24); + + /* Acknowledge the intr before proceeding */ + if (devc->model == MD_C930) + { /* 82C930 has interrupt status register in MAD16 register MC11 */ + unsigned long flags; + + save_flags(flags); + cli(); + + if (devc->c930_password_port) + outb((0xe4), devc->c930_password_port); /* Password */ + outb((11), 0xe0e); + outb((~c930_stat), 0xe0f); + restore_flags(flags); + } else if (devc->model != MD_1848) + ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ + if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) + { + DMAbuf_inputintr(devc->record_dev); + } + if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT && + alt_stat & 0x10) + { + DMAbuf_outputintr(devc->playback_dev, 1); + } + if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + { + devc->timer_ticks++; +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + if (timer_installed == dev && devc->timer_running) + sound_timer_interrupt(); +#endif + } + } /* * Sometimes playback or capture interrupts occur while a timer interrupt * is being handled. The interrupt will not be retriggered if we don't * handle it now. Check if an interrupt is still pending and restart * the handler in this case. */ - if (inb (io_Status (devc)) & 0x01 && cnt++ < 4) - { - goto interrupt_again; - } + if (inb(io_Status(devc)) & 0x01 && cnt++ < 4) + { + goto interrupt_again; + } } #ifdef DESKPROXL @@ -2076,23 +2019,21 @@ */ static int -init_deskpro (struct address_info *hw_config) +init_deskpro(struct address_info *hw_config) { - unsigned char tmp; - - if ((tmp = inb (0xc44)) == 0xff) - { - DDB (printk ("init_deskpro: Dead port 0xc44\n")); - return 0; - } - - outb ((tmp | 0x04), 0xc44); /* Select bank 1 */ - if (inb (0xc44) != 0x04) - { - DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n")); - return 0; - } + unsigned char tmp; + if ((tmp = inb(0xc44)) == 0xff) + { + DDB(printk("init_deskpro: Dead port 0xc44\n")); + return 0; + } + outb((tmp | 0x04), 0xc44); /* Select bank 1 */ + if (inb(0xc44) != 0x04) + { + DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n")); + return 0; + } /* * OK. It looks like a Deskpro so let's proceed. */ @@ -2125,44 +2066,44 @@ */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc44 (before): "); - outb ((tmp & ~0x04), 0xc44); - printk ("%02x ", inb (0xc44)); - outb ((tmp | 0x04), 0xc44); - printk ("%02x\n", inb (0xc44)); + /* Debug printing */ + printk("Port 0xc44 (before): "); + outb((tmp & ~0x04), 0xc44); + printk("%02x ", inb(0xc44)); + outb((tmp | 0x04), 0xc44); + printk("%02x\n", inb(0xc44)); #endif - /* Set bank 1 of the register */ - tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ + /* Set bank 1 of the register */ + tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ - switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0x604: - tmp |= 0x01; - break; - case 0xf40: - tmp |= 0x02; - break; - case 0xe80: - tmp |= 0x03; - break; - default: - DDB (printk ("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); - return 0; - } - outb ((tmp & ~0x04), 0xc44); /* Write to bank=0 */ + switch (hw_config->io_base) + { + case 0x530: + tmp |= 0x00; + break; + case 0x604: + tmp |= 0x01; + break; + case 0xf40: + tmp |= 0x02; + break; + case 0xe80: + tmp |= 0x03; + break; + default: + DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); + return 0; + } + outb((tmp & ~0x04), 0xc44); /* Write to bank=0 */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc44 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc44)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc44)); + /* Debug printing */ + printk("Port 0xc44 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc44)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc44)); #endif /* @@ -2176,26 +2117,26 @@ */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc45 (before): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc45)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc45)); + /* Debug printing */ + printk("Port 0xc45 (before): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc45)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc45)); #endif - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb ((0x88), 0xc45); /* FM base 7:0 = 0x88 */ - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb ((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + outb((0x88), 0xc45); /* FM base 7:0 = 0x88 */ + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + outb((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc45 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc45)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc45)); + /* Debug printing */ + printk("Port 0xc45 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc45)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc45)); #endif @@ -2207,26 +2148,26 @@ */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc46 (before): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc46)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc46)); + /* Debug printing */ + printk("Port 0xc46 (before): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc46)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc46)); #endif - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb ((0x03), 0xc46); /* FM base 15:8 = 0x03 */ - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb ((0x11), 0xc46); /* ASIC ID = 0x11 */ + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + outb((0x03), 0xc46); /* FM base 15:8 = 0x03 */ + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + outb((0x11), 0xc46); /* ASIC ID = 0x11 */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc46 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc46)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc46)); + /* Debug printing */ + printk("Port 0xc46 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc46)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc46)); #endif /* @@ -2237,26 +2178,26 @@ */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc47 (before): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc47)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc47)); + /* Debug printing */ + printk("Port 0xc47 (before): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc47)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc47)); #endif - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - outb ((0x7c), 0xc47); /* FM decode enable bits = 0x7c */ - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - outb ((0x00), 0xc47); /* Reserved bank1 = 0x00 */ + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + outb((0x7c), 0xc47); /* FM decode enable bits = 0x7c */ + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + outb((0x00), 0xc47); /* Reserved bank1 = 0x00 */ #ifdef DEBUGXL - /* Debug printing */ - printk ("Port 0xc47 (after): "); - outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */ - printk ("%02x ", inb (0xc47)); - outb ((tmp | 0x04), 0xc44); /* Select bank=1 */ - printk ("%02x\n", inb (0xc47)); + /* Debug printing */ + printk("Port 0xc47 (after): "); + outb((tmp & ~0x04), 0xc44); /* Select bank=0 */ + printk("%02x ", inb(0xc47)); + outb((tmp | 0x04), 0xc44); /* Select bank=1 */ + printk("%02x\n", inb(0xc47)); #endif /* @@ -2264,209 +2205,202 @@ */ #ifdef DEBUGXL - printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f)); + printk("Port 0xc6f (before) = %02x\n", inb(0xc6f)); #endif - outb ((0x80), 0xc6f); + outb((0x80), 0xc6f); #ifdef DEBUGXL - printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f)); + printk("Port 0xc6f (after) = %02x\n", inb(0xc6f)); #endif - return 1; + return 1; } #endif int -probe_ms_sound (struct address_info *hw_config) +probe_ms_sound(struct address_info *hw_config) { - unsigned char tmp; - - DDB (printk ("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); + unsigned char tmp; - if (check_region (hw_config->io_base, 8)) - { - printk ("MSS: I/O port conflict\n"); - return 0; - } - - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - /* check_opl3(0x388, hw_config); */ - return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); - } + DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); + if (check_region(hw_config->io_base, 8)) + { + printk("MSS: I/O port conflict\n"); + return 0; + } + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ + { + /* check_opl3(0x388, hw_config); */ + return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); + } #ifdef DESKPROXL - if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ - { - if (!init_deskpro (hw_config)) - return 0; - } + if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ + { + if (!init_deskpro(hw_config)) + return 0; + } #endif - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00 or 0x0f. - */ - - if ((tmp = inb (hw_config->io_base + 3)) == 0xff) /* Bus float */ - { - int ret; + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00 or 0x0f. + */ - DDB (printk ("I/O address is inactive (%x)\n", tmp)); - if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))) - return 0; - return 1; - } - DDB (printk ("MSS signature = %x\n", tmp & 0x3f)); - if ((tmp & 0x3f) != 0x04 && - (tmp & 0x3f) != 0x0f && - (tmp & 0x3f) != 0x00) - { - int ret; - - DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb (hw_config->io_base + 3))); - DDB (printk ("Trying to detect codec anyway but IRQ/DMA may not work\n")); - if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))) - return 0; + if ((tmp = inb(hw_config->io_base + 3)) == 0xff) /* Bus float */ + { + int ret; - hw_config->card_subtype = 1; - return 1; - } - - if (hw_config->irq > 11) - { - printk ("MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } - - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk ("MSS: Bad DMA %d\n", hw_config->dma); - return 0; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - - if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - return 0; - } + DDB(printk("I/O address is inactive (%x)\n", tmp)); + if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) + return 0; + return 1; + } + DDB(printk("MSS signature = %x\n", tmp & 0x3f)); + if ((tmp & 0x3f) != 0x04 && + (tmp & 0x3f) != 0x0f && + (tmp & 0x3f) != 0x00) + { + int ret; + + MDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3))); + DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n")); + if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) + return 0; - return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); + hw_config->card_subtype = 1; + return 1; + } + if (hw_config->irq > 11) + { + printk("MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk("MSS: Bad DMA %d\n", hw_config->dma); + return 0; + } + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } + if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + return 0; + } + return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); } void -attach_ms_sound (struct address_info *hw_config) +attach_ms_sound(struct address_info *hw_config) { - static char interrupt_bits[12] = - { - -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - char bits, dma2_bit = 0; + static char interrupt_bits[12] = + { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; + char bits, dma2_bit = 0; - static char dma_bits[4] = - { - 1, 2, 0, 3 - }; + static char dma_bits[4] = + { + 1, 2, 0, 3 + }; - int config_port = hw_config->io_base + 0; - int version_port = hw_config->io_base + 3; - int dma = hw_config->dma; - int dma2 = hw_config->dma2; - - if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - ad1848_init ("MS Sound System", hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0, hw_config->osp); - request_region (hw_config->io_base, 4, "WSS config"); - return; - } - - /* - * Set the IRQ and DMA addresses. - */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == -1) - { - printk ("MSS: Bad IRQ %d\n", hw_config->irq); - return; - } - - outb ((bits | 0x40), config_port); - if ((inb (version_port) & 0x40) == 0) - printk ("[MSS: IRQ Conflict?]"); + int config_port = hw_config->io_base + 0; + int version_port = hw_config->io_base + 3; + int dma = hw_config->dma; + int dma2 = hw_config->dma2; + + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ + { + hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma2, 0, hw_config->osp); + request_region(hw_config->io_base, 4, "WSS config"); + return; + } + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + { + printk("MSS: Bad IRQ %d\n", hw_config->irq); + return; + } + outb((bits | 0x40), config_port); + if ((inb(version_port) & 0x40) == 0) + printk("[MSS: IRQ Conflict?]"); /* * Handle the capture DMA channel */ - if (dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; + if (dma2 != -1 && dma2 != dma) + { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; - dma = dma2; - dma2 = tmp; - } + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } else + { + printk("MSS: Invalid capture DMA\n"); + dma2 = dma; + } + } else + { + dma2 = dma; + } - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } - else - { - printk ("MSS: Invalid capture DMA\n"); - dma2 = dma; - } - } - else - { - dma2 = dma; - } - - hw_config->dma = dma; - hw_config->dma2 = dma2; - - outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - - ad1848_init ("MSS audio codec", hw_config->io_base + 4, - hw_config->irq, - dma, - dma2, 0, - hw_config->osp); - request_region (hw_config->io_base, 4, "WSS config"); + hw_config->dma = dma; + hw_config->dma2 = dma2; + + outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ + + hw_config->slots[0] = ad1848_init("MSS audio codec", hw_config->io_base + 4, + hw_config->irq, + dma, + dma2, 0, + hw_config->osp); + request_region(hw_config->io_base, 4, "WSS config"); } void -unload_ms_sound (struct address_info *hw_config) +unload_ms_sound(struct address_info *hw_config) { - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0); - release_region (hw_config->io_base, 4); + int mixer = audio_devs[hw_config->slots[0]]->mixer_dev; + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma, 0); + if(mixer>=0) + sound_unload_mixerdev(mixer); + sound_unload_audiodev(hw_config->slots[0]); + release_region(hw_config->io_base, 4); + } -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) /* * Timer stuff (for /dev/music). */ @@ -2474,15 +2408,15 @@ static unsigned int current_interval = 0; static unsigned int -ad1848_tmr_start (int dev, unsigned int usecs) +ad1848_tmr_start(int dev, unsigned int usecs) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ - unsigned long divider; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ + unsigned long divider; - save_flags (flags); - cli (); + save_flags(flags); + cli(); /* * Length of the timer interval (in nanoseconds) depends on the @@ -2495,91 +2429,162 @@ * the timer divider. */ - if (devc->model == MD_1845) - xtal_nsecs = 10050; - else if (ad_read (devc, 8) & 0x01) - xtal_nsecs = 9920; - else - xtal_nsecs = 9969; - - divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs; - - if (divider < 100) /* Don't allow shorter intervals than about 1ms */ - divider = 100; - - if (divider > 65535) /* Overflow check */ - divider = 65535; - - ad_write (devc, 21, (divider >> 8) & 0xff); /* Set upper bits */ - ad_write (devc, 20, divider & 0xff); /* Set lower bits */ - ad_write (devc, 16, ad_read (devc, 16) | 0x40); /* Start the timer */ - devc->timer_running = 1; - restore_flags (flags); + if (devc->model == MD_1845) + xtal_nsecs = 10050; + else if (ad_read(devc, 8) & 0x01) + xtal_nsecs = 9920; + else + xtal_nsecs = 9969; + + divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs; + + if (divider < 100) /* Don't allow shorter intervals than about 1ms */ + divider = 100; + + if (divider > 65535) /* Overflow check */ + divider = 65535; + + ad_write(devc, 21, (divider >> 8) & 0xff); /* Set upper bits */ + ad_write(devc, 20, divider & 0xff); /* Set lower bits */ + ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */ + devc->timer_running = 1; + restore_flags(flags); - return current_interval = (divider * xtal_nsecs + 500) / 1000; + return current_interval = (divider * xtal_nsecs + 500) / 1000; } static void -ad1848_tmr_reprogram (int dev) +ad1848_tmr_reprogram(int dev) { /* * Audio driver has changed sampling rate so that a different xtal * oscillator was selected. We have to reprogram the timer rate. */ - ad1848_tmr_start (dev, current_interval); - sound_timer_syncinterval (current_interval); + ad1848_tmr_start(dev, current_interval); + sound_timer_syncinterval(current_interval); } static void -ad1848_tmr_disable (int dev) +ad1848_tmr_disable(int dev) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - save_flags (flags); - cli (); - ad_write (devc, 16, ad_read (devc, 16) & ~0x40); - devc->timer_running = 0; - restore_flags (flags); + save_flags(flags); + cli(); + ad_write(devc, 16, ad_read(devc, 16) & ~0x40); + devc->timer_running = 0; + restore_flags(flags); } static void -ad1848_tmr_restart (int dev) +ad1848_tmr_restart(int dev) { - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - if (current_interval == 0) - return; + if (current_interval == 0) + return; - save_flags (flags); - cli (); - ad_write (devc, 16, ad_read (devc, 16) | 0x40); - devc->timer_running = 1; - restore_flags (flags); + save_flags(flags); + cli(); + ad_write(devc, 16, ad_read(devc, 16) | 0x40); + devc->timer_running = 1; + restore_flags(flags); } static struct sound_lowlev_timer ad1848_tmr = { - 0, - 2, - ad1848_tmr_start, - ad1848_tmr_disable, - ad1848_tmr_restart + 0, + 2, + ad1848_tmr_start, + ad1848_tmr_disable, + ad1848_tmr_restart }; static int -ad1848_tmr_install (int dev) +ad1848_tmr_install(int dev) { - if (timer_installed != -1) - return 0; /* Don't install another timer */ + if (timer_installed != -1) + return 0; /* Don't install another timer */ - timer_installed = ad1848_tmr.dev = dev; - sound_timer_init (&ad1848_tmr, audio_devs[dev]->name); + timer_installed = ad1848_tmr.dev = dev; + sound_timer_init(&ad1848_tmr, audio_devs[dev]->name); - return 1; + return 1; } +#endif + + +EXPORT_SYMBOL(ad1848_detect); +EXPORT_SYMBOL(ad1848_init); +EXPORT_SYMBOL(ad1848_unload); +EXPORT_SYMBOL(adintr); +EXPORT_SYMBOL(probe_ms_sound); +EXPORT_SYMBOL(attach_ms_sound); +EXPORT_SYMBOL(unload_ms_sound); + +#ifdef MODULE + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma2, "i"); +MODULE_PARM(type, "i"); + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; +int type = 0; + +static int loaded = 0; + +struct address_info hw_config; + + +int init_module(void) +{ + printk("ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + if(io!=-1) + { + if(irq == -1 || dma == -1) + { + printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n"); + return -EINVAL; + } + hw_config.irq = irq; + hw_config.io_base = io; + hw_config.dma = dma; + hw_config.dma2 = dma2; + hw_config.card_subtype = type; + if(!probe_ms_sound(&hw_config)) + return -ENODEV; + attach_ms_sound(&hw_config); + loaded=1; + } + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + SOUND_LOCK_END; + if(loaded) + unload_ms_sound(&hw_config); +/* unregister_symtab(&ad1848_syms); */ +} + +#else + +void +export_ad1848_syms(void) +{ + register_symtab(&ad1848_syms); +} + #endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.1.66/linux/drivers/sound/adlib_card.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/adlib_card.c Sat Nov 29 10:33:20 1997 @@ -12,38 +12,62 @@ * for more info. */ #include +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_YM3812 +#if defined(CONFIG_YM3812) || defined(MODULE) -void -attach_adlib_card (struct address_info *hw_config) +void attach_adlib_card(struct address_info *hw_config) { - - opl3_init (hw_config->io_base, hw_config->osp); - request_region (hw_config->io_base, 4, "OPL3/OPL2"); + hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp); + request_region(hw_config->io_base, 4, "OPL3/OPL2"); } -int -probe_adlib (struct address_info *hw_config) +int probe_adlib(struct address_info *hw_config) { - if (check_region (hw_config->io_base, 4)) - { - DDB (printk ("opl3.c: I/O port %x already in use\n", hw_config->io_base)); - return 0; - } + if (check_region(hw_config->io_base, 4)) { + DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); + return 0; + } + return opl3_detect(hw_config->io_base, hw_config->osp); +} - return opl3_detect (hw_config->io_base, hw_config->osp); +void unload_adlib(struct address_info *hw_config) +{ + release_region(hw_config->io_base, 4); + sound_unload_synthdev(hw_config->slots[0]); } -void -unload_adlib (struct address_info *hw_config) +#ifdef MODULE + +int io = -1; +MODULE_PARM(io, "i"); + +struct address_info cfg; + +int init_module(void) { - release_region (hw_config->io_base, 4); + if (io == -1) { + printk("adlib: must specify I/O address.\n"); + return -EINVAL; + } + cfg.io_base = io; + if (probe_adlib(&cfg) == 0) + return -ENODEV; + attach_adlib_card(&cfg); + SOUND_LOCK; + return 0; } +void cleanup_module(void) +{ + unload_adlib(&cfg); + SOUND_LOCK_END; +} +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.66/linux/drivers/sound/audio.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/audio.c Sat Nov 29 10:33:20 1997 @@ -16,7 +16,7 @@ #include "sound_config.h" -#ifdef CONFIG_AUDIO +#if defined(CONFIG_AUDIO) || defined(MODULE) #include "ulaw.h" #include "coproc.h" @@ -30,7 +30,7 @@ #define AM_NONE 0 #define AM_WRITE OPEN_WRITE #define AM_READ OPEN_READ -int dma_ioctl (int dev, unsigned int cmd, caddr_t arg); +int dma_ioctl(int dev, unsigned int cmd, caddr_t arg); static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV]; @@ -38,562 +38,546 @@ #define CNV_MU_LAW 0x00000001 static int -set_format (int dev, int fmt) +set_format(int dev, int fmt) { - if (fmt != AFMT_QUERY) - { - local_conversion[dev] = 0; - - if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ - if (fmt == AFMT_MU_LAW) + if (fmt != AFMT_QUERY) { - fmt = AFMT_U8; - local_conversion[dev] = CNV_MU_LAW; - } - else - fmt = AFMT_U8; /* This is always supported */ + local_conversion[dev] = 0; - audio_format[dev] = audio_devs[dev]->d->set_bits (dev, fmt); - local_format[dev] = fmt; - } - else - return local_format[dev]; + if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ + if (fmt == AFMT_MU_LAW) + { + fmt = AFMT_U8; + local_conversion[dev] = CNV_MU_LAW; + } else + fmt = AFMT_U8; /* This is always supported */ + + audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt); + local_format[dev] = fmt; + } else + return local_format[dev]; - return local_format[dev]; + return local_format[dev]; } int -audio_open (int dev, struct fileinfo *file) +audio_open(int dev, struct fileinfo *file) { - int ret; - int bits; - int dev_type = dev & 0x0f; - int mode = file->mode & O_ACCMODE; - - dev = dev >> 4; - - if (dev_type == SND_DEV_DSP16) - bits = 16; - else - bits = 8; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - if ((ret = DMAbuf_open (dev, mode)) < 0) - return ret; - - if (audio_devs[dev]->coproc) - if ((ret = audio_devs[dev]->coproc-> - open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) - { - audio_release (dev, file); - printk ("Sound: Can't access coprocessor device\n"); + int ret; + int bits; + int dev_type = dev & 0x0f; + int mode = file->mode & O_ACCMODE; - return ret; - } + dev = dev >> 4; - local_conversion[dev] = 0; + if (dev_type == SND_DEV_DSP16) + bits = 16; + else + bits = 8; - if (dev_type == SND_DEV_AUDIO) - { - set_format (dev, AFMT_MU_LAW); - } - else - set_format (dev, bits); + if (dev < 0 || dev >= num_audiodevs) + return -ENXIO; - audio_mode[dev] = AM_NONE; - dev_nblock[dev] = 0; + if ((ret = DMAbuf_open(dev, mode)) < 0) + return ret; + if (audio_devs[dev]->coproc) + if ((ret = audio_devs[dev]->coproc-> + open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) + { + audio_release(dev, file); + printk("Sound: Can't access coprocessor device\n"); - return ret; + return ret; + } + local_conversion[dev] = 0; + + if (dev_type == SND_DEV_AUDIO) + { + set_format(dev, AFMT_MU_LAW); + } else + set_format(dev, bits); + + audio_mode[dev] = AM_NONE; + dev_nblock[dev] = 0; + + + return ret; } static void -sync_output (int dev) +sync_output(int dev) { - int p, i; - int l; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->fragment_size <= 0) - return; - dmap->flags |= DMA_POST; - - /* Align the write pointer with fragment boundaries */ - if ((l = dmap->user_counter % dmap->fragment_size) > 0) - { - int len; - unsigned long offs = dmap->user_counter % dmap->bytes_in_use; - - len = dmap->fragment_size - l; - memset (dmap->raw_buf + offs, dmap->neutral_byte, len); - DMAbuf_move_wrpointer (dev, len); - } + int p, i; + int l; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (dmap->fragment_size <= 0) + return; + dmap->flags |= DMA_POST; + /* Align the write pointer with fragment boundaries */ + if ((l = dmap->user_counter % dmap->fragment_size) > 0) + { + int len; + unsigned long offs = dmap->user_counter % dmap->bytes_in_use; + + len = dmap->fragment_size - l; + memset(dmap->raw_buf + offs, dmap->neutral_byte, len); + DMAbuf_move_wrpointer(dev, len); + } /* * Clean all unused buffer fragments. */ - p = dmap->qtail; - dmap->flags |= DMA_POST; + p = dmap->qtail; + dmap->flags |= DMA_POST; - for (i = dmap->qlen + 1; i < dmap->nbufs; i++) - { - p = (p + 1) % dmap->nbufs; - if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > - (dmap->raw_buf + dmap->buffsize)) - printk ("audio: Buffer error 2\n"); - - memset (dmap->raw_buf + p * dmap->fragment_size, - dmap->neutral_byte, - dmap->fragment_size); - } + for (i = dmap->qlen + 1; i < dmap->nbufs; i++) + { + p = (p + 1) % dmap->nbufs; + if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > + (dmap->raw_buf + dmap->buffsize)) + printk("audio: Buffer error 2\n"); + + memset(dmap->raw_buf + p * dmap->fragment_size, + dmap->neutral_byte, + dmap->fragment_size); + } - dmap->flags |= DMA_DIRTY; + dmap->flags |= DMA_DIRTY; } void -audio_release (int dev, struct fileinfo *file) +audio_release(int dev, struct fileinfo *file) { - int mode; + int mode; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - audio_devs[dev]->dmap_out->closing = 1; - audio_devs[dev]->dmap_in->closing = 1; + audio_devs[dev]->dmap_out->closing = 1; + audio_devs[dev]->dmap_in->closing = 1; - sync_output (dev); + sync_output(dev); - if (audio_devs[dev]->coproc) - audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM); - DMAbuf_release (dev, mode); + if (audio_devs[dev]->coproc) + audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM); + DMAbuf_release(dev, mode); } #if defined(NO_INLINE_ASM) || !defined(i386) static void -translate_bytes (const unsigned char *table, unsigned char *buff, int n) +translate_bytes(const unsigned char *table, unsigned char *buff, int n) { - unsigned long i; + unsigned long i; - if (n <= 0) - return; + if (n <= 0) + return; - for (i = 0; i < n; ++i) - buff[i] = table[buff[i]]; + for (i = 0; i < n; ++i) + buff[i] = table[buff[i]]; } #else extern inline void -translate_bytes (const void *table, void *buff, int n) +translate_bytes(const void *table, void *buff, int n) { - if (n > 0) - { - __asm__ ("cld\n" - "1:\tlodsb\n\t" - "xlatb\n\t" - "stosb\n\t" - "loop 1b\n\t": - : "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) - : "bx", "cx", "di", "si", "ax"); - } + if (n > 0) + { + __asm__("cld\n" + "1:\tlodsb\n\t" + "xlatb\n\t" + "stosb\n\t" + "loop 1b\n\t": + : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff) + : "bx", "cx", "di", "si", "ax"); + } } #endif int -audio_write (int dev, struct fileinfo *file, const char *buf, int count) -{ - int c, p, l, buf_size; - int err; - char *dma_buf; - - dev = dev >> 4; - - p = 0; - c = count; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_WRITE; - else - audio_mode[dev] = AM_WRITE; - - if (!count) /* Flush output */ - { - sync_output (dev); - return 0; - } - - while (c) - { - if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) - { - /* Handle nonblocking mode */ - if (dev_nblock[dev] && err == -EAGAIN) - return p; /* No more space. Return # of accepted bytes */ - return err; - } - - l = c; - - if (l > buf_size) - l = buf_size; - - if (!audio_devs[dev]->d->copy_user) - { - if ((dma_buf + l) > - (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) - { - printk ("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize); - return -EDOM; - } - - if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) - { - printk ("audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf); - return -EDOM; - } - copy_from_user (dma_buf, &(buf)[p], l); - } - else - audio_devs[dev]->d->copy_user (dev, - dma_buf, 0, buf, p, l); - - if (local_conversion[dev] & CNV_MU_LAW) - { - /* - * This just allows interrupts while the conversion is running - */ - sti (); - translate_bytes (ulaw_dsp, (unsigned char *) dma_buf, l); - } - - c -= l; - p += l; - DMAbuf_move_wrpointer (dev, l); - - } - - return count; -} - -int -audio_read (int dev, struct fileinfo *file, char *buf, int count) +audio_write(int dev, struct fileinfo *file, const char *buf, int count) { - int c, p, l; - char *dmabuf; - int buf_no; - - dev = dev >> 4; - p = 0; - c = count; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EPERM; + int c, p, l, buf_size; + int err; + char *dma_buf; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - { - sync_output (dev); - } + dev = dev >> 4; - if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_READ; - else - audio_mode[dev] = AM_READ; + p = 0; + c = count; - while (c) - { - if ((buf_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l, - dev_nblock[dev])) < 0) - { - /* Nonblocking mode handling. Return current # of bytes */ - - if (dev_nblock[dev] && buf_no == -EAGAIN) - return p; - - return buf_no; - } - - if (l > c) - l = c; - - /* - * Insert any local processing here. - */ - - if (local_conversion[dev] & CNV_MU_LAW) - { - /* - * This just allows interrupts while the conversion is running - */ - sti (); - - translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l); - } - - { - char *fixit = dmabuf; + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EPERM; - copy_to_user (&(buf)[p], fixit, l); - }; + if (audio_devs[dev]->flags & DMA_DUPLEX) + audio_mode[dev] |= AM_WRITE; + else + audio_mode[dev] = AM_WRITE; - DMAbuf_rmchars (dev, buf_no, l); + if (!count) /* Flush output */ + { + sync_output(dev); + return 0; + } + while (c) + { + if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) + { + /* Handle nonblocking mode */ + if (dev_nblock[dev] && err == -EAGAIN) + return p; /* No more space. Return # of accepted bytes */ + return err; + } + l = c; + + if (l > buf_size) + l = buf_size; + + if (!audio_devs[dev]->d->copy_user) + { + if ((dma_buf + l) > + (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) + { + printk("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize); + return -EDOM; + } + if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) + { + printk("audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf); + return -EDOM; + } + copy_from_user(dma_buf, &(buf)[p], l); + } else + audio_devs[dev]->d->copy_user(dev, + dma_buf, 0, buf, p, l); + + if (local_conversion[dev] & CNV_MU_LAW) + { + /* + * This just allows interrupts while the conversion is running + */ + sti(); + translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); + } + c -= l; + p += l; + DMAbuf_move_wrpointer(dev, l); - p += l; - c -= l; - } + } - return count - c; + return count; } int -audio_ioctl (int dev, struct fileinfo *file_must_not_be_used, - unsigned int cmd, caddr_t arg) +audio_read(int dev, struct fileinfo *file, char *buf, int count) { - int val; - - /* printk( "audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */ - - dev = dev >> 4; - - if (((cmd >> 8) & 0xff) == 'C') - { - if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ - return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0); - else - printk ("/dev/dsp%d: No coprocessor for this device\n", dev); - - return -ENXIO; - } - else - switch (cmd) - { - case SNDCTL_DSP_SYNC: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - - if (audio_devs[dev]->dmap_out->fragment_size == 0) - return 0; - sync_output (dev); - DMAbuf_sync (dev); - DMAbuf_reset (dev); - return 0; - break; - - case SNDCTL_DSP_POST: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - if (audio_devs[dev]->dmap_out->fragment_size == 0) - return 0; - audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; - sync_output (dev); - dma_ioctl (dev, SNDCTL_DSP_POST, (caddr_t) 0); - return 0; - break; - - case SNDCTL_DSP_RESET: - audio_mode[dev] = AM_NONE; - DMAbuf_reset (dev); - return 0; - break; - - case SNDCTL_DSP_GETFMTS: - return (*(int *) arg = audio_devs[dev]->format_mask); - break; - - case SNDCTL_DSP_SETFMT: - val = *(int *) arg; - return (*(int *) arg = set_format (dev, val)); + int c, p, l; + char *dmabuf; + int buf_no; + + dev = dev >> 4; + p = 0; + c = count; - case SNDCTL_DSP_GETISPACE: if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - - { - audio_buf_info info; - - int err = dma_ioctl (dev, cmd, (caddr_t) & info); - - if (err < 0) - return err; - - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; - } - - case SNDCTL_DSP_GETOSPACE: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; + return -EPERM; - { - audio_buf_info info; - - int err = dma_ioctl (dev, cmd, (caddr_t) & info); - - if (err < 0) - return err; + if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + { + sync_output(dev); + } + if (audio_devs[dev]->flags & DMA_DUPLEX) + audio_mode[dev] |= AM_READ; + else + audio_mode[dev] = AM_READ; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; - } + while (c) + { + if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, + dev_nblock[dev])) < 0) + { + /* Nonblocking mode handling. Return current # of bytes */ + + if (dev_nblock[dev] && buf_no == -EAGAIN) + return p; + + return buf_no; + } + if (l > c) + l = c; + + /* + * Insert any local processing here. + */ + + if (local_conversion[dev] & CNV_MU_LAW) + { + /* + * This just allows interrupts while the conversion is running + */ + sti(); - case SNDCTL_DSP_NONBLOCK: - dev_nblock[dev] = 1; - return 0; - break; + translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l); + } + { + char *fixit = dmabuf; - case SNDCTL_DSP_GETCAPS: - { - int info = 1; /* Revision level of this ioctl() */ + copy_to_user(&(buf)[p], fixit, l); + }; - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode == OPEN_READWRITE) - info |= DSP_CAP_DUPLEX; + DMAbuf_rmchars(dev, buf_no, l); - if (audio_devs[dev]->coproc) - info |= DSP_CAP_COPROC; + p += l; + c -= l; + } - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - info |= DSP_CAP_BATCH; + return count - c; +} - if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ - info |= DSP_CAP_TRIGGER; +int +audio_ioctl(int dev, struct fileinfo *file_must_not_be_used, + unsigned int cmd, caddr_t arg) +{ + int val; - info |= DSP_CAP_MMAP; + /* printk( "audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */ - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; - } - break; + dev = dev >> 4; - case SOUND_PCM_WRITE_RATE: - val = *(int *) arg; - return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, val)); + if (((cmd >> 8) & 0xff) == 'C') + { + if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ + return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk("/dev/dsp%d: No coprocessor for this device\n", dev); + + return -ENXIO; + } else + switch (cmd) + { + case SNDCTL_DSP_SYNC: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + sync_output(dev); + DMAbuf_sync(dev); + DMAbuf_reset(dev); + return 0; + break; + + case SNDCTL_DSP_POST: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; + sync_output(dev); + dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0); + return 0; + break; + + case SNDCTL_DSP_RESET: + audio_mode[dev] = AM_NONE; + DMAbuf_reset(dev); + return 0; + break; + + case SNDCTL_DSP_GETFMTS: + return (*(int *) arg = audio_devs[dev]->format_mask); + break; + + case SNDCTL_DSP_SETFMT: + val = *(int *) arg; + return (*(int *) arg = set_format(dev, val)); + + case SNDCTL_DSP_GETISPACE: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; + if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; + + { + audio_buf_info info; + + int err = dma_ioctl(dev, cmd, (caddr_t) & info); + + if (err < 0) + return err; + + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; + } + + case SNDCTL_DSP_GETOSPACE: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EPERM; + if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; + + { + audio_buf_info info; + + int err = dma_ioctl(dev, cmd, (caddr_t) & info); + + if (err < 0) + return err; + + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; + } + + case SNDCTL_DSP_NONBLOCK: + dev_nblock[dev] = 1; + return 0; + break; + + case SNDCTL_DSP_GETCAPS: + { + int info = 1; /* Revision level of this ioctl() */ + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode == OPEN_READWRITE) + info |= DSP_CAP_DUPLEX; + + if (audio_devs[dev]->coproc) + info |= DSP_CAP_COPROC; + + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ + info |= DSP_CAP_BATCH; + + if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ + info |= DSP_CAP_TRIGGER; + + info |= DSP_CAP_MMAP; + + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; + } + break; + + case SOUND_PCM_WRITE_RATE: + val = *(int *) arg; + return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val)); + + case SOUND_PCM_READ_RATE: + return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0)); + + case SNDCTL_DSP_STEREO: + { + int n; + + n = *(int *) arg; + if (n > 1) + { + printk("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n); + return -EINVAL; + } + if (n < 0) + return -EINVAL; + + return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1); + } + + case SOUND_PCM_WRITE_CHANNELS: + val = *(int *) arg; + return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val)); + + case SOUND_PCM_READ_CHANNELS: + return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0)); + + case SOUND_PCM_READ_BITS: + return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0)); + + case SNDCTL_DSP_SETDUPLEX: + if (audio_devs[dev]->open_mode != OPEN_READWRITE) + return -EPERM; + if (audio_devs[dev]->flags & DMA_DUPLEX) + return 0; + else + return -EIO; + break; + + case SNDCTL_DSP_PROFILE: + if (audio_devs[dev]->open_mode & OPEN_WRITE) + audio_devs[dev]->dmap_out->applic_profile = *(int *) arg; + if (audio_devs[dev]->open_mode & OPEN_READ) + audio_devs[dev]->dmap_in->applic_profile = *(int *) arg; + return 0; + break; - case SOUND_PCM_READ_RATE: - return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, 0)); + default: + return dma_ioctl(dev, cmd, arg); + } +} - case SNDCTL_DSP_STEREO: - { - int n; +void +audio_init_devices(void) +{ + /* + * NOTE! This routine could be called several times during boot. + */ +} - n = *(int *) arg; - if (n > 1) - { - printk ("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n); - return -EINVAL; - } - if (n < 0) - return -EINVAL; +#endif - return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, n + 1) - 1); - } +void +reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) +{ + /* + * This routine breaks the physical device buffers to logical ones. + */ - case SOUND_PCM_WRITE_CHANNELS: - val = *(int *) arg; - return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, val)); + struct audio_operations *dsp_dev = audio_devs[dev]; - case SOUND_PCM_READ_CHANNELS: - return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, 0)); + unsigned i, n; + unsigned sr, nc, sz, bsz; - case SOUND_PCM_READ_BITS: - return (*(int *) arg = audio_devs[dev]->d->set_bits (dev, 0)); + sr = dsp_dev->d->set_speed(dev, 0); + nc = dsp_dev->d->set_channels(dev, 0); + sz = dsp_dev->d->set_bits(dev, 0); - case SNDCTL_DSP_SETDUPLEX: - if (audio_devs[dev]->open_mode != OPEN_READWRITE) - return -EPERM; - if (audio_devs[dev]->flags & DMA_DUPLEX) - return 0; + if (sz == 8) + dmap->neutral_byte = NEUTRAL8; else - return -EIO; - break; - - case SNDCTL_DSP_PROFILE: - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->applic_profile = *(int *) arg; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->applic_profile = *(int *) arg; - return 0; - break; - - default: - return dma_ioctl (dev, cmd, arg); - } -} - -void -audio_init_devices (void) -{ - /* - * NOTE! This routine could be called several times during boot. - */ -} + dmap->neutral_byte = NEUTRAL16; + if (sr < 1 || nc < 1 || sz < 1) + { + printk("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz); + sr = DSP_DEFAULT_SPEED; + nc = 1; + sz = 8; + } + sz = sr * nc * sz; -#endif + sz /= 8; /* #bits -> #bytes */ + dmap->data_rate = sz; -void -reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) -{ - /* - * This routine breaks the physical device buffers to logical ones. - */ - - struct audio_operations *dsp_dev = audio_devs[dev]; - - unsigned i, n; - unsigned sr, nc, sz, bsz; - - sr = dsp_dev->d->set_speed (dev, 0); - nc = dsp_dev->d->set_channels (dev, 0); - sz = dsp_dev->d->set_bits (dev, 0); - - if (sz == 8) - dmap->neutral_byte = NEUTRAL8; - else - dmap->neutral_byte = NEUTRAL16; - - if (sr < 1 || nc < 1 || sz < 1) - { - printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz); - sr = DSP_DEFAULT_SPEED; - nc = 1; - sz = 8; - } - - sz = sr * nc * sz; - - sz /= 8; /* #bits -> #bytes */ - dmap->data_rate = sz; - - if (!dmap->needs_reorg) - return; - dmap->needs_reorg = 0; - - if (dmap->fragment_size == 0) - { /* Compute the fragment size using the default algorithm */ - - /* - * Compute a buffer size for time not exceeding 1 second. - * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds - * of sound (using the current speed, sample size and #channels). - */ - - bsz = dmap->buffsize; - while (bsz > sz) - bsz /= 2; + if (!dmap->needs_reorg) + return; + dmap->needs_reorg = 0; + + if (dmap->fragment_size == 0) + { /* Compute the fragment size using the default algorithm */ + + /* + * Compute a buffer size for time not exceeding 1 second. + * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds + * of sound (using the current speed, sample size and #channels). + */ + + bsz = dmap->buffsize; + while (bsz > sz) + bsz /= 2; - if (bsz == dmap->buffsize) - bsz /= 2; /* Needs at least 2 buffers */ + if (bsz == dmap->buffsize) + bsz /= 2; /* Needs at least 2 buffers */ /* * Split the computed fragment to smaller parts. After 3.5a9 @@ -601,439 +585,429 @@ * results when recording. */ - if (dmap->subdivision == 0) /* Not already set */ - { - dmap->subdivision = 4; /* Init to the default value */ - - if ((bsz / dmap->subdivision) > 4096) - dmap->subdivision *= 2; - if ((bsz / dmap->subdivision) < 4096) - dmap->subdivision = 1; - } - - bsz /= dmap->subdivision; - - if (bsz < 16) - bsz = 16; /* Just a sanity check */ - - dmap->fragment_size = bsz; - } - else - { - /* - * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or - * the buffer size computation has already been done. - */ - if (dmap->fragment_size > (dmap->buffsize / 2)) - dmap->fragment_size = (dmap->buffsize / 2); - bsz = dmap->fragment_size; - } - - if (audio_devs[dev]->min_fragment) - if (bsz < (1 << audio_devs[dev]->min_fragment)) - bsz = 1 << audio_devs[dev]->min_fragment; - if (audio_devs[dev]->max_fragment) - if (bsz > (1 << audio_devs[dev]->max_fragment)) - bsz = 1 << audio_devs[dev]->max_fragment; - bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ + if (dmap->subdivision == 0) /* Not already set */ + { + dmap->subdivision = 4; /* Init to the default value */ + + if ((bsz / dmap->subdivision) > 4096) + dmap->subdivision *= 2; + if ((bsz / dmap->subdivision) < 4096) + dmap->subdivision = 1; + } + bsz /= dmap->subdivision; + + if (bsz < 16) + bsz = 16; /* Just a sanity check */ + + dmap->fragment_size = bsz; + } else + { + /* + * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or + * the buffer size computation has already been done. + */ + if (dmap->fragment_size > (dmap->buffsize / 2)) + dmap->fragment_size = (dmap->buffsize / 2); + bsz = dmap->fragment_size; + } + + if (audio_devs[dev]->min_fragment) + if (bsz < (1 << audio_devs[dev]->min_fragment)) + bsz = 1 << audio_devs[dev]->min_fragment; + if (audio_devs[dev]->max_fragment) + if (bsz > (1 << audio_devs[dev]->max_fragment)) + bsz = 1 << audio_devs[dev]->max_fragment; + bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ #ifdef OS_DMA_ALIGN_CHECK - OS_DMA_ALIGN_CHECK (bsz); + OS_DMA_ALIGN_CHECK(bsz); #endif - n = dmap->buffsize / bsz; - if (n > MAX_SUB_BUFFERS) - n = MAX_SUB_BUFFERS; - if (n > dmap->max_fragments) - n = dmap->max_fragments; - - if (n < 2) - { - n = 2; - bsz /= 2; - } - - dmap->nbufs = n; - dmap->bytes_in_use = n * bsz; - dmap->fragment_size = bsz; - dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + - dmap->bytes_in_use; /* Approximately one hour */ - - if (dmap->raw_buf) - { - memset (dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); - } - - for (i = 0; i < dmap->nbufs; i++) - { - dmap->counts[i] = 0; - } + n = dmap->buffsize / bsz; + if (n > MAX_SUB_BUFFERS) + n = MAX_SUB_BUFFERS; + if (n > dmap->max_fragments) + n = dmap->max_fragments; - dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; + if (n < 2) + { + n = 2; + bsz /= 2; + } + dmap->nbufs = n; + dmap->bytes_in_use = n * bsz; + dmap->fragment_size = bsz; + dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + + dmap->bytes_in_use; /* Approximately one hour */ + + if (dmap->raw_buf) + { + memset(dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); + } + for (i = 0; i < dmap->nbufs; i++) + { + dmap->counts[i] = 0; + } + + dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; } static int -dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) { - if (fact == 0) - { - fact = dmap->subdivision; - if (fact == 0) - fact = 1; - return (*(int *) arg = fact); - } - - if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; + if (fact == 0) + { + fact = dmap->subdivision; + if (fact == 0) + fact = 1; + return (*(int *) arg = fact); + } + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; - if (fact > MAX_REALTIME_FACTOR) - return -EINVAL; + if (fact > MAX_REALTIME_FACTOR) + return -EINVAL; - if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return -EINVAL; + if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) + return -EINVAL; - dmap->subdivision = fact; - return (*(int *) arg = fact); + dmap->subdivision = fact; + return (*(int *) arg = fact); } static int -dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) { - int bytes, count; + int bytes, count; - if (fact == 0) - return -EIO; + if (fact == 0) + return -EIO; - if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; - bytes = fact & 0xffff; - count = (fact >> 16) & 0x7fff; + bytes = fact & 0xffff; + count = (fact >> 16) & 0x7fff; - if (count == 0) - count = MAX_SUB_BUFFERS; - else if (count < MAX_SUB_BUFFERS) - count++; + if (count == 0) + count = MAX_SUB_BUFFERS; + else if (count < MAX_SUB_BUFFERS) + count++; - if (bytes < 4 || bytes > 17) /* <16 || > 512k */ - return -EINVAL; + if (bytes < 4 || bytes > 17) /* <16 || > 512k */ + return -EINVAL; - if (count < 2) - return -EINVAL; + if (count < 2) + return -EINVAL; - if (audio_devs[dev]->min_fragment > 0) - if (bytes < audio_devs[dev]->min_fragment) - bytes = audio_devs[dev]->min_fragment; + if (audio_devs[dev]->min_fragment > 0) + if (bytes < audio_devs[dev]->min_fragment) + bytes = audio_devs[dev]->min_fragment; - if (audio_devs[dev]->max_fragment > 0) - if (bytes > audio_devs[dev]->max_fragment) - bytes = audio_devs[dev]->max_fragment; + if (audio_devs[dev]->max_fragment > 0) + if (bytes > audio_devs[dev]->max_fragment) + bytes = audio_devs[dev]->max_fragment; #ifdef OS_DMA_MINBITS - if (bytes < OS_DMA_MINBITS) - bytes = OS_DMA_MINBITS; + if (bytes < OS_DMA_MINBITS) + bytes = OS_DMA_MINBITS; #endif - dmap->fragment_size = (1 << bytes); - dmap->max_fragments = count; + dmap->fragment_size = (1 << bytes); + dmap->max_fragments = count; - if (dmap->fragment_size > dmap->buffsize) - dmap->fragment_size = dmap->buffsize; + if (dmap->fragment_size > dmap->buffsize) + dmap->fragment_size = dmap->buffsize; - if (dmap->fragment_size == dmap->buffsize && - audio_devs[dev]->flags & DMA_AUTOMODE) - dmap->fragment_size /= 2; /* Needs at least 2 buffers */ - - dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - if (arg) - return (*(int *) arg = bytes | ((count - 1) << 16)); - else - return 0; + if (dmap->fragment_size == dmap->buffsize && + audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->fragment_size /= 2; /* Needs at least 2 buffers */ + + dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ + if (arg) + return (*(int *) arg = bytes | ((count - 1) << 16)); + else + return 0; } int -dma_ioctl (int dev, unsigned int cmd, caddr_t arg) +dma_ioctl(int dev, unsigned int cmd, caddr_t arg) { - struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; - struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; + struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; - switch (cmd) - { - - case SNDCTL_DSP_SUBDIVIDE: - { - int fact; - int ret = 0; - - fact = *(int *) arg; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_subdivide (dev, dmap_out, arg, fact); - if (ret < 0) - return ret; - - if (audio_devs[dev]->open_mode != OPEN_WRITE || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_subdivide (dev, dmap_in, arg, fact); - - return ret; - } - break; - - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_GETOSPACE: - { - struct dma_buffparms *dmap = dmap_out; + switch (cmd) + { - audio_buf_info *info = (audio_buf_info *) arg; + case SNDCTL_DSP_SUBDIVIDE: + { + int fact; + int ret = 0; - if (cmd == SNDCTL_DSP_GETISPACE && - !(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; + fact = *(int *) arg; - if (cmd == SNDCTL_DSP_GETOSPACE && - !(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + ret = dma_subdivide(dev, dmap_out, arg, fact); + if (ret < 0) + return ret; + + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + ret = dma_subdivide(dev, dmap_in, arg, fact); - if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) - dmap = dmap_in; + return ret; + } + break; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -EINVAL; + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_GETOSPACE: + { + struct dma_buffparms *dmap = dmap_out; - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + audio_buf_info *info = (audio_buf_info *) arg; - info->fragstotal = dmap->nbufs; + if (cmd == SNDCTL_DSP_GETISPACE && + !(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + if (cmd == SNDCTL_DSP_GETOSPACE && + !(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) + dmap = dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return -EINVAL; + + if (!(dmap->flags & DMA_ALLOC_DONE)) + reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + + info->fragstotal = dmap->nbufs; + + if (cmd == SNDCTL_DSP_GETISPACE) + info->fragments = dmap->qlen; + else + { + if (!DMAbuf_space_in_queue(dev)) + info->fragments = 0; + else + { + info->fragments = DMAbuf_space_in_queue(dev); + if (audio_devs[dev]->d->local_qlen) + { + int tmp = audio_devs[dev]->d->local_qlen(dev); + + if (tmp && info->fragments) + tmp--; /* + * This buffer has been counted twice + */ + info->fragments -= tmp; + } + } + } + + if (info->fragments < 0) + info->fragments = 0; + else if (info->fragments > dmap->nbufs) + info->fragments = dmap->nbufs; + + info->fragsize = dmap->fragment_size; + info->bytes = info->fragments * dmap->fragment_size; + + if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) + info->bytes -= dmap->counts[dmap->qhead]; + else + { + info->fragments = info->bytes / dmap->fragment_size; + info->bytes -= dmap->user_counter % dmap->fragment_size; + } + } + return 0; - if (cmd == SNDCTL_DSP_GETISPACE) - info->fragments = dmap->qlen; - else - { - if (!DMAbuf_space_in_queue (dev)) - info->fragments = 0; - else - { - info->fragments = DMAbuf_space_in_queue (dev); - if (audio_devs[dev]->d->local_qlen) + case SNDCTL_DSP_SETTRIGGER: { - int tmp = audio_devs[dev]->d->local_qlen (dev); - - if (tmp && info->fragments) - tmp--; /* - * This buffer has been counted twice - */ - info->fragments -= tmp; - } - } - } + unsigned long flags; - if (info->fragments < 0) - info->fragments = 0; - else if (info->fragments > dmap->nbufs) - info->fragments = dmap->nbufs; + int bits; + int changed; - info->fragsize = dmap->fragment_size; - info->bytes = info->fragments * dmap->fragment_size; + bits = *(int *) arg; + bits &= audio_devs[dev]->open_mode; - if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) - info->bytes -= dmap->counts[dmap->qhead]; - else - { - info->fragments = info->bytes / dmap->fragment_size; - info->bytes -= dmap->user_counter % dmap->fragment_size; - } - } - return 0; + if (audio_devs[dev]->d->trigger == NULL) + return -EINVAL; + + if (!(audio_devs[dev]->flags & DMA_DUPLEX)) + if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) + { + printk("Sound: Device doesn't have full duplex capability\n"); + return -EINVAL; + } + save_flags(flags); + cli(); + changed = audio_devs[dev]->enable_bits ^ bits; + + if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) + { + int err; + + reorganize_buffers(dev, dmap_in, 1); + + if ((err = audio_devs[dev]->d->prepare_for_input(dev, + dmap_in->fragment_size, dmap_in->nbufs)) < 0) + return -err; + + dmap_in->dma_mode = DMODE_INPUT; + audio_devs[dev]->enable_bits = bits; + DMAbuf_activate_recording(dev, dmap_in); + } + if ((changed & bits) & PCM_ENABLE_OUTPUT && + (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && + audio_devs[dev]->go) + { + + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + { + reorganize_buffers(dev, dmap_out, 0); + } + dmap_out->dma_mode = DMODE_OUTPUT; + ; + audio_devs[dev]->enable_bits = bits; + dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; + DMAbuf_launch_output(dev, dmap_out); + ; + } + audio_devs[dev]->enable_bits = bits; + if (changed && audio_devs[dev]->d->trigger) + { + audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); + } + restore_flags(flags); + } + case SNDCTL_DSP_GETTRIGGER: + return (*(int *) arg = audio_devs[dev]->enable_bits); + break; - case SNDCTL_DSP_SETTRIGGER: - { - unsigned long flags; + case SNDCTL_DSP_SETSYNCRO: - int bits; - int changed; + if (!audio_devs[dev]->d->trigger) + return -EINVAL; - bits = *(int *) arg; - bits &= audio_devs[dev]->open_mode; + audio_devs[dev]->d->trigger(dev, 0); + audio_devs[dev]->go = 0; + return 0; + break; - if (audio_devs[dev]->d->trigger == NULL) - return -EINVAL; + case SNDCTL_DSP_GETIPTR: + { + count_info info; + unsigned long flags; + struct dma_buffparms *dmap = dmap_in; + + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + save_flags(flags); + cli(); + info.bytes = dmap->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_INPUT) & ~3; + if (info.ptr < dmap->fragment_size && dmap->qtail != 0) + info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + + info.blocks = dmap->qlen; + info.bytes += info.ptr; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + dmap->qlen = 0; /* Reset interrupt counter */ + restore_flags(flags); + return 0; + } + break; - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) - { - printk ("Sound: Device doesn't have full duplex capability\n"); - return -EINVAL; - } + case SNDCTL_DSP_GETOPTR: + { + count_info info; + unsigned long flags; + struct dma_buffparms *dmap = dmap_out; + + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + save_flags(flags); + cli(); + info.bytes = dmap->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT) & ~3; + if (info.ptr < dmap->fragment_size && dmap->qhead != 0) + info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + info.blocks = dmap->qlen; + info.bytes += info.ptr; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); - save_flags (flags); - cli (); - changed = audio_devs[dev]->enable_bits ^ bits; + if (dmap->mapping_flags & DMA_MAP_MAPPED) + dmap->qlen = 0; /* Reset interrupt counter */ - if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) - { - int err; + restore_flags(flags); + return 0; + } + break; - reorganize_buffers (dev, dmap_in, 1); - if ((err = audio_devs[dev]->d->prepare_for_input (dev, - dmap_in->fragment_size, dmap_in->nbufs)) < 0) - return -err; + case SNDCTL_DSP_POST: + ; + if (audio_devs[dev]->dmap_out->qlen > 0) + if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); + ; + return 0; + break; - dmap_in->dma_mode = DMODE_INPUT; - audio_devs[dev]->enable_bits = bits; - DMAbuf_activate_recording (dev, dmap_in); - } + case SNDCTL_DSP_GETBLKSIZE: + { + int fragment_size; + struct dma_buffparms *dmap = dmap_out; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + reorganize_buffers(dev, dmap_out, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + reorganize_buffers(dev, dmap_in, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode == OPEN_READ) + dmap = dmap_in; + fragment_size = dmap->fragment_size; + return (*(int *) arg = fragment_size); + } + break; - if ((changed & bits) & PCM_ENABLE_OUTPUT && - (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && - audio_devs[dev]->go) - { + case SNDCTL_DSP_SETFRAGMENT: + { + int fact; + int ret; - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - { - reorganize_buffers (dev, dmap_out, 0); - } + fact = *(int *) arg; + ret = dma_set_fragment(dev, dmap_out, arg, fact); + if (ret < 0) + return ret; + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + ret = dma_set_fragment(dev, dmap_in, arg, fact); - dmap_out->dma_mode = DMODE_OUTPUT; - ; - audio_devs[dev]->enable_bits = bits; - dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; - DMAbuf_launch_output (dev, dmap_out); - ; - } + return ret; + } + break; - audio_devs[dev]->enable_bits = bits; - if (changed && audio_devs[dev]->d->trigger) - { - audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); + default: + return audio_devs[dev]->d->ioctl(dev, cmd, arg); } - restore_flags (flags); - } - case SNDCTL_DSP_GETTRIGGER: - return (*(int *) arg = audio_devs[dev]->enable_bits); - break; - - case SNDCTL_DSP_SETSYNCRO: - - if (!audio_devs[dev]->d->trigger) - return -EINVAL; - - audio_devs[dev]->d->trigger (dev, 0); - audio_devs[dev]->go = 0; - return 0; - break; - - case SNDCTL_DSP_GETIPTR: - { - count_info info; - unsigned long flags; - struct dma_buffparms *dmap = dmap_in; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - - save_flags (flags); - cli (); - info.bytes = dmap->byte_counter; - info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_INPUT) & ~3; - if (info.ptr < dmap->fragment_size && dmap->qtail != 0) - info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - - info.blocks = dmap->qlen; - info.bytes += info.ptr; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - dmap->qlen = 0; /* Reset interrupt counter */ - restore_flags (flags); - return 0; - } - break; - - case SNDCTL_DSP_GETOPTR: - { - count_info info; - unsigned long flags; - struct dma_buffparms *dmap = dmap_out; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - - save_flags (flags); - cli (); - info.bytes = dmap->byte_counter; - info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT) & ~3; - if (info.ptr < dmap->fragment_size && dmap->qhead != 0) - info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - info.blocks = dmap->qlen; - info.bytes += info.ptr; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - dmap->qlen = 0; /* Reset interrupt counter */ - - restore_flags (flags); - return 0; - } - break; - - - case SNDCTL_DSP_POST: - ; - if (audio_devs[dev]->dmap_out->qlen > 0) - if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) - DMAbuf_launch_output (dev, audio_devs[dev]->dmap_out); - ; - return 0; - break; - - case SNDCTL_DSP_GETBLKSIZE: - { - int fragment_size; - struct dma_buffparms *dmap = dmap_out; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - reorganize_buffers (dev, dmap_out, - (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode != OPEN_WRITE || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - reorganize_buffers (dev, dmap_in, - (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode == OPEN_READ) - dmap = dmap_in; - fragment_size = dmap->fragment_size; - return (*(int *) arg = fragment_size); - } - break; - - case SNDCTL_DSP_SETFRAGMENT: - { - int fact; - int ret; - - fact = *(int *) arg; - ret = dma_set_fragment (dev, dmap_out, arg, fact); - if (ret < 0) - return ret; - - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ) - ret = dma_set_fragment (dev, dmap_in, arg, fact); - - return ret; - } - break; - - default: - return audio_devs[dev]->d->ioctl (dev, cmd, arg); - } } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v2.1.66/linux/drivers/sound/configure.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/configure.c Sat Nov 29 10:33:20 1997 @@ -87,12 +87,12 @@ typedef struct { - unsigned long conditions; - unsigned long exclusive_options; - char macro[20]; - int verify; - int alias; - int default_answ; + unsigned long conditions; + unsigned long exclusive_options; + char macro[20]; + int verify; + int alias; + int default_answ; } hw_entry; @@ -117,209 +117,209 @@ /* * 0 */ - {0, 0, "PAS", 1, 0, 0}, - {0, 0, "SB", 1, 0, 0}, - {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0}, - - {0, 0, "GUS", 1, 0, 0}, - {0, 0, "MPU401", 1, 0, 0}, - {0, 0, "UART6850", 1, 0, 0}, - {0, 0, "PSS", 1, 0, 0}, - {B (OPT_GUS), 0, "GUS16", 1, 0, 0}, - {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0}, - {0, 0, "MSS", 1, 0, 0}, - {0, 0, "SSCAPE", 1, 0, 0}, - {0, 0, "TRIX", 1, 0, 0}, - {0, 0, "MAD16", 1, 0, 0}, - {0, 0, "CS4232", 1, 0, 0}, - {0, 0, "MAUI", 1, 0, 0}, - {0, 0, "SPNP", 1, 0, 0}, - {0, 0, "OPL3SA1", 1, 0, 0}, - {0, 0, "SOFTOSS", 1, 0, 0}, - - {B (OPT_SB), B (OPT_PAS), "UNUSED1", 1, 0, 1}, - {B (OPT_SB) | B (OPT_UNUSED1), B (OPT_PAS), "UNUSED2", 1, 0, 1}, - {B (OPT_UNUSED1) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0}, - {AUDIO_CARDS, 0, "UNUSED3", 1, 0, 1}, - {B (OPT_MPU401) | B (OPT_MAUI), 0, "UNUSED4", 0, 0, 0}, - {MIDI_CARDS, 0, "UNUSED5", 1, 0, 1}, - {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, - {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1} + {0, 0, "PAS", 1, 0, 0}, + {0, 0, "SB", 1, 0, 0}, + {0, B(OPT_PAS) | B(OPT_SB), "ADLIB", 1, 0, 0}, + + {0, 0, "GUS", 1, 0, 0}, + {0, 0, "MPU401", 1, 0, 0}, + {0, 0, "UART6850", 1, 0, 0}, + {0, 0, "PSS", 1, 0, 0}, + {B(OPT_GUS), 0, "GUS16", 1, 0, 0}, + {B(OPT_GUS), B(OPT_GUS16), "GUSMAX", 1, 0, 0}, + {0, 0, "MSS", 1, 0, 0}, + {0, 0, "SSCAPE", 1, 0, 0}, + {0, 0, "TRIX", 1, 0, 0}, + {0, 0, "MAD16", 1, 0, 0}, + {0, 0, "CS4232", 1, 0, 0}, + {0, 0, "MAUI", 1, 0, 0}, + {0, 0, "SPNP", 1, 0, 0}, + {0, 0, "OPL3SA1", 1, 0, 0}, + {0, 0, "SOFTOSS", 1, 0, 0}, + + {B(OPT_SB), B(OPT_PAS), "UNUSED1", 1, 0, 1}, + {B(OPT_SB) | B(OPT_UNUSED1), B(OPT_PAS), "UNUSED2", 1, 0, 1}, + {B(OPT_UNUSED1) | B(OPT_MSS) | B(OPT_MPU401), 0, "AEDSP16", 1, 0, 0}, + {AUDIO_CARDS, 0, "UNUSED3", 1, 0, 1}, + {B(OPT_MPU401) | B(OPT_MAUI), 0, "UNUSED4", 0, 0, 0}, + {MIDI_CARDS, 0, "UNUSED5", 1, 0, 1}, + {B(OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, + {B(OPT_PSS) | B(OPT_SB) | B(OPT_PAS) | B(OPT_ADLIB) | B(OPT_MSS) | B(OPT_PSS), B(OPT_YM3812_AUTO), "YM3812", 1, 0, 1} }; char *questions[] = { - "ProAudioSpectrum 16 support", - "100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support", - "Generic OPL2/OPL3 FM synthesizer support", - "Gravis Ultrasound support", - "MPU-401 support (NOT for SB16)", - "6850 UART Midi support", - "PSS (ECHO-ADI2111) support", - "16 bit sampling option of GUS (_NOT_ GUS MAX)", - "GUS MAX support", - "Microsoft Sound System support", - "Ensoniq SoundScape support", - "MediaTrix AudioTrix Pro support", - "Support for OPTi MAD16 and/or Mozart based cards", - "Support for Crystal CS4232 based (PnP) cards", - "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers", - "Support for PnP sound cards (_EXPERIMENTAL_)", - "Yamaha OPL3-SA1 audio controller", - "SoftOSS software wave table engine", - - "*** Unused option 1 ***", - "*** Unused option 2 ***", - "Audio Excel DSP 16 initialization support", - "*** Unused option 3 ***", - "*** Unused option 4 ***", - "*** Unused option 5 ***", - "This should not be asked", - "FM synthesizer (YM3812/OPL-3) support", - "Is the sky really falling" + "ProAudioSpectrum 16 support", + "100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support", + "Generic OPL2/OPL3 FM synthesizer support", + "Gravis Ultrasound support", + "MPU-401 support (NOT for SB16)", + "6850 UART Midi support", + "PSS (ECHO-ADI2111) support", + "16 bit sampling option of GUS (_NOT_ GUS MAX)", + "GUS MAX support", + "Microsoft Sound System support", + "Ensoniq SoundScape support", + "MediaTrix AudioTrix Pro support", + "Support for OPTi MAD16 and/or Mozart based cards", + "Support for Crystal CS4232 based (PnP) cards", + "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers", + "Support for PnP sound cards (_EXPERIMENTAL_)", + "Yamaha OPL3-SA1 audio controller", + "SoftOSS software wave table engine", + + "*** Unused option 1 ***", + "*** Unused option 2 ***", + "Audio Excel DSP 16 initialization support", + "*** Unused option 3 ***", + "*** Unused option 4 ***", + "*** Unused option 5 ***", + "This should not be asked", + "FM synthesizer (YM3812/OPL-3) support", + "Is the sky really falling" }; /* help text for each option */ char *help[] = { - "Enable this option only if you have a Pro Audio Spectrum 16,\n" - "Pro Audio Studio 16, or Logitech SoundMan 16. Don't enable this if\n" - "you have some other card made by MediaVision or Logitech as\n" - "they are not PAS16 compatible.\n", + "Enable this option only if you have a Pro Audio Spectrum 16,\n" + "Pro Audio Studio 16, or Logitech SoundMan 16. Don't enable this if\n" + "you have some other card made by MediaVision or Logitech as\n" + "they are not PAS16 compatible.\n", - "Enable this if you have an original Sound Blaster card made by\n" - "Creative Labs or a 100%% hardware compatible clone. For an\n" - "unknown card you may want to try this if it claims to be\n" - "Sound Blaster compatible.\n", + "Enable this if you have an original Sound Blaster card made by\n" + "Creative Labs or a 100%% hardware compatible clone. For an\n" + "unknown card you may want to try this if it claims to be\n" + "Sound Blaster compatible.\n", - "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n" - "FM synthesizer chip.\n", + "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n" + "FM synthesizer chip.\n", - "Enable this option for any type of Gravis Ultrasound card\n" - "including the GUS or GUS MAX.\n", + "Enable this option for any type of Gravis Ultrasound card\n" + "including the GUS or GUS MAX.\n", - "The MPU401 interface is supported by almost all sound cards. However,\n" - "some natively supported cards have their own driver for\n" - "MPU401. Enabling the MPU401 option with these cards will cause a\n" - "conflict. Also enabling MPU401 on a system that doesn't really have a\n" - "MPU401 could cause some trouble. It's safe to enable this if you have a\n" - "true MPU401 MIDI interface card.\n", +"The MPU401 interface is supported by almost all sound cards. However,\n" + "some natively supported cards have their own driver for\n" + "MPU401. Enabling the MPU401 option with these cards will cause a\n" +"conflict. Also enabling MPU401 on a system that doesn't really have a\n" + "MPU401 could cause some trouble. It's safe to enable this if you have a\n" + "true MPU401 MIDI interface card.\n", - "This option enables support for MIDI interfaces based on the 6850\n" - "UART chip. This interface is rarely found on sound cards.\n", + "This option enables support for MIDI interfaces based on the 6850\n" + "UART chip. This interface is rarely found on sound cards.\n", - "Enable this option if you have an Orchid SW32, Cardinal DSP16 or other\n" - "sound card based on the PSS chipset (AD1848 codec, ADSP-2115 DSP chip,\n" - "and Echo ESC614 ASIC CHIP).\n", +"Enable this option if you have an Orchid SW32, Cardinal DSP16 or other\n" +"sound card based on the PSS chipset (AD1848 codec, ADSP-2115 DSP chip,\n" + "and Echo ESC614 ASIC CHIP).\n", - "Enable this if you have installed the 16-bit sampling daughtercard on\n" - "your GUS card. Do not use if you have a GUS MAX as enabling this option\n" - "disables GUS MAX support.\n", +"Enable this if you have installed the 16-bit sampling daughtercard on\n" + "your GUS card. Do not use if you have a GUS MAX as enabling this option\n" + "disables GUS MAX support.\n", - "Enable this option if you have a Gravis Ultrasound MAX sound\n" - "card\n", + "Enable this option if you have a Gravis Ultrasound MAX sound\n" + "card\n", - "Enable this option if you have the original Windows Sound System\n" - "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n", + "Enable this option if you have the original Windows Sound System\n" + "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n", - "Enable this if you have a sound card based on the Ensoniq\n" - "SoundScape chipset. Such cards are being manufactured by Ensoniq,\n" - "Spea and Reveal (Reveal makes other cards as well).\n", + "Enable this if you have a sound card based on the Ensoniq\n" + "SoundScape chipset. Such cards are being manufactured by Ensoniq,\n" + "Spea and Reveal (Reveal makes other cards as well).\n", - "Enable this option if you have the AudioTrix Pro sound card\n" - "manufactured by MediaTrix.\n", + "Enable this option if you have the AudioTrix Pro sound card\n" + "manufactured by MediaTrix.\n", - "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n" - "82C928 or 82C929) audio interface chip. These chips are currently\n" - "quite common so it's possible that many no-name cards have one of\n" - "them. In addition the MAD16 chip is used in some cards made by known\n" - "manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n" - "Diamond (latest ones).\n", + "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n" + "82C928 or 82C929) audio interface chip. These chips are currently\n" + "quite common so it's possible that many no-name cards have one of\n" + "them. In addition the MAD16 chip is used in some cards made by known\n" +"manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n" + "Diamond (latest ones).\n", - "Enable this if you have a card based on the Crystal CS4232 chip set.\n", +"Enable this if you have a card based on the Crystal CS4232 chip set.\n", - "Enable this option if you have a Turtle Beach Wave Front, Maui,\n" - "or Tropez sound card.\n", + "Enable this option if you have a Turtle Beach Wave Front, Maui,\n" + "or Tropez sound card.\n", - "Use this option to enable experimental support for cards that\n" - "use the Plug and Play protocol.\n", + "Use this option to enable experimental support for cards that\n" + "use the Plug and Play protocol.\n", - "Use this option with Yamaha OPL3-SA1 (YMF701) chip.\n", + "Use this option with Yamaha OPL3-SA1 (YMF701) chip.\n", - "SoftOSS is a virtual wave table engine by 4Front Technologies. It can\n" - "be used together with any 16 bit stereo soundcard.\n" +"SoftOSS is a virtual wave table engine by 4Front Technologies. It can\n" + "be used together with any 16 bit stereo soundcard.\n" - "Enable this option if your card is a Sound Blaster Pro or\n" - "Sound Blaster 16. It also works with many Sound Blaster Pro clones.\n", + "Enable this option if your card is a Sound Blaster Pro or\n" + "Sound Blaster 16. It also works with many Sound Blaster Pro clones.\n", - "Enable this if you have a Sound Blaster 16, including the AWE32.\n", + "Enable this if you have a Sound Blaster 16, including the AWE32.\n", - "Enable this if you have an Audio Excel DSP16 card. See the file\n" - "Readme.aedsp16 for more information.\n", + "Enable this if you have an Audio Excel DSP16 card. See the file\n" + "Readme.aedsp16 for more information.\n", - "This option enables the A/D and D/A converter (PCM) devices\n" - "supported by almost all sound cards.\n", + "This option enables the A/D and D/A converter (PCM) devices\n" + "supported by almost all sound cards.\n", - "This should not be asked", + "This should not be asked", - "This enables the dev/midixx devices and access to any MIDI ports\n" - "using /dev/sequencer and /dev/music. This option also affects any\n" - "MPU401 and/or General MIDI compatible devices.\n", + "This enables the dev/midixx devices and access to any MIDI ports\n" + "using /dev/sequencer and /dev/music. This option also affects any\n" + "MPU401 and/or General MIDI compatible devices.\n", - "This should not be asked", + "This should not be asked", - "This enables the Yamaha FM synthesizer chip used on many sound\n" - "cards.\n", + "This enables the Yamaha FM synthesizer chip used on many sound\n" + "cards.\n", - "Is the sky really falling" + "Is the sky really falling" }; struct kludge { - char *name; - int mask; + char *name; + int mask; } extra_options[] = { - { - "MPU_EMU", MPU_DEVS - } - , - { - "AD1848", AD1848_DEVS - } - , - { - "SBDSP", SBDSP_DEVS - } - , - { - "UART401", UART401_DEVS - } - , - { - "GUSHW", B (OPT_GUS) | B (OPT_SPNP) - } - , - { - "SSCAPEHW", B (OPT_SSCAPE) | B (OPT_SPNP) - } - , - { - "SEQUENCER", SEQUENCER_DEVS - } - , - { - "AUDIO", AUDIO_CARDS - } - , - { - "MIDI", MIDI_CARDS - } - , - { - NULL, 0 - } + { + "MPU_EMU", MPU_DEVS + } + , + { + "AD1848", AD1848_DEVS + } + , + { + "SBDSP", SBDSP_DEVS + } + , + { + "UART401", UART401_DEVS + } + , + { + "GUSHW", B(OPT_GUS) | B(OPT_SPNP) + } + , + { + "SSCAPEHW", B(OPT_SSCAPE) | B(OPT_SPNP) + } + , + { + "SEQUENCER", SEQUENCER_DEVS + } + , + { + "AUDIO", AUDIO_CARDS + } + , + { + "MIDI", MIDI_CARDS + } + , + { + NULL, 0 + } }; char *oldconf = "/etc/soundconf"; @@ -332,1377 +332,1338 @@ int dump_only = 0; -void build_defines (void); +void build_defines(void); #include "hex2hex.h" -int bin2hex (char *path, char *target, char *varname); +int bin2hex(char *path, char *target, char *varname); int -can_select_option (int nr) +can_select_option(int nr) { - if (hw_table[nr].conditions) - if (!(hw_table[nr].conditions & selected_options)) - return 0; - - if (hw_table[nr].exclusive_options) - if (hw_table[nr].exclusive_options & selected_options) - return 0; + if (hw_table[nr].conditions) + if (!(hw_table[nr].conditions & selected_options)) + return 0; + + if (hw_table[nr].exclusive_options) + if (hw_table[nr].exclusive_options & selected_options) + return 0; - if (DISABLED_OPTIONS & B (nr)) - return 0; + if (DISABLED_OPTIONS & B(nr)) + return 0; - return 1; + return 1; } int -think_positively (char *prompt, int def_answ, char *help) +think_positively(char *prompt, int def_answ, char *help) { - char answ[512]; - int len; + char answ[512]; + int len; -response: - fprintf (stderr, prompt); - if (def_answ) - fprintf (stderr, " [Y/n/?] "); - else - fprintf (stderr, " [N/y/?] "); - - if ((len = read (0, answ, sizeof (answ))) < 1) - { - fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); - - perror ("stdin"); - printf ("invalid_configuration__run_make_config_again\n"); - exit (-1); - } + response: + fprintf(stderr, prompt); + if (def_answ) + fprintf(stderr, " [Y/n/?] "); + else + fprintf(stderr, " [N/y/?] "); - if (len < 2) /* + if ((len = read(0, answ, sizeof(answ))) < 1) + { + fprintf(stderr, "\n\nERROR! Cannot read stdin\n"); + + perror("stdin"); + printf("invalid_configuration__run_make_config_again\n"); + exit(-1); + } + if (len < 2) /* * There is an additional LF at the end */ - return def_answ; + return def_answ; - if (answ[0] == '?') - { /* display help message */ - fprintf (stderr, "\n"); - fprintf (stderr, help); - fprintf (stderr, "\n"); - goto response; - } - - answ[len - 1] = 0; + if (answ[0] == '?') + { /* display help message */ + fprintf(stderr, "\n"); + fprintf(stderr, help); + fprintf(stderr, "\n"); + goto response; + } + answ[len - 1] = 0; - if (!strcmp (answ, "y") || !strcmp (answ, "Y")) - return 1; + if (!strcmp(answ, "y") || !strcmp(answ, "Y")) + return 1; - return 0; + return 0; } int -ask_value (char *format, int default_answer) +ask_value(char *format, int default_answer) { - char answ[512]; - int len, num; + char answ[512]; + int len, num; -play_it_again_Sam: + play_it_again_Sam: - if ((len = read (0, answ, sizeof (answ))) < 1) - { - fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); - - perror ("stdin"); - printf ("invalid_configuration__run_make_config_again\n"); - exit (-1); - } + if ((len = read(0, answ, sizeof(answ))) < 1) + { + fprintf(stderr, "\n\nERROR! Cannot read stdin\n"); - if (len < 2) /* + perror("stdin"); + printf("invalid_configuration__run_make_config_again\n"); + exit(-1); + } + if (len < 2) /* * There is an additional LF at the end */ - return default_answer; - - answ[len - 1] = 0; + return default_answer; - if (sscanf (answ, format, &num) != 1) - { - fprintf (stderr, "Illegal format. Try again: "); - goto play_it_again_Sam; - } + answ[len - 1] = 0; - return num; + if (sscanf(answ, format, &num) != 1) + { + fprintf(stderr, "Illegal format. Try again: "); + goto play_it_again_Sam; + } + return num; } #define FMT_HEX 1 #define FMT_INT 2 void -show_comment (int mask, char *txt) +show_comment(int mask, char *txt) { - int i; + int i; - if (dump_only) - { + if (dump_only) + { - for (i = 0; i < OPT_LAST; i++) - if (mask == B (i)) + for (i = 0; i < OPT_LAST; i++) + if (mask == B(i)) + { + printf("\n\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", + hw_table[i].macro); + printf("comment '%s'\n", txt); + printf("fi\n"); + } + } else { - printf ("\n\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", - hw_table[i].macro); - printf ("comment '%s'\n", txt); - printf ("fi\n"); - } - } - else - { - if (!(mask & selected_options)) - return; + if (!(mask & selected_options)) + return; - fprintf (stderr, "%s\n", txt); - } + fprintf(stderr, "%s\n", txt); + } } void -ask_int_choice (int mask, char *macro, - char *question, - int format, - int defa, - char *choices) +ask_int_choice(int mask, char *macro, + char *question, + int format, + int defa, + char *choices) { - int num, i; + int num, i; - if (dump_only) - { + if (dump_only) + { - for (i = 0; i < OPT_LAST; i++) - if (mask == B (i)) + for (i = 0; i < OPT_LAST; i++) + if (mask == B(i)) + { + unsigned int j; + + for (j = 0; j < strlen(choices); j++) + if (choices[j] == '\'') + choices[j] = '_'; + + printf("\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", + hw_table[i].macro); + if (format == FMT_INT) + printf("int '%s %s' %s %d\n", question, choices, macro, defa); + else + printf("hex '%s %s' %s %x\n", question, choices, macro, defa); + printf("fi\n"); + } + } else { - unsigned int j; - - for (j = 0; j < strlen (choices); j++) - if (choices[j] == '\'') - choices[j] = '_'; - - printf ("\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n", - hw_table[i].macro); - if (format == FMT_INT) - printf ("int '%s %s' %s %d\n", question, choices, macro, defa); - else - printf ("hex '%s %s' %s %x\n", question, choices, macro, defa); - printf ("fi\n"); - } - } - else - { - if (!(mask & selected_options)) - return; - - fprintf (stderr, "\n%s\n", question); - if (strcmp (choices, "")) - fprintf (stderr, "Possible values are: %s\n", choices); + if (!(mask & selected_options)) + return; - if (format == FMT_INT) - { - if (defa == -1) - fprintf (stderr, "\t(-1 disables this feature)\n"); - fprintf (stderr, "The default value is %d\n", defa); - fprintf (stderr, "Enter the value: "); - num = ask_value ("%d", defa); - if (num == -1) - return; - fprintf (stderr, "%s set to %d.\n", question, num); - printf ("#define %s %d\n", macro, num); - } - else - { - if (defa == 0) - fprintf (stderr, "\t(0 disables this feature)\n"); - fprintf (stderr, "The default value is %x\n", defa); - fprintf (stderr, "Enter the value: "); - num = ask_value ("%x", defa); - if (num == 0) - return; - fprintf (stderr, "%s set to %x.\n", question, num); - printf ("#define %s 0x%x\n", macro, num); - } - } + fprintf(stderr, "\n%s\n", question); + if (strcmp(choices, "")) + fprintf(stderr, "Possible values are: %s\n", choices); + + if (format == FMT_INT) + { + if (defa == -1) + fprintf(stderr, "\t(-1 disables this feature)\n"); + fprintf(stderr, "The default value is %d\n", defa); + fprintf(stderr, "Enter the value: "); + num = ask_value("%d", defa); + if (num == -1) + return; + fprintf(stderr, "%s set to %d.\n", question, num); + printf("#define %s %d\n", macro, num); + } else + { + if (defa == 0) + fprintf(stderr, "\t(0 disables this feature)\n"); + fprintf(stderr, "The default value is %x\n", defa); + fprintf(stderr, "Enter the value: "); + num = ask_value("%x", defa); + if (num == 0) + return; + fprintf(stderr, "%s set to %x.\n", question, num); + printf("#define %s 0x%x\n", macro, num); + } + } } void -rebuild_file (char *line) +rebuild_file(char *line) { - char *method, *next, *old, *var, *p; + char *method, *next, *old, *var, *p; - method = p = line; + method = p = line; - while (*p && *p != ' ') - p++; - *p++ = 0; - - old = p; - while (*p && *p != ' ') - p++; - *p++ = 0; - - next = p; - while (*p && *p != ' ') - p++; - *p++ = 0; - - var = p; - while (*p && *p != ' ') - p++; - *p++ = 0; - - fprintf (stderr, "Rebuilding file `%s' (%s %s)\n", next, method, old); - - if (strcmp (method, "bin2hex") == 0) - { - if (!bin2hex (old, next, var)) - { - fprintf (stderr, "Rebuild failed\n"); - exit (-1); - } - } - else if (strcmp (method, "hex2hex") == 0) - { - if (!hex2hex (old, next, var)) - { - fprintf (stderr, "Rebuild failed\n"); - exit (-1); - } - } - else - { - fprintf (stderr, "Failed to build `%s' - unknown method %s\n", - next, method); - exit (-1); - } + while (*p && *p != ' ') + p++; + *p++ = 0; + + old = p; + while (*p && *p != ' ') + p++; + *p++ = 0; + + next = p; + while (*p && *p != ' ') + p++; + *p++ = 0; + + var = p; + while (*p && *p != ' ') + p++; + *p++ = 0; + + fprintf(stderr, "Rebuilding file `%s' (%s %s)\n", next, method, old); + + if (strcmp(method, "bin2hex") == 0) + { + if (!bin2hex(old, next, var)) + { + fprintf(stderr, "Rebuild failed\n"); + exit(-1); + } + } else if (strcmp(method, "hex2hex") == 0) + { + if (!hex2hex(old, next, var)) + { + fprintf(stderr, "Rebuild failed\n"); + exit(-1); + } + } else + { + fprintf(stderr, "Failed to build `%s' - unknown method %s\n", + next, method); + exit(-1); + } } int -use_old_config (char *filename) +use_old_config(char *filename) { - char buf[1024]; - int i = 0; + char buf[1024]; + int i = 0; - FILE *oldf; + FILE *oldf; - fprintf (stderr, "Copying old configuration from `%s'\n", filename); + fprintf(stderr, "Copying old configuration from `%s'\n", filename); - if ((oldf = fopen (filename, "r")) == NULL) - { - fprintf (stderr, "Couldn't open previous configuration file\n"); - perror (filename); - return 0; - } + if ((oldf = fopen(filename, "r")) == NULL) + { + fprintf(stderr, "Couldn't open previous configuration file\n"); + perror(filename); + return 0; + } + while (fgets(buf, 1024, oldf) != NULL) + { + char tmp[100]; - while (fgets (buf, 1024, oldf) != NULL) - { - char tmp[100]; + if (buf[0] != '#') + { + printf("%s", buf); - if (buf[0] != '#') - { - printf ("%s", buf); + strncpy(tmp, buf, 8); + tmp[8] = 0; - strncpy (tmp, buf, 8); - tmp[8] = 0; + if (strcmp(tmp, "/*build ") == 0) + rebuild_file(&buf[8]); - if (strcmp (tmp, "/*build ") == 0) - rebuild_file (&buf[8]); + continue; + } + strncpy(tmp, buf, 8); + tmp[8] = 0; - continue; - } + if (strcmp(tmp, "#define ") == 0) + { + char *id = &buf[8]; - strncpy (tmp, buf, 8); - tmp[8] = 0; + i = 0; + while (id[i] && id[i] != ' ' && + id[i] != '\t' && id[i] != '\n') + i++; + + strncpy(tmp, id, i); + tmp[i] = 0; + + if (strcmp(tmp, "SELECTED_SOUND_OPTIONS") == 0) + continue; + + if (strcmp(tmp, "KERNEL_SOUNDCARD") == 0) + continue; + + if (strcmp(tmp, "JAZZ_DMA16") == 0) /* Rename it (hack) */ + { + printf("#define SB_DMA2 %s\n", + &buf[18]); + continue; + } + if (strcmp(tmp, "SB16_DMA") == 0) /* Rename it (hack) */ + { + printf("#define SB_DMA2 %s\n", + &buf[16]); + continue; + } + tmp[8] = 0; /* Truncate the string */ + if (strcmp(tmp, "EXCLUDE_") == 0) + continue; /* Skip excludes */ + + strncpy(tmp, id, i); + tmp[7] = 0; /* Truncate the string */ + + if (strcmp(tmp, "CONFIG_") == 0) + { + strncpy(tmp, &id[7], i - 7); + tmp[i - 7] = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (strcmp(hw_table[i].macro, tmp) == 0) + { + selected_options |= (1 << i); + break; + } + continue; + } + printf("%s", buf); + continue; + } + if (strcmp(tmp, "#undef ") == 0) + { + char *id = &buf[8]; - if (strcmp (tmp, "#define ") == 0) - { - char *id = &buf[8]; + i = 0; + while (id[i] && id[i] != ' ' && + id[i] != '\t' && id[i] != '\n') + i++; + + strncpy(tmp, id, i); + tmp[7] = 0; /* Truncate the string */ + if (strcmp(tmp, "CONFIG_") == 0) + continue; + + strncpy(tmp, id, i); + + tmp[8] = 0; /* Truncate the string */ + if (strcmp(tmp, "EXCLUDE_") != 0) + continue; /* Not a #undef EXCLUDE_ line */ + strncpy(tmp, &id[8], i - 8); + tmp[i - 8] = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (strcmp(hw_table[i].macro, tmp) == 0) + { + selected_options |= (1 << i); + break; + } + continue; + } + printf("%s", buf); + } + fclose(oldf); - i = 0; - while (id[i] && id[i] != ' ' && - id[i] != '\t' && id[i] != '\n') - i++; - - strncpy (tmp, id, i); - tmp[i] = 0; - - if (strcmp (tmp, "SELECTED_SOUND_OPTIONS") == 0) - continue; - - if (strcmp (tmp, "KERNEL_SOUNDCARD") == 0) - continue; - - if (strcmp (tmp, "JAZZ_DMA16") == 0) /* Rename it (hack) */ - { - printf ("#define SB_DMA2 %s\n", - &buf[18]); - continue; - } - - if (strcmp (tmp, "SB16_DMA") == 0) /* Rename it (hack) */ - { - printf ("#define SB_DMA2 %s\n", - &buf[16]); - continue; - } - - tmp[8] = 0; /* Truncate the string */ - if (strcmp (tmp, "EXCLUDE_") == 0) - continue; /* Skip excludes */ - - strncpy (tmp, id, i); - tmp[7] = 0; /* Truncate the string */ - - if (strcmp (tmp, "CONFIG_") == 0) - { - strncpy (tmp, &id[7], i - 7); - tmp[i - 7] = 0; - - for (i = 0; i <= OPT_LAST; i++) - if (strcmp (hw_table[i].macro, tmp) == 0) - { - selected_options |= (1 << i); - break; - } - continue; - } + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B(i)) + printf("#define CONFIG_%s\n", hw_table[i].macro); + else + printf("#undef CONFIG_%s\n", hw_table[i].macro); - printf ("%s", buf); - continue; - } - if (strcmp (tmp, "#undef ") == 0) - { - char *id = &buf[8]; + printf("\n"); - i = 0; - while (id[i] && id[i] != ' ' && - id[i] != '\t' && id[i] != '\n') - i++; - - strncpy (tmp, id, i); - tmp[7] = 0; /* Truncate the string */ - if (strcmp (tmp, "CONFIG_") == 0) - continue; - - strncpy (tmp, id, i); - - tmp[8] = 0; /* Truncate the string */ - if (strcmp (tmp, "EXCLUDE_") != 0) - continue; /* Not a #undef EXCLUDE_ line */ - strncpy (tmp, &id[8], i - 8); - tmp[i - 8] = 0; - - for (i = 0; i <= OPT_LAST; i++) - if (strcmp (hw_table[i].macro, tmp) == 0) - { - selected_options |= (1 << i); - break; - } - continue; - } + i = 0; + + while (extra_options[i].name != NULL) + { + if (selected_options & extra_options[i].mask) + printf("#define CONFIG_%s\n", extra_options[i].name); + else + printf("#undef CONFIG_%s\n", extra_options[i].name); + i++; + } - printf ("%s", buf); - } - fclose (oldf); - - for (i = 0; i <= OPT_LAST; i++) - if (!hw_table[i].alias) - if (selected_options & B (i)) - printf ("#define CONFIG_%s\n", hw_table[i].macro); - else - printf ("#undef CONFIG_%s\n", hw_table[i].macro); - - - printf ("\n"); - - i = 0; - - while (extra_options[i].name != NULL) - { - if (selected_options & extra_options[i].mask) - printf ("#define CONFIG_%s\n", extra_options[i].name); - else - printf ("#undef CONFIG_%s\n", extra_options[i].name); - i++; - } - - printf ("\n"); - - printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); - fprintf (stderr, "Old configuration copied.\n"); - - build_defines (); - old_config_used = 1; - return 1; + printf("\n"); + + printf("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); + fprintf(stderr, "Old configuration copied.\n"); + + build_defines(); + old_config_used = 1; + return 1; } void -build_defines (void) +build_defines(void) { - FILE *optf; - int i; - - if ((optf = fopen (".defines", "w")) == NULL) - { - perror (".defines"); - exit (-1); - } - + FILE *optf; + int i; - for (i = 0; i <= OPT_LAST; i++) - if (!hw_table[i].alias) - if (selected_options & B (i)) - fprintf (optf, "CONFIG_%s=y\n", hw_table[i].macro); + if ((optf = fopen(".defines", "w")) == NULL) + { + perror(".defines"); + exit(-1); + } + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B(i)) + fprintf(optf, "CONFIG_%s=y\n", hw_table[i].macro); - fprintf (optf, "\n"); + fprintf(optf, "\n"); - i = 0; + i = 0; - while (extra_options[i].name != NULL) - { - if (selected_options & extra_options[i].mask) - fprintf (optf, "CONFIG_%s=y\n", extra_options[i].name); - i++; - } + while (extra_options[i].name != NULL) + { + if (selected_options & extra_options[i].mask) + fprintf(optf, "CONFIG_%s=y\n", extra_options[i].name); + i++; + } - fprintf (optf, "\n"); - fclose (optf); + fprintf(optf, "\n"); + fclose(optf); } void -ask_parameters (void) +ask_parameters(void) { - int num; + int num; + + build_defines(); + /* + * IRQ and DMA settings + */ + + ask_int_choice(B(OPT_AEDSP16), "AEDSP16_BASE", + "I/O base for Audio Excel DSP 16", + FMT_HEX, + 0x220, + "220 or 240"); + + ask_int_choice(B(OPT_SB), "SBC_BASE", + "I/O base for SB", + FMT_HEX, + 0x220, + "Check from manual of the card"); + + ask_int_choice(B(OPT_SB), "SBC_IRQ", + "Sound Blaster IRQ", + FMT_INT, + 7, + "Check from manual of the card"); + + ask_int_choice(B(OPT_SB), "SBC_DMA", + "Sound Blaster DMA", + FMT_INT, + 1, + "0, 1 or 3"); + + ask_int_choice(B(OPT_SB), "SB_DMA2", + "Sound Blaster 16 bit DMA (SB16, Jazz16, SMW)", + FMT_INT, + 5, + "5, 6 or 7 (use 1 for 8 bit cards)"); + + ask_int_choice(B(OPT_SB), "SB_MPU_BASE", + "MPU401 I/O base of SB16, Jazz16 and ES1688", + FMT_HEX, + 0x330, + "Check from manual of the card"); + + show_comment(B(OPT_SB), + "MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688."); + show_comment(B(OPT_SB), + "Enter -1 to the following question if you have something else such as SB16/32."); + + ask_int_choice(B(OPT_SB), "SB_MPU_IRQ", + "SB MPU401 IRQ (Jazz16, SM Wave and ES1688)", + FMT_INT, + -1, + "Check from manual of the card"); + + ask_int_choice(B(OPT_PAS), "PAS_IRQ", + "PAS16 IRQ", + FMT_INT, + 10, + "3, 4, 5, 7, 9, 10, 11, 12, 14 or 15"); + + ask_int_choice(B(OPT_PAS), "PAS_DMA", + "PAS16 DMA", + FMT_INT, + 3, + "0, 1, 3, 5, 6 or 7"); + + if (selected_options & B(OPT_PAS)) + { + if (think_positively("Enable Joystick port on ProAudioSpectrum", 0, + "Enable this option if you want to use the joystick port provided\n" + "on the PAS sound card.\n")) + printf("#define PAS_JOYSTICK_ENABLE\n"); + + if (think_positively("Enable PAS16 bus clock option", 0, + "The PAS16 can be noisy with some motherboards. There is a command\n" + "line switch (:T?) in the DOS driver for PAS16 which solves this.\n" + "Don't enable this feature unless you have problems and have to use\n" + "this switch with DOS\n")) + printf("#define BROKEN_BUS_CLOCK\n"); + + if (think_positively("Disable SB mode of PAS16", 0, + "You should disable SB emulation of PAS16 if you want to use\n" + "Another SB compatible card in the same system\n")) + printf("#define DISABLE_SB_EMULATION\n"); + } + ask_int_choice(B(OPT_GUS), "GUS_BASE", + "I/O base for GUS", + FMT_HEX, + 0x220, + "210, 220, 230, 240, 250 or 260"); + + + ask_int_choice(B(OPT_GUS), "GUS_IRQ", + "GUS IRQ", + FMT_INT, + 15, + "3, 5, 7, 9, 11, 12 or 15"); + + ask_int_choice(B(OPT_GUS), "GUS_DMA", + "GUS DMA", + FMT_INT, + 6, + "1, 3, 5, 6 or 7"); + + ask_int_choice(B(OPT_GUS), "GUS_DMA2", + "Second DMA channel for GUS", + FMT_INT, + -1, + "1, 3, 5, 6 or 7"); + + ask_int_choice(B(OPT_GUS16), "GUS16_BASE", + "I/O base for the 16 bit daughtercard of GUS", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + + ask_int_choice(B(OPT_GUS16), "GUS16_IRQ", + "GUS 16 bit daughtercard IRQ", + FMT_INT, + 7, + "3, 4, 5, 7, or 9"); + + ask_int_choice(B(OPT_GUS16), "GUS16_DMA", + "GUS DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MPU401), "MPU_BASE", + "I/O base for MPU401", + FMT_HEX, + 0x330, + "Check from manual of the card"); + + ask_int_choice(B(OPT_MPU401), "MPU_IRQ", + "MPU401 IRQ", + FMT_INT, + 9, + "Check from manual of the card"); + + if (dump_only) + show_comment(B(OPT_MAUI), + "ERROR! You have to use old sound configuration method with Maui."); + + ask_int_choice(B(OPT_MAUI), "MAUI_BASE", + "I/O base for Maui", + FMT_HEX, + 0x330, + "210, 230, 260, 290, 300, 320, 338 or 330"); + + ask_int_choice(B(OPT_MAUI), "MAUI_IRQ", + "Maui IRQ", + FMT_INT, + 9, + "5, 9, 12 or 15"); + + ask_int_choice(B(OPT_UART6850), "U6850_BASE", + "I/O base for UART 6850 MIDI port", + FMT_HEX, + 0, + "(Unknown)"); + + ask_int_choice(B(OPT_UART6850), "U6850_IRQ", + "UART6850 IRQ", + FMT_INT, + -1, + "(Unknown)"); + + if (dump_only) + show_comment(B(OPT_PSS), + "ERROR! You have to use old sound configuration method with PSS cards."); + + ask_int_choice(B(OPT_PSS), "PSS_BASE", + "PSS I/O base", + FMT_HEX, + 0x220, + "220 or 240"); + + ask_int_choice(B(OPT_PSS), "PSS_MSS_BASE", + "PSS audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_PSS), "PSS_MSS_IRQ", + "PSS audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_PSS), "PSS_MSS_DMA", + "PSS audio DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_PSS), "PSS_MPU_BASE", + "PSS MIDI I/O base", + FMT_HEX, + 0x330, + ""); + + ask_int_choice(B(OPT_PSS), "PSS_MPU_IRQ", + "PSS MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice(B(OPT_MSS), "MSS_BASE", + "MSS/WSS I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_MSS), "MSS_IRQ", + "MSS/WSS IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_MSS), "MSS_DMA", + "MSS/WSS DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MSS), "MSS_DMA2", + "MSS/WSS second DMA (if possible)", + FMT_INT, + -1, + "0, 1 or 3"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_BASE", + "SoundScape MIDI I/O base", + FMT_HEX, + 0x330, + "320, 330, 340 or 350"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_IRQ", + "SoundScape MIDI IRQ", + FMT_INT, + 9, + ""); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_DMA", + "SoundScape initialization DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_MSS_BASE", + "SoundScape audio I/O base", + FMT_HEX, + 0x534, + "534, 608, E84 or F44"); + + ask_int_choice(B(OPT_SSCAPE), "SSCAPE_MSS_IRQ", + "SoundScape audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + + if (selected_options & B(OPT_SSCAPE)) + { + int reveal_spea; + + reveal_spea = think_positively( + "Is your SoundScape card made/marketed by Reveal or Spea", + 0, + "Enable if you have a SoundScape card with the Reveal or\n" + "Spea name on it.\n"); + if (reveal_spea) + printf("#define REVEAL_SPEA\n"); - build_defines (); - /* - * IRQ and DMA settings - */ - - ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE", - "I/O base for Audio Excel DSP 16", - FMT_HEX, - 0x220, - "220 or 240"); - - ask_int_choice (B (OPT_SB), "SBC_BASE", - "I/O base for SB", - FMT_HEX, - 0x220, - "Check from manual of the card"); - - ask_int_choice (B (OPT_SB), "SBC_IRQ", - "Sound Blaster IRQ", - FMT_INT, - 7, - "Check from manual of the card"); - - ask_int_choice (B (OPT_SB), "SBC_DMA", - "Sound Blaster DMA", - FMT_INT, - 1, - "0, 1 or 3"); - - ask_int_choice (B (OPT_SB), "SB_DMA2", - "Sound Blaster 16 bit DMA (SB16, Jazz16, SMW)", - FMT_INT, - 5, - "5, 6 or 7 (use 1 for 8 bit cards)"); - - ask_int_choice (B (OPT_SB), "SB_MPU_BASE", - "MPU401 I/O base of SB16, Jazz16 and ES1688", - FMT_HEX, - 0x330, - "Check from manual of the card"); - - show_comment (B (OPT_SB), - "MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688."); - show_comment (B (OPT_SB), - "Enter -1 to the following question if you have something else such as SB16/32."); - - ask_int_choice (B (OPT_SB), "SB_MPU_IRQ", - "SB MPU401 IRQ (Jazz16, SM Wave and ES1688)", - FMT_INT, - -1, - "Check from manual of the card"); - - ask_int_choice (B (OPT_PAS), "PAS_IRQ", - "PAS16 IRQ", - FMT_INT, - 10, - "3, 4, 5, 7, 9, 10, 11, 12, 14 or 15"); - - ask_int_choice (B (OPT_PAS), "PAS_DMA", - "PAS16 DMA", - FMT_INT, - 3, - "0, 1, 3, 5, 6 or 7"); - - if (selected_options & B (OPT_PAS)) - { - if (think_positively ("Enable Joystick port on ProAudioSpectrum", 0, - "Enable this option if you want to use the joystick port provided\n" - "on the PAS sound card.\n")) - printf ("#define PAS_JOYSTICK_ENABLE\n"); - - if (think_positively ("Enable PAS16 bus clock option", 0, - "The PAS16 can be noisy with some motherboards. There is a command\n" - "line switch (:T?) in the DOS driver for PAS16 which solves this.\n" - "Don't enable this feature unless you have problems and have to use\n" - "this switch with DOS\n")) - printf ("#define BROKEN_BUS_CLOCK\n"); - - if (think_positively ("Disable SB mode of PAS16", 0, - "You should disable SB emulation of PAS16 if you want to use\n" - "Another SB compatible card in the same system\n")) - printf ("#define DISABLE_SB_EMULATION\n"); - } - - ask_int_choice (B (OPT_GUS), "GUS_BASE", - "I/O base for GUS", - FMT_HEX, - 0x220, - "210, 220, 230, 240, 250 or 260"); - - - ask_int_choice (B (OPT_GUS), "GUS_IRQ", - "GUS IRQ", - FMT_INT, - 15, - "3, 5, 7, 9, 11, 12 or 15"); - - ask_int_choice (B (OPT_GUS), "GUS_DMA", - "GUS DMA", - FMT_INT, - 6, - "1, 3, 5, 6 or 7"); - - ask_int_choice (B (OPT_GUS), "GUS_DMA2", - "Second DMA channel for GUS", - FMT_INT, - -1, - "1, 3, 5, 6 or 7"); - - ask_int_choice (B (OPT_GUS16), "GUS16_BASE", - "I/O base for the 16 bit daughtercard of GUS", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - - ask_int_choice (B (OPT_GUS16), "GUS16_IRQ", - "GUS 16 bit daughtercard IRQ", - FMT_INT, - 7, - "3, 4, 5, 7, or 9"); - - ask_int_choice (B (OPT_GUS16), "GUS16_DMA", - "GUS DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MPU401), "MPU_BASE", - "I/O base for MPU401", - FMT_HEX, - 0x330, - "Check from manual of the card"); - - ask_int_choice (B (OPT_MPU401), "MPU_IRQ", - "MPU401 IRQ", - FMT_INT, - 9, - "Check from manual of the card"); - - if (dump_only) - show_comment (B (OPT_MAUI), - "ERROR! You have to use old sound configuration method with Maui."); - - ask_int_choice (B (OPT_MAUI), "MAUI_BASE", - "I/O base for Maui", - FMT_HEX, - 0x330, - "210, 230, 260, 290, 300, 320, 338 or 330"); - - ask_int_choice (B (OPT_MAUI), "MAUI_IRQ", - "Maui IRQ", - FMT_INT, - 9, - "5, 9, 12 or 15"); - - ask_int_choice (B (OPT_UART6850), "U6850_BASE", - "I/O base for UART 6850 MIDI port", - FMT_HEX, - 0, - "(Unknown)"); - - ask_int_choice (B (OPT_UART6850), "U6850_IRQ", - "UART6850 IRQ", - FMT_INT, - -1, - "(Unknown)"); - - if (dump_only) - show_comment (B (OPT_PSS), - "ERROR! You have to use old sound configuration method with PSS cards."); - - ask_int_choice (B (OPT_PSS), "PSS_BASE", - "PSS I/O base", - FMT_HEX, - 0x220, - "220 or 240"); - - ask_int_choice (B (OPT_PSS), "PSS_MSS_BASE", - "PSS audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_PSS), "PSS_MSS_IRQ", - "PSS audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_PSS), "PSS_MSS_DMA", - "PSS audio DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_PSS), "PSS_MPU_BASE", - "PSS MIDI I/O base", - FMT_HEX, - 0x330, - ""); - - ask_int_choice (B (OPT_PSS), "PSS_MPU_IRQ", - "PSS MIDI IRQ", - FMT_INT, - 9, - "3, 4, 5, 7 or 9"); - - ask_int_choice (B (OPT_MSS), "MSS_BASE", - "MSS/WSS I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_MSS), "MSS_IRQ", - "MSS/WSS IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_MSS), "MSS_DMA", - "MSS/WSS DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MSS), "MSS_DMA2", - "MSS/WSS second DMA (if possible)", - FMT_INT, - -1, - "0, 1 or 3"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_BASE", - "SoundScape MIDI I/O base", - FMT_HEX, - 0x330, - "320, 330, 340 or 350"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ", - "SoundScape MIDI IRQ", - FMT_INT, - 9, - ""); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_DMA", - "SoundScape initialization DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_BASE", - "SoundScape audio I/O base", - FMT_HEX, - 0x534, - "534, 608, E84 or F44"); - - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_IRQ", - "SoundScape audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - - if (selected_options & B (OPT_SSCAPE)) - { - int reveal_spea; - - reveal_spea = think_positively ( - "Is your SoundScape card made/marketed by Reveal or Spea", - 0, - "Enable if you have a SoundScape card with the Reveal or\n" - "Spea name on it.\n"); - if (reveal_spea) - printf ("#define REVEAL_SPEA\n"); - - } - - if (dump_only) - show_comment (B (OPT_TRIX), - "ERROR! You have to use old sound configuration method with OPL3-SA1."); - - ask_int_choice (B (OPT_TRIX), "TRIX_BASE", - "OPL3-SA1 audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_TRIX), "TRIX_IRQ", - "OPL3-SA1 audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_TRIX), "TRIX_DMA", - "OPL3-SA1 audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_TRIX), "TRIX_DMA2", - "OPL3-SA1 second (duplex) DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_TRIX), "TRIX_MPU_BASE", - "OPL3-SA1 MIDI I/O base", - FMT_HEX, - 0x330, - "330, 370, 3B0 or 3F0"); - - ask_int_choice (B (OPT_TRIX), "TRIX_MPU_IRQ", - "OPL3-SA1 MIDI IRQ", - FMT_INT, - 9, - "3, 4, 5, 7 or 9"); - - ask_int_choice (B (OPT_TRIX), "TRIX_SB_BASE", - "OPL3-SA1 SB I/O base", - FMT_HEX, - 0x220, - "220, 210, 230, 240, 250, 260 or 270"); - - ask_int_choice (B (OPT_TRIX), "TRIX_SB_IRQ", - "OPL3-SA1 SB IRQ", - FMT_INT, - 7, - "3, 4, 5 or 7"); - - ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA", - "OPL3-SA1 SB DMA", - FMT_INT, - 1, - "1 or 3"); - - - ask_int_choice (B (OPT_OPL3SA1), "OPL3SA1_BASE", - "OPL3-SA1 audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_OPL3SA1), "OPL3SA1_IRQ", - "OPL3-SA1 audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_OPL3SA1), "OPL3SA1_DMA", - "OPL3-SA1 audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_OPL3SA1), "OPL3SA1_DMA2", - "OPL3-SA1 second (duplex) DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_OPL3SA1), "OPL3SA1_MPU_BASE", - "OPL3-SA1 MIDI I/O base", - FMT_HEX, - 0x330, - "330, 370, 3B0 or 3F0"); - - ask_int_choice (B (OPT_OPL3SA1), "OPL3SA1_MPU_IRQ", - "OPL3-SA1 MIDI IRQ", - FMT_INT, - 9, - "3, 4, 5, 7 or 9"); - - ask_int_choice (B (OPT_CS4232), "CS4232_BASE", - "CS4232 audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_CS4232), "CS4232_IRQ", - "CS4232 audio IRQ", - FMT_INT, - 11, - "5, 7, 9, 11, 12 or 15"); - - ask_int_choice (B (OPT_CS4232), "CS4232_DMA", - "CS4232 audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_CS4232), "CS4232_DMA2", - "CS4232 second (duplex) DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_CS4232), "CS4232_MPU_BASE", - "CS4232 MIDI I/O base", - FMT_HEX, - 0x330, - "330, 370, 3B0 or 3F0"); - - ask_int_choice (B (OPT_CS4232), "CS4232_MPU_IRQ", - "CS4232 MIDI IRQ", - FMT_INT, - 9, - "5, 7, 9, 11, 12 or 15"); - - ask_int_choice (B (OPT_MAD16), "MAD16_BASE", - "MAD16 audio I/O base", - FMT_HEX, - 0x530, - "530, 604, E80 or F40"); - - ask_int_choice (B (OPT_MAD16), "MAD16_IRQ", - "MAD16 audio IRQ", - FMT_INT, - 11, - "7, 9, 10 or 11"); - - ask_int_choice (B (OPT_MAD16), "MAD16_DMA", - "MAD16 audio DMA", - FMT_INT, - 3, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MAD16), "MAD16_DMA2", - "MAD16 second (duplex) DMA", - FMT_INT, - 0, - "0, 1 or 3"); - - ask_int_choice (B (OPT_MAD16), "MAD16_MPU_BASE", - "MAD16 MIDI I/O base", - FMT_HEX, - 0x330, - "300, 310, 320 or 330 (0 disables)"); - - ask_int_choice (B (OPT_MAD16), "MAD16_MPU_IRQ", - "MAD16 MIDI IRQ", - FMT_INT, - 9, - "5, 7, 9 or 10"); - ask_int_choice (B (OPT_SOFTOSS), "SOFTOSS_RATE", - "Sampling rate for SoftOSS", - FMT_INT, - 22050, - "8000 to 48000"); - ask_int_choice (B (OPT_SOFTOSS), "SOFTOSS_VOICES", - "Max # of concurrent voices for SoftOSS", - FMT_INT, - 32, - "4 to 32"); + } + if (dump_only) + show_comment(B(OPT_TRIX), + "ERROR! You have to use old sound configuration method with OPL3-SA1."); + + ask_int_choice(B(OPT_TRIX), "TRIX_BASE", + "OPL3-SA1 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_TRIX), "TRIX_IRQ", + "OPL3-SA1 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_TRIX), "TRIX_DMA", + "OPL3-SA1 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_TRIX), "TRIX_DMA2", + "OPL3-SA1 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_TRIX), "TRIX_MPU_BASE", + "OPL3-SA1 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice(B(OPT_TRIX), "TRIX_MPU_IRQ", + "OPL3-SA1 MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice(B(OPT_TRIX), "TRIX_SB_BASE", + "OPL3-SA1 SB I/O base", + FMT_HEX, + 0x220, + "220, 210, 230, 240, 250, 260 or 270"); + + ask_int_choice(B(OPT_TRIX), "TRIX_SB_IRQ", + "OPL3-SA1 SB IRQ", + FMT_INT, + 7, + "3, 4, 5 or 7"); + + ask_int_choice(B(OPT_TRIX), "TRIX_SB_DMA", + "OPL3-SA1 SB DMA", + FMT_INT, + 1, + "1 or 3"); + + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_BASE", + "OPL3-SA1 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_IRQ", + "OPL3-SA1 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_DMA", + "OPL3-SA1 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_DMA2", + "OPL3-SA1 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_MPU_BASE", + "OPL3-SA1 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice(B(OPT_OPL3SA1), "OPL3SA1_MPU_IRQ", + "OPL3-SA1 MIDI IRQ", + FMT_INT, + 9, + "3, 4, 5, 7 or 9"); + + ask_int_choice(B(OPT_CS4232), "CS4232_BASE", + "CS4232 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_CS4232), "CS4232_IRQ", + "CS4232 audio IRQ", + FMT_INT, + 11, + "5, 7, 9, 11, 12 or 15"); + + ask_int_choice(B(OPT_CS4232), "CS4232_DMA", + "CS4232 audio DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_CS4232), "CS4232_DMA2", + "CS4232 second (duplex) DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_CS4232), "CS4232_MPU_BASE", + "CS4232 MIDI I/O base", + FMT_HEX, + 0x330, + "330, 370, 3B0 or 3F0"); + + ask_int_choice(B(OPT_CS4232), "CS4232_MPU_IRQ", + "CS4232 MIDI IRQ", + FMT_INT, + 9, + "5, 7, 9, 11, 12 or 15"); + + ask_int_choice(B(OPT_MAD16), "MAD16_BASE", + "MAD16 audio I/O base", + FMT_HEX, + 0x530, + "530, 604, E80 or F40"); + + ask_int_choice(B(OPT_MAD16), "MAD16_IRQ", + "MAD16 audio IRQ", + FMT_INT, + 11, + "7, 9, 10 or 11"); + + ask_int_choice(B(OPT_MAD16), "MAD16_DMA", + "MAD16 audio DMA", + FMT_INT, + 3, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MAD16), "MAD16_DMA2", + "MAD16 second (duplex) DMA", + FMT_INT, + 0, + "0, 1 or 3"); + + ask_int_choice(B(OPT_MAD16), "MAD16_MPU_BASE", + "MAD16 MIDI I/O base", + FMT_HEX, + 0x330, + "300, 310, 320 or 330 (0 disables)"); + + ask_int_choice(B(OPT_MAD16), "MAD16_MPU_IRQ", + "MAD16 MIDI IRQ", + FMT_INT, + 9, + "5, 7, 9 or 10"); + ask_int_choice(B(OPT_SOFTOSS), "SOFTOSS_RATE", + "Sampling rate for SoftOSS", + FMT_INT, + 22050, + "8000 to 48000"); + ask_int_choice(B(OPT_SOFTOSS), "SOFTOSS_VOICES", + "Max # of concurrent voices for SoftOSS", + FMT_INT, + 32, + "4 to 32"); } void -dump_script (void) +dump_script(void) { - int i; - - for (i = 0; i <= OPT_LAST; i++) - if (!(DUMMY_OPTS & B (i))) - if (!(DISABLED_OPTIONS & B (i))) - { - printf ("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro); - } + int i; + for (i = 0; i <= OPT_LAST; i++) + if (!(DUMMY_OPTS & B(i))) + if (!(DISABLED_OPTIONS & B(i))) + { + printf("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro); + } /* * Some "hardcoded" options */ - dump_only = 1; - selected_options = 0; - ask_parameters (); + dump_only = 1; + selected_options = 0; + ask_parameters(); - printf ("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n"); + printf("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n"); } void -dump_fixed_local (void) +dump_fixed_local(void) { - int i = 0; + int i = 0; - printf ("/* Computer generated file. Please don't edit! */\n\n"); - printf ("#define KERNEL_COMPATIBLE_CONFIG\n\n"); - printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n\n", selected_options); - - while (extra_options[i].name != NULL) - { - int n = 0, j; - - printf ("#if "); - - for (j = 0; j < OPT_LAST; j++) - if (!(DISABLED_OPTIONS & B (j))) - if (extra_options[i].mask & B (j)) - { - if (n) - printf (" || "); - if (!(n++ % 2)) - printf ("\\\n "); - - printf ("defined(CONFIG_%s)", hw_table[j].macro); - } - - printf ("\n"); - printf ("#\tdefine CONFIG_%s\n", extra_options[i].name); - printf ("#endif\n\n"); - i++; - } + printf("/* Computer generated file. Please don't edit! */\n\n"); + printf("#define KERNEL_COMPATIBLE_CONFIG\n\n"); + printf("#define SELECTED_SOUND_OPTIONS\t0x%08x\n\n", selected_options); + + while (extra_options[i].name != NULL) + { + int n = 0, j; + + printf("#if "); + + for (j = 0; j < OPT_LAST; j++) + if (!(DISABLED_OPTIONS & B(j))) + if (extra_options[i].mask & B(j)) + { + if (n) + printf(" || "); + if (!(n++ % 2)) + printf("\\\n "); + + printf("defined(CONFIG_%s)", hw_table[j].macro); + } + printf("\n"); + printf("#\tdefine CONFIG_%s\n", extra_options[i].name); + printf("#endif\n\n"); + i++; + } } void -dump_fixed_defines (void) +dump_fixed_defines(void) { - int i = 0; + int i = 0; - printf ("# Computer generated file. Please don't edit\n\n"); + printf("# Computer generated file. Please don't edit\n\n"); - while (extra_options[i].name != NULL) - { - int j; - - for (j = 0; j < OPT_LAST; j++) - if (!(DISABLED_OPTIONS & B (j))) - if (extra_options[i].mask & B (j)) - { - printf ("ifdef CONFIG_%s\n", hw_table[j].macro); - printf ("CONFIG_%s=y\n", extra_options[i].name); - printf ("endif\n\n"); - } + while (extra_options[i].name != NULL) + { + int j; - i++; - } + for (j = 0; j < OPT_LAST; j++) + { + if (!(DISABLED_OPTIONS & B(j))) + { + if (extra_options[i].mask & B(j)) + { + printf("ifdef CONFIG_%s\n", hw_table[j].macro); + printf ("ifneq ($(CONFIG_%s),Y)\n", extra_options[i].name); + printf("CONFIG_%s=y\n", extra_options[i].name); + printf("endif\n"); + printf("endif\n\n"); + } + } + } + i++; + } } int -main (int argc, char *argv[]) +main(int argc, char *argv[]) { - int i, full_driver = 1; - char old_config_file[200]; + int i, full_driver = 1; + char old_config_file[200]; - if (getuid () != 0) /* Not root */ - { - char *home; - - if ((home = getenv ("HOME")) != NULL) - { - sprintf (old_config_file, "%s/.soundconf", home); - oldconf = old_config_file; - } - } - - if (argc > 1) - { - if (strcmp (argv[1], "-o") == 0 && - use_old_config (oldconf)) - exit (0); - else if (strcmp (argv[1], "script") == 0) - { - dump_script (); - exit (0); - } - else if (strcmp (argv[1], "fixedlocal") == 0) - { - dump_fixed_local (); - exit (0); - } - else if (strcmp (argv[1], "fixeddefines") == 0) - { - dump_fixed_defines (); - exit (0); - } - } + if (getuid() != 0) /* Not root */ + { + char *home; - fprintf (stderr, "\nConfiguring Sound Support\n\n"); + if ((home = getenv("HOME")) != NULL) + { + sprintf(old_config_file, "%s/.soundconf", home); + oldconf = old_config_file; + } + } + if (argc > 1) + { + if (strcmp(argv[1], "-o") == 0 && + use_old_config(oldconf)) + exit(0); + else if (strcmp(argv[1], "script") == 0) + { + dump_script(); + exit(0); + } else if (strcmp(argv[1], "fixedlocal") == 0) + { + dump_fixed_local(); + exit(0); + } else if (strcmp(argv[1], "fixeddefines") == 0) + { + dump_fixed_defines(); + exit(0); + } + } + fprintf(stderr, "\nConfiguring Sound Support\n\n"); - if (access (oldconf, R_OK) == 0) - { - char str[255]; + if (access(oldconf, R_OK) == 0) + { + char str[255]; - sprintf (str, "Old configuration exists in `%s'. Use it", oldconf); - if (think_positively (str, 1, - "Enable this option to load the previously saved configuration file\n" + sprintf(str, "Old configuration exists in `%s'. Use it", oldconf); + if (think_positively(str, 1, + "Enable this option to load the previously saved configuration file\n" "for all of the sound driver parameters.\n")) - if (use_old_config (oldconf)) - exit (0); - } - - printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n"); - printf ("/*\tMaking changes to this file is not as simple as it may look.\t*/\n\n"); - printf ("/*\tIf you change the CONFIG_ settings in local.h you\t*/\n"); - printf ("/*\t_have_ to edit .defines too.\t*/\n\n"); - - { - /* - * Partial driver - */ + if (use_old_config(oldconf)) + exit(0); + } + printf("/*\tGenerated by configure. Don't edit!!!!\t*/\n"); + printf("/*\tMaking changes to this file is not as simple as it may look.\t*/\n\n"); + printf("/*\tIf you change the CONFIG_ settings in local.h you\t*/\n"); + printf("/*\t_have_ to edit .defines too.\t*/\n\n"); + + { + /* + * Partial driver + */ + + full_driver = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (can_select_option(i)) + { + if (!(selected_options & B(i))) /* + * Not selected yet + */ + if (!hw_table[i].verify) + { + if (hw_table[i].alias) + selected_options |= B(hw_table[i].alias); + else + selected_options |= B(i); + } else + { + int def_answ = hw_table[i].default_answ; + + if (think_positively(questions[i], def_answ, help[i])) + if (hw_table[i].alias) + selected_options |= B(hw_table[i].alias); + else + selected_options |= B(i); + } + } + } - full_driver = 0; + if (selected_options & B(OPT_SB)) + { + if (think_positively( + "Support for the SG NX Pro mixer", 0, + "Enable this if you want to support the additional mixer functions\n" + "provided on Sound Galaxy NX Pro sound cards.\n")) + printf("#define __SGNXPRO__\n"); + } + if (selected_options & B(OPT_SB)) + { + if (think_positively("Support for the MV Jazz16 (ProSonic etc.)", 0, + "Enable this if you have an MV Jazz16 or ProSonic sound card.\n")) + { + if (think_positively("Do you have SoundMan Wave", 0, + "Enable this option of you have the Logitech SoundMan Wave sound card.\n")) + { + printf("#define SM_WAVE\n"); + + midi0001_again: + if (think_positively( + "Do you have access to the MIDI0001.BIN file", 1, + "The Logitech SoundMan Wave has a microcontroller which must be\n" + "initialized before MIDI emulation works. This is possible only if the\n" + "microcode file is compiled into the driver.\n")) + { + char path[512]; + + fprintf(stderr, + "Enter full name of the MIDI0001.BIN file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including microcode file %s\n", path); + + if (!bin2hex(path, "smw-midi0001.h", "smw_ucode")) + { + fprintf(stderr, "Couldn't open file %s\n", + path); + if (think_positively("Try again with correct path", 1, + "The specified file could not be opened. Enter the correct path to the\n" + "file.\n")) + goto midi0001_again; + } else + { + printf("#define SMW_MIDI0001_INCLUDED\n"); + printf("/*build bin2hex %s smw-midi0001.h smw_ucode */\n", path); + } + } + } + } + } + if (selected_options & B(OPT_SB)) + { + if (think_positively("Do you have a Logitech SoundMan Games", 0, + "The Logitech SoundMan Games supports 44 kHz in stereo while the\n" + "standard SB Pro supports just 22 kHz stereo. You have the option of\n" + "enabling SM Games mode. However, enable it only if you are sure that\n" + "your card is an SM Games. Enabling this feature with a plain old SB\n" + "Pro will cause troubles with stereo mode.\n\n" + "DANGER! Read the above once again before answering 'y'\n" + "Answer 'n' if you are unsure what to do!\n")) + printf("#define SM_GAMES\n"); + } + if (selected_options & B(OPT_AEDSP16)) + { + int sel1 = 0; - for (i = 0; i <= OPT_LAST; i++) - if (can_select_option (i)) - { - if (!(selected_options & B (i))) /* - * Not selected yet - */ - if (!hw_table[i].verify) - { - if (hw_table[i].alias) - selected_options |= B (hw_table[i].alias); - else - selected_options |= B (i); - } - else - { - int def_answ = hw_table[i].default_answ; - - if (think_positively (questions[i], def_answ, help[i])) - if (hw_table[i].alias) - selected_options |= B (hw_table[i].alias); - else - selected_options |= B (i); - } - } - } + if (selected_options & B(OPT_SB)) + { - if (selected_options & B (OPT_SB)) - { - if (think_positively ( - "Support for the SG NX Pro mixer", 0, - "Enable this if you want to support the additional mixer functions\n" - "provided on Sound Galaxy NX Pro sound cards.\n")) - printf ("#define __SGNXPRO__\n"); - } - - if (selected_options & B (OPT_SB)) - { - if (think_positively ("Support for the MV Jazz16 (ProSonic etc.)", 0, - "Enable this if you have an MV Jazz16 or ProSonic sound card.\n")) - { - if (think_positively ("Do you have SoundMan Wave", 0, - "Enable this option of you have the Logitech SoundMan Wave sound card.\n")) - { - printf ("#define SM_WAVE\n"); - - midi0001_again: - if (think_positively ( - "Do you have access to the MIDI0001.BIN file", 1, - "The Logitech SoundMan Wave has a microcontroller which must be\n" - "initialized before MIDI emulation works. This is possible only if the\n" - "microcode file is compiled into the driver.\n")) - { - char path[512]; + if (think_positively( + "Do you want support for the Audio Excel Sound Blaster Pro mode", + 1, + "Enable this option if you want the Audio Excel sound card to operate\n" + "in Sound Blaster Pro mode.\n")) + { + printf("#define AEDSP16_SBPRO\n"); + sel1 = 1; + } + } + if ((selected_options & B(OPT_MSS)) && (sel1 == 0)) + { - fprintf (stderr, - "Enter full name of the MIDI0001.BIN file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including microcode file %s\n", path); - - if (!bin2hex (path, "smw-midi0001.h", "smw_ucode")) - { - fprintf (stderr, "Couldn't open file %s\n", - path); - if (think_positively ("Try again with correct path", 1, - "The specified file could not be opened. Enter the correct path to the\n" - "file.\n")) - goto midi0001_again; + if (think_positively( + "Do you want support for the Audio Excel Microsoft Sound System mode", + 1, + "Enable this option if you want the Audio Excel sound card to operate\n" + "in Microsoft Sound System mode.\n")) + { + printf("#define AEDSP16_MSS\n"); + sel1 = 1; + } } - else + if (sel1 == 0) { - printf ("#define SMW_MIDI0001_INCLUDED\n"); - printf ("/*build bin2hex %s smw-midi0001.h smw_ucode */\n", path); + printf("invalid_configuration__run_make_config_again\n"); + fprintf(stderr, "ERROR!!!!!\nYou must select at least one mode when using Audio Excel!\n"); + exit(-1); } - } - } - } - } - - if (selected_options & B (OPT_SB)) - { - if (think_positively ("Do you have a Logitech SoundMan Games", 0, - "The Logitech SoundMan Games supports 44 kHz in stereo while the\n" - "standard SB Pro supports just 22 kHz stereo. You have the option of\n" - "enabling SM Games mode. However, enable it only if you are sure that\n" - "your card is an SM Games. Enabling this feature with a plain old SB\n" - "Pro will cause troubles with stereo mode.\n\n" - "DANGER! Read the above once again before answering 'y'\n" - "Answer 'n' if you are unsure what to do!\n")) - printf ("#define SM_GAMES\n"); - } - - if (selected_options & B (OPT_AEDSP16)) - { - int sel1 = 0; + if (selected_options & B(OPT_MPU401)) + printf("#define AEDSP16_MPU401\n"); + } + if (selected_options & B(OPT_PSS)) + { + genld_again: + if (think_positively("Do you wish to include an LD file", 1, + "If you want to emulate the Sound Blaster card and you have a DSPxxx.LD\n" + "file then you must include the LD in the kernel.\n")) + { + char path[512]; - if (selected_options & B (OPT_SB)) - { + fprintf(stderr, + "Enter the path to your LD file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including LD file %s\n", path); + + if (!bin2hex(path, "synth-ld.h", "pss_synth")) + { + fprintf(stderr, "couldn't open `%s' as the LD file\n", path); + if (think_positively("try again with correct path", 1, + "The given LD file could not opened.\n")) + goto genld_again; + } else + { + printf("#define PSS_HAVE_LD\n"); + printf("/*build bin2hex %s synth-ld.h pss_synth */\n", path); + } + } else + { + FILE *sf = fopen("synth-ld.h", "w"); - if (think_positively ( - "Do you want support for the Audio Excel Sound Blaster Pro mode", - 1, - "Enable this option if you want the Audio Excel sound card to operate\n" - "in Sound Blaster Pro mode.\n")) - { - printf ("#define AEDSP16_SBPRO\n"); - sel1 = 1; - } - } + fprintf(sf, "/* automatically generated by configure */\n"); + fprintf(sf, "unsigned char pss_synth[1];\n" + "#define pss_synthLen 0\n"); + fclose(sf); + } + } + if (selected_options & B(OPT_TRIX)) + { + hex2hex_again: - if ((selected_options & B (OPT_MSS)) && (sel1 == 0)) - { + if (think_positively("Do you want to include TRXPRO.HEX in your kernel", + 1, + "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n" + "needs to be initialized by downloading the code from the file TRXPRO.HEX\n" + "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n" + "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n" + "Pro will not work without this file!\n")) + { + char path[512]; - if (think_positively ( - "Do you want support for the Audio Excel Microsoft Sound System mode", - 1, - "Enable this option if you want the Audio Excel sound card to operate\n" - "in Microsoft Sound System mode.\n")) - { - printf ("#define AEDSP16_MSS\n"); - sel1 = 1; - } - } + fprintf(stderr, + "Enter the path to your TRXPRO.HEX file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including HEX file `%s'\n", path); + + if (!hex2hex(path, "trix_boot.h", "trix_boot")) + goto hex2hex_again; + printf("/*build hex2hex %s trix_boot.h trix_boot */\n", path); + printf("#define INCLUDE_TRIX_BOOT\n"); + } + } + if (selected_options & B(OPT_MSS)) + { + if (think_positively("Support for builtin sound of Compaq Deskpro XL", 0, + "Enable this if you have Compaq Deskpro XL.\n")) + { + printf("#define DESKPROXL\n"); + } + } + if (selected_options & B(OPT_MAUI)) + { + oswf_again: + if (think_positively( + "Do you have access to the OSWF.MOT file", 1, + "TB Maui and Tropez have a microcontroller which needs to be initialized\n" + "prior use. OSWF.MOT is a file distributed with card's DOS/Windows drivers\n" + "which is required during initialization\n")) + { + char path[512]; - if (sel1 == 0) - { - printf ("invalid_configuration__run_make_config_again\n"); - fprintf (stderr, "ERROR!!!!!\nYou must select at least one mode when using Audio Excel!\n"); - exit (-1); - } - if (selected_options & B (OPT_MPU401)) - printf ("#define AEDSP16_MPU401\n"); - } - - if (selected_options & B (OPT_PSS)) - { - genld_again: - if (think_positively ("Do you wish to include an LD file", 1, - "If you want to emulate the Sound Blaster card and you have a DSPxxx.LD\n" - "file then you must include the LD in the kernel.\n")) - { - char path[512]; + fprintf(stderr, + "Enter full name of the OSWF.MOT file (pwd is sound): "); + scanf("%s", path); + fprintf(stderr, "including microcode file %s\n", path); + + if (!bin2hex(path, "maui_boot.h", "maui_os")) + { + fprintf(stderr, "Couldn't open file %s\n", + path); + if (think_positively("Try again with correct path", 1, + "The specified file could not be opened. Enter the correct path to the\n" + "file.\n")) + goto oswf_again; + } else + { + printf("#define HAVE_MAUI_BOOT\n"); + printf("/*build bin2hex %s maui_boot.h maui_os */\n", path); + } + } + } + if (!(selected_options & ANY_DEVS)) + { + printf("invalid_configuration__run_make_config_again\n"); + fprintf(stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device ***\n\n"); + exit(0); + } + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B(i)) + printf("#define CONFIG_%s\n", hw_table[i].macro); + else + printf("#undef CONFIG_%s\n", hw_table[i].macro); - fprintf (stderr, - "Enter the path to your LD file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including LD file %s\n", path); - - if (!bin2hex (path, "synth-ld.h", "pss_synth")) - { - fprintf (stderr, "couldn't open `%s' as the LD file\n", path); - if (think_positively ("try again with correct path", 1, - "The given LD file could not opened.\n")) - goto genld_again; - } - else - { - printf ("#define PSS_HAVE_LD\n"); - printf ("/*build bin2hex %s synth-ld.h pss_synth */\n", path); - } - } - else - { - FILE *sf = fopen ("synth-ld.h", "w"); + printf("\n"); - fprintf (sf, "/* automatically generated by configure */\n"); - fprintf (sf, "unsigned char pss_synth[1];\n" - "#define pss_synthLen 0\n"); - fclose (sf); - } - } + i = 0; - if (selected_options & B (OPT_TRIX)) - { - hex2hex_again: - - if (think_positively ("Do you want to include TRXPRO.HEX in your kernel", - 1, - "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n" - "needs to be initialized by downloading the code from the file TRXPRO.HEX\n" - "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n" - "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n" - "Pro will not work without this file!\n")) - { - char path[512]; + while (extra_options[i].name != NULL) + { + if (selected_options & extra_options[i].mask) + printf("#define CONFIG_%s\n", extra_options[i].name); + else + printf("#undef CONFIG_%s\n", extra_options[i].name); + i++; + } - fprintf (stderr, - "Enter the path to your TRXPRO.HEX file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including HEX file `%s'\n", path); - - if (!hex2hex (path, "trix_boot.h", "trix_boot")) - goto hex2hex_again; - printf ("/*build hex2hex %s trix_boot.h trix_boot */\n", path); - printf ("#define INCLUDE_TRIX_BOOT\n"); - } - } + printf("\n"); - if (selected_options & B (OPT_MSS)) - { - if (think_positively ("Support for builtin sound of Compaq Deskpro XL", 0, - "Enable this if you have Compaq Deskpro XL.\n")) - { - printf ("#define DESKPROXL\n"); - } - } + ask_parameters(); - if (selected_options & B (OPT_MAUI)) - { - oswf_again: - if (think_positively ( - "Do you have access to the OSWF.MOT file", 1, - "TB Maui and Tropez have a microcontroller which needs to be initialized\n" - "prior use. OSWF.MOT is a file distributed with card's DOS/Windows drivers\n" - "which is required during initialization\n")) - { - char path[512]; + printf("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options); + fprintf(stderr, "\nThe sound driver is now configured.\n"); - fprintf (stderr, - "Enter full name of the OSWF.MOT file (pwd is sound): "); - scanf ("%s", path); - fprintf (stderr, "including microcode file %s\n", path); - - if (!bin2hex (path, "maui_boot.h", "maui_os")) - { - fprintf (stderr, "Couldn't open file %s\n", - path); - if (think_positively ("Try again with correct path", 1, - "The specified file could not be opened. Enter the correct path to the\n" - "file.\n")) - goto oswf_again; - } - else - { - printf ("#define HAVE_MAUI_BOOT\n"); - printf ("/*build bin2hex %s maui_boot.h maui_os */\n", path); - } - } - } + if (!old_config_used) + { + char str[255]; - if (!(selected_options & ANY_DEVS)) - { - printf ("invalid_configuration__run_make_config_again\n"); - fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device ***\n\n"); - exit (0); - } - - for (i = 0; i <= OPT_LAST; i++) - if (!hw_table[i].alias) - if (selected_options & B (i)) - printf ("#define CONFIG_%s\n", hw_table[i].macro); - else - printf ("#undef CONFIG_%s\n", hw_table[i].macro); - - printf ("\n"); - - i = 0; - - while (extra_options[i].name != NULL) - { - if (selected_options & extra_options[i].mask) - printf ("#define CONFIG_%s\n", extra_options[i].name); - else - printf ("#undef CONFIG_%s\n", extra_options[i].name); - i++; - } - - printf ("\n"); - - ask_parameters (); - - printf ("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options); - fprintf (stderr, "\nThe sound driver is now configured.\n"); - - if (!old_config_used) - { - char str[255]; - - sprintf (str, "Save copy of this configuration to `%s'", oldconf); - if (think_positively (str, 1, - "If you enable this option then the sound driver configuration is\n" - "saved to a file. If you later need to recompile the kernel you have\n" - "the option of using the saved configuration.\n")) - { - char cmd[200]; + sprintf(str, "Save copy of this configuration to `%s'", oldconf); + if (think_positively(str, 1, + "If you enable this option then the sound driver configuration is\n" + "saved to a file. If you later need to recompile the kernel you have\n" + "the option of using the saved configuration.\n")) + { + char cmd[200]; - sprintf (cmd, "cp local.h %s", oldconf); + sprintf(cmd, "cp local.h %s", oldconf); - fclose (stdout); - if (system (cmd) != 0) - perror (cmd); - } - } - exit (0); + fclose(stdout); + if (system(cmd) != 0) + perror(cmd); + } + } + exit(0); } int -bin2hex (char *path, char *target, char *varname) +bin2hex(char *path, char *target, char *varname) { - int fd; - int count; - char c; - int i = 0; - - if ((fd = open (path, 0)) > 0) - { - FILE *sf = fopen (target, "w"); - - fprintf (sf, "/* automatically generated by configure */\n"); - fprintf (sf, "static unsigned char %s[] = {\n", varname); - while (1) - { - count = read (fd, &c, 1); - if (count == 0) - break; - if (i != 0 && (i % 10) == 0) - fprintf (sf, "\n"); - fprintf (sf, "0x%02lx,", c & 0xFFL); - i++; - } - fprintf (sf, "};\n" - "#define %sLen %d\n", varname, i); - fclose (sf); - close (fd); - return 1; - } + int fd; + int count; + char c; + int i = 0; + + if ((fd = open(path, 0)) > 0) + { + FILE *sf = fopen(target, "w"); - return 0; + fprintf(sf, "/* automatically generated by configure */\n"); + fprintf(sf, "static unsigned char %s[] = {\n", varname); + while (1) + { + count = read(fd, &c, 1); + if (count == 0) + break; + if (i != 0 && (i % 10) == 0) + fprintf(sf, "\n"); + fprintf(sf, "0x%02lx,", c & 0xFFL); + i++; + } + fprintf(sf, "};\n" + "#define %sLen %d\n", varname, i); + fclose(sf); + close(fd); + return 1; + } + return 0; } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.1.66/linux/drivers/sound/cs4232.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/cs4232.c Sat Nov 29 10:33:20 1997 @@ -21,19 +21,20 @@ * for more info. */ #include - +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_CS4232 +#if defined(CONFIG_CS4232) || defined (MODULE) #define KEY_PORT 0x279 /* Same as LPT1 status port */ #define CSN_NUM 0x99 /* Just a random number */ -static void -CS_OUT (unsigned char a) +static void +CS_OUT(unsigned char a) { - outb ((a), KEY_PORT); + outb((a), KEY_PORT); } #define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);} #define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);} @@ -42,55 +43,54 @@ static int mpu_detected = 0; int -probe_cs4232_mpu (struct address_info *hw_config) +probe_cs4232_mpu(struct address_info *hw_config) { /* * Just write down the config values. */ - mpu_base = hw_config->io_base; - mpu_irq = hw_config->irq; + mpu_base = hw_config->io_base; + mpu_irq = hw_config->irq; - return 1; + return 1; } void -attach_cs4232_mpu (struct address_info *hw_config) +attach_cs4232_mpu(struct address_info *hw_config) { } static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ { - 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, - 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2, - 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13, - 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a + 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, + 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2, + 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13, + 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a }; int -probe_cs4232 (struct address_info *hw_config) +probe_cs4232(struct address_info *hw_config) { - int i, n; - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - - static struct wait_queue *cs_sleeper = NULL; - static volatile struct snd_wait cs_sleep_flag = - {0}; + int i, n; + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + + static struct wait_queue *cs_sleeper = NULL; + static volatile struct snd_wait cs_sleep_flag = + {0}; /* * Verify that the I/O port range is free. */ - if (check_region (base, 4)) - { - printk ("cs4232.c: I/O port 0x%03x not free\n", base); - return 0; - } - - if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp)) - return 1; /* The card is already active */ + if (check_region(base, 4)) + { + printk("cs4232.c: I/O port 0x%03x not free\n", base); + return 0; + } + if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) + return 1; /* The card is already active */ /* * This version of the driver doesn't use the PnP method when configuring @@ -105,241 +105,287 @@ * first time. */ - for (n = 0; n < 4; n++) - { - cs_sleep_flag.opts = WK_NONE; + for (n = 0; n < 4; n++) + { + cs_sleep_flag.opts = WK_NONE; /* * Wake up the card by sending a 32 byte Crystal key to the key port. */ - for (i = 0; i < 32; i++) - CS_OUT (crystal_key[i]); + for (i = 0; i < 32; i++) + CS_OUT(crystal_key[i]); - { - unsigned long tlimit; + { + unsigned long tlimit; - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Delay */ /* * Now set the CSN (Card Select Number). */ - CS_OUT2 (0x06, CSN_NUM); + CS_OUT2(0x06, CSN_NUM); /* * Then set some config bytes. First logical device 0 */ - CS_OUT2 (0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ - CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ + CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ + CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ - if (check_region (0x388, 4)) /* Not free */ - CS_OUT3 (0x48, 0x00, 0x00) /* FM base off */ - else - CS_OUT3 (0x48, 0x03, 0x88); /* FM base 0x388 */ - - CS_OUT3 (0x42, 0x00, 0x00); /* SB base off */ - CS_OUT2 (0x22, irq); /* SB+WSS IRQ */ - CS_OUT2 (0x2a, dma1); /* SB+WSS DMA */ - - if (dma2 != -1) - CS_OUT2 (0x25, dma2) /* WSS DMA2 */ - else - CS_OUT2 (0x25, 4); /* No WSS DMA2 */ - - CS_OUT2 (0x33, 0x01); /* Activate logical dev 0 */ - - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ + if (check_region(0x388, 4)) /* Not free */ + CS_OUT3(0x48, 0x00, 0x00) /* FM base off */ + else + CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */ + + CS_OUT3(0x42, 0x00, 0x00); /* SB base off */ + CS_OUT2(0x22, irq); /* SB+WSS IRQ */ + CS_OUT2(0x2a, dma1); /* SB+WSS DMA */ + + if (dma2 != -1) + CS_OUT2(0x25, dma2) /* WSS DMA2 */ + else + CS_OUT2(0x25, 4); /* No WSS DMA2 */ + + CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */ + + + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Delay */ /* * Initialize logical device 3 (MPU) */ #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0) - { - CS_OUT2 (0x15, 0x03); /* Select logical device 3 (MPU) */ - CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ - CS_OUT2 (0x22, mpu_irq); /* MPU IRQ */ - CS_OUT2 (0x33, 0x01); /* Activate logical dev 3 */ - } + if (mpu_base != 0 && mpu_irq != 0) + { + CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ + CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ + CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ + CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ + } #endif /* * Finally activate the chip */ - CS_OUT (0x79); + CS_OUT(0x79); - { - unsigned long tlimit; + { + unsigned long tlimit; - if (HZ / 5) - current->timeout = tlimit = jiffies + (HZ / 5); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ + if (HZ / 5) + current->timeout = tlimit = jiffies + (HZ / 5); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Delay */ /* * Then try to detect the codec part of the chip */ - if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp)) - return 1; + if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) + return 1; - { - unsigned long tlimit; + { + unsigned long tlimit; - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + cs_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&cs_sleeper); + if (!(cs_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + cs_sleep_flag.opts |= WK_TIMEOUT; + } + cs_sleep_flag.opts &= ~WK_SLEEP; + }; /* Longer delay */ } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Longer delay */ - } - return 0; + return 0; } void -attach_cs4232 (struct address_info *hw_config) +attach_cs4232(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; - - if (dma2 == -1) - dma2 = dma1; - - ad1848_init ("Crystal audio controller", base, - irq, - dma1, /* Playback DMA */ - dma2, /* Capture DMA */ - 0, - hw_config->osp); - - if (num_mixers > old_num_mixers) - { /* Assume the mixer map is as suggested in the CS4232 databook */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ - } - + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int old_num_mixers = num_mixers; + + if (dma2 == -1) + dma2 = dma1; + + hw_config->slots[0] = ad1848_init("Crystal audio controller", base, + irq, + dma1, /* Playback DMA */ + dma2, /* Capture DMA */ + 0, + hw_config->osp); + + if (num_mixers > old_num_mixers) + { /* Assume the mixer map is as suggested in the CS4232 databook */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ + } #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0) - { - static struct address_info hw_config2 = - {0}; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - - if (probe_uart401 (&hw_config2)) - { - mpu_detected = 1; - attach_uart401 (&hw_config2); - } - else - { - mpu_base = mpu_irq = 0; - } - } + if (mpu_base != 0 && mpu_irq != 0) + { + static struct address_info hw_config2 = + {0}; /* Ensure it's initialized */ + + hw_config2.io_base = mpu_base; + hw_config2.irq = mpu_irq; + hw_config2.dma = -1; + hw_config2.dma2 = -1; + hw_config2.always_detect = 0; + hw_config2.name = NULL; + hw_config2.driver_use_1 = 0; + hw_config2.driver_use_2 = 0; + hw_config2.card_subtype = 0; + + if (probe_uart401(&hw_config2)) + { + mpu_detected = 1; + attach_uart401(&hw_config2); + } else + { + mpu_base = mpu_irq = 0; + } + hw_config->slots[1] = hw_config2.slots[1]; + } #endif } void -unload_cs4232 (struct address_info *hw_config) +unload_cs4232(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - - if (dma2 == -1) - dma2 = dma1; + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; - ad1848_unload (base, - irq, - dma1, /* Playback DMA */ - dma2, /* Capture DMA */ - 0); + if (dma2 == -1) + dma2 = dma1; + ad1848_unload(base, + irq, + dma1, /* Playback DMA */ + dma2, /* Capture DMA */ + 0); + sound_unload_audiodev(hw_config->slots[0]); #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) - { - static struct address_info hw_config2 = - {0}; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; + if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) + { + static struct address_info hw_config2 = + {0}; /* Ensure it's initialized */ + + hw_config2.io_base = mpu_base; + hw_config2.irq = mpu_irq; + hw_config2.dma = -1; + hw_config2.dma2 = -1; + hw_config2.always_detect = 0; + hw_config2.name = NULL; + hw_config2.driver_use_1 = 0; + hw_config2.driver_use_2 = 0; + hw_config2.card_subtype = 0; + hw_config2.slots[1] = hw_config->slots[1]; - unload_uart401 (&hw_config2); - } + unload_uart401(&hw_config2); + } #endif } void -unload_cs4232_mpu (struct address_info *hw_config) +unload_cs4232_mpu(struct address_info *hw_config) { - /* Not required. Handled by cs4232_unload */ + /* Not required. Handled by cs4232_unload */ } +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; + +struct address_info cfg; + +/* + * Install a CS4232 based card. Need to have ad1848 and mpu401 + * loaded ready. + */ + +int +init_module(void) +{ + if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) + { + printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + if (probe_cs4232(&cfg) == 0) + return -ENODEV; + + probe_cs4232_mpu(&cfg); /* Bug always returns 0 not OK -- AC */ + + attach_cs4232(&cfg); + attach_cs4232_mpu(&cfg); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + unload_cs4232_mpu(&cfg); + unload_cs4232(&cfg); + SOUND_LOCK_END; +} +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.1.66/linux/drivers/sound/dev_table.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/dev_table.c Sat Nov 29 10:33:20 1997 @@ -20,529 +20,642 @@ int sound_started = 0; -int sndtable_get_cardcount (void); +int sndtable_get_cardcount(void); int -snd_find_driver (int type) +snd_find_driver(int type) { - int i, n = num_sound_drivers; + int i, n = num_sound_drivers; - for (i = 0; i < n; i++) - if (sound_drivers[i].card_type == type) - return i; + for (i = 0; i < n; i++) + if (sound_drivers[i].card_type == type) + return i; - return -1; + return -1; } static void -start_services (void) +start_services(void) { - int soundcards_installed; + int soundcards_installed; - if (!(soundcards_installed = sndtable_get_cardcount ())) - return; /* No cards detected */ +#ifdef FIXME + if (!(soundcards_installed = sndtable_get_cardcount())) + return; /* No cards detected */ +#endif #ifdef CONFIG_AUDIO - if (num_audiodevs) /* Audio devices present */ - { - int dev; + if (num_audiodevs) /* Audio devices present */ + { + int dev; - for (dev = 0; dev < num_audiodevs; dev++) - { - } - audio_init_devices (); - } + for (dev = 0; dev < num_audiodevs; dev++) + { + } + audio_init_devices(); + } #endif - return; + return; } static void -start_cards (void) +start_cards(void) { - int i, n = num_sound_cards; - int drv; + int i, n = num_sound_cards; + int drv; - sound_started = 1; - if (trace_init) - printk ("Sound initialization started\n"); + sound_started = 1; + if (trace_init) + printk("Sound initialization started\n"); #ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_preinit_lowlevel_drivers (void); + { + extern void sound_preinit_lowlevel_drivers(void); - sound_preinit_lowlevel_drivers (); - } +#ifdef FIXME + sound_preinit_lowlevel_drivers(); +#endif + } #endif /* * Check the number of cards actually defined in the table */ - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - num_sound_cards = i + 1; + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + num_sound_cards = i + 1; - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].enabled) - { - snd_installed_cards[i].for_driver_use = NULL; - - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - { - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - continue; - } - - snd_installed_cards[i].config.card_subtype = - sound_drivers[drv].card_subtype; - - if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) - { - - sound_drivers[drv].attach (&snd_installed_cards[i].config); - - } - else - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - } + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + if (snd_installed_cards[i].enabled) + { + snd_installed_cards[i].for_driver_use = NULL; + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) + { + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + continue; + } + snd_installed_cards[i].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe(&snd_installed_cards[i].config)) + { + + sound_drivers[drv].attach(&snd_installed_cards[i].config); + + } else + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + } #ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_init_lowlevel_drivers (void); + { + extern void sound_init_lowlevel_drivers(void); - sound_init_lowlevel_drivers (); - } + sound_init_lowlevel_drivers(); + } #endif - if (trace_init) - printk ("Sound initialization complete\n"); + if (trace_init) + printk("Sound initialization complete\n"); } void -sndtable_init (void) +sndtable_init(void) { - start_cards (); + start_cards(); } void -sound_unload_drivers (void) +sound_unload_drivers(void) { - int i, n = num_sound_cards; - int drv; - - if (!sound_started) - return; + int i, n = num_sound_cards; + int drv; - if (trace_init) - printk ("Sound unload started\n"); + if (!sound_started) + return; + if (trace_init) + printk("Sound unload started\n"); - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].enabled) - { - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) - { - if (sound_drivers[drv].unload) - { - sound_drivers[drv].unload (&snd_installed_cards[i].config); - snd_installed_cards[i].enabled = 0; - } - } - } - for (i=0;iio_base; - snd_installed_cards[sel].config.irq = hw_config->irq; - snd_installed_cards[sel].config.dma = hw_config->dma; - snd_installed_cards[sel].config.dma2 = hw_config->dma2; - snd_installed_cards[sel].config.name = hw_config->name; - snd_installed_cards[sel].config.always_detect = hw_config->always_detect; - snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + snd_installed_cards[sel].for_driver_use = NULL; + snd_installed_cards[sel].config.io_base = hw_config->io_base; + snd_installed_cards[sel].config.irq = hw_config->irq; + snd_installed_cards[sel].config.dma = hw_config->dma; + snd_installed_cards[sel].config.dma2 = hw_config->dma2; + snd_installed_cards[sel].config.name = hw_config->name; + snd_installed_cards[sel].config.always_detect = hw_config->always_detect; + snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + + if ((drv = snd_find_driver(snd_installed_cards[sel].card_type)) == -1) + { + snd_installed_cards[sel].enabled = 0; + DEB(printk("Failed to find driver\n")); + return 0; + } + DEB(printk("Driver name '%s'\n", sound_drivers[drv].name)); + + hw_config->card_subtype = + snd_installed_cards[sel].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe(hw_config)) + { + DEB(printk("Hardware probed OK\n")); + return 1; + } + DEB(printk("Failed to find hardware\n")); + snd_installed_cards[sel].enabled = 0; /* + * Mark as not detected + */ + return 0; + } + return 0; +} - if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1) - { - snd_installed_cards[sel].enabled = 0; - DEB (printk ("Failed to find driver\n")); - return 0; - } - DEB (printk ("Driver name '%s'\n", sound_drivers[drv].name)); - hw_config->card_subtype = - snd_installed_cards[sel].config.card_subtype = - sound_drivers[drv].card_subtype; +int +sndtable_init_card(int unit, struct address_info *hw_config) +{ + int i, n = num_sound_cards; - if (sound_drivers[drv].probe (hw_config)) - { - DEB (printk ("Hardware probed OK\n")); - return 1; - } + DEB(printk("sndtable_init_card(%d) entered\n", unit)); - DEB (printk ("Failed to find hardware\n")); - snd_installed_cards[sel].enabled = 0; /* - * Mark as not detected - */ - return 0; - } + if (!unit) + { + sndtable_init(); + return 1; + } + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + if (snd_installed_cards[i].card_type == unit) + { + int drv; - return 0; + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + snd_installed_cards[i].config.dma2 = hw_config->dma2; + snd_installed_cards[i].config.name = hw_config->name; + snd_installed_cards[i].config.always_detect = hw_config->always_detect; + snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; + + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + else + { + + DEB(printk("Located card - calling attach routine\n")); + sound_drivers[drv].attach(hw_config); + + DEB(printk("attach routine finished\n")); + } + start_services(); + return 1; + } + DEB(printk("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards)); + return 0; } +int +sndtable_get_cardcount(void) +{ + return num_audiodevs + num_mixers + num_synths + num_midis; +} int -sndtable_init_card (int unit, struct address_info *hw_config) +sndtable_identify_card(char *name) { - int i, n = num_sound_cards; + int i, n = num_sound_drivers; - DEB (printk ("sndtable_init_card(%d) entered\n", unit)); + if (name == NULL) + return 0; - if (!unit) - { - sndtable_init (); - return 1; - } + for (i = 0; i < n; i++) + if (sound_drivers[i].driver_id != NULL) + { + char *id = sound_drivers[i].driver_id; + int j; - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].card_type == unit) - { - int drv; + for (j = 0; j < 80 && name[j] == id[j]; j++) + if (id[j] == 0 && name[j] == 0) /* Match */ + return sound_drivers[i].card_type; + } + return 0; +} - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - snd_installed_cards[i].config.dma2 = hw_config->dma2; - snd_installed_cards[i].config.name = hw_config->name; - snd_installed_cards[i].config.always_detect = hw_config->always_detect; - snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; +void +sound_setup(char *str, int *ints) +{ + int i, n = num_sound_cards; - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - else - { + /* + * First disable all drivers + */ - DEB (printk ("Located card - calling attach routine\n")); - sound_drivers[drv].attach (hw_config); + for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + snd_installed_cards[i].enabled = 0; - DEB (printk ("attach routine finished\n")); - } - start_services (); - return 1; - } + if (ints[0] == 0 || ints[1] == 0) + return; + /* + * Then enable them one by time + */ - DEB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards)); - return 0; + for (i = 1; i <= ints[0]; i++) + { + int card_type, ioaddr, irq, dma, dma2, + ptr, j; + unsigned int val; + + val = (unsigned int) ints[i]; + + card_type = (val & 0x0ff00000) >> 20; + + if (card_type > 127) + { + /* + * Add any future extensions here + */ + return; + } + ioaddr = (val & 0x000fff00) >> 8; + irq = (val & 0x000000f0) >> 4; + dma = (val & 0x0000000f); + dma2 = (val & 0xf0000000) >> 28; + + ptr = -1; + for (j = 0; j < n && ptr == -1; j++) + if (snd_installed_cards[j].card_type == card_type && + !snd_installed_cards[j].enabled) /* + * Not already found + */ + ptr = j; + + if (ptr == -1) + printk("Sound: Invalid setup parameter 0x%08x\n", val); + else + { + snd_installed_cards[ptr].enabled = 1; + snd_installed_cards[ptr].config.io_base = ioaddr; + snd_installed_cards[ptr].config.irq = irq; + snd_installed_cards[ptr].config.dma = dma; + snd_installed_cards[ptr].config.dma2 = dma2; + snd_installed_cards[ptr].config.name = NULL; + snd_installed_cards[ptr].config.always_detect = 0; + snd_installed_cards[ptr].config.driver_use_1 = 0; + snd_installed_cards[ptr].config.driver_use_2 = 0; + snd_installed_cards[ptr].config.card_subtype = 0; + } + } } -int -sndtable_get_cardcount (void) + +struct address_info + * +sound_getconf(int card_type) { - return num_audiodevs + num_mixers + num_synths + num_midis; + int j, ptr; + int n = num_sound_cards; + + ptr = -1; + for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) + if (snd_installed_cards[j].card_type == card_type) + ptr = j; + + if (ptr == -1) + return (struct address_info *) NULL; + + return &snd_installed_cards[ptr].config; } + + int -sndtable_identify_card (char *name) +sound_install_audiodrv(int vers, + char *name, + struct audio_driver *driver, + int driver_size, + int flags, + unsigned int format_mask, + void *devc, + int dma1, + int dma2) { - int i, n = num_sound_drivers; +#ifdef CONFIG_AUDIO + struct audio_driver *d; + struct audio_operations *op; + int l, num; - if (name == NULL) - return 0; + if (vers != AUDIO_DRIVER_VERSION || + driver_size > sizeof(struct audio_driver)) + { + printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name); + return -(EINVAL); + } + num = sound_alloc_audiodev(); + + if (num == -1) + { + printk(KERN_ERR "sound: Too many audio drivers\n"); + return -(EBUSY); + } + d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver))); + sound_mem_sizes[sound_nblocks] = sizeof(struct audio_driver); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct audio_operations); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (d == NULL || op == NULL) + { + printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name); + sound_unload_audiodev(num); + return -(ENOMEM); + } + memset((char *) op, 0, sizeof(struct audio_operations)); + if (driver_size < sizeof(struct audio_driver)) + memset((char *) d, 0, sizeof(struct audio_driver)); + + memcpy((char *) d, (char *) driver, driver_size); + + op->d = d; + + l = strlen(name) + 1; + if (l > sizeof(op->name)) + l = sizeof(op->name); + strncpy(op->name, name, l); + op->name[l - 1] = 0; + op->flags = flags; + op->format_mask = format_mask; + op->devc = devc; - for (i = 0; i < n; i++) - if (sound_drivers[i].driver_id != NULL) - { - char *id = sound_drivers[i].driver_id; - int j; +/* + * Hardcoded defaults + */ + audio_devs[num] = op; - for (j = 0; j < 80 && name[j] == id[j]; j++) - if (id[j] == 0 && name[j] == 0) /* Match */ - return sound_drivers[i].card_type; - } + DMAbuf_init(num, dma1, dma2); - return 0; + audio_init_devices(); + return num; +#else + return -EINVAL; +#endif } -void -sound_setup (char *str, int *ints) +int +sound_install_mixer(int vers, + char *name, + struct mixer_operations *driver, + int driver_size, + void *devc) { - int i, n = num_sound_cards; - - /* - * First disable all drivers - */ + struct mixer_operations *op; + int l; - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - snd_installed_cards[i].enabled = 0; + int n = sound_alloc_mixerdev(); - if (ints[0] == 0 || ints[1] == 0) - return; - /* - * Then enable them one by time - */ + if (n == -1) + { + printk(KERN_ERR "Sound: Too many mixer drivers\n"); + return -(EBUSY); + } + if (vers != MIXER_DRIVER_VERSION || + driver_size > sizeof(struct mixer_operations)) + { + printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name); + return -(EINVAL); + } + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations); - for (i = 1; i <= ints[0]; i++) - { - int card_type, ioaddr, irq, dma, dma2, ptr, j; - unsigned int val; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (op == NULL) + { + printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); + return -(ENOMEM); + } + memset((char *) op, 0, sizeof(struct mixer_operations)); - val = (unsigned int) ints[i]; + memcpy((char *) op, (char *) driver, driver_size); - card_type = (val & 0x0ff00000) >> 20; + l = strlen(name) + 1; + if (l > sizeof(op->name)) + l = sizeof(op->name); + strncpy(op->name, name, l); + op->name[l - 1] = 0; + op->devc = devc; - if (card_type > 127) - { - /* - * Add any future extensions here - */ - return; - } + mixer_devs[n] = op; + return n; +} - ioaddr = (val & 0x000fff00) >> 8; - irq = (val & 0x000000f0) >> 4; - dma = (val & 0x0000000f); - dma2 = (val & 0xf0000000) >> 28; - - ptr = -1; - for (j = 0; j < n && ptr == -1; j++) - if (snd_installed_cards[j].card_type == card_type && - !snd_installed_cards[j].enabled) /* - * Not already found - */ - ptr = j; - - if (ptr == -1) - printk ("Sound: Invalid setup parameter 0x%08x\n", val); - else - { - snd_installed_cards[ptr].enabled = 1; - snd_installed_cards[ptr].config.io_base = ioaddr; - snd_installed_cards[ptr].config.irq = irq; - snd_installed_cards[ptr].config.dma = dma; - snd_installed_cards[ptr].config.dma2 = dma2; - snd_installed_cards[ptr].config.name = NULL; - snd_installed_cards[ptr].config.always_detect = 0; - snd_installed_cards[ptr].config.driver_use_1 = 0; - snd_installed_cards[ptr].config.driver_use_2 = 0; - snd_installed_cards[ptr].config.card_subtype = 0; - } - } +void +sound_unload_audiodev(int dev) +{ + if (dev != -1) + audio_devs[dev] = NULL; } +int +sound_alloc_audiodev(void) +{ + int i; -struct address_info - * -sound_getconf (int card_type) + for (i = 0; i < MAX_AUDIO_DEV; i++) + { + if (audio_devs[i] == NULL) + { + if (i >= num_audiodevs) + num_audiodevs = i + 1; + return i; + } + } + return -1; +} + +int +sound_alloc_mididev(void) { - int j, ptr; - int n = num_sound_cards; + int i; - ptr = -1; - for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) - if (snd_installed_cards[j].card_type == card_type) - ptr = j; + for (i = 0; i < MAX_MIDI_DEV; i++) + { + if (midi_devs[i] == NULL) + { + if (i >= num_midis) + num_midis++; + return i; + } + } + + return -1; +} - if (ptr == -1) - return (struct address_info *) NULL; +int +sound_alloc_synthdev(void) +{ + int i; - return &snd_installed_cards[ptr].config; + for (i = 0; i < MAX_SYNTH_DEV; i++) + { + if (synth_devs[i] == NULL) + { + if (i >= num_synths) + num_synths++; + return i; + } + } + return -1; } +int +sound_alloc_mixerdev(void) +{ + int i; + for (i = 0; i < MAX_MIXER_DEV; i++) + { + if (mixer_devs[i] == NULL) + { + if (i >= num_mixers) + num_mixers++; + return i; + } + } + return -1; +} int -sound_install_audiodrv (int vers, - char *name, - struct audio_driver *driver, - int driver_size, - int flags, - unsigned int format_mask, - void *devc, - int dma1, - int dma2) +sound_alloc_timerdev(void) { -#ifdef CONFIG_AUDIO - struct audio_driver *d; - struct audio_operations *op; - int l, num; - - if (num_audiodevs >= MAX_AUDIO_DEV) - { - printk ("Sound: Too many audio drivers\n"); - return -EIO; - } - - if (vers != AUDIO_DRIVER_VERSION || - driver_size > sizeof (struct audio_driver)) - { - printk ("Sound: Incompatible audio driver for %s\n", name); - return -EIO; - } - - - d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_driver))); - sound_mem_sizes[sound_nblocks] = sizeof (struct audio_driver); - - if (sound_nblocks < 1024) - sound_nblocks++;; - - op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct audio_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - if (d == NULL || op == NULL) - { - printk ("Sound: Can't allocate driver for (%s)\n", name); - return -ENOSPC; - } - - memset ((char *) op, 0, sizeof (struct audio_operations)); - if (driver_size < sizeof (struct audio_driver)) - memset ((char *) d, 0, sizeof (struct audio_driver)); - - memcpy ((char *) d, (char *) driver, driver_size); - - op->d = d; - - l = strlen (name) + 1; - if (l > sizeof (op->name)) - l = sizeof (op->name); - strncpy (op->name, name, l); - op->name[l - 1] = 0; - op->flags = flags; - op->format_mask = format_mask; - op->devc = devc; + int i; -/* - * Hardcoded defaults - */ - audio_devs[num_audiodevs] = op; - num = num_audiodevs++; + for (i = 0; i < MAX_TIMER_DEV; i++) + { + if (sound_timer_devs[i] == NULL) + { + if (i >= num_sound_timers) + num_sound_timers++; + return i; + } + } + return -1; +} - DMAbuf_init (num, dma1, dma2); +void +sound_unload_mixerdev(int dev) +{ + if (dev != -1) + mixer_devs[dev] = NULL; +} - audio_init_devices (); - return num; -#else - return -EINVAL; +void +sound_unload_mididev(int dev) +{ +#ifdef CONFIG_MIDI + if (dev != -1) + midi_devs[dev] = NULL; #endif } -int -sound_install_mixer (int vers, - char *name, - struct mixer_operations *driver, - int driver_size, - void *devc) -{ - struct mixer_operations *op; - int l; - - if (num_mixers >= MAX_MIXER_DEV) - { - printk ("Sound: Too many mixer drivers\n"); - return -EIO; - } - - if (vers != MIXER_DRIVER_VERSION || - driver_size > sizeof (struct mixer_operations)) - { - printk ("Sound: Incompatible mixer driver for %s\n", name); - return -EIO; - } - - - op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct mixer_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - if (op == NULL) - { - printk ("Sound: Can't allocate mixer driver for (%s)\n", name); - return -ENOSPC; - } - - memset ((char *) op, 0, sizeof (struct mixer_operations)); - - memcpy ((char *) op, (char *) driver, driver_size); - - l = strlen (name) + 1; - if (l > sizeof (op->name)) - l = sizeof (op->name); - strncpy (op->name, name, l); - op->name[l - 1] = 0; - op->devc = devc; +void +sound_unload_synthdev(int dev) +{ + if (dev != -1) + synth_devs[dev] = NULL; +} - mixer_devs[num_mixers] = op; - return num_mixers++; +void +sound_unload_timerdev(int dev) +{ + if (dev != -1) + sound_timer_devs[dev] = NULL; } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.1.66/linux/drivers/sound/dev_table.h Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/dev_table.h Sat Nov 29 10:33:20 1997 @@ -338,12 +338,13 @@ */ struct driver_info sound_drivers[] = { -#ifdef CONFIG_PSS +#if defined(CONFIG_PSS) && !defined(CONFIG_PSS_MODULE) {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif +#if defined(CONFIG_GUS) && !defined(CONFIG_GUS_MODULE) #ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif @@ -351,8 +352,9 @@ {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif +#endif -#ifdef CONFIG_MSS +#if defined(CONFIG_MSS) && !defined(CONFIG_MSS_MODULE) {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* Compaq Deskpro XL */ {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, @@ -365,30 +367,30 @@ {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif -#if defined(CONFIG_YM3812) +#if defined(CONFIG_YM3812) && !defined(CONFIG_YM3812_MODULE) {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, #endif -#ifdef CONFIG_PAS +#if defined(CONFIG_PAS) && !defined(CONFIG_PAS_MODULE) {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) && !defined(CONFIG_MPU401_MODULE) {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) && !defined(CONFIG_UART401_MODULE) {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", attach_uart401, probe_uart401, unload_uart401}, #endif -#if defined(CONFIG_MAUI) +#if defined(CONFIG_MAUI) && !defined(CONFIG_MAUI_MODULE) {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif -#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) && !defined(CONFIG_UART6850_MODULE) {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif -#ifdef CONFIG_SBDSP +#if defined(CONFIG_SBDSP) && !defined(CONFIG_SBDSP_MODULE) {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, @@ -408,13 +410,13 @@ {"OPL3SAMPU", 0, SNDCARD_OPL3SA1_MPU, "OPL3-SA MIDI", attach_opl3sa_mpu, probe_opl3sa_mpu, unload_opl3sa_mpu}, #endif -#ifdef CONFIG_TRIX +#if defined (CONFIG_TRIX) && !defined(CONFIG_TRIX_MODULE) {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif -#ifdef CONFIG_SOFTOSS +#if defined(CONFIG_SOFTOSS) && !defined(CONFIG_SOFTOSS_MODULE) {"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table", attach_softsyn_card, probe_softsyn, unload_softsyn}, #endif @@ -561,7 +563,7 @@ {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE}, #endif -#ifdef CONFIG_YM3812 +#if defined(CONFIG_YM3812) {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif {0, {0}, 0} @@ -638,4 +640,15 @@ int driver_size, void *devc); +void sound_unload_audiodev(int dev); +void sound_unload_mixerdev(int dev); +void sound_unload_mididev(int dev); +void sound_unload_synthdev(int dev); +void sound_unload_timerdev(int dev); +int sound_alloc_audiodev(void); +int sound_alloc_mixerdev(void); +int sound_alloc_timerdev(void); +int sound_alloc_synthdev(void); +int sound_alloc_mididev(void); #endif /* _DEV_TABLE_H_ */ + diff -u --recursive --new-file v2.1.66/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.66/linux/drivers/sound/dmabuf.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/dmabuf.c Sat Nov 29 10:33:20 1997 @@ -22,12 +22,12 @@ {NULL}; static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = { - {0}}; + {0}}; static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = {NULL}; static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = { - {0}}; + {0}}; static int ndmaps = 0; @@ -35,724 +35,700 @@ static struct dma_buffparms dmaps[MAX_DMAP] = { - {0}}; + {0}}; -static void dma_reset_output (int dev); -static void dma_reset_input (int dev); -static int local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); +static void dma_reset_output(int dev); +static void dma_reset_input(int dev); +static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode); static void -dma_init_buffers (int dev, struct dma_buffparms *dmap) +dma_init_buffers(int dev, struct dma_buffparms *dmap) { - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->bytes_in_use = dmap->buffsize; - - dmap->dma_mode = DMODE_NONE; - dmap->mapping_flags = 0; - dmap->neutral_byte = 0x80; - dmap->data_rate = 8000; - dmap->cfrag = -1; - dmap->closing = 0; - dmap->nbufs = 1; - dmap->flags = DMA_BUSY; /* Other flags off */ + dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + dmap->byte_counter = 0; + dmap->max_byte_counter = 8000 * 60 * 60; + dmap->bytes_in_use = dmap->buffsize; + + dmap->dma_mode = DMODE_NONE; + dmap->mapping_flags = 0; + dmap->neutral_byte = 0x80; + dmap->data_rate = 8000; + dmap->cfrag = -1; + dmap->closing = 0; + dmap->nbufs = 1; + dmap->flags = DMA_BUSY; /* Other flags off */ } static int -open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) +open_dmap(int dev, int mode, struct dma_buffparms *dmap, int chan) { - if (dmap->flags & DMA_BUSY) - return -EBUSY; + if (dmap->flags & DMA_BUSY) + return -EBUSY; - { - int err; + { + int err; + + if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0) + return err; + } + + if (dmap->raw_buf == NULL) + { + printk("Sound: DMA buffers not available\n"); + return -ENOSPC; /* Memory allocation failed during boot */ + } + if (sound_open_dma(chan, audio_devs[dev]->name)) + { + printk("Unable to grab(2) DMA%d for the audio driver\n", chan); + return -EBUSY; + } + dma_init_buffers(dev, dmap); + dmap->open_mode = mode; + dmap->subdivision = dmap->underrun_count = 0; + dmap->fragment_size = 0; + dmap->max_fragments = 65536; /* Just a large value */ + dmap->byte_counter = 0; + dmap->max_byte_counter = 8000 * 60 * 60; + dmap->applic_profile = APF_NORMAL; + dmap->needs_reorg = 1; + dmap->audio_callback = NULL; + dmap->callback_parm = 0; - if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0) - return err; - } - - if (dmap->raw_buf == NULL) - { - printk ("Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - - if (sound_open_dma (chan, audio_devs[dev]->name)) - { - printk ("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; - } - - dma_init_buffers (dev, dmap); - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->applic_profile = APF_NORMAL; - dmap->needs_reorg = 1; - dmap->audio_callback = NULL; - dmap->callback_parm = 0; - - - if (dmap->dma_mode & DMODE_OUTPUT) - { - out_sleep_flag[dev].opts = WK_NONE; - } - else - { - in_sleep_flag[dev].opts = WK_NONE; - } - return 0; + if (dmap->dma_mode & DMODE_OUTPUT) + { + out_sleep_flag[dev].opts = WK_NONE; + } else + { + in_sleep_flag[dev].opts = WK_NONE; + } + + return 0; } static void -close_dmap (int dev, struct dma_buffparms *dmap, int chan) +close_dmap(int dev, struct dma_buffparms *dmap, int chan) { - sound_close_dma (chan); + sound_close_dma(chan); - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; + if (dmap->flags & DMA_BUSY) + dmap->dma_mode = DMODE_NONE; + dmap->flags &= ~DMA_BUSY; - disable_dma (dmap->dma); + disable_dma(dmap->dma); } static unsigned int -default_set_bits (int dev, unsigned int bits) +default_set_bits(int dev, unsigned int bits) { - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits); + return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits); } static int -default_set_speed (int dev, int speed) +default_set_speed(int dev, int speed) { - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) & speed); + return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t) & speed); } static short -default_set_channels (int dev, short channels) +default_set_channels(int dev, short channels) { - int c = channels; + int c = channels; - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c); + return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c); } static void -check_driver (struct audio_driver *d) +check_driver(struct audio_driver *d) { - if (d->set_speed == NULL) - d->set_speed = default_set_speed; - if (d->set_bits == NULL) - d->set_bits = default_set_bits; - if (d->set_channels == NULL) - d->set_channels = default_set_channels; + if (d->set_speed == NULL) + d->set_speed = default_set_speed; + if (d->set_bits == NULL) + d->set_bits = default_set_bits; + if (d->set_channels == NULL) + d->set_channels = default_set_channels; } int -DMAbuf_open (int dev, int mode) +DMAbuf_open(int dev, int mode) { - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (dev >= num_audiodevs) - { - return -ENXIO; - } - - if (!audio_devs[dev]) - { - return -ENXIO; - } - - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; - } - - check_driver (audio_devs[dev]->d); - - if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) - return retval; - - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; - - if (dmap_in == dmap_out) - audio_devs[dev]->flags &= ~DMA_DUPLEX; - - if (mode & OPEN_WRITE) - { - if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) - { - audio_devs[dev]->d->close (dev); - return retval; - } - } + int retval; + struct dma_buffparms *dmap_in = NULL; + struct dma_buffparms *dmap_out = NULL; - audio_devs[dev]->enable_bits = mode; + if (dev >= num_audiodevs || audio_devs[dev] == NULL) + { + return -ENXIO; + } + if (!audio_devs[dev]) + { + return -ENXIO; + } + if (!(audio_devs[dev]->flags & DMA_DUPLEX)) + { + audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; + audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; + } + check_driver(audio_devs[dev]->d); - if (mode == OPEN_READ || (mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) - { - audio_devs[dev]->d->close (dev); + if ((retval = audio_devs[dev]->d->open(dev, mode)) < 0) + return retval; - if (mode & OPEN_WRITE) - { - close_dmap (dev, dmap_out, audio_devs[dev]->dmap_out->dma); - } + dmap_out = audio_devs[dev]->dmap_out; + dmap_in = audio_devs[dev]->dmap_in; - return retval; - } - } + if (dmap_in == dmap_out) + audio_devs[dev]->flags &= ~DMA_DUPLEX; - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; + if (mode & OPEN_WRITE) + { + if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) + { + audio_devs[dev]->d->close(dev); + return retval; + } + } + audio_devs[dev]->enable_bits = mode; - if (mode & OPEN_READ) - in_sleep_flag[dev].opts = WK_NONE; + if (mode == OPEN_READ || (mode != OPEN_WRITE && + audio_devs[dev]->flags & DMA_DUPLEX)) + { + if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) + { + audio_devs[dev]->d->close(dev); + + if (mode & OPEN_WRITE) + { + close_dmap(dev, dmap_out, audio_devs[dev]->dmap_out->dma); + } + return retval; + } + } + audio_devs[dev]->open_mode = mode; + audio_devs[dev]->go = 1; - if (mode & OPEN_WRITE) - out_sleep_flag[dev].opts = WK_NONE; + if (mode & OPEN_READ) + in_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->d->set_bits (dev, 8); - audio_devs[dev]->d->set_channels (dev, 1); - audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); + if (mode & OPEN_WRITE) + out_sleep_flag[dev].opts = WK_NONE; - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } + audio_devs[dev]->d->set_bits(dev, 8); + audio_devs[dev]->d->set_channels(dev, 1); + audio_devs[dev]->d->set_speed(dev, DSP_DEFAULT_SPEED); - return 0; + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + { + memset(audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + } + return 0; } void -DMAbuf_reset (int dev) +DMAbuf_reset(int dev) { - if (audio_devs[dev]->open_mode & OPEN_WRITE) - dma_reset_output (dev); + if (audio_devs[dev]->open_mode & OPEN_WRITE) + dma_reset_output(dev); - if (audio_devs[dev]->open_mode & OPEN_READ) - dma_reset_input (dev); + if (audio_devs[dev]->open_mode & OPEN_READ) + dma_reset_input(dev); } static void -dma_reset_output (int dev) +dma_reset_output(int dev) { - unsigned long flags; - int tmout; + unsigned long flags; + int tmout; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ - return; + if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ + return; /* * First wait until the current fragment has been played completely */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 5; /* Some safety distance */ + tmout += HZ / 5; /* Some safety distance */ - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - audio_devs[dev]->dmap_out->underrun_count = 0; - if (!(current->signal & ~current->blocked) - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { + audio_devs[dev]->dmap_out->underrun_count = 0; + if (!(current->signal & ~current->blocked) + && audio_devs[dev]->dmap_out->qlen + && audio_devs[dev]->dmap_out->underrun_count == 0) + { - { - unsigned long tlimit; + { + unsigned long tlimit; - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + } + audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* * Finally shut the device off */ - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_output) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_output (dev); - audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; - restore_flags (flags); - - clear_dma_ff (dmap->dma); - disable_dma (dmap->dma); - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0); - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + if (!(audio_devs[dev]->flags & DMA_DUPLEX) || + !audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->halt_io(dev); + else + audio_devs[dev]->d->halt_output(dev); + audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; + restore_flags(flags); + + clear_dma_ff(dmap->dma); + disable_dma(dmap->dma); + dmap->byte_counter = 0; + reorganize_buffers(dev, audio_devs[dev]->dmap_out, 0); + dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; } static void -dma_reset_input (int dev) +dma_reset_input(int dev) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - save_flags (flags); - cli (); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_input) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_input (dev); - audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; - restore_flags (flags); - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1); + save_flags(flags); + cli(); + if (!(audio_devs[dev]->flags & DMA_DUPLEX) || + !audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->halt_io(dev); + else + audio_devs[dev]->d->halt_input(dev); + audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; + restore_flags(flags); + + dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; + dmap->byte_counter = 0; + reorganize_buffers(dev, audio_devs[dev]->dmap_in, 1); } void -DMAbuf_launch_output (int dev, struct dma_buffparms *dmap) +DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) { - if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ - - dmap->dma_mode = DMODE_OUTPUT; + if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) + return; /* Don't start DMA yet */ - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - if (!(dmap->flags & DMA_STARTED)) - { - reorganize_buffers (dev, dmap, 0); - - if (audio_devs[dev]->d->prepare_for_output (dev, - dmap->fragment_size, dmap->nbufs)) - return; - - if (!(dmap->flags & DMA_NODMA)) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_WRITE); - } - dmap->flags |= DMA_STARTED; - } - if (dmap->counts[dmap->qhead] == 0) - dmap->counts[dmap->qhead] = dmap->fragment_size; + dmap->dma_mode = DMODE_OUTPUT; - dmap->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - dmap->flags |= DMA_ACTIVE; + if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) + { + if (!(dmap->flags & DMA_STARTED)) + { + reorganize_buffers(dev, dmap, 0); + + if (audio_devs[dev]->d->prepare_for_output(dev, + dmap->fragment_size, dmap->nbufs)) + return; + + if (!(dmap->flags & DMA_NODMA)) + { + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_WRITE); + } + dmap->flags |= DMA_STARTED; + } + if (dmap->counts[dmap->qhead] == 0) + dmap->counts[dmap->qhead] = dmap->fragment_size; + + dmap->dma_mode = DMODE_OUTPUT; + audio_devs[dev]->d->output_block(dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1); + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; } int -DMAbuf_sync (int dev) +DMAbuf_sync(int dev) { - unsigned long flags; - int tmout, n = 0; - - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { + unsigned long flags; + int tmout, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - ; - if (dmap->qlen > 0) - if (!(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output (dev, dmap); - ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - while (!(current->signal & ~current->blocked) - && n++ <= audio_devs[dev]->dmap_out->nbufs - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { + if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + return 0; + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) { - unsigned long tlimit; - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; - restore_flags (flags); - return audio_devs[dev]->dmap_out->qlen; - } - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - restore_flags (flags); - /* - * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait until the device has finished playing. - */ - - save_flags (flags); - cli (); - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - { - while (!((current->signal & ~current->blocked)) - && audio_devs[dev]->d->local_qlen (dev)) - { + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - { - unsigned long tlimit; + save_flags(flags); + cli(); - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - } - restore_flags (flags); - } - audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; - return audio_devs[dev]->dmap_out->qlen; + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 5; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + + ; + if (dmap->qlen > 0) + if (!(dmap->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, dmap); + ; + + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; + + audio_devs[dev]->dmap_out->underrun_count = 0; + while (!(current->signal & ~current->blocked) + && n++ <= audio_devs[dev]->dmap_out->nbufs + && audio_devs[dev]->dmap_out->qlen + && audio_devs[dev]->dmap_out->underrun_count == 0) + { + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) + { + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; + restore_flags(flags); + return audio_devs[dev]->dmap_out->qlen; + } + } + audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + restore_flags(flags); + /* + * Some devices such as GUS have huge amount of on board RAM for the + * audio data. We have to wait until the device has finished playing. + */ + + save_flags(flags); + cli(); + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ + { + while (!((current->signal & ~current->blocked)) + && audio_devs[dev]->d->local_qlen(dev)) + { + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + } + } + restore_flags(flags); + } + audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; + return audio_devs[dev]->dmap_out->qlen; } int -DMAbuf_release (int dev, int mode) +DMAbuf_release(int dev, int mode) { - unsigned long flags; + unsigned long flags; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->closing = 1; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->closing = 1; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) - if (!((current->signal & ~current->blocked)) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) - { - DMAbuf_sync (dev); - } - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } - - save_flags (flags); - cli (); - - DMAbuf_reset (dev); - audio_devs[dev]->d->close (dev); - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); - - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->open_mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); - audio_devs[dev]->open_mode = 0; - - restore_flags (flags); + if (audio_devs[dev]->open_mode & OPEN_WRITE) + audio_devs[dev]->dmap_out->closing = 1; + if (audio_devs[dev]->open_mode & OPEN_READ) + audio_devs[dev]->dmap_in->closing = 1; + + if (audio_devs[dev]->open_mode & OPEN_WRITE) + if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) + if (!((current->signal & ~current->blocked)) + && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) + { + DMAbuf_sync(dev); + } + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + { + memset(audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + } + save_flags(flags); + cli(); - return 0; -} + DMAbuf_reset(dev); + audio_devs[dev]->d->close(dev); -int -DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap) -{ - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) - return 0; + if (audio_devs[dev]->open_mode == OPEN_READ || + (audio_devs[dev]->open_mode != OPEN_WRITE && + audio_devs[dev]->flags & DMA_DUPLEX)) + close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); + audio_devs[dev]->open_mode = 0; - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ - { - DMAbuf_sync (dev); - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - if (!dmap->dma_mode) - { - int err; - - reorganize_buffers (dev, dmap, 1); - if ((err = audio_devs[dev]->d->prepare_for_input (dev, - dmap->fragment_size, dmap->nbufs)) < 0) - { - return err; - } - dmap->dma_mode = DMODE_INPUT; - } + restore_flags(flags); - if (!(dmap->flags & DMA_ACTIVE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - return 0; + return 0; } int -DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) +DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) { - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EIO; - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - save_flags (flags); - cli (); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (1)\n"); - restore_flags (flags); - return -EINVAL; - } - else - while (dmap->qlen <= 0 && n++ < 10) - { - int tmout; + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || - !audio_devs[dev]->go) - { - restore_flags (flags); - return -EAGAIN; - } + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) + return 0; - if ((err = DMAbuf_activate_recording (dev, dmap)) < 0) + if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ { - restore_flags (flags); - return err; + DMAbuf_sync(dev); + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; } - - /* Wait for the next block */ - - if (dontblock) + if (!dmap->dma_mode) { - restore_flags (flags); - return -EAGAIN; - } + int err; - if (!audio_devs[dev]->go) - tmout = 0; - else + reorganize_buffers(dev, dmap, 1); + if ((err = audio_devs[dev]->d->prepare_for_input(dev, + dmap->fragment_size, dmap->nbufs)) < 0) + { + return err; + } + dmap->dma_mode = DMODE_INPUT; + } + if (!(dmap->flags & DMA_ACTIVE)) { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_READ); + audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 0); + dmap->flags |= DMA_ACTIVE; + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); } + return 0; +} +int +DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) +{ + unsigned long flags; + int err = 0, n = 0; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EIO; + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + + save_flags(flags); + cli(); + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + { + printk("Sound: Can't read from mmapped device (1)\n"); + restore_flags(flags); + return -EINVAL; + } else + while (dmap->qlen <= 0 && n++ < 10) + { + int tmout; - { - unsigned long tlimit; + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || + !audio_devs[dev]->go) + { + restore_flags(flags); + return -EAGAIN; + } + if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) + { + restore_flags(flags); + return err; + } + /* Wait for the next block */ + + if (dontblock) + { + restore_flags(flags); + return -EAGAIN; + } + if (!audio_devs[dev]->go) + tmout = 0; + else + { + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 5; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + } + + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + in_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&in_sleeper[dev]); + if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + in_sleep_flag[dev].opts |= WK_TIMEOUT; + } + in_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) + { + err = -EIO; + printk("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); + dma_reset_input(dev); + ; + } else + err = -EINTR; + } + restore_flags(flags); - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; - } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) + if (dmap->qlen <= 0) { - err = -EIO; - printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input (dev); - ; + if (err == 0) + err = -EINTR; + return err; } - else - err = -EINTR; - } - restore_flags (flags); - - if (dmap->qlen <= 0) - { - if (err == 0) - err = -EINTR; - return err; - } + *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; + *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; + return dmap->qhead; } int -DMAbuf_rmchars (int dev, int buff_no, int c) +DMAbuf_rmchars(int dev, int buff_no, int c) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - int p = dmap->counts[dmap->qhead] + c; + int p = dmap->counts[dmap->qhead] + c; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; - } - else if (dmap->qlen <= 0) - return -EIO; - else if (p >= dmap->fragment_size) - { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } - else - dmap->counts[dmap->qhead] = p; + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + printk("Sound: Can't read from mmapped device (2)\n"); + return -EINVAL; + } else if (dmap->qlen <= 0) + return -EIO; + else if (p >= dmap->fragment_size) + { /* This buffer is completely empty */ + dmap->counts[dmap->qhead] = 0; + dmap->qlen--; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + } else + dmap->counts[dmap->qhead] = p; - return 0; + return 0; } int -DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction) +DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction) { /* * Try to approximate the active byte position of the DMA pointer within the * buffer area as well as possible. */ - int pos; - unsigned long flags; - - save_flags (flags); - cli (); - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else - { - int chan = dmap->dma; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = get_dma_residue (chan); - pos = dmap->bytes_in_use - pos; + int pos; + unsigned long flags; - if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) - if (direction == DMODE_OUTPUT) - { - if (dmap->qhead == 0) - if (pos > dmap->fragment_size) + save_flags(flags); + cli(); + if (!(dmap->flags & DMA_ACTIVE)) pos = 0; - } else { - if (dmap->qtail == 0) - if (pos > dmap->fragment_size) - pos = 0; - } + int chan = dmap->dma; - if (pos < 0) - pos = 0; - if (pos >= dmap->bytes_in_use) - pos = 0; - enable_dma (dmap->dma); - } - restore_flags (flags); - /* printk( "%04x ", pos); */ + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = get_dma_residue(chan); + pos = dmap->bytes_in_use - pos; + + if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) + if (direction == DMODE_OUTPUT) + { + if (dmap->qhead == 0) + if (pos > dmap->fragment_size) + pos = 0; + } else + { + if (dmap->qtail == 0) + if (pos > dmap->fragment_size) + pos = 0; + } + if (pos < 0) + pos = 0; + if (pos >= dmap->bytes_in_use) + pos = 0; + enable_dma(dmap->dma); + } + restore_flags(flags); + /* printk( "%04x ", pos); */ - return pos; + return pos; } /* @@ -760,839 +736,802 @@ * one or more audio devices at desired moment. */ static void -DMAbuf_start_device (int dev) +DMAbuf_start_device(int dev) { - if (audio_devs[dev]->open_mode != 0) - if (!audio_devs[dev]->go) - { - /* OK to start the device */ - audio_devs[dev]->go = 1; + if (audio_devs[dev]->open_mode != 0) + if (!audio_devs[dev]->go) + { + /* OK to start the device */ + audio_devs[dev]->go = 1; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } } void -DMAbuf_start_devices (unsigned int devmask) +DMAbuf_start_devices(unsigned int devmask) { - int dev; + int dev; - for (dev = 0; dev < num_audiodevs; dev++) - if (devmask & (1 << dev)) - DMAbuf_start_device (dev); + for (dev = 0; dev < num_audiodevs; dev++) + if ((devmask & (1 << dev)) && audio_devs[dev] != NULL) + DMAbuf_start_device(dev); } int -DMAbuf_space_in_queue (int dev) +DMAbuf_space_in_queue(int dev) { - int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int len, max, tmp; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + int lim = dmap->nbufs; + - int lim = dmap->nbufs; + if (lim < 2) + lim = 2; + if (dmap->qlen >= lim) /* No space at all */ + return 0; - if (lim < 2) - lim = 2; - - if (dmap->qlen >= lim) /* No space at all */ - return 0; - - /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ - - max = dmap->max_fragments; - if (max > lim) - max = lim; - len = dmap->qlen; - - if (audio_devs[dev]->d->local_qlen) - { - tmp = audio_devs[dev]->d->local_qlen (dev); - if (tmp && len) - tmp--; /* - * This buffer has been counted twice - */ - len += tmp; - } - if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ - len = len + 1; - - if (len >= max) - return 0; - return max - len; + /* + * Verify that there are no more pending buffers than the limit + * defined by the process. + */ + + max = dmap->max_fragments; + if (max > lim) + max = lim; + len = dmap->qlen; + + if (audio_devs[dev]->d->local_qlen) + { + tmp = audio_devs[dev]->d->local_qlen(dev); + if (tmp && len) + tmp--; /* + * This buffer has been counted twice + */ + len += tmp; + } + if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ + len = len + 1; + + if (len >= max) + return 0; + return max - len; } static int -output_sleep (int dev, int dontblock) +output_sleep(int dev, int dontblock) { - int tmout; - int err = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dontblock) - { - return -EAGAIN; - } - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - { - return -EAGAIN; - } - - /* - * Wait for free space - */ - if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - if ((current->signal & ~current->blocked)) - return -EIO; - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - ; - dma_reset_output (dev); - } - else if ((current->signal & ~current->blocked)) - { - err = -EINTR; - } + int tmout; + int err = 0; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (dontblock) + { + return -EAGAIN; + } + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + { + return -EAGAIN; + } + /* + * Wait for free space + */ + if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) + tmout = 0; + else + { + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; + + tmout += HZ / 5; /* Some safety distance */ + + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + } + + if ((current->signal & ~current->blocked)) + return -EIO; - return err; + + { + unsigned long tlimit; + + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + out_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&out_sleeper[dev]); + if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + out_sleep_flag[dev].opts |= WK_TIMEOUT; + } + out_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) + { + printk("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); + ; + dma_reset_output(dev); + } else if ((current->signal & ~current->blocked)) + { + err = -EINTR; + } + return err; } static int -find_output_space (int dev, char **buf, int *size) +find_output_space(int dev, char **buf, int *size) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - unsigned long active_offs; - long len, offs; - int maxfrags; - int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - - *buf = dmap->raw_buf; - - if (!(maxfrags = DMAbuf_space_in_queue (dev)) && !occupied_bytes) - { - return 0; - } + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long flags; + unsigned long active_offs; + long len, offs; + int maxfrags; + int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - save_flags (flags); - cli (); + *buf = dmap->raw_buf; + + if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) + { + return 0; + } + save_flags(flags); + cli(); #ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; + active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; #else - active_offs = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - /* Check for pointer wrapping situation */ - if (active_offs < 0 || active_offs >= dmap->bytes_in_use) - active_offs = 0; - active_offs += dmap->byte_counter; + active_offs = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT); + /* Check for pointer wrapping situation */ + if (active_offs < 0 || active_offs >= dmap->bytes_in_use) + active_offs = 0; + active_offs += dmap->byte_counter; #endif - offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; - if (offs < 0 || offs >= dmap->bytes_in_use) - { - printk ("OSS: Got unexpected offs %ld. Giving up.\n", offs); - printk ("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); - return 0; - } - *buf = dmap->raw_buf + offs; - - len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - - if ((offs + len) > dmap->bytes_in_use) - { - len = dmap->bytes_in_use - offs; - } - - if (len < 0) - { - restore_flags (flags); - return 0; - } - - if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) - { - len = (maxfrags * dmap->fragment_size) - occupied_bytes; - } + offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; + if (offs < 0 || offs >= dmap->bytes_in_use) + { + printk("OSS: Got unexpected offs %ld. Giving up.\n", offs); + printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); + return 0; + } + *buf = dmap->raw_buf + offs; - *size = len & ~3; + len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - restore_flags (flags); - return (len > 0); + if ((offs + len) > dmap->bytes_in_use) + { + len = dmap->bytes_in_use - offs; + } + if (len < 0) + { + restore_flags(flags); + return 0; + } + if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) + { + len = (maxfrags * dmap->fragment_size) - occupied_bytes; + } + *size = len & ~3; + + restore_flags(flags); + return (len > 0); } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) +DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) { - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; - } - - if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ - { - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - dmap->dma_mode = DMODE_OUTPUT; - - save_flags (flags); - cli (); - - while (find_output_space (dev, buf, size) <= 0) - { - if ((err = output_sleep (dev, dontblock)) < 0) - { - restore_flags (flags); - return err; - } - } + unsigned long flags; + int err = -EIO; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + printk("Sound: Can't write to mmapped device (3)\n"); + return -EINVAL; + } + if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ + { + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; + } + dmap->dma_mode = DMODE_OUTPUT; + + save_flags(flags); + cli(); + + while (find_output_space(dev, buf, size) <= 0) + { + if ((err = output_sleep(dev, dontblock)) < 0) + { + restore_flags(flags); + return err; + } + } - restore_flags (flags); + restore_flags(flags); - return 0; + return 0; } int -DMAbuf_move_wrpointer (int dev, int l) +DMAbuf_move_wrpointer(int dev, int l) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long ptr = (dmap->user_counter / dmap->fragment_size) - * dmap->fragment_size; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long ptr = (dmap->user_counter / dmap->fragment_size) + * dmap->fragment_size; - unsigned long end_ptr, p; - int post = (dmap->flags & DMA_POST); + unsigned long end_ptr, p; + int post = (dmap->flags & DMA_POST); - ; + ; - dmap->flags &= ~DMA_POST; + dmap->flags &= ~DMA_POST; - dmap->cfrag = -1; + dmap->cfrag = -1; - dmap->user_counter += l; - dmap->flags |= DMA_DIRTY; + dmap->user_counter += l; + dmap->flags |= DMA_DIRTY; - if (dmap->user_counter >= dmap->max_byte_counter) - { /* Wrap the byte counters */ - long decr = dmap->user_counter; + if (dmap->user_counter >= dmap->max_byte_counter) + { /* Wrap the byte counters */ + long decr = dmap->user_counter; - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->user_counter; - dmap->byte_counter -= decr; - } - - end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; + dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->user_counter; + dmap->byte_counter -= decr; + } + end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - p = (dmap->user_counter - 1) % dmap->bytes_in_use; - dmap->neutral_byte = dmap->raw_buf[p]; + p = (dmap->user_counter - 1) % dmap->bytes_in_use; + dmap->neutral_byte = dmap->raw_buf[p]; - /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) - { - dmap->counts[dmap->qtail] = dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - ptr += dmap->fragment_size; - } + /* Update the fragment based bookkeeping too */ + while (ptr < end_ptr) + { + dmap->counts[dmap->qtail] = dmap->fragment_size; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + dmap->qlen++; + ptr += dmap->fragment_size; + } - dmap->counts[dmap->qtail] = dmap->user_counter - ptr; + dmap->counts[dmap->qtail] = dmap->user_counter - ptr; /* * Let the low level driver to perform some postprocessing to * the written data. */ - if (audio_devs[dev]->d->postprocess_write) - audio_devs[dev]->d->postprocess_write (dev); + if (audio_devs[dev]->d->postprocess_write) + audio_devs[dev]->d->postprocess_write(dev); - if (!(dmap->flags & DMA_ACTIVE)) - if (dmap->qlen > 1 || - (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - { - DMAbuf_launch_output (dev, dmap); - } - - ; - return 0; + if (!(dmap->flags & DMA_ACTIVE)) + if (dmap->qlen > 1 || + (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) + { + DMAbuf_launch_output(dev, dmap); + }; + return 0; } int -DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) +DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; + int chan; + struct dma_buffparms *dmap; - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(1) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } + if (dma_mode == DMA_MODE_WRITE) + { + chan = audio_devs[dev]->dmap_out->dma; + dmap = audio_devs[dev]->dmap_out; + } else + { + chan = audio_devs[dev]->dmap_in->dma; + dmap = audio_devs[dev]->dmap_in; + } - if (chan < 0) - return 0; + if (dmap->raw_buf == NULL) + { + printk("sound: DMA buffer(1) == NULL\n"); + printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); + return 0; + } + if (chan < 0) + return 0; - sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0); + sound_start_dma(dev, dmap, chan, physaddr, count, dma_mode, 0); - return count; + return count; } static int -local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) +local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; + int chan; + struct dma_buffparms *dmap; - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(2) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (dmap->flags & DMA_NODMA) - { - return 1; - } + if (dma_mode == DMA_MODE_WRITE) + { + chan = audio_devs[dev]->dmap_out->dma; + dmap = audio_devs[dev]->dmap_out; + } else + { + chan = audio_devs[dev]->dmap_in->dma; + dmap = audio_devs[dev]->dmap_in; + } - if (chan < 0) - return 0; + if (dmap->raw_buf == NULL) + { + printk("sound: DMA buffer(2) == NULL\n"); + printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); + return 0; + } + if (dmap->flags & DMA_NODMA) + { + return 1; + } + if (chan < 0) + return 0; - sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); - dmap->flags |= DMA_STARTED; + sound_start_dma(dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); + dmap->flags |= DMA_STARTED; - return count; + return count; } static void -finish_output_interrupt (int dev, struct dma_buffparms *dmap) +finish_output_interrupt(int dev, struct dma_buffparms *dmap) { - unsigned long flags; + unsigned long flags; - if (dmap->audio_callback != NULL) - dmap->audio_callback (dev, dmap->callback_parm); + if (dmap->audio_callback != NULL) + dmap->audio_callback(dev, dmap->callback_parm); - save_flags (flags); - cli (); - if ((out_sleep_flag[dev].opts & WK_SLEEP)) - { - { - out_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&out_sleeper[dev]); - }; - } - restore_flags (flags); + save_flags(flags); + cli(); + if ((out_sleep_flag[dev].opts & WK_SLEEP)) + { + { + out_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&out_sleeper[dev]); + }; + } + restore_flags(flags); } static void -do_outputintr (int dev, int dummy) +do_outputintr(int dev, int dummy) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - int this_fragment; + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int this_fragment; #ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_out->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + if (audio_devs[dev]->dmap_out->dma >= 0) + sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); #endif - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ - { - /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - - DMAbuf_launch_output (dev, dmap); - finish_output_interrupt (dev, dmap); - return; - } - - save_flags (flags); - cli (); - - dmap->qlen--; - this_fragment = dmap->qhead; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; + if (dmap->raw_buf == NULL) + { + printk("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ + { + /* mmapped access */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + if (dmap->qhead == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + dmap->qlen++; /* Yes increment it (don't decrement) */ + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + dmap->flags &= ~DMA_ACTIVE; + dmap->counts[dmap->qhead] = dmap->fragment_size; + + DMAbuf_launch_output(dev, dmap); + finish_output_interrupt(dev, dmap); + return; + } + save_flags(flags); + cli(); - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } + dmap->qlen--; + this_fragment = dmap->qhead; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; + if (dmap->qhead == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + dmap->flags &= ~DMA_ACTIVE; - while (dmap->qlen < 0) - { - dmap->underrun_count++; + while (dmap->qlen < 0) + { + dmap->underrun_count++; - dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) - { - dmap->flags &= ~DMA_DIRTY; - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->buffsize); - } - dmap->user_counter += dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } + dmap->qlen++; + if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) + { + dmap->flags &= ~DMA_DIRTY; + memset(audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->buffsize); + } + dmap->user_counter += dmap->fragment_size; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } - if (dmap->qlen > 0) - DMAbuf_launch_output (dev, dmap); + if (dmap->qlen > 0) + DMAbuf_launch_output(dev, dmap); - restore_flags (flags); - finish_output_interrupt (dev, dmap); + restore_flags(flags); + finish_output_interrupt(dev, dmap); } void -DMAbuf_outputintr (int dev, int notify_only) +DMAbuf_outputintr(int dev, int notify_only) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; + if (!(dmap->flags & DMA_NODMA)) + { + int chan = dmap->dma, pos, n; - n = 0; - while (dmap->qhead != pos && n++ < dmap->nbufs) - { - do_outputintr (dev, notify_only); - } - } - else - do_outputintr (dev, notify_only); - restore_flags (flags); + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue(chan); + enable_dma(dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qhead != pos && n++ < dmap->nbufs) + { + do_outputintr(dev, notify_only); + } + } else + do_outputintr(dev, notify_only); + restore_flags(flags); } static void -do_inputintr (int dev) +do_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; #ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_in->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); + if (audio_devs[dev]->dmap_in->dma >= 0) + sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); #endif - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - } - else if (dmap->qlen >= (dmap->nbufs - 1)) - { - printk ("Sound: Recording overrun\n"); - dmap->underrun_count++; - - /* Just throw away the oldest fragment but keep the engine running */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) - { - dmap->qlen++; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - } + if (dmap->raw_buf == NULL) + { + printk("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + dmap->qlen++; + + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + { + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_READ); + audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1); + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; + } else if (dmap->qlen >= (dmap->nbufs - 1)) + { + printk("Sound: Recording overrun\n"); + dmap->underrun_count++; - if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + /* Just throw away the oldest fragment but keep the engine running */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) + { + dmap->qlen++; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) /* Wrapped */ + { + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ + { + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + } + if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) + { + local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_READ); + audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - - save_flags (flags); - cli (); - if (dmap->qlen > 0) - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { - { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&in_sleeper[dev]); - }; - } - restore_flags (flags); + dmap->fragment_size, 1); + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, + audio_devs[dev]->enable_bits * audio_devs[dev]->go); + } + dmap->flags |= DMA_ACTIVE; + + save_flags(flags); + cli(); + if (dmap->qlen > 0) + if ((in_sleep_flag[dev].opts & WK_SLEEP)) + { + { + in_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&in_sleeper[dev]); + }; + } + restore_flags(flags); } void -DMAbuf_inputintr (int dev) +DMAbuf_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - - save_flags (flags); - cli (); + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; + save_flags(flags); + cli(); - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; + if (!(dmap->flags & DMA_NODMA)) + { + int chan = dmap->dma, pos, n; - n = 0; - while (dmap->qtail != pos && ++n < dmap->nbufs) - { - do_inputintr (dev); - } - } - else - do_inputintr (dev); - restore_flags (flags); + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue(chan); + enable_dma(dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qtail != pos && ++n < dmap->nbufs) + { + do_inputintr(dev); + } + } else + do_inputintr(dev); + restore_flags(flags); } int -DMAbuf_open_dma (int dev) +DMAbuf_open_dma(int dev) { /* * NOTE! This routine opens only the primary DMA channel (output). */ - int chan = audio_devs[dev]->dmap_out->dma; - int err; + int chan = audio_devs[dev]->dmap_out->dma; + int err; - if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) - { - return -EBUSY; - } - dma_init_buffers (dev, audio_devs[dev]->dmap_out); - out_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; - - if (chan >= 0) - { - unsigned long flags; - - save_flags (flags); - cli (); - disable_dma (audio_devs[dev]->dmap_out->dma); - clear_dma_ff (chan); - restore_flags (flags); - } + if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) + { + return -EBUSY; + } + dma_init_buffers(dev, audio_devs[dev]->dmap_out); + out_sleep_flag[dev].opts = WK_NONE; + audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; + audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; - return 0; + if (chan >= 0) + { + unsigned long flags; + + save_flags(flags); + cli(); + disable_dma(audio_devs[dev]->dmap_out->dma); + clear_dma_ff(chan); + restore_flags(flags); + } + return 0; } void -DMAbuf_close_dma (int dev) +DMAbuf_close_dma(int dev) { - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); } void -DMAbuf_init (int dev, int dma1, int dma2) +DMAbuf_init(int dev, int dma1, int dma2) { - /* - * NOTE! This routine could be called several times. - */ - - if (audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) - panic ("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; + /* + * NOTE! This routine could be called several times. + */ - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } - else - { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_out->dma = dma1; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_in->dma = dma2; - } - } - } + if (audio_devs[dev] && audio_devs[dev]->dmap_out == NULL) + { + if (audio_devs[dev]->d == NULL) + panic("OSS: audio_devs[%d]->d == NULL\n", dev); + + if (audio_devs[dev]->parent_dev) + { /* Use DMA map of the parent dev */ + int parent = audio_devs[dev]->parent_dev - 1; + + audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; + audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; + } else + { + audio_devs[dev]->dmap_out = + audio_devs[dev]->dmap_in = + &dmaps[ndmaps++]; + audio_devs[dev]->dmap_out->dma = dma1; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { + audio_devs[dev]->dmap_in = + &dmaps[ndmaps++]; + audio_devs[dev]->dmap_in->dma = dma2; + } + } + } } int -DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) +DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) { - struct dma_buffparms *dmap; - unsigned long flags; - - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - dmap = audio_devs[dev]->dmap_in; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); + struct dma_buffparms *dmap; + unsigned long flags; - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode != DMODE_INPUT) - { - if (dmap->dma_mode == DMODE_NONE && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && - audio_devs[dev]->go) - { - unsigned long flags; - - save_flags (flags); - cli (); - DMAbuf_activate_recording (dev, dmap); - restore_flags (flags); - } - return 0; - } - - if (!dmap->qlen) - { - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; + switch (sel_type) + { + case SEL_IN: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; + + dmap = audio_devs[dev]->dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags(flags); + cli(); + + in_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&in_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + if (dmap->dma_mode != DMODE_INPUT) + { + if (dmap->dma_mode == DMODE_NONE && + audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && + !dmap->qlen && + audio_devs[dev]->go) + { + unsigned long flags; + + save_flags(flags); + cli(); + DMAbuf_activate_recording(dev, dmap); + restore_flags(flags); + } + return 0; + } + if (!dmap->qlen) + { + save_flags(flags); + cli(); + + in_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&in_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + return 1; + break; + + case SEL_OUT: + dmap = audio_devs[dev]->dmap_out; + + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + { + if (dmap->qlen) + return 1; + + save_flags(flags); + cli(); + + out_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&out_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + if (dmap->dma_mode == DMODE_INPUT) + { + return 0; + } + if (dmap->dma_mode == DMODE_NONE) + { + return 1; + } + if (!DMAbuf_space_in_queue(dev)) + { + save_flags(flags); + cli(); + + out_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&out_sleeper[dev], wait); + restore_flags(flags); + return 0; + } + return 1; + break; - case SEL_OUT: - dmap = audio_devs[dev]->dmap_out; + case SEL_EX: + return 0; + } - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return 0; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode == DMODE_INPUT) - { - return 0; - } - - if (dmap->dma_mode == DMODE_NONE) - { - return 1; - } - - if (!DMAbuf_space_in_queue (dev)) - { - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } - - return 0; } void @@ -1600,10 +1539,12 @@ { /* This routine is called when driver is being unloaded */ #ifdef RUNTIME_DMA_ALLOC - sound_free_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + sound_free_dmap (dev, audio_devs[dev]->dmap_out, + audio_devs[dev]->dmap_out->dma); - if (audio_devs[dev]->flags & DMA_DUPLEX) - sound_free_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); + if (audio_devs[dev]->flags & DMA_DUPLEX) + sound_free_dmap (dev, audio_devs[dev]->dmap_in, + audio_devs[dev]->dmap_in->dma); #endif } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.1.66/linux/drivers/sound/dmasound.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/dmasound.c Sat Nov 29 10:33:20 1997 @@ -3,76 +3,76 @@ /* -OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k + OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k -(c) 1995 by Michael Schlueter & Michael Marte + (c) 1995 by Michael Schlueter & Michael Marte -Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS -interface and the u-law to signed byte conversion. + Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS + interface and the u-law to signed byte conversion. -Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, -/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like -to thank: -Michael Schlueter for initial ideas and documentation on the MFP and -the DMA sound hardware. -Therapy? for their CD 'Troublegum' which really made me rock. - -/dev/sndstat is based on code by Hannu Savolainen, the author of the -VoxWare family of drivers. - -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. - -History: -1995/8/25 first release - -1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming - and several race conditions - -1995/9/14 ++roman: After some discussion with Michael Schlueter, revised - the interrupt disabling - Slightly speeded up U8->S8 translation by using long - operations where possible - Added 4:3 interpolation for /dev/audio - -1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio - converting to play at 12517Hz instead of 6258Hz. - -1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program - the DMA for another frame while there's still one - running. This allows the IRQ response to be - arbitrarily delayed and playing will still continue. - -1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for - Falcon audio (the Falcon doesn't raise an IRQ at the - end of a frame, but at the beginning instead!). uses - 'if (codec_dma)' in lots of places to simply switch - between Falcon and TT code. - -1995/11/06 ++TeSche: started introducing a hardware abstraction scheme - (may perhaps also serve for Amigas?), can now play - samples at almost all frequencies by means of a more - generalized expand routine, takes a good deal of care - to cut data only at sample sizes, buffer size is now - a kernel runtime option, implemented fsync() & several - minor improvements - ++Guenther: useful hints and bug fixes, cross-checked it for - Falcons - -1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. - Unification to drivers/sound/dmasound.c. - -1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. - -1996/6/13 ++topi: fixed things that were broken (mainly the amiga - 14-bit routines), /dev/sndstat shows now the real - hardware frequency, the lowpass filter is disabled - by default now. + Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, + /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like + to thank: + Michael Schlueter for initial ideas and documentation on the MFP and + the DMA sound hardware. + Therapy? for their CD 'Troublegum' which really made me rock. + + /dev/sndstat is based on code by Hannu Savolainen, the author of the + VoxWare family of drivers. + + 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. + + History: + 1995/8/25 first release + + 1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming + and several race conditions + + 1995/9/14 ++roman: After some discussion with Michael Schlueter, revised + the interrupt disabling + Slightly speeded up U8->S8 translation by using long + operations where possible + Added 4:3 interpolation for /dev/audio + + 1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio + converting to play at 12517Hz instead of 6258Hz. + + 1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program + the DMA for another frame while there's still one + running. This allows the IRQ response to be + arbitrarily delayed and playing will still continue. + + 1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for + Falcon audio (the Falcon doesn't raise an IRQ at the + end of a frame, but at the beginning instead!). uses + 'if (codec_dma)' in lots of places to simply switch + between Falcon and TT code. + + 1995/11/06 ++TeSche: started introducing a hardware abstraction scheme + (may perhaps also serve for Amigas?), can now play + samples at almost all frequencies by means of a more + generalized expand routine, takes a good deal of care + to cut data only at sample sizes, buffer size is now + a kernel runtime option, implemented fsync() & several + minor improvements + ++Guenther: useful hints and bug fixes, cross-checked it for + Falcons + + 1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. + Unification to drivers/sound/dmasound.c. + + 1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. + + 1996/6/13 ++topi: fixed things that were broken (mainly the amiga + 14-bit routines), /dev/sndstat shows now the real + hardware frequency, the lowpass filter is disabled + by default now. -1996/9/25 ++geert: modularization + 1996/9/25 ++geert: modularization -*/ + */ #include @@ -94,53 +94,55 @@ #ifdef CONFIG_ATARI #include #include -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA #include #include -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ #include "dmasound.h" #include #ifdef MODULE -static int chrdev_registered = 0; -static int irq_installed = 0; -#endif /* MODULE */ -static char **sound_buffers = NULL; +static int chrdev_registered = 0; +static int irq_installed = 0; + +#endif /* MODULE */ +static char **sound_buffers = NULL; #ifdef CONFIG_ATARI -extern void atari_microwire_cmd(int cmd); -#endif /* CONFIG_ATARI */ +extern void atari_microwire_cmd(int cmd); + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA /* - * The minimum period for audio depends on htotal (for OCS/ECS/AGA) - * (Imported from arch/m68k/amiga/amisound.c) + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * (Imported from arch/m68k/amiga/amisound.c) */ extern volatile u_short amiga_audio_min_period; /* - * amiga_mksound() should be able to restore the period after beeping - * (Imported from arch/m68k/amiga/amisound.c) + * amiga_mksound() should be able to restore the period after beeping + * (Imported from arch/m68k/amiga/amisound.c) */ -extern u_short amiga_audio_period; +extern u_short amiga_audio_period; /* - * Audio DMA masks + * Audio DMA masks */ #define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3) #define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1) #define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3) -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Some declarations *******************************************************/ @@ -155,7 +157,7 @@ #define MIN_BUFSIZE 4 #define MAX_BUFSIZE 128 /* Limit for Amiga */ -static int catchRadius = 0, numBufs = 4, bufSize = 32; +static int catchRadius = 0, numBufs = 4, bufSize = 32; #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -175,76 +177,78 @@ /* 8 bit mu-law */ -static char ulaw2dma8[] = { - -126, -122, -118, -114, -110, -106, -102, -98, - -94, -90, -86, -82, -78, -74, -70, -66, - -63, -61, -59, -57, -55, -53, -51, -49, - -47, -45, -43, -41, -39, -37, -35, -33, - -31, -30, -29, -28, -27, -26, -25, -24, - -23, -22, -21, -20, -19, -18, -17, -16, - -16, -15, -15, -14, -14, -13, -13, -12, - -12, -11, -11, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -7, -6, -6, - -6, -6, -5, -5, -5, -5, -4, -4, - -4, -4, -4, -4, -3, -3, -3, -3, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 0, - 125, 121, 117, 113, 109, 105, 101, 97, - 93, 89, 85, 81, 77, 73, 69, 65, - 62, 60, 58, 56, 54, 52, 50, 48, - 46, 44, 42, 40, 38, 36, 34, 32, - 30, 29, 28, 27, 26, 25, 24, 23, - 22, 21, 20, 19, 18, 17, 16, 15, - 15, 14, 14, 13, 13, 12, 12, 11, - 11, 10, 10, 9, 9, 8, 8, 7, - 7, 7, 6, 6, 6, 6, 5, 5, - 5, 5, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 +static char ulaw2dma8[] = +{ + -126, -122, -118, -114, -110, -106, -102, -98, + -94, -90, -86, -82, -78, -74, -70, -66, + -63, -61, -59, -57, -55, -53, -51, -49, + -47, -45, -43, -41, -39, -37, -35, -33, + -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, + -16, -15, -15, -14, -14, -13, -13, -12, + -12, -11, -11, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -7, -6, -6, + -6, -6, -5, -5, -5, -5, -4, -4, + -4, -4, -4, -4, -3, -3, -3, -3, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, + 125, 121, 117, 113, 109, 105, 101, 97, + 93, 89, 85, 81, 77, 73, 69, 65, + 62, 60, 58, 56, 54, 52, 50, 48, + 46, 44, 42, 40, 38, 36, 34, 32, + 30, 29, 28, 27, 26, 25, 24, 23, + 22, 21, 20, 19, 18, 17, 16, 15, + 15, 14, 14, 13, 13, 12, 12, 11, + 11, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 5, 5, + 5, 5, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; /* 8 bit A-law */ -static char alaw2dma8[] = { - -22, -21, -24, -23, -18, -17, -20, -19, - -30, -29, -32, -31, -26, -25, -28, -27, - -11, -11, -12, -12, -9, -9, -10, -10, - -15, -15, -16, -16, -13, -13, -14, -14, - -86, -82, -94, -90, -70, -66, -78, -74, - -118, -114, -126, -122, -102, -98, -110, -106, - -43, -41, -47, -45, -35, -33, -39, -37, - -59, -57, -63, -61, -51, -49, -55, -53, - -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -6, -6, -6, -6, -5, -5, -5, -5, - -8, -8, -8, -8, -7, -7, -7, -7, - -3, -3, -3, -3, -3, -3, -3, -3, - -4, -4, -4, -4, -4, -4, -4, -4, - 21, 20, 23, 22, 17, 16, 19, 18, - 29, 28, 31, 30, 25, 24, 27, 26, - 10, 10, 11, 11, 8, 8, 9, 9, - 14, 14, 15, 15, 12, 12, 13, 13, - 86, 82, 94, 90, 70, 66, 78, 74, - 118, 114, 126, 122, 102, 98, 110, 106, - 43, 41, 47, 45, 35, 33, 39, 37, - 59, 57, 63, 61, 51, 49, 55, 53, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 4, 4, 4, 4, - 7, 7, 7, 7, 6, 6, 6, 6, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 +static char alaw2dma8[] = +{ + -22, -21, -24, -23, -18, -17, -20, -19, + -30, -29, -32, -31, -26, -25, -28, -27, + -11, -11, -12, -12, -9, -9, -10, -10, + -15, -15, -16, -16, -13, -13, -14, -14, + -86, -82, -94, -90, -70, -66, -78, -74, + -118, -114, -126, -122, -102, -98, -110, -106, + -43, -41, -47, -45, -35, -33, -39, -37, + -59, -57, -63, -61, -51, -49, -55, -53, + -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -6, -6, -6, -6, -5, -5, -5, -5, + -8, -8, -8, -8, -7, -7, -7, -7, + -3, -3, -3, -3, -3, -3, -3, -3, + -4, -4, -4, -4, -4, -4, -4, -4, + 21, 20, 23, 22, 17, 16, 19, 18, + 29, 28, 31, 30, 25, 24, 27, 26, + 10, 10, 11, 11, 8, 8, 9, 9, + 14, 14, 15, 15, 12, 12, 13, 13, + 86, 82, 94, 90, 70, 66, 78, 74, + 118, 114, 126, 122, 102, 98, 110, 106, + 43, 41, 47, 45, 35, 33, 39, 37, + 59, 57, 63, 61, 51, 49, 55, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 4, 4, 4, 4, + 7, 7, 7, 7, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }; @@ -252,378 +256,403 @@ /* 16 bit mu-law */ -static char ulaw2dma16[] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, - -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, - -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, - -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0, +static char ulaw2dma16[] = +{ + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, }; /* 16 bit A-law */ -static char alaw2dma16[] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848, +static char alaw2dma16[] = +{ + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, }; -#endif /* HAS_16BIT_TABLES */ + +#endif /* HAS_16BIT_TABLES */ #ifdef HAS_14BIT_TABLES /* 14 bit mu-law (LSB) */ -static char alaw2dma14l[] = { - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 49, 17, 49, 17, 49, 17, 49, 17, - 49, 17, 49, 17, 49, 17, 49, 17, - 41, 57, 9, 25, 41, 57, 9, 25, - 41, 57, 9, 25, 41, 57, 9, 25, - 37, 45, 53, 61, 5, 13, 21, 29, - 37, 45, 53, 61, 5, 13, 21, 29, - 35, 39, 43, 47, 51, 55, 59, 63, - 3, 7, 11, 15, 19, 23, 27, 31, - 34, 36, 38, 40, 42, 44, 46, 48, - 50, 52, 54, 56, 58, 60, 62, 0, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 15, 47, 15, 47, 15, 47, 15, 47, - 15, 47, 15, 47, 15, 47, 15, 47, - 23, 7, 55, 39, 23, 7, 55, 39, - 23, 7, 55, 39, 23, 7, 55, 39, - 27, 19, 11, 3, 59, 51, 43, 35, - 27, 19, 11, 3, 59, 51, 43, 35, - 29, 25, 21, 17, 13, 9, 5, 1, - 61, 57, 53, 49, 45, 41, 37, 33, - 30, 28, 26, 24, 22, 20, 18, 16, - 14, 12, 10, 8, 6, 4, 2, 0 +static char alaw2dma14l[] = +{ + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 49, 17, 49, 17, 49, 17, 49, 17, + 49, 17, 49, 17, 49, 17, 49, 17, + 41, 57, 9, 25, 41, 57, 9, 25, + 41, 57, 9, 25, 41, 57, 9, 25, + 37, 45, 53, 61, 5, 13, 21, 29, + 37, 45, 53, 61, 5, 13, 21, 29, + 35, 39, 43, 47, 51, 55, 59, 63, + 3, 7, 11, 15, 19, 23, 27, 31, + 34, 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, 0, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 15, 47, 15, 47, 15, 47, 15, 47, + 15, 47, 15, 47, 15, 47, 15, 47, + 23, 7, 55, 39, 23, 7, 55, 39, + 23, 7, 55, 39, 23, 7, 55, 39, + 27, 19, 11, 3, 59, 51, 43, 35, + 27, 19, 11, 3, 59, 51, 43, 35, + 29, 25, 21, 17, 13, 9, 5, 1, + 61, 57, 53, 49, 45, 41, 37, 33, + 30, 28, 26, 24, 22, 20, 18, 16, + 14, 12, 10, 8, 6, 4, 2, 0 }; /* 14 bit A-law (LSB) */ -static char alaw2dma14l[] = { - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 16, 48, 16, 48, 16, 48, 16, 48, - 16, 48, 16, 48, 16, 48, 16, 48, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 40, 56, 8, 24, 40, 56, 8, 24, - 40, 56, 8, 24, 40, 56, 8, 24, - 20, 28, 4, 12, 52, 60, 36, 44, - 20, 28, 4, 12, 52, 60, 36, 44, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 48, 16, 48, 16, 48, 16, 48, 16, - 48, 16, 48, 16, 48, 16, 48, 16, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 24, 8, 56, 40, 24, 8, 56, 40, - 24, 8, 56, 40, 24, 8, 56, 40, - 44, 36, 60, 52, 12, 4, 28, 20, - 44, 36, 60, 52, 12, 4, 28, 20 +static char alaw2dma14l[] = +{ + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 48, 16, 48, 16, 48, 16, 48, + 16, 48, 16, 48, 16, 48, 16, 48, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 40, 56, 8, 24, 40, 56, 8, 24, + 40, 56, 8, 24, 40, 56, 8, 24, + 20, 28, 4, 12, 52, 60, 36, 44, + 20, 28, 4, 12, 52, 60, 36, 44, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 48, 16, 48, 16, 48, 16, 48, 16, + 48, 16, 48, 16, 48, 16, 48, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 24, 8, 56, 40, 24, 8, 56, 40, + 24, 8, 56, 40, 24, 8, 56, 40, + 44, 36, 60, 52, 12, 4, 28, 20, + 44, 36, 60, 52, 12, 4, 28, 20 }; -#endif /* HAS_14BIT_TABLES */ + +#endif /* HAS_14BIT_TABLES */ /*** Translations ************************************************************/ #ifdef CONFIG_ATARI -static long ata_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -#endif /* CONFIG_ATARI */ +static long ata_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static long ami_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -#endif /* CONFIG_AMIGA */ +static long ami_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); + +#endif /* CONFIG_AMIGA */ /*** Machine definitions *****************************************************/ -typedef struct { - int type; - void *(*dma_alloc)(unsigned int, int); - void (*dma_free)(void *, unsigned int); - int (*irqinit)(void); +typedef struct + { + int type; + void *(*dma_alloc) (unsigned int, int); + void (*dma_free) (void *, unsigned int); + int (*irqinit) (void); #ifdef MODULE - void (*irqcleanup)(void); -#endif /* MODULE */ - void (*init)(void); - void (*silence)(void); - int (*setFormat)(int); - int (*setVolume)(int); - int (*setBass)(int); - int (*setTreble)(int); - void (*play)(void); -} MACHINE; + void (*irqcleanup) (void); +#endif /* MODULE */ + void (*init) (void); + void (*silence) (void); + int (*setFormat) (int); + int (*setVolume) (int); + int (*setBass) (int); + int (*setTreble) (int); + void (*play) (void); + } +MACHINE; /*** Low level stuff *********************************************************/ -typedef struct { - int format; /* AFMT_* */ - int stereo; /* 0 = mono, 1 = stereo */ - int size; /* 8/16 bit*/ - int speed; /* speed */ -} SETTINGS; - -typedef struct { - long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long); -} TRANS; - -struct sound_settings { - MACHINE mach; /* machine dependent things */ - SETTINGS hard; /* hardware settings */ - SETTINGS soft; /* software settings */ - SETTINGS dsp; /* /dev/dsp default settings */ - TRANS *trans; /* supported translations */ - int volume_left; /* volume (range is machine dependent) */ - int volume_right; - int bass; /* tone (range is machine dependent) */ - int treble; - int minDev; /* minor device number currently open */ +typedef struct + { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit */ + int speed; /* speed */ + } +SETTINGS; + +typedef struct + { + long (*ct_ulaw) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_alaw) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s8) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u8) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16be) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16be) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16le) (const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16le) (const u_char *, unsigned long, u_char *, long *, long); + } +TRANS; + +struct sound_settings + { + MACHINE mach; /* machine dependent things */ + SETTINGS hard; /* hardware settings */ + SETTINGS soft; /* software settings */ + SETTINGS dsp; /* /dev/dsp default settings */ + TRANS *trans; /* supported translations */ + int volume_left; /* volume (range is machine dependent) */ + int volume_right; + int bass; /* tone (range is machine dependent) */ + int treble; + int minDev; /* minor device number currently open */ #ifdef CONFIG_ATARI - int bal; /* balance factor for expanding (not volume!) */ - u_long data; /* data for expanding */ -#endif /* CONFIG_ATARI */ -}; + int bal; /* balance factor for expanding (not volume!) */ + u_long data; /* data for expanding */ +#endif /* CONFIG_ATARI */ + }; static struct sound_settings sound; #ifdef CONFIG_ATARI -static void *AtaAlloc(unsigned int size, int flags); -static void AtaFree(void *, unsigned int size); -static int AtaIrqInit(void); +static void *AtaAlloc(unsigned int size, int flags); +static void AtaFree(void *, unsigned int size); +static int AtaIrqInit(void); + #ifdef MODULE -static void AtaIrqCleanUp(void); -#endif /* MODULE */ -static int AtaSetBass(int bass); -static int AtaSetTreble(int treble); -static void TTSilence(void); -static void TTInit(void); -static int TTSetFormat(int format); -static int TTSetVolume(int volume); -static void FalconSilence(void); -static void FalconInit(void); -static int FalconSetFormat(int format); -static int FalconSetVolume(int volume); -static void ata_sq_play_next_frame(int index); -static void AtaPlay(void); -static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); -#endif /* CONFIG_ATARI */ +static void AtaIrqCleanUp(void); + +#endif /* MODULE */ +static int AtaSetBass(int bass); +static int AtaSetTreble(int treble); +static void TTSilence(void); +static void TTInit(void); +static int TTSetFormat(int format); +static int TTSetVolume(int volume); +static void FalconSilence(void); +static void FalconInit(void); +static int FalconSetFormat(int format); +static int FalconSetVolume(int volume); +static void ata_sq_play_next_frame(int index); +static void AtaPlay(void); +static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static void *AmiAlloc(unsigned int size, int flags); -static void AmiFree(void *, unsigned int); -static int AmiIrqInit(void); +static void *AmiAlloc(unsigned int size, int flags); +static void AmiFree(void *, unsigned int); +static int AmiIrqInit(void); + #ifdef MODULE -static void AmiIrqCleanUp(void); -#endif /* MODULE */ -static void AmiSilence(void); -static void AmiInit(void); -static int AmiSetFormat(int format); -static int AmiSetVolume(int volume); -static int AmiSetTreble(int treble); -static void ami_sq_play_next_frame(int index); -static void AmiPlay(void); -static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); -#endif /* CONFIG_AMIGA */ +static void AmiIrqCleanUp(void); + +#endif /* MODULE */ +static void AmiSilence(void); +static void AmiInit(void); +static int AmiSetFormat(int format); +static int AmiSetVolume(int volume); +static int AmiSetTreble(int treble); +static void ami_sq_play_next_frame(int index); +static void AmiPlay(void); +static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); + +#endif /* CONFIG_AMIGA */ /*** Mid level stuff *********************************************************/ -static void sound_silence(void); -static void sound_init(void); -static int sound_set_format(int format); -static int sound_set_speed(int speed); -static int sound_set_stereo(int stereo); -static int sound_set_volume(int volume); +static void sound_silence(void); +static void sound_init(void); +static int sound_set_format(int format); +static int sound_set_speed(int speed); +static int sound_set_stereo(int stereo); +static int sound_set_volume(int volume); + #ifdef CONFIG_ATARI -static int sound_set_bass(int bass); -#endif /* CONFIG_ATARI */ -static int sound_set_treble(int treble); -static long sound_copy_translate(const u_char *userPtr, - unsigned long userCount, - u_char frame[], long *frameUsed, - long frameLeft); +static int sound_set_bass(int bass); + +#endif /* CONFIG_ATARI */ +static int sound_set_treble(int treble); +static long sound_copy_translate(const u_char * userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft); /* * /dev/mixer abstraction */ -struct sound_mixer { - int busy; -}; +struct sound_mixer + { + int busy; + }; static struct sound_mixer mixer; -static void mixer_init(void); -static int mixer_open(int open_mode); -static int mixer_release(void); -static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg); +static void mixer_init(void); +static int mixer_open(int open_mode); +static int mixer_release(void); +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); /* * Sound queue stuff, the heart of the driver */ -struct sound_queue { - int max_count, block_size; - char **buffers; - - /* it shouldn't be necessary to declare any of these volatile */ - int front, rear, count; - int rear_size; - /* - * The use of the playing field depends on the hardware - * - * Atari: The number of frames that are loaded/playing - * - * Amiga: Bit 0 is set: a frame is loaded - * Bit 1 is set: a frame is playing - */ - int playing; - struct wait_queue *write_queue, *open_queue, *sync_queue; - int open_mode; - int busy, syncing; +struct sound_queue + { + int max_count, block_size; + char **buffers; + + /* it shouldn't be necessary to declare any of these volatile */ + int front, rear, count; + int rear_size; + /* + * The use of the playing field depends on the hardware + * + * Atari: The number of frames that are loaded/playing + * + * Amiga: Bit 0 is set: a frame is loaded + * Bit 1 is set: a frame is playing + */ + int playing; + struct wait_queue *write_queue, *open_queue, *sync_queue; + int open_mode; + int busy, syncing; #ifdef CONFIG_ATARI - int ignore_int; /* ++TeSche: used for Falcon */ -#endif /* CONFIG_ATARI */ + int ignore_int; /* ++TeSche: used for Falcon */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - int block_size_half, block_size_quarter; -#endif /* CONFIG_AMIGA */ -}; + int block_size_half, block_size_quarter; +#endif /* CONFIG_AMIGA */ + }; static struct sound_queue sq; @@ -637,70 +666,72 @@ interruptible_sleep_on(&queue); #define WAKE_UP(queue) (wake_up_interruptible(&queue)) -static void sq_init(int numBufs, int bufSize, char **buffers); -static void sq_play(void); -static long sq_write(const char *src, unsigned long uLeft); -static int sq_open(int open_mode); -static void sq_reset(void); -static int sq_sync(void); -static int sq_release(void); +static void sq_init(int numBufs, int bufSize, char **buffers); +static void sq_play(void); +static long sq_write(const char *src, unsigned long uLeft); +static int sq_open(int open_mode); +static void sq_reset(void); +static int sq_sync(void); +static int sq_release(void); /* * /dev/sndstat */ -struct sound_state { - int busy; - char buf[512]; - int len, ptr; -}; +struct sound_state + { + int busy; + char buf[512]; + int len, ptr; + }; static struct sound_state state; -static void state_init(void); -static int state_open(int open_mode); -static int state_release(void); -static long state_read(char *dest, unsigned long count); +static void state_init(void); +static int state_open(int open_mode); +static int state_release(void); +static long state_read(char *dest, unsigned long count); /*** High level stuff ********************************************************/ -static int sound_open(struct inode *inode, struct file *file); -static int sound_fsync(struct inode *inode, struct file *filp); -static void sound_release(struct inode *inode, struct file *file); +static int sound_open(struct inode *inode, struct file *file); +static int sound_fsync(struct inode *inode, struct file *filp); +static void sound_release(struct inode *inode, struct file *file); static long long sound_lseek(struct inode *inode, struct file *file, long long offset, int orig); -static long sound_read(struct inode *inode, struct file *file, char *buf, - unsigned long count); -static long sound_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count); -static inline int ioctl_return(int *addr, int value) -{ - if (value < 0) - return(value); - - return put_user(value, addr); -} -static int unknown_minor_dev(char *fname, int dev); -static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg); +static long sound_read(struct inode *inode, struct file *file, char *buf, + unsigned long count); +static long sound_write(struct inode *inode, struct file *file, + const char *buf, unsigned long count); +static inline int +ioctl_return(int *addr, int value) +{ + if (value < 0) + return (value); + + return put_user(value, addr); +} +static int unknown_minor_dev(char *fname, int dev); +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); /*** Config & Setup **********************************************************/ -void soundcard_init(void); -void dmasound_setup(char *str, int *ints); -void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ +void soundcard_init(void); +void dmasound_setup(char *str, int *ints); +void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ /*** Translations ************************************************************/ /* ++TeSche: radically changed for new expanding purposes... - * + * These two routines now deal with copying/expanding/translating the samples * from user space into our buffer at the right frequency. They take care about * how much data there's actually to read, how much buffer space there is and @@ -724,849 +755,1014 @@ */ #ifdef CONFIG_ATARI -static long ata_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - long count, used; - u_char *p = &frame[*frameUsed]; +static long +ata_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - if (sound.soft.stereo) - count &= ~1; - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = table[data]; - count--; - } - *frameUsed += used; - return(used); + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + *frameUsed += used; + return (used); } -static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - void *p = &frame[*frameUsed]; + long count, used; + void *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - if (sound.soft.stereo) - count &= ~1; - used = count; - copy_from_user(p, userPtr, count); - *frameUsed += used; - return(used); + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + return (used); } -static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; + long count, used; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = data ^ 0x80; - count--; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - u_short data; - get_user(data, ((u_short *)userPtr)++); - *p++ = data ^ 0x8080; - count--; - } - } - *frameUsed += used; - return(used); -} + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft); + used = count; + while (count > 0) + { + u_char data; -static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used*2; - } else { - void *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft) & ~3; - used = count; - copy_from_user(p, userPtr, count); + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + u_short data; + + get_user(data, ((u_short *) userPtr)++); + *p++ = data ^ 0x8080; + count--; + } + } *frameUsed += used; - } - return(used); + return (used); } -static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used*2; - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>2; - used = count*4; - while (count > 0) { - get_user(data, ((u_int *)userPtr)++); - *p++ = data ^ 0x80008000; - count--; - } - *frameUsed += used; - } - return(used); + long count, used; + u_long data; + + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used * 2; + } else + { + void *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~3; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + } + return (used); } -static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - count = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used*2; - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>2; - used = count*4; - while (count > 0) { - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data); - *p++ = data; - count--; - } - *frameUsed += used; - } - return(used); + long count, used; + u_long data; + + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used * 2; + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 2; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_int *) userPtr)++); + *p++ = data ^ 0x80008000; + count--; + } + *frameUsed += used; + } + return (used); } -static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - count = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *p++ = data; - *p++ = data; - } - *frameUsed += used*2; - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - count = min(userCount, frameLeft)>>2; - used = count; - while (count > 0) { - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data) ^ 0x80008000; - *p++ = data; - count--; - } - *frameUsed += used; - } - return(used); + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used * 2; + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 2; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data); + *p++ = data; + count--; + } + *frameUsed += used; + } + return (used); } -static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ata_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (!userCount) - break; - get_user(c, userPtr++); - data = table[c]; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 2) { - u_char c; - if (bal < 0) { - if (userCount < 2) - break; - get_user(c, userPtr++); - data = table[c] << 8; - get_user(c, userPtr++); - data |= table[c]; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *p++ = data; + *p++ = data; + } + *frameUsed += used * 2; + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + count = min(userCount, frameLeft) >> 2; + used = count; + while (count > 0) + { + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + *p++ = data; + count--; + } + *frameUsed += used; + } + return (used); } -static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - while (frameLeft) { - if (bal < 0) { - if (!userCount) - break; - get_user(data, userPtr++); - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 2) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); +static long +ata_ctx_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + while (frameLeft) + { + u_char c; + + if (bal < 0) + { + if (!userCount) + break; + get_user(c, userPtr++); + data = table[c]; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 2) + { + u_char c; + + if (bal < 0) + { + if (userCount < 2) + break; + get_user(c, userPtr++); + data = table[c] << 8; + get_user(c, userPtr++); + data |= table[c]; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); } -static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - while (frameLeft) { - if (bal < 0) { - if (!userCount) - break; - get_user(data, userPtr++); - data ^= 0x80; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 2) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8080; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); +static long +ata_ctx_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + while (frameLeft) + { + if (bal < 0) + { + if (!userCount) + break; + get_user(data, userPtr++); + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 2) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); } -static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); +static long +ata_ctx_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + while (frameLeft) + { + if (bal < 0) + { + if (!userCount) + break; + get_user(data, userPtr++); + data ^= 0x80; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 2) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8080; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); } -static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - data ^= 0x80008000; - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); +static long +ata_ctx_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); } -static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data); - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); +static long +ata_ctx_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + data ^= 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); } -static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) { - u_short *p = (u_short *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 2) - break; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else { - u_long *p = (u_long *)&frame[*frameUsed]; - while (frameLeft >= 4) { - if (bal < 0) { - if (userCount < 4) - break; - get_user(data, ((u_int *)userPtr)++); - data = le2be16dbl(data) ^ 0x80008000; - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf-frameLeft; - return(used); +static long +ata_ctx_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); } -#endif /* CONFIG_ATARI */ + + +static long +ata_ctx_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) + { + u_short *p = (u_short *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 2) + break; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else + { + u_long *p = (u_long *) & frame[*frameUsed]; + + while (frameLeft >= 4) + { + if (bal < 0) + { + if (userCount < 4) + break; + get_user(data, ((u_int *) userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf - frameLeft; + return (used); +} +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static long ami_ct_law(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - long count, used; +static long +ami_ct_law(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + + if (!sound.soft.stereo) + { + u_char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) + { + u_char data; - if (!sound.soft.stereo) { - u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft) & ~1; - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = table[data]; - count--; - } - } else { - u_char *left = &frame[*frameUsed>>1]; - u_char *right = left+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *left++ = table[data]; - get_user(data, userPtr++); - *right++ = table[data]; - count--; - } - } - *frameUsed += used; - return(used); + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + } else + { + u_char *left = &frame[*frameUsed >> 1]; + u_char *right = left + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *left++ = table[data]; + get_user(data, userPtr++); + *right++ = table[data]; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_s8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; + long count, used; - if (!sound.soft.stereo) { - void *p = &frame[*frameUsed]; - count = min(userCount, frameLeft) & ~1; - used = count; - copy_from_user(p, userPtr, count); - } else { - u_char *left = &frame[*frameUsed>>1]; - u_char *right = left+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(*left++, userPtr++); - get_user(*right++, userPtr++); - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + void *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~1; + used = count; + copy_from_user(p, userPtr, count); + } else + { + u_char *left = &frame[*frameUsed >> 1]; + u_char *right = left + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(*left++, userPtr++); + get_user(*right++, userPtr++); + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long +ami_ct_u8(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; + long count, used; - if (!sound.soft.stereo) { - char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft) & ~1; - used = count; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *p++ = data ^ 0x80; - count--; - } - } else { - u_char *left = &frame[*frameUsed>>1]; - u_char *right = left+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - u_char data; - get_user(data, userPtr++); - *left++ = data ^ 0x80; - get_user(data, userPtr++); - *right++ = data ^ 0x80; - count--; - } - } - *frameUsed += used; - return(used); + if (!sound.soft.stereo) + { + char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else + { + u_char *left = &frame[*frameUsed >> 1]; + u_char *right = left + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + u_char data; + + get_user(data, userPtr++); + *left++ = data ^ 0x80; + get_user(data, userPtr++); + *right++ = data ^ 0x80; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); +static long +ami_ct_s16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - data ^= 0x8000; - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); +static long +ami_ct_u16be(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + data ^= 0x8000; + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data); - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); +static long +ami_ct_s16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data); + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) { - u_char *high = &frame[*frameUsed>>1]; - u_char *low = high+sq.block_size_half; - count = min(userCount, frameLeft)>>1 & ~1; - used = count*2; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *high++ = data>>8; - *low++ = (data>>2) & 0x3f; - count--; - } - } else { - u_char *lefth = &frame[*frameUsed>>2]; - u_char *leftl = lefth+sq.block_size_quarter; - u_char *righth = lefth+sq.block_size_half; - u_char *rightl = righth+sq.block_size_quarter; - count = min(userCount, frameLeft)>>2 & ~1; - used = count*4; - while (count > 0) { - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *lefth++ = data>>8; - *leftl++ = (data>>2) & 0x3f; - get_user(data, ((u_short *)userPtr)++); - data = le2be16(data) ^ 0x8000; - *righth++ = data>>8; - *rightl++ = (data>>2) & 0x3f; - count--; - } - } - *frameUsed += used; - return(used); +static long +ami_ct_u16le(const u_char * userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) + { + u_char *high = &frame[*frameUsed >> 1]; + u_char *low = high + sq.block_size_half; + + count = min(userCount, frameLeft) >> 1 & ~1; + used = count * 2; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *high++ = data >> 8; + *low++ = (data >> 2) & 0x3f; + count--; + } + } else + { + u_char *lefth = &frame[*frameUsed >> 2]; + u_char *leftl = lefth + sq.block_size_quarter; + u_char *righth = lefth + sq.block_size_half; + u_char *rightl = righth + sq.block_size_quarter; + + count = min(userCount, frameLeft) >> 2 & ~1; + used = count * 4; + while (count > 0) + { + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *lefth++ = data >> 8; + *leftl++ = (data >> 2) & 0x3f; + get_user(data, ((u_short *) userPtr)++); + data = le2be16(data) ^ 0x8000; + *righth++ = data >> 8; + *rightl++ = (data >> 2) & 0x3f; + count--; + } + } + *frameUsed += used; + return (used); } -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ #ifdef CONFIG_ATARI -static TRANS transTTNormal = { - ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL +static TRANS transTTNormal = +{ + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL }; -static TRANS transTTExpanding = { - ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL +static TRANS transTTExpanding = +{ + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL }; -static TRANS transFalconNormal = { - ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, - ata_ct_s16le, ata_ct_u16le +static TRANS transFalconNormal = +{ +ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, + ata_ct_s16le, ata_ct_u16le }; -static TRANS transFalconExpanding = { - ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, - ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le +static TRANS transFalconExpanding = +{ + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, + ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le }; -#endif /* CONFIG_ATARI */ + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static TRANS transAmiga = { - ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, - ami_ct_s16le, ami_ct_u16le +static TRANS transAmiga = +{ +ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, + ami_ct_s16le, ami_ct_u16le }; -#endif /* CONFIG_AMIGA */ + +#endif /* CONFIG_AMIGA */ /*** Low level stuff *********************************************************/ @@ -1578,60 +1774,68 @@ * Atari (TT/Falcon) */ -static void *AtaAlloc(unsigned int size, int flags) +static void * +AtaAlloc(unsigned int size, int flags) { - int order; - unsigned int a_size; - order = 0; - a_size = PAGE_SIZE; - while (a_size < size) { - order++; - a_size <<= 1; - } - return (void *) __get_dma_pages(flags, order); -} - -static void AtaFree(void *obj, unsigned int size) -{ - int order; - unsigned int a_size; - order = 0; - a_size = PAGE_SIZE; - while (a_size < size) { - order++; - a_size <<= 1; - } - free_pages ((unsigned long) obj, order); -} - -static int AtaIrqInit(void) -{ - /* Set up timer A. Timer A - will receive a signal upon end of playing from the sound - hardware. Furthermore Timer A is able to count events - and will cause an interrupt after a programmed number - of events. So all we need to keep the music playing is - to provide the sound hardware with new data upon - an interrupt from timer A. */ - mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ - mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ - mfp.tim_ct_a = 8; /* Turn on event counting. */ - /* Register interrupt handler. */ - request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, - "DMA sound", ata_sq_interrupt); - mfp.int_en_a |= 0x20; /* Turn interrupt on. */ - mfp.int_mk_a |= 0x20; - return(1); + int order; + unsigned int a_size; + + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) + { + order++; + a_size <<= 1; + } + return (void *) __get_dma_pages(flags, order); +} + +static void +AtaFree(void *obj, unsigned int size) +{ + int order; + unsigned int a_size; + + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) + { + order++; + a_size <<= 1; + } + free_pages((unsigned long) obj, order); +} + +static int +AtaIrqInit(void) +{ + /* Set up timer A. Timer A + will receive a signal upon end of playing from the sound + hardware. Furthermore Timer A is able to count events + and will cause an interrupt after a programmed number + of events. So all we need to keep the music playing is + to provide the sound hardware with new data upon + an interrupt from timer A. */ + mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ + mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ + mfp.tim_ct_a = 8; /* Turn on event counting. */ + /* Register interrupt handler. */ + request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, + "DMA sound", ata_sq_interrupt); + mfp.int_en_a |= 0x20; /* Turn interrupt on. */ + mfp.int_mk_a |= 0x20; + return (1); } #ifdef MODULE -static void AtaIrqCleanUp(void) +static void +AtaIrqCleanUp(void) { - mfp.tim_ct_a = 0; /* stop timer */ - mfp.int_en_a &= ~0x20; /* turn interrupt off */ - free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); + mfp.tim_ct_a = 0; /* stop timer */ + mfp.int_en_a &= ~0x20; /* turn interrupt off */ + free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); } -#endif /* MODULE */ +#endif /* MODULE */ #define TONE_VOXWARE_TO_DB(v) \ @@ -1639,19 +1843,21 @@ #define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) -static int AtaSetBass(int bass) +static int +AtaSetBass(int bass) { - sound.bass = TONE_VOXWARE_TO_DB(bass); - atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); - return(TONE_DB_TO_VOXWARE(sound.bass)); + sound.bass = TONE_VOXWARE_TO_DB(bass); + atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); + return (TONE_DB_TO_VOXWARE(sound.bass)); } -static int AtaSetTreble(int treble) +static int +AtaSetTreble(int treble) { - sound.treble = TONE_VOXWARE_TO_DB(treble); - atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); - return(TONE_DB_TO_VOXWARE(sound.treble)); + sound.treble = TONE_VOXWARE_TO_DB(treble); + atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); + return (TONE_DB_TO_VOXWARE(sound.treble)); } @@ -1661,88 +1867,100 @@ */ -static void TTSilence(void) +static void +TTSilence(void) { - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ } -static void TTInit(void) +static void +TTInit(void) { - int mode, i, idx; - const int freq[4] = {50066, 25033, 12517, 6258}; + int mode, i, idx; + const int freq[4] = + {50066, 25033, 12517, 6258}; - /* search a frequency that fits into the allowed error range */ + /* search a frequency that fits into the allowed error range */ - idx = -1; - for (i = 0; i < arraysize(freq); i++) - /* this isn't as much useful for a TT than for a Falcon, but - * then it doesn't hurt very much to implement it for a TT too. - */ - if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) - idx = i; - if (idx > -1) { - sound.soft.speed = freq[idx]; - sound.trans = &transTTNormal; - } else - sound.trans = &transTTExpanding; - - TTSilence(); - sound.hard = sound.soft; - - if (sound.hard.speed > 50066) { - /* we would need to squeeze the sound, but we won't do that */ - sound.hard.speed = 50066; - mode = DMASND_MODE_50KHZ; - sound.trans = &transTTNormal; - } else if (sound.hard.speed > 25033) { - sound.hard.speed = 50066; - mode = DMASND_MODE_50KHZ; - } else if (sound.hard.speed > 12517) { - sound.hard.speed = 25033; - mode = DMASND_MODE_25KHZ; - } else if (sound.hard.speed > 6258) { - sound.hard.speed = 12517; - mode = DMASND_MODE_12KHZ; - } else { - sound.hard.speed = 6258; - mode = DMASND_MODE_6KHZ; - } - - tt_dmasnd.mode = (sound.hard.stereo ? - DMASND_MODE_STEREO : DMASND_MODE_MONO) | - DMASND_MODE_8BIT | mode; - - sound.bal = -sound.soft.speed; + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* this isn't as much useful for a TT than for a Falcon, but + * then it doesn't hurt very much to implement it for a TT too. + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) + { + sound.soft.speed = freq[idx]; + sound.trans = &transTTNormal; + } else + sound.trans = &transTTExpanding; + + TTSilence(); + sound.hard = sound.soft; + + if (sound.hard.speed > 50066) + { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + sound.trans = &transTTNormal; + } else if (sound.hard.speed > 25033) + { + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + } else if (sound.hard.speed > 12517) + { + sound.hard.speed = 25033; + mode = DMASND_MODE_25KHZ; + } else if (sound.hard.speed > 6258) + { + sound.hard.speed = 12517; + mode = DMASND_MODE_12KHZ; + } else + { + sound.hard.speed = 6258; + mode = DMASND_MODE_6KHZ; + } + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + DMASND_MODE_8BIT | mode; + + sound.bal = -sound.soft.speed; } -static int TTSetFormat(int format) -{ - /* TT sound DMA supports only 8bit modes */ - - switch (format) { - case AFMT_QUERY: - return(sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_S8: - case AFMT_U8: - break; - default: - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = 8; - if (sound.minDev == SND_DEV_DSP) { - sound.dsp.format = format; - sound.dsp.size = 8; - } - TTInit(); +static int +TTSetFormat(int format) +{ + /* TT sound DMA supports only 8bit modes */ + + switch (format) + { + case AFMT_QUERY: + return (sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_S8: + case AFMT_U8: + break; + default: + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = 8; + if (sound.minDev == SND_DEV_DSP) + { + sound.dsp.format = format; + sound.dsp.size = 8; + } + TTInit(); - return(format); + return (format); } @@ -1751,14 +1969,15 @@ #define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) -static int TTSetVolume(int volume) +static int +TTSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); - atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); - sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); - atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); - return(VOLUME_DB_TO_VOXWARE(sound.volume_left) | - (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); + sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); + atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); + sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); + atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); + return (VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); } @@ -1768,135 +1987,151 @@ */ -static void FalconSilence(void) +static void +FalconSilence(void) { - /* stop playback, set sample rate 50kHz for PSG sound */ - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; - tt_dmasnd.int_div = 0; /* STE compatible divider */ - tt_dmasnd.int_ctrl = 0x0; - tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ - tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ - tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ - tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ + /* stop playback, set sample rate 50kHz for PSG sound */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; + tt_dmasnd.int_div = 0; /* STE compatible divider */ + tt_dmasnd.int_ctrl = 0x0; + tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ + tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ + tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ + tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ } -static void FalconInit(void) -{ - int divider, i, idx; - const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; +static void +FalconInit(void) +{ + int divider, i, idx; + const int freq[8] = + {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; + + /* search a frequency that fits into the allowed error range */ + + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would + * be playable without expanding, but that now a kernel runtime + * option + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) + { + sound.soft.speed = freq[idx]; + sound.trans = &transFalconNormal; + } else + sound.trans = &transFalconExpanding; - /* search a frequency that fits into the allowed error range */ + FalconSilence(); + sound.hard = sound.soft; + + if (sound.hard.size == 16) + { + /* the Falcon can play 16bit samples only in stereo */ + sound.hard.stereo = 1; + } + if (sound.hard.speed > 49170) + { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 49170; + divider = 1; + sound.trans = &transFalconNormal; + } else if (sound.hard.speed > 32780) + { + sound.hard.speed = 49170; + divider = 1; + } else if (sound.hard.speed > 24585) + { + sound.hard.speed = 32780; + divider = 2; + } else if (sound.hard.speed > 19668) + { + sound.hard.speed = 24585; + divider = 3; + } else if (sound.hard.speed > 16390) + { + sound.hard.speed = 19668; + divider = 4; + } else if (sound.hard.speed > 12292) + { + sound.hard.speed = 16390; + divider = 5; + } else if (sound.hard.speed > 9834) + { + sound.hard.speed = 12292; + divider = 7; + } else if (sound.hard.speed > 8195) + { + sound.hard.speed = 9834; + divider = 9; + } else + { + sound.hard.speed = 8195; + divider = 11; + } + tt_dmasnd.int_div = divider; + + /* Setup Falcon sound DMA for playback */ + tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ + tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ + tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ + tt_dmasnd.cbar_dst = 0x0000; + tt_dmasnd.rec_track_select = 0; + tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ + tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + ((sound.hard.size == 8) ? + DMASND_MODE_8BIT : DMASND_MODE_16BIT) | + DMASND_MODE_6KHZ; + + sound.bal = -sound.soft.speed; +} - idx = -1; - for (i = 0; i < arraysize(freq); i++) - /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would - * be playable without expanding, but that now a kernel runtime - * option - */ - if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) - idx = i; - if (idx > -1) { - sound.soft.speed = freq[idx]; - sound.trans = &transFalconNormal; - } else - sound.trans = &transFalconExpanding; - - FalconSilence(); - sound.hard = sound.soft; - - if (sound.hard.size == 16) { - /* the Falcon can play 16bit samples only in stereo */ - sound.hard.stereo = 1; - } - - if (sound.hard.speed > 49170) { - /* we would need to squeeze the sound, but we won't do that */ - sound.hard.speed = 49170; - divider = 1; - sound.trans = &transFalconNormal; - } else if (sound.hard.speed > 32780) { - sound.hard.speed = 49170; - divider = 1; - } else if (sound.hard.speed > 24585) { - sound.hard.speed = 32780; - divider = 2; - } else if (sound.hard.speed > 19668) { - sound.hard.speed = 24585; - divider = 3; - } else if (sound.hard.speed > 16390) { - sound.hard.speed = 19668; - divider = 4; - } else if (sound.hard.speed > 12292) { - sound.hard.speed = 16390; - divider = 5; - } else if (sound.hard.speed > 9834) { - sound.hard.speed = 12292; - divider = 7; - } else if (sound.hard.speed > 8195) { - sound.hard.speed = 9834; - divider = 9; - } else { - sound.hard.speed = 8195; - divider = 11; - } - tt_dmasnd.int_div = divider; - - /* Setup Falcon sound DMA for playback */ - tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ - tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ - tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ - tt_dmasnd.cbar_dst = 0x0000; - tt_dmasnd.rec_track_select = 0; - tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ - tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ - - tt_dmasnd.mode = (sound.hard.stereo ? - DMASND_MODE_STEREO : DMASND_MODE_MONO) | - ((sound.hard.size == 8) ? - DMASND_MODE_8BIT : DMASND_MODE_16BIT) | - DMASND_MODE_6KHZ; - - sound.bal = -sound.soft.speed; -} - - -static int FalconSetFormat(int format) -{ - int size; - /* Falcon sound DMA supports 8bit and 16bit modes */ - - switch (format) { - case AFMT_QUERY: - return(sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_BE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_U16_LE: - size = 16; - break; - default: /* :-) */ - size = 8; - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = size; - if (sound.minDev == SND_DEV_DSP) { - sound.dsp.format = format; - sound.dsp.size = sound.soft.size; - } - FalconInit(); +static int +FalconSetFormat(int format) +{ + int size; + + /* Falcon sound DMA supports 8bit and 16bit modes */ + + switch (format) + { + case AFMT_QUERY: + return (sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) + { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + FalconInit(); - return(format); + return (format); } @@ -1908,168 +2143,181 @@ #define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) -static int FalconSetVolume(int volume) +static int +FalconSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); - sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); - tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; - return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) | - VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); + sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); + sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); + tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; + return (VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); } -static void ata_sq_play_next_frame(int index) +static void +ata_sq_play_next_frame(int index) { - char *start, *end; + char *start, *end; - /* used by AtaPlay() if all doubts whether there really is something - * to be played are already wiped out. - */ - start = sq_block_address(sq.front); - end = start+((sq.count == index) ? sq.rear_size : sq.block_size); - /* end might not be a legal virtual address. */ - DMASNDSetEnd(VTOP(end - 1) + 1); - DMASNDSetBase(VTOP(start)); + /* used by AtaPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + end = start + ((sq.count == index) ? sq.rear_size : sq.block_size); + /* end might not be a legal virtual address. */ + DMASNDSetEnd(VTOP(end - 1) + 1); + DMASNDSetBase(VTOP(start)); /* Since only an even number of samples per frame can - be played, we might lose one byte here. (TO DO) */ - sq.front = (sq.front+1) % sq.max_count; - sq.playing++; - tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; + be played, we might lose one byte here. (TO DO) */ + sq.front = (sq.front + 1) % sq.max_count; + sq.playing++; + tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; } -static void AtaPlay(void) -{ - /* ++TeSche: Note that sq.playing is no longer just a flag but holds - * the number of frames the DMA is currently programmed for instead, - * may be 0, 1 (currently being played) or 2 (pre-programmed). - * - * Changes done to sq.count and sq.playing are a bit more subtle again - * so now I must admit I also prefer disabling the irq here rather - * than considering all possible situations. But the point is that - * disabling the irq doesn't have any bad influence on this version of - * the driver as we benefit from having pre-programmed the DMA - * wherever possible: There's no need to reload the DMA at the exact - * time of an interrupt but only at some time while the pre-programmed - * frame is playing! - */ - atari_disable_irq(IRQ_MFP_TIMA); +static void +AtaPlay(void) +{ + /* ++TeSche: Note that sq.playing is no longer just a flag but holds + * the number of frames the DMA is currently programmed for instead, + * may be 0, 1 (currently being played) or 2 (pre-programmed). + * + * Changes done to sq.count and sq.playing are a bit more subtle again + * so now I must admit I also prefer disabling the irq here rather + * than considering all possible situations. But the point is that + * disabling the irq doesn't have any bad influence on this version of + * the driver as we benefit from having pre-programmed the DMA + * wherever possible: There's no need to reload the DMA at the exact + * time of an interrupt but only at some time while the pre-programmed + * frame is playing! + */ + atari_disable_irq(IRQ_MFP_TIMA); - if (sq.playing == 2 || /* DMA is 'full' */ - sq.count <= 0) { /* nothing to do */ + if (sq.playing == 2 || /* DMA is 'full' */ + sq.count <= 0) + { /* nothing to do */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.playing == 0) + { + /* looks like there's nothing 'in' the DMA yet, so try + * to put two frames into it (at least one is available). + */ + if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(1); + if (sq.count == 1) + { + /* no more frames */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, there were two frames, but the second + * one is not yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } else + { + /* there's already a frame being played so we may only stuff + * one new into the DMA, but even if this may be the last + * frame existing the previous one is still on sq.count. + */ + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } atari_enable_irq(IRQ_MFP_TIMA); - return; - } - - if (sq.playing == 0) { - /* looks like there's nothing 'in' the DMA yet, so try - * to put two frames into it (at least one is available). - */ - if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(1); - if (sq.count == 1) { - /* no more frames */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, there were two frames, but the second - * one is not yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(2); - } else { - /* there's already a frame being played so we may only stuff - * one new into the DMA, but even if this may be the last - * frame existing the previous one is still on sq.count. - */ - if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(2); - } - atari_enable_irq(IRQ_MFP_TIMA); } -static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +static void +ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) { #if 0 - /* ++TeSche: if you should want to test this... */ - static int cnt = 0; - if (sq.playing == 2) - if (++cnt == 10) { - /* simulate losing an interrupt */ - cnt = 0; - return; - } -#endif + /* ++TeSche: if you should want to test this... */ + static int cnt = 0; - if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) { - /* ++TeSche: Falcon only: ignore first irq because it comes - * immediately after starting a frame. after that, irqs come - * (almost) like on the TT. - */ - sq.ignore_int = 0; - return; - } + if (sq.playing == 2) + if (++cnt == 10) + { + /* simulate losing an interrupt */ + cnt = 0; + return; + } +#endif - if (!sq.playing) { - /* playing was interrupted and sq_reset() has already cleared - * the sq variables, so better don't do anything here. + if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) + { + /* ++TeSche: Falcon only: ignore first irq because it comes + * immediately after starting a frame. after that, irqs come + * (almost) like on the TT. + */ + sq.ignore_int = 0; + return; + } + if (!sq.playing) + { + /* playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + /* Probably ;) one frame is finished. Well, in fact it may be that a + * pre-programmed one is also finished because there has been a long + * delay in interrupt delivery and we've completely lost one, but + * there's no way to detect such a situation. In such a case the last + * frame will be played more than once and the situation will recover + * as soon as the irq gets through. */ - WAKE_UP(sq.sync_queue); - return; - } - - /* Probably ;) one frame is finished. Well, in fact it may be that a - * pre-programmed one is also finished because there has been a long - * delay in interrupt delivery and we've completely lost one, but - * there's no way to detect such a situation. In such a case the last - * frame will be played more than once and the situation will recover - * as soon as the irq gets through. - */ - sq.count--; - sq.playing--; - - if (!sq.playing) { - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - sq.ignore_int = 1; - } + sq.count--; + sq.playing--; - WAKE_UP(sq.write_queue); + if (!sq.playing) + { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + sq.ignore_int = 1; + } + WAKE_UP(sq.write_queue); /* At least one block of the queue is free now - so wake up a writing process blocked because - of a full queue. */ + so wake up a writing process blocked because + of a full queue. */ - if ((sq.playing != 1) || (sq.count != 1)) - /* We must be a bit carefully here: sq.count indicates the - * number of buffers used and not the number of frames to - * be played. If sq.count==1 and sq.playing==1 that means - * the only remaining frame was already programmed earlier - * (and is currently running) so we mustn't call AtaPlay() - * here, otherwise we'll play one frame too much. - */ - AtaPlay(); + if ((sq.playing != 1) || (sq.count != 1)) + /* We must be a bit carefully here: sq.count indicates the + * number of buffers used and not the number of frames to + * be played. If sq.count==1 and sq.playing==1 that means + * the only remaining frame was already programmed earlier + * (and is currently running) so we mustn't call AtaPlay() + * here, otherwise we'll play one frame too much. + */ + AtaPlay(); - if (!sq.playing) WAKE_UP(sq.sync_queue); + if (!sq.playing) + WAKE_UP(sq.sync_queue); /* We are not playing after AtaPlay(), so there - is nothing to play any more. Wake up a process - waiting for audio output to drain. */ + is nothing to play any more. Wake up a process + waiting for audio output to drain. */ } -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA @@ -2079,109 +2327,120 @@ */ -static void *AmiAlloc(unsigned int size, int flags) +static void * +AmiAlloc(unsigned int size, int flags) { - return(amiga_chip_alloc((long)size)); + return (amiga_chip_alloc((long) size)); } -static void AmiFree(void *obj, unsigned int size) +static void +AmiFree(void *obj, unsigned int size) { - amiga_chip_free (obj); + amiga_chip_free(obj); } -static int AmiIrqInit(void) +static int +AmiIrqInit(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; - /* Register interrupt handler. */ - if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, - "DMA sound", ami_sq_interrupt)) - return(0); - return(1); + /* Register interrupt handler. */ + if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, + "DMA sound", ami_sq_interrupt)) + return (0); + return (1); } #ifdef MODULE -static void AmiIrqCleanUp(void) -{ - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; - /* release the interrupt */ - free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); -} -#endif /* MODULE */ - -static void AmiSilence(void) +static void +AmiIrqCleanUp(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; + /* release the interrupt */ + free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); } +#endif /* MODULE */ - -static void AmiInit(void) +static void +AmiSilence(void) { - int period, i; - - AmiSilence(); - - if (sound.soft.speed) - period = amiga_colorclock/sound.soft.speed-1; - else - period = amiga_audio_min_period; - sound.hard = sound.soft; - sound.trans = &transAmiga; - - if (period < amiga_audio_min_period) { - /* we would need to squeeze the sound, but we won't do that */ - period = amiga_audio_min_period; - } else if (period > 65535) { - period = 65535; - } - sound.hard.speed = amiga_colorclock/(period+1); - - for (i = 0; i < 4; i++) - custom.aud[i].audper = period; - amiga_audio_period = period; - - AmiSetTreble(50); /* recommended for newer amiga models */ + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; } -static int AmiSetFormat(int format) +static void +AmiInit(void) { - int size; - - /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ + int period, i; - switch (format) { - case AFMT_QUERY: - return(sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_BE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_U16_LE: - size = 16; - break; - default: /* :-) */ - size = 8; - format = AFMT_S8; - } + AmiSilence(); - sound.soft.format = format; - sound.soft.size = size; - if (sound.minDev == SND_DEV_DSP) { - sound.dsp.format = format; - sound.dsp.size = sound.soft.size; - } - AmiInit(); + if (sound.soft.speed) + period = amiga_colorclock / sound.soft.speed - 1; + else + period = amiga_audio_min_period; + sound.hard = sound.soft; + sound.trans = &transAmiga; + + if (period < amiga_audio_min_period) + { + /* we would need to squeeze the sound, but we won't do that */ + period = amiga_audio_min_period; + } else if (period > 65535) + { + period = 65535; + } + sound.hard.speed = amiga_colorclock / (period + 1); + + for (i = 0; i < 4; i++) + custom.aud[i].audper = period; + amiga_audio_period = period; + + AmiSetTreble(50); /* recommended for newer amiga models */ +} + + +static int +AmiSetFormat(int format) +{ + int size; + + /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ + + switch (format) + { + case AFMT_QUERY: + return (sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) + { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + AmiInit(); - return(format); + return (format); } @@ -2189,24 +2448,26 @@ (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100) #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64) -static int AmiSetVolume(int volume) +static int +AmiSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); - custom.aud[0].audvol = sound.volume_left; - sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); - custom.aud[1].audvol = sound.volume_right; - return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) | - (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); -} - -static int AmiSetTreble(int treble) -{ - sound.treble = treble; - if (treble < 50) - ciaa.pra &= ~0x02; - else - ciaa.pra |= 0x02; - return(treble); + sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); + custom.aud[0].audvol = sound.volume_left; + sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); + custom.aud[1].audvol = sound.volume_right; + return (VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); +} + +static int +AmiSetTreble(int treble) +{ + sound.treble = treble; + if (treble < 50) + ciaa.pra &= ~0x02; + else + ciaa.pra |= 0x02; + return (treble); } @@ -2215,279 +2476,302 @@ #define AMI_PLAY_MASK 3 -static void ami_sq_play_next_frame(int index) +static void +ami_sq_play_next_frame(int index) { - u_char *start, *ch0, *ch1, *ch2, *ch3; - u_long size; + u_char *start, *ch0, *ch1, *ch2, *ch3; + u_long size; - /* used by AmiPlay() if all doubts whether there really is something - * to be played are already wiped out. - */ - start = sq_block_address(sq.front); - size = (sq.count == index ? sq.rear_size : sq.block_size)>>1; - - if (sound.hard.stereo) { - ch0 = start; - ch1 = start+sq.block_size_half; - size >>= 1; - } else { - ch0 = start; - ch1 = start; - } - if (sound.hard.size == 8) { - custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); - custom.aud[0].audlen = size; - custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); - custom.aud[1].audlen = size; - custom.dmacon = AMI_AUDIO_8; - } else { - size >>= 1; - custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); - custom.aud[0].audlen = size; - custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); - custom.aud[1].audlen = size; - if (sound.volume_left == 64 && sound.volume_right == 64) { - /* We can play pseudo 14-bit only with the maximum volume */ - ch3 = ch0+sq.block_size_quarter; - ch2 = ch1+sq.block_size_quarter; - custom.aud[2].audvol = 1; /* we are being affected by the beeps */ - custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ - custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2); - custom.aud[2].audlen = size; - custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3); - custom.aud[3].audlen = size; - custom.dmacon = AMI_AUDIO_14; - } else - custom.dmacon = AMI_AUDIO_8; - } - sq.front = (sq.front+1) % sq.max_count; - sq.playing |= AMI_PLAY_LOADED; -} - - -static void AmiPlay(void) -{ - int minframes = 1; - - custom.intena = IF_AUD0; + /* used by AmiPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + size = (sq.count == index ? sq.rear_size : sq.block_size) >> 1; - if (sq.playing & AMI_PLAY_LOADED) { - /* There's already a frame loaded */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } + if (sound.hard.stereo) + { + ch0 = start; + ch1 = start + sq.block_size_half; + size >>= 1; + } else + { + ch0 = start; + ch1 = start; + } + if (sound.hard.size == 8) + { + custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + custom.dmacon = AMI_AUDIO_8; + } else + { + size >>= 1; + custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + if (sound.volume_left == 64 && sound.volume_right == 64) + { + /* We can play pseudo 14-bit only with the maximum volume */ + ch3 = ch0 + sq.block_size_quarter; + ch2 = ch1 + sq.block_size_quarter; + custom.aud[2].audvol = 1; /* we are being affected by the beeps */ + custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ + custom.aud[2].audlc = (u_short *) ZTWO_PADDR(ch2); + custom.aud[2].audlen = size; + custom.aud[3].audlc = (u_short *) ZTWO_PADDR(ch3); + custom.aud[3].audlen = size; + custom.dmacon = AMI_AUDIO_14; + } else + custom.dmacon = AMI_AUDIO_8; + } + sq.front = (sq.front + 1) % sq.max_count; + sq.playing |= AMI_PLAY_LOADED; +} - if (sq.playing & AMI_PLAY_PLAYING) - /* Increase threshold: frame 1 is already being played */ - minframes = 2; - if (sq.count < minframes) { - /* Nothing to do */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } +static void +AmiPlay(void) +{ + int minframes = 1; + + custom.intena = IF_AUD0; + + if (sq.playing & AMI_PLAY_LOADED) + { + /* There's already a frame loaded */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + if (sq.playing & AMI_PLAY_PLAYING) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + if (sq.count < minframes) + { + /* Nothing to do */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) + { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + ami_sq_play_next_frame(minframes); - if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ custom.intena = IF_SETCLR | IF_AUD0; - return; - } - - ami_sq_play_next_frame(minframes); - - custom.intena = IF_SETCLR | IF_AUD0; } -static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +static void +ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) { - int minframes = 1; + int minframes = 1; - if (!sq.playing) { - /* Playing was interrupted and sq_reset() has already cleared - * the sq variables, so better don't do anything here. - */ - WAKE_UP(sq.sync_queue); - return; - } - - if (sq.playing & AMI_PLAY_PLAYING) { - /* We've just finished a frame */ - sq.count--; - WAKE_UP(sq.write_queue); - } - - if (sq.playing & AMI_PLAY_LOADED) - /* Increase threshold: frame 1 is already being played */ - minframes = 2; - - /* Shift the flags */ - sq.playing = (sq.playing<<1) & AMI_PLAY_MASK; - - if (!sq.playing) - /* No frame is playing, disable audio DMA */ - custom.dmacon = AMI_AUDIO_OFF; - - if (sq.count >= minframes) - /* Try to play the next frame */ - AmiPlay(); - - if (!sq.playing) - /* Nothing to play anymore. - Wake up a process waiting for audio output to drain. */ - WAKE_UP(sq.sync_queue); + if (!sq.playing) + { + /* Playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + if (sq.playing & AMI_PLAY_PLAYING) + { + /* We've just finished a frame */ + sq.count--; + WAKE_UP(sq.write_queue); + } + if (sq.playing & AMI_PLAY_LOADED) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + /* Shift the flags */ + sq.playing = (sq.playing << 1) & AMI_PLAY_MASK; + + if (!sq.playing) + /* No frame is playing, disable audio DMA */ + custom.dmacon = AMI_AUDIO_OFF; + + if (sq.count >= minframes) + /* Try to play the next frame */ + AmiPlay(); + + if (!sq.playing) + /* Nothing to play anymore. + Wake up a process waiting for audio output to drain. */ + WAKE_UP(sq.sync_queue); } -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Machine definitions *****************************************************/ #ifdef CONFIG_ATARI -static MACHINE machTT = { - DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, +static MACHINE machTT = +{ + DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, #ifdef MODULE - AtaIrqCleanUp, -#endif /* MODULE */ - TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, - AtaPlay + AtaIrqCleanUp, +#endif /* MODULE */ + TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, + AtaPlay }; -static MACHINE machFalcon = { - DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, +static MACHINE machFalcon = +{ + DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, #ifdef MODULE - AtaIrqCleanUp, -#endif /* MODULE */ - FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, - AtaSetTreble, AtaPlay + AtaIrqCleanUp, +#endif /* MODULE */ + FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, + AtaSetTreble, AtaPlay }; -#endif /* CONFIG_ATARI */ + +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static MACHINE machAmiga = { - DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, +static MACHINE machAmiga = +{ + DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, #ifdef MODULE - AmiIrqCleanUp, -#endif /* MODULE */ - AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, - AmiPlay + AmiIrqCleanUp, +#endif /* MODULE */ + AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, + AmiPlay }; -#endif /* CONFIG_AMIGA */ + +#endif /* CONFIG_AMIGA */ /*** Mid level stuff *********************************************************/ -static void sound_silence(void) +static void +sound_silence(void) { - /* update hardware settings one more */ - (*sound.mach.init)(); + /* update hardware settings one more */ + (*sound.mach.init) (); - (*sound.mach.silence)(); + (*sound.mach.silence) (); } -static void sound_init(void) +static void +sound_init(void) { - (*sound.mach.init)(); + (*sound.mach.init) (); } -static int sound_set_format(int format) +static int +sound_set_format(int format) { - return(*sound.mach.setFormat)(format); + return (*sound.mach.setFormat) (format); } -static int sound_set_speed(int speed) +static int +sound_set_speed(int speed) { - if (speed < 0) - return(sound.soft.speed); + if (speed < 0) + return (sound.soft.speed); - sound.soft.speed = speed; - (*sound.mach.init)(); - if (sound.minDev == SND_DEV_DSP) - sound.dsp.speed = sound.soft.speed; + sound.soft.speed = speed; + (*sound.mach.init) (); + if (sound.minDev == SND_DEV_DSP) + sound.dsp.speed = sound.soft.speed; - return(sound.soft.speed); + return (sound.soft.speed); } -static int sound_set_stereo(int stereo) +static int +sound_set_stereo(int stereo) { - if (stereo < 0) - return(sound.soft.stereo); + if (stereo < 0) + return (sound.soft.stereo); - stereo = !!stereo; /* should be 0 or 1 now */ + stereo = !!stereo; /* should be 0 or 1 now */ - sound.soft.stereo = stereo; - if (sound.minDev == SND_DEV_DSP) - sound.dsp.stereo = stereo; - (*sound.mach.init)(); + sound.soft.stereo = stereo; + if (sound.minDev == SND_DEV_DSP) + sound.dsp.stereo = stereo; + (*sound.mach.init) (); - return(stereo); + return (stereo); } -static int sound_set_volume(int volume) +static int +sound_set_volume(int volume) { - return(*sound.mach.setVolume)(volume); + return (*sound.mach.setVolume) (volume); } #ifdef CONFIG_ATARI -static int sound_set_bass(int bass) +static int +sound_set_bass(int bass) { - return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50); + return (sound.mach.setBass ? (*sound.mach.setBass) (bass) : 50); } -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ -static int sound_set_treble(int treble) -{ - return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50); +static int +sound_set_treble(int treble) +{ + return (sound.mach.setTreble ? (*sound.mach.setTreble) (treble) : 50); } -static long sound_copy_translate(const u_char *userPtr, - unsigned long userCount, - u_char frame[], long *frameUsed, - long frameLeft) -{ - long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL; - - switch (sound.soft.format) { - case AFMT_MU_LAW: - ct_func = sound.trans->ct_ulaw; - break; - case AFMT_A_LAW: - ct_func = sound.trans->ct_alaw; - break; - case AFMT_S8: - ct_func = sound.trans->ct_s8; - break; - case AFMT_U8: - ct_func = sound.trans->ct_u8; - break; - case AFMT_S16_BE: - ct_func = sound.trans->ct_s16be; - break; - case AFMT_U16_BE: - ct_func = sound.trans->ct_u16be; - break; - case AFMT_S16_LE: - ct_func = sound.trans->ct_s16le; - break; - case AFMT_U16_LE: - ct_func = sound.trans->ct_u16le; - break; - } - if (ct_func) - return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); - else - return(0); +static long +sound_copy_translate(const u_char * userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft) +{ + long (*ct_func) (const u_char *, unsigned long, u_char *, long *, long) = NULL; + + switch (sound.soft.format) + { + case AFMT_MU_LAW: + ct_func = sound.trans->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans->ct_u16le; + break; + } + if (ct_func) + return (ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); + else + return (0); } @@ -2501,199 +2785,215 @@ #define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3) -static void mixer_init(void) +static void +mixer_init(void) { - mixer.busy = 0; - sound.treble = 0; - sound.bass = 0; - switch (sound.mach.type) { + mixer.busy = 0; + sound.treble = 0; + sound.bass = 0; + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - atari_microwire_cmd(MW_LM1992_VOLUME(0)); - sound.volume_left = 0; - atari_microwire_cmd(MW_LM1992_BALLEFT(0)); - sound.volume_right = 0; - atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); - atari_microwire_cmd(MW_LM1992_TREBLE(0)); - atari_microwire_cmd(MW_LM1992_BASS(0)); - break; - case DMASND_FALCON: - sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; - sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + atari_microwire_cmd(MW_LM1992_VOLUME(0)); + sound.volume_left = 0; + atari_microwire_cmd(MW_LM1992_BALLEFT(0)); + sound.volume_right = 0; + atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); + atari_microwire_cmd(MW_LM1992_TREBLE(0)); + atari_microwire_cmd(MW_LM1992_BASS(0)); + break; + case DMASND_FALCON: + sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; + sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - sound.volume_left = 64; - sound.volume_right = 64; - custom.aud[0].audvol = sound.volume_left; - custom.aud[3].audvol = 1; /* For pseudo 14bit */ - custom.aud[1].audvol = sound.volume_right; - custom.aud[2].audvol = 1; /* For pseudo 14bit */ - sound.treble = 50; - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + sound.volume_left = 64; + sound.volume_right = 64; + custom.aud[0].audvol = sound.volume_left; + custom.aud[3].audvol = 1; /* For pseudo 14bit */ + custom.aud[1].audvol = sound.volume_right; + custom.aud[2].audvol = 1; /* For pseudo 14bit */ + sound.treble = 50; + break; +#endif /* CONFIG_AMIGA */ + } } -static int mixer_open(int open_mode) +static int +mixer_open(int open_mode) { - if (mixer.busy) - return(-EBUSY); - mixer.busy = 1; - return(0); + if (mixer.busy) + return (-EBUSY); + mixer.busy = 1; + return (0); } -static int mixer_release(void) +static int +mixer_release(void) { - mixer.busy = 0; - return(0); + mixer.busy = 0; + return (0); } -static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg) +static int +mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) { - int data; - switch (sound.mach.type) { + int data; + + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_FALCON: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); - case SOUND_MIXER_READ_RECMASK: - return(IOCTL_OUT(arg, SOUND_MASK_MIC)); - case SOUND_MIXER_READ_STEREODEVS: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); - case SOUND_MIXER_READ_CAPS: - return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); - case SOUND_MIXER_READ_VOLUME: - return(IOCTL_OUT(arg, - VOLUME_ATT_TO_VOXWARE(sound.volume_left) | - VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - tt_dmasnd.input_gain = - RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | - RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); - /* fall thru, return set value */ - case SOUND_MIXER_READ_MIC: - return(IOCTL_OUT(arg, - RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | - RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); - case SOUND_MIXER_READ_SPEAKER: - { - int porta; - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = sound_ym.rd_data_reg_sel; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_WRITE_SPEAKER: - { - int porta; - IOCTL_IN(arg, data); - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = (sound_ym.rd_data_reg_sel & ~0x40) | - (data < 50 ? 0x40 : 0); - sound_ym.wd_data = porta; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } - } - break; - - case DMASND_TT: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - return(IOCTL_OUT(arg, - SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | - ((atari_mch_cookie >> 16) == ATARI_MCH_TT ? - SOUND_MASK_SPEAKER : 0))); - case SOUND_MIXER_READ_RECMASK: - return(IOCTL_OUT(arg, 0)); - case SOUND_MIXER_READ_STEREODEVS: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); - case SOUND_MIXER_READ_VOLUME: - return(IOCTL_OUT(arg, - VOLUME_DB_TO_VOXWARE(sound.volume_left) | - (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); - case SOUND_MIXER_READ_BASS: - return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); - case SOUND_MIXER_READ_TREBLE: - return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); - case SOUND_MIXER_READ_SPEAKER: - { - int porta; - if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) { - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = sound_ym.rd_data_reg_sel; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } else - return(-EINVAL); - } - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_WRITE_BASS: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_bass(data))); - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_treble(data))); - case SOUND_MIXER_WRITE_SPEAKER: - if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) { - int porta; - IOCTL_IN(arg, data); - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = (sound_ym.rd_data_reg_sel & ~0x40) | - (data < 50 ? 0x40 : 0); - sound_ym.wd_data = porta; - sti(); - return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } else - return(-EINVAL); - } - break; -#endif /* CONFIG_ATARI */ + case DMASND_FALCON: + switch (cmd) + { + case SOUND_MIXER_READ_DEVMASK: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + case SOUND_MIXER_READ_RECMASK: + return (IOCTL_OUT(arg, SOUND_MASK_MIC)); + case SOUND_MIXER_READ_STEREODEVS: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); + case SOUND_MIXER_READ_CAPS: + return (IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); + case SOUND_MIXER_READ_VOLUME: + return (IOCTL_OUT(arg, + VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + tt_dmasnd.input_gain = + RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | + RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); + /* fall thru, return set value */ + case SOUND_MIXER_READ_MIC: + return (IOCTL_OUT(arg, + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_SPEAKER: + { + int porta; + + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + } + break; + + case DMASND_TT: + switch (cmd) + { + case SOUND_MIXER_READ_DEVMASK: + return (IOCTL_OUT(arg, + SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | + ((atari_mch_cookie >> 16) == ATARI_MCH_TT ? + SOUND_MASK_SPEAKER : 0))); + case SOUND_MIXER_READ_RECMASK: + return (IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return (IOCTL_OUT(arg, + VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); + case SOUND_MIXER_READ_BASS: + return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); + case SOUND_MIXER_READ_TREBLE: + return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + + if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) + { + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return (-EINVAL); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_BASS: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_bass(data))); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_treble(data))); + case SOUND_MIXER_WRITE_SPEAKER: + if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) + { + int porta; + + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return (-EINVAL); + } + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); - case SOUND_MIXER_READ_RECMASK: - return(IOCTL_OUT(arg, 0)); - case SOUND_MIXER_READ_STEREODEVS: - return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); - case SOUND_MIXER_READ_VOLUME: - return(IOCTL_OUT(arg, - VOLUME_AMI_TO_VOXWARE(sound.volume_left) | - VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_READ_TREBLE: - return(IOCTL_OUT(arg, sound.treble)); - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_treble(data))); - } - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + switch (cmd) + { + case SOUND_MIXER_READ_DEVMASK: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); + case SOUND_MIXER_READ_RECMASK: + return (IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return (IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return (IOCTL_OUT(arg, + VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_READ_TREBLE: + return (IOCTL_OUT(arg, sound.treble)); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_treble(data))); + } + break; +#endif /* CONFIG_AMIGA */ + } - return(-EINVAL); + return (-EINVAL); } @@ -2703,198 +3003,216 @@ */ -static void sq_init(int numBufs, int bufSize, char **buffers) +static void +sq_init(int numBufs, int bufSize, char **buffers) { - sq.max_count = numBufs; - sq.block_size = bufSize; - sq.buffers = buffers; - - sq.front = sq.count = 0; - sq.rear = -1; - sq.write_queue = sq.open_queue = sq.sync_queue = 0; - sq.busy = 0; - sq.syncing = 0; + sq.max_count = numBufs; + sq.block_size = bufSize; + sq.buffers = buffers; + + sq.front = sq.count = 0; + sq.rear = -1; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + sq.syncing = 0; - sq.playing = 0; + sq.playing = 0; #ifdef CONFIG_ATARI - sq.ignore_int = 0; -#endif /* CONFIG_ATARI */ + sq.ignore_int = 0; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - sq.block_size_half = sq.block_size>>1; - sq.block_size_quarter = sq.block_size_half>>1; -#endif /* CONFIG_AMIGA */ - - sound_silence(); - - /* whatever you like as startup mode for /dev/dsp, - * (/dev/audio hasn't got a startup mode). note that - * once changed a new open() will *not* restore these! - */ - sound.dsp.format = AFMT_S8; - sound.dsp.stereo = 0; - sound.dsp.size = 8; + sq.block_size_half = sq.block_size >> 1; + sq.block_size_quarter = sq.block_size_half >> 1; +#endif /* CONFIG_AMIGA */ + + sound_silence(); - /* set minimum rate possible without expanding */ - switch (sound.mach.type) { + /* whatever you like as startup mode for /dev/dsp, + * (/dev/audio hasn't got a startup mode). note that + * once changed a new open() will *not* restore these! + */ + sound.dsp.format = AFMT_S8; + sound.dsp.stereo = 0; + sound.dsp.size = 8; + + /* set minimum rate possible without expanding */ + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - sound.dsp.speed = 6258; - break; - case DMASND_FALCON: - sound.dsp.speed = 8195; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + sound.dsp.speed = 6258; + break; + case DMASND_FALCON: + sound.dsp.speed = 8195; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - sound.dsp.speed = 8000; - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + sound.dsp.speed = 8000; + break; +#endif /* CONFIG_AMIGA */ + } - /* before the first open to /dev/dsp this wouldn't be set */ - sound.soft = sound.dsp; - sound.hard = sound.dsp; + /* before the first open to /dev/dsp this wouldn't be set */ + sound.soft = sound.dsp; + sound.hard = sound.dsp; } -static void sq_play(void) +static void +sq_play(void) { - (*sound.mach.play)(); + (*sound.mach.play) (); } /* ++TeSche: radically changed this one too */ -static long sq_write(const char *src, unsigned long uLeft) +static long +sq_write(const char *src, unsigned long uLeft) { - long uWritten = 0; - u_char *dest; - long uUsed, bUsed, bLeft; - - /* ++TeSche: Is something like this necessary? - * Hey, that's an honest question! Or does any other part of the - * filesystem already checks this situation? I really don't know. - */ - if (uLeft == 0) - return(0); - - /* The interrupt doesn't start to play the last, incomplete frame. - * Thus we can append to it without disabling the interrupts! (Note - * also that sq.rear isn't affected by the interrupt.) - */ - - if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { - dest = sq_block_address(sq.rear); - bUsed = sq.rear_size; - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); - src += uUsed; - uWritten += uUsed; - uLeft -= uUsed; - sq.rear_size = bUsed; - } - - do { - while (sq.count == sq.max_count) { - sq_play(); - if (NON_BLOCKING(sq.open_mode)) - return(uWritten > 0 ? uWritten : -EAGAIN); - SLEEP(sq.write_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - return(uWritten > 0 ? uWritten : -EINTR); - } + long uWritten = 0; + u_char *dest; + long uUsed, bUsed, bLeft; + + /* ++TeSche: Is something like this necessary? + * Hey, that's an honest question! Or does any other part of the + * filesystem already checks this situation? I really don't know. + */ + if (uLeft == 0) + return (0); - /* Here, we can avoid disabling the interrupt by first - * copying and translating the data, and then updating - * the sq variables. Until this is done, the interrupt - * won't see the new frame and we can work on it - * undisturbed. + /* The interrupt doesn't start to play the last, incomplete frame. + * Thus we can append to it without disabling the interrupts! (Note + * also that sq.rear isn't affected by the interrupt.) */ - dest = sq_block_address((sq.rear+1) % sq.max_count); - bUsed = 0; - bLeft = sq.block_size; - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); - src += uUsed; - uWritten += uUsed; - uLeft -= uUsed; - if (bUsed) { - sq.rear = (sq.rear+1) % sq.max_count; - sq.rear_size = bUsed; - sq.count++; - } - } while (bUsed); /* uUsed may have been 0 */ + if (sq.count > 0 && (bLeft = sq.block_size - sq.rear_size) > 0) + { + dest = sq_block_address(sq.rear); + bUsed = sq.rear_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + sq.rear_size = bUsed; + } + do + { + while (sq.count == sq.max_count) + { + sq_play(); + if (NON_BLOCKING(sq.open_mode)) + return (uWritten > 0 ? uWritten : -EAGAIN); + SLEEP(sq.write_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return (uWritten > 0 ? uWritten : -EINTR); + } + + /* Here, we can avoid disabling the interrupt by first + * copying and translating the data, and then updating + * the sq variables. Until this is done, the interrupt + * won't see the new frame and we can work on it + * undisturbed. + */ + + dest = sq_block_address((sq.rear + 1) % sq.max_count); + bUsed = 0; + bLeft = sq.block_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + if (bUsed) + { + sq.rear = (sq.rear + 1) % sq.max_count; + sq.rear_size = bUsed; + sq.count++; + } + } + while (bUsed); /* uUsed may have been 0 */ - sq_play(); + sq_play(); - return(uWritten); + return (uWritten); } -static int sq_open(int open_mode) +static int +sq_open(int open_mode) { - if (sq.busy) { - if (NON_BLOCKING(open_mode)) - return(-EBUSY); - while (sq.busy) { - SLEEP(sq.open_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - return(-EINTR); - } - } - sq.open_mode = open_mode; - sq.busy = 1; + if (sq.busy) + { + if (NON_BLOCKING(open_mode)) + return (-EBUSY); + while (sq.busy) + { + SLEEP(sq.open_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return (-EINTR); + } + } + sq.open_mode = open_mode; + sq.busy = 1; #ifdef CONFIG_ATARI - sq.ignore_int = 1; -#endif /* CONFIG_ATARI */ - return(0); + sq.ignore_int = 1; +#endif /* CONFIG_ATARI */ + return (0); } -static void sq_reset(void) +static void +sq_reset(void) { - sound_silence(); - sq.playing = 0; - sq.count = 0; - sq.front = (sq.rear+1) % sq.max_count; + sound_silence(); + sq.playing = 0; + sq.count = 0; + sq.front = (sq.rear + 1) % sq.max_count; } -static int sq_sync(void) +static int +sq_sync(void) { - int rc = 0; + int rc = 0; - sq.syncing = 1; - sq_play(); /* there may be an incomplete frame waiting */ + sq.syncing = 1; + sq_play(); /* there may be an incomplete frame waiting */ - while (sq.playing) { - SLEEP(sq.sync_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) { - /* While waiting for audio output to drain, an interrupt occurred. - Stop audio output immediately and clear the queue. */ - sq_reset(); - rc = -EINTR; - break; - } - } + while (sq.playing) + { + SLEEP(sq.sync_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + { + /* While waiting for audio output to drain, an interrupt occurred. + Stop audio output immediately and clear the queue. */ + sq_reset(); + rc = -EINTR; + break; + } + } - sq.syncing = 0; - return(rc); + sq.syncing = 0; + return (rc); } -static int sq_release(void) +static int +sq_release(void) { - int rc = 0; - if (sq.busy) { - rc = sq_sync(); - sq.busy = 0; - WAKE_UP(sq.open_queue); - /* Wake up a process waiting for the queue being released. - Note: There may be several processes waiting for a call to open() - returning. */ - } - return(rc); + int rc = 0; + + if (sq.busy) + { + rc = sq_sync(); + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue being released. + Note: There may be several processes waiting for a call to open() + returning. */ + } + return (rc); } @@ -2904,128 +3222,136 @@ */ -static void state_init(void) +static void +state_init(void) { - state.busy = 0; + state.busy = 0; } /* state.buf should not overflow! */ -static int state_open(int open_mode) +static int +state_open(int open_mode) { - char *buffer = state.buf, *mach = ""; - int len = 0; + char *buffer = state.buf, *mach = ""; + int len = 0; - if (state.busy) - return(-EBUSY); + if (state.busy) + return (-EBUSY); - state.ptr = 0; - state.busy = 1; + state.ptr = 0; + state.busy = 1; - switch (sound.mach.type) { + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - case DMASND_FALCON: - mach = "Atari "; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + case DMASND_FALCON: + mach = "Atari "; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - mach = "Amiga "; - break; -#endif /* CONFIG_AMIGA */ - } - len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); - - len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); - switch (sound.soft.format) { - case AFMT_MU_LAW: - len += sprintf(buffer+len, " (mu-law)"); - break; - case AFMT_A_LAW: - len += sprintf(buffer+len, " (A-law)"); - break; - case AFMT_U8: - len += sprintf(buffer+len, " (unsigned 8 bit)"); - break; - case AFMT_S8: - len += sprintf(buffer+len, " (signed 8 bit)"); - break; - case AFMT_S16_BE: - len += sprintf(buffer+len, " (signed 16 bit big)"); - break; - case AFMT_U16_BE: - len += sprintf(buffer+len, " (unsigned 16 bit big)"); - break; - case AFMT_S16_LE: - len += sprintf(buffer+len, " (signed 16 bit little)"); - break; - case AFMT_U16_LE: - len += sprintf(buffer+len, " (unsigned 16 bit little)"); - break; - } - len += sprintf(buffer+len, "\n"); - len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", - sound.soft.speed, sound.hard.speed); - len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", - sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); - switch (sound.mach.type) { + case DMASND_AMIGA: + mach = "Amiga "; + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer + len, "%sDMA sound driver:\n", mach); + + len += sprintf(buffer + len, "\tsound.format = 0x%x", sound.soft.format); + switch (sound.soft.format) + { + case AFMT_MU_LAW: + len += sprintf(buffer + len, " (mu-law)"); + break; + case AFMT_A_LAW: + len += sprintf(buffer + len, " (A-law)"); + break; + case AFMT_U8: + len += sprintf(buffer + len, " (unsigned 8 bit)"); + break; + case AFMT_S8: + len += sprintf(buffer + len, " (signed 8 bit)"); + break; + case AFMT_S16_BE: + len += sprintf(buffer + len, " (signed 16 bit big)"); + break; + case AFMT_U16_BE: + len += sprintf(buffer + len, " (unsigned 16 bit big)"); + break; + case AFMT_S16_LE: + len += sprintf(buffer + len, " (signed 16 bit little)"); + break; + case AFMT_U16_LE: + len += sprintf(buffer + len, " (unsigned 16 bit little)"); + break; + } + len += sprintf(buffer + len, "\n"); + len += sprintf(buffer + len, "\tsound.speed = %dHz (phys. %dHz)\n", + sound.soft.speed, sound.hard.speed); + len += sprintf(buffer + len, "\tsound.stereo = 0x%x (%s)\n", + sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); + switch (sound.mach.type) + { #ifdef CONFIG_ATARI - case DMASND_TT: - len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n", - sound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n", - sound.volume_right); - len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n", - sound.bass); - len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n", - sound.treble); - break; - case DMASND_FALCON: - len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n", - sound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n", - sound.volume_right); - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-40...0]\n", + sound.volume_left); + len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-40...0]\n", + sound.volume_right); + len += sprintf(buffer + len, "\tsound.bass = %ddB [-12...+12]\n", + sound.bass); + len += sprintf(buffer + len, "\tsound.treble = %ddB [-12...+12]\n", + sound.treble); + break; + case DMASND_FALCON: + len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-22.5...0]\n", + sound.volume_left); + len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-22.5...0]\n", + sound.volume_right); + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", - sound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", - sound.volume_right); - break; -#endif /* CONFIG_AMIGA */ - } - len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n", - sq.block_size, sq.max_count); - len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, - sq.rear_size); - len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n", - sq.playing, sq.syncing); - state.len = len; - return(0); + case DMASND_AMIGA: + len += sprintf(buffer + len, "\tsound.volume_left = %d [0...64]\n", + sound.volume_left); + len += sprintf(buffer + len, "\tsound.volume_right = %d [0...64]\n", + sound.volume_right); + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer + len, "\tsq.block_size = %d sq.max_count = %d\n", + sq.block_size, sq.max_count); + len += sprintf(buffer + len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, + sq.rear_size); + len += sprintf(buffer + len, "\tsq.playing = %d sq.syncing = %d\n", + sq.playing, sq.syncing); + state.len = len; + return (0); } -static int state_release(void) -{ - state.busy = 0; - return(0); +static int +state_release(void) +{ + state.busy = 0; + return (0); } -static long state_read(char *dest, unsigned long count) -{ - int n = state.len-state.ptr; - if (n > count) - n = count; - if (n <= 0) - return(0); - copy_to_user(dest, &state.buf[state.ptr], n); - state.ptr += n; - return(n); +static long +state_read(char *dest, unsigned long count) +{ + int n = state.len - state.ptr; + + if (n > count) + n = count; + if (n <= 0) + return (0); + copy_to_user(dest, &state.buf[state.ptr], n); + state.ptr += n; + return (n); } @@ -3033,231 +3359,241 @@ /*** High level stuff ********************************************************/ -static int sound_open(struct inode *inode, struct file *file) +static int +sound_open(struct inode *inode, struct file *file) { - int dev = MINOR(inode->i_rdev) & 0x0f; - int rc = 0; + int dev = MINOR(inode->i_rdev) & 0x0f; + int rc = 0; - switch (dev) { - case SND_DEV_STATUS: - rc = state_open(file->f_flags); - break; - case SND_DEV_CTL: - rc = mixer_open(file->f_flags); - break; - case SND_DEV_DSP: - case SND_DEV_AUDIO: - rc = sq_open(file->f_flags); - if (rc == 0) { - sound.minDev = dev; - sound.soft = sound.dsp; - sound.hard = sound.dsp; - sound_init(); - if (dev == SND_DEV_AUDIO) { - sound_set_speed(8000); - sound_set_stereo(0); - sound_set_format(AFMT_MU_LAW); - } - } - break; - default: - rc = -ENXIO; - } + switch (dev) + { + case SND_DEV_STATUS: + rc = state_open(file->f_flags); + break; + case SND_DEV_CTL: + rc = mixer_open(file->f_flags); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + rc = sq_open(file->f_flags); + if (rc == 0) + { + sound.minDev = dev; + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_init(); + if (dev == SND_DEV_AUDIO) + { + sound_set_speed(8000); + sound_set_stereo(0); + sound_set_format(AFMT_MU_LAW); + } + } + break; + default: + rc = -ENXIO; + } #ifdef MODULE - if (rc >= 0) - MOD_INC_USE_COUNT; + if (rc >= 0) + MOD_INC_USE_COUNT; #endif - return(rc); + return (rc); } -static int sound_fsync(struct inode *inode, struct file *filp) +static int +sound_fsync(struct inode *inode, struct file *filp) { - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = MINOR(inode->i_rdev) & 0x0f; - switch (dev) { - case SND_DEV_STATUS: - case SND_DEV_CTL: - return(0); - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return(sq_sync()); - default: - return(unknown_minor_dev("sound_fsync", dev)); - } + switch (dev) + { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return (0); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return (sq_sync()); + default: + return (unknown_minor_dev("sound_fsync", dev)); + } } -static void sound_release(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - - switch (dev & 0x0f) { - case SND_DEV_STATUS: - state_release(); - break; - case SND_DEV_CTL: - mixer_release(); - break; - case SND_DEV_DSP: - case SND_DEV_AUDIO: - sq_release(); - sound.soft = sound.dsp; - sound.hard = sound.dsp; - sound_silence(); - break; - default: - unknown_minor_dev("sound_release", dev); - return; - } +static void +sound_release(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + state_release(); + break; + case SND_DEV_CTL: + mixer_release(); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + sq_release(); + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_silence(); + break; + default: + unknown_minor_dev("sound_release", dev); + return; + } #ifdef MODULE - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #endif } -static long long sound_lseek(struct inode *inode, struct file *file, - long long offset, int orig) +static long long +sound_lseek(struct inode *inode, struct file *file, + long long offset, int orig) { - return -ESPIPE; + return -ESPIPE; } -static long sound_read(struct inode *inode, struct file *file, char *buf, - unsigned long count) +static ssize_t sound_read(struct file *file, char *buf, szie_t count, loff_t *ppos) { - int dev = MINOR(inode->i_rdev); + int dev = MINOR(file->f_dentry->d_inode->i_rdev); - switch (dev & 0x0f) { - case SND_DEV_STATUS: - return(state_read(buf, count)); - case SND_DEV_CTL: - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return(-EPERM); - default: - return(unknown_minor_dev("sound_read", dev)); - } + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return (state_read(buf, count)); + case SND_DEV_CTL: + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return (-EPERM); + default: + return (unknown_minor_dev("sound_read", dev)); + } } -static long sound_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int dev = MINOR(inode->i_rdev); + int dev = MINOR(file->f_dentry->d_inode->i_rdev); - switch (dev & 0x0f) { - case SND_DEV_STATUS: - case SND_DEV_CTL: - return(-EPERM); - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return(sq_write(buf, count)); - default: - return(unknown_minor_dev("sound_write", dev)); - } + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return (-EPERM); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return (sq_write(buf, count)); + default: + return (unknown_minor_dev("sound_write", dev)); + } } static int unknown_minor_dev(char *fname, int dev) { - /* printk("%s: Unknown minor device %d\n", fname, dev); */ - return(-ENXIO); + /* printk("%s: Unknown minor device %d\n", fname, dev); */ + return (-ENXIO); } -static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg) +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { - int dev = MINOR(inode->i_rdev); - u_long fmt; - int data; - - switch (dev & 0x0f) { - case SND_DEV_STATUS: - return(-EPERM); - case SND_DEV_CTL: - return(mixer_ioctl(inode, file, cmd, arg)); - case SND_DEV_AUDIO: - case SND_DEV_DSP: - switch (cmd) { - case SNDCTL_DSP_RESET: - sq_reset(); - return(0); - case SNDCTL_DSP_POST: - case SNDCTL_DSP_SYNC: - return(sound_fsync(inode, file)); - - /* ++TeSche: before changing any of these it's probably wise to - * wait until sound playing has settled down - */ - case SNDCTL_DSP_SPEED: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_speed(data))); - case SNDCTL_DSP_STEREO: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_stereo(data))); - case SOUND_PCM_WRITE_CHANNELS: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1)); - case SNDCTL_DSP_SETFMT: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return(IOCTL_OUT(arg, sound_set_format(data))); - case SNDCTL_DSP_GETFMTS: - fmt = 0; - if (sound.trans) { - if (sound.trans->ct_ulaw) - fmt |= AFMT_MU_LAW; - if (sound.trans->ct_alaw) - fmt |= AFMT_A_LAW; - if (sound.trans->ct_s8) - fmt |= AFMT_S8; - if (sound.trans->ct_u8) - fmt |= AFMT_U8; - if (sound.trans->ct_s16be) - fmt |= AFMT_S16_BE; - if (sound.trans->ct_u16be) - fmt |= AFMT_U16_BE; - if (sound.trans->ct_s16le) - fmt |= AFMT_S16_LE; - if (sound.trans->ct_u16le) - fmt |= AFMT_U16_LE; - } - return(IOCTL_OUT(arg, fmt)); - case SNDCTL_DSP_GETBLKSIZE: - return(IOCTL_OUT(arg, 10240)); - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - break; + int dev = MINOR(inode->i_rdev); + u_long fmt; + int data; + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return (-EPERM); + case SND_DEV_CTL: + return (mixer_ioctl(inode, file, cmd, arg)); + case SND_DEV_AUDIO: + case SND_DEV_DSP: + switch (cmd) + { + case SNDCTL_DSP_RESET: + sq_reset(); + return (0); + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + return (sound_fsync(inode, file)); + + /* ++TeSche: before changing any of these it's probably wise to + * wait until sound playing has settled down + */ + case SNDCTL_DSP_SPEED: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_speed(data))); + case SNDCTL_DSP_STEREO: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_stereo(data))); + case SOUND_PCM_WRITE_CHANNELS: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_stereo(data - 1) + 1)); + case SNDCTL_DSP_SETFMT: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return (IOCTL_OUT(arg, sound_set_format(data))); + case SNDCTL_DSP_GETFMTS: + fmt = 0; + if (sound.trans) + { + if (sound.trans->ct_ulaw) + fmt |= AFMT_MU_LAW; + if (sound.trans->ct_alaw) + fmt |= AFMT_A_LAW; + if (sound.trans->ct_s8) + fmt |= AFMT_S8; + if (sound.trans->ct_u8) + fmt |= AFMT_U8; + if (sound.trans->ct_s16be) + fmt |= AFMT_S16_BE; + if (sound.trans->ct_u16be) + fmt |= AFMT_U16_BE; + if (sound.trans->ct_s16le) + fmt |= AFMT_S16_LE; + if (sound.trans->ct_u16le) + fmt |= AFMT_U16_LE; + } + return (IOCTL_OUT(arg, fmt)); + case SNDCTL_DSP_GETBLKSIZE: + return (IOCTL_OUT(arg, 10240)); + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + break; + default: + return (mixer_ioctl(inode, file, cmd, arg)); + } + break; default: - return(mixer_ioctl(inode, file, cmd, arg)); - } - break; - - default: - return(unknown_minor_dev("sound_ioctl", dev)); - } - return(-EINVAL); + return (unknown_minor_dev("sound_ioctl", dev)); + } + return (-EINVAL); } static struct file_operations sound_fops = { - sound_lseek, - sound_read, - sound_write, - NULL, - NULL, /* select */ - sound_ioctl, - NULL, - sound_open, - sound_release, - sound_fsync + sound_lseek, + sound_read, + sound_write, + NULL, + NULL, /* select */ + sound_ioctl, + NULL, + sound_open, + sound_release, + sound_fsync }; @@ -3265,171 +3601,186 @@ /*** Config & Setup **********************************************************/ -void soundcard_init(void) +void +soundcard_init(void) { - int has_sound = 0; - int i; + int has_sound = 0; + int i; - switch (m68k_machtype) { + switch (m68k_machtype) + { #ifdef CONFIG_ATARI - case MACH_ATARI: - if (ATARIHW_PRESENT(PCM_8BIT)) { - if (ATARIHW_PRESENT(CODEC)) - sound.mach = machFalcon; - else if (ATARIHW_PRESENT(MICROWIRE)) - sound.mach = machTT; - else - break; - if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) - has_sound = 1; - else - printk("DMA sound driver: Timer A interrupt already in use\n"); - } - break; + case MACH_ATARI: + if (ATARIHW_PRESENT(PCM_8BIT)) + { + if (ATARIHW_PRESENT(CODEC)) + sound.mach = machFalcon; + else if (ATARIHW_PRESENT(MICROWIRE)) + sound.mach = machTT; + else + break; + if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) + has_sound = 1; + else + printk(KERN_ERR "DMA sound driver: Timer A interrupt already in use\n"); + } + break; -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case MACH_AMIGA: - if (AMIGAHW_PRESENT(AMI_AUDIO)) { - sound.mach = machAmiga; - has_sound = 1; - } - break; -#endif /* CONFIG_AMIGA */ - } - if (!has_sound) - return; + case MACH_AMIGA: + if (AMIGAHW_PRESENT(AMI_AUDIO)) + { + sound.mach = machAmiga; + has_sound = 1; + } + break; +#endif /* CONFIG_AMIGA */ + } + if (!has_sound) + return; - /* Set up sound queue, /dev/audio and /dev/dsp. */ - sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); - if (!sound_buffers) { + /* Set up sound queue, /dev/audio and /dev/dsp. */ + sound_buffers = kmalloc(numBufs * sizeof(char *), GFP_KERNEL); + + if (!sound_buffers) + { out_of_memory: - printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); - return; - } - for (i = 0; i < numBufs; i++) { - sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); - if (!sound_buffers[i]) { - while (i--) - sound.mach.dma_free (sound_buffers[i], bufSize << 10); - kfree (sound_buffers); - sound_buffers = 0; - goto out_of_memory; - } - } + printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); + return; + } + for (i = 0; i < numBufs; i++) + { + sound_buffers[i] = sound.mach.dma_alloc(bufSize << 10, GFP_KERNEL); + if (!sound_buffers[i]) + { + while (i--) + sound.mach.dma_free(sound_buffers[i], bufSize << 10); + kfree(sound_buffers); + sound_buffers = 0; + goto out_of_memory; + } + } #ifndef MODULE - /* Register driver with the VFS. */ - register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + /* Register driver with the VFS. */ + register_chrdev(SOUND_MAJOR, "sound", &sound_fops); #endif - sq_init(numBufs, bufSize << 10, sound_buffers); + sq_init(numBufs, bufSize << 10, sound_buffers); - /* Set up /dev/sndstat. */ - state_init(); + /* Set up /dev/sndstat. */ + state_init(); - /* Set up /dev/mixer. */ - mixer_init(); + /* Set up /dev/mixer. */ + mixer_init(); - if (!sound.mach.irqinit()) { - printk("DMA sound driver: Interrupt initialization failed\n"); - return; - } + if (!sound.mach.irqinit()) + { + printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); + return; + } #ifdef MODULE - irq_installed = 1; + irq_installed = 1; #endif - printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, - bufSize); + printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", numBufs, + bufSize); - return; + return; } void sound_setup(char *str, int *ints) { - /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ + /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ } #define MAXARGS 8 /* Should be sufficient for now */ -void dmasound_setup(char *str, int *ints) +void +dmasound_setup(char *str, int *ints) { - /* check the bootstrap parameter for "dmasound=" */ + /* check the bootstrap parameter for "dmasound=" */ - switch (ints[0]) { - case 3: - if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) - printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); - else - catchRadius = ints[3]; - /* fall through */ - case 2: - if (ints[1] < MIN_BUFFERS) - printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); - else - numBufs = ints[1]; - if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) - printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize); - else - bufSize = ints[2]; - break; - case 0: - break; - default: - printk("dmasound_setup: illegal number of arguments\n"); - } + switch (ints[0]) + { + case 3: + if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) + printk(KERN_WARNING "dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[3]; + /* fall through */ + case 2: + if (ints[1] < MIN_BUFFERS) + printk(KERN_WARNING "dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); + else + numBufs = ints[1]; + if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) + printk(KERN_WARNING "dmasound_setup: illegal buffer size, using default = %d\n", bufSize); + else + bufSize = ints[2]; + break; + case 0: + break; + default: + printk(KERN_WARNING "dmasound_setup: illegal number of arguments\n"); + } } #ifdef MODULE -static int dmasound[MAXARGS] = { 0 }; +static int dmasound[MAXARGS] = { + 0 +}; int init_module(void) { - int err, i = 0; - int ints[MAXARGS+1]; + int err, i = 0; + int ints[MAXARGS + 1]; - while (i < MAXARGS && dmasound[i]) - ints[i + 1] = dmasound[i++]; - ints[0] = i; - - if (i) - dmasound_setup("dmasound=", ints); - - err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); - if (err) { - printk("dmasound: driver already loaded/included in kernel\n"); - return err; - } - chrdev_registered = 1; - soundcard_init(); + while (i < MAXARGS && dmasound[i]) + ints[i + 1] = dmasound[i++]; + ints[0] = i; + + if (i) + dmasound_setup("dmasound=", ints); + + err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + if (err) + { + printk(KERN_ERR "dmasound: driver already loaded/included in kernel\n"); + return err; + } + chrdev_registered = 1; + soundcard_init(); - return 0; + return 0; } void cleanup_module(void) { - int i; + int i; - if (MOD_IN_USE) - return; - - if (chrdev_registered) - unregister_chrdev(SOUND_MAJOR, "sound"); + if (MOD_IN_USE) + return; - if (irq_installed) { - sound_silence(); - sound.mach.irqcleanup(); - } + if (chrdev_registered) + unregister_chrdev(SOUND_MAJOR, "sound"); - if (sound_buffers) { - for (i = 0; i < numBufs; i++) - sound.mach.dma_free(sound_buffers[i], bufSize << 10); - kfree(sound_buffers); - } + if (irq_installed) + { + sound_silence(); + sound.mach.irqcleanup(); + } + if (sound_buffers) + { + for (i = 0; i < numBufs; i++) + sound.mach.dma_free(sound_buffers[i], bufSize << 10); + kfree(sound_buffers); + } } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.66/linux/drivers/sound/gus_card.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/gus_card.c Sat Nov 29 10:33:20 1997 @@ -11,15 +11,16 @@ * for more info. */ #include - +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_GUSHW +#if defined(CONFIG_GUSHW) || defined(MODULE) #include "gus_hw.h" -void gusintr (int irq, void *dev_id, struct pt_regs *dummy); +void gusintr(int irq, void *dev_id, struct pt_regs *dummy); int gus_base = 0, gus_irq = 0, gus_dma = 0; extern int gus_wave_volume; @@ -28,142 +29,136 @@ int gus_pnp_flag = 0; void -attach_gus_card (struct address_info *hw_config) +attach_gus_card(struct address_info *hw_config) { - snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); + snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); - gus_wave_init (hw_config); + gus_wave_init(hw_config); - request_region (hw_config->io_base, 16, "GUS"); - request_region (hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ + request_region(hw_config->io_base, 16, "GUS"); + request_region(hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ - if (sound_alloc_dma (hw_config->dma, "GUS")) - printk ("gus_card.c: Can't allocate DMA channel\n"); - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - if (sound_alloc_dma (hw_config->dma2, "GUS(2)")) - printk ("gus_card.c: Can't allocate DMA channel2\n"); -#ifdef CONFIG_MIDI - gus_midi_init (); + if (sound_alloc_dma(hw_config->dma, "GUS")) + printk("gus_card.c: Can't allocate DMA channel\n"); + if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) + if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) + printk("gus_card.c: Can't allocate DMA channel 2\n"); +#if defined(CONFIG_MIDI) + gus_midi_init(hw_config); #endif } int -probe_gus (struct address_info *hw_config) +probe_gus(struct address_info *hw_config) { - int irq; - int io_addr; - - if (hw_config->card_subtype == 1) - gus_pnp_flag = 1; + int irq; + int io_addr; - irq = hw_config->irq; - - if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */ - if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && - irq != 11 && irq != 12 && irq != 15) - { - printk ("GUS: Unsupported IRQ %d\n", irq); - return 0; - } + if (hw_config->card_subtype == 1) + gus_pnp_flag = 1; - if (check_region (hw_config->io_base, 16)) - printk ("GUS: I/O range conflict (1)\n"); - else if (check_region (hw_config->io_base + 0x100, 16)) - printk ("GUS: I/O range conflict (2)\n"); - else if (gus_wave_detect (hw_config->io_base)) - return 1; + irq = hw_config->irq; + + if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */ + if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && + irq != 11 && irq != 12 && irq != 15) + { + printk("GUS: Unsupported IRQ %d\n", irq); + return 0; + } + if (check_region(hw_config->io_base, 16)) + printk("GUS: I/O range conflict (1)\n"); + else if (check_region(hw_config->io_base + 0x100, 16)) + printk("GUS: I/O range conflict (2)\n"); + else if (gus_wave_detect(hw_config->io_base)) + return 1; #ifndef EXCLUDE_GUS_IODETECT - /* - * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) - */ - - for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) - if (io_addr != hw_config->io_base) /* - * Already tested - */ - if (!check_region (io_addr, 16)) - if (!check_region (io_addr + 0x100, 16)) - if (gus_wave_detect (io_addr)) - { - hw_config->io_base = io_addr; - return 1; - } - + /* + * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) + */ + + for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) + if (io_addr != hw_config->io_base) /* + * Already tested + */ + if (!check_region(io_addr, 16)) + if (!check_region(io_addr + 0x100, 16)) + if (gus_wave_detect(io_addr)) + { + hw_config->io_base = io_addr; + return 1; + } #endif - return 0; + return 0; } void -unload_gus (struct address_info *hw_config) +unload_gus(struct address_info *hw_config) { - DDB (printk ("unload_gus(%x)\n", hw_config->io_base)); + DDB(printk("unload_gus(%x)\n", hw_config->io_base)); - gus_wave_unload (); + gus_wave_unload(hw_config); - release_region (hw_config->io_base, 16); - release_region (hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ - snd_release_irq (hw_config->irq); + release_region(hw_config->io_base, 16); + release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ + snd_release_irq(hw_config->irq); - sound_free_dma (hw_config->dma); + sound_free_dma(hw_config->dma); - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - sound_free_dma (hw_config->dma2); + if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) + sound_free_dma(hw_config->dma2); } void -gusintr (int irq, void *dev_id, struct pt_regs *dummy) +gusintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char src; - extern int gus_timer_enabled; + unsigned char src; + extern int gus_timer_enabled; - sti (); + sti(); #ifdef CONFIG_GUSMAX - if (have_gus_max) - adintr (irq, NULL, NULL); + if (have_gus_max) + adintr(irq, NULL, NULL); #endif - while (1) - { - if (!(src = inb (u_IrqStatus))) - return; - - if (src & DMA_TC_IRQ) - { - guswave_dma_irq (); - } - - if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) - { -#ifdef CONFIG_MIDI - gus_midi_interrupt (0); -#endif - } - - if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) - { -#ifdef CONFIG_SEQUENCER - if (gus_timer_enabled) - { - sound_timer_interrupt (); - } - - gus_write8 (0x45, 0); /* Ack IRQ */ - gus_timer_command (4, 0x80); /* Reset IRQ flags */ + while (1) + { + if (!(src = inb(u_IrqStatus))) + return; + + if (src & DMA_TC_IRQ) + { + guswave_dma_irq(); + } + if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) + { +#if defined(CONFIG_MIDI) + gus_midi_interrupt(0); +#endif + } + if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) + { +#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) + if (gus_timer_enabled) + { + sound_timer_interrupt(); + } + gus_write8(0x45, 0); /* Ack IRQ */ + gus_timer_command(4, 0x80); /* Reset IRQ flags */ #else - gus_write8 (0x45, 0); /* Stop timers */ + gus_write8(0x45, 0); /* Stop timers */ #endif - } - - if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) - { - gus_voice_irq (); - } - } + } + if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) + { + gus_voice_irq(); + } + } } #endif @@ -174,33 +169,100 @@ #ifdef CONFIG_GUS16 int -probe_gus_db16 (struct address_info *hw_config) +probe_gus_db16(struct address_info *hw_config) { - return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); + return ad1848_detect(hw_config->io_base, NULL, hw_config->osp); } void -attach_gus_db16 (struct address_info *hw_config) +attach_gus_db16(struct address_info *hw_config) { -#ifdef CONFIG_GUSHW - gus_pcm_volume = 100; - gus_wave_volume = 90; +#if defined(CONFIG_GUSHW) || defined(MODULE) + gus_pcm_volume = 100; + gus_wave_volume = 90; #endif - ad1848_init ("GUS 16 bit sampling", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0, - hw_config->osp); + hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, 0, + hw_config->osp); } void -unload_gus_db16 (struct address_info *hw_config) +unload_gus_db16(struct address_info *hw_config) { - ad1848_unload (hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, 0); + ad1848_unload(hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, 0); + sound_unload_audiodev(hw_config->slots[3]); } +#endif + +#ifdef MODULE + +static struct address_info config; + +/* + * Note DMA2 of -1 has the right meaning in the GUS driver as well + * as here. + */ + +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* 1 for PnP */ +int gus16 = 0; +static int db16 = 0; /* Has a Gus16 AD1848 on it */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(gus16, "i"); +MODULE_PARM(db16, "i"); + +int +init_module(void) +{ + printk("Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, IRQ, and DMA are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + config.card_subtype = type; + +#if defined(CONFIG_GUS16) + if (probe_gus_db16(&config) && gus16) + { + attach_gus_db16(&config); + db16 = 1; + } +#endif + if (probe_gus(&config) == 0) + return -ENODEV; + attach_gus_card(&config); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (db16) + unload_gus_db16(&config); + unload_gus(&config); + SOUND_LOCK_END; +} + #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.1.66/linux/drivers/sound/gus_midi.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/gus_midi.c Sat Nov 29 10:33:20 1997 @@ -17,8 +17,7 @@ #include "gus_hw.h" -#ifdef CONFIG_GUSHW -#ifdef CONFIG_MIDI +#if ( defined(CONFIG_GUSHW) && defined(CONFIG_MIDI) ) || defined (MODULE) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -34,183 +33,178 @@ extern int gus_base, gus_irq, gus_dma; extern int *gus_osp; -static int -GUS_MIDI_STATUS (void) +static int +GUS_MIDI_STATUS(void) { - return inb (u_MidiStatus); + return inb(u_MidiStatus); } static int -gus_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +gus_midi_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - if (midi_busy) - { - printk ("GUS: Midi busy\n"); - return -EBUSY; - } - - outb ((MIDI_RESET), u_MidiControl); - gus_delay (); - - gus_midi_control = 0; - input_opened = 0; - - if (mode == OPEN_READ || mode == OPEN_READWRITE) - if (!gus_pnp_flag) - { - gus_midi_control |= MIDI_ENABLE_RCV; - input_opened = 1; - } - - - outb ((gus_midi_control), u_MidiControl); /* Enable */ + if (midi_busy) + { + printk("GUS: Midi busy\n"); + return -EBUSY; + } + outb((MIDI_RESET), u_MidiControl); + gus_delay(); + + gus_midi_control = 0; + input_opened = 0; + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + if (!gus_pnp_flag) + { + gus_midi_control |= MIDI_ENABLE_RCV; + input_opened = 1; + } + outb((gus_midi_control), u_MidiControl); /* Enable */ + + midi_busy = 1; + qlen = qhead = qtail = output_used = 0; + midi_input_intr = input; - midi_busy = 1; - qlen = qhead = qtail = output_used = 0; - midi_input_intr = input; - - return 0; + return 0; } static int -dump_to_midi (unsigned char midi_byte) +dump_to_midi(unsigned char midi_byte) { - unsigned long flags; - int ok = 0; + unsigned long flags; + int ok = 0; - output_used = 1; + output_used = 1; - save_flags (flags); - cli (); - - if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY) - { - ok = 1; - outb ((midi_byte), u_MidiData); - } - else - { - /* - * Enable Midi xmit interrupts (again) - */ - gus_midi_control |= MIDI_ENABLE_XMIT; - outb ((gus_midi_control), u_MidiControl); - } + save_flags(flags); + cli(); + + if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) + { + ok = 1; + outb((midi_byte), u_MidiData); + } else + { + /* + * Enable Midi xmit interrupts (again) + */ + gus_midi_control |= MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + } - restore_flags (flags); - return ok; + restore_flags(flags); + return ok; } static void -gus_midi_close (int dev) +gus_midi_close(int dev) { - /* - * Reset FIFO pointers, disable intrs - */ + /* + * Reset FIFO pointers, disable intrs + */ - outb ((MIDI_RESET), u_MidiControl); - midi_busy = 0; + outb((MIDI_RESET), u_MidiControl); + midi_busy = 0; } static int -gus_midi_out (int dev, unsigned char midi_byte) +gus_midi_out(int dev, unsigned char midi_byte) { - unsigned long flags; + unsigned long flags; - /* - * Drain the local queue first - */ + /* + * Drain the local queue first + */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } - restore_flags (flags); + restore_flags(flags); - /* - * Output the byte if the local queue is empty. - */ + /* + * Output the byte if the local queue is empty. + */ - if (!qlen) - if (dump_to_midi (midi_byte)) - return 1; /* - * OK - */ + if (!qlen) + if (dump_to_midi(midi_byte)) + return 1; /* + * OK + */ - /* - * Put to the local queue - */ + /* + * Put to the local queue + */ - if (qlen >= 256) - return 0; /* + if (qlen >= 256) + return 0; /* * Local queue full */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; + tmp_queue[qtail] = midi_byte; + qlen++; + qtail++; - restore_flags (flags); + restore_flags(flags); - return 1; + return 1; } static int -gus_midi_start_read (int dev) +gus_midi_start_read(int dev) { - return 0; + return 0; } static int -gus_midi_end_read (int dev) +gus_midi_end_read(int dev) { - return 0; + return 0; } static int -gus_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +gus_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -gus_midi_kick (int dev) +gus_midi_kick(int dev) { } static int -gus_midi_buffer_status (int dev) +gus_midi_buffer_status(int dev) { - unsigned long flags; - - if (!output_used) - return 0; + unsigned long flags; - save_flags (flags); - cli (); + if (!output_used) + return 0; - if (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } + save_flags(flags); + cli(); - restore_flags (flags); + if (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } + restore_flags(flags); - return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY); + return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY); } #define MIDI_SYNTH_NAME "Gravis Ultrasound Midi" @@ -219,82 +213,81 @@ static struct midi_operations gus_midi_operations = { - {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, - &std_midi_synth, - {0}, - gus_midi_open, - gus_midi_close, - gus_midi_ioctl, - gus_midi_out, - gus_midi_start_read, - gus_midi_end_read, - gus_midi_kick, - NULL, /* + {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + &std_midi_synth, + {0}, + gus_midi_open, + gus_midi_close, + gus_midi_ioctl, + gus_midi_out, + gus_midi_start_read, + gus_midi_end_read, + gus_midi_kick, + NULL, /* * command */ - gus_midi_buffer_status, - NULL + gus_midi_buffer_status, + NULL }; void -gus_midi_init (void) +gus_midi_init(struct address_info *hw_config) { - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - outb ((MIDI_RESET), u_MidiControl); - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &gus_midi_operations; - sequencer_init (); - return; + int dev = sound_alloc_mididev(); + + if (dev == -1) + { + printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); + return; + } + outb((MIDI_RESET), u_MidiControl); + + std_midi_synth.midi_dev = my_dev = dev; + hw_config->slots[2] = dev; + midi_devs[dev] = &gus_midi_operations; + sequencer_init(); + return; } void -gus_midi_interrupt (int dummy) +gus_midi_interrupt(int dummy) { - volatile unsigned char stat, data; - unsigned long flags; - int timeout = 10; - - save_flags (flags); - cli (); - - while (timeout-- > 0 && (stat = GUS_MIDI_STATUS ()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) - { - if (stat & MIDI_RCV_FULL) - { - data = inb (u_MidiData); - if (input_opened) - midi_input_intr (my_dev, data); - } - - if (stat & MIDI_XMIT_EMPTY) - { - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - if (!qlen) - { - /* - * Disable Midi output interrupts, since no data in the buffer - */ - gus_midi_control &= ~MIDI_ENABLE_XMIT; - outb ((gus_midi_control), u_MidiControl); - outb ((gus_midi_control), u_MidiControl); - } - } - - } + volatile unsigned char stat, data; + unsigned long flags; + int timeout = 10; + + save_flags(flags); + cli(); + + while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) + { + if (stat & MIDI_RCV_FULL) + { + data = inb(u_MidiData); + if (input_opened) + midi_input_intr(my_dev, data); + } + if (stat & MIDI_XMIT_EMPTY) + { + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + if (!qlen) + { + /* + * Disable Midi output interrupts, since no data in the buffer + */ + gus_midi_control &= ~MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + outb((gus_midi_control), u_MidiControl); + } + } + } - restore_flags (flags); + restore_flags(flags); } -#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c --- v2.1.66/linux/drivers/sound/gus_vol.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/gus_vol.c Sat Nov 29 10:33:20 1997 @@ -1,3 +1,4 @@ + /* * gus_vol.c - Compute volume for GUS. */ @@ -11,7 +12,7 @@ #include #include "sound_config.h" -#ifdef CONFIG_GUSHW +#if defined(CONFIG_GUSHW) || defined(MODULE) #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume @@ -34,87 +35,85 @@ * basses. The normal value is 64. Strings are assigned lower values. */ unsigned short -gus_adagio_vol (int vel, int mainv, int xpn, int voicev) +gus_adagio_vol(int vel, int mainv, int xpn, int voicev) { - int i, m, n, x; + int i, m, n, x; - /* - * A voice volume of 64 is considered neutral, so adjust the main volume if - * something other than this neutral value was assigned in the patch - * library. - */ - x = 256 + 6 * (voicev - 64); - - /* - * Boost expression by voice volume above neutral. - */ - if (voicev > 65) - xpn += voicev - 64; - xpn += (voicev - 64) / 2; - - /* - * Combine multiplicative and level components. - */ - x = vel * xpn * 6 + (voicev / 4) * x; + /* + * A voice volume of 64 is considered neutral, so adjust the main volume if + * something other than this neutral value was assigned in the patch + * library. + */ + x = 256 + 6 * (voicev - 64); + + /* + * Boost expression by voice volume above neutral. + */ + if (voicev > 65) + xpn += voicev - 64; + xpn += (voicev - 64) / 2; + + /* + * Combine multiplicative and level components. + */ + x = vel * xpn * 6 + (voicev / 4) * x; #ifdef GUS_VOLUME - /* - * Further adjustment by installation-specific master volume control - * (default 60). - */ - x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; + /* + * Further adjustment by installation-specific master volume control + * (default 60). + */ + x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; #endif #ifdef GUS_USE_CHN_MAIN_VOLUME - /* - * Experimental support for the channel main volume - */ + /* + * Experimental support for the channel main volume + */ - mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ - x = (x * mainv * mainv) / 16384; + mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ + x = (x * mainv * mainv) / 16384; #endif - if (x < 2) - return (0); - else if (x >= 65535) - return ((15 << 8) | 255); - - /* - * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit - * mantissa m. - */ - n = x; - i = 7; - if (n < 128) - { - while (i > 0 && n < (1 << i)) - i--; - } - else - while (n > 255) - { - n >>= 1; - i++; - } - /* - * Mantissa is part of linear volume not expressed in exponent. (This is - * not quite like real logs -- I wonder if it's right.) - */ - m = x - (1 << i); - - /* - * Adjust mantissa to 8 bits. - */ - if (m > 0) - { - if (i > 8) - m >>= i - 8; - else if (i < 8) - m <<= 8 - i; - } - - return ((i << 8) + m); + if (x < 2) + return (0); + else if (x >= 65535) + return ((15 << 8) | 255); + + /* + * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit + * mantissa m. + */ + n = x; + i = 7; + if (n < 128) + { + while (i > 0 && n < (1 << i)) + i--; + } else + while (n > 255) + { + n >>= 1; + i++; + } + /* + * Mantissa is part of linear volume not expressed in exponent. (This is + * not quite like real logs -- I wonder if it's right.) + */ + m = x - (1 << i); + + /* + * Adjust mantissa to 8 bits. + */ + if (m > 0) + { + if (i > 8) + m >>= i - 8; + else if (i < 8) + m <<= 8 - i; + } + return ((i << 8) + m); } /* @@ -124,31 +123,31 @@ */ unsigned short -gus_linear_vol (int vol, int mainvol) +gus_linear_vol(int vol, int mainvol) { - int mixer_mainvol; + int mixer_mainvol; - if (vol <= 0) - vol = 0; - else if (vol >= 127) - vol = 127; + if (vol <= 0) + vol = 0; + else if (vol >= 127) + vol = 127; #ifdef GUS_VOLUME - mixer_mainvol = GUS_VOLUME; + mixer_mainvol = GUS_VOLUME; #else - mixer_mainvol = 100; + mixer_mainvol = 100; #endif #ifdef GUS_USE_CHN_MAIN_VOLUME - if (mainvol <= 0) - mainvol = 0; - else if (mainvol >= 127) - mainvol = 127; + if (mainvol <= 0) + mainvol = 0; + else if (mainvol >= 127) + mainvol = 127; #else - mainvol = 127; + mainvol = 127; #endif - return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; + return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.66/linux/drivers/sound/gus_wave.c Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/gus_wave.c Sat Nov 29 10:33:20 1997 @@ -19,7 +19,7 @@ #include #include "gus_hw.h" -#ifdef CONFIG_GUSHW +#if defined(CONFIG_GUSHW) || defined(MODULE) #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) @@ -30,38 +30,39 @@ struct voice_info { - unsigned long orig_freq; - unsigned long current_freq; - unsigned long mode; - int fixed_pitch; - int bender; - int bender_range; - int panning; - int midi_volume; - unsigned int initial_volume; - unsigned int current_volume; - int loop_irq_mode, loop_irq_parm; + unsigned long orig_freq; + unsigned long current_freq; + unsigned long mode; + int fixed_pitch; + int bender; + int bender_range; + int panning; + int midi_volume; + unsigned int initial_volume; + unsigned int current_volume; + int loop_irq_mode, loop_irq_parm; #define LMODE_FINISH 1 #define LMODE_PCM 2 #define LMODE_PCM_STOP 3 - int volume_irq_mode, volume_irq_parm; + int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 #define VMODE_START_NOTE 3 - int env_phase; - unsigned char env_rate[6]; - unsigned char env_offset[6]; - - /* - * Volume computation parameters for gus_adagio_vol() - */ - int main_vol, expression_vol, patch_vol; - - /* Variables for "Ultraclick" removal */ - int dev_pending, note_pending, volume_pending, sample_pending; - char kill_pending; - long offset_pending; + int env_phase; + unsigned char env_rate[6]; + unsigned char env_offset[6]; + + /* + * Volume computation parameters for gus_adagio_vol() + */ + int main_vol, expression_vol, patch_vol; + + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, + sample_pending; + char kill_pending; + long offset_pending; }; @@ -136,26 +137,26 @@ static int freq_div_table[] = { - 44100, - 44100, /* 14 */ - 41160, /* 15 */ - 38587, /* 16 */ - 36317, /* 17 */ - 34300, /* 18 */ - 32494, /* 19 */ - 30870, /* 20 */ - 29400, /* 21 */ - 28063, /* 22 */ - 26843, /* 23 */ - 25725, /* 24 */ - 24696, /* 25 */ - 23746, /* 26 */ - 22866, /* 27 */ - 22050, /* 28 */ - 21289, /* 29 */ - 20580, /* 30 */ - 19916, /* 31 */ - 19293 /* 32 */ + 44100, + 44100, /* 14 */ + 41160, /* 15 */ + 38587, /* 16 */ + 36317, /* 17 */ + 34300, /* 18 */ + 32494, /* 19 */ + 30870, /* 20 */ + 29400, /* 21 */ + 28063, /* 22 */ + 26843, /* 23 */ + 25725, /* 24 */ + 24696, /* 25 */ + 23746, /* 26 */ + 22866, /* 27 */ + 22050, /* 28 */ + 21289, /* 29 */ + 20580, /* 30 */ + 19916, /* 31 */ + 19293 /* 32 */ }; static struct patch_info *samples; @@ -171,722 +172,711 @@ static struct synth_info gus_info = {"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; -static void gus_poke (long addr, unsigned char data); -static void compute_and_set_volume (int voice, int volume, int ramp_time); -extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev); -extern unsigned short gus_linear_vol (int vol, int mainvol); -static void compute_volume (int voice, int volume); -static void do_volume_irq (int voice); -static void set_input_volumes (void); -static void gus_tmr_install (int io_base); +static void gus_poke(long addr, unsigned char data); +static void compute_and_set_volume(int voice, int volume, int ramp_time); +extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev); +extern unsigned short gus_linear_vol(int vol, int mainvol); +static void compute_volume(int voice, int volume); +static void do_volume_irq(int voice); +static void set_input_volumes(void); +static void gus_tmr_install(int io_base); #define INSTANT_RAMP -1 /* Instant change. No ramping */ #define FAST_RAMP 0 /* Fastest possible ramp */ static void -reset_sample_memory (void) +reset_sample_memory(void) { - int i; + int i; - for (i = 0; i <= MAX_SAMPLE; i++) - sample_ptrs[i] = -1; - for (i = 0; i < 32; i++) - sample_map[i] = -1; - for (i = 0; i < 32; i++) - patch_map[i] = -1; + for (i = 0; i <= MAX_SAMPLE; i++) + sample_ptrs[i] = -1; + for (i = 0; i < 32; i++) + sample_map[i] = -1; + for (i = 0; i < 32; i++) + patch_map[i] = -1; - gus_poke (0, 0); /* Put a silent sample to the beginning */ - gus_poke (1, 0); - free_mem_ptr = 2; + gus_poke(0, 0); /* Put a silent sample to the beginning */ + gus_poke(1, 0); + free_mem_ptr = 2; - free_sample = 0; + free_sample = 0; - for (i = 0; i < MAX_PATCH; i++) - patch_table[i] = NOT_SAMPLE; + for (i = 0; i < MAX_PATCH; i++) + patch_table[i] = NOT_SAMPLE; } void -gus_delay (void) +gus_delay(void) { - int i; + int i; - for (i = 0; i < 7; i++) - inb (u_DRAMIO); + for (i = 0; i < 7; i++) + inb(u_DRAMIO); } static void -gus_poke (long addr, unsigned char data) +gus_poke(long addr, unsigned char data) { /* Writes a byte to the DRAM */ - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - outb ((0x43), u_Command); - outb ((addr & 0xff), u_DataLo); - outb (((addr >> 8) & 0xff), u_DataHi); - - outb ((0x44), u_Command); - outb (((addr >> 16) & 0xff), u_DataHi); - outb ((data), u_DRAMIO); - restore_flags (flags); + save_flags(flags); + cli(); + outb((0x43), u_Command); + outb((addr & 0xff), u_DataLo); + outb(((addr >> 8) & 0xff), u_DataHi); + + outb((0x44), u_Command); + outb(((addr >> 16) & 0xff), u_DataHi); + outb((data), u_DRAMIO); + restore_flags(flags); } static unsigned char -gus_peek (long addr) +gus_peek(long addr) { /* Reads a byte from the DRAM */ - unsigned long flags; - unsigned char tmp; + unsigned long flags; + unsigned char tmp; - save_flags (flags); - cli (); - outb ((0x43), u_Command); - outb ((addr & 0xff), u_DataLo); - outb (((addr >> 8) & 0xff), u_DataHi); - - outb ((0x44), u_Command); - outb (((addr >> 16) & 0xff), u_DataHi); - tmp = inb (u_DRAMIO); - restore_flags (flags); + save_flags(flags); + cli(); + outb((0x43), u_Command); + outb((addr & 0xff), u_DataLo); + outb(((addr >> 8) & 0xff), u_DataHi); + + outb((0x44), u_Command); + outb(((addr >> 16) & 0xff), u_DataHi); + tmp = inb(u_DRAMIO); + restore_flags(flags); - return tmp; + return tmp; } void -gus_write8 (int reg, unsigned int data) +gus_write8(int reg, unsigned int data) { /* Writes to an indirect register (8 bit) */ - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg), u_Command); - outb (((unsigned char) (data & 0xff)), u_DataHi); + outb((reg), u_Command); + outb(((unsigned char) (data & 0xff)), u_DataHi); - restore_flags (flags); + restore_flags(flags); } static unsigned char -gus_read8 (int reg) +gus_read8(int reg) { /* Reads from an indirect register (8 bit). Offset 0x80. */ - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); - outb ((reg | 0x80), u_Command); - val = inb (u_DataHi); - restore_flags (flags); + save_flags(flags); + cli(); + outb((reg | 0x80), u_Command); + val = inb(u_DataHi); + restore_flags(flags); - return val; + return val; } static unsigned char -gus_look8 (int reg) +gus_look8(int reg) { /* Reads from an indirect register (8 bit). No additional offset. */ - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); - outb ((reg), u_Command); - val = inb (u_DataHi); - restore_flags (flags); + save_flags(flags); + cli(); + outb((reg), u_Command); + val = inb(u_DataHi); + restore_flags(flags); - return val; + return val; } static void -gus_write16 (int reg, unsigned int data) +gus_write16(int reg, unsigned int data) { /* Writes to an indirect register (16 bit) */ - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg), u_Command); + outb((reg), u_Command); - outb (((unsigned char) (data & 0xff)), u_DataLo); - outb (((unsigned char) ((data >> 8) & 0xff)), u_DataHi); + outb(((unsigned char) (data & 0xff)), u_DataLo); + outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi); - restore_flags (flags); + restore_flags(flags); } static unsigned short -gus_read16 (int reg) +gus_read16(int reg) { /* Reads from an indirect register (16 bit). Offset 0x80. */ - unsigned long flags; - unsigned char hi, lo; + unsigned long flags; + unsigned char hi, lo; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg | 0x80), u_Command); + outb((reg | 0x80), u_Command); - lo = inb (u_DataLo); - hi = inb (u_DataHi); + lo = inb(u_DataLo); + hi = inb(u_DataHi); - restore_flags (flags); + restore_flags(flags); - return ((hi << 8) & 0xff00) | lo; + return ((hi << 8) & 0xff00) | lo; } static unsigned short -gus_look16 (int reg) +gus_look16(int reg) { /* Reads from an indirect register (16 bit). No additional offset. */ - unsigned long flags; - unsigned char hi, lo; + unsigned long flags; + unsigned char hi, lo; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((reg), u_Command); + outb((reg), u_Command); - lo = inb (u_DataLo); - hi = inb (u_DataHi); + lo = inb(u_DataLo); + hi = inb(u_DataHi); - restore_flags (flags); + restore_flags(flags); - return ((hi << 8) & 0xff00) | lo; + return ((hi << 8) & 0xff00) | lo; } static void -gus_write_addr (int reg, unsigned long address, int frac, int is16bit) +gus_write_addr(int reg, unsigned long address, int frac, int is16bit) { /* Writes an 24 bit memory address */ - unsigned long hold_address; - unsigned long flags; - - save_flags (flags); - cli (); - if (is16bit) - { - if (iw_mode) - { - /* Interwave spesific address translations */ - address >>= 1; - } - else - { - /* - * Special processing required for 16 bit patches - */ + unsigned long hold_address; + unsigned long flags; - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - } - - gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) - + (frac << 5)); - /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ - gus_delay (); - gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) - + (frac << 5)); - restore_flags (flags); + save_flags(flags); + cli(); + if (is16bit) + { + if (iw_mode) + { + /* Interwave spesific address translations */ + address >>= 1; + } else + { + /* + * Special processing required for 16 bit patches + */ + + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + } + gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); + gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); + /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ + gus_delay(); + gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); + gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); + restore_flags(flags); } static void -gus_select_voice (int voice) +gus_select_voice(int voice) { - if (voice < 0 || voice > 31) - return; + if (voice < 0 || voice > 31) + return; - outb ((voice), u_Voice); + outb((voice), u_Voice); } static void -gus_select_max_voices (int nvoices) +gus_select_max_voices(int nvoices) { - if (iw_mode) - nvoices = 32; - if (nvoices < 14) - nvoices = 14; - if (nvoices > 32) - nvoices = 32; + if (iw_mode) + nvoices = 32; + if (nvoices < 14) + nvoices = 14; + if (nvoices > 32) + nvoices = 32; - voice_alloc->max_voice = nr_voices = nvoices; + voice_alloc->max_voice = nr_voices = nvoices; - gus_write8 (0x0e, (nvoices - 1) | 0xc0); + gus_write8(0x0e, (nvoices - 1) | 0xc0); } static void -gus_voice_on (unsigned int mode) +gus_voice_on(unsigned int mode) { - gus_write8 (0x00, (unsigned char) (mode & 0xfc)); - gus_delay (); - gus_write8 (0x00, (unsigned char) (mode & 0xfc)); + gus_write8(0x00, (unsigned char) (mode & 0xfc)); + gus_delay(); + gus_write8(0x00, (unsigned char) (mode & 0xfc)); } static void -gus_voice_off (void) +gus_voice_off(void) { - gus_write8 (0x00, gus_read8 (0x00) | 0x03); + gus_write8(0x00, gus_read8(0x00) | 0x03); } static void -gus_voice_mode (unsigned int m) +gus_voice_mode(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | - (mode & 0xfc)); /* Don't touch last two bits */ - gus_delay (); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); + gus_write8(0x00, (gus_read8(0x00) & 0x03) | + (mode & 0xfc)); /* Don't touch last two bits */ + gus_delay(); + gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc)); } static void -gus_voice_freq (unsigned long freq) +gus_voice_freq(unsigned long freq) { - unsigned long divisor = freq_div_table[nr_voices - 14]; - unsigned short fc; + unsigned long divisor = freq_div_table[nr_voices - 14]; + unsigned short fc; - /* Interwave plays at 44100 Hz with any number of voices */ - if (iw_mode) - fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); - else - fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); - fc = fc << 1; + /* Interwave plays at 44100 Hz with any number of voices */ + if (iw_mode) + fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); + else + fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); + fc = fc << 1; - gus_write16 (0x01, fc); + gus_write16(0x01, fc); } static void -gus_voice_volume (unsigned int vol) +gus_voice_volume(unsigned int vol) { - gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */ - gus_write16 (0x09, (unsigned short) (vol << 4)); + gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */ + gus_write16(0x09, (unsigned short) (vol << 4)); } static void -gus_voice_balance (unsigned int balance) +gus_voice_balance(unsigned int balance) { - gus_write8 (0x0c, (unsigned char) (balance & 0xff)); + gus_write8(0x0c, (unsigned char) (balance & 0xff)); } static void -gus_ramp_range (unsigned int low, unsigned int high) +gus_ramp_range(unsigned int low, unsigned int high) { - gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff)); - gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff)); + gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff)); + gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff)); } static void -gus_ramp_rate (unsigned int scale, unsigned int rate) +gus_ramp_rate(unsigned int scale, unsigned int rate) { - gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); + gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); } static void -gus_rampon (unsigned int m) +gus_rampon(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x0d, mode & 0xfc); - gus_delay (); - gus_write8 (0x0d, mode & 0xfc); + gus_write8(0x0d, mode & 0xfc); + gus_delay(); + gus_write8(0x0d, mode & 0xfc); } static void -gus_ramp_mode (unsigned int m) +gus_ramp_mode(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | - (mode & 0xfc)); /* Leave the last 2 bits alone */ - gus_delay (); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); + gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | + (mode & 0xfc)); /* Leave the last 2 bits alone */ + gus_delay(); + gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); } static void -gus_rampoff (void) +gus_rampoff(void) { - gus_write8 (0x0d, 0x03); + gus_write8(0x0d, 0x03); } static void -gus_set_voice_pos (int voice, long position) +gus_set_voice_pos(int voice, long position) { - int sample_no; + int sample_no; - if ((sample_no = sample_map[voice]) != -1) - if (position < samples[sample_no].len) - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - voices[voice].offset_pending = position; - else - gus_write_addr (0x0a, sample_ptrs[sample_no] + position, 0, - samples[sample_no].mode & WAVE_16_BITS); + if ((sample_no = sample_map[voice]) != -1) + if (position < samples[sample_no].len) + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].offset_pending = position; + else + gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0, + samples[sample_no].mode & WAVE_16_BITS); } static void -gus_voice_init (int voice) +gus_voice_init(int voice) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_volume (0); - gus_voice_off (); - gus_write_addr (0x0a, 0, 0, 0); /* Set current position to 0 */ - gus_write8 (0x00, 0x03); /* Voice off */ - gus_write8 (0x0d, 0x03); /* Ramping off */ - voice_alloc->map[voice] = 0; - voice_alloc->alloc_times[voice] = 0; - restore_flags (flags); + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(0); + gus_voice_off(); + gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */ + gus_write8(0x00, 0x03); /* Voice off */ + gus_write8(0x0d, 0x03); /* Ramping off */ + voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; + restore_flags(flags); } static void -gus_voice_init2 (int voice) +gus_voice_init2(int voice) { - voices[voice].panning = 0; - voices[voice].mode = 0; - voices[voice].orig_freq = 20000; - voices[voice].current_freq = 20000; - voices[voice].bender = 0; - voices[voice].bender_range = 200; - voices[voice].initial_volume = 0; - voices[voice].current_volume = 0; - voices[voice].loop_irq_mode = 0; - voices[voice].loop_irq_parm = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].volume_irq_parm = 0; - voices[voice].env_phase = 0; - voices[voice].main_vol = 127; - voices[voice].patch_vol = 127; - voices[voice].expression_vol = 127; - voices[voice].sample_pending = -1; - voices[voice].fixed_pitch = 0; + voices[voice].panning = 0; + voices[voice].mode = 0; + voices[voice].orig_freq = 20000; + voices[voice].current_freq = 20000; + voices[voice].bender = 0; + voices[voice].bender_range = 200; + voices[voice].initial_volume = 0; + voices[voice].current_volume = 0; + voices[voice].loop_irq_mode = 0; + voices[voice].loop_irq_parm = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].volume_irq_parm = 0; + voices[voice].env_phase = 0; + voices[voice].main_vol = 127; + voices[voice].patch_vol = 127; + voices[voice].expression_vol = 127; + voices[voice].sample_pending = -1; + voices[voice].fixed_pitch = 0; } static void -step_envelope (int voice) +step_envelope(int voice) { - unsigned vol, prev_vol, phase; - unsigned char rate; - long int flags; - - if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) - { - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_rampoff (); - restore_flags (flags); - return; - /* - * Sustain phase begins. Continue envelope after receiving note off. - */ - } - - if (voices[voice].env_phase >= 5) - { /* Envelope finished. Shoot the voice down */ - gus_voice_init (voice); - return; - } - - prev_vol = voices[voice].current_volume; - phase = ++voices[voice].env_phase; - compute_volume (voice, voices[voice].midi_volume); - vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; - rate = voices[voice].env_rate[phase]; + unsigned vol, prev_vol, phase; + unsigned char rate; + long int flags; - save_flags (flags); - cli (); - gus_select_voice (voice); + if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + return; + /* + * Sustain phase begins. Continue envelope after receiving note off. + */ + } + if (voices[voice].env_phase >= 5) + { /* Envelope finished. Shoot the voice down */ + gus_voice_init(voice); + return; + } + prev_vol = voices[voice].current_volume; + phase = ++voices[voice].env_phase; + compute_volume(voice, voices[voice].midi_volume); + vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; + rate = voices[voice].env_rate[phase]; - gus_voice_volume (prev_vol); + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(prev_vol); - gus_write8 (0x06, rate); /* Ramping rate */ - voices[voice].volume_irq_mode = VMODE_ENVELOPE; + gus_write8(0x06, rate); /* Ramping rate */ - if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ - { - restore_flags (flags); - step_envelope (voice); /* Continue the envelope on the next step */ - return; - } + voices[voice].volume_irq_mode = VMODE_ENVELOPE; - if (vol > prev_vol) - { - if (vol >= (4096 - 64)) - vol = 4096 - 65; - gus_ramp_range (0, vol); - gus_rampon (0x20); /* Increasing volume, with IRQ */ - } - else - { - if (vol <= 64) - vol = 65; - gus_ramp_range (vol, 4030); - gus_rampon (0x60); /* Decreasing volume, with IRQ */ - } - voices[voice].current_volume = vol; - restore_flags (flags); + if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ + { + restore_flags(flags); + step_envelope(voice); /* Continue the envelope on the next step */ + return; + } + if (vol > prev_vol) + { + if (vol >= (4096 - 64)) + vol = 4096 - 65; + gus_ramp_range(0, vol); + gus_rampon(0x20); /* Increasing volume, with IRQ */ + } else + { + if (vol <= 64) + vol = 65; + gus_ramp_range(vol, 4030); + gus_rampon(0x60); /* Decreasing volume, with IRQ */ + } + voices[voice].current_volume = vol; + restore_flags(flags); } static void -init_envelope (int voice) +init_envelope(int voice) { - voices[voice].env_phase = -1; - voices[voice].current_volume = 64; + voices[voice].env_phase = -1; + voices[voice].current_volume = 64; - step_envelope (voice); + step_envelope(voice); } static void -start_release (int voice, long int flags) +start_release(int voice, long int flags) { - if (gus_read8 (0x00) & 0x03) - return; /* Voice already stopped */ + if (gus_read8(0x00) & 0x03) + return; /* Voice already stopped */ - voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ + voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ - voices[voice].current_volume = - voices[voice].initial_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + voices[voice].current_volume = + voices[voice].initial_volume = + gus_read16(0x09) >> 4; /* Get current volume */ - voices[voice].mode &= ~WAVE_SUSTAIN_ON; - gus_rampoff (); - restore_flags (flags); - step_envelope (voice); + voices[voice].mode &= ~WAVE_SUSTAIN_ON; + gus_rampoff(); + restore_flags(flags); + step_envelope(voice); } static void -gus_voice_fade (int voice) +gus_voice_fade(int voice) { - int instr_no = sample_map[voice], is16bits; - long int flags; - - save_flags (flags); - cli (); - gus_select_voice (voice); - - if (instr_no < 0 || instr_no > MAX_SAMPLE) - { - gus_write8 (0x00, 0x03); /* Hard stop */ - voice_alloc->map[voice] = 0; - restore_flags (flags); - return; - } - - is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ + int instr_no = sample_map[voice], is16bits; + long int flags; - if (voices[voice].mode & WAVE_ENVELOPES) - { - start_release (voice, flags); - restore_flags (flags); - return; - } + save_flags(flags); + cli(); + gus_select_voice(voice); - /* - * Ramp the volume down but not too quickly. - */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* Get current volume */ - { - gus_voice_off (); - gus_rampoff (); - gus_voice_init (voice); - restore_flags (flags); - return; - } + if (instr_no < 0 || instr_no > MAX_SAMPLE) + { + gus_write8(0x00, 0x03); /* Hard stop */ + voice_alloc->map[voice] = 0; + restore_flags(flags); + return; + } + is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ - gus_ramp_range (65, 4030); - gus_ramp_rate (2, 4); - gus_rampon (0x40 | 0x20); /* Down, once, with IRQ */ - voices[voice].volume_irq_mode = VMODE_HALT; - restore_flags (flags); + if (voices[voice].mode & WAVE_ENVELOPES) + { + start_release(voice, flags); + restore_flags(flags); + return; + } + /* + * Ramp the volume down but not too quickly. + */ + if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */ + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + restore_flags(flags); + return; + } + gus_ramp_range(65, 4030); + gus_ramp_rate(2, 4); + gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */ + voices[voice].volume_irq_mode = VMODE_HALT; + restore_flags(flags); } static void -gus_reset (void) +gus_reset(void) { - int i; + int i; - gus_select_max_voices (24); - volume_base = 3071; - volume_scale = 4; - volume_method = VOL_METHOD_ADAGIO; + gus_select_max_voices(24); + volume_base = 3071; + volume_scale = 4; + volume_method = VOL_METHOD_ADAGIO; - for (i = 0; i < 32; i++) - { - gus_voice_init (i); /* Turn voice off */ - gus_voice_init2 (i); - } + for (i = 0; i < 32; i++) + { + gus_voice_init(i); /* Turn voice off */ + gus_voice_init2(i); + } } static void -gus_initialize (void) +gus_initialize(void) { - unsigned long flags; - unsigned char dma_image, irq_image, tmp; + unsigned long flags; + unsigned char dma_image, irq_image, tmp; - static unsigned char gus_irq_map[16] = - {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; + static unsigned char gus_irq_map[16] = + {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; - static unsigned char gus_dma_map[8] = - {0, 1, 0, 2, 0, 3, 4, 5}; + static unsigned char gus_dma_map[8] = + {0, 1, 0, 2, 0, 3, 4, 5}; + + save_flags(flags); + cli(); + gus_write8(0x4c, 0); /* Reset GF1 */ + gus_delay(); + gus_delay(); + + gus_write8(0x4c, 1); /* Release Reset */ + gus_delay(); + gus_delay(); - save_flags (flags); - cli (); - gus_write8 (0x4c, 0); /* Reset GF1 */ - gus_delay (); - gus_delay (); - - gus_write8 (0x4c, 1); /* Release Reset */ - gus_delay (); - gus_delay (); - - /* - * Clear all interrupts - */ - - gus_write8 (0x41, 0); /* DMA control */ - gus_write8 (0x45, 0); /* Timer control */ - gus_write8 (0x49, 0); /* Sample control */ - - gus_select_max_voices (24); - - inb (u_Status); /* Touch the status register */ + /* + * Clear all interrupts + */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_write8(0x41, 0); /* DMA control */ + gus_write8(0x45, 0); /* Timer control */ + gus_write8(0x49, 0); /* Sample control */ - gus_reset (); /* Resets all voices */ + gus_select_max_voices(24); - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + inb(u_Status); /* Touch the status register */ - gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - /* - * Set up for Digital ASIC - */ + gus_reset(); /* Resets all voices */ - outb ((0x05), gus_base + 0x0f); + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - mix_image |= 0x02; /* Disable line out (for a moment) */ - outb ((mix_image), u_Mixer); + gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */ - outb ((0x00), u_IRQDMAControl); + /* + * Set up for Digital ASIC + */ - outb ((0x00), gus_base + 0x0f); + outb((0x05), gus_base + 0x0f); - /* - * Now set up the DMA and IRQ interface - * - * The GUS supports two IRQs and two DMAs. - * - * Just one DMA channel is used. This prevents simultaneous ADC and DAC. - * Adding this support requires significant changes to the dmabuf.c, dsp.c - * and audio.c also. - */ + mix_image |= 0x02; /* Disable line out (for a moment) */ + outb((mix_image), u_Mixer); - irq_image = 0; - tmp = gus_irq_map[gus_irq]; - if (!gus_pnp_flag && !tmp) - printk ("Warning! GUS IRQ not selected\n"); - irq_image |= tmp; - irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ + outb((0x00), u_IRQDMAControl); - dual_dma_mode = 1; - if (gus_dma2 == gus_dma || gus_dma2 == -1) - { - dual_dma_mode = 0; - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + outb((0x00), gus_base + 0x0f); - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk ("Warning! GUS DMA not selected\n"); + /* + * Now set up the DMA and IRQ interface + * + * The GUS supports two IRQs and two DMAs. + * + * Just one DMA channel is used. This prevents simultaneous ADC and DAC. + * Adding this support requires significant changes to the dmabuf.c, dsp.c + * and audio.c also. + */ - dma_image |= tmp; - } - else - /* Setup dual DMA channel mode for GUS MAX */ - { - dma_image = gus_dma_map[gus_dma]; - if (!dma_image) - printk ("Warning! GUS DMA not selected\n"); + irq_image = 0; + tmp = gus_irq_map[gus_irq]; + if (!gus_pnp_flag && !tmp) + printk("Warning! GUS IRQ not selected\n"); + irq_image |= tmp; + irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ - tmp = gus_dma_map[gus_dma2] << 3; - if (!tmp) - { - printk ("Warning! Invalid GUS MAX DMA\n"); - tmp = 0x40; /* Combine DMA channels */ - dual_dma_mode = 0; - } + dual_dma_mode = 1; + if (gus_dma2 == gus_dma || gus_dma2 == -1) + { + dual_dma_mode = 0; + dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - dma_image |= tmp; - } + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk("Warning! GUS DMA not selected\n"); + + dma_image |= tmp; + } else + /* Setup dual DMA channel mode for GUS MAX */ + { + dma_image = gus_dma_map[gus_dma]; + if (!dma_image) + printk("Warning! GUS DMA not selected\n"); + + tmp = gus_dma_map[gus_dma2] << 3; + if (!tmp) + { + printk("Warning! Invalid GUS MAX DMA\n"); + tmp = 0x40; /* Combine DMA channels */ + dual_dma_mode = 0; + } + dma_image |= tmp; + } - /* - * For some reason the IRQ and DMA addresses must be written twice - */ + /* + * For some reason the IRQ and DMA addresses must be written twice + */ - /* - * Doing it first time - */ + /* + * Doing it first time + */ - outb ((mix_image), u_Mixer); /* Select DMA control */ - outb ((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */ + outb((mix_image), u_Mixer); /* Select DMA control */ + outb((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */ - outb ((mix_image | 0x40), u_Mixer); /* Select IRQ control */ - outb ((irq_image), u_IRQDMAControl); /* Set IRQ address */ + outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */ + outb((irq_image), u_IRQDMAControl); /* Set IRQ address */ - /* - * Doing it second time - */ + /* + * Doing it second time + */ - outb ((mix_image), u_Mixer); /* Select DMA control */ - outb ((dma_image), u_IRQDMAControl); /* Set DMA address */ + outb((mix_image), u_Mixer); /* Select DMA control */ + outb((dma_image), u_IRQDMAControl); /* Set DMA address */ - outb ((mix_image | 0x40), u_Mixer); /* Select IRQ control */ - outb ((irq_image), u_IRQDMAControl); /* Set IRQ address */ + outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */ + outb((irq_image), u_IRQDMAControl); /* Set IRQ address */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - mix_image &= ~0x02; /* Enable line out */ - mix_image |= 0x08; /* Enable IRQ */ - outb ((mix_image), u_Mixer); /* - * Turn mixer channels on - * Note! Mic in is left off. - */ + mix_image &= ~0x02; /* Enable line out */ + mix_image |= 0x08; /* Enable IRQ */ + outb((mix_image), u_Mixer); /* + * Turn mixer channels on + * Note! Mic in is left off. + */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + gusintr(gus_irq, NULL, NULL); /* Serve pending interrupts */ - inb (u_Status); /* Touch the status register */ + inb(u_Status); /* Touch the status register */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - if (iw_mode) - gus_write8 (0x19, gus_read8 (0x19) | 0x01); - restore_flags (flags); + if (iw_mode) + gus_write8(0x19, gus_read8(0x19) | 0x01); + restore_flags(flags); } static void -pnp_mem_init (void) +pnp_mem_init(void) { #include "iwmem.h" #define CHUNK_SIZE (256*1024) #define BANK_SIZE (4*1024*1024) #define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) - int bank, chunk, addr, total = 0; - int bank_sizes[4]; - int i, j, bits = -1, nbanks = 0; + int bank, chunk, addr, total = 0; + int bank_sizes[4]; + int i, j, bits = -1, nbanks = 0; /* * This routine determines what kind of RAM is installed in each of the four @@ -896,68 +886,68 @@ /* * Place the chip into enhanced mode */ - gus_write8 (0x19, gus_read8 (0x19) | 0x01); - gus_write8 (0x53, gus_look8 (0x53) & ~0x02); /* Select DRAM I/O access */ + gus_write8(0x19, gus_read8(0x19) | 0x01); + gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */ /* * Set memory configuration to 4 DRAM banks of 4M in each (16M total). */ - gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | 0x000c); + gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c); /* * Perform the DRAM size detection for each bank individually. */ - for (bank = 0; bank < 4; bank++) - { - int size = 0; - - addr = bank * BANK_SIZE; - - /* Clean check points of each chunk */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - /* Write a value to each chunk point and verify the result */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x55); - gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0xAA); - - if (gus_peek (addr + chunk * CHUNK_SIZE + 0L) == 0x55 && - gus_peek (addr + chunk * CHUNK_SIZE + 1L) == 0xAA) - { /* OK. There is RAM. Now check for possible shadows */ - int ok = 1, chunk2; - - for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) - if (gus_peek (addr + chunk2 * CHUNK_SIZE + 0L) || - gus_peek (addr + chunk2 * CHUNK_SIZE + 1L)) - ok = 0; /* Addressing wraps */ - - if (ok) - size = (chunk + 1) * CHUNK_SIZE; - } - gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - bank_sizes[bank] = size; - if (size) - nbanks = bank + 1; - DDB (printk ("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); - } - - if (nbanks == 0) /* No RAM - Give up */ - { - printk ("Sound: An Interwave audio chip detected but no DRAM\n"); - printk ("Sound: Unable to work with this card.\n"); - gus_write8 (0x19, gus_read8 (0x19) & ~0x01); - gus_mem_size = 0; - return; - } + for (bank = 0; bank < 4; bank++) + { + int size = 0; + + addr = bank * BANK_SIZE; + + /* Clean check points of each chunk */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + /* Write a value to each chunk point and verify the result */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); + + if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && + gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA) + { /* OK. There is RAM. Now check for possible shadows */ + int ok = 1, chunk2; + + for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) + if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || + gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) + ok = 0; /* Addressing wraps */ + + if (ok) + size = (chunk + 1) * CHUNK_SIZE; + } + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + bank_sizes[bank] = size; + if (size) + nbanks = bank + 1; + DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); + } + + if (nbanks == 0) /* No RAM - Give up */ + { + printk("Sound: An Interwave audio chip detected but no DRAM\n"); + printk("Sound: Unable to work with this card.\n"); + gus_write8(0x19, gus_read8(0x19) & ~0x01); + gus_mem_size = 0; + return; + } /* * Now we know how much DRAM there is in each bank. The next step is * to find a DRAM size encoding (0 to 12) which is best for the combination @@ -967,665 +957,640 @@ * of memory we have. */ - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < 4; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < 4; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } /* * If necessary, try to find a combination where other than the last * bank matches our configuration and the last bank is left oversized. * In this way we don't leave holes in the middle of memory. */ - if (bits == -1) /* No luck yet */ - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) - bits = -1; /* The last bank is too small */ - } - + if (bits == -1) /* No luck yet */ + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) + bits = -1; /* The last bank is too small */ + } /* * The last resort is to search for a combination where the last bank is * smaller than the actual SIMM. This leaves some memory in the last bank * unused but doesn't leave holes in the DRAM address space. */ - if (bits == -1) /* No luck yet */ - { - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } - - if (bits != -1) - { - printk ("Interwave: Can't use all installed RAM.\n"); - printk ("Interwave: Try reordering SIMMS.\n"); - } - } - - if (bits == -1) - { - printk ("Interwave: Can't find working DRAM encoding.\n"); - printk ("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); - bits = 0; - } - - DDB (printk ("Interwave: Selecting DRAM addressing mode %d\n", bits)); - - for (bank = 0; bank < 4; bank++) - { - DDB (printk (" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); - - if (bank_sizes[bank] > mem_decode[bits][bank]) - total += mem_decode[bits][bank]; - else - total += bank_sizes[bank]; - } + if (bits == -1) /* No luck yet */ + { + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + + if (bits != -1) + { + printk("Interwave: Can't use all installed RAM.\n"); + printk("Interwave: Try reordering SIMMS.\n"); + } + } + if (bits == -1) + { + printk("Interwave: Can't find working DRAM encoding.\n"); + printk("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); + bits = 0; + } + DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits)); + + for (bank = 0; bank < 4; bank++) + { + DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); + + if (bank_sizes[bank] > mem_decode[bits][bank]) + total += mem_decode[bits][bank]; + else + total += bank_sizes[bank]; + } - DDB (printk ("Total %dk of DRAM (enhanced mode)\n", total / 1024)); + DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024)); /* * Set the memory addressing mode. */ - gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits); + gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits); /* Leave the chip into enhanced mode. Disable LFO */ - gus_mem_size = total; - iw_mode = 1; - gus_write8 (0x19, (gus_read8 (0x19) | 0x01) & ~0x02); + gus_mem_size = total; + iw_mode = 1; + gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02); } int -gus_wave_detect (int baseaddr) +gus_wave_detect(int baseaddr) { - unsigned long i, max_mem = 1024L; - unsigned long loc; - unsigned char val; + unsigned long i, max_mem = 1024L; + unsigned long loc; + unsigned char val; - gus_base = baseaddr; + gus_base = baseaddr; - gus_write8 (0x4c, 0); /* Reset GF1 */ - gus_delay (); - gus_delay (); + gus_write8(0x4c, 0); /* Reset GF1 */ + gus_delay(); + gus_delay(); - gus_write8 (0x4c, 1); /* Release Reset */ - gus_delay (); - gus_delay (); + gus_write8(0x4c, 1); /* Release Reset */ + gus_delay(); + gus_delay(); #ifdef GUSPNP_AUTODETECT - val = gus_look8 (0x5b); /* Version number register */ - gus_write8 (0x5b, ~val); /* Invert all bits */ + val = gus_look8(0x5b); /* Version number register */ + gus_write8(0x5b, ~val); /* Invert all bits */ - if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0)) /* No change */ - if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ - { - DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); - gus_pnp_flag = 1; - } - else - { - DDB (printk ("Not an Interwave chip (%x)\n", gus_look8 (0x5b))); - gus_pnp_flag = 0; - } - gus_write8 (0x5b, val); /* Restore all bits */ + if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */ + if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ + { + DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); + gus_pnp_flag = 1; + } else + { + DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); + gus_pnp_flag = 0; + } + gus_write8(0x5b, val); /* Restore all bits */ #endif - if (gus_pnp_flag) - pnp_mem_init (); - if (iw_mode) - return 1; - - /* See if there is first block there.... */ - gus_poke (0L, 0xaa); - if (gus_peek (0L) != 0xaa) - return (0); - - /* Now zero it out so that I can check for mirroring .. */ - gus_poke (0L, 0x00); - for (i = 1L; i < max_mem; i++) - { - int n, failed; - - /* check for mirroring ... */ - if (gus_peek (0L) != 0) - break; - loc = i << 10; - - for (n = loc - 1, failed = 0; n <= loc; n++) - { - gus_poke (loc, 0xaa); - if (gus_peek (loc) != 0xaa) - failed = 1; - - gus_poke (loc, 0x55); - if (gus_peek (loc) != 0x55) - failed = 1; - } - - if (failed) - break; - } - gus_mem_size = i << 10; - return 1; + if (gus_pnp_flag) + pnp_mem_init(); + if (iw_mode) + return 1; + + /* See if there is first block there.... */ + gus_poke(0L, 0xaa); + if (gus_peek(0L) != 0xaa) + return (0); + + /* Now zero it out so that I can check for mirroring .. */ + gus_poke(0L, 0x00); + for (i = 1L; i < max_mem; i++) + { + int n, failed; + + /* check for mirroring ... */ + if (gus_peek(0L) != 0) + break; + loc = i << 10; + + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke(loc, 0xaa); + if (gus_peek(loc) != 0xaa) + failed = 1; + + gus_poke(loc, 0x55); + if (gus_peek(loc) != 0x55) + failed = 1; + } + + if (failed) + break; + } + gus_mem_size = i << 10; + return 1; } static int -guswave_ioctl (int dev, - unsigned int cmd, caddr_t arg) +guswave_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - switch (cmd) - { - case SNDCTL_SYNTH_INFO: - gus_info.nr_voices = nr_voices; - memcpy ((&((char *) arg)[0]), (char *) &gus_info, sizeof (gus_info)); - return 0; - break; - - case SNDCTL_SEQ_RESETSAMPLES: - reset_sample_memory (); - return 0; - break; - - case SNDCTL_SEQ_PERCMODE: - return 0; - break; - - case SNDCTL_SYNTH_MEMAVL: - return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; - - default: - return -EINVAL; - } + switch (cmd) + { + case SNDCTL_SYNTH_INFO: + gus_info.nr_voices = nr_voices; + memcpy((&((char *) arg)[0]), (char *) &gus_info, sizeof(gus_info)); + return 0; + break; + + case SNDCTL_SEQ_RESETSAMPLES: + reset_sample_memory(); + return 0; + break; + + case SNDCTL_SEQ_PERCMODE: + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; + + default: + return -EINVAL; + } } static int -guswave_set_instr (int dev, int voice, int instr_no) +guswave_set_instr(int dev, int voice, int instr_no) { - int sample_no; + int sample_no; - if (instr_no < 0 || instr_no > MAX_PATCH) - instr_no = 0; /* Default to acoustic piano */ + if (instr_no < 0 || instr_no > MAX_PATCH) + instr_no = 0; /* Default to acoustic piano */ - if (voice < 0 || voice > 31) - return -EINVAL; - - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].sample_pending = instr_no; - return 0; - } - - sample_no = patch_table[instr_no]; - patch_map[voice] = -1; - - if (sample_no == NOT_SAMPLE) - { - printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return -EINVAL; /* Patch not defined */ - } - - if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ - { - printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); - return -EINVAL; - } - - sample_map[voice] = sample_no; - patch_map[voice] = instr_no; - return 0; + if (voice < 0 || voice > 31) + return -EINVAL; + + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].sample_pending = instr_no; + return 0; + } + sample_no = patch_table[instr_no]; + patch_map[voice] = -1; + + if (sample_no == NOT_SAMPLE) + { + printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice); + return -EINVAL; /* Patch not defined */ + } + if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ + { + printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); + return -EINVAL; + } + sample_map[voice] = sample_no; + patch_map[voice] = instr_no; + return 0; } static int -guswave_kill_note (int dev, int voice, int note, int velocity) +guswave_kill_note(int dev, int voice, int note, int velocity) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - /* voice_alloc->map[voice] = 0xffff; */ - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].kill_pending = 1; - restore_flags (flags); - } - else - { - restore_flags (flags); - gus_voice_fade (voice); - } + save_flags(flags); + cli(); + /* voice_alloc->map[voice] = 0xffff; */ + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].kill_pending = 1; + restore_flags(flags); + } else + { + restore_flags(flags); + gus_voice_fade(voice); + } - restore_flags (flags); - return 0; + restore_flags(flags); + return 0; } static void -guswave_aftertouch (int dev, int voice, int pressure) +guswave_aftertouch(int dev, int voice, int pressure) { } static void -guswave_panning (int dev, int voice, int value) +guswave_panning(int dev, int voice, int value) { - if (voice >= 0 || voice < 32) - voices[voice].panning = value; + if (voice >= 0 || voice < 32) + voices[voice].panning = value; } static void -guswave_volume_method (int dev, int mode) +guswave_volume_method(int dev, int mode) { - if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) - volume_method = mode; + if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) + volume_method = mode; } static void -compute_volume (int voice, int volume) +compute_volume(int voice, int volume) { - if (volume < 128) - voices[voice].midi_volume = volume; - - switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; + if (volume < 128) + voices[voice].midi_volume = volume; - case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ - voices[voice].initial_volume = - gus_linear_vol (volume, voices[voice].main_vol); - break; + switch (volume_method) + { + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; + + case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ + voices[voice].initial_volume = + gus_linear_vol(volume, voices[voice].main_vol); + break; - default: - voices[voice].initial_volume = volume_base + - (voices[voice].midi_volume * volume_scale); - } + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); + } - if (voices[voice].initial_volume > 4030) - voices[voice].initial_volume = 4030; + if (voices[voice].initial_volume > 4030) + voices[voice].initial_volume = 4030; } static void -compute_and_set_volume (int voice, int volume, int ramp_time) +compute_and_set_volume(int voice, int volume, int ramp_time) { - int curr, target, rate; - unsigned long flags; - - compute_volume (voice, volume); - voices[voice].current_volume = voices[voice].initial_volume; + int curr, target, rate; + unsigned long flags; - save_flags (flags); - cli (); - /* - * CAUTION! Interrupts disabled. Enable them before returning - */ + compute_volume(voice, volume); + voices[voice].current_volume = voices[voice].initial_volume; - gus_select_voice (voice); - - curr = gus_read16 (0x09) >> 4; - target = voices[voice].initial_volume; + save_flags(flags); + cli(); + /* + * CAUTION! Interrupts disabled. Enable them before returning + */ - if (ramp_time == INSTANT_RAMP) - { - gus_rampoff (); - gus_voice_volume (target); - restore_flags (flags); - return; - } + gus_select_voice(voice); - if (ramp_time == FAST_RAMP) - rate = 63; - else - rate = 16; - gus_ramp_rate (0, rate); + curr = gus_read16(0x09) >> 4; + target = voices[voice].initial_volume; - if ((target - curr) / 64 == 0) /* Close enough to target. */ - { - gus_rampoff (); - gus_voice_volume (target); - restore_flags (flags); - return; - } + if (ramp_time == INSTANT_RAMP) + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } + if (ramp_time == FAST_RAMP) + rate = 63; + else + rate = 16; + gus_ramp_rate(0, rate); - if (target > curr) - { - if (target > (4095 - 65)) - target = 4095 - 65; - gus_ramp_range (curr, target); - gus_rampon (0x00); /* Ramp up, once, no IRQ */ - } - else - { - if (target < 65) - target = 65; + if ((target - curr) / 64 == 0) /* Close enough to target. */ + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } + if (target > curr) + { + if (target > (4095 - 65)) + target = 4095 - 65; + gus_ramp_range(curr, target); + gus_rampon(0x00); /* Ramp up, once, no IRQ */ + } else + { + if (target < 65) + target = 65; - gus_ramp_range (target, curr); - gus_rampon (0x40); /* Ramp down, once, no irq */ - } - restore_flags (flags); + gus_ramp_range(target, curr); + gus_rampon(0x40); /* Ramp down, once, no irq */ + } + restore_flags(flags); } static void -dynamic_volume_change (int voice) +dynamic_volume_change(int voice) { - unsigned char status; - unsigned long flags; + unsigned char status; + unsigned long flags; + + save_flags(flags); + cli(); + gus_select_voice(voice); + status = gus_read8(0x00); /* Get voice status */ + restore_flags(flags); + + if (status & 0x03) + return; /* Voice was not running */ + + if (!(voices[voice].mode & WAVE_ENVELOPES)) + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + /* + * Voice is running and has envelopes. + */ - save_flags (flags); - cli (); - gus_select_voice (voice); - status = gus_read8 (0x00); /* Get voice status */ - restore_flags (flags); + save_flags(flags); + cli(); + gus_select_voice(voice); + status = gus_read8(0x0d); /* Ramping status */ + restore_flags(flags); - if (status & 0x03) - return; /* Voice was not running */ + if (status & 0x03) /* Sustain phase? */ + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + if (voices[voice].env_phase < 0) + return; - if (!(voices[voice].mode & WAVE_ENVELOPES)) - { - compute_and_set_volume (voice, voices[voice].midi_volume, 1); - return; - } + compute_volume(voice, voices[voice].midi_volume); - /* - * Voice is running and has envelopes. - */ +} - save_flags (flags); - cli (); - gus_select_voice (voice); - status = gus_read8 (0x0d); /* Ramping status */ - restore_flags (flags); +static void +guswave_controller(int dev, int voice, int ctrl_num, int value) +{ + unsigned long flags; + unsigned long freq; - if (status & 0x03) /* Sustain phase? */ - { - compute_and_set_volume (voice, voices[voice].midi_volume, 1); - return; - } + if (voice < 0 || voice > 31) + return; - if (voices[voice].env_phase < 0) - return; + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; - compute_volume (voice, voices[voice].midi_volume); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune(voices[voice].orig_freq, value, + voices[voice].bender_range, 0); + voices[voice].current_freq = freq; + + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(freq); + restore_flags(flags); + } + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + if (volume_method == VOL_METHOD_ADAGIO) + { + voices[voice].expression_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + } + break; + + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + voices[voice].main_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + break; + default: + break; + } } -static void -guswave_controller (int dev, int voice, int ctrl_num, int value) +static int +guswave_start_note2(int dev, int voice, int note_num, int volume) { - unsigned long flags; - unsigned long freq; + int sample, best_sample, best_delta, delta_freq; + int is16bits, samplep, patch, pan; + unsigned long note_freq, base_note, freq, flags; + unsigned char mode = 0; - if (voice < 0 || voice > 31) - return; + if (voice < 0 || voice > 31) + { + printk("GUS: Invalid voice\n"); + return -EINVAL; + } + if (note_num == 255) + { + if (voices[voice].mode & WAVE_ENVELOPES) + { + voices[voice].midi_volume = volume; + dynamic_volume_change(voice); + return 0; + } + compute_and_set_volume(voice, volume, 1); + return 0; + } + if ((patch = patch_map[voice]) == -1) + { + return -EINVAL; + } + if ((samplep = patch_table[patch]) == NOT_SAMPLE) + { + return -EINVAL; + } + note_freq = note_to_freq(note_num); - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - voices[voice].bender = value; + /* + * Find a sample within a patch so that the note_freq is between low_note + * and high_note. + */ + sample = -1; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - { - freq = compute_finetune (voices[voice].orig_freq, value, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; + best_sample = samplep; + best_delta = 1000000; + while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) + { + delta_freq = note_freq - samples[samplep].base_note; + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = samplep; + best_delta = delta_freq; + } + if (samples[samplep].low_note <= note_freq && + note_freq <= samples[samplep].high_note) + sample = samplep; + else + samplep = samples[samplep].key; /* Link to next sample */ + } + if (sample == -1) + sample = best_sample; - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_freq (freq); - restore_flags (flags); - } - break; + if (sample == -1) + { + printk("GUS: Patch %d not defined for note %d\n", patch, note_num); + return 0; /* Should play default patch ??? */ + } + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; + voices[voice].mode = samples[sample].mode; + voices[voice].patch_vol = samples[sample].volume; - case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - if (volume_method == VOL_METHOD_ADAGIO) - { - voices[voice].expression_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change (voice); - } - break; + if (iw_mode) + gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ - case CTL_PAN: - voices[voice].panning = (value * 2) - 128; - break; + if (voices[voice].mode & WAVE_ENVELOPES) + { + int i; - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; + for (i = 0; i < 6; i++) + { + voices[voice].env_rate[i] = samples[sample].env_rate[i]; + voices[voice].env_offset[i] = samples[sample].env_offset[i]; + } + } + sample_map[voice] = sample; - case CTRL_MAIN_VOLUME: - voices[voice].main_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change (voice); - break; + if (voices[voice].fixed_pitch) /* Fixed pitch */ + { + freq = samples[sample].base_freq; + } else + { + base_note = samples[sample].base_note / 100; + note_freq /= 100; - default: - break; - } -} + freq = samples[sample].base_freq * note_freq / base_note; + } -static int -guswave_start_note2 (int dev, int voice, int note_num, int volume) -{ - int sample, best_sample, best_delta, delta_freq; - int is16bits, samplep, patch, pan; - unsigned long note_freq, base_note, freq, flags; - unsigned char mode = 0; - - if (voice < 0 || voice > 31) - { - printk ("GUS: Invalid voice\n"); - return -EINVAL; - } - - if (note_num == 255) - { - if (voices[voice].mode & WAVE_ENVELOPES) - { - voices[voice].midi_volume = volume; - dynamic_volume_change (voice); - return 0; - } - - compute_and_set_volume (voice, volume, 1); - return 0; - } - - if ((patch = patch_map[voice]) == -1) - { - return -EINVAL; - } - - if ((samplep = patch_table[patch]) == NOT_SAMPLE) - { - return -EINVAL; - } - - note_freq = note_to_freq (note_num); - - /* - * Find a sample within a patch so that the note_freq is between low_note - * and high_note. - */ - sample = -1; - - best_sample = samplep; - best_delta = 1000000; - while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) - { - delta_freq = note_freq - samples[samplep].base_note; - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = samplep; - best_delta = delta_freq; - } - if (samples[samplep].low_note <= note_freq && - note_freq <= samples[samplep].high_note) - sample = samplep; - else - samplep = samples[samplep].key; /* Link to next sample */ - } - if (sample == -1) - sample = best_sample; - - if (sample == -1) - { - printk ("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ - } - - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; - voices[voice].mode = samples[sample].mode; - voices[voice].patch_vol = samples[sample].volume; - - if (iw_mode) - gus_write8 (0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ - - if (voices[voice].mode & WAVE_ENVELOPES) - { - int i; - - for (i = 0; i < 6; i++) - { - voices[voice].env_rate[i] = samples[sample].env_rate[i]; - voices[voice].env_offset[i] = samples[sample].env_offset[i]; - } - } - - sample_map[voice] = sample; - - if (voices[voice].fixed_pitch) /* Fixed pitch */ - { - freq = samples[sample].base_freq; - } - else - { - base_note = samples[sample].base_note / 100; - note_freq /= 100; - - freq = samples[sample].base_freq * note_freq / base_note; - } - - voices[voice].orig_freq = freq; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - pan = (samples[sample].panning + voices[voice].panning) / 32; - pan += 7; - if (pan < 0) - pan = 0; - if (pan > 15) - pan = 15; - - if (samples[sample].mode & WAVE_16_BITS) - { - mode |= 0x04; /* 16 bits */ - if ((sample_ptrs[sample] / GUS_BANK_SIZE) != - ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) - printk ("GUS: Sample address error\n"); - } + voices[voice].orig_freq = freq; + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ + + freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender, + voices[voice].bender_range, 0); + voices[voice].current_freq = freq; + + pan = (samples[sample].panning + voices[voice].panning) / 32; + pan += 7; + if (pan < 0) + pan = 0; + if (pan > 15) + pan = 15; + + if (samples[sample].mode & WAVE_16_BITS) + { + mode |= 0x04; /* 16 bits */ + if ((sample_ptrs[sample] / GUS_BANK_SIZE) != + ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) + printk("GUS: Sample address error\n"); + } /************************************************************************* * CAUTION! Interrupts disabled. Don't return before enabling *************************************************************************/ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_off (); - gus_rampoff (); - - restore_flags (flags); - - if (voices[voice].mode & WAVE_ENVELOPES) - { - compute_volume (voice, volume); - init_envelope (voice); - } - else - { - compute_and_set_volume (voice, volume, 0); - } - - save_flags (flags); - cli (); - gus_select_voice (voice); - - if (samples[sample].mode & WAVE_LOOP_BACK) - gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, 0, is16bits); /* start=end */ - else - gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - 0, is16bits); /* Sample start=begin */ - - if (samples[sample].mode & WAVE_LOOPING) - { - mode |= 0x08; - - if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; - - if (samples[sample].mode & WAVE_LOOP_BACK) - { - gus_write_addr (0x0a, - sample_ptrs[sample] + samples[sample].loop_end - - voices[voice].offset_pending, - (samples[sample].fractions >> 4) & 0x0f, is16bits); - mode |= 0x40; - } - - gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, - samples[sample].fractions & 0x0f, - is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } - else - { - mode |= 0x20; /* Loop IRQ at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ - voices[voice].loop_irq_parm = 1; - gus_write_addr (0x02, sample_ptrs[sample], - 0, is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } - gus_voice_freq (freq); - gus_voice_balance (pan); - gus_voice_on (mode); - restore_flags (flags); + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_off(); + gus_rampoff(); + + restore_flags(flags); + + if (voices[voice].mode & WAVE_ENVELOPES) + { + compute_volume(voice, volume); + init_envelope(voice); + } else + { + compute_and_set_volume(voice, volume, 0); + } + + save_flags(flags); + cli(); + gus_select_voice(voice); + + if (samples[sample].mode & WAVE_LOOP_BACK) + gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - + voices[voice].offset_pending, 0, is16bits); /* start=end */ + else + gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, + 0, is16bits); /* Sample start=begin */ + + if (samples[sample].mode & WAVE_LOOPING) + { + mode |= 0x08; + + if (samples[sample].mode & WAVE_BIDIR_LOOP) + mode |= 0x10; - return 0; + if (samples[sample].mode & WAVE_LOOP_BACK) + { + gus_write_addr(0x0a, + sample_ptrs[sample] + samples[sample].loop_end - + voices[voice].offset_pending, + (samples[sample].fractions >> 4) & 0x0f, is16bits); + mode |= 0x40; + } + gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, + samples[sample].fractions & 0x0f, + is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, + (samples[sample].fractions >> 4) & 0x0f, + is16bits); /* Loop end location */ + } else + { + mode |= 0x20; /* Loop IRQ at the end */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ + voices[voice].loop_irq_parm = 1; + gus_write_addr(0x02, sample_ptrs[sample], + 0, is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, + (samples[sample].fractions >> 4) & 0x0f, + is16bits); /* Loop end location */ + } + gus_voice_freq(freq); + gus_voice_balance(pan); + gus_voice_on(mode); + restore_flags(flags); + + return 0; } /* @@ -1635,1946 +1600,1925 @@ */ static int -guswave_start_note (int dev, int voice, int note_num, int volume) +guswave_start_note(int dev, int voice, int note_num, int volume) +{ + long int flags; + int mode; + int ret_val = 0; + + save_flags(flags); + cli(); + if (note_num == 255) + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].volume_pending = volume; + } else + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } + } else + { + gus_select_voice(voice); + mode = gus_read8(0x00); + if (mode & 0x20) + gus_write8(0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + restore_flags(flags); /* Run temporarily with interrupts enabled */ + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + save_flags(flags); + cli(); + gus_select_voice(voice); /* Reselect the voice (just to be sure) */ + } + if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } else + { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff(); + gus_ramp_range(2000, 4065); + gus_ramp_rate(0, 63); /* Fastest possible rate */ + gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ + } + } + restore_flags(flags); + return ret_val; +} + +static void +guswave_reset(int dev) { - long int flags; - int mode; - int ret_val = 0; - - save_flags (flags); - cli (); - if (note_num == 255) - { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].volume_pending = volume; - } - else - { - ret_val = guswave_start_note2 (dev, voice, note_num, volume); - } - } - else - { - gus_select_voice (voice); - mode = gus_read8 (0x00); - if (mode & 0x20) - gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ - - voices[voice].offset_pending = 0; - voices[voice].kill_pending = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].loop_irq_mode = 0; - - if (voices[voice].sample_pending >= 0) - { - restore_flags (flags); /* Run temporarily with interrupts enabled */ - guswave_set_instr (voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - save_flags (flags); - cli (); - gus_select_voice (voice); /* Reselect the voice (just to be sure) */ - } - - if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < (unsigned) 2065)) - { - ret_val = guswave_start_note2 (dev, voice, note_num, volume); - } - else - { - voices[voice].dev_pending = dev; - voices[voice].note_pending = note_num; - voices[voice].volume_pending = volume; - voices[voice].volume_irq_mode = VMODE_START_NOTE; - - gus_rampoff (); - gus_ramp_range (2000, 4065); - gus_ramp_rate (0, 63); /* Fastest possible rate */ - gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ - } - } - restore_flags (flags); - return ret_val; -} - -static void -guswave_reset (int dev) -{ - int i; - - for (i = 0; i < 32; i++) - { - gus_voice_init (i); - gus_voice_init2 (i); - } + int i; + + for (i = 0; i < 32; i++) + { + gus_voice_init(i); + gus_voice_init2(i); + } } static int -guswave_open (int dev, int mode) +guswave_open(int dev, int mode) { - int err; + int err; - if (gus_busy) - return -EBUSY; + if (gus_busy) + return -EBUSY; - voice_alloc->timestamp = 0; + voice_alloc->timestamp = 0; - if ((err = DMAbuf_open_dma (gus_devnum)) < 0) - { - /* printk( "GUS: Loading samples without DMA\n"); */ - gus_no_dma = 1; /* Upload samples using PIO */ - } - else - gus_no_dma = 0; + if ((err = DMAbuf_open_dma(gus_devnum)) < 0) + { + /* printk( "GUS: Loading samples without DMA\n"); */ + gus_no_dma = 1; /* Upload samples using PIO */ + } else + gus_no_dma = 0; - dram_sleep_flag.opts = WK_NONE; - gus_busy = 1; - active_device = GUS_DEV_WAVE; + dram_sleep_flag.opts = WK_NONE; + gus_busy = 1; + active_device = GUS_DEV_WAVE; - gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ - gus_initialize (); - gus_reset (); - gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + gusintr(gus_irq, NULL, NULL); /* Serve pending interrupts */ + gus_initialize(); + gus_reset(); + gusintr(gus_irq, NULL, NULL); /* Serve pending interrupts */ - return 0; + return 0; } static void -guswave_close (int dev) +guswave_close(int dev) { - gus_busy = 0; - active_device = 0; - gus_reset (); + gus_busy = 0; + active_device = 0; + gus_reset(); - if (!gus_no_dma) - DMAbuf_close_dma (gus_devnum); + if (!gus_no_dma) + DMAbuf_close_dma(gus_devnum); } static int -guswave_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +guswave_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - struct patch_info patch; - int instr; - long sizeof_patch; - - unsigned long blk_sz, blk_end, left, src_offs, target; - - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ - - if (format != GUS_PATCH) - { - printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } - - if (count < sizeof_patch) - { - printk ("GUS Error: Patch header too short\n"); - return -EINVAL; - } - - count -= sizeof_patch; - - if (free_sample >= MAX_SAMPLE) - { - printk ("GUS: Sample table full\n"); - return -ENOSPC; - } - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - copy_from_user (&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs); - - if (patch.mode & WAVE_ROM) - return -EINVAL; - if (gus_mem_size == 0) - - return -ENOSPC; - - instr = patch.instr_no; - - if (instr < 0 || instr > MAX_PATCH) - { - printk ("GUS: Invalid patch number %d\n", instr); - return -EINVAL; - } - - if (count < patch.len) - { - printk ("GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len); - patch.len = count; - } - - if (patch.len <= 0 || patch.len > gus_mem_size) - { - printk ("GUS: Invalid sample length %d\n", (int) patch.len); - return -EINVAL; - } - - if (patch.mode & WAVE_LOOPING) - { - if (patch.loop_start < 0 || patch.loop_start >= patch.len) - { - printk ("GUS: Invalid loop start\n"); - return -EINVAL; - } - - if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) - { - printk ("GUS: Invalid loop end\n"); - return -EINVAL; - } - } - - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ - - if (patch.mode & WAVE_16_BITS) - { - /* - * 16 bit samples must fit one 256k bank. - */ - if (patch.len >= GUS_BANK_SIZE) - { - printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return -ENOSPC; - } - - if ((free_mem_ptr / GUS_BANK_SIZE) != - ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) - { - unsigned long tmp_mem = /* Align to 256K */ - ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - - if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; - - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ - } - } - - if ((free_mem_ptr + patch.len) > gus_mem_size) - return -ENOSPC; - - sample_ptrs[free_sample] = free_mem_ptr; - - /* - * Tremolo is not possible with envelopes - */ - - if (patch.mode & WAVE_ENVELOPES) - patch.mode &= ~WAVE_TREMOLO; - - if (!(patch.mode & WAVE_FRACTIONS)) - { - patch.fractions = 0; - } - - memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); - - /* - * Link this_one sample to the list of samples for patch 'instr'. - */ - - samples[free_sample].key = patch_table[instr]; - patch_table[instr] = free_sample; - - /* - * Use DMA to transfer the wave data to the DRAM - */ - - left = patch.len; - src_offs = 0; - target = free_mem_ptr; - - while (left) /* Not completely transferred yet */ - { - blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; - if (blk_sz > left) - blk_sz = left; - - /* - * DMA cannot cross bank (256k) boundaries. Check for that. - */ - blk_end = target + blk_sz; - - if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) - { /* Split the block */ - - blk_end &= ~(GUS_BANK_SIZE - 1); - blk_sz = blk_end - target; - } + struct patch_info patch; + int instr; + long sizeof_patch; - if (gus_no_dma) - { - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - long i; - unsigned char data; + unsigned long blk_sz, blk_end, left, src_offs, target; - for (i = 0; i < blk_sz; i++) - { - get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); - if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke (target + i, data); - } - } - else - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; - - if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) - { - printk ("GUS: DMA buffer == NULL\n"); - return -ENOSPC; - } + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ - /* - * OK, move now. First in and then out. - */ + if (format != GUS_PATCH) + { + printk("GUS Error: Invalid patch format (key) 0x%x\n", format); + return -EINVAL; + } + if (count < sizeof_patch) + { + printk("GUS Error: Patch header too short\n"); + return -EINVAL; + } + count -= sizeof_patch; - copy_from_user (audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); + if (free_sample >= MAX_SAMPLE) + { + printk("GUS: Sample table full\n"); + return -ENOSPC; + } + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ - save_flags (flags); - cli (); -/******** INTERRUPTS DISABLED NOW ********/ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (gus_devnum, - audio_devs[gus_devnum]->dmap_out->raw_buf_phys, - blk_sz, DMA_MODE_WRITE); + copy_from_user(&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs); - /* - * Set the DRAM address for the wave data - */ + if (patch.mode & WAVE_ROM) + return -EINVAL; + if (gus_mem_size == 0) - if (iw_mode) - { - /* Different address translation in enhanced mode */ - - unsigned char hi; - - if (gus_dma > 4) - address = target >> 1; /* Convert to 16 bit word address */ - else - address = target; - - hi = (unsigned char) ((address >> 16) & 0xf0); - hi += (unsigned char) (address & 0x0f); - - gus_write16 (0x42, (address >> 4) & 0xffff); /* DMA address (low) */ - gus_write8 (0x50, hi); - } - else - { - address = target; + return -ENOSPC; - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + instr = patch.instr_no; - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - } + if (instr < 0 || instr > MAX_PATCH) + { + printk("GUS: Invalid patch number %d\n", instr); + return -EINVAL; + } + if (count < patch.len) + { + printk("GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len); + patch.len = count; + } + if (patch.len <= 0 || patch.len > gus_mem_size) + { + printk("GUS: Invalid sample length %d\n", (int) patch.len); + return -EINVAL; + } + if (patch.mode & WAVE_LOOPING) + { + if (patch.loop_start < 0 || patch.loop_start >= patch.len) + { + printk("GUS: Invalid loop start\n"); + return -EINVAL; + } + if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) + { + printk("GUS: Invalid loop end\n"); + return -EINVAL; + } + } + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ - /* - * Start the DMA transfer - */ + if (patch.mode & WAVE_16_BITS) + { + /* + * 16 bit samples must fit one 256k bank. + */ + if (patch.len >= GUS_BANK_SIZE) + { + printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len); + return -ENOSPC; + } + if ((free_mem_ptr / GUS_BANK_SIZE) != + ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) + { + unsigned long tmp_mem = /* Align to 256K */ + ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ + if ((tmp_mem + patch.len) > gus_mem_size) + return -ENOSPC; - gus_write8 (0x41, dma_command); /* Lets go luteet (=bugs) */ + free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + } + } + if ((free_mem_ptr + patch.len) > gus_mem_size) + return -ENOSPC; - /* - * Sleep here until the DRAM DMA done interrupt is served - */ - active_device = GUS_DEV_WAVE; + sample_ptrs[free_sample] = free_mem_ptr; + + /* + * Tremolo is not possible with envelopes + */ + + if (patch.mode & WAVE_ENVELOPES) + patch.mode &= ~WAVE_TREMOLO; + + if (!(patch.mode & WAVE_FRACTIONS)) + { + patch.fractions = 0; + } + memcpy((char *) &samples[free_sample], &patch, sizeof_patch); + + /* + * Link this_one sample to the list of samples for patch 'instr'. + */ + + samples[free_sample].key = patch_table[instr]; + patch_table[instr] = free_sample; + + /* + * Use DMA to transfer the wave data to the DRAM + */ + + left = patch.len; + src_offs = 0; + target = free_mem_ptr; + + while (left) /* Not completely transferred yet */ + { + blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; + if (blk_sz > left) + blk_sz = left; + + /* + * DMA cannot cross bank (256k) boundaries. Check for that. + */ + blk_end = target + blk_sz; + + if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) + { /* Split the block */ + + blk_end &= ~(GUS_BANK_SIZE - 1); + blk_sz = blk_end - target; + } + if (gus_no_dma) + { + /* + * For some reason the DMA is not possible. We have to use PIO. + */ + long i; + unsigned char data; + + for (i = 0; i < blk_sz; i++) + { + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); + if (patch.mode & WAVE_UNSIGNED) + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* Convert to signed */ + gus_poke(target + i, data); + } + } else + { + unsigned long address, hold_address; + unsigned char dma_command; + unsigned long flags; + + if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) + { + printk("GUS: DMA buffer == NULL\n"); + return -ENOSPC; + } + /* + * OK, move now. First in and then out. + */ + + copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); + + save_flags(flags); + cli(); +/******** INTERRUPTS DISABLED NOW ********/ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(gus_devnum, + audio_devs[gus_devnum]->dmap_out->raw_buf_phys, + blk_sz, DMA_MODE_WRITE); + + /* + * Set the DRAM address for the wave data + */ + + if (iw_mode) + { + /* Different address translation in enhanced mode */ + + unsigned char hi; + + if (gus_dma > 4) + address = target >> 1; /* Convert to 16 bit word address */ + else + address = target; + + hi = (unsigned char) ((address >> 16) & 0xf0); + hi += (unsigned char) (address & 0x0f); + + gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ + gus_write8(0x50, hi); + } else + { + address = target; + + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + } + + /* + * Start the DMA transfer + */ + + dma_command = 0x21; /* IRQ enable, DMA start */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* Invert MSB */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ + + gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ + + /* + * Sleep here until the DRAM DMA done interrupt is served + */ + active_device = GUS_DEV_WAVE; + + + { + unsigned long tlimit; + + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + dram_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&dram_sleeper); + if (!(dram_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + dram_sleep_flag.opts |= WK_TIMEOUT; + } + dram_sleep_flag.opts &= ~WK_SLEEP; + }; + if ((dram_sleep_flag.opts & WK_TIMEOUT)) + printk("GUS: DMA Transfer timed out\n"); + restore_flags(flags); + } + + /* + * Now the next part + */ + + left -= blk_sz; + src_offs += blk_sz; + target += blk_sz; + gus_write8(0x41, 0); /* Stop DMA */ + } + + free_mem_ptr += patch.len; + + free_sample++; + return 0; +} + +static void +guswave_hw_control(int dev, unsigned char *event_rec) +{ + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; + unsigned flags; + cmd = event_rec[2]; + voice = event_rec[3]; + p1 = *(unsigned short *) &event_rec[4]; + p2 = *(unsigned short *) &event_rec[6]; + plong = *(unsigned int *) &event_rec[4]; + + if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + do_volume_irq(voice); + + switch (cmd) { - unsigned long tlimit; - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - dram_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&dram_sleeper); - if (!(dram_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - dram_sleep_flag.opts |= WK_TIMEOUT; - } - dram_sleep_flag.opts &= ~WK_SLEEP; - }; - if ((dram_sleep_flag.opts & WK_TIMEOUT)) - printk ("GUS: DMA Transfer timed out\n"); - restore_flags (flags); - } - - /* - * Now the next part - */ - - left -= blk_sz; - src_offs += blk_sz; - target += blk_sz; - - gus_write8 (0x41, 0); /* Stop DMA */ - } - - free_mem_ptr += patch.len; - - free_sample++; - return 0; -} - -static void -guswave_hw_control (int dev, unsigned char *event_rec) -{ - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; - unsigned flags; - - cmd = event_rec[2]; - voice = event_rec[3]; - p1 = *(unsigned short *) &event_rec[4]; - p2 = *(unsigned short *) &event_rec[6]; - plong = *(unsigned int *) &event_rec[4]; - - if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && - (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) - do_volume_irq (voice); - - switch (cmd) - { - - case _GUS_NUMVOICES: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_select_max_voices (p1); - restore_flags (flags); - break; - - case _GUS_VOICESAMPLE: - guswave_set_instr (dev, voice, p1); - break; - - case _GUS_VOICEON: - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_on (p1); - restore_flags (flags); - break; - - case _GUS_VOICEOFF: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_off (); - restore_flags (flags); - break; - - case _GUS_VOICEFADE: - gus_voice_fade (voice); - break; - - case _GUS_VOICEMODE: - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_mode (p1); - restore_flags (flags); - break; - - case _GUS_VOICEBALA: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_balance (p1); - restore_flags (flags); - break; - - case _GUS_VOICEFREQ: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_freq (plong); - restore_flags (flags); - break; - - case _GUS_VOICEVOL: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_volume (p1); - restore_flags (flags); - break; - - case _GUS_VOICEVOL2: /* Just update the software voice level */ - voices[voice].initial_volume = - voices[voice].current_volume = p1; - break; - - case _GUS_RAMPRANGE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_ramp_range (p1, p2); - restore_flags (flags); - break; - - case _GUS_RAMPRATE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NJET-NJET */ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_ramp_rate (p1, p2); - restore_flags (flags); - break; - - case _GUS_RAMPMODE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_ramp_mode (p1); - restore_flags (flags); - break; - - case _GUS_RAMPON: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* EI-EI */ - save_flags (flags); - cli (); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_rampon (p1); - restore_flags (flags); - break; - - case _GUS_RAMPOFF: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NEJ-NEJ */ - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_rampoff (); - restore_flags (flags); - break; - - case _GUS_VOLUME_SCALE: - volume_base = p1; - volume_scale = p2; - break; - - case _GUS_VOICE_POS: - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_set_voice_pos (voice, plong); - restore_flags (flags); - break; + case _GUS_NUMVOICES: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_select_max_voices(p1); + restore_flags(flags); + break; + + case _GUS_VOICESAMPLE: + guswave_set_instr(dev, voice, p1); + break; + + case _GUS_VOICEON: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_on(p1); + restore_flags(flags); + break; + + case _GUS_VOICEOFF: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_off(); + restore_flags(flags); + break; + + case _GUS_VOICEFADE: + gus_voice_fade(voice); + break; + + case _GUS_VOICEMODE: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_mode(p1); + restore_flags(flags); + break; + + case _GUS_VOICEBALA: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_balance(p1); + restore_flags(flags); + break; + + case _GUS_VOICEFREQ: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(plong); + restore_flags(flags); + break; + + case _GUS_VOICEVOL: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(p1); + restore_flags(flags); + break; + + case _GUS_VOICEVOL2: /* Just update the software voice level */ + voices[voice].initial_volume = + voices[voice].current_volume = p1; + break; + + case _GUS_RAMPRANGE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_range(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPRATE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NJET-NJET */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_rate(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPMODE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_ramp_mode(p1); + restore_flags(flags); + break; + + case _GUS_RAMPON: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* EI-EI */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_rampon(p1); + restore_flags(flags); + break; + + case _GUS_RAMPOFF: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NEJ-NEJ */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + break; + + case _GUS_VOLUME_SCALE: + volume_base = p1; + volume_scale = p2; + break; + + case _GUS_VOICE_POS: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_set_voice_pos(voice, plong); + restore_flags(flags); + break; - default:; - } + default:; + } } static int -gus_audio_set_speed (int speed) +gus_audio_set_speed(int speed) { - if (speed <= 0) - speed = gus_audio_speed; + if (speed <= 0) + speed = gus_audio_speed; - if (speed < 4000) - speed = 4000; + if (speed < 4000) + speed = 4000; - if (speed > 44100) - speed = 44100; + if (speed > 44100) + speed = 44100; - gus_audio_speed = speed; + gus_audio_speed = speed; - if (only_read_access) - { - /* Compute nearest valid recording speed and return it */ + if (only_read_access) + { + /* Compute nearest valid recording speed and return it */ - /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ - speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - speed = (9878400 / (speed * 16)) - 2; - } - return speed; + /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ + speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; + speed = (9878400 / (speed * 16)) - 2; + } + return speed; } static int -gus_audio_set_channels (int channels) +gus_audio_set_channels(int channels) { - if (!channels) - return gus_audio_channels; - if (channels > 2) - channels = 2; - if (channels < 1) - channels = 1; - gus_audio_channels = channels; - return channels; + if (!channels) + return gus_audio_channels; + if (channels > 2) + channels = 2; + if (channels < 1) + channels = 1; + gus_audio_channels = channels; + return channels; } static int -gus_audio_set_bits (int bits) +gus_audio_set_bits(int bits) { - if (!bits) - return gus_audio_bits; + if (!bits) + return gus_audio_bits; - if (bits != 8 && bits != 16) - bits = 8; + if (bits != 8 && bits != 16) + bits = 8; - if (only_8_bits) - bits = 8; + if (only_8_bits) + bits = 8; - gus_audio_bits = bits; - return bits; + gus_audio_bits = bits; + return bits; } static int -gus_audio_ioctl (int dev, unsigned int cmd, caddr_t arg) +gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int val; + int val; - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_speed (val)); - break; + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_speed(val)); + break; + + case SOUND_PCM_READ_RATE: + return (*(int *) arg = gus_audio_speed); + break; + + case SNDCTL_DSP_STEREO: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_channels(val + 1) - 1); + break; + + case SOUND_PCM_WRITE_CHANNELS: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_channels(val)); + break; + + case SOUND_PCM_READ_CHANNELS: + return (*(int *) arg = gus_audio_channels); + break; + + case SNDCTL_DSP_SETFMT: + val = *(int *) arg; + return (*(int *) arg = gus_audio_set_bits(val)); + break; + + case SOUND_PCM_READ_BITS: + return (*(int *) arg = gus_audio_bits); + + case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ + return (*(int *) arg = -EINVAL); + break; + + case SOUND_PCM_READ_FILTER: + return (*(int *) arg = -EINVAL); + break; - case SOUND_PCM_READ_RATE: - return (*(int *) arg = gus_audio_speed); - break; + } + return -EINVAL; +} - case SNDCTL_DSP_STEREO: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_channels (val + 1) - 1); - break; +static void +gus_audio_reset(int dev) +{ + if (recording_active) + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } +} - case SOUND_PCM_WRITE_CHANNELS: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_channels (val)); - break; +static int saved_iw_mode; /* A hack hack hack */ - case SOUND_PCM_READ_CHANNELS: - return (*(int *) arg = gus_audio_channels); - break; +static int +gus_audio_open(int dev, int mode) +{ + if (gus_busy) + return -EBUSY; - case SNDCTL_DSP_SETFMT: - val = *(int *) arg; - return (*(int *) arg = gus_audio_set_bits (val)); - break; + if (gus_pnp_flag && mode & OPEN_READ) + { + printk("GUS: Audio device #%d is playback only.\n", dev); + return -EIO; + } + gus_initialize(); - case SOUND_PCM_READ_BITS: - return (*(int *) arg = gus_audio_bits); + gus_busy = 1; + active_device = 0; - case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - return (*(int *) arg = -EINVAL); - break; + gus_reset(); + reset_sample_memory(); + gus_select_max_voices(14); + saved_iw_mode = iw_mode; + if (iw_mode) + { + /* There are some problems with audio in enhanced mode so disable it */ + gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ + iw_mode = 0; + } + pcm_active = 0; + dma_active = 0; + pcm_opened = 1; + if (mode & OPEN_READ) + { + recording_active = 1; + set_input_volumes(); + } + only_read_access = !(mode & OPEN_WRITE); + only_8_bits = mode & OPEN_READ; + if (only_8_bits) + audio_devs[dev]->format_mask = AFMT_U8; + else + audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; - case SOUND_PCM_READ_FILTER: - return (*(int *) arg = -EINVAL); - break; + return 0; +} - } - return -EINVAL; +static void +gus_audio_close(int dev) +{ + iw_mode = saved_iw_mode; + gus_reset(); + gus_busy = 0; + pcm_opened = 0; + active_device = 0; + + if (recording_active) + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } + recording_active = 0; } static void -gus_audio_reset (int dev) +gus_audio_update_volume(void) { - if (recording_active) - { - gus_write8 (0x49, 0x00); /* Halt recording */ - set_input_volumes (); - } + unsigned long flags; + int voice; + + if (pcm_active && pcm_opened) + for (voice = 0; voice < gus_audio_channels; voice++) + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + restore_flags(flags); + } } -static int saved_iw_mode; /* A hack hack hack */ +static void +play_next_pcm_block(void) +{ + unsigned long flags; + int speed = gus_audio_speed; + int this_one, is16bits, chn; + unsigned long dram_loc; + unsigned char mode[2], ramp_mode[2]; -static int -gus_audio_open (int dev, int mode) + if (!pcm_qlen) + return; + + this_one = pcm_head; + + for (chn = 0; chn < gus_audio_channels; chn++) + { + mode[chn] = 0x00; + ramp_mode[chn] = 0x03; /* Ramping and rollover off */ + + if (chn == 0) + { + mode[chn] |= 0x20; /* Loop IRQ */ + voices[chn].loop_irq_mode = LMODE_PCM; + } + if (gus_audio_bits != 8) + { + is16bits = 1; + mode[chn] |= 0x04; /* 16 bit data */ + } else + is16bits = 0; + + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; + + if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ + { + mode[chn] |= 0x08; /* Enable loop */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ + } else + { + if (chn == 0) + ramp_mode[chn] = 0x04; /* Enable rollover bit */ + } + + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_voice_freq(speed); + + if (gus_audio_channels == 1) + gus_voice_balance(7); /* mono */ + else if (chn == 0) + gus_voice_balance(0); /* left */ + else + gus_voice_balance(15); /* right */ + + if (!pcm_active) /* Playback not already active */ + { + /* + * The playback was not started yet (or there has been a pause). + * Start the voice (again) and ask for a rollover irq at the end of + * this_one block. If this_one one is last of the buffers, use just + * the normal loop with irq. + */ + + gus_voice_off(); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + + gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ + gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + + if (chn != 0) + gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, + 0, is16bits); /* Loop end location */ + } + if (chn == 0) + gus_write_addr(0x04, dram_loc + pcm_bsize - 1, + 0, is16bits); /* Loop end location */ + else + mode[chn] |= 0x08; /* Enable looping */ + + + restore_flags(flags); + } + + for (chn = 0; chn < gus_audio_channels; chn++) + { + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_write8(0x0d, ramp_mode[chn]); + if (iw_mode) + gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ + gus_voice_on(mode[chn]); + restore_flags(flags); + } + + pcm_active = 1; +} + +static void +gus_transfer_output_block(int dev, unsigned long buf, + int total_count, int intrflag, int chn) { - if (gus_busy) - return -EBUSY; + /* + * This routine transfers one block of audio data to the DRAM. In mono mode + * it's called just once. When in stereo mode, this_one routine is called + * once for both channels. + * + * The left/mono channel data is transferred to the beginning of dram and the + * right data to the area pointed by gus_page_size. + */ - if (gus_pnp_flag && mode & OPEN_READ) - { - printk ("GUS: Audio device #%d is playback only.\n", dev); - return -EIO; - } - gus_initialize (); - - gus_busy = 1; - active_device = 0; - - gus_reset (); - reset_sample_memory (); - gus_select_max_voices (14); - saved_iw_mode = iw_mode; - if (iw_mode) - { - /* There are some problems with audio in enhanced mode so disable it */ - gus_write8 (0x19, gus_read8 (0x19) & ~0x01); /* Disable enhanced mode */ - iw_mode = 0; - } - - pcm_active = 0; - dma_active = 0; - pcm_opened = 1; - if (mode & OPEN_READ) - { - recording_active = 1; - set_input_volumes (); - } - only_read_access = !(mode & OPEN_WRITE); - only_8_bits = mode & OPEN_READ; - if (only_8_bits) - audio_devs[dev]->format_mask = AFMT_U8; - else - audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; - - return 0; -} - -static void -gus_audio_close (int dev) -{ - iw_mode = saved_iw_mode; - gus_reset (); - gus_busy = 0; - pcm_opened = 0; - active_device = 0; - - if (recording_active) - { - gus_write8 (0x49, 0x00); /* Halt recording */ - set_input_volumes (); - } - - recording_active = 0; -} - -static void -gus_audio_update_volume (void) -{ - unsigned long flags; - int voice; - - if (pcm_active && pcm_opened) - for (voice = 0; voice < gus_audio_channels; voice++) - { - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_rampoff (); - gus_voice_volume (1530 + (25 * gus_pcm_volume)); - gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - restore_flags (flags); - } -} - -static void -play_next_pcm_block (void) -{ - unsigned long flags; - int speed = gus_audio_speed; - int this_one, is16bits, chn; - unsigned long dram_loc; - unsigned char mode[2], ramp_mode[2]; - - if (!pcm_qlen) - return; - - this_one = pcm_head; - - for (chn = 0; chn < gus_audio_channels; chn++) - { - mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - - if (chn == 0) - { - mode[chn] |= 0x20; /* Loop IRQ */ - voices[chn].loop_irq_mode = LMODE_PCM; - } - - if (gus_audio_bits != 8) - { - is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ - } - else - is16bits = 0; - - dram_loc = this_one * pcm_bsize; - dram_loc += chn * pcm_banksize; - - if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ - { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03; /* Disable rollover bit */ - } - else - { - if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ - } - - save_flags (flags); - cli (); - gus_select_voice (chn); - gus_voice_freq (speed); - - if (gus_audio_channels == 1) - gus_voice_balance (7); /* mono */ - else if (chn == 0) - gus_voice_balance (0); /* left */ - else - gus_voice_balance (15); /* right */ + int this_one, count; + unsigned long flags; + unsigned char dma_command; + unsigned long address, hold_address; - if (!pcm_active) /* Playback not already active */ - { - /* - * The playback was not started yet (or there has been a pause). - * Start the voice (again) and ask for a rollover irq at the end of - * this_one block. If this_one one is last of the buffers, use just - * the normal loop with irq. - */ + save_flags(flags); + cli(); + + count = total_count / gus_audio_channels; + + if (chn == 0) + { + if (pcm_qlen >= pcm_nblk) + printk("GUS Warning: PCM buffers out of sync\n"); - gus_voice_off (); - gus_rampoff (); - gus_voice_volume (1530 + (25 * gus_pcm_volume)); - gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - - gus_write_addr (0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ - gus_write_addr (0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ - - if (chn != 0) - gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - 0, is16bits); /* Loop end location */ - } - - if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_bsize - 1, - 0, is16bits); /* Loop end location */ - else - mode[chn] |= 0x08; /* Enable looping */ - - - restore_flags (flags); - } - - for (chn = 0; chn < gus_audio_channels; chn++) - { - save_flags (flags); - cli (); - gus_select_voice (chn); - gus_write8 (0x0d, ramp_mode[chn]); - if (iw_mode) - gus_write8 (0x15, 0x00); /* Reset voice deactivate bit of SMSI */ - gus_voice_on (mode[chn]); - restore_flags (flags); - } - - pcm_active = 1; -} - -static void -gus_transfer_output_block (int dev, unsigned long buf, - int total_count, int intrflag, int chn) -{ - /* - * This routine transfers one block of audio data to the DRAM. In mono mode - * it's called just once. When in stereo mode, this_one routine is called - * once for both channels. - * - * The left/mono channel data is transferred to the beginning of dram and the - * right data to the area pointed by gus_page_size. - */ - - int this_one, count; - unsigned long flags; - unsigned char dma_command; - unsigned long address, hold_address; - - save_flags (flags); - cli (); - - count = total_count / gus_audio_channels; - - if (chn == 0) - { - if (pcm_qlen >= pcm_nblk) - printk ("GUS Warning: PCM buffers out of sync\n"); - - this_one = pcm_current_block = pcm_tail; - pcm_qlen++; - pcm_tail = (pcm_tail + 1) % pcm_nblk; - pcm_datasize[this_one] = count; - } - else - this_one = pcm_current_block; - - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); - - address = this_one * pcm_bsize; - address += chn * pcm_banksize; - - if (audio_devs[dev]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - - dma_command = 0x21; /* IRQ enable, DMA start */ - - if (gus_audio_bits != 8) - dma_command |= 0x40; /* 16 bit _DATA_ */ - else - dma_command |= 0x80; /* Invert MSB */ - - if (audio_devs[dev]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ - - gus_write8 (0x41, dma_command); /* Kick start */ - - if (chn == (gus_audio_channels - 1)) /* Last channel */ - { - /* - * Last (right or mono) channel data - */ - dma_active = 1; /* DMA started. There is a unacknowledged buffer */ - active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) - { - play_next_pcm_block (); - } - } - else - { - /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ - active_device = GUS_DEV_PCM_CONTINUE; - } + this_one = pcm_current_block = pcm_tail; + pcm_qlen++; + pcm_tail = (pcm_tail + 1) % pcm_nblk; + pcm_datasize[this_one] = count; + } else + this_one = pcm_current_block; - restore_flags (flags); + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE); + + address = this_one * pcm_bsize; + address += chn * pcm_banksize; + + if (audio_devs[dev]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + + dma_command = 0x21; /* IRQ enable, DMA start */ + + if (gus_audio_bits != 8) + dma_command |= 0x40; /* 16 bit _DATA_ */ + else + dma_command |= 0x80; /* Invert MSB */ + + if (audio_devs[dev]->dmap_out->dma > 3) + dma_command |= 0x04; /* 16 bit DMA channel */ + + gus_write8(0x41, dma_command); /* Kick start */ + + if (chn == (gus_audio_channels - 1)) /* Last channel */ + { + /* + * Last (right or mono) channel data + */ + dma_active = 1; /* DMA started. There is a unacknowledged buffer */ + active_device = GUS_DEV_PCM_DONE; + if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) + { + play_next_pcm_block(); + } + } else + { + /* + * Left channel data. The right channel + * is transferred after DMA interrupt + */ + active_device = GUS_DEV_PCM_CONTINUE; + } + + restore_flags(flags); } static void -gus_uninterleave8 (char *buf, int l) +gus_uninterleave8(char *buf, int l) { /* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - char *buf2 = buf + halfsize, *src = bounce_buf; + int i, p = 0, halfsize = l / 2; + char *buf2 = buf + halfsize, *src = bounce_buf; - memcpy (bounce_buf, buf, l); + memcpy(bounce_buf, buf, l); - for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + for (i = 0; i < halfsize; i++) + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } static void -gus_uninterleave16 (short *buf, int l) +gus_uninterleave16(short *buf, int l) { /* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - short *buf2 = buf + halfsize, *src = (short *) bounce_buf; + int i, p = 0, halfsize = l / 2; + short *buf2 = buf + halfsize, *src = (short *) bounce_buf; - memcpy (bounce_buf, (char *) buf, l * 2); + memcpy(bounce_buf, (char *) buf, l * 2); - for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + for (i = 0; i < halfsize; i++) + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } static void -gus_audio_output_block (int dev, unsigned long buf, int total_count, - int intrflag) +gus_audio_output_block(int dev, unsigned long buf, int total_count, + int intrflag) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; + dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; - pcm_current_buf = buf; - pcm_current_count = total_count; - pcm_current_intrflag = intrflag; - pcm_current_dev = dev; - if (gus_audio_channels == 2) - { - char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); + pcm_current_buf = buf; + pcm_current_count = total_count; + pcm_current_intrflag = intrflag; + pcm_current_dev = dev; + if (gus_audio_channels == 2) + { + char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); - if (gus_audio_bits == 8) - gus_uninterleave8 (b, total_count); - else - gus_uninterleave16 ((short *) b, total_count / 2); - } - gus_transfer_output_block (dev, buf, total_count, intrflag, 0); + if (gus_audio_bits == 8) + gus_uninterleave8(b, total_count); + else + gus_uninterleave16((short *) b, total_count / 2); + } + gus_transfer_output_block(dev, buf, total_count, intrflag, 0); } static void -gus_audio_start_input (int dev, unsigned long buf, int count, - int intrflag) +gus_audio_start_input(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags; - unsigned char mode; + unsigned long flags; + unsigned char mode; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enabled, invert MSB */ + mode = 0xa0; /* DMA IRQ enabled, invert MSB */ - if (audio_devs[dev]->dmap_in->dma > 3) - mode |= 0x04; /* 16 bit DMA channel */ - if (gus_audio_channels > 1) - mode |= 0x02; /* Stereo */ - mode |= 0x01; /* DMA enable */ + if (audio_devs[dev]->dmap_in->dma > 3) + mode |= 0x04; /* 16 bit DMA channel */ + if (gus_audio_channels > 1) + mode |= 0x02; /* Stereo */ + mode |= 0x01; /* DMA enable */ - gus_write8 (0x49, mode); + gus_write8(0x49, mode); - restore_flags (flags); + restore_flags(flags); } static int -gus_audio_prepare_for_input (int dev, int bsize, int bcount) +gus_audio_prepare_for_input(int dev, int bsize, int bcount) { - unsigned int rate; - - gus_audio_bsize = bsize; - audio_devs[dev]->dmap_in->flags |= DMA_NODMA; - rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; + unsigned int rate; - gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ + gus_audio_bsize = bsize; + audio_devs[dev]->dmap_in->flags |= DMA_NODMA; + rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - if (gus_audio_bits != 8) - { - printk ("GUS Error: 16 bit recording not supported\n"); - return -EINVAL; - } + gus_write8(0x48, rate & 0xff); /* Set sampling rate */ - return 0; + if (gus_audio_bits != 8) + { + printk("GUS Error: 16 bit recording not supported\n"); + return -EINVAL; + } + return 0; } static int -gus_audio_prepare_for_output (int dev, int bsize, int bcount) +gus_audio_prepare_for_output(int dev, int bsize, int bcount) { - int i; + int i; - long mem_ptr, mem_size; + long mem_ptr, mem_size; - audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; - mem_ptr = 0; - mem_size = gus_mem_size / gus_audio_channels; + audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; + mem_ptr = 0; + mem_size = gus_mem_size / gus_audio_channels; - if (mem_size > (256 * 1024)) - mem_size = 256 * 1024; + if (mem_size > (256 * 1024)) + mem_size = 256 * 1024; - pcm_bsize = bsize / gus_audio_channels; - pcm_head = pcm_tail = pcm_qlen = 0; + pcm_bsize = bsize / gus_audio_channels; + pcm_head = pcm_tail = pcm_qlen = 0; - pcm_nblk = 2; /* MAX_PCM_BUFFERS; */ - if ((pcm_bsize * pcm_nblk) > mem_size) - pcm_nblk = mem_size / pcm_bsize; + pcm_nblk = 2; /* MAX_PCM_BUFFERS; */ + if ((pcm_bsize * pcm_nblk) > mem_size) + pcm_nblk = mem_size / pcm_bsize; - for (i = 0; i < pcm_nblk; i++) - pcm_datasize[i] = 0; + for (i = 0; i < pcm_nblk; i++) + pcm_datasize[i] = 0; - pcm_banksize = pcm_nblk * pcm_bsize; + pcm_banksize = pcm_nblk * pcm_bsize; - if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) - pcm_nblk--; - gus_write8 (0x41, 0); /* Disable GF1 DMA */ + if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) + pcm_nblk--; + gus_write8(0x41, 0); /* Disable GF1 DMA */ - return 0; + return 0; } static int -gus_local_qlen (int dev) +gus_local_qlen(int dev) { - return pcm_qlen; + return pcm_qlen; } static struct audio_driver gus_audio_driver = { - gus_audio_open, - gus_audio_close, - gus_audio_output_block, - gus_audio_start_input, - gus_audio_ioctl, - gus_audio_prepare_for_input, - gus_audio_prepare_for_output, - gus_audio_reset, - gus_local_qlen, - NULL + gus_audio_open, + gus_audio_close, + gus_audio_output_block, + gus_audio_start_input, + gus_audio_ioctl, + gus_audio_prepare_for_input, + gus_audio_prepare_for_output, + gus_audio_reset, + gus_local_qlen, + NULL }; static void -guswave_setup_voice (int dev, int voice, int chn) +guswave_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; - guswave_set_instr (dev, voice, info->pgm_num); + guswave_set_instr(dev, voice, info->pgm_num); - voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just MSB */ - voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - voices[voice].panning = - (info->controllers[CTL_PAN] * 2) - 128; - voices[voice].bender = 0; - voices[voice].bender_range = info->bender_range; + voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just MSB */ + voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + voices[voice].panning = + (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].bender = 0; + voices[voice].bender_range = info->bender_range; - if (chn == 9) - voices[voice].fixed_pitch = 1; + if (chn == 9) + voices[voice].fixed_pitch = 1; } static void -guswave_bender (int dev, int voice, int value) +guswave_bender(int dev, int voice, int value) { - int freq; - unsigned long flags; + int freq; + unsigned long flags; - voices[voice].bender = value - 8192; - freq = compute_finetune (voices[voice].orig_freq, value - 8192, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; + voices[voice].bender = value - 8192; + freq = compute_finetune(voices[voice].orig_freq, value - 8192, + voices[voice].bender_range, 0); + voices[voice].current_freq = freq; - save_flags (flags); - cli (); - gus_select_voice (voice); - gus_voice_freq (freq); - restore_flags (flags); + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(freq); + restore_flags(flags); } static int -guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) +guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best = -1, best_time = 0x7fffffff; + int i, p, best = -1, best_time = 0x7fffffff; + + p = alloc->ptr; + /* + * First look for a completely stopped voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } - p = alloc->ptr; - /* - * First look for a completely stopped voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } - - /* - * Then look for a releasing voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - return p; - } - p = (p + 1) % alloc->max_voice; - } + /* + * Then look for a releasing voice + */ - if (best >= 0) - p = best; + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; + } + + if (best >= 0) + p = best; - alloc->ptr = p; - return p; + alloc->ptr = p; + return p; } static struct synth_operations guswave_operations = { - "GUS", - &gus_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_GUS, - guswave_open, - guswave_close, - guswave_ioctl, - guswave_kill_note, - guswave_start_note, - guswave_set_instr, - guswave_reset, - guswave_hw_control, - guswave_load_patch, - guswave_aftertouch, - guswave_controller, - guswave_panning, - guswave_volume_method, - guswave_bender, - guswave_alloc, - guswave_setup_voice + "GUS", + &gus_info, + 0, + SYNTH_TYPE_SAMPLE, + SAMPLE_TYPE_GUS, + guswave_open, + guswave_close, + guswave_ioctl, + guswave_kill_note, + guswave_start_note, + guswave_set_instr, + guswave_reset, + guswave_hw_control, + guswave_load_patch, + guswave_aftertouch, + guswave_controller, + guswave_panning, + guswave_volume_method, + guswave_bender, + guswave_alloc, + guswave_setup_voice }; static void -set_input_volumes (void) +set_input_volumes(void) { - unsigned long flags; - unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + + if (have_gus_max) /* Don't disturb GUS MAX */ + return; - if (have_gus_max) /* Don't disturb GUS MAX */ - return; + save_flags(flags); + cli(); - save_flags (flags); - cli (); - - /* - * Enable channels having vol > 10% - * Note! bit 0x01 means the line in DISABLED while 0x04 means - * the mic in ENABLED. - */ - if (gus_line_vol > 10) - mask &= ~0x01; - if (gus_mic_vol > 10) - mask |= 0x04; - - if (recording_active) - { - /* - * Disable channel, if not selected for recording - */ - if (!(gus_recmask & SOUND_MASK_LINE)) - mask |= 0x01; - if (!(gus_recmask & SOUND_MASK_MIC)) - mask &= ~0x04; - } - - mix_image &= ~0x07; - mix_image |= mask & 0x07; - outb ((mix_image), u_Mixer); + /* + * Enable channels having vol > 10% + * Note! bit 0x01 means the line in DISABLED while 0x04 means + * the mic in ENABLED. + */ + if (gus_line_vol > 10) + mask &= ~0x01; + if (gus_mic_vol > 10) + mask |= 0x04; - restore_flags (flags); + if (recording_active) + { + /* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) + mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) + mask &= ~0x04; + } + mix_image &= ~0x07; + mix_image |= mask & 0x07; + outb((mix_image), u_Mixer); + + restore_flags(flags); } int -gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ SOUND_MASK_SYNTH|SOUND_MASK_PCM) - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - gus_recmask = *(int *) arg; - gus_recmask &= MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - return (*(int *) arg = gus_recmask); - break; - - case SOUND_MIXER_MIC: - { - int vol; - - vol = *(int *) arg; - vol &= 0xff; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes (); - return (*(int *) arg = vol | (vol << 8)); - } - break; - - case SOUND_MIXER_LINE: - { - int vol; - - vol = *(int *) arg; - vol &= 0xff; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes (); - return (*(int *) arg = vol | (vol << 8)); - } - break; - - case SOUND_MIXER_PCM: - gus_pcm_volume = *(int *) arg; - gus_pcm_volume &= 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_audio_update_volume (); - return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); - break; - - case SOUND_MIXER_SYNTH: - { - int voice; - - gus_wave_volume = *(int *) arg; - gus_wave_volume &= 0xff; - - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; - - if (active_device == GUS_DEV_WAVE) - for (voice = 0; voice < nr_voices; voice++) - dynamic_volume_change (voice); /* Apply the new vol */ - - return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); - } - break; - - default: - return -EINVAL; - } - else - switch (cmd & 0xff) /* - * Return parameters - */ + if (((cmd >> 8) & 0xff) == 'M') { - - case SOUND_MIXER_RECSRC: - return (*(int *) arg = gus_recmask); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = MIX_DEVS); - break; - - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = 0); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); - break; - - case SOUND_MIXER_MIC: - return (*(int *) arg = gus_mic_vol | (gus_mic_vol << 8)); - break; - - case SOUND_MIXER_LINE: - return (*(int *) arg = gus_line_vol | (gus_line_vol << 8)); - break; - - case SOUND_MIXER_PCM: - return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); - break; - - case SOUND_MIXER_SYNTH: - return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); - break; - - default: - return -EINVAL; - } - } - else - return -EINVAL; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = *(int *) arg; + gus_recmask &= MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + return (*(int *) arg = gus_recmask); + break; + + case SOUND_MIXER_MIC: + { + int vol; + + vol = *(int *) arg; + vol &= 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + return (*(int *) arg = vol | (vol << 8)); + } + break; + + case SOUND_MIXER_LINE: + { + int vol; + + vol = *(int *) arg; + vol &= 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes(); + return (*(int *) arg = vol | (vol << 8)); + } + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = *(int *) arg; + gus_pcm_volume &= 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_audio_update_volume(); + return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + { + int voice; + + gus_wave_volume = *(int *) arg; + gus_wave_volume &= 0xff; + + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + + if (active_device == GUS_DEV_WAVE) + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change(voice); /* Apply the new vol */ + + return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); + } + break; + + default: + return -EINVAL; + } else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = gus_recmask); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = MIX_DEVS); + break; + + case SOUND_MIXER_STEREODEVS: + return (*(int *) arg = 0); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = 0); + break; + + case SOUND_MIXER_MIC: + return (*(int *) arg = gus_mic_vol | (gus_mic_vol << 8)); + break; + + case SOUND_MIXER_LINE: + return (*(int *) arg = gus_line_vol | (gus_line_vol << 8)); + break; + + case SOUND_MIXER_PCM: + return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8)); + break; + + default: + return -EINVAL; + } + } else + return -EINVAL; } static struct mixer_operations gus_mixer_operations = { - "GUS", - "Gravis Ultrasound", - gus_default_mixer_ioctl + "GUS", + "Gravis Ultrasound", + gus_default_mixer_ioctl }; -static void -gus_default_mixer_init (void) +static int +gus_default_mixer_init(void) { - if (num_mixers < MAX_MIXER_DEV) /* - * Don't install if there is another - * mixer - */ - mixer_devs[num_mixers++] = &gus_mixer_operations; + int n; - if (have_gus_max) - { + if ((n = sound_alloc_mixerdev()) != -1) + { /* + * Don't install if there is another + * mixer + */ + mixer_devs[n] = &gus_mixer_operations; + } + if (have_gus_max) + { /* * Enable all mixer channels on the GF1 side. Otherwise recording will * not be possible using GUS MAX. */ - mix_image &= ~0x07; - mix_image |= 0x04; /* All channels enabled */ - outb ((mix_image), u_Mixer); - } + mix_image &= ~0x07; + mix_image |= 0x04; /* All channels enabled */ + outb((mix_image), u_Mixer); + } + return n; } void -gus_wave_init (struct address_info *hw_config) +gus_wave_init(struct address_info *hw_config) { - unsigned long flags; - unsigned char val; - char *model_num = "2.4"; - char tmp[64], tmp2[64]; - int gus_type = 0x24; /* 2.4 */ - - int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; - - if (!gus_pnp_flag) - if (irq < 0 || irq > 15) - { - printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return; - } - - if (dma < 0 || dma > 7 || dma == 4) - { - printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return; - } - - gus_irq = irq; - gus_dma = dma; - gus_dma2 = dma2; - - if (gus_dma2 == -1) - gus_dma2 = dma; - - /* - * Try to identify the GUS model. - * - * Versions < 3.6 don't have the digital ASIC. Try to probe it first. - */ - - save_flags (flags); - cli (); - outb ((0x20), gus_base + 0x0f); - val = inb (gus_base + 0x0f); - restore_flags (flags); - - if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ - { - int ad_flags = 0; - - if (gus_pnp_flag) - ad_flags = 0x12345678; /* Interwave "magic" */ - /* - * It has the digital ASIC so the card is at least v3.4. - * Next try to detect the true model. - */ - - if (gus_pnp_flag) /* Hack hack hack */ - val = 10; - else - val = inb (u_MixSelect); - - /* - * Value 255 means pre-3.7 which don't have mixer. - * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. - * 10 and above is GUS MAX which has the CS4231 codec/mixer. - * - */ - - if (val == 255 || val < 5) - { - model_num = "3.4"; - gus_type = 0x34; - } - else if (val < 10) - { - model_num = "3.7"; - gus_type = 0x37; - mixer_type = ICS2101; - request_region (u_MixSelect, 1, "GUS mixer"); - } - else - { - model_num = "MAX"; - gus_type = 0x40; - mixer_type = CS4231; -#ifdef CONFIG_GUSMAX + unsigned long flags; + unsigned char val; + char *model_num = "2.4"; + char tmp[64], tmp2[64]; + int gus_type = 0x24; /* 2.4 */ + + int irq = hw_config->irq, dma = hw_config->dma, + dma2 = hw_config->dma2; + int dev; + int sdev; + + hw_config->slots[0] = -1; /* No wave */ + hw_config->slots[1] = -1; /* No ad1848 */ + hw_config->slots[4] = -1; /* No audio */ + hw_config->slots[5] = -1; /* No mixer */ + + if (!gus_pnp_flag) + if (irq < 0 || irq > 15) + { + printk("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + return; + } + if (dma < 0 || dma > 7 || dma == 4) { - unsigned char max_config = 0x40; /* Codec enable */ + printk("ERROR! Invalid DMA#%d. GUS Disabled", dma); + return; + } + gus_irq = irq; + gus_dma = dma; + gus_dma2 = dma2; + + if (gus_dma2 == -1) + gus_dma2 = dma; + + /* + * Try to identify the GUS model. + * + * Versions < 3.6 don't have the digital ASIC. Try to probe it first. + */ + + save_flags(flags); + cli(); + outb((0x20), gus_base + 0x0f); + val = inb(gus_base + 0x0f); + restore_flags(flags); + + if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ + { + int ad_flags = 0; + + if (gus_pnp_flag) + ad_flags = 0x12345678; /* Interwave "magic" */ + /* + * It has the digital ASIC so the card is at least v3.4. + * Next try to detect the true model. + */ + + if (gus_pnp_flag) /* Hack hack hack */ + val = 10; + else + val = inb(u_MixSelect); + + /* + * Value 255 means pre-3.7 which don't have mixer. + * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. + * 10 and above is GUS MAX which has the CS4231 codec/mixer. + * + */ + + if (val == 255 || val < 5) + { + model_num = "3.4"; + gus_type = 0x34; + } else if (val < 10) + { + model_num = "3.7"; + gus_type = 0x37; + mixer_type = ICS2101; + request_region(u_MixSelect, 1, "GUS mixer"); + } else + { + model_num = "MAX"; + gus_type = 0x40; + mixer_type = CS4231; +#ifdef CONFIG_GUSMAX + { + unsigned char max_config = 0x40; /* Codec enable */ - if (gus_dma2 == -1) - gus_dma2 = gus_dma; + if (gus_dma2 == -1) + gus_dma2 = gus_dma; - if (gus_dma > 3) - max_config |= 0x10; /* 16 bit capture DMA */ + if (gus_dma > 3) + max_config |= 0x10; /* 16 bit capture DMA */ - if (gus_dma2 > 3) - max_config |= 0x20; /* 16 bit playback DMA */ - - max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ - - outb ((max_config), gus_base + 0x106); /* UltraMax control */ - } - - if (ad1848_detect (gus_base + 0x10c, &ad_flags, hw_config->osp)) - { - char *name = "GUS MAX"; - int old_num_mixers = num_mixers; - - if (gus_pnp_flag) - name = "GUS PnP"; - - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - have_gus_max = 1; - if (hw_config->name) - name = hw_config->name; - - ad1848_init (name, gus_base + 0x10c, - -irq, - gus_dma2, /* Playback DMA */ - gus_dma, /* Capture DMA */ - 1, /* Share DMA channels with GF1 */ - hw_config->osp); - - if (num_mixers > old_num_mixers) - { /* GUS has it's own mixer map */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE); - } - } - else - printk ("[Where's the CS4231?]"); + if (gus_dma2 > 3) + max_config |= 0x20; /* 16 bit playback DMA */ + + max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ + + outb((max_config), gus_base + 0x106); /* UltraMax control */ + } + + if (ad1848_detect(gus_base + 0x10c, &ad_flags, hw_config->osp)) + { + char *name = "GUS MAX"; + int old_num_mixers = num_mixers; + + if (gus_pnp_flag) + name = "GUS PnP"; + + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + have_gus_max = 1; + if (hw_config->name) + name = hw_config->name; + + hw_config->slots[1] = ad1848_init(name, gus_base + 0x10c, + -irq, + gus_dma2, /* Playback DMA */ + gus_dma, /* Capture DMA */ + 1, /* Share DMA channels with GF1 */ + hw_config->osp); + + if (num_mixers > old_num_mixers) + { /* GUS has it's own mixer map */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } + } else + printk("[Where's the CS4231?]"); #else - printk ("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); + printk("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); #endif - } - } - else - { - /* - * ASIC not detected so the card must be 2.2 or 2.4. - * There could still be the 16-bit/mixer daughter card. - */ - } - - if (hw_config->name) - { - - strncpy (tmp, hw_config->name, 45); - tmp[45] = 0; - sprintf (tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024); - tmp2[sizeof (tmp2) - 1] = 0; - } - else if (gus_pnp_flag) - { - sprintf (tmp2, "Gravis UltraSound PnP (%dk)", - (int) gus_mem_size / 1024); - } - else - sprintf (tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); - - - samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc ((MAX_SAMPLE + 1) * sizeof (*samples))); - sound_mem_sizes[sound_nblocks] = (MAX_SAMPLE + 1) * sizeof (*samples); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (samples == NULL) - { - printk ("GUS Error: Cant allocate memory for instrument tables\n"); - return; - } - - conf_printf (tmp2, hw_config); - tmp2[sizeof (gus_info.name) - 1] = 0; - strcpy (gus_info.name, tmp2); - - if (num_synths >= MAX_SYNTH_DEV) - printk ("GUS Error: Too many synthesizers\n"); - else - { - voice_alloc = &guswave_operations.alloc; - if (iw_mode) - guswave_operations.id = "IWAVE"; - synth_devs[num_synths++] = &guswave_operations; - sequencer_init (); -#ifdef CONFIG_SEQUENCER - gus_tmr_install (gus_base + 8); + } + } else + { + /* + * ASIC not detected so the card must be 2.2 or 2.4. + * There could still be the 16-bit/mixer daughter card. + */ + } + + if (hw_config->name) + { + + strncpy(tmp, hw_config->name, 45); + tmp[45] = 0; + sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024); + tmp2[sizeof(tmp2) - 1] = 0; + } else if (gus_pnp_flag) + { + sprintf(tmp2, "Gravis UltraSound PnP (%dk)", + (int) gus_mem_size / 1024); + } else + sprintf(tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); + + + samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc((MAX_SAMPLE + 1) * sizeof(*samples))); + sound_mem_sizes[sound_nblocks] = (MAX_SAMPLE + 1) * sizeof(*samples); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (samples == NULL) + { + printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n"); + return; + } + conf_printf(tmp2, hw_config); + tmp2[sizeof(gus_info.name) - 1] = 0; + strcpy(gus_info.name, tmp2); + + if ((sdev = sound_alloc_synthdev()) == -1) + printk(KERN_WARNING "gus_init: Too many synthesizers\n"); + else + { + voice_alloc = &guswave_operations.alloc; + if (iw_mode) + guswave_operations.id = "IWAVE"; + hw_config->slots[0] = sdev; + synth_devs[sdev] = &guswave_operations; + sequencer_init(); +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + gus_tmr_install(gus_base + 8); #endif - } + } + + reset_sample_memory(); + + gus_initialize(); + + if (gus_mem_size > 0) + if ((dev = sound_alloc_audiodev()) != -1) + { + hw_config->slots[4] = dev; + if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + "Ultrasound", + &gus_audio_driver, + sizeof(struct audio_driver), + NEEDS_RESTART | + ((!iw_mode && dma2 != dma && dma2 != -1) ? + DMA_DUPLEX : 0), + AFMT_U8 | AFMT_S16_LE, + NULL, + dma, + dma2)) < 0) + return; + + audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ + audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ + audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */ + audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; + } else + printk("GUS: Too many audio devices available\n"); - reset_sample_memory (); + /* + * Mixer dependent initialization. + */ - gus_initialize (); + switch (mixer_type) + { + case ICS2101: + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + request_region(u_MixSelect, 1, "GUS mixer"); + hw_config->slots[5] = ics2101_mixer_init(); + audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ + return; - if (gus_mem_size > 0) - if (num_audiodevs < MAX_AUDIO_DEV) - { - - if ((gus_devnum = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - "Ultrasound", - &gus_audio_driver, - sizeof (struct audio_driver), - NEEDS_RESTART | - ((!iw_mode && dma2 != dma && dma2 != -1) ? - DMA_DUPLEX : 0), - AFMT_U8 | AFMT_S16_LE, - NULL, - dma, - dma2)) < 0) - return; - - audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ - audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ - audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */ - audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; - } - else - printk ("GUS: Too many audio devices available\n"); - - /* - * Mixer dependent initialization. - */ - - switch (mixer_type) - { - case ICS2101: - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - request_region (u_MixSelect, 1, "GUS mixer"); - ics2101_mixer_init (); - return; - - case CS4231: - /* Initialized elsewhere (ad1848.c) */ - default: - gus_default_mixer_init (); - return; - } + case CS4231: + /* Initialized elsewhere (ad1848.c) */ + default: + hw_config->slots[5] = gus_default_mixer_init(); + audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ + return; + } } void -gus_wave_unload (void) +gus_wave_unload(struct address_info *hw_config) { #ifdef CONFIG_GUSMAX - if (have_gus_max) - { - ad1848_unload (gus_base + 0x10c, - -gus_irq, - gus_dma2, /* Playback DMA */ - gus_dma, /* Capture DMA */ - 1); /* Share DMA channels with GF1 */ - } + if (have_gus_max) + { + ad1848_unload(gus_base + 0x10c, + -gus_irq, + gus_dma2, /* Playback DMA */ + gus_dma, /* Capture DMA */ + 1); /* Share DMA channels with GF1 */ + } #endif - if (mixer_type == ICS2101) - { - release_region (u_MixSelect, 1); - } + if (mixer_type == ICS2101) + { + release_region(u_MixSelect, 1); + } + if (hw_config->slots[0] != -1) + sound_unload_synthdev(hw_config->slots[0]); + if (hw_config->slots[1] != -1) + sound_unload_audiodev(hw_config->slots[1]); + if (hw_config->slots[2] != -1) + sound_unload_mididev(hw_config->slots[2]); + if (hw_config->slots[4] != -1) + sound_unload_audiodev(hw_config->slots[4]); + if (hw_config->slots[5] != -1) + sound_unload_mixerdev(hw_config->slots[4]); } static void -do_loop_irq (int voice) -{ - unsigned char tmp; - int mode, parm; - unsigned long flags; - - save_flags (flags); - cli (); - gus_select_voice (voice); +do_loop_irq(int voice) +{ + unsigned char tmp; + int mode, parm; + unsigned long flags; + + save_flags(flags); + cli(); + gus_select_voice(voice); - tmp = gus_read8 (0x00); - tmp &= ~0x20; /* + tmp = gus_read8(0x00); + tmp &= ~0x20; /* * Disable wave IRQ for this_one voice */ - gus_write8 (0x00, tmp); + gus_write8(0x00, tmp); - if (tmp & 0x03) /* Voice stopped */ - voice_alloc->map[voice] = 0; + if (tmp & 0x03) /* Voice stopped */ + voice_alloc->map[voice] = 0; - mode = voices[voice].loop_irq_mode; - voices[voice].loop_irq_mode = 0; - parm = voices[voice].loop_irq_parm; + mode = voices[voice].loop_irq_mode; + voices[voice].loop_irq_mode = 0; + parm = voices[voice].loop_irq_parm; - switch (mode) - { + switch (mode) + { - case LMODE_FINISH: /* + case LMODE_FINISH: /* * Final loop finished, shoot volume down */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* - * Get current volume - */ - { - gus_voice_off (); - gus_rampoff (); - gus_voice_init (voice); - break; - } - gus_ramp_range (65, 4065); - gus_ramp_rate (0, 63); /* - * Fastest possible rate - */ - gus_rampon (0x20 | 0x40); /* - * Ramp down, once, irq - */ - voices[voice].volume_irq_mode = VMODE_HALT; - break; + if ((int) (gus_read16(0x09) >> 4) < 100) /* + * Get current volume + */ + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + break; + } + gus_ramp_range(65, 4065); + gus_ramp_rate(0, 63); /* + * Fastest possible rate + */ + gus_rampon(0x20 | 0x40); /* + * Ramp down, once, irq + */ + voices[voice].volume_irq_mode = VMODE_HALT; + break; + + case LMODE_PCM_STOP: + pcm_active = 0; /* Signal to the play_next_pcm_block routine */ + case LMODE_PCM: + { + + pcm_qlen--; + pcm_head = (pcm_head + 1) % pcm_nblk; + if (pcm_qlen && pcm_active) + { + play_next_pcm_block(); + } else + { /* Underrun. Just stop the voice */ + gus_select_voice(0); /* Left channel */ + gus_voice_off(); + gus_rampoff(); + gus_select_voice(1); /* Right channel */ + gus_voice_off(); + gus_rampoff(); + pcm_active = 0; + } + + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + break; - case LMODE_PCM_STOP: - pcm_active = 0; /* Signal to the play_next_pcm_block routine */ - case LMODE_PCM: - { - - pcm_qlen--; - pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen && pcm_active) - { - play_next_pcm_block (); - } - else - { /* Underrun. Just stop the voice */ - gus_select_voice (0); /* Left channel */ - gus_voice_off (); - gus_rampoff (); - gus_select_voice (1); /* Right channel */ - gus_voice_off (); - gus_rampoff (); - pcm_active = 0; + default:; } - - /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr (gus_devnum, 0); - } - break; - - default:; - } - restore_flags (flags); + restore_flags(flags); } static void -do_volume_irq (int voice) +do_volume_irq(int voice) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + unsigned char tmp; + int mode, parm; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - gus_select_voice (voice); + gus_select_voice(voice); - tmp = gus_read8 (0x0d); - tmp &= ~0x20; /* + tmp = gus_read8(0x0d); + tmp &= ~0x20; /* * Disable volume ramp IRQ */ - gus_write8 (0x0d, tmp); + gus_write8(0x0d, tmp); - mode = voices[voice].volume_irq_mode; - voices[voice].volume_irq_mode = 0; - parm = voices[voice].volume_irq_parm; - - switch (mode) - { - case VMODE_HALT: /* Decay phase finished */ - if (iw_mode) - gus_write8 (0x15, 0x02); /* Set voice deactivate bit of SMSI */ - restore_flags (flags); - gus_voice_init (voice); - break; - - case VMODE_ENVELOPE: - gus_rampoff (); - restore_flags (flags); - step_envelope (voice); - break; - - case VMODE_START_NOTE: - restore_flags (flags); - guswave_start_note2 (voices[voice].dev_pending, voice, - voices[voice].note_pending, voices[voice].volume_pending); - if (voices[voice].kill_pending) - guswave_kill_note (voices[voice].dev_pending, voice, - voices[voice].note_pending, 0); - - if (voices[voice].sample_pending >= 0) - { - guswave_set_instr (voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - } - break; - - default:; - } - restore_flags (flags); + mode = voices[voice].volume_irq_mode; + voices[voice].volume_irq_mode = 0; + parm = voices[voice].volume_irq_parm; + + switch (mode) + { + case VMODE_HALT: /* Decay phase finished */ + if (iw_mode) + gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */ + restore_flags(flags); + gus_voice_init(voice); + break; + + case VMODE_ENVELOPE: + gus_rampoff(); + restore_flags(flags); + step_envelope(voice); + break; + + case VMODE_START_NOTE: + restore_flags(flags); + guswave_start_note2(voices[voice].dev_pending, voice, + voices[voice].note_pending, voices[voice].volume_pending); + if (voices[voice].kill_pending) + guswave_kill_note(voices[voice].dev_pending, voice, + voices[voice].note_pending, 0); + + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; + + default: + restore_flags(flags); + } + restore_flags(flags); } void -gus_voice_irq (void) +gus_voice_irq(void) { - unsigned long wave_ignore = 0, volume_ignore = 0; - unsigned long voice_bit; - - unsigned char src, voice; + unsigned long wave_ignore = 0, volume_ignore = 0; + unsigned long voice_bit; - while (1) - { - src = gus_read8 (0x0f); /* - * Get source info - */ - voice = src & 0x1f; - src &= 0xc0; + unsigned char src, voice; - if (src == (0x80 | 0x40)) - return; /* - * No interrupt - */ - - voice_bit = 1 << voice; - - if (!(src & 0x80)) /* - * Wave IRQ pending - */ - if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ + while (1) { - wave_ignore |= voice_bit; - do_loop_irq (voice); - } + src = gus_read8(0x0f); /* + * Get source info + */ + voice = src & 0x1f; + src &= 0xc0; + + if (src == (0x80 | 0x40)) + return; /* + * No interrupt + */ - if (!(src & 0x40)) /* - * Volume IRQ pending - */ - if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ - { - volume_ignore |= voice_bit; - do_volume_irq (voice); + voice_bit = 1 << voice; + + if (!(src & 0x80)) /* + * Wave IRQ pending + */ + if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* + * Not done + * yet + */ + { + wave_ignore |= voice_bit; + do_loop_irq(voice); + } + if (!(src & 0x40)) /* + * Volume IRQ pending + */ + if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* + * Not done + * yet + */ + { + volume_ignore |= voice_bit; + do_volume_irq(voice); + } } - } } void -guswave_dma_irq (void) +guswave_dma_irq(void) { - unsigned char status; - - status = gus_look8 (0x41); /* Get DMA IRQ Status */ - if (status & 0x40) /* DMA interrupt pending */ - switch (active_device) - { - case GUS_DEV_WAVE: - if ((dram_sleep_flag.opts & WK_SLEEP)) - { - dram_sleep_flag.opts = WK_WAKEUP; - wake_up (&dram_sleeper); - }; - break; - - case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - gus_transfer_output_block (pcm_current_dev, pcm_current_buf, - pcm_current_count, - pcm_current_intrflag, 1); - break; - - case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - if (pcm_qlen < pcm_nblk) - { - dma_active = 0; - if (gus_busy) - { - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr (gus_devnum, 0); - } - } - break; - - default:; - } + unsigned char status; - status = gus_look8 (0x49); /* - * Get Sampling IRQ Status - */ - if (status & 0x40) /* + status = gus_look8(0x41); /* Get DMA IRQ Status */ + if (status & 0x40) /* DMA interrupt pending */ + switch (active_device) + { + case GUS_DEV_WAVE: + if ((dram_sleep_flag.opts & WK_SLEEP)) + { + dram_sleep_flag.opts = WK_WAKEUP; + wake_up(&dram_sleeper); + }; + break; + + case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + gus_transfer_output_block(pcm_current_dev, pcm_current_buf, + pcm_current_count, + pcm_current_intrflag, 1); + break; + + case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + if (pcm_qlen < pcm_nblk) + { + dma_active = 0; + if (gus_busy) + { + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + } + break; + + default:; + } + status = gus_look8(0x49); /* + * Get Sampling IRQ Status + */ + if (status & 0x40) /* * Sampling Irq pending */ - { - DMAbuf_inputintr (gus_devnum); - } - + { + DMAbuf_inputintr(gus_devnum); + } } -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + /* * Timer stuff */ @@ -3583,105 +3527,103 @@ static volatile int curr_timer = 0; void -gus_timer_command (unsigned int addr, unsigned int val) +gus_timer_command(unsigned int addr, unsigned int val) { - int i; + int i; - outb (((unsigned char) (addr & 0xff)), select_addr); + outb(((unsigned char) (addr & 0xff)), select_addr); - for (i = 0; i < 2; i++) - inb (select_addr); + for (i = 0; i < 2; i++) + inb(select_addr); - outb (((unsigned char) (val & 0xff)), data_addr); + outb(((unsigned char) (val & 0xff)), data_addr); - for (i = 0; i < 2; i++) - inb (select_addr); + for (i = 0; i < 2; i++) + inb(select_addr); } static void -arm_timer (int timer, unsigned int interval) +arm_timer(int timer, unsigned int interval) { - curr_timer = timer; + curr_timer = timer; - if (timer == 1) - { - gus_write8 (0x46, 256 - interval); /* Set counter for timer 1 */ - gus_write8 (0x45, 0x04); /* Enable timer 1 IRQ */ - gus_timer_command (0x04, 0x01); /* Start timer 1 */ - } - else - { - gus_write8 (0x47, 256 - interval); /* Set counter for timer 2 */ - gus_write8 (0x45, 0x08); /* Enable timer 2 IRQ */ - gus_timer_command (0x04, 0x02); /* Start timer 2 */ - } + if (timer == 1) + { + gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ + gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ + gus_timer_command(0x04, 0x01); /* Start timer 1 */ + } else + { + gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ + gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ + gus_timer_command(0x04, 0x02); /* Start timer 2 */ + } - gus_timer_enabled = 1; + gus_timer_enabled = 1; } static unsigned int -gus_tmr_start (int dev, unsigned int usecs_per_tick) +gus_tmr_start(int dev, unsigned int usecs_per_tick) { - int timer_no, resolution; - int divisor; + int timer_no, resolution; + int divisor; - if (usecs_per_tick > (256 * 80)) - { - timer_no = 2; - resolution = 320; /* usec */ - } - else - { - timer_no = 1; - resolution = 80; /* usec */ - } + if (usecs_per_tick > (256 * 80)) + { + timer_no = 2; + resolution = 320; /* usec */ + } else + { + timer_no = 1; + resolution = 80; /* usec */ + } - divisor = (usecs_per_tick + (resolution / 2)) / resolution; + divisor = (usecs_per_tick + (resolution / 2)) / resolution; - arm_timer (timer_no, divisor); + arm_timer(timer_no, divisor); - return divisor * resolution; + return divisor * resolution; } static void -gus_tmr_disable (int dev) +gus_tmr_disable(int dev) { - gus_write8 (0x45, 0); /* Disable both timers */ - gus_timer_enabled = 0; + gus_write8(0x45, 0); /* Disable both timers */ + gus_timer_enabled = 0; } static void -gus_tmr_restart (int dev) +gus_tmr_restart(int dev) { - if (curr_timer == 1) - gus_write8 (0x45, 0x04); /* Start timer 1 again */ - else - gus_write8 (0x45, 0x08); /* Start timer 2 again */ - gus_timer_enabled = 1; + if (curr_timer == 1) + gus_write8(0x45, 0x04); /* Start timer 1 again */ + else + gus_write8(0x45, 0x08); /* Start timer 2 again */ + gus_timer_enabled = 1; } static struct sound_lowlev_timer gus_tmr = { - 0, - 1, - gus_tmr_start, - gus_tmr_disable, - gus_tmr_restart + 0, + 1, + gus_tmr_start, + gus_tmr_disable, + gus_tmr_restart }; static void -gus_tmr_install (int io_base) +gus_tmr_install(int io_base) { - struct sound_lowlev_timer *tmr; + struct sound_lowlev_timer *tmr; - select_addr = io_base; - data_addr = io_base + 1; + select_addr = io_base; + data_addr = io_base + 1; - tmr = &gus_tmr; + tmr = &gus_tmr; #ifdef THIS_GETS_FIXED - sound_timer_init (&gus_tmr, "GUS"); + sound_timer_init(&gus_tmr, "GUS"); #endif } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.1.66/linux/drivers/sound/ics2101.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/ics2101.c Sat Nov 29 10:33:20 1997 @@ -14,7 +14,7 @@ #include "sound_config.h" -#if defined(CONFIG_GUSHW) +#if defined(CONFIG_GUSHW) || defined(MODULE) #include #include "gus_hw.h" @@ -31,222 +31,206 @@ static int right_fix[ICS_MIXDEVS] = {2, 2, 2, 1, 2, 1}; -static int -scale_vol (int vol) +static int scale_vol(int vol) { - /* - * Experimental volume scaling by Risto Kankkunen. - * This should give smoother volume response than just - * a plain multiplication. - */ - int e; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - vol = (31 * vol + 50) / 100; - e = 0; - if (vol) - { - while (vol < 16) + /* + * Experimental volume scaling by Risto Kankkunen. + * This should give smoother volume response than just + * a plain multiplication. + */ + + int e; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + vol = (31 * vol + 50) / 100; + e = 0; + if (vol) { - vol <<= 1; - e--; + while (vol < 16) + { + vol <<= 1; + e--; + } + vol -= 16; + e += 7; } - vol -= 16; - e += 7; - } - return ((e << 4) + vol); + return ((e << 4) + vol); } -static void -write_mix (int dev, int chn, int vol) +static void write_mix(int dev, int chn, int vol) { - int *selector; - unsigned long flags; - int ctrl_addr = dev << 3; - int attn_addr = dev << 3; - - vol = scale_vol (vol); - - if (chn == CHN_LEFT) - { - selector = left_fix; - ctrl_addr |= 0x00; - attn_addr |= 0x02; - } - else - { - selector = right_fix; - ctrl_addr |= 0x01; - attn_addr |= 0x03; - } - - save_flags (flags); - cli (); - outb ((ctrl_addr), u_MixSelect); - outb ((selector[dev]), u_MixData); - outb ((attn_addr), u_MixSelect); - outb (((unsigned char) vol), u_MixData); - restore_flags (flags); + int *selector; + unsigned long flags; + int ctrl_addr = dev << 3; + int attn_addr = dev << 3; + + vol = scale_vol(vol); + + if (chn == CHN_LEFT) + { + selector = left_fix; + ctrl_addr |= 0x00; + attn_addr |= 0x02; + } + else + { + selector = right_fix; + ctrl_addr |= 0x01; + attn_addr |= 0x03; + } + + save_flags(flags); + cli(); + outb((ctrl_addr), u_MixSelect); + outb((selector[dev]), u_MixData); + outb((attn_addr), u_MixSelect); + outb(((unsigned char) vol), u_MixData); + restore_flags(flags); } -static int -set_volumes (int dev, int vol) +static int set_volumes(int dev, int vol) { - int left = vol & 0x00ff; - int right = (vol >> 8) & 0x00ff; + int left = vol & 0x00ff; + int right = (vol >> 8) & 0x00ff; - if (left < 0) - left = 0; - if (left > 100) - left = 100; - if (right < 0) - right = 0; - if (right > 100) - right = 100; - - write_mix (dev, CHN_LEFT, left); - write_mix (dev, CHN_RIGHT, right); - - vol = left + (right << 8); - volumes[dev] = vol; - return vol; + if (left < 0) + left = 0; + if (left > 100) + left = 100; + if (right < 0) + right = 0; + if (right > 100) + right = 100; + + write_mix(dev, CHN_LEFT, left); + write_mix(dev, CHN_RIGHT, right); + + vol = left + (right << 8); + volumes[dev] = vol; + return vol; } -static int -ics2101_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR (cmd) & _SIOC_WRITE) + if (((cmd >> 8) & 0xff) == 'M') { - int val; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { + int val; - val = *(int *) arg; + val = *(int *) arg; - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - return gus_default_mixer_ioctl (dev, cmd, arg); - break; - - case SOUND_MIXER_MIC: - return (*(int *) arg = set_volumes (DEV_MIC, val)); - break; - - case SOUND_MIXER_CD: - return (*(int *) arg = set_volumes (DEV_CD, val)); - break; - - case SOUND_MIXER_LINE: - return (*(int *) arg = set_volumes (DEV_LINE, val)); - break; - - case SOUND_MIXER_SYNTH: - return (*(int *) arg = set_volumes (DEV_GF1, val)); - break; - - case SOUND_MIXER_VOLUME: - return (*(int *) arg = set_volumes (DEV_VOL, val)); - break; - - default: - return -EINVAL; - } - } - else - switch (cmd & 0xff) /* - * Return parameters - */ - { - - case SOUND_MIXER_RECSRC: - return gus_default_mixer_ioctl (dev, cmd, arg); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = MIX_DEVS); - break; - - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); - break; - - case SOUND_MIXER_MIC: - return (*(int *) arg = volumes[DEV_MIC]); - break; - - case SOUND_MIXER_LINE: - return (*(int *) arg = volumes[DEV_LINE]); - break; - - case SOUND_MIXER_CD: - return (*(int *) arg = volumes[DEV_CD]); - break; - - case SOUND_MIXER_VOLUME: - return (*(int *) arg = volumes[DEV_VOL]); - break; - - case SOUND_MIXER_SYNTH: - return (*(int *) arg = volumes[DEV_GF1]); - break; - - default: - return -EINVAL; - } - } + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + return gus_default_mixer_ioctl(dev, cmd, arg); + + case SOUND_MIXER_MIC: + return (*(int *) arg = set_volumes(DEV_MIC, val)); + + case SOUND_MIXER_CD: + return (*(int *) arg = set_volumes(DEV_CD, val)); + + case SOUND_MIXER_LINE: + return (*(int *) arg = set_volumes(DEV_LINE, val)); + + case SOUND_MIXER_SYNTH: + return (*(int *) arg = set_volumes(DEV_GF1, val)); + + case SOUND_MIXER_VOLUME: + return (*(int *) arg = set_volumes(DEV_VOL, val)); + + default: + return -EINVAL; + } + } + else + { + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return gus_default_mixer_ioctl(dev, cmd, arg); - return -EINVAL; + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = MIX_DEVS); + + case SOUND_MIXER_STEREODEVS: + return (*(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC); + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE); + + case SOUND_MIXER_CAPS: + return (*(int *) arg = 0); + break; + + case SOUND_MIXER_MIC: + return (*(int *) arg = volumes[DEV_MIC]); + + case SOUND_MIXER_LINE: + return (*(int *) arg = volumes[DEV_LINE]); + + case SOUND_MIXER_CD: + return (*(int *) arg = volumes[DEV_CD]); + + case SOUND_MIXER_VOLUME: + return (*(int *) arg = volumes[DEV_VOL]); + + case SOUND_MIXER_SYNTH: + return (*(int *) arg = volumes[DEV_GF1]); + + default: + return -EINVAL; + } + } + } + return -EINVAL; } static struct mixer_operations ics2101_mixer_operations = { - "ICS2101", - "ICS2101 Multimedia Mixer", - ics2101_mixer_ioctl + "ICS2101", + "ICS2101 Multimedia Mixer", + ics2101_mixer_ioctl }; -void -ics2101_mixer_init (void) +int +ics2101_mixer_init(void) { - int i; - - if (num_mixers < MAX_MIXER_DEV) - { - mixer_devs[num_mixers++] = &ics2101_mixer_operations; - - /* - * Some GUS v3.7 cards had some channels flipped. Disable - * the flipping feature if the model id is other than 5. - */ + int i; + int n; - if (inb (u_MixSelect) != 5) + if ((n = sound_alloc_mixerdev()) != -1) { - for (i = 0; i < ICS_MIXDEVS; i++) - left_fix[i] = 1; - for (i = 0; i < ICS_MIXDEVS; i++) - right_fix[i] = 2; - } - - set_volumes (DEV_GF1, 0x5a5a); - set_volumes (DEV_CD, 0x5a5a); - set_volumes (DEV_MIC, 0x0000); - set_volumes (DEV_LINE, 0x5a5a); - set_volumes (DEV_VOL, 0x5a5a); - set_volumes (DEV_UNUSED, 0x0000); - } + n = num_mixers; + mixer_devs[n] = &ics2101_mixer_operations; + /* + * Some GUS v3.7 cards had some channels flipped. Disable + * the flipping feature if the model id is other than 5. + */ + + if (inb(u_MixSelect) != 5) + { + for (i = 0; i < ICS_MIXDEVS; i++) + left_fix[i] = 1; + for (i = 0; i < ICS_MIXDEVS; i++) + right_fix[i] = 2; + } + set_volumes(DEV_GF1, 0x5a5a); + set_volumes(DEV_CD, 0x5a5a); + set_volumes(DEV_MIC, 0x0000); + set_volumes(DEV_LINE, 0x5a5a); + set_volumes(DEV_VOL, 0x5a5a); + set_volumes(DEV_UNUSED, 0x0000); + } + return n; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/local.h.master linux/drivers/sound/local.h.master --- v2.1.66/linux/drivers/sound/local.h.master Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/local.h.master Sat Nov 29 10:33:20 1997 @@ -0,0 +1,228 @@ +/* Computer generated file. Please don't edit! */ + +#define KERNEL_COMPATIBLE_CONFIG + +#define SELECTED_SOUND_OPTIONS 0x00000000 + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) +# define CONFIG_MPU_EMU +#endif + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_MSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_MSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) +# define CONFIG_AD1848 +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_PSS) || \ + defined(CONFIG_GUS16) || defined(CONFIG_GUSMAX) || \ + defined(CONFIG_MSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_OPL3SA1) || \ + defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_GUS16_MODULE) || defined(CONFIG_GUSMAX_MODULE) || \ + defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \ + defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_AUDIO +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_MPU401) || \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_OPL3SA1) || defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_MPU401_MODULE) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) || \ + defined(CONFIG_OPL3SA1_MODULE) || defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_MIDI +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP +#endif +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP_MODULE +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) +# define CONFIG_UART401 +#endif + +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +#ifndef CONFIG_UART401_MODULE +#define CONFIG_UART401_MODULE +#endif +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_ADLIB) || defined(CONFIG_GUS) || \ + defined(CONFIG_MPU401) || defined(CONFIG_PSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_MAUI) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_ADLIB_MODULE) || defined(CONFIG_GUS_MODULE) || \ + defined(CONFIG_MPU401_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \ + defined(CONFIG_MAUI_MODULE) +# define CONFIG_SEQUENCER +#endif + +/* + * Force on additional support + */ + +#define SM_WAVE +#define __SGNXPRO__ +#define SM_GAMES +#define DESKPROXL +/* Computer generated file. Please don't edit! */ + +#define KERNEL_COMPATIBLE_CONFIG + +#define SELECTED_SOUND_OPTIONS 0x00000000 + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) +# define CONFIG_MPU_EMU +#endif + +#if \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_MSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_MSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) +# define CONFIG_AD1848 +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_PSS) || \ + defined(CONFIG_GUS16) || defined(CONFIG_GUSMAX) || \ + defined(CONFIG_MSS) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_OPL3SA1) || \ + defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_GUS16_MODULE) || defined(CONFIG_GUSMAX_MODULE) || \ + defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \ + defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_AUDIO +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_GUS) || defined(CONFIG_MPU401) || \ + defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ + defined(CONFIG_GUSMAX) || defined(CONFIG_SSCAPE) || \ + defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ + defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ + defined(CONFIG_OPL3SA1) || defined(CONFIG_SOFTOSS) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_GUS_MODULE) || defined(CONFIG_MPU401_MODULE) || \ + defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ + defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ + defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) || \ + defined(CONFIG_OPL3SA1_MODULE) || defined(CONFIG_SOFTOSS_MODULE) +# define CONFIG_MIDI +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP +#endif +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +# define CONFIG_SBDSP_MODULE +#endif + +#if \ + defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) +# define CONFIG_UART401 +#endif + +#if \ + defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) +#ifndef CONFIG_UART401_MODULE +#define CONFIG_UART401_MODULE +#endif +#endif + +#if \ + defined(CONFIG_PAS) || defined(CONFIG_SB) || \ + defined(CONFIG_ADLIB) || defined(CONFIG_GUS) || \ + defined(CONFIG_MPU401) || defined(CONFIG_PSS) || \ + defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ + defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ + defined(CONFIG_MAUI) || \ + defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ + defined(CONFIG_ADLIB_MODULE) || defined(CONFIG_GUS_MODULE) || \ + defined(CONFIG_MPU401_MODULE) || defined(CONFIG_PSS_MODULE) || \ + defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ + defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \ + defined(CONFIG_MAUI_MODULE) +# define CONFIG_SEQUENCER +#endif + +/* + * Force on additional support + */ + +#define SM_WAVE +#define __SGNXPRO__ +#define SM_GAMES +#define DESKPROXL diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/ChangeLog.awe linux/drivers/sound/lowlevel/ChangeLog.awe --- v2.1.66/linux/drivers/sound/lowlevel/ChangeLog.awe Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/lowlevel/ChangeLog.awe Sat Nov 29 10:33:20 1997 @@ -1,3 +1,15 @@ +ver.0.4.2c + - Add a mode to enable drum channel toggle via bank number + change. + +ver.0.4.2b + - Clear voice position after note on + - Change nrvoices according to the current playing mode + +ver.0.4.2a + - Fix a bug in pitch calculation with scale parameter + - Change default chorus & reverb modes + ver.0.4.2 - Use indirect voice allocation mode; used as default mode - Add preset mapping @@ -10,6 +22,10 @@ - Add channel priority mode macro, and disable it as default - Add unset effect macro - Add user defined chorus/reverb modes + - Do not initialize effect parameters when allocating voices + - Accept realtime filter-Q parameter change + - Check value range of set/add effects + - Change drum flags automatically when receiving bank #128 ver.0.4.1 development versions diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/Makefile linux/drivers/sound/lowlevel/Makefile --- v2.1.66/linux/drivers/sound/lowlevel/Makefile Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/lowlevel/Makefile Sat Nov 29 10:33:20 1997 @@ -3,15 +3,19 @@ ALLOBJS = init.o aci.o awe_wave.o aedsp16.o OBJS = init.o -ifdef CONFIG_LOWLEVEL_SOUND -ifdef CONFIG_ACI_MIXER -OBJS := $(OBJS) aci.o +ifeq ($(CONFIG_LOWLEVEL_SOUND),y) +ifeq ($(CONFIG_ACI_MIXER),y) + OBJS := $(OBJS) aci.o endif -ifdef CONFIG_AWE32_SYNTH +ifeq ($(CONFIG_AWE32_SYNTH),y) OBJS := $(OBJS) awe_wave.o +else + ifeq ($(CONFIG_AWE32_SYNTH),m) + MX_OBJS := $(MX_OBJS) awe_wave.o + endif endif -ifdef CONFIG_AEDSP16 -OBJS := $(OBJS) aedsp16.o +ifeq ($(CONFIG_AEDSP16),y) + OBJS := $(OBJS) aedsp16.o endif endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/README.awe linux/drivers/sound/lowlevel/README.awe --- v2.1.66/linux/drivers/sound/lowlevel/README.awe Wed Nov 12 13:34:26 1997 +++ linux/drivers/sound/lowlevel/README.awe Sat Nov 29 10:33:20 1997 @@ -1,6 +1,6 @@ ================================================================ AWE32 Sound Driver for Linux / FreeBSD - version 0.4.2; Sep. 1, 1997 + version 0.4.2c; Oct. 7, 1997 ================================================================ * GENERAL NOTES @@ -41,7 +41,7 @@ The current version supports this type of sounds with a special extension, but it uses a non-standard way of sequencer calls. Then, so far, only drvmidi and playmidi can play the multiple instruments -and stereo sounds properly. +and stereo sounds properly as MIDI sequencers. To load SoundFont files, sfxload utility is required. All AWE32 driver and utilities can be downloaded from: diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/awe_config.h linux/drivers/sound/lowlevel/awe_config.h --- v2.1.66/linux/drivers/sound/lowlevel/awe_config.h Tue Nov 18 17:22:07 1997 +++ linux/drivers/sound/lowlevel/awe_config.h Sat Nov 29 10:33:20 1997 @@ -2,7 +2,7 @@ * sound/awe_config.h * * Configuration of AWE32 sound driver - * version 0.4.2; Sep. 1, 1997 + * version 0.4.2; Sep. 15, 1997 * * Copyright (C) 1996 Takashi Iwai * @@ -27,13 +27,21 @@ /*---------------------------------------------------------------- * system configuration *----------------------------------------------------------------*/ -#define AWE_NEW_KERNEL_INTERFACE /* if you're using obsolete VoxWare 3.0.x on Linux 1.2.x (or FreeBSD), * define the following line. */ #undef AWE_OBSOLETE_VOXWARE +#ifdef __FreeBSD__ +# define AWE_OBSOLETE_VOXWARE +#endif + +/* if you're using OSS-Lite on Linux 2.1.6 or later, define the + * following line. + */ +#define AWE_NEW_KERNEL_INTERFACE + /* if you have lowlevel.h in the lowlevel directory (OSS-Lite), define * the following line. */ @@ -90,7 +98,7 @@ *----------------------------------------------------------------*/ /* initialize FM passthrough even without extended RAM */ -#define AWE_ALWAYS_INIT_FM +#undef AWE_ALWAYS_INIT_FM /* debug on */ #define AWE_DEBUG_ON diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/awe_hw.h linux/drivers/sound/lowlevel/awe_hw.h --- v2.1.66/linux/drivers/sound/lowlevel/awe_hw.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/lowlevel/awe_hw.h Sat Nov 29 10:33:20 1997 @@ -3,7 +3,7 @@ * * Access routines and definitions for the low level driver for the * AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2; Sep. 1, 1997 + * version 0.4.2; Sep. 15, 1997 * * Copyright (C) 1996,1997 Takashi Iwai * diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/awe_version.h linux/drivers/sound/lowlevel/awe_version.h --- v2.1.66/linux/drivers/sound/lowlevel/awe_version.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/lowlevel/awe_version.h Sat Nov 29 10:33:20 1997 @@ -3,8 +3,20 @@ #ifndef AWE_VERSION_H_DEF #define AWE_VERSION_H_DEF -#define AWE_VERSION_NUMBER 0x00040200 -#define AWEDRV_VERSION "0.4.2" +#define AWE_VERSION_NUMBER 0x00040203 +#define AWEDRV_VERSION "0.4.2c" +#define AWE_MAJOR_VERSION(id) (((id) >> 16) & 0xff) +#define AWE_MINOR_VERSION(id) (((id) >> 8) & 0xff) +#define AWE_TINY_VERSION(id) ((id) & 0xff) + +#endif +/* AWE32 driver version number */ + +#ifndef AWE_VERSION_H_DEF +#define AWE_VERSION_H_DEF + +#define AWE_VERSION_NUMBER 0x00040202 +#define AWEDRV_VERSION "0.4.2b" #define AWE_MAJOR_VERSION(id) (((id) >> 16) & 0xff) #define AWE_MINOR_VERSION(id) (((id) >> 8) & 0xff) #define AWE_TINY_VERSION(id) ((id) & 0xff) diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/awe_voice.h linux/drivers/sound/lowlevel/awe_voice.h --- v2.1.66/linux/drivers/sound/lowlevel/awe_voice.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/lowlevel/awe_voice.h Sat Nov 29 10:33:20 1997 @@ -0,0 +1,490 @@ +/* + * sound/awe_voice.h + * + * Voice information definitions for the low level driver for the + * AWE32/Sound Blaster 32 wave table synth. + * version 0.4.2c; Oct. 7, 1997 + * + * Copyright (C) 1996,1997 Takashi Iwai + * + * 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. + */ + +#ifndef AWE_VOICE_H +#define AWE_VOICE_H + +#ifndef SAMPLE_TYPE_AWE32 +#define SAMPLE_TYPE_AWE32 0x20 +#endif + +#ifndef _PATCHKEY +#define _PATCHKEY(id) ((id<<8)|0xfd) +#endif + +/*---------------------------------------------------------------- + * patch information record + *----------------------------------------------------------------*/ + +/* patch interface header: 16 bytes */ +typedef struct awe_patch_info { + short key; /* use AWE_PATCH here */ +#define AWE_PATCH _PATCHKEY(0x07) + + short device_no; /* synthesizer number */ + unsigned short sf_id; /* file id (should be zero) */ + short optarg; /* optional argument */ + int len; /* data length (without this header) */ + + short type; /* patch operation type */ +#define AWE_LOAD_INFO 0 /* awe_voice_rec */ +#define AWE_LOAD_DATA 1 /* awe_sample_info */ +#define AWE_OPEN_PATCH 2 /* awe_open_parm */ +#define AWE_CLOSE_PATCH 3 /* none */ +#define AWE_UNLOAD_PATCH 4 /* none */ +#define AWE_REPLACE_DATA 5 /* awe_sample_info (optarg=#channels)*/ +#define AWE_MAP_PRESET 6 /* awe_voice_map */ +#define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */ +#define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */ + + short reserved; /* word alignment data */ + + /* the actual patch data begins after this */ +#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 + char data[0]; +#endif +} awe_patch_info; + +/*#define AWE_PATCH_INFO_SIZE 16*/ +#define AWE_PATCH_INFO_SIZE sizeof(awe_patch_info) + + +/*---------------------------------------------------------------- + * open patch + *----------------------------------------------------------------*/ + +#define AWE_PATCH_NAME_LEN 32 + +typedef struct _awe_open_parm { + unsigned short type; /* sample type */ +#define AWE_PAT_TYPE_MISC 0 +#define AWE_PAT_TYPE_GM 1 +#define AWE_PAT_TYPE_GS 2 +#define AWE_PAT_TYPE_MT32 3 +#define AWE_PAT_TYPE_XG 4 +#define AWE_PAT_TYPE_SFX 5 +#define AWE_PAT_TYPE_GUS 6 +#define AWE_PAT_TYPE_MAP 7 + +#define AWE_PAT_LOCKED 0x100 /* lock the samples */ + + short reserved; + char name[AWE_PATCH_NAME_LEN]; +} awe_open_parm; + +/*#define AWE_OPEN_PARM_SIZE 28*/ +#define AWE_OPEN_PARM_SIZE sizeof(awe_open_parm) + + +/*---------------------------------------------------------------- + * raw voice information record + *----------------------------------------------------------------*/ + +/* wave table envelope & effect parameters to control EMU8000 */ +typedef struct _awe_voice_parm { + unsigned short moddelay; /* modulation delay (0x8000) */ + unsigned short modatkhld; /* modulation attack & hold time (0x7f7f) */ + unsigned short moddcysus; /* modulation decay & sustain (0x7f7f) */ + unsigned short modrelease; /* modulation release time (0x807f) */ + short modkeyhold, modkeydecay; /* envelope change per key (not used) */ + unsigned short voldelay; /* volume delay (0x8000) */ + unsigned short volatkhld; /* volume attack & hold time (0x7f7f) */ + unsigned short voldcysus; /* volume decay & sustain (0x7f7f) */ + unsigned short volrelease; /* volume release time (0x807f) */ + short volkeyhold, volkeydecay; /* envelope change per key (not used) */ + unsigned short lfo1delay; /* LFO1 delay (0x8000) */ + unsigned short lfo2delay; /* LFO2 delay (0x8000) */ + unsigned short pefe; /* modulation pitch & cutoff (0x0000) */ + unsigned short fmmod; /* LFO1 pitch & cutoff (0x0000) */ + unsigned short tremfrq; /* LFO1 volume & freq (0x0000) */ + unsigned short fm2frq2; /* LFO2 pitch & freq (0x0000) */ + unsigned char cutoff; /* initial cutoff (0xff) */ + unsigned char filterQ; /* initial filter Q [0-15] (0x0) */ + unsigned char chorus; /* chorus send (0x00) */ + unsigned char reverb; /* reverb send (0x00) */ + unsigned short reserved[4]; /* not used */ +} awe_voice_parm; + +#define AWE_VOICE_PARM_SIZE 48 + + +/* wave table parameters: 92 bytes */ +typedef struct _awe_voice_info { + unsigned short sf_id; /* file id (should be zero) */ + unsigned short sample; /* sample id */ + int start, end; /* sample offset correction */ + int loopstart, loopend; /* loop offset correction */ + short rate_offset; /* sample rate pitch offset */ + unsigned short mode; /* sample mode */ +#define AWE_MODE_ROMSOUND 0x8000 +#define AWE_MODE_STEREO 1 +#define AWE_MODE_LOOPING 2 +#define AWE_MODE_NORELEASE 4 /* obsolete */ +#define AWE_MODE_INIT_PARM 8 + + short root; /* midi root key */ + short tune; /* pitch tuning (in cents) */ + char low, high; /* key note range */ + char vellow, velhigh; /* velocity range */ + char fixkey, fixvel; /* fixed key, velocity */ + char pan, fixpan; /* panning, fixed panning */ + short exclusiveClass; /* exclusive class (0 = none) */ + unsigned char amplitude; /* sample volume (127 max) */ + unsigned char attenuation; /* attenuation (0.375dB) */ + short scaleTuning; /* pitch scale tuning(%), normally 100 */ + awe_voice_parm parm; /* voice envelope parameters */ + short index; /* internal index (set by driver) */ +} awe_voice_info; + +/*#define AWE_VOICE_INFO_SIZE 92*/ +#define AWE_VOICE_INFO_SIZE sizeof(awe_voice_info) + +/*----------------------------------------------------------------*/ + +/* The info entry of awe_voice_rec is changed from 0 to 1 + * for some compilers refusing zero size array. + * Due to this change, sizeof(awe_voice_rec) becomes different + * from older versions. + * Use AWE_VOICE_REC_SIZE instead. + */ + +/* instrument info header: 4 bytes */ +typedef struct _awe_voice_rec_hdr { + unsigned char bank; /* midi bank number */ + unsigned char instr; /* midi preset number */ + char nvoices; /* number of voices */ + char write_mode; /* write mode; normally 0 */ +#define AWE_WR_APPEND 0 /* append anyway */ +#define AWE_WR_EXCLUSIVE 1 /* skip if already exists */ +#define AWE_WR_REPLACE 2 /* replace if already exists */ +} awe_voice_rec_hdr; + +/*#define AWE_VOICE_REC_SIZE 4*/ +#define AWE_VOICE_REC_SIZE sizeof(awe_voice_rec_hdr) + +/* the standard patch structure for one sample */ +typedef struct _awe_voice_rec_patch { + awe_patch_info patch; + awe_voice_rec_hdr hdr; + awe_voice_info info; +} awe_voice_rec_patch; + + +/* obsolete data type */ +#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 +#define AWE_INFOARRAY_SIZE 0 +#else +#define AWE_INFOARRAY_SIZE 1 +#endif + +typedef struct _awe_voice_rec { + unsigned char bank; /* midi bank number */ + unsigned char instr; /* midi preset number */ + short nvoices; /* number of voices */ + /* voice information follows here */ + awe_voice_info info[AWE_INFOARRAY_SIZE]; +} awe_voice_rec; + + +/*---------------------------------------------------------------- + * sample wave information + *----------------------------------------------------------------*/ + +/* wave table sample header: 32 bytes */ +typedef struct awe_sample_info { + unsigned short sf_id; /* file id (should be zero) */ + unsigned short sample; /* sample id */ + int start, end; /* start & end offset */ + int loopstart, loopend; /* loop start & end offset */ + int size; /* size (0 = ROM) */ + short checksum_flag; /* use check sum = 1 */ + unsigned short mode_flags; /* mode flags */ +#define AWE_SAMPLE_8BITS 1 /* wave data is 8bits */ +#define AWE_SAMPLE_UNSIGNED 2 /* wave data is unsigned */ +#define AWE_SAMPLE_NO_BLANK 4 /* no blank loop is attached */ +#define AWE_SAMPLE_SINGLESHOT 8 /* single-shot w/o loop */ +#define AWE_SAMPLE_BIDIR_LOOP 16 /* bidirectional looping */ +#define AWE_SAMPLE_STEREO_LEFT 32 /* stereo left sound */ +#define AWE_SAMPLE_STEREO_RIGHT 64 /* stereo right sound */ +#define AWE_SAMPLE_REVERSE_LOOP 128 /* reverse looping */ + unsigned int checksum; /* check sum */ +#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 + unsigned short data[0]; /* sample data follows here */ +#endif +} awe_sample_info; + +/*#define AWE_SAMPLE_INFO_SIZE 32*/ +#define AWE_SAMPLE_INFO_SIZE sizeof(awe_sample_info) + + +/*---------------------------------------------------------------- + * voice preset mapping + *----------------------------------------------------------------*/ + +typedef struct awe_voice_map { + int map_bank, map_instr, map_key; /* key = -1 means all keys */ + int src_bank, src_instr, src_key; +} awe_voice_map; + +#define AWE_VOICE_MAP_SIZE sizeof(awe_voice_map) + + +/*---------------------------------------------------------------- + * awe hardware controls + *----------------------------------------------------------------*/ + +#define _AWE_DEBUG_MODE 0x00 +#define _AWE_REVERB_MODE 0x01 +#define _AWE_CHORUS_MODE 0x02 +#define _AWE_REMOVE_LAST_SAMPLES 0x03 +#define _AWE_INITIALIZE_CHIP 0x04 +#define _AWE_SEND_EFFECT 0x05 +#define _AWE_TERMINATE_CHANNEL 0x06 +#define _AWE_TERMINATE_ALL 0x07 +#define _AWE_INITIAL_VOLUME 0x08 +#define _AWE_INITIAL_ATTEN _AWE_INITIAL_VOLUME +#define _AWE_RESET_CHANNEL 0x09 +#define _AWE_CHANNEL_MODE 0x0a +#define _AWE_DRUM_CHANNELS 0x0b +#define _AWE_MISC_MODE 0x0c +#define _AWE_RELEASE_ALL 0x0d +#define _AWE_NOTEOFF_ALL 0x0e +#define _AWE_CHN_PRESSURE 0x0f +/*#define _AWE_GET_CURRENT_MODE 0x10*/ +#define _AWE_EQUALIZER 0x11 +/*#define _AWE_GET_MISC_MODE 0x12*/ +/*#define _AWE_GET_FONTINFO 0x13*/ + +#define _AWE_MODE_FLAG 0x80 +#define _AWE_COOKED_FLAG 0x40 /* not supported */ +#define _AWE_MODE_VALUE_MASK 0x3F + +/*----------------------------------------------------------------*/ + +#define _AWE_SET_CMD(p,dev,voice,cmd,p1,p2) \ +{((char*)(p))[0] = SEQ_PRIVATE;\ + ((char*)(p))[1] = dev;\ + ((char*)(p))[2] = _AWE_MODE_FLAG|(cmd);\ + ((char*)(p))[3] = voice;\ + ((unsigned short*)(p))[2] = p1;\ + ((unsigned short*)(p))[3] = p2;} + +/* buffered access */ +#define _AWE_CMD(dev, voice, cmd, p1, p2) \ +{_SEQ_NEEDBUF(8);\ + _AWE_SET_CMD(_seqbuf + _seqbufptr, dev, voice, cmd, p1, p2);\ + _SEQ_ADVBUF(8);} + +/* direct access */ +#define _AWE_CMD_NOW(seqfd,dev,voice,cmd,p1,p2) \ +{struct seq_event_rec tmp;\ + _AWE_SET_CMD(&tmp, dev, voice, cmd, p1, p2);\ + ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, &tmp);} + +/*----------------------------------------------------------------*/ + +/* set debugging mode */ +#define AWE_DEBUG_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0) +/* set reverb mode; from 0 to 7 */ +#define AWE_REVERB_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0) +/* set chorus mode; from 0 to 7 */ +#define AWE_CHORUS_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0) + +/* reset channel */ +#define AWE_RESET_CHANNEL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 0, 0) +#define AWE_RESET_CONTROL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 1, 0) + +/* send an effect to all layers */ +#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value) +#define AWE_ADD_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x80),value) +#define AWE_UNSET_EFFECT(dev,voice,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x40),0) +/* send an effect to a layer */ +#define AWE_SEND_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)),value) +#define AWE_ADD_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x80),value) +#define AWE_UNSET_LAYER_EFFECT(dev,voice,layer,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x40),0) + +/* terminate sound on the channel/voice */ +#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0) +/* terminate all sounds */ +#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0) +/* release all sounds (w/o sustain effect) */ +#define AWE_RELEASE_ALL(dev) _AWE_CMD(dev, 0, _AWE_RELEASE_ALL, 0, 0) +/* note off all sounds (w sustain effect) */ +#define AWE_NOTEOFF_ALL(dev) _AWE_CMD(dev, 0, _AWE_NOTEOFF_ALL, 0, 0) + +/* set initial attenuation */ +#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0) +#define AWE_INITIAL_ATTEN AWE_INITIAL_VOLUME +/* relative attenuation */ +#define AWE_SET_ATTEN(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 1) + +/* set channel playing mode; mode=0/1/2 */ +#define AWE_SET_CHANNEL_MODE(dev,mode) _AWE_CMD(dev, 0, _AWE_CHANNEL_MODE, mode, 0) +#define AWE_PLAY_INDIRECT 0 /* indirect voice mode (default) */ +#define AWE_PLAY_MULTI 1 /* multi note voice mode */ +#define AWE_PLAY_DIRECT 2 /* direct single voice mode */ +#define AWE_PLAY_MULTI2 3 /* sequencer2 mode; used internally */ + +/* set drum channel mask; channels is 32bit long value */ +#define AWE_DRUM_CHANNELS(dev,channels) _AWE_CMD(dev, 0, _AWE_DRUM_CHANNELS, ((channels) & 0xffff), ((channels) >> 16)) + +/* set bass and treble control; values are from 0 to 11 */ +#define AWE_EQUALIZER(dev,bass,treble) _AWE_CMD(dev, 0, _AWE_EQUALIZER, bass, treble) + +/* remove last loaded samples */ +#define AWE_REMOVE_LAST_SAMPLES(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0) +/* initialize emu8000 chip */ +#define AWE_INITIALIZE_CHIP(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_INITIALIZE_CHIP, 0, 0) + +/* set miscellaneous modes; meta command */ +#define AWE_MISC_MODE(dev,mode,value) _AWE_CMD(dev, 0, _AWE_MISC_MODE, mode, value) +/* exclusive sound off; 1=off */ +#define AWE_EXCLUSIVE_SOUND(dev,mode) AWE_MISC_MODE(dev,AWE_MD_EXCLUSIVE_SOUND,mode) +/* default GUS bank number */ +#define AWE_SET_GUS_BANK(dev,bank) AWE_MISC_MODE(dev,AWE_MD_GUS_BANK,bank) +/* change panning position in realtime; 0=don't 1=do */ +#define AWE_REALTIME_PAN(dev,mode) AWE_MISC_MODE(dev,AWE_MD_REALTIME_PAN,mode) + +/* extended pressure controls; not portable with other sound drivers */ +#define AWE_KEY_PRESSURE(dev,ch,note,vel) SEQ_START_NOTE(dev,ch,(note)+128,vel) +#define AWE_CHN_PRESSURE(dev,ch,vel) _AWE_CMD(dev,ch,_AWE_CHN_PRESSURE,vel,0) + +/*----------------------------------------------------------------*/ + +/* reverb mode parameters */ +#define AWE_REVERB_ROOM1 0 +#define AWE_REVERB_ROOM2 1 +#define AWE_REVERB_ROOM3 2 +#define AWE_REVERB_HALL1 3 +#define AWE_REVERB_HALL2 4 +#define AWE_REVERB_PLATE 5 +#define AWE_REVERB_DELAY 6 +#define AWE_REVERB_PANNINGDELAY 7 +#define AWE_REVERB_PREDEFINED 8 +/* user can define reverb modes up to 32 */ +#define AWE_REVERB_NUMBERS 32 + +typedef struct awe_reverb_fx_rec { + unsigned short parms[28]; +} awe_reverb_fx_rec; + +/*----------------------------------------------------------------*/ + +/* chorus mode parameters */ +#define AWE_CHORUS_1 0 +#define AWE_CHORUS_2 1 +#define AWE_CHORUS_3 2 +#define AWE_CHORUS_4 3 +#define AWE_CHORUS_FEEDBACK 4 +#define AWE_CHORUS_FLANGER 5 +#define AWE_CHORUS_SHORTDELAY 6 +#define AWE_CHORUS_SHORTDELAY2 7 +#define AWE_CHORUS_PREDEFINED 8 +/* user can define chorus modes up to 32 */ +#define AWE_CHORUS_NUMBERS 32 + +typedef struct awe_chorus_fx_rec { + unsigned short feedback; /* feedback level (0xE600-0xE6FF) */ + unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */ + unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */ + unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */ + unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */ +} awe_chorus_fx_rec; + +/*----------------------------------------------------------------*/ + +/* misc mode types */ +enum { +/* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */ +/* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */ +/* 2*/ AWE_MD_VERSION, /* read only */ +/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* ignored */ +/* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */ +/* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */ +/* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */ +/* 7*/ AWE_MD_ZERO_ATTEN, /* attenuation of max volume (default=32) */ +/* 8*/ AWE_MD_CHN_PRIOR, /* 0/1: set MIDI channel priority mode (default=1) */ +/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity (def=18) */ +/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number (def=0) */ +/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */ +/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */ +/*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */ + AWE_MD_END, +}; + +/*----------------------------------------------------------------*/ + +/* effect parameters */ +enum { + +/* modulation envelope parameters */ +/* 0*/ AWE_FX_ENV1_DELAY, /* WORD: ENVVAL */ +/* 1*/ AWE_FX_ENV1_ATTACK, /* BYTE: up ATKHLD */ +/* 2*/ AWE_FX_ENV1_HOLD, /* BYTE: lw ATKHLD */ +/* 3*/ AWE_FX_ENV1_DECAY, /* BYTE: lw DCYSUS */ +/* 4*/ AWE_FX_ENV1_RELEASE, /* BYTE: lw DCYSUS */ +/* 5*/ AWE_FX_ENV1_SUSTAIN, /* BYTE: up DCYSUS */ +/* 6*/ AWE_FX_ENV1_PITCH, /* BYTE: up PEFE */ +/* 7*/ AWE_FX_ENV1_CUTOFF, /* BYTE: lw PEFE */ + +/* volume envelope parameters */ +/* 8*/ AWE_FX_ENV2_DELAY, /* WORD: ENVVOL */ +/* 9*/ AWE_FX_ENV2_ATTACK, /* BYTE: up ATKHLDV */ +/*10*/ AWE_FX_ENV2_HOLD, /* BYTE: lw ATKHLDV */ +/*11*/ AWE_FX_ENV2_DECAY, /* BYTE: lw DCYSUSV */ +/*12*/ AWE_FX_ENV2_RELEASE, /* BYTE: lw DCYSUSV */ +/*13*/ AWE_FX_ENV2_SUSTAIN, /* BYTE: up DCYSUSV */ + +/* LFO1 (tremolo & vibrato) parameters */ +/*14*/ AWE_FX_LFO1_DELAY, /* WORD: LFO1VAL */ +/*15*/ AWE_FX_LFO1_FREQ, /* BYTE: lo TREMFRQ */ +/*16*/ AWE_FX_LFO1_VOLUME, /* BYTE: up TREMFRQ */ +/*17*/ AWE_FX_LFO1_PITCH, /* BYTE: up FMMOD */ +/*18*/ AWE_FX_LFO1_CUTOFF, /* BYTE: lo FMMOD */ + +/* LFO2 (vibrato) parameters */ +/*19*/ AWE_FX_LFO2_DELAY, /* WORD: LFO2VAL */ +/*20*/ AWE_FX_LFO2_FREQ, /* BYTE: lo FM2FRQ2 */ +/*21*/ AWE_FX_LFO2_PITCH, /* BYTE: up FM2FRQ2 */ + +/* Other overall effect parameters */ +/*22*/ AWE_FX_INIT_PITCH, /* SHORT: pitch offset */ +/*23*/ AWE_FX_CHORUS, /* BYTE: chorus effects send (0-255) */ +/*24*/ AWE_FX_REVERB, /* BYTE: reverb effects send (0-255) */ +/*25*/ AWE_FX_CUTOFF, /* BYTE: up IFATN */ +/*26*/ AWE_FX_FILTERQ, /* BYTE: up CCCA */ + +/* Sample / loop offset changes */ +/*27*/ AWE_FX_SAMPLE_START, /* SHORT: offset */ +/*28*/ AWE_FX_LOOP_START, /* SHORT: offset */ +/*29*/ AWE_FX_LOOP_END, /* SHORT: offset */ +/*30*/ AWE_FX_COARSE_SAMPLE_START, /* SHORT: upper word offset */ +/*31*/ AWE_FX_COARSE_LOOP_START, /* SHORT: upper word offset */ +/*32*/ AWE_FX_COARSE_LOOP_END, /* SHORT: upper word offset */ +/*33*/ AWE_FX_ATTEN, /* BYTE: lo IFATN */ + + AWE_FX_END, +}; + +#endif /* AWE_VOICE_H */ diff -u --recursive --new-file v2.1.66/linux/drivers/sound/lowlevel/awe_wave.c linux/drivers/sound/lowlevel/awe_wave.c --- v2.1.66/linux/drivers/sound/lowlevel/awe_wave.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/lowlevel/awe_wave.c Sat Nov 29 10:33:20 1997 @@ -2,7 +2,7 @@ * sound/awe_wave.c * * The low level driver for the AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2; Sep. 1, 1997 + * version 0.4.2c; Oct. 7, 1997 * * Copyright (C) 1996,1997 Takashi Iwai * @@ -24,12 +24,18 @@ #ifdef __FreeBSD__ # include #else +#ifdef MODULE +#include +#include +#include +# include "../soundmodule.h" +#endif # include "awe_config.h" #endif /*----------------------------------------------------------------*/ -#ifdef CONFIG_AWE32_SYNTH +#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE) #ifdef __FreeBSD__ # include @@ -96,20 +102,21 @@ /* bank record */ typedef struct _awe_voice_list { - int next; /* index list */ - unsigned char bank, instr; - char type, disabled; - awe_voice_info v; + int next; /* linked list with same sf_id */ + unsigned char bank, instr; /* preset number information */ + char type, disabled; /* type=normal/mapped, disabled=boolean */ + awe_voice_info v; /* voice information */ int next_instr; /* preset table list */ int next_bank; /* preset table list */ } awe_voice_list; +/* voice list type */ #define V_ST_NORMAL 0 #define V_ST_MAPPED 1 typedef struct _awe_sample_list { - int next; /* sf list */ - awe_sample_info v; + int next; /* linked list with same sf_id */ + awe_sample_info v; /* sample information */ } awe_sample_list; /* sample and information table */ @@ -153,6 +160,7 @@ /* channel parameters */ typedef struct _awe_chan_info { + int channel; /* channel number */ int bank; /* current tone bank */ int instr; /* current program */ int bender; /* midi pitchbend (-8192 - 8192) */ @@ -163,9 +171,9 @@ int chan_press; /* channel pressure */ int vrec; /* instrument list */ int def_vrec; /* default instrument list */ + int sustained; /* sustain status in MIDI */ FX_Rec fx; /* effects */ FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */ - int sustained; /* sustain status in MIDI */ } awe_chan_info; /* voice parameters */ @@ -203,6 +211,7 @@ #define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED)) #define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON) #define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED)) +#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM)) /* MIDI channel effects information (for hw control) */ @@ -233,15 +242,20 @@ static int patch_opened = 0; /* sample already loaded? */ -static int reverb_mode = 3; /* reverb mode */ -static int chorus_mode = 5; /* chorus mode */ +static int reverb_mode = 4; /* reverb mode */ +static int chorus_mode = 2; /* chorus mode */ static short init_atten = AWE_DEFAULT_ATTENUATION; /* 12dB below */ static int awe_present = FALSE; /* awe device present? */ static int awe_busy = FALSE; /* awe device opened? */ +static int my_dev = -1; +static int my_mixerdev = -1 ; + #define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25)) #define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c))) +#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c))) +#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c))) static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */ static int playing_mode = AWE_PLAY_INDIRECT; @@ -266,6 +280,7 @@ {AWE_DEFAULT_PRESET, TRUE}, /* def_preset */ {AWE_DEFAULT_BANK, TRUE}, /* def_bank */ {AWE_DEFAULT_DRUM, TRUE}, /* def_drum */ + {FALSE, TRUE}, /* toggle_drum_bank */ }; static int misc_modes[AWE_MD_END]; @@ -341,12 +356,15 @@ static void awe_fx_fmmod(int voice, int forced); static void awe_fx_tremfrq(int voice, int forced); static void awe_fx_fm2frq2(int voice, int forced); +static void awe_fx_filterQ(int voice, int forced); static void awe_calc_pitch(int voice); #ifdef AWE_HAS_GUS_COMPATIBILITY static void awe_calc_pitch_from_freq(int voice, int freq); #endif static void awe_calc_volume(int voice); -static void awe_voice_init(int voice, int keep_ch_info); +static void awe_voice_init(int voice, int init_all); +static void awe_channel_init(int ch, int init_all); +static void awe_fx_init(int ch); /* sequencer interface */ static int awe_open(int dev, int mode); @@ -379,6 +397,7 @@ static void awe_voice_change(int voice, fx_affect_func func); static void awe_sostenuto_on(int voice, int forced); static void awe_sustain_off(int voice, int forced); +static void awe_terminate_and_init(int voice, int forced); /* voice search */ static int awe_search_instr(int bank, int preset); @@ -446,7 +465,7 @@ static struct synth_operations awe_operations = { #ifdef AWE_OSS38 - "Emu8000", + "EMU8K", #endif &awe_info, 0, @@ -532,17 +551,17 @@ INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list); INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list); - if (num_synths >= MAX_SYNTH_DEV) - printk("AWE32 Error: too many synthesizers\n"); + if (my_dev=sound_alloc_synthdev()) + printk(KERN_WARNING "AWE32 Error: too many synthesizers\n"); else { voice_alloc = &awe_operations.alloc; voice_alloc->max_voice = awe_max_voices; - synth_devs[num_synths++] = &awe_operations; + synth_devs[my_dev] = &awe_operations; } #ifdef CONFIG_AWE32_MIXER - if (num_mixers < MAX_MIXER_DEV) { - mixer_devs[num_mixers++] = &awe_mixer_operations; + if (my_mixerdev=sound_alloc_mixerdev()) { + mixer_devs[my_mixerdev] = &awe_mixer_operations; } #endif @@ -600,6 +619,8 @@ my_free(voices); my_free(channels); free_tables(); + sound_unload_mixerdev(my_mixerdev); + sound_unload_synthdev(my_dev); awe_present = FALSE; } } @@ -1054,16 +1075,70 @@ *================================================================*/ /* set an effect value */ +#define FX_FLAG_OFF 0 +#define FX_FLAG_SET 1 +#define FX_FLAG_ADD 2 + #define FX_SET(rec,type,value) \ - ((rec)->flags[type] = 1, (rec)->val[type] = (value)) + ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value)) #define FX_ADD(rec,type,value) \ - ((rec)->flags[type] = 2, (rec)->val[type] = (value)) + ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value)) #define FX_UNSET(rec,type) \ - ((rec)->flags[type] = 0, (rec)->val[type] = 0) + ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0) /* check the effect value is set */ #define FX_ON(rec,type) ((rec)->flags[type]) +#define PARM_BYTE 0 +#define PARM_WORD 1 + +static struct PARM_DEFS { + int type; /* byte or word */ + int low, high; /* value range */ + fx_affect_func realtime; /* realtime paramater change */ +} parm_defs[] = { + {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */ + {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */ + {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */ + {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */ + {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */ + + {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */ + {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */ + {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */ + {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */ + + {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */ + {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */ + {PARM_BYTE, 0, 0x7f, awe_fx_tremfrq}, /* lfo1 volume (positive only)*/ + {PARM_BYTE, 0, 0x7f, awe_fx_fmmod}, /* lfo1 pitch (positive only)*/ + {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff (positive only)*/ + + {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */ + {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */ + {PARM_BYTE, 0, 0x7f, awe_fx_fm2frq2}, /* lfo2 pitch (positive only)*/ + + {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */ + {PARM_BYTE, 0, 0xff, NULL}, /* chorus */ + {PARM_BYTE, 0, 0xff, NULL}, /* reverb */ + {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */ + {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */ + + {PARM_WORD, 0, 0xffff, NULL}, /* sample start */ + {PARM_WORD, 0, 0xffff, NULL}, /* loop start */ + {PARM_WORD, 0, 0xffff, NULL}, /* loop end */ + {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */ + {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */ + {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */ + {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */ +}; + + static unsigned char FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value) { @@ -1073,10 +1148,15 @@ effect = lay->val[type]; if (!on && (on = FX_ON(rec, type)) != 0) effect = rec->val[type]; - if (on == 1) + if (on == FX_FLAG_ADD) + effect += (int)value; + if (on) { + if (effect < parm_defs[type].low) + effect = parm_defs[type].low; + else if (effect > parm_defs[type].high) + effect = parm_defs[type].high; return (unsigned char)effect; - else if (on == 2) - return (unsigned char)(effect + (int)value); + } return value; } @@ -1090,10 +1170,15 @@ effect = lay->val[type]; if (!on && (on = FX_ON(rec, type)) != 0) effect = rec->val[type]; - if (on == 1) + if (on == FX_FLAG_ADD) + effect += (int)value; + if (on) { + if (effect < parm_defs[type].low) + effect = parm_defs[type].low; + else if (effect > parm_defs[type].high) + effect = parm_defs[type].high; return (unsigned short)effect; - else if (on == 2) - return (unsigned short)(effect + (int)value); + } return value; } @@ -1229,6 +1314,12 @@ awe_poke_dw(AWE_CPF(voice), 0x40000000); voices[voice].state = AWE_ST_ON; + + /* clear voice position for the next note on this channel */ + if (SINGLE_LAYER_MODE()) { + FX_UNSET(fx, AWE_FX_SAMPLE_START); + FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START); + } } @@ -1254,7 +1345,7 @@ tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE, (unsigned char)vp->parm.volrelease); awe_poke(AWE_DCYSUSV(voice), tmp); - awe_voice_init(voice, TRUE); + voices[voice].state = AWE_ST_RELEASED; } /* force to terminate the voice (no releasing echo) */ @@ -1263,7 +1354,7 @@ { awe_poke(AWE_DCYSUSV(voice), 0x807F); awe_tweak_voice(voice); - awe_voice_init(voice, FALSE); + voices[voice].state = AWE_ST_OFF; } /* turn off other voices with the same exclusive class (for drums) */ @@ -1284,6 +1375,7 @@ voices[i].sample->exclusiveClass == exclass) { DEBUG(4,printk("AWE32: [exoff(%d)]\n", i)); awe_terminate(i); + awe_voice_init(i, TRUE); } } } @@ -1321,7 +1413,7 @@ if (voices[voice].layer < MAX_LAYERS) fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; - if (IS_NO_EFFECT(voice) && !forced) return; + if (!IS_PLAYING(voice) && !forced) return; if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; @@ -1336,6 +1428,8 @@ static void awe_set_voice_vol(int voice, int forced) { + if (IS_EMPTY(voice)) + return; awe_calc_volume(voice); awe_set_volume(voice, forced); } @@ -1439,6 +1533,26 @@ } +/* Q & current address (Q 4bit value, MSB) */ +static void +awe_fx_filterQ(int voice, int forced) +{ + unsigned int addr; + awe_voice_info *vp; + FX_Rec *fx = &voices[voice].cinfo->fx; + FX_Rec *fx_lay = NULL; + if (voices[voice].layer < MAX_LAYERS) + fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer]; + + if (IS_NO_EFFECT(voice) && !forced) return; + if ((vp = voices[voice].sample) == NULL || vp->index < 0) + return; + + addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff; + addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28); + awe_poke_dw(AWE_CCCA(voice), addr); +} + /*================================================================ * calculate pitch offset *---------------------------------------------------------------- @@ -1472,6 +1586,8 @@ offset = (vp->note - ap->root) * 4096 / 12; DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset)); } + offset = (offset * ap->scaleTuning) / 100; + DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); offset += ap->tune * 4096 / 1200; DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset)); if (cp->bender != 0) { @@ -1479,8 +1595,6 @@ /* (819200: 1 semitone) ==> (4096: 12 semitones) */ offset += cp->bender * cp->bender_range / 2400; } - offset = (offset * ap->scaleTuning) / 100; - DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset)); /* add initial pitch correction */ if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH)) @@ -1603,8 +1717,20 @@ /* drop sustain */ static void awe_sustain_off(int voice, int forced) { - if (voices[voice].state == AWE_ST_SUSTAINED) + if (voices[voice].state == AWE_ST_SUSTAINED) { awe_note_off(voice); + awe_fx_init(voices[voice].ch); + awe_voice_init(voice, FALSE); + } +} + + +/* terminate and initialize voice */ +static void awe_terminate_and_init(int voice, int forced) +{ + awe_terminate(voice); + awe_fx_init(voices[voice].ch); + awe_voice_init(voice, TRUE); } @@ -1618,49 +1744,54 @@ /* initialize the voice */ static void -awe_voice_init(int voice, int keep_ch_info) +awe_voice_init(int voice, int init_all) { voice_info *vp = &voices[voice]; - vp->note = -1; - vp->velocity = 0; - vp->sostenuto = 0; + + /* reset voice search key */ if (playing_mode == AWE_PLAY_DIRECT) vp->key = AWE_VOICE_KEY(voice); else vp->key = 0; + + /* clear voice mapping */ + voice_alloc->map[voice] = 0; + + /* touch the timing flag */ vp->time = current_alloc_time; - /* keep channel info for terminating release echo if necessary */ - if (keep_ch_info) - vp->state = AWE_ST_RELEASED; - else { + /* initialize other parameters if necessary */ + if (init_all) { + vp->note = -1; + vp->velocity = 0; + vp->sostenuto = 0; + vp->sample = NULL; vp->cinfo = &channels[voice]; vp->ch = voice; vp->state = AWE_ST_OFF; - } - - /* emu8000 parameters */ - vp->apitch = 0; - vp->avol = 255; - vp->apan = -1; - /* clear voice mapping */ - voice_alloc->map[voice] = 0; + /* emu8000 parameters */ + vp->apitch = 0; + vp->avol = 255; + vp->apan = -1; + } +} - /* clear effects */ +/* clear effects */ +static void awe_fx_init(int ch) +{ if (SINGLE_LAYER_MODE() && !misc_modes[AWE_MD_KEEP_EFFECT]) { - BZERO(&vp->cinfo->fx, sizeof(vp->cinfo->fx)); - BZERO(&vp->cinfo->fx_layer, sizeof(vp->cinfo->fx_layer)); + BZERO(&channels[ch].fx, sizeof(channels[ch].fx)); + BZERO(&channels[ch].fx_layer, sizeof(&channels[ch].fx_layer)); } - - /*awe_tweak_voice(voice);*/ } /* initialize channel info */ static void awe_channel_init(int ch, int init_all) { awe_chan_info *cp = &channels[ch]; + cp->channel = ch; if (init_all) { cp->panning = 0; /* zero center */ cp->bender_range = 200; /* sense * 100 */ @@ -1724,10 +1855,6 @@ return RET_ERROR(EBUSY); awe_busy = TRUE; - awe_reset(dev); - - /* clear sample position flag */ - patch_opened = 0; /* set default mode */ awe_init_misc_modes(FALSE); @@ -1735,6 +1862,11 @@ drum_flags = DEFAULT_DRUM_FLAGS; playing_mode = AWE_PLAY_INDIRECT; + /* reset voices & channels */ + awe_reset(dev); + + patch_opened = 0; + return 0; } @@ -1818,8 +1950,11 @@ if (do_sustain && (voices[voice].cinfo->sustained == 127 || voices[voice].sostenuto == 127)) voices[voice].state = AWE_ST_SUSTAINED; - else + else { awe_note_off(voice); + awe_fx_init(voices[voice].ch); + awe_voice_init(voice, FALSE); + } } /* release all notes */ @@ -1941,10 +2076,11 @@ /* if the same note still playing, stop it */ for (i = 0; i < awe_max_voices; i++) if (voices[i].key == key) { - if (voices[i].state == AWE_ST_ON) + if (voices[i].state == AWE_ST_ON) { awe_note_off(i); - else if (voices[i].state == AWE_ST_STANDBY) awe_voice_init(i, FALSE); + } else if (voices[i].state == AWE_ST_STANDBY) + awe_voice_init(i, TRUE); } /* allocate voices */ @@ -2008,19 +2144,18 @@ return RET_ERROR(EINVAL); cinfo = &channels[voice]; - def_bank = cinfo->bank; - if (MULTI_LAYER_MODE()) { - if (IS_DRUM_CHANNEL(voice)) - def_bank = AWE_DRUM_BANK; - } + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice)) + def_bank = AWE_DRUM_BANK; /* always search drumset */ + else + def_bank = cinfo->bank; cinfo->vrec = -1; cinfo->def_vrec = -1; cinfo->vrec = awe_search_instr(def_bank, instr_no); - if (def_bank == AWE_DRUM_BANK) + if (def_bank == AWE_DRUM_BANK) /* search default drumset */ cinfo->def_vrec = awe_search_instr(def_bank, misc_modes[AWE_MD_DEF_DRUM]); - else + else /* search default preset */ cinfo->def_vrec = awe_search_instr(misc_modes[AWE_MD_DEF_BANK], instr_no); if (cinfo->vrec < 0 && cinfo->def_vrec < 0) { @@ -2040,8 +2175,10 @@ int i; current_alloc_time = 0; /* don't turn off voice 31 and 32. they are used also for FM voices */ - for (i = 0; i < awe_max_voices; i++) + for (i = 0; i < awe_max_voices; i++) { awe_terminate(i); + awe_voice_init(i, TRUE); + } for (i = 0; i < AWE_MAX_CHANNELS; i++) awe_channel_init(i, TRUE); for (i = 0; i < 16; i++) { @@ -2136,15 +2273,19 @@ break; case _GUS_VOICEOFF: - awe_terminate(i); + awe_terminate(i); + awe_fx_init(voices[i].ch); + awe_voice_init(i, TRUE); break; case _GUS_VOICEFADE: awe_note_off(i); + awe_fx_init(voices[i].ch); + awe_voice_init(i, FALSE); break; - + case _GUS_VOICEFREQ: - awe_calc_pitch_from_freq(i, plong); + awe_calc_pitch_from_freq(i, plong); break; } } @@ -2154,26 +2295,6 @@ #endif -/* converter function table for realtime paramter change */ - -static fx_affect_func fx_realtime[] = { - /* env1: delay, attack, hold, decay, release, sustain, pitch, cutoff*/ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - /* env2: delay, attack, hold, decay, release, sustain */ - NULL, NULL, NULL, NULL, NULL, NULL, - /* lfo1: delay, freq, volume, pitch, cutoff */ - NULL, awe_fx_tremfrq, awe_fx_tremfrq, awe_fx_fmmod, awe_fx_fmmod, - /* lfo2: delay, freq, pitch */ - NULL, awe_fx_fm2frq2, awe_fx_fm2frq2, - /* global: initpitch, chorus, reverb, cutoff, filterQ */ - awe_set_voice_pitch, NULL, NULL, awe_set_volume, NULL, - /* sample: start, loopstart, loopend */ - NULL, NULL, NULL, NULL, NULL, NULL, - /* global: attenuation */ - awe_set_volume, -}; - - /* AWE32 specific controls */ static void awe_hw_awe_control(int dev, int cmd, unsigned char *event) @@ -2224,27 +2345,27 @@ case _AWE_SEND_EFFECT: fx = &cinfo->fx; - i = 0; /* set */ + i = FX_FLAG_SET; if (p1 >= 0x100) { int layer = (p1 >> 8); if (layer >= 0 && layer < MAX_LAYERS) fx = &cinfo->fx_layer[layer]; p1 &= 0xff; } - if (p1 & 0x40) i = 2; /* clear */ - if (p1 & 0x80) i = 1; /* add */ + if (p1 & 0x40) i = FX_FLAG_OFF; + if (p1 & 0x80) i = FX_FLAG_ADD; p1 &= 0x3f; if (p1 < AWE_FX_END) { - DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, cinfo->fx.val[p1])); - if (i == 0) + DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, p2)); + if (i == FX_FLAG_SET) FX_SET(fx, p1, p2); - else if (i == 1) + else if (i == FX_FLAG_ADD) FX_ADD(fx, p1, p2); else FX_UNSET(fx, p1); - if (i != 2 && fx_realtime[p1]) { + if (i != FX_FLAG_OFF && parm_defs[p1].realtime) { DEBUG(0,printk("AWE32: fx_realtime (%d)\n", voice)); - awe_voice_change(voice, fx_realtime[p1]); + awe_voice_change(voice, parm_defs[p1].realtime); } } break; @@ -2258,7 +2379,7 @@ break; case _AWE_TERMINATE_CHANNEL: - awe_voice_change(voice, (fx_affect_func)awe_terminate); + awe_voice_change(voice, awe_terminate_and_init); break; case _AWE_RELEASE_ALL: @@ -2276,7 +2397,7 @@ init_atten = misc_modes[AWE_MD_ZERO_ATTEN] + (short)p1; if (init_atten < 0) init_atten = 0; for (i = 0; i < awe_max_voices; i++) - awe_set_voice_vol(i, FALSE); + awe_set_voice_vol(i, TRUE); break; case _AWE_CHN_PRESSURE: @@ -2360,7 +2481,14 @@ switch (ctrl_num) { case CTL_BANK_SELECT: /* MIDI control #0 */ DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value)); + if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) && + !misc_modes[AWE_MD_TOGGLE_DRUM_BANK]) + break; cinfo->bank = value; + if (cinfo->bank == AWE_DRUM_BANK) + DRUM_CHANNEL_ON(cinfo->channel); + else + DRUM_CHANNEL_OFF(cinfo->channel); awe_set_instr(dev, voice, cinfo->instr); break; @@ -3117,7 +3245,6 @@ /* initialize FM */ awe_init_fm(); - /*awe_tweak();*/ return 0; } @@ -3561,8 +3688,11 @@ } } /* clear voice */ - if (best >= 0) - awe_terminate(best); + if (best >= 0) { + if (voices[best].state != AWE_ST_OFF) + awe_terminate(best); + awe_voice_init(best, TRUE); + } return best; } @@ -3647,6 +3777,7 @@ awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) { playing_mode = AWE_PLAY_MULTI2; + awe_info.nr_voices = AWE_MAX_CHANNELS; return awe_clear_voice(); } @@ -3719,7 +3850,7 @@ if (level >= 128) level = 127; init_atten = vol_table[level]; for (i = 0; i < awe_max_voices; i++) - awe_set_voice_vol(i, FALSE); + awe_set_voice_vol(i, TRUE); break; } } @@ -4010,7 +4141,10 @@ /* change maximum channels to 30 */ awe_max_voices = AWE_NORMAL_VOICES; - awe_info.nr_voices = awe_max_voices; + if (playing_mode == AWE_PLAY_DIRECT) + awe_info.nr_voices = awe_max_voices; + else + awe_info.nr_voices = AWE_MAX_CHANNELS; voice_alloc->max_voice = awe_max_voices; } @@ -4426,3 +4560,18 @@ #endif /* CONFIG_AWE32_SYNTH */ + +#ifdef MODULE +int init_module(void) +{ + attach_awe(); + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + unload_awe(); + SOUND_LOCK_END; +} +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.1.66/linux/drivers/sound/mad16.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/mad16.c Sat Nov 29 10:33:20 1997 @@ -6,7 +6,7 @@ * for more info. */ #include - +#include /* * sound/mad16.c * @@ -59,8 +59,18 @@ */ #include "sound_config.h" +#include "soundmodule.h" + +#ifdef MODULE +#define MAD16_CDSEL mad16_cdsel +#define MAD16_CONF mad16_conf + +static int mad16_conf; +static int mad16_cdsel; + +#endif -#ifdef CONFIG_MAD16 +#if defined(CONFIG_MAD16) || defined(MODULE) #include "sb.h" @@ -108,127 +118,121 @@ #endif static unsigned char -mad_read (int port) +mad_read(int port) { - unsigned long flags; - unsigned char tmp; + unsigned long flags; + unsigned char tmp; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb ((0xE2), PASSWD_REG); - break; - - case C929: - outb ((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - outb ((0xE5), PASSWD_REG); - break; - } - - if (board_type == C930) - { - outb ((port - MC0_PORT), 0xe0e); /* Write to index reg */ - tmp = inb (0xe0f); /* Read from data reg */ - } - else - tmp = inb (port); - restore_flags (flags); + switch (board_type) /* Output password */ + { + case C928: + case MOZART: + outb((0xE2), PASSWD_REG); + break; + + case C929: + outb((0xE3), PASSWD_REG); + break; + + case C930: + /* outb(( 0xE4), PASSWD_REG); */ + break; + + case C924: + outb((0xE5), PASSWD_REG); + break; + } + + if (board_type == C930) + { + outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ + tmp = inb(0xe0f); /* Read from data reg */ + } else + tmp = inb(port); + restore_flags(flags); - return tmp; + return tmp; } static void -mad_write (int port, int value) +mad_write(int port, int value) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb ((0xE2), PASSWD_REG); - break; - - case C929: - outb ((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - outb ((0xE5), PASSWD_REG); - break; - } - - if (board_type == C930) - { - outb ((port - MC0_PORT), 0xe0e); /* Write to index reg */ - outb (((unsigned char) (value & 0xff)), 0xe0f); - } - else - outb (((unsigned char) (value & 0xff)), port); - restore_flags (flags); + switch (board_type) /* Output password */ + { + case C928: + case MOZART: + outb((0xE2), PASSWD_REG); + break; + + case C929: + outb((0xE3), PASSWD_REG); + break; + + case C930: + /* outb(( 0xE4), PASSWD_REG); */ + break; + + case C924: + outb((0xE5), PASSWD_REG); + break; + } + + if (board_type == C930) + { + outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ + outb(((unsigned char) (value & 0xff)), 0xe0f); + } else + outb(((unsigned char) (value & 0xff)), port); + restore_flags(flags); } static int -detect_c930 (void) +detect_c930(void) { - unsigned char tmp = mad_read (MC1_PORT); + unsigned char tmp = mad_read(MC1_PORT); - if ((tmp & 0x06) != 0x06) - { - DDB (printk ("Wrong C930 signature (%x)\n", tmp)); - /* return 0; */ - } - - mad_write (MC1_PORT, 0); - - if (mad_read (MC1_PORT) != 0x06) - { - DDB (printk ("Wrong C930 signature2 (%x)\n", tmp)); - /* return 0; */ - } - - mad_write (MC1_PORT, tmp); /* Restore bits */ - - mad_write (MC7_PORT, 0); - if ((tmp = mad_read (MC7_PORT)) != 0) - { - DDB (printk ("MC7 not writable (%x)\n", tmp)); - return 0; - } - - mad_write (MC7_PORT, 0xcb); - if ((tmp = mad_read (MC7_PORT)) != 0xcb) - { - DDB (printk ("MC7 not writable2 (%x)\n", tmp)); - return 0; - } - - return 1; + if ((tmp & 0x06) != 0x06) + { + DDB(printk("Wrong C930 signature (%x)\n", tmp)); + /* return 0; */ + } + mad_write(MC1_PORT, 0); + + if (mad_read(MC1_PORT) != 0x06) + { + DDB(printk("Wrong C930 signature2 (%x)\n", tmp)); + /* return 0; */ + } + mad_write(MC1_PORT, tmp); /* Restore bits */ + + mad_write(MC7_PORT, 0); + if ((tmp = mad_read(MC7_PORT)) != 0) + { + DDB(printk("MC7 not writable (%x)\n", tmp)); + return 0; + } + mad_write(MC7_PORT, 0xcb); + if ((tmp = mad_read(MC7_PORT)) != 0xcb) + { + DDB(printk("MC7 not writable2 (%x)\n", tmp)); + return 0; + } + return 1; } static int -detect_mad16 (void) +detect_mad16(void) { - unsigned char tmp, tmp2; - int i; + unsigned char tmp, tmp2; + int i; /* * Check that reading a register doesn't return bus float (0xff) @@ -236,568 +240,715 @@ * the card is in low power mode. Normally at least the power saving mode * bit should be 0. */ - if ((tmp = mad_read (MC1_PORT)) == 0xff) - { - DDB (printk ("MC1_PORT returned 0xff\n")); - return 0; - } - - for (i = 0xf8d; i <= 0xf98; i++) - DDB (printk ("Port %0x (init value) = %0x\n", i, mad_read (i))); + if ((tmp = mad_read(MC1_PORT)) == 0xff) + { + DDB(printk("MC1_PORT returned 0xff\n")); + return 0; + } + for (i = 0xf8d; i <= 0xf98; i++) + DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i))); - if (board_type == C930) - return detect_c930 (); + if (board_type == C930) + return detect_c930(); /* * Now check that the gate is closed on first I/O after writing * the password. (This is how a MAD16 compatible card works). */ - if ((tmp2 = inb (MC1_PORT)) == tmp) /* It didn't close */ - { - DDB (printk ("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); - return 0; - } - - mad_write (MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ - if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ - { - mad_write (MC1_PORT, tmp); /* Restore */ - DDB (printk ("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); - return 0; - } - - mad_write (MC1_PORT, tmp); /* Restore */ - return 1; /* Bingo */ + if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */ + { + DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); + return 0; + } + mad_write(MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ + if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ + { + mad_write(MC1_PORT, tmp); /* Restore */ + DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); + return 0; + } + mad_write(MC1_PORT, tmp); /* Restore */ + return 1; /* Bingo */ } static int -wss_init (struct address_info *hw_config) +wss_init(struct address_info *hw_config) { - int ad_flags = 0; + int ad_flags = 0; /* * Verify the WSS parameters */ - if (check_region (hw_config->io_base, 8)) - { - printk ("MSS: I/O port conflict\n"); - return 0; - } - - if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return 0; - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. - */ - - if ((inb (hw_config->io_base + 3) & 0x3f) != 0x04 && - (inb (hw_config->io_base + 3) & 0x3f) != 0x00) - { - DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb (hw_config->io_base + 3))); - return 0; - } - - if (hw_config->irq > 11) - { - printk ("MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } - - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk ("MSS: Bad DMA %d\n", hw_config->dma); - return 0; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - - if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - } - - return 1; + if (check_region(hw_config->io_base, 8)) + { + printk("MSS: I/O port conflict\n"); + return 0; + } + if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) + return 0; + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00. + */ + + if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 && + (inb(hw_config->io_base + 3) & 0x3f) != 0x00) + { + DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3))); + return 0; + } + if (hw_config->irq > 11) + { + printk("MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk("MSS: Bad DMA %d\n", hw_config->dma); + return 0; + } + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } + if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) + { + printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + } + return 1; } static int -init_c930 (struct address_info *hw_config) +init_c930(struct address_info *hw_config) { - unsigned char cfg; + unsigned char cfg; - cfg = (mad_read (MC1_PORT) & ~0x30); - /* mad_write(MC1_PORT, 0); */ + cfg = (mad_read(MC1_PORT) & ~0x30); + /* mad_write(MC1_PORT, 0); */ - switch (hw_config->io_base) - { - case 0x530: - cfg |= 0x00; - break; - case 0xe80: - cfg |= 0x10; - break; - case 0xf40: - cfg |= 0x20; - break; - case 0x604: - cfg |= 0x30; - break; - - default: - printk ("MAD16: Invalid codec port %x\n", hw_config->io_base); - return 0; - } - mad_write (MC1_PORT, cfg); - - /* MC2 is CD configuration. Don't touch it. */ - - mad_write (MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ - mad_write (MC4_PORT, 0x52); /* ??? */ - mad_write (MC5_PORT, 0x3C); /* Init it into mode2 */ - mad_write (MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ - mad_write (MC7_PORT, 0xCB); - mad_write (MC10_PORT, 0x11); + switch (hw_config->io_base) + { + case 0x530: + cfg |= 0x00; + break; + case 0xe80: + cfg |= 0x10; + break; + case 0xf40: + cfg |= 0x20; + break; + case 0x604: + cfg |= 0x30; + break; + + default: + printk("MAD16: Invalid codec port %x\n", hw_config->io_base); + return 0; + } + mad_write(MC1_PORT, cfg); + + /* MC2 is CD configuration. Don't touch it. */ + + mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ + mad_write(MC4_PORT, 0x52); /* ??? */ + mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */ + mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ + mad_write(MC7_PORT, 0xCB); + mad_write(MC10_PORT, 0x11); - return wss_init (hw_config); + return wss_init(hw_config); } static int -chip_detect (void) +chip_detect(void) { - int i; + int i; /* * Then try to detect with the old password */ - board_type = C924; + board_type = C924; - DDB (printk ("Detect using password = 0xE5\n")); + DDB(printk("Detect using password = 0xE5\n")); - if (!detect_mad16 ()) /* No luck. Try different model */ - { - board_type = C928; + if (!detect_mad16()) /* No luck. Try different model */ + { + board_type = C928; - DDB (printk ("Detect using password = 0xE2\n")); + DDB(printk("Detect using password = 0xE2\n")); - if (!detect_mad16 ()) - { - board_type = C929; + if (!detect_mad16()) + { + board_type = C929; - DDB (printk ("Detect using password = 0xE3\n")); + DDB(printk("Detect using password = 0xE3\n")); - if (!detect_mad16 ()) - { - if (inb (PASSWD_REG) != 0xff) - return 0; + if (!detect_mad16()) + { + if (inb(PASSWD_REG) != 0xff) + return 0; /* * First relocate MC# registers to 0xe0e/0xe0f, disable password */ - outb ((0xE4), PASSWD_REG); - outb ((0x80), PASSWD_REG); - - board_type = C930; - - DDB (printk ("Detect using password = 0xE4\n")); - - for (i = 0xf8d; i <= 0xf93; i++) - DDB (printk ("port %03x = %02x\n", i, mad_read (i))); + outb((0xE4), PASSWD_REG); + outb((0x80), PASSWD_REG); - if (!detect_mad16 ()) - return 0; - - DDB (printk ("mad16.c: 82C930 detected\n")); - } - else - { - DDB (printk ("mad16.c: 82C929 detected\n")); - } - } - else - { - unsigned char model; + board_type = C930; - if (((model = mad_read (MC3_PORT)) & 0x03) == 0x03) - { - DDB (printk ("mad16.c: Mozart detected\n")); - board_type = MOZART; - } - else - { - DDB (printk ("mad16.c: 82C928 detected???\n")); - board_type = C928; - } - } - } + DDB(printk("Detect using password = 0xE4\n")); - return 1; + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); + + if (!detect_mad16()) + return 0; + + DDB(printk("mad16.c: 82C930 detected\n")); + } else + { + DDB(printk("mad16.c: 82C929 detected\n")); + } + } else + { + unsigned char model; + + if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) + { + DDB(printk("mad16.c: Mozart detected\n")); + board_type = MOZART; + } else + { + DDB(printk("mad16.c: 82C928 detected???\n")); + board_type = C928; + } + } + } + return 1; } int -probe_mad16 (struct address_info *hw_config) +probe_mad16(struct address_info *hw_config) { - int i; - static int valid_ports[] = - {0x530, 0xe80, 0xf40, 0x604}; - unsigned char tmp; - unsigned char cs4231_mode = 0; + int i; + static int valid_ports[] = + {0x530, 0xe80, 0xf40, 0x604}; + unsigned char tmp; + unsigned char cs4231_mode = 0; - int ad_flags = 0; + int ad_flags = 0; - if (already_initialized) - return 0; + if (already_initialized) + return 0; - mad16_osp = hw_config->osp; + mad16_osp = hw_config->osp; /* * Check that all ports return 0xff (bus float) when no password * is written to the password register. */ - DDB (printk ("--- Detecting MAD16 / Mozart ---\n")); - if (!chip_detect ()) - return 0; + DDB(printk("--- Detecting MAD16 / Mozart ---\n")); + if (!chip_detect()) + return 0; - if (board_type == C930) - return init_c930 (hw_config); + if (board_type == C930) + return init_c930(hw_config); - for (i = 0xf8d; i <= 0xf93; i++) - DDB (printk ("port %03x = %02x\n", i, mad_read (i))); + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); /* * Set the WSS address */ - tmp = (mad_read (MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ + tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ - for (i = 0; i < 5; i++) - { - if (i > 3) /* Not a valid port */ - { - printk ("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); - return 0; - } - - if (valid_ports[i] == hw_config->io_base) - { - tmp |= i << 4; /* WSS port select bits */ - break; - } - } + for (i = 0; i < 5; i++) + { + if (i > 3) /* Not a valid port */ + { + printk("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); + return 0; + } + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 4; /* WSS port select bits */ + break; + } + } /* * Set optional CD-ROM and joystick settings. */ #ifdef MAD16_CONF - tmp &= ~0x0f; - tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */ + tmp &= ~0x0f; + tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */ #endif - mad_write (MC1_PORT, tmp); + mad_write(MC1_PORT, tmp); #if defined(MAD16_CONF) && defined(MAD16_CDSEL) - tmp = MAD16_CDSEL; + tmp = MAD16_CDSEL; #else - tmp = mad_read (MC2_PORT); + tmp = mad_read(MC2_PORT); #endif #ifdef MAD16_OPL4 - tmp |= 0x20; /* Enable OPL4 access */ + tmp |= 0x20; /* Enable OPL4 access */ #endif - mad_write (MC2_PORT, tmp); - mad_write (MC3_PORT, 0xf0); /* Disable SB */ + mad_write(MC2_PORT, tmp); + mad_write(MC3_PORT, 0xf0); /* Disable SB */ + + if (board_type == C924) /* Specific C924 init values */ + { + mad_write(MC4_PORT, 0xA0); + mad_write(MC5_PORT, 0x05); + mad_write(MC6_PORT, 0x03); + } + if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) + return 0; + + if (ad_flags & (AD_F_CS4231 | AD_F_CS4248)) + cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ - if (board_type == C924) /* Specific C924 init values */ - { - mad_write (MC4_PORT, 0xA0); - mad_write (MC5_PORT, 0x05); - mad_write (MC6_PORT, 0x03); - } - - if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return 0; - - if (ad_flags & (AD_F_CS4231 | AD_F_CS4248)) - cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ - - if (board_type == C929) - { - mad_write (MC4_PORT, 0xa2); - mad_write (MC5_PORT, 0xA5 | cs4231_mode); - mad_write (MC6_PORT, 0x03); /* Disable MPU401 */ - } - else - { - mad_write (MC4_PORT, 0x02); - mad_write (MC5_PORT, 0x30 | cs4231_mode); - } + if (board_type == C929) + { + mad_write(MC4_PORT, 0xa2); + mad_write(MC5_PORT, 0xA5 | cs4231_mode); + mad_write(MC6_PORT, 0x03); /* Disable MPU401 */ + } else + { + mad_write(MC4_PORT, 0x02); + mad_write(MC5_PORT, 0x30 | cs4231_mode); + } - for (i = 0xf8d; i <= 0xf93; i++) - DDB (printk ("port %03x after init = %02x\n", i, mad_read (i))); + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x after init = %02x\n", i, mad_read(i))); - wss_init (hw_config); + wss_init(hw_config); - return 1; + return 1; } void -attach_mad16 (struct address_info *hw_config) +attach_mad16(struct address_info *hw_config) { - static char interrupt_bits[12] = - { - -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - char bits; - - static char dma_bits[4] = - { - 1, 2, 0, 3 - }; - - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; - int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2; - unsigned char dma2_bit = 0; - - already_initialized = 1; - - if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return; - - /* - * Set the IRQ and DMA addresses. - */ - if (board_type == C930) - interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == -1) - return; - - outb ((bits | 0x40), config_port); - if ((inb (version_port) & 0x40) == 0) - printk ("[IRQ Conflict?]"); + static char interrupt_bits[12] = + { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; + char bits; + + static char dma_bits[4] = + { + 1, 2, 0, 3 + }; + + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2; + unsigned char dma2_bit = 0; + + already_initialized = 1; + + if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) + return; + + /* + * Set the IRQ and DMA addresses. + */ + if (board_type == C930) + interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + return; + + outb((bits | 0x40), config_port); + if ((inb(version_port) & 0x40) == 0) + printk("[IRQ Conflict?]"); /* * Handle the capture DMA channel */ - if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; - - dma = dma2; - dma2 = tmp; - } - - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } - else - { - printk ("MAD16: Invalid capture DMA\n"); - dma2 = dma; - } - } - else - dma2 = dma; - - outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ - - ad1848_init ("MAD16 WSS", hw_config->io_base + 4, - hw_config->irq, - dma, - dma2, 0, - hw_config->osp); - request_region (hw_config->io_base, 4, "MAD16 WSS config"); + if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) + { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } else + { + printk("MAD16: Invalid capture DMA\n"); + dma2 = dma; + } + } else + dma2 = dma; + + outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ + + hw_config->slots[0] = ad1848_init("MAD16 WSS", hw_config->io_base + 4, + hw_config->irq, + dma, + dma2, 0, + hw_config->osp); + request_region(hw_config->io_base, 4, "MAD16 WSS config"); } void -attach_mad16_mpu (struct address_info *hw_config) +attach_mad16_mpu(struct address_info *hw_config) { - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { -#ifdef CONFIG_MIDI - - if (mad_read (MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { +#if defined(CONFIG_MIDI) + + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; - hw_config->name = "Mad16/Mozart"; - sb_dsp_init (hw_config); + hw_config->name = "Mad16/Mozart"; + sb_dsp_init(hw_config); #endif - return; - } - + return; + } #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (!already_initialized) - return; + if (!already_initialized) + return; - hw_config->driver_use_1 = SB_MIDI_ONLY; - hw_config->name = "Mad16/Mozart"; - attach_uart401 (hw_config); + hw_config->driver_use_1 = SB_MIDI_ONLY; + hw_config->name = "Mad16/Mozart"; + attach_uart401(hw_config); #endif } int -probe_mad16_mpu (struct address_info *hw_config) +probe_mad16_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - static int mpu_attached = 0; - static int valid_ports[] = - {0x330, 0x320, 0x310, 0x300}; - static short valid_irqs[] = - {9, 10, 5, 7}; - unsigned char tmp; - - int i; /* A variable with secret power */ - - if (!already_initialized) /* The MSS port must be initialized first */ - return 0; - - if (mpu_attached) /* Don't let them call this twice */ - return 0; - mpu_attached = 1; - - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { - -#ifdef CONFIG_MIDI - unsigned char tmp; - - tmp = mad_read (MC3_PORT); - - /* - * MAD16 SB base is defined by the WSS base. It cannot be changed - * alone. - * Ignore configured I/O base. Use the active setting. - */ - - if (mad_read (MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; + static int mpu_attached = 0; + static int valid_ports[] = + {0x330, 0x320, 0x310, 0x300}; + static short valid_irqs[] = + {9, 10, 5, 7}; + unsigned char tmp; - switch (hw_config->irq) - { - case 5: - tmp = (tmp & 0x3f) | 0x80; - break; - case 7: - tmp = (tmp & 0x3f); - break; - case 11: - tmp = (tmp & 0x3f) | 0x40; - break; - default: - printk ("mad16/Mozart: Invalid MIDI IRQ\n"); - return 0; - } - - mad_write (MC3_PORT, tmp | 0x04); - hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect (hw_config); + int i; /* A variable with secret power */ + + if (!already_initialized) /* The MSS port must be initialized first */ + return 0; + + if (mpu_attached) /* Don't let them call this twice */ + return 0; + mpu_attached = 1; + + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { + +#if defined(CONFIG_MIDI) + unsigned char tmp; + + tmp = mad_read(MC3_PORT); + + /* + * MAD16 SB base is defined by the WSS base. It cannot be changed + * alone. + * Ignore configured I/O base. Use the active setting. + */ + + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; + + switch (hw_config->irq) + { + case 5: + tmp = (tmp & 0x3f) | 0x80; + break; + case 7: + tmp = (tmp & 0x3f); + break; + case 11: + tmp = (tmp & 0x3f) | 0x40; + break; + default: + printk("mad16/Mozart: Invalid MIDI IRQ\n"); + return 0; + } + + mad_write(MC3_PORT, tmp | 0x04); + hw_config->driver_use_1 = SB_MIDI_ONLY; + return sb_dsp_detect(hw_config); #else - return 0; + return 0; #endif - } - - tmp = mad_read (MC6_PORT) & 0x83; - tmp |= 0x80; /* MPU-401 enable */ + } + tmp = mad_read(MC6_PORT) & 0x83; + tmp |= 0x80; /* MPU-401 enable */ /* * Set the MPU base bits */ - for (i = 0; i < 5; i++) - { - if (i > 3) /* Out of array bounds */ - { - printk ("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); - return 0; - } - - if (valid_ports[i] == hw_config->io_base) - { - tmp |= i << 5; - break; - } - } + for (i = 0; i < 5; i++) + { + if (i > 3) /* Out of array bounds */ + { + printk("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); + return 0; + } + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 5; + break; + } + } /* * Set the MPU IRQ bits */ - for (i = 0; i < 5; i++) - { - if (i > 3) /* Out of array bounds */ - { - printk ("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); - return 0; - } + for (i = 0; i < 5; i++) + { + if (i > 3) /* Out of array bounds */ + { + printk("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); + return 0; + } + if (valid_irqs[i] == hw_config->irq) + { + tmp |= i << 3; + break; + } + } + mad_write(MC6_PORT, tmp); /* Write MPU401 config */ - if (valid_irqs[i] == hw_config->irq) - { - tmp |= i << 3; - break; - } - } - mad_write (MC6_PORT, tmp); /* Write MPU401 config */ - - return probe_uart401 (hw_config); + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } void -unload_mad16 (struct address_info *hw_config) +unload_mad16(struct address_info *hw_config) { - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0); - release_region (hw_config->io_base, 4); + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma2, 0); + release_region(hw_config->io_base, 4); + sound_unload_audiodev(hw_config->slots[0]); } void -unload_mad16_mpu (struct address_info *hw_config) +unload_mad16_mpu(struct address_info *hw_config) { -#ifdef CONFIG_MIDI - if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { - sb_dsp_unload (hw_config); - return; - } +#if defined(CONFIG_MIDI) + if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ + { + sb_dsp_unload(hw_config); + return; + } #endif #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unload_uart401 (hw_config); + unload_uart401(hw_config); #endif } + +#ifdef MODULE + +int io = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int irq = -1; + +int cdtype = 0; +int cdirq = 0; +int cdport = 0x340; +int cddma = 3; +int opl4 = 0; +int joystick = 0; + +static int found_mpu; + + +static int dma_map[2][8] = +{ + {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02}, + {0x03, -1, 0x01, 0x00, -1, -1, -1, -1} +}; + +static int irq_map[16] = +{ + 0x00, -1, -1, 0x0A, + -1, 0x04, -1, 0x08, + -1, 0x10, 0x14, 0x18, + -1, -1, -1, -1 +}; + +struct address_info config; + +int +init_module(void) +{ + int dmatype = 0; + + printk("MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, DMA and irq are mandatory\n"); + return -EINVAL; + } + printk("CDROM "); + switch (cdtype) + { + case 0x00: + printk("Disabled"); + cdirq = 0; + break; + case 0x02: + printk("Sony CDU31A"); + dmatype = 2; + break; + case 0x04: + printk("Mitsumi"); + dmatype = 1; + break; + case 0x06: + printk("Panasonic Lasermate"); + dmatype = 2; + break; + case 0x08: + printk("Secondary IDE"); + dmatype = 1; + break; + case 0x0A: + printk("Primary IDE"); + dmatype = 1; + break; + default: + printk("\nInvalid CDROM type\n"); + return -EINVAL; + } + + if (dmatype) + { + if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) + { + printk("\nInvalid CDROM DMA\n"); + return -EINVAL; + } + if (cddma) + printk(", DMA %d", cddma); + else + printk(", no DMA"); + } + if (cdtype && !cdirq) + printk(", no IRQ"); + else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) + { + printk(", invalid IRQ (disabling)"); + cdirq = 0; + } else + printk(", IRQ %d", cdirq); + + printk(".\nJoystick port "); + if (joystick == 1) + printk("enabled.\n"); + else + { + joystick = 0; + printk("disabled.\n"); + } + + /* + * Build the config words + */ + + mad16_conf = (joystick ^ 1) | cdtype; + mad16_cdsel = 0; + if (opl4) + mad16_cdsel |= 0x20; + mad16_cdsel |= dma_map[dmatype][cddma]; + + if (cdtype < 0x08) + { + switch (cdport) + { + case 0x340: + mad16_cdsel |= 0x00; + break; + case 0x330: + mad16_cdsel |= 0x40; + break; + case 0x360: + mad16_cdsel |= 0x80; + break; + case 0x320: + mad16_cdsel |= 0xC0; + break; + default: + printk("Unknown CDROM I/O base %d\n", cdport); + return -EINVAL; + } + } + mad16_cdsel |= irq_map[cdirq]; + + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + + if (!probe_mad16(&config)) + return -ENODEV; + found_mpu = probe_mad16_mpu(&config); + + attach_mad16(&config); + + if (found_mpu) + attach_mad16_mpu(&config); + + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (found_mpu) + unload_mad16_mpu(&config); + unload_mad16(&config); + SOUND_LOCK_END; +} + +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.1.66/linux/drivers/sound/maui.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/maui.c Sat Nov 29 10:33:20 1997 @@ -11,14 +11,16 @@ * for more info. */ #include - +#include #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" +#include "soundmodule.h" +#include "sound_firmware.h" -#ifdef CONFIG_MAUI +#if defined(CONFIG_MAUI) || defined(MODULE) static int maui_base = 0x330; @@ -37,7 +39,7 @@ #define STAT_RX_IENA 0x01 static int (*orig_load_patch) (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) = NULL; + int offs, int count, int pmgr_flag) = NULL; #ifdef HAVE_MAUI_BOOT #include "maui_boot.h" @@ -52,439 +54,472 @@ {0}; static int -maui_wait (int mask) +maui_wait(int mask) { - int i; + int i; /* * Perform a short initial wait without sleeping */ - for (i = 0; i < 100; i++) - { - if (inb (HOST_STAT_PORT) & mask) - { - return 1; - } - } + for (i = 0; i < 100; i++) + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + } /* * Wait up to 15 seconds with sleeping */ - for (i = 0; i < 150; i++) - { - if (inb (HOST_STAT_PORT) & mask) - { - return 1; - } - - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - maui_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&maui_sleeper); - if (!(maui_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - maui_sleep_flag.opts |= WK_TIMEOUT; - } - maui_sleep_flag.opts &= ~WK_SLEEP; - }; - if ((current->signal & ~current->blocked)) - { - return 0; - } - } + for (i = 0; i < 150; i++) + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + maui_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&maui_sleeper); + if (!(maui_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + maui_sleep_flag.opts |= WK_TIMEOUT; + } + maui_sleep_flag.opts &= ~WK_SLEEP; + }; + if ((current->signal & ~current->blocked)) + { + return 0; + } + } - return 0; + return 0; } static int -maui_read (void) +maui_read(void) { - if (maui_wait (STAT_RX_AVAIL)) - return inb (HOST_DATA_PORT); + if (maui_wait(STAT_RX_AVAIL)) + return inb(HOST_DATA_PORT); - return -1; + return -1; } static int -maui_write (unsigned char data) +maui_write(unsigned char data) { - if (maui_wait (STAT_TX_AVAIL)) - { - outb ((data), HOST_DATA_PORT); - return 1; - } - printk ("Maui: Write timeout\n"); + if (maui_wait(STAT_TX_AVAIL)) + { + outb((data), HOST_DATA_PORT); + return 1; + } + printk("Maui: Write timeout\n"); - return 0; + return 0; } static void -mauiintr (int irq, void *dev_id, struct pt_regs *dummy) +mauiintr(int irq, void *dev_id, struct pt_regs *dummy) { - irq_ok = 1; + irq_ok = 1; } static int -download_code (void) +download_code(void) { - int i, lines = 0; - int eol_seen = 0, done = 0; - int skip = 1; - - printk ("Code download (%d bytes): ", maui_osLen); - - for (i = 0; i < maui_osLen; i++) - { - if (maui_os[i] != '\r') - if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) - { - skip = 0; - - if (maui_os[i] == '\n') - eol_seen = skip = 1; - else if (maui_os[i] == 'S') - { - if (maui_os[i + 1] == '8') - done = 1; - if (!maui_write (0xF1)) - goto failure; - if (!maui_write ('S')) - goto failure; - } - else - { - if (!maui_write (maui_os[i])) - goto failure; - } - - if (eol_seen) - { - int c = 0; - - int n; + int i, lines = 0; + int eol_seen = 0, done = 0; + int skip = 1; - eol_seen = 0; + printk("Code download (%d bytes): ", maui_osLen); - for (n = 0; n < 2; n++) - if (maui_wait (STAT_RX_AVAIL)) - { - c = inb (HOST_DATA_PORT); - break; - } - - if (c != 0x80) - { - printk ("Download not acknowledged\n"); - return 0; - } - else if (!(lines++ % 10)) - printk ("."); - - if (done) - { - printk ("\nDownload complete\n"); - return 1; - } - } + for (i = 0; i < maui_osLen; i++) + { + if (maui_os[i] != '\r') + if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) + { + skip = 0; + + if (maui_os[i] == '\n') + eol_seen = skip = 1; + else if (maui_os[i] == 'S') + { + if (maui_os[i + 1] == '8') + done = 1; + if (!maui_write(0xF1)) + goto failure; + if (!maui_write('S')) + goto failure; + } else + { + if (!maui_write(maui_os[i])) + goto failure; + } + + if (eol_seen) + { + int c = 0; + + int n; + + eol_seen = 0; + + for (n = 0; n < 2; n++) + if (maui_wait(STAT_RX_AVAIL)) + { + c = inb(HOST_DATA_PORT); + break; + } + if (c != 0x80) + { + printk("Download not acknowledged\n"); + return 0; + } else if (!(lines++ % 10)) + printk("."); + + if (done) + { + printk("\nDownload complete\n"); + return 1; + } + } + } } - } -failure: + failure: - printk ("\nDownload failed!!!\n"); - return 0; + printk("\nDownload failed!!!\n"); + return 0; } static int -maui_init (int irq) +maui_init(int irq) { - int i; - unsigned char bits; - - switch (irq) - { - case 9: - bits = 0x00; - break; - case 5: - bits = 0x08; - break; - case 12: - bits = 0x10; - break; - case 15: - bits = 0x18; - break; - - default: - printk ("Maui: Invalid IRQ %d\n", irq); - return 0; - } + int i; + unsigned char bits; - outb ((0x00), HOST_CTRL_PORT); /* Reset */ + switch (irq) + { + case 9: + bits = 0x00; + break; + case 5: + bits = 0x08; + break; + case 12: + bits = 0x10; + break; + case 15: + bits = 0x18; + break; + + default: + printk("Maui: Invalid IRQ %d\n", irq); + return 0; + } - outb ((bits), HOST_DATA_PORT); /* Set the IRQ bits */ - outb ((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ + outb((0x00), HOST_CTRL_PORT); /* Reset */ - outb ((0x80), HOST_CTRL_PORT); /* Leave reset */ - outb ((0x80), HOST_CTRL_PORT); /* Leave reset */ + outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */ + outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ - outb ((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ + outb((0x80), HOST_CTRL_PORT); /* Leave reset */ + outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - for (i = 0; i < 1000000 && !irq_ok; i++); + outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ - if (!irq_ok) - return 0; + for (i = 0; i < 1000000 && !irq_ok; i++); - outb ((0x80), HOST_CTRL_PORT); /* Leave reset */ + if (!irq_ok) + return 0; - printk ("Turtle Beach Maui initialization\n"); + outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - if (!download_code ()) - return 0; + printk("Turtle Beach Maui initialization\n"); - outb ((0xE0), HOST_CTRL_PORT); /* Normal operation */ + if (!download_code()) + return 0; - /* Select mpu401 mode */ + outb((0xE0), HOST_CTRL_PORT); /* Normal operation */ - maui_write (0xf0); - maui_write (1); - if (maui_read () != 0x80) - { - maui_write (0xf0); - maui_write (1); - if (maui_read () != 0x80) - printk ("Maui didn't acknowledge set HW mode command\n"); - } + /* Select mpu401 mode */ - printk ("Maui initialized OK\n"); - return 1; + maui_write(0xf0); + maui_write(1); + if (maui_read() != 0x80) + { + maui_write(0xf0); + maui_write(1); + if (maui_read() != 0x80) + printk("Maui didn't acknowledge set HW mode command\n"); + } + printk("Maui initialized OK\n"); + return 1; } static int -maui_short_wait (int mask) +maui_short_wait(int mask) { - int i; + int i; - for (i = 0; i < 1000; i++) - { - if (inb (HOST_STAT_PORT) & mask) - { - return 1; - } - } + for (i = 0; i < 1000; i++) + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + } - return 0; + return 0; } static int -maui_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +maui_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - struct sysex_info header; - unsigned long left, src_offs; - int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; - int i; + struct sysex_info header; + unsigned long left, src_offs; + int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; + int i; - if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ - return orig_load_patch (dev, format, addr, offs, count, pmgr_flag); + if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ + return orig_load_patch(dev, format, addr, offs, count, pmgr_flag); - if (format != MAUI_PATCH) - { - printk ("Maui: Unknown patch format\n"); - } - - if (count < hdr_size) - { - printk ("Maui error: Patch header too short\n"); - return -EINVAL; - } - - count -= hdr_size; - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - copy_from_user (&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); + if (format != MAUI_PATCH) + { + printk("Maui: Unknown patch format\n"); + } + if (count < hdr_size) + { + printk("Maui error: Patch header too short\n"); + return -EINVAL; + } + count -= hdr_size; - if (count < header.len) - { - printk ("Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); - header.len = count; - } + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ - left = header.len; - src_offs = 0; + copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); - for (i = 0; i < left; i++) - { - unsigned char data; + if (count < header.len) + { + printk("Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); + header.len = count; + } + left = header.len; + src_offs = 0; - get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); - if (i == 0 && !(data & 0x80)) - return -EINVAL; + for (i = 0; i < left; i++) + { + unsigned char data; - if (maui_write (data) == -1) - return -EIO; - } + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); + if (i == 0 && !(data & 0x80)) + return -EINVAL; - if ((i = maui_read ()) != 0x80) - { - if (i != -1) - printk ("Maui: Error status %02x\n", i); + if (maui_write(data) == -1) + return -EIO; + } - return -EIO; - } + if ((i = maui_read()) != 0x80) + { + if (i != -1) + printk("Maui: Error status %02x\n", i); - return 0; + return -EIO; + } + return 0; } int -probe_maui (struct address_info *hw_config) +probe_maui(struct address_info *hw_config) { - int i; - int tmp1, tmp2, ret; + int i; + int tmp1, tmp2, ret; - if (check_region (hw_config->io_base, 8)) - return 0; + if (check_region(hw_config->io_base, 8)) + return 0; - maui_base = hw_config->io_base; - maui_osp = hw_config->osp; + maui_base = hw_config->io_base; + maui_osp = hw_config->osp; - if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0) - return 0; + if (snd_set_irq_handler(hw_config->irq, mauiintr, "Maui", maui_osp) < 0) + return 0; - maui_sleep_flag.opts = WK_NONE; + maui_sleep_flag.opts = WK_NONE; /* * Initialize the processor if necessary */ - if (maui_osLen > 0) - { - if (!(inb (HOST_STAT_PORT) & STAT_TX_AVAIL) || - !maui_write (0x9F) || /* Report firmware version */ - !maui_short_wait (STAT_RX_AVAIL) || - maui_read () == -1 || maui_read () == -1) - if (!maui_init (hw_config->irq)) - { - snd_release_irq (hw_config->irq); - return 0; - } - } - - if (!maui_write (0xCF)) /* Report hardware version */ - { - printk ("No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq (hw_config->irq); - return 0; - } - - if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1) - { - printk ("No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq (hw_config->irq); - return 0; - } - - if (tmp1 == 0xff || tmp2 == 0xff) - { - snd_release_irq (hw_config->irq); - return 0; - } - - if (trace_init) - printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2); - - if (!maui_write (0x9F)) /* Report firmware version */ - return 0; - if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1) - return 0; - - if (trace_init) - printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2); - - if (!maui_write (0x85)) /* Report free DRAM */ - return 0; - tmp1 = 0; - for (i = 0; i < 4; i++) - { - tmp1 |= maui_read () << (7 * i); - } - if (trace_init) - printk ("Available DRAM %dk\n", tmp1 / 1024); - - for (i = 0; i < 1000; i++) - if (probe_mpu401 (hw_config)) - break; + if (maui_osLen > 0) + { + if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || + !maui_write(0x9F) || /* Report firmware version */ + !maui_short_wait(STAT_RX_AVAIL) || + maui_read() == -1 || maui_read() == -1) + if (!maui_init(hw_config->irq)) + { + snd_release_irq(hw_config->irq); + return 0; + } + } + if (!maui_write(0xCF)) /* Report hardware version */ + { + printk("No WaveFront firmware detected (card uninitialized?)\n"); + snd_release_irq(hw_config->irq); + return 0; + } + if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) + { + printk("No WaveFront firmware detected (card uninitialized?)\n"); + snd_release_irq(hw_config->irq); + return 0; + } + if (tmp1 == 0xff || tmp2 == 0xff) + { + snd_release_irq(hw_config->irq); + return 0; + } + if (trace_init) + printk("WaveFront hardware version %d.%d\n", tmp1, tmp2); + + if (!maui_write(0x9F)) /* Report firmware version */ + return 0; + if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) + return 0; + + if (trace_init) + printk("WaveFront firmware version %d.%d\n", tmp1, tmp2); + + if (!maui_write(0x85)) /* Report free DRAM */ + return 0; + tmp1 = 0; + for (i = 0; i < 4; i++) + { + tmp1 |= maui_read() << (7 * i); + } + if (trace_init) + printk("Available DRAM %dk\n", tmp1 / 1024); + + for (i = 0; i < 1000; i++) + if (probe_mpu401(hw_config)) + break; - ret = probe_mpu401 (hw_config); + ret = probe_mpu401(hw_config); - if (ret) - request_region (hw_config->io_base + 2, 6, "Maui"); + if (ret) + request_region(hw_config->io_base + 2, 6, "Maui"); - return ret; + return ret; } void -attach_maui (struct address_info *hw_config) +attach_maui(struct address_info *hw_config) { - int this_dev = num_midis; + int this_dev; + + conf_printf("Maui", hw_config); + + hw_config->irq *= -1; + hw_config->name = "Maui"; + attach_mpu401(hw_config); + + if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ + { + struct synth_operations *synth; + + this_dev = hw_config->slots[1]; + + /* + * Intercept patch loading calls so that they can be handled + * by the Maui driver. + */ - conf_printf ("Maui", hw_config); + synth = midi_devs[this_dev]->converter; + synth->id = "MAUI"; - hw_config->irq *= -1; - hw_config->name = "Maui"; - attach_mpu401 (hw_config); - - if (num_midis > this_dev) /* The MPU401 driver installed itself */ - { - struct synth_operations *synth; - - /* - * Intercept patch loading calls so that they can be handled - * by the Maui driver. - */ - - synth = midi_devs[this_dev]->converter; - synth->id = "MAUI"; - - if (synth != NULL) - { - orig_load_patch = synth->load_patch; - synth->load_patch = &maui_load_patch; - } - else - printk ("Maui: Can't install patch loader\n"); - } + if (synth != NULL) + { + orig_load_patch = synth->load_patch; + synth->load_patch = &maui_load_patch; + } else + printk(KERN_ERR "Maui: Can't install patch loader\n"); + } } void -unload_maui (struct address_info *hw_config) +unload_maui(struct address_info *hw_config) { - int irq = hw_config->irq; + int irq = hw_config->irq; - release_region (hw_config->io_base + 2, 6); + release_region(hw_config->io_base + 2, 6); - unload_mpu401 (hw_config); + unload_mpu401(hw_config); - if (irq < 0) - irq = -irq; + if (irq < 0) + irq = -irq; - if (irq > 0) - snd_release_irq (irq); + if (irq > 0) + snd_release_irq(irq); } +#ifdef MODULE + +int io = -1; +int irq = -1; +static int fw_load = 0; + +struct address_info cfg; + +/* + * Install a CS4232 based card. Need to have ad1848 and mpu401 + * loaded ready. + */ + +int +init_module(void) +{ + printk("Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); + if (io == -1 || irq == -1) + { + printk("maui: irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + + if (maui_os == NULL) + { + fw_load = 1; + maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); + } + if (probe_maui(&cfg) == 0) + return -ENODEV; + attach_maui(&cfg); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (fw_load && maui_os) + kfree(maui_os); + unload_maui(&cfg); + SOUND_LOCK_END; +} +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v2.1.66/linux/drivers/sound/midi_synth.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/midi_synth.c Sat Nov 29 10:33:20 1997 @@ -12,13 +12,12 @@ */ #include - #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" -#ifdef CONFIG_MIDI +#if defined(CONFIG_MIDI) || defined (MODULE) #define _MIDI_SYNTH_C_ @@ -33,7 +32,7 @@ {0}; static unsigned char prev_out_status[MAX_MIDI_DEV]; -#ifndef CONFIG_SEQUENCER +#if !defined(CONFIG_SEQUENCER) && !defined(MODULE) #define STORE(cmd) #else #define STORE(cmd) \ @@ -50,694 +49,686 @@ #define _SEQ_ADVBUF(x) len=x void -do_midi_msg (int synthno, unsigned char *msg, int mlen) +do_midi_msg(int synthno, unsigned char *msg, int mlen) { - switch (msg[0] & 0xf0) - { - case 0x90: - if (msg[2] != 0) - { - STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - } - msg[2] = 64; - - case 0x80: - STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xA0: - STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xB0: - STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f, - msg[1], msg[2])); - break; - - case 0xC0: - STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xD0: - STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xE0: - STORE (SEQ_BENDER (synthno, msg[0] & 0x0f, - (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); - break; - - default: - /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ - ; - } + switch (msg[0] & 0xf0) + { + case 0x90: + if (msg[2] != 0) + { + STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + } + msg[2] = 64; + + case 0x80: + STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xA0: + STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xB0: + STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, + msg[1], msg[2])); + break; + + case 0xC0: + STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xD0: + STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xE0: + STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, + (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + break; + + default: + /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ + ; + } } static void -midi_outc (int midi_dev, int data) +midi_outc(int midi_dev, int data) { - int timeout; + int timeout; - for (timeout = 0; timeout < 3200; timeout++) - if (midi_devs[midi_dev]->outputc (midi_dev, (unsigned char) (data & 0xff))) - { - if (data & 0x80) /* - * Status byte - */ - prev_out_status[midi_dev] = - (unsigned char) (data & 0xff); /* - * Store for running status + for (timeout = 0; timeout < 3200; timeout++) + if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff))) + { + if (data & 0x80) /* + * Status byte */ - return; /* - * Mission complete - */ - } - - /* - * Sorry! No space on buffers. - */ - printk ("Midi send timed out\n"); + prev_out_status[midi_dev] = + (unsigned char) (data & 0xff); /* + * Store for running status + */ + return; /* + * Mission complete + */ + } + /* + * Sorry! No space on buffers. + */ + printk("Midi send timed out\n"); } static int -prefix_cmd (int midi_dev, unsigned char status) +prefix_cmd(int midi_dev, unsigned char status) { - if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) - return 1; + if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) + return 1; - return midi_devs[midi_dev]->prefix_cmd (midi_dev, status); + return midi_devs[midi_dev]->prefix_cmd(midi_dev, status); } static void -midi_synth_input (int orig_dev, unsigned char data) +midi_synth_input(int orig_dev, unsigned char data) { - int dev; - struct midi_input_info *inc; + int dev; + struct midi_input_info *inc; - static unsigned char len_tab[] = /* # of data bytes following a status - */ - { - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ - }; - - if (orig_dev < 0 || orig_dev > num_midis) - return; - - if (data == 0xfe) /* Ignore active sensing */ - return; - - dev = midi2synth[orig_dev]; - inc = &midi_devs[orig_dev]->in_info; - - switch (inc->m_state) - { - case MST_INIT: - if (data & 0x80) /* MIDI status byte */ - { - if ((data & 0xf0) == 0xf0) /* Common message */ - { - switch (data) - { - case 0xf0: /* Sysex */ - inc->m_state = MST_SYSEX; - break; /* Sysex */ - - case 0xf1: /* MTC quarter frame */ - case 0xf3: /* Song select */ - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = 1; - inc->m_buf[0] = data; - break; - - case 0xf2: /* Song position pointer */ - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = 2; - inc->m_buf[0] = data; - break; - - default: - inc->m_buf[0] = data; - inc->m_ptr = 1; - do_midi_msg (dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - inc->m_left = 0; - } - } - else - { - inc->m_state = MST_DATA; - inc->m_ptr = 1; - inc->m_left = len_tab[(data >> 4) - 8]; - inc->m_buf[0] = inc->m_prev_status = data; - } - } - else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ - { /* Data byte (use running status) */ - inc->m_state = MST_DATA; - inc->m_ptr = 2; - inc->m_left = len_tab[(data >> 4) - 8] - 1; - inc->m_buf[0] = inc->m_prev_status; - inc->m_buf[1] = data; - } - break; /* MST_INIT */ - - case MST_DATA: - inc->m_buf[inc->m_ptr++] = data; - if (--inc->m_left <= 0) - { - inc->m_state = MST_INIT; - do_midi_msg (dev, inc->m_buf, inc->m_ptr); - inc->m_ptr = 0; - } - break; /* MST_DATA */ - - case MST_SYSEX: - if (data == 0xf7) /* Sysex end */ + static unsigned char len_tab[] = /* # of data bytes following a status + */ { - inc->m_state = MST_INIT; - inc->m_left = 0; - inc->m_ptr = 0; - } - break; /* MST_SYSEX */ - - default: - printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); - inc->m_state = MST_INIT; - } + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ + }; + + if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + return; + + if (data == 0xfe) /* Ignore active sensing */ + return; + + dev = midi2synth[orig_dev]; + inc = &midi_devs[orig_dev]->in_info; + + switch (inc->m_state) + { + case MST_INIT: + if (data & 0x80) /* MIDI status byte */ + { + if ((data & 0xf0) == 0xf0) /* Common message */ + { + switch (data) + { + case 0xf0: /* Sysex */ + inc->m_state = MST_SYSEX; + break; /* Sysex */ + + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* Song select */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 1; + inc->m_buf[0] = data; + break; + + case 0xf2: /* Song position pointer */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 2; + inc->m_buf[0] = data; + break; + + default: + inc->m_buf[0] = data; + inc->m_ptr = 1; + do_midi_msg(dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + inc->m_left = 0; + } + } else + { + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = len_tab[(data >> 4) - 8]; + inc->m_buf[0] = inc->m_prev_status = data; + } + } else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ + { /* Data byte (use running status) */ + inc->m_state = MST_DATA; + inc->m_ptr = 2; + inc->m_left = len_tab[(data >> 4) - 8] - 1; + inc->m_buf[0] = inc->m_prev_status; + inc->m_buf[1] = data; + } + break; /* MST_INIT */ + + case MST_DATA: + inc->m_buf[inc->m_ptr++] = data; + if (--inc->m_left <= 0) + { + inc->m_state = MST_INIT; + do_midi_msg(dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } + break; /* MST_DATA */ + + case MST_SYSEX: + if (data == 0xf7) /* Sysex end */ + { + inc->m_state = MST_INIT; + inc->m_left = 0; + inc->m_ptr = 0; + } + break; /* MST_SYSEX */ + + default: + printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); + inc->m_state = MST_INIT; + } } static void -leave_sysex (int dev) +leave_sysex(int dev) { - int orig_dev = synth_devs[dev]->midi_dev; - int timeout = 0; + int orig_dev = synth_devs[dev]->midi_dev; + int timeout = 0; - if (!sysex_state[dev]) - return; + if (!sysex_state[dev]) + return; - sysex_state[dev] = 0; + sysex_state[dev] = 0; - while (!midi_devs[orig_dev]->outputc (orig_dev, 0xf7) && - timeout < 1000) - timeout++; + while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && + timeout < 1000) + timeout++; - sysex_state[dev] = 0; + sysex_state[dev] = 0; } static void -midi_synth_output (int dev) +midi_synth_output(int dev) { - /* - * Currently NOP - */ + /* + * Currently NOP + */ } int -midi_synth_ioctl (int dev, - unsigned int cmd, caddr_t arg) +midi_synth_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - /* - * int orig_dev = synth_devs[dev]->midi_dev; - */ + /* + * int orig_dev = synth_devs[dev]->midi_dev; + */ - switch (cmd) - { + switch (cmd) + { - case SNDCTL_SYNTH_INFO: - memcpy ((&((char *) arg)[0]), (char *) synth_devs[dev]->info, sizeof (struct synth_info)); + case SNDCTL_SYNTH_INFO: + memcpy((&((char *) arg)[0]), (char *) synth_devs[dev]->info, sizeof(struct synth_info)); - return 0; - break; + return 0; + break; - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } int -midi_synth_kill_note (int dev, int channel, int note, int velocity) +midi_synth_kill_note(int dev, int channel, int note, int velocity) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; - if (note < 0 || note > 127) - return 0; - if (channel < 0 || channel > 15) - return 0; - if (velocity < 0) - velocity = 0; - if (velocity > 127) - velocity = 127; + if (note < 0 || note > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + if (velocity < 0) + velocity = 0; + if (velocity > 127) + velocity = 127; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; - if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) - { /* + if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) + { /* * Use running status */ - if (!prefix_cmd (orig_dev, note)) - return 0; + if (!prefix_cmd(orig_dev, note)) + return 0; - midi_outc (orig_dev, note); + midi_outc(orig_dev, note); - if (msg == 0x90) /* - * Running status = Note on - */ - midi_outc (orig_dev, 0); /* - * Note on with velocity 0 == note - * off - */ - else - midi_outc (orig_dev, velocity); - } - else - { - if (velocity == 64) - { - if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /* - * Note on - */ - midi_outc (orig_dev, note); - midi_outc (orig_dev, 0); /* - * Zero G + if (msg == 0x90) /* + * Running status = Note on */ - } - else - { - if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0x80 | (channel & 0x0f)); /* - * Note off - */ - midi_outc (orig_dev, note); - midi_outc (orig_dev, velocity); - } - } + midi_outc(orig_dev, 0); /* + * Note on with velocity 0 == note + * off + */ + else + midi_outc(orig_dev, velocity); + } else + { + if (velocity == 64) + { + if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* + * Note on + */ + midi_outc(orig_dev, note); + midi_outc(orig_dev, 0); /* + * Zero G + */ + } else + { + if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* + * Note off + */ + midi_outc(orig_dev, note); + midi_outc(orig_dev, velocity); + } + } - return 0; + return 0; } int -midi_synth_set_instr (int dev, int channel, int instr_no) +midi_synth_set_instr(int dev, int channel, int instr_no) { - int orig_dev = synth_devs[dev]->midi_dev; + int orig_dev = synth_devs[dev]->midi_dev; - if (instr_no < 0 || instr_no > 127) - instr_no = 0; - if (channel < 0 || channel > 15) - return 0; + if (instr_no < 0 || instr_no > 127) + instr_no = 0; + if (channel < 0 || channel > 15) + return 0; - leave_sysex (dev); + leave_sysex(dev); - if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f))) - return 0; - midi_outc (orig_dev, 0xc0 | (channel & 0x0f)); /* + if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0xc0 | (channel & 0x0f)); /* * Program change */ - midi_outc (orig_dev, instr_no); + midi_outc(orig_dev, instr_no); - return 0; + return 0; } int -midi_synth_start_note (int dev, int channel, int note, int velocity) +midi_synth_start_note(int dev, int channel, int note, int velocity) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; - if (note < 0 || note > 127) - return 0; - if (channel < 0 || channel > 15) - return 0; - if (velocity < 0) - velocity = 0; - if (velocity > 127) - velocity = 127; + if (note < 0 || note > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + if (velocity < 0) + velocity = 0; + if (velocity > 127) + velocity = 127; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; - if (chn == channel && msg == 0x90) - { /* + if (chn == channel && msg == 0x90) + { /* * Use running status */ - if (!prefix_cmd (orig_dev, note)) - return 0; - midi_outc (orig_dev, note); - midi_outc (orig_dev, velocity); - } - else - { - if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f))) + if (!prefix_cmd(orig_dev, note)) + return 0; + midi_outc(orig_dev, note); + midi_outc(orig_dev, velocity); + } else + { + if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) + return 0; + midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* + * Note on + */ + midi_outc(orig_dev, note); + midi_outc(orig_dev, velocity); + } return 0; - midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /* - * Note on - */ - midi_outc (orig_dev, note); - midi_outc (orig_dev, velocity); - } - return 0; } void -midi_synth_reset (int dev) +midi_synth_reset(int dev) { - leave_sysex (dev); + leave_sysex(dev); } int -midi_synth_open (int dev, int mode) +midi_synth_open(int dev, int mode) { - int orig_dev = synth_devs[dev]->midi_dev; - int err; - unsigned long flags; - struct midi_input_info *inc; - - if (orig_dev < 0 || orig_dev > num_midis) - return -ENXIO; - - midi2synth[orig_dev] = dev; - sysex_state[dev] = 0; - prev_out_status[orig_dev] = 0; - - if ((err = midi_devs[orig_dev]->open (orig_dev, mode, - midi_synth_input, midi_synth_output)) < 0) - return err; - - inc = &midi_devs[orig_dev]->in_info; - - save_flags (flags); - cli (); - inc->m_busy = 0; - inc->m_state = MST_INIT; - inc->m_ptr = 0; - inc->m_left = 0; - inc->m_prev_status = 0x00; - restore_flags (flags); + int orig_dev = synth_devs[dev]->midi_dev; + int err; + unsigned long flags; + struct midi_input_info *inc; + + if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + return -ENXIO; + + midi2synth[orig_dev] = dev; + sysex_state[dev] = 0; + prev_out_status[orig_dev] = 0; + + if ((err = midi_devs[orig_dev]->open(orig_dev, mode, + midi_synth_input, midi_synth_output)) < 0) + return err; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + inc = &midi_devs[orig_dev]->in_info; + + save_flags(flags); + cli(); + inc->m_busy = 0; + inc->m_state = MST_INIT; + inc->m_ptr = 0; + inc->m_left = 0; + inc->m_prev_status = 0x00; + restore_flags(flags); - sysex_sleep_flag.opts = WK_NONE; + sysex_sleep_flag.opts = WK_NONE; - return 1; + return 1; } void -midi_synth_close (int dev) +midi_synth_close(int dev) { - int orig_dev = synth_devs[dev]->midi_dev; + int orig_dev = synth_devs[dev]->midi_dev; - leave_sysex (dev); + leave_sysex(dev); - /* - * Shut up the synths by sending just single active sensing message. - */ - midi_devs[orig_dev]->outputc (orig_dev, 0xfe); + /* + * Shut up the synths by sending just single active sensing message. + */ + midi_devs[orig_dev]->outputc(orig_dev, 0xfe); - midi_devs[orig_dev]->close (orig_dev); + midi_devs[orig_dev]->close(orig_dev); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif } void -midi_synth_hw_control (int dev, unsigned char *event) +midi_synth_hw_control(int dev, unsigned char *event) { } int -midi_synth_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +midi_synth_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - int orig_dev = synth_devs[dev]->midi_dev; - - struct sysex_info sysex; - int i; - unsigned long left, src_offs, eox_seen = 0; - int first_byte = 1; - int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; - - leave_sysex (dev); - - if (!prefix_cmd (orig_dev, 0xf0)) - return 0; - - if (format != SYSEX_PATCH) - { - printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } - - if (count < hdr_size) - { - printk ("MIDI Error: Patch header too short\n"); - return -EINVAL; - } - - count -= hdr_size; - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - copy_from_user (&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs); - - if (count < sysex.len) - { - printk ("MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len); - sysex.len = count; - } - - left = sysex.len; - src_offs = 0; - - sysex_sleep_flag.opts = WK_NONE; - - for (i = 0; i < left && !(current->signal & ~current->blocked); i++) - { - unsigned char data; - - get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); + int orig_dev = synth_devs[dev]->midi_dev; - eox_seen = (i > 0 && data & 0x80); /* End of sysex */ + struct sysex_info sysex; + int i; + unsigned long left, src_offs, eox_seen = 0; + int first_byte = 1; + int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; + + leave_sysex(dev); + + if (!prefix_cmd(orig_dev, 0xf0)) + return 0; + + if (format != SYSEX_PATCH) + { + printk("MIDI Error: Invalid patch format (key) 0x%x\n", format); + return -EINVAL; + } + if (count < hdr_size) + { + printk("MIDI Error: Patch header too short\n"); + return -EINVAL; + } + count -= hdr_size; + + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ + + copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs); + + if (count < sysex.len) + { + printk("MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len); + sysex.len = count; + } + left = sysex.len; + src_offs = 0; + + sysex_sleep_flag.opts = WK_NONE; + + for (i = 0; i < left && !(current->signal & ~current->blocked); i++) + { + unsigned char data; + + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); + + eox_seen = (i > 0 && data & 0x80); /* End of sysex */ + + if (eox_seen && data != 0xf7) + data = 0xf7; + + if (i == 0) + { + if (data != 0xf0) + { + printk("Error: Sysex start missing\n"); + return -EINVAL; + } + } + while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && + !(current->signal & ~current->blocked)) + + { + unsigned long tlimit; + + if (1) + current->timeout = tlimit = jiffies + (1); + else + tlimit = (unsigned long) -1; + sysex_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sysex_sleeper); + if (!(sysex_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sysex_sleep_flag.opts |= WK_TIMEOUT; + } + sysex_sleep_flag.opts &= ~WK_SLEEP; + }; /* Wait for timeout */ + + if (!first_byte && data & 0x80) + return 0; + first_byte = 0; + } - if (eox_seen && data != 0xf7) - data = 0xf7; - - if (i == 0) - { - if (data != 0xf0) - { - printk ("Error: Sysex start missing\n"); - return -EINVAL; - } - } - - while (!midi_devs[orig_dev]->outputc (orig_dev, (unsigned char) (data & 0xff)) && - !(current->signal & ~current->blocked)) - - { - unsigned long tlimit; - - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sysex_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sysex_sleeper); - if (!(sysex_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sysex_sleep_flag.opts |= WK_TIMEOUT; - } - sysex_sleep_flag.opts &= ~WK_SLEEP; - }; /* Wait for timeout */ - - if (!first_byte && data & 0x80) + if (!eox_seen) + midi_outc(orig_dev, 0xf7); return 0; - first_byte = 0; - } - - if (!eox_seen) - midi_outc (orig_dev, 0xf7); - return 0; } void -midi_synth_panning (int dev, int channel, int pressure) +midi_synth_panning(int dev, int channel, int pressure) { } void -midi_synth_aftertouch (int dev, int channel, int pressure) +midi_synth_aftertouch(int dev, int channel, int pressure) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; - if (pressure < 0 || pressure > 127) - return; - if (channel < 0 || channel > 15) - return; + if (pressure < 0 || pressure > 127) + return; + if (channel < 0 || channel > 15) + return; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; - if (msg != 0xd0 || chn != channel) /* - * Test for running status - */ - { - if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f))) - return; - midi_outc (orig_dev, 0xd0 | (channel & 0x0f)); /* - * Channel pressure - */ - } - else if (!prefix_cmd (orig_dev, pressure)) - return; + if (msg != 0xd0 || chn != channel) /* + * Test for running status + */ + { + if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f))) + return; + midi_outc(orig_dev, 0xd0 | (channel & 0x0f)); /* + * Channel pressure + */ + } else if (!prefix_cmd(orig_dev, pressure)) + return; - midi_outc (orig_dev, pressure); + midi_outc(orig_dev, pressure); } void -midi_synth_controller (int dev, int channel, int ctrl_num, int value) +midi_synth_controller(int dev, int channel, int ctrl_num, int value) { - int orig_dev = synth_devs[dev]->midi_dev; - int chn, msg; + int orig_dev = synth_devs[dev]->midi_dev; + int chn, msg; - if (ctrl_num < 0 || ctrl_num > 127) - return; - if (channel < 0 || channel > 15) - return; - - leave_sysex (dev); - - msg = prev_out_status[orig_dev] & 0xf0; - chn = prev_out_status[orig_dev] & 0x0f; - - if (msg != 0xb0 || chn != channel) - { - if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f))) - return; - midi_outc (orig_dev, 0xb0 | (channel & 0x0f)); - } - else if (!prefix_cmd (orig_dev, ctrl_num)) - return; + if (ctrl_num < 0 || ctrl_num > 127) + return; + if (channel < 0 || channel > 15) + return; + + leave_sysex(dev); + + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; + + if (msg != 0xb0 || chn != channel) + { + if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f))) + return; + midi_outc(orig_dev, 0xb0 | (channel & 0x0f)); + } else if (!prefix_cmd(orig_dev, ctrl_num)) + return; - midi_outc (orig_dev, ctrl_num); - midi_outc (orig_dev, value & 0x7f); + midi_outc(orig_dev, ctrl_num); + midi_outc(orig_dev, value & 0x7f); } void -midi_synth_bender (int dev, int channel, int value) +midi_synth_bender(int dev, int channel, int value) { - int orig_dev = synth_devs[dev]->midi_dev; - int msg, prev_chn; + int orig_dev = synth_devs[dev]->midi_dev; + int msg, prev_chn; - if (channel < 0 || channel > 15) - return; + if (channel < 0 || channel > 15) + return; - if (value < 0 || value > 16383) - return; + if (value < 0 || value > 16383) + return; - leave_sysex (dev); + leave_sysex(dev); - msg = prev_out_status[orig_dev] & 0xf0; - prev_chn = prev_out_status[orig_dev] & 0x0f; + msg = prev_out_status[orig_dev] & 0xf0; + prev_chn = prev_out_status[orig_dev] & 0x0f; - if (msg != 0xd0 || prev_chn != channel) /* - * Test for running status - */ - { - if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f))) - return; - midi_outc (orig_dev, 0xe0 | (channel & 0x0f)); - } - else if (!prefix_cmd (orig_dev, value & 0x7f)) - return; + if (msg != 0xd0 || prev_chn != channel) /* + * Test for running status + */ + { + if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f))) + return; + midi_outc(orig_dev, 0xe0 | (channel & 0x0f)); + } else if (!prefix_cmd(orig_dev, value & 0x7f)) + return; - midi_outc (orig_dev, value & 0x7f); - midi_outc (orig_dev, (value >> 7) & 0x7f); + midi_outc(orig_dev, value & 0x7f); + midi_outc(orig_dev, (value >> 7) & 0x7f); } void -midi_synth_setup_voice (int dev, int voice, int channel) +midi_synth_setup_voice(int dev, int voice, int channel) { } int -midi_synth_send_sysex (int dev, unsigned char *bytes, int len) +midi_synth_send_sysex(int dev, unsigned char *bytes, int len) { - int orig_dev = synth_devs[dev]->midi_dev; - int i; + int orig_dev = synth_devs[dev]->midi_dev; + int i; - for (i = 0; i < len; i++) - { - switch (bytes[i]) - { - case 0xf0: /* Start sysex */ - if (!prefix_cmd (orig_dev, 0xf0)) - return 0; - sysex_state[dev] = 1; - break; - - case 0xf7: /* End sysex */ - if (!sysex_state[dev]) /* Orphan sysex end */ - return 0; - sysex_state[dev] = 0; - break; - - default: - if (!sysex_state[dev]) - return 0; - - if (bytes[i] & 0x80) /* Error. Another message before sysex end */ - { - bytes[i] = 0xf7; /* Sysex end */ - sysex_state[dev] = 0; - } - } + for (i = 0; i < len; i++) + { + switch (bytes[i]) + { + case 0xf0: /* Start sysex */ + if (!prefix_cmd(orig_dev, 0xf0)) + return 0; + sysex_state[dev] = 1; + break; + + case 0xf7: /* End sysex */ + if (!sysex_state[dev]) /* Orphan sysex end */ + return 0; + sysex_state[dev] = 0; + break; + + default: + if (!sysex_state[dev]) + return 0; + + if (bytes[i] & 0x80) /* Error. Another message before sysex end */ + { + bytes[i] = 0xf7; /* Sysex end */ + sysex_state[dev] = 0; + } + } - if (!midi_devs[orig_dev]->outputc (orig_dev, bytes[i])) - { + if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i])) + { /* * Hardware level buffer is full. Abort the sysex message. */ - int timeout = 0; + int timeout = 0; - bytes[i] = 0xf7; - sysex_state[dev] = 0; + bytes[i] = 0xf7; + sysex_state[dev] = 0; - while (!midi_devs[orig_dev]->outputc (orig_dev, bytes[i]) && - timeout < 1000) - timeout++; - } + while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) && + timeout < 1000) + timeout++; + } + if (!sysex_state[dev]) + return 0; + } - if (!sysex_state[dev]) return 0; - } - - return 0; } + #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.1.66/linux/drivers/sound/midibuf.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/midibuf.c Sat Nov 29 10:33:20 1997 @@ -28,24 +28,24 @@ {NULL}; static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { - {0}}; + {0}}; static struct wait_queue *input_sleeper[MAX_MIDI_DEV] = {NULL}; static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { - {0}}; + {0}}; struct midi_buf { - int len, head, tail; - unsigned char queue[MAX_QUEUE_SIZE]; + int len, head, tail; + unsigned char queue[MAX_QUEUE_SIZE]; }; struct midi_parms { - int prech_timeout; /* - * Timeout before the first ch - */ + int prech_timeout; /* + * Timeout before the first ch + */ }; static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = @@ -54,7 +54,7 @@ {NULL}; static struct midi_parms parms[MAX_MIDI_DEV]; -static void midi_poll (unsigned long dummy); +static void midi_poll(unsigned long dummy); static struct timer_list poll_timer = @@ -85,458 +85,446 @@ } static void -drain_midi_queue (int dev) +drain_midi_queue(int dev) { - /* - * Give the Midi driver time to drain its output queues - */ - - if (midi_devs[dev]->buffer_status != NULL) - while (!(current->signal & ~current->blocked) && - midi_devs[dev]->buffer_status (dev)) - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; + /* + * Give the Midi driver time to drain its output queues + */ + + if (midi_devs[dev]->buffer_status != NULL) + while (!(current->signal & ~current->blocked) && + midi_devs[dev]->buffer_status(dev)) + + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper[dev]); + if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag[dev].opts |= WK_TIMEOUT; + } + midi_sleep_flag[dev].opts &= ~WK_SLEEP; + }; } static void -midi_input_intr (int dev, unsigned char data) +midi_input_intr(int dev, unsigned char data) { - if (midi_in_buf[dev] == NULL) - return; + if (midi_in_buf[dev] == NULL) + return; - if (data == 0xfe) /* + if (data == 0xfe) /* * Active sensing */ - return; /* + return; /* * Ignore */ - if (SPACE_AVAIL (midi_in_buf[dev])) - { - QUEUE_BYTE (midi_in_buf[dev], data); - if ((input_sleep_flag[dev].opts & WK_SLEEP)) - { - input_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&input_sleeper[dev]); - }; - } - + if (SPACE_AVAIL(midi_in_buf[dev])) + { + QUEUE_BYTE(midi_in_buf[dev], data); + if ((input_sleep_flag[dev].opts & WK_SLEEP)) + { + input_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&input_sleeper[dev]); + }; + } } static void -midi_output_intr (int dev) +midi_output_intr(int dev) { - /* - * Currently NOP - */ + /* + * Currently NOP + */ } static void -midi_poll (unsigned long dummy) +midi_poll(unsigned long dummy) { - unsigned long flags; - int dev; + unsigned long flags; + int dev; - save_flags (flags); - cli (); - if (open_devs) - { - for (dev = 0; dev < num_midis; dev++) - if (midi_out_buf[dev] != NULL) - { - int ok = 1; - - while (DATA_AVAIL (midi_out_buf[dev]) && ok) - { - int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; - - restore_flags (flags); /* Give some time to others */ - ok = midi_devs[dev]->outputc (dev, c); - save_flags (flags); - cli (); - midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; - midi_out_buf[dev]->len--; - } - - if (DATA_AVAIL (midi_out_buf[dev]) < 100 && - (midi_sleep_flag[dev].opts & WK_SLEEP)) - { - midi_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&midi_sleeper[dev]); - }; - } - - { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; /* + save_flags(flags); + cli(); + if (open_devs) + { + for (dev = 0; dev < num_midis; dev++) + if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) + { + int ok = 1; + + while (DATA_AVAIL(midi_out_buf[dev]) && ok) + { + int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; + + restore_flags(flags); /* Give some time to others */ + ok = midi_devs[dev]->outputc(dev, c); + save_flags(flags); + cli(); + midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; + midi_out_buf[dev]->len--; + } + + if (DATA_AVAIL(midi_out_buf[dev]) < 100 && + (midi_sleep_flag[dev].opts & WK_SLEEP)) + { + midi_sleep_flag[dev].opts = WK_WAKEUP; + wake_up(&midi_sleeper[dev]); + }; + } + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; /* * Come back later */ - } - restore_flags (flags); + } + restore_flags(flags); } int -MIDIbuf_open (int dev, struct fileinfo *file) +MIDIbuf_open(int dev, struct fileinfo *file) { - int mode, err; + int mode, err; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - if (num_midis > MAX_MIDI_DEV) - { - printk ("Sound: FATAL ERROR: Too many midi interfaces\n"); - num_midis = MAX_MIDI_DEV; - } - - if (dev < 0 || dev >= num_midis) - { - printk ("Sound: Nonexistent MIDI interface %d\n", dev); - return -ENXIO; - } - - /* - * Interrupts disabled. Be careful - */ - - if ((err = midi_devs[dev]->open (dev, mode, - midi_input_intr, midi_output_intr)) < 0) - { - return err; - } - - parms[dev].prech_timeout = 0; - - midi_in_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf)); - - if (midi_in_buf[dev] == NULL) - { - printk ("midi: Can't allocate buffer\n"); - midi_devs[dev]->close (dev); - return -EIO; - } - midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - - midi_out_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf)); - - if (midi_out_buf[dev] == NULL) - { - printk ("midi: Can't allocate buffer\n"); - midi_devs[dev]->close (dev); - vfree (midi_in_buf[dev]); - midi_in_buf[dev] = NULL; - return -EIO; - } - midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; - open_devs++; - - midi_sleep_flag[dev].opts = WK_NONE; - input_sleep_flag[dev].opts = WK_NONE; - - if (open_devs < 2) /* This was first open */ - { - ; - - { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; /* Start polling */ - } + if (num_midis > MAX_MIDI_DEV) + { + printk("Sound: FATAL ERROR: Too many midi interfaces\n"); + num_midis = MAX_MIDI_DEV; + } + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + { + printk("Sound: Nonexistent MIDI interface %d\n", dev); + return -ENXIO; + } + /* + * Interrupts disabled. Be careful + */ - return err; -} + if ((err = midi_devs[dev]->open(dev, mode, + midi_input_intr, midi_output_intr)) < 0) + { + return err; + } + parms[dev].prech_timeout = 0; -void -MIDIbuf_release (int dev, struct fileinfo *file) -{ - int mode; - unsigned long flags; + midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + if (midi_in_buf[dev] == NULL) + { + printk("midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + return -EIO; + } + midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - if (dev < 0 || dev >= num_midis) - return; + midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); - save_flags (flags); - cli (); + if (midi_out_buf[dev] == NULL) + { + printk("midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + vfree(midi_in_buf[dev]); + midi_in_buf[dev] = NULL; + return -EIO; + } + midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; + open_devs++; - /* - * Wait until the queue is empty - */ + midi_sleep_flag[dev].opts = WK_NONE; + input_sleep_flag[dev].opts = WK_NONE; - if (mode != OPEN_READ) - { - midi_devs[dev]->outputc (dev, 0xfe); /* - * Active sensing to shut the - * devices - */ + if (open_devs < 2) /* This was first open */ + { + ; - while (!(current->signal & ~current->blocked) && - DATA_AVAIL (midi_out_buf[dev])) + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; /* Start polling */ + } + return err; +} - { - unsigned long tlimit; +void +MIDIbuf_release(int dev, struct fileinfo *file) +{ + int mode; + unsigned long flags; - if (0) - current->timeout = tlimit = jiffies + (0); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; /* - * Sync - */ + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - drain_midi_queue (dev); /* - * Ensure the output queues are empty + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + return; + + save_flags(flags); + cli(); + + /* + * Wait until the queue is empty + */ + + if (mode != OPEN_READ) + { + midi_devs[dev]->outputc(dev, 0xfe); /* + * Active sensing to shut the + * devices + */ + + while (!(current->signal & ~current->blocked) && + DATA_AVAIL(midi_out_buf[dev])) + + { + unsigned long tlimit; + + if (0) + current->timeout = tlimit = jiffies + (0); + else + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper[dev]); + if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag[dev].opts |= WK_TIMEOUT; + } + midi_sleep_flag[dev].opts &= ~WK_SLEEP; + }; /* + * Sync */ - } - restore_flags (flags); + drain_midi_queue(dev); /* + * Ensure the output queues are empty + */ + } + restore_flags(flags); - midi_devs[dev]->close (dev); + midi_devs[dev]->close(dev); - vfree (midi_in_buf[dev]); - vfree (midi_out_buf[dev]); - midi_in_buf[dev] = NULL; - midi_out_buf[dev] = NULL; - if (open_devs < 2) - del_timer (&poll_timer);; - open_devs--; + vfree(midi_in_buf[dev]); + vfree(midi_out_buf[dev]); + midi_in_buf[dev] = NULL; + midi_out_buf[dev] = NULL; + if (open_devs < 2) + del_timer(&poll_timer);; + open_devs--; } int -MIDIbuf_write (int dev, struct fileinfo *file, const char *buf, int count) +MIDIbuf_write(int dev, struct fileinfo *file, const char *buf, int count) { - unsigned long flags; - int c, n, i; - unsigned char tmp_data; + unsigned long flags; + int c, n, i; + unsigned char tmp_data; - dev = dev >> 4; + dev = dev >> 4; - if (!count) - return 0; + if (!count) + return 0; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - c = 0; + c = 0; - while (c < count) - { - n = SPACE_AVAIL (midi_out_buf[dev]); + while (c < count) + { + n = SPACE_AVAIL(midi_out_buf[dev]); - if (n == 0) /* + if (n == 0) /* * No space just now. We have to sleep */ - { + { - { - unsigned long tlimit; + { + unsigned long tlimit; - if (0) - current->timeout = tlimit = jiffies + (0); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((current->signal & ~current->blocked)) - { - restore_flags (flags); - return -EINTR; - } - - n = SPACE_AVAIL (midi_out_buf[dev]); - } - - if (n > (count - c)) - n = count - c; - - for (i = 0; i < n; i++) - { - copy_from_user ((char *) &tmp_data, &(buf)[c], 1); - QUEUE_BYTE (midi_out_buf[dev], tmp_data); - c++; - } - } + if (0) + current->timeout = tlimit = jiffies + (0); + else + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper[dev]); + if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag[dev].opts |= WK_TIMEOUT; + } + midi_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((current->signal & ~current->blocked)) + { + restore_flags(flags); + return -EINTR; + } + n = SPACE_AVAIL(midi_out_buf[dev]); + } + if (n > (count - c)) + n = count - c; + + for (i = 0; i < n; i++) + { + copy_from_user((char *) &tmp_data, &(buf)[c], 1); + QUEUE_BYTE(midi_out_buf[dev], tmp_data); + c++; + } + } - restore_flags (flags); + restore_flags(flags); - return c; + return c; } int -MIDIbuf_read (int dev, struct fileinfo *file, char *buf, int count) +MIDIbuf_read(int dev, struct fileinfo *file, char *buf, int count) { - int n, c = 0; - unsigned long flags; - unsigned char tmp_data; + int n, c = 0; + unsigned long flags; + unsigned char tmp_data; - dev = dev >> 4; + dev = dev >> 4; - save_flags (flags); - cli (); - - if (!DATA_AVAIL (midi_in_buf[dev])) /* - * No data yet, wait - */ - { + save_flags(flags); + cli(); - { - unsigned long tlimit; - - if (parms[dev].prech_timeout) - current->timeout = tlimit = jiffies + (parms[dev].prech_timeout); - else - tlimit = (unsigned long) -1; - input_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&input_sleeper[dev]); - if (!(input_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - input_sleep_flag[dev].opts |= WK_TIMEOUT; - } - input_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((current->signal & ~current->blocked)) - c = -EINTR; /* - * The user is getting restless - */ - } - - if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /* - * Got some bytes + if (!DATA_AVAIL(midi_in_buf[dev])) /* + * No data yet, wait */ - { - n = DATA_AVAIL (midi_in_buf[dev]); - if (n > count) - n = count; - c = 0; - - while (c < n) - { - REMOVE_BYTE (midi_in_buf[dev], tmp_data); - { - char *fixit = (char *) &tmp_data; - - copy_to_user (&(buf)[c], fixit, 1); - }; - c++; - } - } + { + + { + unsigned long tlimit; - restore_flags (flags); + if (parms[dev].prech_timeout) + current->timeout = tlimit = jiffies + (parms[dev].prech_timeout); + else + tlimit = (unsigned long) -1; + input_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on(&input_sleeper[dev]); + if (!(input_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + input_sleep_flag[dev].opts |= WK_TIMEOUT; + } + input_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((current->signal & ~current->blocked)) + c = -EINTR; /* + * The user is getting restless + */ + } + if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /* + * Got some bytes + */ + { + n = DATA_AVAIL(midi_in_buf[dev]); + if (n > count) + n = count; + c = 0; + + while (c < n) + { + REMOVE_BYTE(midi_in_buf[dev], tmp_data); + { + char *fixit = (char *) &tmp_data; + + copy_to_user(&(buf)[c], fixit, 1); + }; + c++; + } + } + restore_flags(flags); - return c; + return c; } int -MIDIbuf_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +MIDIbuf_ioctl(int dev, struct fileinfo *file, + unsigned int cmd, caddr_t arg) { - int val; + int val; - dev = dev >> 4; + dev = dev >> 4; - if (((cmd >> 8) & 0xff) == 'C') - { - if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ - return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0); - else - printk ("/dev/midi%d: No coprocessor for this device\n", dev); - - return -ENXIO; - } - else - switch (cmd) - { - - case SNDCTL_MIDI_PRETIME: - val = *(int *) arg; - if (val < 0) - val = 0; - - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return (*(int *) arg = val); - break; - - default: - return midi_devs[dev]->ioctl (dev, cmd, arg); - } + if (((cmd >> 8) & 0xff) == 'C') + { + if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ + return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk("/dev/midi%d: No coprocessor for this device\n", dev); + + return -ENXIO; + } else + switch (cmd) + { + + case SNDCTL_MIDI_PRETIME: + val = *(int *) arg; + if (val < 0) + val = 0; + + val = (HZ * val) / 10; + parms[dev].prech_timeout = val; + return (*(int *) arg = val); + break; + + default: + return midi_devs[dev]->ioctl(dev, cmd, arg); + } } int -MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) +MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) { - dev = dev >> 4; - - switch (sel_type) - { - case SEL_IN: - if (!DATA_AVAIL (midi_in_buf[dev])) - { - - input_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&input_sleeper[dev], wait); - return 0; - } - return 1; - break; + dev = dev >> 4; - case SEL_OUT: - if (SPACE_AVAIL (midi_out_buf[dev])) - { - - midi_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&midi_sleeper[dev], wait); - return 0; - } - return 1; - break; + switch (sel_type) + { + case SEL_IN: + if (!DATA_AVAIL(midi_in_buf[dev])) + { + + input_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&input_sleeper[dev], wait); + return 0; + } + return 1; + break; + + case SEL_OUT: + if (SPACE_AVAIL(midi_out_buf[dev])) + { + + midi_sleep_flag[dev].opts = WK_SLEEP; + poll_wait(&midi_sleeper[dev], wait); + return 0; + } + return 1; + break; - case SEL_EX: - return 0; - } + case SEL_EX: + return 0; + } - return 0; + return 0; } void -MIDIbuf_init (void) +MIDIbuf_init(void) { } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.1.66/linux/drivers/sound/mpu401.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/mpu401.c Sat Nov 29 10:33:21 1997 @@ -11,88 +11,89 @@ * for more info. */ #include - +#include #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" +#include "soundmodule.h" -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) || defined(MODULE) #include "coproc.h" -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; #endif struct mpu_config { - int base; /* + int base; /* * I/O base */ - int irq; - int opened; /* - * Open mode - */ - int devno; - int synthno; - int uart_mode; - int initialized; - int mode; + int irq; + int opened; /* + * Open mode + */ + int devno; + int synthno; + int uart_mode; + int initialized; + int mode; #define MODE_MIDI 1 #define MODE_SYNTH 2 - unsigned char version, revision; - unsigned int capabilities; + unsigned char version, revision; + unsigned int capabilities; #define MPU_CAP_INTLG 0x10000000 #define MPU_CAP_SYNC 0x00000010 #define MPU_CAP_FSK 0x00000020 #define MPU_CAP_CLS 0x00000040 #define MPU_CAP_SMPTE 0x00000080 #define MPU_CAP_2PORT 0x00000001 - int timer_flag; + int timer_flag; #define MBUF_MAX 10 #define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \ {printk( "MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;} - int m_busy; - unsigned char m_buf[MBUF_MAX]; - int m_ptr; - int m_state; - int m_left; - unsigned char last_status; - void (*inputintr) (int dev, unsigned char data); - int shared_irq; - int *osp; + int m_busy; + unsigned char m_buf[MBUF_MAX]; + int m_ptr; + int m_state; + int m_left; + unsigned char last_status; + void (*inputintr) (int dev, unsigned char data); + int shared_irq; + int *osp; }; #define DATAPORT(base) (base) #define COMDPORT(base) (base+1) #define STATPORT(base) (base+1) -static int -mpu401_status (struct mpu_config *devc) +static int +mpu401_status(struct mpu_config *devc) { - return inb (STATPORT (devc->base)); + return inb(STATPORT(devc->base)); } #define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY)) -static void -write_command (struct mpu_config *devc, unsigned char cmd) +static void +write_command(struct mpu_config *devc, unsigned char cmd) { - outb ((cmd), COMDPORT (devc->base)); + outb((cmd), COMDPORT(devc->base)); } -static int -read_data (struct mpu_config *devc) +static int +read_data(struct mpu_config *devc) { - return inb (DATAPORT (devc->base)); + return inb(DATAPORT(devc->base)); } -static void -write_data (struct mpu_config *devc, unsigned char byte) +static void +write_data(struct mpu_config *devc, unsigned char byte) { - outb ((byte), DATAPORT (devc->base)); + outb((byte), DATAPORT(devc->base)); } #define OUTPUT_READY 0x40 @@ -103,19 +104,19 @@ static struct mpu_config dev_conf[MAX_MIDI_DEV] = { - {0}}; + {0}}; static int n_mpu_devs = 0; static volatile int irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static int reset_mpu401 (struct mpu_config *devc); -static void set_uart_mode (int dev, struct mpu_config *devc, int arg); +static int reset_mpu401(struct mpu_config *devc); +static void set_uart_mode(int dev, struct mpu_config *devc, int arg); -static void mpu_timer_init (int midi_dev); -static void mpu_timer_interrupt (void); -static void timer_ext_event (struct mpu_config *devc, int event, int parm); +static int mpu_timer_init(int midi_dev); +static void mpu_timer_interrupt(void); +static void timer_ext_event(struct mpu_config *devc, int event, int parm); static struct synth_info mpu_synth_info_proto = {"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT}; @@ -139,17 +140,17 @@ static unsigned char len_tab[] = /* # of data bytes following a status */ { - 2, /* 8x */ - 2, /* 9x */ - 2, /* Ax */ - 2, /* Bx */ - 1, /* Cx */ - 1, /* Dx */ - 2, /* Ex */ - 0 /* Fx */ + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ }; -#ifndef CONFIG_SEQUENCER +#if !defined(CONFIG_SEQUENCER) && !defined(MODULE) #define STORE(cmd) #else #define STORE(cmd) \ @@ -166,779 +167,750 @@ #define _SEQ_ADVBUF(x) len=x static int -mpu_input_scanner (struct mpu_config *devc, unsigned char midic) +mpu_input_scanner(struct mpu_config *devc, unsigned char midic) { - switch (devc->m_state) - { - case ST_INIT: - switch (midic) - { - case 0xf8: - /* Timer overflow */ - break; - - case 0xfc: - printk (""); - break; - - case 0xfd: - if (devc->timer_flag) - mpu_timer_interrupt (); - break; - - case 0xfe: - return MPU_ACK; - break; - - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - printk ("", midic & 0x0f); - break; - - case 0xf9: - printk (""); - break; - - case 0xff: - devc->m_state = ST_SYSMSG; - break; - - default: - if (midic <= 0xef) - { - /* printk( "mpu time: %d ", midic); */ - devc->m_state = ST_TIMED; - } - else - printk (" ", midic); - } - break; - - case ST_TIMED: - { - int msg = ((int) (midic & 0xf0) >> 4); - - devc->m_state = ST_DATABYTE; - - if (msg < 8) /* Data byte */ + switch (devc->m_state) { - /* printk( "midi msg (running status) "); */ - msg = ((int) (devc->last_status & 0xf0) >> 4); - msg -= 8; - devc->m_left = len_tab[msg] - 1; - - devc->m_ptr = 2; - devc->m_buf[0] = devc->last_status; - devc->m_buf[1] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } + case ST_INIT: + switch (midic) + { + case 0xf8: + /* Timer overflow */ + break; + + case 0xfc: + printk(""); + break; + + case 0xfd: + if (devc->timer_flag) + mpu_timer_interrupt(); + break; + + case 0xfe: + return MPU_ACK; + break; + + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + printk("", midic & 0x0f); + break; + + case 0xf9: + printk(""); + break; + + case 0xff: + devc->m_state = ST_SYSMSG; + break; + + default: + if (midic <= 0xef) + { + /* printk( "mpu time: %d ", midic); */ + devc->m_state = ST_TIMED; + } else + printk(" ", midic); + } + break; + + case ST_TIMED: + { + int msg = ((int) (midic & 0xf0) >> 4); + + devc->m_state = ST_DATABYTE; + + if (msg < 8) /* Data byte */ + { + /* printk( "midi msg (running status) "); */ + msg = ((int) (devc->last_status & 0xf0) >> 4); + msg -= 8; + devc->m_left = len_tab[msg] - 1; + + devc->m_ptr = 2; + devc->m_buf[0] = devc->last_status; + devc->m_buf[1] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } else if (msg == 0xf) /* MPU MARK */ + { + devc->m_state = ST_INIT; + + switch (midic) + { + case 0xf8: + /* printk( "NOP "); */ + break; + + case 0xf9: + /* printk( "meas end "); */ + break; + + case 0xfc: + /* printk( "data end "); */ + break; + + default: + printk("Unknown MPU mark %02x\n", midic); + } + } else + { + devc->last_status = midic; + /* printk( "midi msg "); */ + msg -= 8; + devc->m_left = len_tab[msg]; + + devc->m_ptr = 1; + devc->m_buf[0] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } + } + break; + + case ST_SYSMSG: + switch (midic) + { + case 0xf0: + printk(""); + devc->m_state = ST_SYSEX; + break; + + case 0xf1: + devc->m_state = ST_MTC; + break; + + case 0xf2: + devc->m_state = ST_SONGPOS; + devc->m_ptr = 0; + break; + + case 0xf3: + devc->m_state = ST_SONGSEL; + break; + + case 0xf6: + /* printk( "tune_request\n"); */ + devc->m_state = ST_INIT; + + /* + * Real time messages + */ + case 0xf8: + /* midi clock */ + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_CLOCK, 0); + break; + + case 0xfA: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_START, 0); + break; + + case 0xFB: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_CONTINUE, 0); + break; + + case 0xFC: + devc->m_state = ST_INIT; + timer_ext_event(devc, TMR_STOP, 0); + break; + + case 0xFE: + /* active sensing */ + devc->m_state = ST_INIT; + break; + + case 0xff: + /* printk( "midi hard reset"); */ + devc->m_state = ST_INIT; + break; + + default: + printk("unknown MIDI sysmsg %0x\n", midic); + devc->m_state = ST_INIT; + } + break; + + case ST_MTC: + devc->m_state = ST_INIT; + printk("MTC frame %x02\n", midic); + break; + + case ST_SYSEX: + if (midic == 0xf7) + { + printk(""); + devc->m_state = ST_INIT; + } else + printk("%02x ", midic); + break; + + case ST_SONGPOS: + BUFTEST(devc); + devc->m_buf[devc->m_ptr++] = midic; + if (devc->m_ptr == 2) + { + devc->m_state = ST_INIT; + devc->m_ptr = 0; + timer_ext_event(devc, TMR_SPP, + ((devc->m_buf[1] & 0x7f) << 7) | + (devc->m_buf[0] & 0x7f)); + } + break; + + case ST_DATABYTE: + BUFTEST(devc); + devc->m_buf[devc->m_ptr++] = midic; + if ((--devc->m_left) <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + break; + + default: + printk("Bad state %d ", devc->m_state); + devc->m_state = ST_INIT; } - else if (msg == 0xf) /* MPU MARK */ - { - devc->m_state = ST_INIT; - - switch (midic) - { - case 0xf8: - /* printk( "NOP "); */ - break; - - case 0xf9: - /* printk( "meas end "); */ - break; - case 0xfc: - /* printk( "data end "); */ - break; - - default: - printk ("Unknown MPU mark %02x\n", midic); - } - } - else - { - devc->last_status = midic; - /* printk( "midi msg "); */ - msg -= 8; - devc->m_left = len_tab[msg]; - - devc->m_ptr = 1; - devc->m_buf[0] = midic; - - if (devc->m_left <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - } - } - break; - - case ST_SYSMSG: - switch (midic) - { - case 0xf0: - printk (""); - devc->m_state = ST_SYSEX; - break; - - case 0xf1: - devc->m_state = ST_MTC; - break; - - case 0xf2: - devc->m_state = ST_SONGPOS; - devc->m_ptr = 0; - break; - - case 0xf3: - devc->m_state = ST_SONGSEL; - break; - - case 0xf6: - /* printk( "tune_request\n"); */ - devc->m_state = ST_INIT; - - /* - * Real time messages - */ - case 0xf8: - /* midi clock */ - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_CLOCK, 0); - break; - - case 0xfA: - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_START, 0); - break; - - case 0xFB: - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_CONTINUE, 0); - break; - - case 0xFC: - devc->m_state = ST_INIT; - timer_ext_event (devc, TMR_STOP, 0); - break; - - case 0xFE: - /* active sensing */ - devc->m_state = ST_INIT; - break; - - case 0xff: - /* printk( "midi hard reset"); */ - devc->m_state = ST_INIT; - break; - - default: - printk ("unknown MIDI sysmsg %0x\n", midic); - devc->m_state = ST_INIT; - } - break; - - case ST_MTC: - devc->m_state = ST_INIT; - printk ("MTC frame %x02\n", midic); - break; - - case ST_SYSEX: - if (midic == 0xf7) - { - printk (""); - devc->m_state = ST_INIT; - } - else - printk ("%02x ", midic); - break; - - case ST_SONGPOS: - BUFTEST (devc); - devc->m_buf[devc->m_ptr++] = midic; - if (devc->m_ptr == 2) - { - devc->m_state = ST_INIT; - devc->m_ptr = 0; - timer_ext_event (devc, TMR_SPP, - ((devc->m_buf[1] & 0x7f) << 7) | - (devc->m_buf[0] & 0x7f)); - } - break; - - case ST_DATABYTE: - BUFTEST (devc); - devc->m_buf[devc->m_ptr++] = midic; - if ((--devc->m_left) <= 0) - { - devc->m_state = ST_INIT; - do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); - devc->m_ptr = 0; - } - break; - - default: - printk ("Bad state %d ", devc->m_state); - devc->m_state = ST_INIT; - } - - return 1; + return 1; } static void -mpu401_input_loop (struct mpu_config *devc) +mpu401_input_loop(struct mpu_config *devc) { - unsigned long flags; - int busy; - int n; + unsigned long flags; + int busy; + int n; - save_flags (flags); - cli (); - busy = devc->m_busy; - devc->m_busy = 1; - restore_flags (flags); + save_flags(flags); + cli(); + busy = devc->m_busy; + devc->m_busy = 1; + restore_flags(flags); - if (busy) /* Already inside the scanner */ - return; + if (busy) /* Already inside the scanner */ + return; - n = 50; + n = 50; - while (input_avail (devc) && n-- > 0) - { - unsigned char c = read_data (devc); + while (input_avail(devc) && n-- > 0) + { + unsigned char c = read_data(devc); - if (devc->mode == MODE_SYNTH) - { - mpu_input_scanner (devc, c); - } - else if (devc->opened & OPEN_READ && devc->inputintr != NULL) - devc->inputintr (devc->devno, c); - } + if (devc->mode == MODE_SYNTH) + { + mpu_input_scanner(devc, c); + } else if (devc->opened & OPEN_READ && devc->inputintr != NULL) + devc->inputintr(devc->devno, c); + } - devc->m_busy = 0; + devc->m_busy = 0; } void -mpuintr (int irq, void *dev_id, struct pt_regs *dummy) +mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { - struct mpu_config *devc; - int dev; + struct mpu_config *devc; + int dev; - sti (); + sti(); /* * FreeBSD (and some others) pass unit number to the interrupt handler. * In this case we have to scan the table for first handler. */ - if (irq < 1 || irq > 15) - { - dev = -1; - } - else - dev = irq2dev[irq]; - - if (dev == -1) - { - int origirq = irq; - - for (irq = 0; irq <= 16; irq++) - if (irq2dev[irq] != -1) - break; - if (irq > 15) - { - printk ("MPU-401: Bogus interrupt #%d?\n", origirq); - return; - } - dev = irq2dev[irq]; - devc = &dev_conf[dev]; - } - else - devc = &dev_conf[dev]; - - if (input_avail (devc)) - if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) - mpu401_input_loop (devc); - else - { - /* Dummy read (just to acknowledge the interrupt) */ - read_data (devc); - } + if (irq < 1 || irq > 15) + { + dev = -1; + } else + dev = irq2dev[irq]; + + if (dev == -1) + { + int origirq = irq; + for (irq = 0; irq <= 16; irq++) + if (irq2dev[irq] != -1) + break; + if (irq > 15) + { + printk("MPU-401: Bogus interrupt #%d?\n", origirq); + return; + } + dev = irq2dev[irq]; + devc = &dev_conf[dev]; + } else + devc = &dev_conf[dev]; + + if (input_avail(devc)) + if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) + mpu401_input_loop(devc); + else + { + /* Dummy read (just to acknowledge the interrupt) */ + read_data(devc); + } } static int -mpu401_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +mpu401_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - int err; - struct mpu_config *devc; + int err; + struct mpu_config *devc; - if (dev < 0 || dev >= num_midis) - return -ENXIO; - - devc = &dev_conf[dev]; - - if (devc->opened) - { - printk ("MPU-401: Midi busy\n"); - return -EBUSY; - } - - /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. - */ - - if (!devc->initialized) - { - if (mpu401_status (devc) == 0xff) /* Bus float */ - { - printk ("MPU-401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401 (devc); - } + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + return -ENXIO; - irq2dev[devc->irq] = dev; + devc = &dev_conf[dev]; - if (midi_devs[dev]->coproc) - if ((err = midi_devs[dev]->coproc-> - open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) - { - printk ("MPU-401: Can't access coprocessor device\n"); + if (devc->opened) + { + printk("MPU-401: Midi busy\n"); + return -EBUSY; + } + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloading its microcode. + */ - return err; - } + if (!devc->initialized) + { + if (mpu401_status(devc) == 0xff) /* Bus float */ + { + printk("MPU-401: Device not initialized properly\n"); + return -EIO; + } + reset_mpu401(devc); + } + irq2dev[devc->irq] = dev; - set_uart_mode (dev, devc, 1); - devc->mode = MODE_MIDI; - devc->synthno = 0; + if (midi_devs[dev]->coproc) + if ((err = midi_devs[dev]->coproc-> + open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) + { + printk("MPU-401: Can't access coprocessor device\n"); + + return err; + } + set_uart_mode(dev, devc, 1); + devc->mode = MODE_MIDI; + devc->synthno = 0; - mpu401_input_loop (devc); + mpu401_input_loop(devc); - devc->inputintr = input; - devc->opened = mode; + devc->inputintr = input; + devc->opened = mode; - return 0; + return 0; } static void -mpu401_close (int dev) +mpu401_close(int dev) { - struct mpu_config *devc; + struct mpu_config *devc; - devc = &dev_conf[dev]; + devc = &dev_conf[dev]; - if (devc->uart_mode) - reset_mpu401 (devc); /* - * This disables the UART mode - */ - devc->mode = 0; + if (devc->uart_mode) + reset_mpu401(devc); /* + * This disables the UART mode + */ + devc->mode = 0; - devc->inputintr = NULL; + devc->inputintr = NULL; - if (midi_devs[dev]->coproc) - midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI); - devc->opened = 0; + if (midi_devs[dev]->coproc) + midi_devs[dev]->coproc->close(midi_devs[dev]->coproc->devc, COPR_MIDI); + devc->opened = 0; } static int -mpu401_out (int dev, unsigned char midi_byte) +mpu401_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; + int timeout; + unsigned long flags; + + struct mpu_config *devc; - struct mpu_config *devc; + devc = &dev_conf[dev]; - devc = &dev_conf[dev]; + /* + * Sometimes it takes about 30000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ - /* - * Sometimes it takes about 30000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); - - save_flags (flags); - cli (); - if (!output_ready (devc)) - { - printk ("MPU-401: Send data timeout\n"); - restore_flags (flags); - return 0; - } - - write_data (devc, midi_byte); - restore_flags (flags); - return 1; + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); + + save_flags(flags); + cli(); + if (!output_ready(devc)) + { + printk("MPU-401: Send data timeout\n"); + restore_flags(flags); + return 0; + } + write_data(devc, midi_byte); + restore_flags(flags); + return 1; } static int -mpu401_command (int dev, mpu_command_rec * cmd) +mpu401_command(int dev, mpu_command_rec * cmd) { - int i, timeout, ok; - int ret = 0; - unsigned long flags; - struct mpu_config *devc; + int i, timeout, ok; + int ret = 0; + unsigned long flags; + struct mpu_config *devc; - devc = &dev_conf[dev]; + devc = &dev_conf[dev]; - if (devc->uart_mode) /* + if (devc->uart_mode) /* * Not possible in UART mode */ - { - printk ("MPU-401 commands not possible in the UART mode\n"); - return -EINVAL; - } - - /* - * Test for input since pending input seems to block the output. - */ - if (input_avail (devc)) - mpu401_input_loop (devc); - - /* - * Sometimes it takes about 50000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - timeout = 50000; -retry: - if (timeout-- <= 0) - { - printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; - } - - save_flags (flags); - cli (); - - if (!output_ready (devc)) - { - restore_flags (flags); - goto retry; - } - - write_command (devc, cmd->cmd); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_avail (devc)) - { - if (devc->opened && devc->mode == MODE_SYNTH) { - if (mpu_input_scanner (devc, read_data (devc)) == MPU_ACK) - ok = 1; + printk("MPU-401 commands not possible in the UART mode\n"); + return -EINVAL; } - else - { /* Device is not currently open. Use simpler method */ - if (read_data (devc) == MPU_ACK) - ok = 1; - } - } - - if (!ok) - { - restore_flags (flags); - /* printk( "MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ - return -EIO; - } - - if (cmd->nr_args) - for (i = 0; i < cmd->nr_args; i++) - { - for (timeout = 3000; timeout > 0 && !output_ready (devc); timeout--); - - if (!mpu401_out (dev, cmd->data[i])) - { - restore_flags (flags); - printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; - } - } - - ret = 0; - cmd->data[0] = 0; - - if (cmd->nr_returns) - for (i = 0; i < cmd->nr_returns; i++) - { - ok = 0; - for (timeout = 5000; timeout > 0 && !ok; timeout--) - if (input_avail (devc)) - { - cmd->data[i] = read_data (devc); - ok = 1; - } + /* + * Test for input since pending input seems to block the output. + */ + if (input_avail(devc)) + mpu401_input_loop(devc); + + /* + * Sometimes it takes about 50000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + timeout = 50000; + retry: + if (timeout-- <= 0) + { + printk("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); + return -EIO; + } + save_flags(flags); + cli(); - if (!ok) + if (!output_ready(devc)) { - restore_flags (flags); - /* printk( "MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ - return -EIO; + restore_flags(flags); + goto retry; } - } + write_command(devc, cmd->cmd); - restore_flags (flags); + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail(devc)) + { + if (devc->opened && devc->mode == MODE_SYNTH) + { + if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK) + ok = 1; + } else + { /* Device is not currently open. Use simpler method */ + if (read_data(devc) == MPU_ACK) + ok = 1; + } + } + if (!ok) + { + restore_flags(flags); + /* printk( "MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ + return -EIO; + } + if (cmd->nr_args) + for (i = 0; i < cmd->nr_args; i++) + { + for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--); + + if (!mpu401_out(dev, cmd->data[i])) + { + restore_flags(flags); + printk("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); + return -EIO; + } + } + ret = 0; + cmd->data[0] = 0; + + if (cmd->nr_returns) + for (i = 0; i < cmd->nr_returns; i++) + { + ok = 0; + for (timeout = 5000; timeout > 0 && !ok; timeout--) + if (input_avail(devc)) + { + cmd->data[i] = read_data(devc); + ok = 1; + } + if (!ok) + { + restore_flags(flags); + /* printk( "MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ + return -EIO; + } + } + restore_flags(flags); - return ret; + return ret; } static int -mpu_cmd (int dev, int cmd, int data) +mpu_cmd(int dev, int cmd, int data) { - int ret; + int ret; - static mpu_command_rec rec; + static mpu_command_rec rec; - rec.cmd = cmd & 0xff; - rec.nr_args = ((cmd & 0xf0) == 0xE0); - rec.nr_returns = ((cmd & 0xf0) == 0xA0); - rec.data[0] = data & 0xff; - - if ((ret = mpu401_command (dev, &rec)) < 0) - { - return ret; - } - return (unsigned char) rec.data[0]; + rec.cmd = cmd & 0xff; + rec.nr_args = ((cmd & 0xf0) == 0xE0); + rec.nr_returns = ((cmd & 0xf0) == 0xA0); + rec.data[0] = data & 0xff; + + if ((ret = mpu401_command(dev, &rec)) < 0) + { + return ret; + } + return (unsigned char) rec.data[0]; } static int -mpu401_prefix_cmd (int dev, unsigned char status) +mpu401_prefix_cmd(int dev, unsigned char status) { - struct mpu_config *devc = &dev_conf[dev]; + struct mpu_config *devc = &dev_conf[dev]; - if (devc->uart_mode) - return 1; + if (devc->uart_mode) + return 1; - if (status < 0xf0) - { - if (mpu_cmd (dev, 0xD0, 0) < 0) - { - return 0; - } - - return 1; - } - - switch (status) - { - case 0xF0: - if (mpu_cmd (dev, 0xDF, 0) < 0) - { - return 0; - } - - return 1; - break; + if (status < 0xf0) + { + if (mpu_cmd(dev, 0xD0, 0) < 0) + { + return 0; + } + return 1; + } + switch (status) + { + case 0xF0: + if (mpu_cmd(dev, 0xDF, 0) < 0) + { + return 0; + } + return 1; + break; - default: - return 0; - } + default: + return 0; + } } static int -mpu401_start_read (int dev) +mpu401_start_read(int dev) { - return 0; + return 0; } static int -mpu401_end_read (int dev) +mpu401_end_read(int dev) { - return 0; + return 0; } static int -mpu401_ioctl (int dev, unsigned cmd, caddr_t arg) +mpu401_ioctl(int dev, unsigned cmd, caddr_t arg) { - struct mpu_config *devc; - int val; - - devc = &dev_conf[dev]; - - switch (cmd) - { - case SNDCTL_MIDI_MPUMODE: - if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ - { - printk ("MPU-401: Intelligent mode not supported by the HW\n"); - return -EINVAL; - } - val = *(int *) arg; - set_uart_mode (dev, devc, !val); - return 0; - break; - - case SNDCTL_MIDI_MPUCMD: - { - int ret; - mpu_command_rec rec; - - memcpy ((char *) &rec, (&((char *) arg)[0]), sizeof (rec)); + struct mpu_config *devc; + int val; - if ((ret = mpu401_command (dev, &rec)) < 0) - return ret; + devc = &dev_conf[dev]; - memcpy ((&((char *) arg)[0]), (char *) &rec, sizeof (rec)); - return 0; - } - break; + switch (cmd) + { + case SNDCTL_MIDI_MPUMODE: + if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ + { + printk("MPU-401: Intelligent mode not supported by the HW\n"); + return -EINVAL; + } + val = *(int *) arg; + set_uart_mode(dev, devc, !val); + return 0; + break; + + case SNDCTL_MIDI_MPUCMD: + { + int ret; + mpu_command_rec rec; + + memcpy((char *) &rec, (&((char *) arg)[0]), sizeof(rec)); + + if ((ret = mpu401_command(dev, &rec)) < 0) + return ret; + + memcpy((&((char *) arg)[0]), (char *) &rec, sizeof(rec)); + return 0; + } + break; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } static void -mpu401_kick (int dev) +mpu401_kick(int dev) { } static int -mpu401_buffer_status (int dev) +mpu401_buffer_status(int dev) { - return 0; /* + return 0; /* * No data in buffers */ } static int -mpu_synth_ioctl (int dev, - unsigned int cmd, caddr_t arg) +mpu_synth_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - int midi_dev; - struct mpu_config *devc; + int midi_dev; + struct mpu_config *devc; - midi_dev = synth_devs[dev]->midi_dev; + midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis) - return -ENXIO; + if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + return -ENXIO; - devc = &dev_conf[midi_dev]; + devc = &dev_conf[midi_dev]; - switch (cmd) - { + switch (cmd) + { - case SNDCTL_SYNTH_INFO: - memcpy ((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof (struct synth_info)); + case SNDCTL_SYNTH_INFO: + memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info)); - return 0; - break; + return 0; + break; - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; + } } static int -mpu_synth_open (int dev, int mode) +mpu_synth_open(int dev, int mode) { - int midi_dev, err; - struct mpu_config *devc; + int midi_dev, err; + struct mpu_config *devc; - midi_dev = synth_devs[dev]->midi_dev; + midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis) - { - return -ENXIO; - } - - devc = &dev_conf[midi_dev]; - - /* - * Verify that the device is really running. - * Some devices (such as Ensoniq SoundScape don't - * work before the on board processor (OBP) is initialized - * by downloading its microcode. - */ - - if (!devc->initialized) - { - if (mpu401_status (devc) == 0xff) /* Bus float */ - { - printk ("MPU-401: Device not initialized properly\n"); - return -EIO; - } - reset_mpu401 (devc); - } + if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + { + return -ENXIO; + } + devc = &dev_conf[midi_dev]; + + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloading its microcode. + */ + + if (!devc->initialized) + { + if (mpu401_status(devc) == 0xff) /* Bus float */ + { + printk("MPU-401: Device not initialized properly\n"); + return -EIO; + } + reset_mpu401(devc); + } + if (devc->opened) + { + printk("MPU-401: Midi busy\n"); + return -EBUSY; + } + devc->mode = MODE_SYNTH; + devc->synthno = dev; + + devc->inputintr = NULL; + irq2dev[devc->irq] = midi_dev; - if (devc->opened) - { - printk ("MPU-401: Midi busy\n"); - return -EBUSY; - } - - devc->mode = MODE_SYNTH; - devc->synthno = dev; - - devc->inputintr = NULL; - irq2dev[devc->irq] = midi_dev; - - if (midi_devs[midi_dev]->coproc) - if ((err = midi_devs[midi_dev]->coproc-> - open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) - { - printk ("MPU-401: Can't access coprocessor device\n"); - - return err; - } - - devc->opened = mode; - reset_mpu401 (devc); - - if (mode & OPEN_READ) - { - mpu_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ - mpu_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ - mpu_cmd (midi_dev, 0x87, 0); /* Enable pitch & controller */ - } + if (midi_devs[midi_dev]->coproc) + if ((err = midi_devs[midi_dev]->coproc-> + open(midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) + { + printk("MPU-401: Can't access coprocessor device\n"); + + return err; + } + devc->opened = mode; + reset_mpu401(devc); - return 0; + if (mode & OPEN_READ) + { + mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */ + mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ + mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */ + } + return 0; } static void -mpu_synth_close (int dev) +mpu_synth_close(int dev) { - int midi_dev; - struct mpu_config *devc; + int midi_dev; + struct mpu_config *devc; - midi_dev = synth_devs[dev]->midi_dev; + midi_dev = synth_devs[dev]->midi_dev; - devc = &dev_conf[midi_dev]; - mpu_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ - mpu_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */ + devc = &dev_conf[midi_dev]; + mpu_cmd(midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ + mpu_cmd(midi_dev, 0x8a, 0); /* Disable data in stopped mode */ - devc->inputintr = NULL; + devc->inputintr = NULL; - if (midi_devs[midi_dev]->coproc) - midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI); - devc->opened = 0; - devc->mode = 0; + if (midi_devs[midi_dev]->coproc) + midi_devs[midi_dev]->coproc->close(midi_devs[midi_dev]->coproc->devc, COPR_MIDI); + devc->opened = 0; + devc->mode = 0; } #define MIDI_SYNTH_NAME "MPU-401 UART Midi" @@ -947,375 +919,369 @@ static struct synth_operations mpu401_synth_proto = { - "MPU401", - NULL, - 0, - SYNTH_TYPE_MIDI, - 0, - mpu_synth_open, - mpu_synth_close, - mpu_synth_ioctl, - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - midi_synth_hw_control, - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, - midi_synth_bender, - NULL, /* alloc */ - midi_synth_setup_voice, - midi_synth_send_sysex + "MPU401", + NULL, + 0, + SYNTH_TYPE_MIDI, + 0, + mpu_synth_open, + mpu_synth_close, + mpu_synth_ioctl, + midi_synth_kill_note, + midi_synth_start_note, + midi_synth_set_instr, + midi_synth_reset, + midi_synth_hw_control, + midi_synth_load_patch, + midi_synth_aftertouch, + midi_synth_controller, + midi_synth_panning, + NULL, + midi_synth_bender, + NULL, /* alloc */ + midi_synth_setup_voice, + midi_synth_send_sysex }; static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV]; static struct midi_operations mpu401_midi_proto = { - {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - NULL, - {0}, - mpu401_open, - mpu401_close, - mpu401_ioctl, - mpu401_out, - mpu401_start_read, - mpu401_end_read, - mpu401_kick, - NULL, - mpu401_buffer_status, - mpu401_prefix_cmd + {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + NULL, + {0}, + mpu401_open, + mpu401_close, + mpu401_ioctl, + mpu401_out, + mpu401_start_read, + mpu401_end_read, + mpu401_kick, + NULL, + mpu401_buffer_status, + mpu401_prefix_cmd }; static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; static void -mpu401_chk_version (struct mpu_config *devc) +mpu401_chk_version(int n, struct mpu_config *devc) { - int tmp; - unsigned long flags; + int tmp; + unsigned long flags; + + devc->version = devc->revision = 0; - devc->version = devc->revision = 0; + save_flags(flags); + cli(); + if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0) + { + restore_flags(flags); + return; + } + if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ + { + restore_flags(flags); + return; + } + devc->version = tmp; - save_flags (flags); - cli (); - if ((tmp = mpu_cmd (num_midis, 0xAC, 0)) < 0) - { - restore_flags (flags); - return; - } - - if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ - { - restore_flags (flags); - return; - } - - devc->version = tmp; - - if ((tmp = mpu_cmd (num_midis, 0xAD, 0)) < 0) - { - devc->version = 0; - restore_flags (flags); - return; - } - devc->revision = tmp; + if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) + { + devc->version = 0; + restore_flags(flags); + return; + } + devc->revision = tmp; - restore_flags (flags); + restore_flags(flags); } void -attach_mpu401 (struct address_info *hw_config) +attach_mpu401(struct address_info *hw_config) { - unsigned long flags; - char revision_char; + unsigned long flags; + char revision_char; - struct mpu_config *devc; + int m; + struct mpu_config *devc; - if (num_midis >= MAX_MIDI_DEV) - { - printk ("MPU-401: Too many midi devices detected\n"); - return; - } - - devc = &dev_conf[num_midis]; - - devc->base = hw_config->io_base; - devc->osp = hw_config->osp; - devc->irq = hw_config->irq; - devc->opened = 0; - devc->uart_mode = 0; - devc->initialized = 0; - devc->version = 0; - devc->revision = 0; - devc->capabilities = 0; - devc->timer_flag = 0; - devc->m_busy = 0; - devc->m_state = ST_INIT; - devc->shared_irq = hw_config->always_detect; - devc->irq = hw_config->irq; - - if (devc->irq < 0) - { - devc->irq *= -1; - devc->shared_irq = 1; - } - irq2dev[devc->irq] = num_midis; - - if (!hw_config->always_detect) - { - /* Verify the hardware again */ - if (!reset_mpu401 (devc)) - { - printk ("MPU401: Device didn't respond\n"); - return; - } + hw_config->slots[1] = -1; + m = sound_alloc_mididev(); + if (m == -1) + { + printk(KERN_WARNING "MPU-401: Too many midi devices detected\n"); + return; + } + devc = &dev_conf[m]; + devc->base = hw_config->io_base; + devc->osp = hw_config->osp; + devc->irq = hw_config->irq; + devc->opened = 0; + devc->uart_mode = 0; + devc->initialized = 0; + devc->version = 0; + devc->revision = 0; + devc->capabilities = 0; + devc->timer_flag = 0; + devc->m_busy = 0; + devc->m_state = ST_INIT; + devc->shared_irq = hw_config->always_detect; + devc->irq = hw_config->irq; - if (!devc->shared_irq) - if (snd_set_irq_handler (devc->irq, mpuintr, "mpu401", devc->osp) < 0) + if (devc->irq < 0) { - printk ("MPU401: Failed to allocate IRQ%d\n", devc->irq); - return; + devc->irq *= -1; + devc->shared_irq = 1; } + irq2dev[devc->irq] = m; - save_flags (flags); - cli (); - mpu401_chk_version (devc); - if (devc->version == 0) - mpu401_chk_version (devc); - restore_flags (flags); - } - - request_region (hw_config->io_base, 2, "mpu401"); - - if (devc->version != 0) - if (mpu_cmd (num_midis, 0xC5, 0) >= 0) /* Set timebase OK */ - if (mpu_cmd (num_midis, 0xE0, 120) >= 0) /* Set tempo OK */ - devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - - - mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - - if (mpu401_synth_operations[num_midis] == NULL) - { - printk ("mpu401: Can't allocate memory\n"); - return; - } - - if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ - { - memcpy ((char *) mpu401_synth_operations[num_midis], - (char *) &std_midi_synth, - sizeof (struct synth_operations)); - } - else - { - memcpy ((char *) mpu401_synth_operations[num_midis], - (char *) &mpu401_synth_proto, - sizeof (struct synth_operations)); - } - - memcpy ((char *) &mpu401_midi_operations[num_midis], - (char *) &mpu401_midi_proto, - sizeof (struct midi_operations)); - - mpu401_midi_operations[num_midis].converter = - mpu401_synth_operations[num_midis]; - - memcpy ((char *) &mpu_synth_info[num_midis], - (char *) &mpu_synth_info_proto, - sizeof (struct synth_info)); - - n_mpu_devs++; - - if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ - { - int ports = (devc->revision & 0x08) ? 32 : 16; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | - MPU_CAP_CLS | MPU_CAP_2PORT; - - revision_char = (devc->revision == 0x7f) ? 'M' : ' '; - sprintf (mpu_synth_info[num_midis].name, - "MQX-%d%c MIDI Interface #%d", - ports, - revision_char, - n_mpu_devs); - } - else - { - - revision_char = devc->revision ? devc->revision + '@' : ' '; - if ((int) devc->revision > ('Z' - '@')) - revision_char = '+'; - - devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - - if (hw_config->name) - sprintf (mpu_synth_info[num_midis].name, "%s (MPU401)", hw_config->name); - else - sprintf (mpu_synth_info[num_midis].name, - "MPU-401 %d.%d%c Midi interface #%d", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char, - n_mpu_devs); - } - - strcpy (mpu401_midi_operations[num_midis].info.name, - mpu_synth_info[num_midis].name); - - conf_printf (mpu_synth_info[num_midis].name, hw_config); - - mpu401_synth_operations[num_midis]->midi_dev = devc->devno = num_midis; - mpu401_synth_operations[devc->devno]->info = - &mpu_synth_info[devc->devno]; - - if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */ - mpu_timer_init (num_midis); - - irq2dev[devc->irq] = num_midis; - midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; - sequencer_init (); -} + if (!hw_config->always_detect) + { + /* Verify the hardware again */ + if (!reset_mpu401(devc)) + { + printk(KERN_WARNING "mpu401: Device didn't respond\n"); + sound_unload_mididev(m); + return; + } + if (!devc->shared_irq) + if (snd_set_irq_handler(devc->irq, mpuintr, "mpu401", devc->osp) < 0) + { + printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq); + sound_unload_mididev(m); + return; + } + save_flags(flags); + cli(); + mpu401_chk_version(m, devc); + if (devc->version == 0) + mpu401_chk_version(m, devc); + restore_flags(flags); + } + request_region(hw_config->io_base, 2, "mpu401"); + + if (devc->version != 0) + if (mpu_cmd(m, 0xC5, 0) >= 0) /* Set timebase OK */ + if (mpu_cmd(m, 0xE0, 120) >= 0) /* Set tempo OK */ + devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ -static int -reset_mpu401 (struct mpu_config *devc) -{ - unsigned long flags; - int ok, timeout, n; - int timeout_limit; - /* - * Send the RESET command. Try again if no success at the first time. - * (If the device is in the UART mode, it will not ack the reset cmd). - */ + mpu401_synth_operations[m] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - ok = 0; + if (sound_nblocks < 1024) + sound_nblocks++;; - timeout_limit = devc->initialized ? 30000 : 100000; - devc->initialized = 1; + if (mpu401_synth_operations[m] == NULL) + { + sound_unload_mididev(m); + printk(KERN_ERR "mpu401: Can't allocate memory\n"); + return; + } + if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ + { + memcpy((char *) mpu401_synth_operations[m], + (char *) &std_midi_synth, + sizeof(struct synth_operations)); + } else + { + memcpy((char *) mpu401_synth_operations[m], + (char *) &mpu401_synth_proto, + sizeof(struct synth_operations)); + } - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) - ok = output_ready (devc); + memcpy((char *) &mpu401_midi_operations[m], + (char *) &mpu401_midi_proto, + sizeof(struct midi_operations)); - write_command (devc, MPU_RESET); /* - * Send MPU-401 RESET Command - */ + mpu401_midi_operations[m].converter = + mpu401_synth_operations[m]; - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ + memcpy((char *) &mpu_synth_info[m], + (char *) &mpu_synth_info_proto, + sizeof(struct synth_info)); - for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) - { - save_flags (flags); - cli (); - if (input_avail (devc)) - if (read_data (devc) == MPU_ACK) - ok = 1; - restore_flags (flags); - } + n_mpu_devs++; - } + if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ + { + int ports = (devc->revision & 0x08) ? 32 : 16; - devc->m_state = ST_INIT; - devc->m_ptr = 0; - devc->m_left = 0; - devc->last_status = 0; - devc->uart_mode = 0; + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | + MPU_CAP_CLS | MPU_CAP_2PORT; - return ok; + revision_char = (devc->revision == 0x7f) ? 'M' : ' '; + sprintf(mpu_synth_info[m].name, + "MQX-%d%c MIDI Interface #%d", + ports, + revision_char, + n_mpu_devs); + } else + { + + revision_char = devc->revision ? devc->revision + '@' : ' '; + if ((int) devc->revision > ('Z' - '@')) + revision_char = '+'; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; + + if (hw_config->name) + sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name); + else + sprintf(mpu_synth_info[m].name, + "MPU-401 %d.%d%c Midi interface #%d", + (int) (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char, + n_mpu_devs); + } + + strcpy(mpu401_midi_operations[m].info.name, + mpu_synth_info[m].name); + + conf_printf(mpu_synth_info[m].name, hw_config); + + mpu401_synth_operations[m]->midi_dev = devc->devno = m; + mpu401_synth_operations[devc->devno]->info = + &mpu_synth_info[devc->devno]; + + if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */ + hw_config->slots[2] = mpu_timer_init(m); + + irq2dev[devc->irq] = m; + midi_devs[m] = &mpu401_midi_operations[devc->devno]; + hw_config->slots[1] = m; + sequencer_init(); +} + +static int +reset_mpu401(struct mpu_config *devc) +{ + unsigned long flags; + int ok, timeout, n; + int timeout_limit; + + /* + * Send the RESET command. Try again if no success at the first time. + * (If the device is in the UART mode, it will not ack the reset cmd). + */ + + ok = 0; + + timeout_limit = devc->initialized ? 30000 : 100000; + devc->initialized = 1; + + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) + ok = output_ready(devc); + + write_command(devc, MPU_RESET); /* + * Send MPU-401 RESET Command + */ + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) + { + save_flags(flags); + cli(); + if (input_avail(devc)) + if (read_data(devc) == MPU_ACK) + ok = 1; + restore_flags(flags); + } + + } + + devc->m_state = ST_INIT; + devc->m_ptr = 0; + devc->m_left = 0; + devc->last_status = 0; + devc->uart_mode = 0; + + return ok; } static void -set_uart_mode (int dev, struct mpu_config *devc, int arg) +set_uart_mode(int dev, struct mpu_config *devc, int arg) { - if (!arg && (devc->capabilities & MPU_CAP_INTLG)) - { - return; - } - - if ((devc->uart_mode == 0) == (arg == 0)) - { - return; /* Already set */ - } - - reset_mpu401 (devc); /* This exits the uart mode */ - - if (arg) - { - if (mpu_cmd (dev, UART_MODE_ON, 0) < 0) - { - printk ("MPU%d: Can't enter UART mode\n", devc->devno); - devc->uart_mode = 0; - return; - } - } - devc->uart_mode = arg; + if (!arg && (devc->capabilities & MPU_CAP_INTLG)) + { + return; + } + if ((devc->uart_mode == 0) == (arg == 0)) + { + return; /* Already set */ + } + reset_mpu401(devc); /* This exits the uart mode */ + + if (arg) + { + if (mpu_cmd(dev, UART_MODE_ON, 0) < 0) + { + printk("MPU%d: Can't enter UART mode\n", devc->devno); + devc->uart_mode = 0; + return; + } + } + devc->uart_mode = arg; } int -probe_mpu401 (struct address_info *hw_config) +probe_mpu401(struct address_info *hw_config) { - int ok = 0; - struct mpu_config tmp_devc; + int ok = 0; + struct mpu_config tmp_devc; + + if (check_region(hw_config->io_base, 2)) + { + printk("\n\nmpu401.c: I/O port %x already in use\n\n", hw_config->io_base); + return 0; + } + tmp_devc.base = hw_config->io_base; + tmp_devc.irq = hw_config->irq; + tmp_devc.initialized = 0; + tmp_devc.opened = 0; + tmp_devc.osp = hw_config->osp; - if (check_region (hw_config->io_base, 2)) - { - printk ("\n\nmpu401.c: I/O port %x already in use\n\n", hw_config->io_base); - return 0; - } - - tmp_devc.base = hw_config->io_base; - tmp_devc.irq = hw_config->irq; - tmp_devc.initialized = 0; - tmp_devc.opened = 0; - tmp_devc.osp = hw_config->osp; - - if (hw_config->always_detect) - return 1; - - if (inb (hw_config->io_base + 1) == 0xff) - { - DDB (printk ("MPU401: Port %x looks dead.\n", hw_config->io_base)); - return 0; /* Just bus float? */ - } - - ok = reset_mpu401 (&tmp_devc); - - if (!ok) - { - DDB (printk ("MPU401: Reset failed on port %x\n", hw_config->io_base)); - } + if (hw_config->always_detect) + return 1; - return ok; + if (inb(hw_config->io_base + 1) == 0xff) + { + DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base)); + return 0; /* Just bus float? */ + } + ok = reset_mpu401(&tmp_devc); + + if (!ok) + { + DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base)); + } + return ok; } void -unload_mpu401 (struct address_info *hw_config) +unload_mpu401(struct address_info *hw_config) { - release_region (hw_config->io_base, 2); - if (hw_config->always_detect == 0 && hw_config->irq > 0) - snd_release_irq (hw_config->irq); + release_region(hw_config->io_base, 2); + if (hw_config->always_detect == 0 && hw_config->irq > 0) + snd_release_irq(hw_config->irq); + sound_unload_mididev(hw_config->slots[1]); + sound_unload_timerdev(hw_config->slots[2]); } /***************************************************** * Timer stuff ****************************************************/ -#if defined(CONFIG_SEQUENCER) +#if defined(CONFIG_SEQUENCER) || defined(MODULE) static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; static volatile int curr_tempo, curr_timebase, hw_timebase; @@ -1326,525 +1292,566 @@ static int metronome_mode; static unsigned long -clocks2ticks (unsigned long clocks) +clocks2ticks(unsigned long clocks) { - /* - * The MPU-401 supports just a limited set of possible timebase values. - * Since the applications require more choices, the driver has to - * program the HW to do its best and to convert between the HW and - * actual timebases. - */ + /* + * The MPU-401 supports just a limited set of possible timebase values. + * Since the applications require more choices, the driver has to + * program the HW to do its best and to convert between the HW and + * actual timebases. + */ - return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; + return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; } static void -set_timebase (int midi_dev, int val) +set_timebase(int midi_dev, int val) { - int hw_val; + int hw_val; + + if (val < 48) + val = 48; + if (val > 1000) + val = 1000; + + hw_val = val; + hw_val = (hw_val + 12) / 24; + if (hw_val > max_timebase) + hw_val = max_timebase; - if (val < 48) - val = 48; - if (val > 1000) - val = 1000; - - hw_val = val; - hw_val = (hw_val + 12) / 24; - if (hw_val > max_timebase) - hw_val = max_timebase; - - if (mpu_cmd (midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) - { - printk ("MPU: Can't set HW timebase to %d\n", hw_val * 24); - return; - } - hw_timebase = hw_val * 24; - curr_timebase = val; + if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) + { + printk("MPU: Can't set HW timebase to %d\n", hw_val * 24); + return; + } + hw_timebase = hw_val * 24; + curr_timebase = val; } static void -tmr_reset (void) +tmr_reset(void) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = curr_clocks = 0; - restore_flags (flags); + save_flags(flags); + cli(); + next_event_time = (unsigned long) -1; + prev_event_time = 0; + curr_ticks = curr_clocks = 0; + restore_flags(flags); } static void -set_timer_mode (int midi_dev) +set_timer_mode(int midi_dev) { - if (timer_mode & TMR_MODE_CLS) - mpu_cmd (midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */ - - if (timer_mode & TMR_INTERNAL) - { - mpu_cmd (midi_dev, 0x80, 0); /* Use MIDI sync */ - } - else - { - if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) - { - mpu_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ - mpu_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ - } - else if (timer_mode & TMR_MODE_FSK) - mpu_cmd (midi_dev, 0x81, 0); /* Use FSK sync */ - } + if (timer_mode & TMR_MODE_CLS) + mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ + + if (timer_mode & TMR_INTERNAL) + { + mpu_cmd(midi_dev, 0x80, 0); /* Use MIDI sync */ + } else + { + if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) + { + mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */ + mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ + } else if (timer_mode & TMR_MODE_FSK) + mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */ + } } static void -stop_metronome (int midi_dev) +stop_metronome(int midi_dev) { - mpu_cmd (midi_dev, 0x84, 0); /* Disable metronome */ + mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ } static void -setup_metronome (int midi_dev) +setup_metronome(int midi_dev) { - int numerator, denominator; - int clks_per_click, num_32nds_per_beat; - int beats_per_measure; - - numerator = ((unsigned) metronome_mode >> 24) & 0xff; - denominator = ((unsigned) metronome_mode >> 16) & 0xff; - clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff; - num_32nds_per_beat = (unsigned) metronome_mode & 0xff; - beats_per_measure = (numerator * 4) >> denominator; - - if (!metronome_mode) - mpu_cmd (midi_dev, 0x84, 0); /* Disable metronome */ - else - { - mpu_cmd (midi_dev, 0xE4, clks_per_click); - mpu_cmd (midi_dev, 0xE6, beats_per_measure); - mpu_cmd (midi_dev, 0x83, 0); /* Enable metronome without accents */ - } + int numerator, denominator; + int clks_per_click, num_32nds_per_beat; + int beats_per_measure; + + numerator = ((unsigned) metronome_mode >> 24) & 0xff; + denominator = ((unsigned) metronome_mode >> 16) & 0xff; + clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff; + num_32nds_per_beat = (unsigned) metronome_mode & 0xff; + beats_per_measure = (numerator * 4) >> denominator; + + if (!metronome_mode) + mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */ + else + { + mpu_cmd(midi_dev, 0xE4, clks_per_click); + mpu_cmd(midi_dev, 0xE6, beats_per_measure); + mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */ + } } static int -mpu_start_timer (int midi_dev) +mpu_start_timer(int midi_dev) { - tmr_reset (); - set_timer_mode (midi_dev); + tmr_reset(); + set_timer_mode(midi_dev); - if (tmr_running) - return TIMER_NOT_ARMED; /* Already running */ + if (tmr_running) + return TIMER_NOT_ARMED; /* Already running */ - if (timer_mode & TMR_INTERNAL) - { - mpu_cmd (midi_dev, 0x02, 0); /* Send MIDI start */ - tmr_running = 1; - return TIMER_NOT_ARMED; - } - else - { - mpu_cmd (midi_dev, 0x35, 0); /* Enable mode messages to PC */ - mpu_cmd (midi_dev, 0x38, 0); /* Enable sys common messages to PC */ - mpu_cmd (midi_dev, 0x39, 0); /* Enable real time messages to PC */ - mpu_cmd (midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ - } + if (timer_mode & TMR_INTERNAL) + { + mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */ + tmr_running = 1; + return TIMER_NOT_ARMED; + } else + { + mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */ + mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */ + mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */ + mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ + } - return TIMER_ARMED; + return TIMER_ARMED; } static int -mpu_timer_open (int dev, int mode) +mpu_timer_open(int dev, int mode) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; - if (timer_open) - return -EBUSY; + if (timer_open) + return -EBUSY; - tmr_reset (); - curr_tempo = 50; - mpu_cmd (midi_dev, 0xE0, 50); - curr_timebase = hw_timebase = 120; - set_timebase (midi_dev, 120); - timer_open = 1; - metronome_mode = 0; - set_timer_mode (midi_dev); + tmr_reset(); + curr_tempo = 50; + mpu_cmd(midi_dev, 0xE0, 50); + curr_timebase = hw_timebase = 120; + set_timebase(midi_dev, 120); + timer_open = 1; + metronome_mode = 0; + set_timer_mode(midi_dev); - mpu_cmd (midi_dev, 0xe7, 0x04); /* Send all clocks to host */ - mpu_cmd (midi_dev, 0x95, 0); /* Enable clock to host */ + mpu_cmd(midi_dev, 0xe7, 0x04); /* Send all clocks to host */ + mpu_cmd(midi_dev, 0x95, 0); /* Enable clock to host */ - return 0; + return 0; } static void -mpu_timer_close (int dev) +mpu_timer_close(int dev) { - int midi_dev = sound_timer_devs[dev]->devlink; + int midi_dev = sound_timer_devs[dev]->devlink; - timer_open = tmr_running = 0; - mpu_cmd (midi_dev, 0x15, 0); /* Stop all */ - mpu_cmd (midi_dev, 0x94, 0); /* Disable clock to host */ - mpu_cmd (midi_dev, 0x8c, 0); /* Disable measure end messages to host */ - stop_metronome (midi_dev); + timer_open = tmr_running = 0; + mpu_cmd(midi_dev, 0x15, 0); /* Stop all */ + mpu_cmd(midi_dev, 0x94, 0); /* Disable clock to host */ + mpu_cmd(midi_dev, 0x8c, 0); /* Disable measure end messages to host */ + stop_metronome(midi_dev); } static int -mpu_timer_event (int dev, unsigned char *event) +mpu_timer_event(int dev, unsigned char *event) { - unsigned char command = event[1]; - unsigned long parm = *(unsigned int *) &event[4]; - int midi_dev = sound_timer_devs[dev]->devlink; - - switch (command) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - if (tmr_running) - break; - return mpu_start_timer (midi_dev); - break; - - case TMR_STOP: - mpu_cmd (midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome (midi_dev); - tmr_running = 0; - break; - - case TMR_CONTINUE: - if (tmr_running) - break; - mpu_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */ - setup_metronome (midi_dev); - tmr_running = 1; - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - - if (mpu_cmd (midi_dev, 0xE0, parm) < 0) - printk ("MPU: Can't set tempo to %d\n", (int) parm); - curr_tempo = parm; - } - break; + unsigned char command = event[1]; + unsigned long parm = *(unsigned int *) &event[4]; + int midi_dev = sound_timer_devs[dev]->devlink; - case TMR_ECHO: - seq_copy_to_input (event, 8); - break; - - case TMR_TIMESIG: - if (metronome_mode) /* Metronome enabled */ - { - metronome_mode = parm; - setup_metronome (midi_dev); - } - break; + switch (command) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + if (tmr_running) + break; + return mpu_start_timer(midi_dev); + break; + + case TMR_STOP: + mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome(midi_dev); + tmr_running = 0; + break; + + case TMR_CONTINUE: + if (tmr_running) + break; + mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ + setup_metronome(midi_dev); + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + + if (mpu_cmd(midi_dev, 0xE0, parm) < 0) + printk("MPU: Can't set tempo to %d\n", (int) parm); + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; + + case TMR_TIMESIG: + if (metronome_mode) /* Metronome enabled */ + { + metronome_mode = parm; + setup_metronome(midi_dev); + } + break; - default:; - } + default:; + } - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static unsigned long -mpu_timer_get_time (int dev) +mpu_timer_get_time(int dev) { - if (!timer_open) - return 0; + if (!timer_open) + return 0; - return curr_ticks; + return curr_ticks; } static int -mpu_timer_ioctl (int dev, - unsigned int command, caddr_t arg) +mpu_timer_ioctl(int dev, + unsigned int command, caddr_t arg) { - int midi_dev = sound_timer_devs[dev]->devlink; - - switch (command) - { - case SNDCTL_TMR_SOURCE: - { - int parm; + int midi_dev = sound_timer_devs[dev]->devlink; - parm = *(int *) arg; - parm &= timer_caps; - - if (parm != 0) + switch (command) { - timer_mode = parm; + case SNDCTL_TMR_SOURCE: + { + int parm; + + parm = *(int *) arg; + parm &= timer_caps; + + if (parm != 0) + { + timer_mode = parm; + + if (timer_mode & TMR_MODE_CLS) + mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */ + } + return (*(int *) arg = timer_mode); + } + break; + + case SNDCTL_TMR_START: + mpu_start_timer(midi_dev); + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome(midi_dev); + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + if (tmr_running) + return 0; + tmr_running = 1; + mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */ + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val; + + val = *(int *) arg; + if (val) + set_timebase(midi_dev, val); + + return (*(int *) arg = curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val; + int ret; + + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) + { + printk("MPU: Can't set tempo to %d\n", (int) val); + return ret; + } + curr_tempo = val; + } + return (*(int *) arg = curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + { + int val; + + val = *(int *) arg; + if (val != 0) /* Can't change */ + return -EINVAL; + + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + } + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + break; + + case SNDCTL_TMR_METRONOME: + metronome_mode = *(int *) arg; + setup_metronome(midi_dev); + return 0; + break; - if (timer_mode & TMR_MODE_CLS) - mpu_cmd (midi_dev, 0x3c, 0); /* Use CLS sync */ - else if (timer_mode & TMR_MODE_SMPTE) - mpu_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */ + default:; } - return (*(int *) arg = timer_mode); - } - break; - - case SNDCTL_TMR_START: - mpu_start_timer (midi_dev); - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - mpu_cmd (midi_dev, 0x01, 0); /* Send MIDI stop */ - stop_metronome (midi_dev); - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - if (tmr_running) - return 0; - tmr_running = 1; - mpu_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */ - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - - val = *(int *) arg; - if (val) - set_timebase (midi_dev, val); - - return (*(int *) arg = curr_timebase); - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - int ret; - - val = *(int *) arg; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - if ((ret = mpu_cmd (midi_dev, 0xE0, val)) < 0) - { - printk ("MPU: Can't set tempo to %d\n", (int) val); - return ret; - } - - curr_tempo = val; - } - - return (*(int *) arg = curr_tempo); - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - - val = *(int *) arg; - if (val != 0) /* Can't change */ - return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - } - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - metronome_mode = *(int *) arg; - setup_metronome (midi_dev); - return 0; - break; - - default:; - } - - return -EINVAL; + return -EINVAL; } static void -mpu_timer_arm (int dev, long time) +mpu_timer_arm(int dev, long time) { - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; - next_event_time = prev_event_time = time; + next_event_time = prev_event_time = time; - return; + return; } static struct sound_timer_operations mpu_timer = { - {"MPU-401 Timer", 0}, - 10, /* Priority */ - 0, /* Local device link */ - mpu_timer_open, - mpu_timer_close, - mpu_timer_event, - mpu_timer_get_time, - mpu_timer_ioctl, - mpu_timer_arm + {"MPU-401 Timer", 0}, + 10, /* Priority */ + 0, /* Local device link */ + mpu_timer_open, + mpu_timer_close, + mpu_timer_event, + mpu_timer_get_time, + mpu_timer_ioctl, + mpu_timer_arm }; static void -mpu_timer_interrupt (void) +mpu_timer_interrupt(void) { - if (!timer_open) - return; + if (!timer_open) + return; - if (!tmr_running) - return; + if (!tmr_running) + return; - curr_clocks++; - curr_ticks = clocks2ticks (curr_clocks); + curr_clocks++; + curr_ticks = clocks2ticks(curr_clocks); - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer (0); - } + if (curr_ticks >= next_event_time) + { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } } -static void -timer_ext_event (struct mpu_config *devc, int event, int parm) +static void timer_ext_event(struct mpu_config *devc, int event, int parm) { - int midi_dev = devc->devno; + int midi_dev = devc->devno; - if (!devc->timer_flag) - return; + if (!devc->timer_flag) + return; - switch (event) - { - case TMR_CLOCK: - printk (""); - break; - - case TMR_START: - printk ("Ext MIDI start\n"); - if (!tmr_running) - if (timer_mode & TMR_EXTERNAL) - { - tmr_running = 1; - setup_metronome (midi_dev); - next_event_time = 0; - STORE (SEQ_START_TIMER ()); - } - break; - - case TMR_STOP: - printk ("Ext MIDI stop\n"); - if (timer_mode & TMR_EXTERNAL) + switch (event) { - tmr_running = 0; - stop_metronome (midi_dev); - STORE (SEQ_STOP_TIMER ()); - } - break; + case TMR_CLOCK: + printk(""); + break; + + case TMR_START: + printk("Ext MIDI start\n"); + if (!tmr_running) + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 1; + setup_metronome(midi_dev); + next_event_time = 0; + STORE(SEQ_START_TIMER()); + } + break; + + case TMR_STOP: + printk("Ext MIDI stop\n"); + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 0; + stop_metronome(midi_dev); + STORE(SEQ_STOP_TIMER()); + } + break; + + case TMR_CONTINUE: + printk("Ext MIDI continue\n"); + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 1; + setup_metronome(midi_dev); + STORE(SEQ_CONTINUE_TIMER()); + } + break; + + case TMR_SPP: + printk("Songpos: %d\n", parm); + if (timer_mode & TMR_EXTERNAL) + { + STORE(SEQ_SONGPOS(parm)); + } + break; + } +} + +static int mpu_timer_init(int midi_dev) +{ + struct mpu_config *devc; + int n; + + devc = &dev_conf[midi_dev]; + + if (timer_initialized) + return -1; /* There is already a similar timer */ + + timer_initialized = 1; + + mpu_timer.devlink = midi_dev; + dev_conf[midi_dev].timer_flag = 1; + + n = sound_alloc_timerdev(); + if (n == -1) + n = 0; + sound_timer_devs[n] = &mpu_timer; - case TMR_CONTINUE: - printk ("Ext MIDI continue\n"); - if (timer_mode & TMR_EXTERNAL) + if (devc->version < 0x20) /* Original MPU-401 */ + timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI; + else { - tmr_running = 1; - setup_metronome (midi_dev); - STORE (SEQ_CONTINUE_TIMER ()); - } - break; + /* + * The version number 2.0 is used (at least) by the + * MusicQuest cards and the Roland Super-MPU. + * + * MusicQuest has given a special meaning to the bits of the + * revision number. The Super-MPU returns 0. + */ - case TMR_SPP: - printk ("Songpos: %d\n", parm); - if (timer_mode & TMR_EXTERNAL) - { - STORE (SEQ_SONGPOS (parm)); - } - break; - } -} + if (devc->revision) + timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; -static void -mpu_timer_init (int midi_dev) -{ - struct mpu_config *devc; - int n; + if (devc->revision & 0x02) + timer_caps |= TMR_MODE_CLS; - devc = &dev_conf[midi_dev]; - if (timer_initialized) - return; /* There is already a similar timer */ + if (devc->revision & 0x40) + max_timebase = 10; /* Has the 216 and 240 ppqn modes */ + } - timer_initialized = 1; + timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; + return n; - mpu_timer.devlink = midi_dev; - dev_conf[midi_dev].timer_flag = 1; +} - if (num_sound_timers >= MAX_TIMER_DEV) - n = 0; /* Overwrite the system timer */ - else - n = num_sound_timers++; - sound_timer_devs[n] = &mpu_timer; +#endif - if (devc->version < 0x20) /* Original MPU-401 */ - timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI; - else - { - /* - * The version number 2.0 is used (at least) by the - * MusicQuest cards and the Roland Super-MPU. - * - * MusicQuest has given a special meaning to the bits of the - * revision number. The Super-MPU returns 0. - */ - if (devc->revision) - timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; +EXPORT_SYMBOL(probe_mpu401); +EXPORT_SYMBOL(attach_mpu401); +EXPORT_SYMBOL(unload_mpu401); +EXPORT_SYMBOL(mpuintr); - if (devc->revision & 0x02) - timer_caps |= TMR_MODE_CLS; +#ifdef MODULE +MODULE_PARM(irq, "i"); +MODULE_PARM(io, "i"); - if (devc->revision & 0x40) - max_timebase = 10; /* Has the 216 and 240 ppqn modes */ - } +int io = -1; +int irq = -1; +struct address_info hw; - timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; +int init_module(void) +{ + /* Can be loaded either for module use or to provide functions + to others */ + if (io != -1 && irq != -1) + { + hw.irq = irq; + hw.io_base = io; + if (probe_mpu401(&hw) == 0) + return -ENODEV; + attach_mpu401(&hw); + } + SOUND_LOCK; + return 0; +} +void cleanup_module(void) +{ + if (io != -1 && irq != -1) + { + unload_mpu401(&hw); + } + /* FREE SYMTAB */ + SOUND_LOCK_END; } -#endif +#else +void +export_mpu401_syms(void) +{ + register_symtab(&mpu401_syms); +} +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.1.66/linux/drivers/sound/opl3.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/opl3.c Sat Nov 29 10:33:21 1997 @@ -11,7 +11,7 @@ * for more info. */ #include - +#include /* * Major improvements to the FM handling 30AUG92 by Rob Hooft, @@ -21,8 +21,9 @@ */ #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_YM3812 +#if defined(CONFIG_YM3812) || defined(MODULE) #include "opl3.h" @@ -30,265 +31,248 @@ #define OFFS_4OP 11 struct voice_info - { - unsigned char keyon_byte; - long bender; - long bender_range; - unsigned long orig_freq; - unsigned long current_freq; - int volume; - int mode; - int panning; /* 0xffff means not set */ - }; +{ + unsigned char keyon_byte; + long bender; + long bender_range; + unsigned long orig_freq; + unsigned long current_freq; + int volume; + int mode; + int panning; /* 0xffff means not set */ +}; typedef struct opl_devinfo - { - int base; - int left_io, right_io; - int nr_voice; - int lv_map[MAX_VOICE]; - - struct voice_info voc[MAX_VOICE]; - struct voice_alloc_info *v_alloc; - struct channel_info *chn_info; - - struct sbi_instrument i_map[SBFM_MAXINSTR]; - struct sbi_instrument *act_i[MAX_VOICE]; - - struct synth_info fm_info; - - int busy; - int model; - unsigned char cmask; - - int is_opl4; - int *osp; - } -opl_devinfo; +{ + int base; + int left_io, right_io; + int nr_voice; + int lv_map[MAX_VOICE]; + + struct voice_info voc[MAX_VOICE]; + struct voice_alloc_info *v_alloc; + struct channel_info *chn_info; + + struct sbi_instrument i_map[SBFM_MAXINSTR]; + struct sbi_instrument *act_i[MAX_VOICE]; + + struct synth_info fm_info; + + int busy; + int model; + unsigned char cmask; + + int is_opl4; + int *osp; +} opl_devinfo; static struct opl_devinfo *devc = NULL; static int detected_model; -static int store_instr (int instr_no, struct sbi_instrument *instr); -static void freq_to_fnum (int freq, int *block, int *fnum); -static void opl3_command (int io_addr, unsigned int addr, unsigned int val); -static int opl3_kill_note (int dev, int voice, int note, int velocity); +static int store_instr(int instr_no, struct sbi_instrument *instr); +static void freq_to_fnum(int freq, int *block, int *fnum); +static void opl3_command(int io_addr, unsigned int addr, unsigned int val); +static int opl3_kill_note(int dev, int voice, int note, int velocity); -static void -enter_4op_mode (void) +static void enter_4op_mode(void) { - int i; - static int v4op[MAX_VOICE] = - {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17}; + int i; + static int v4op[MAX_VOICE] = { + 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17 + }; - devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */ - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f); + devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */ + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f); - for (i = 0; i < 3; i++) - pv_map[i].voice_mode = 4; - for (i = 3; i < 6; i++) - pv_map[i].voice_mode = 0; + for (i = 0; i < 3; i++) + pv_map[i].voice_mode = 4; + for (i = 3; i < 6; i++) + pv_map[i].voice_mode = 0; - for (i = 9; i < 12; i++) - pv_map[i].voice_mode = 4; - for (i = 12; i < 15; i++) - pv_map[i].voice_mode = 0; + for (i = 9; i < 12; i++) + pv_map[i].voice_mode = 4; + for (i = 12; i < 15; i++) + pv_map[i].voice_mode = 0; - for (i = 0; i < 12; i++) - devc->lv_map[i] = v4op[i]; - devc->v_alloc->max_voice = devc->nr_voice = 12; + for (i = 0; i < 12; i++) + devc->lv_map[i] = v4op[i]; + devc->v_alloc->max_voice = devc->nr_voice = 12; } -static int -opl3_ioctl (int dev, - unsigned int cmd, caddr_t arg) +static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg) { - switch (cmd) - { - - case SNDCTL_FM_LOAD_INSTR: - { - struct sbi_instrument ins; - - printk ("Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); - memcpy ((char *) &ins, (&((char *) arg)[0]), sizeof (ins)); - - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) - { - printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - - return store_instr (ins.channel, &ins); - } - break; - - case SNDCTL_SYNTH_INFO: - devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - - memcpy ((&((char *) arg)[0]), (char *) &devc->fm_info, sizeof (devc->fm_info)); - return 0; - break; - - case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; - - case SNDCTL_FM_4OP_ENABLE: - if (devc->model == 2) - enter_4op_mode (); - return 0; - break; + switch (cmd) + { - default: - return -EINVAL; - } + case SNDCTL_FM_LOAD_INSTR: + { + struct sbi_instrument ins; + + printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); + memcpy((char *) &ins, (&((char *) arg)[0]), sizeof(ins)); + + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) + { + printk("FM Error: Invalid instrument number %d\n", ins.channel); + return -EINVAL; + } + return store_instr(ins.channel, &ins); + } + + case SNDCTL_SYNTH_INFO: + devc->fm_info.nr_voices = + (devc->nr_voice == 12) ? 6 : devc->nr_voice; + memcpy((&((char *) arg)[0]), (char *) &devc->fm_info, sizeof(devc->fm_info)); + return 0; + + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + + case SNDCTL_FM_4OP_ENABLE: + if (devc->model == 2) + enter_4op_mode(); + return 0; + default: + return -EINVAL; + } } -int -opl3_detect (int ioaddr, int *osp) +int opl3_detect(int ioaddr, int *osp) { - /* - * This function returns 1 if the FM chip is present at the given I/O port - * The detection algorithm plays with the timer built in the FM chip and - * looks for a change in the status register. - * - * Note! The timers of the FM chip are not connected to AdLib (and compatible) - * boards. - * - * Note2! The chip is initialized if detected. - */ - - unsigned char stat1, signature; - int i; - - if (devc != NULL) - return 0; - - - devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (*devc))); - sound_mem_sizes[sound_nblocks] = sizeof (*devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - - if (devc == NULL) - { - printk ("OPL3: Can't allocate memory for the device control structure\n"); - return 0; - } + /* + * This function returns 1 if the FM chip is present at the given I/O port + * The detection algorithm plays with the timer built in the FM chip and + * looks for a change in the status register. + * + * Note! The timers of the FM chip are not connected to AdLib (and compatible) + * boards. + * + * Note2! The chip is initialized if detected. + */ - devc->osp = osp; - devc->base = ioaddr; + unsigned char stat1, signature; + int i; - /* Reset timers 1 and 2 */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - - /* Reset the IRQ of the FM chip */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); - - signature = stat1 = inb (ioaddr); /* Status register */ + if (devc != NULL) + { + printk(KERN_ERR "opl3: Only one OPL3 supported.\n"); + return 0; + } - if (signature != 0x00 && signature != 0x06 && signature != 0x02 && - signature != 0x0f) - { - DDB (printk ("OPL3 not detected %x\n", signature)); - return 0; - } + devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(*devc))); + sound_mem_sizes[sound_nblocks] = sizeof(*devc); + if (sound_nblocks < 1024) + sound_nblocks++;; - if (signature == 0x06) /* OPL2 */ - { - detected_model = 2; - } - else if (signature == 0x00 || signature == 0x0f) /* OPL3 or OPL4 */ - { - unsigned char tmp; + if (devc == NULL) + { + printk(KERN_ERR "OPL3: Can't allocate memory for the device control " + "structure \n "); + return 0; + } + devc->osp = osp; + devc->base = ioaddr; - detected_model = 3; + /* Reset timers 1 and 2 */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - /* - * Detect availability of OPL4 (_experimental_). Works probably - * only after a cold boot. In addition the OPL4 port - * of the chip may not be connected to the PC bus at all. - */ + /* Reset the IRQ of the FM chip */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); - opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, 0x00); - opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); + signature = stat1 = inb(ioaddr); /* Status register */ - if ((tmp = inb (ioaddr)) == 0x02) /* Have a OPL4 */ + if (signature != 0x00 && signature != 0x06 && signature != 0x02 && + signature != 0x0f) { - detected_model = 4; + MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature)); + return 0; } - if (!check_region (ioaddr - 8, 2)) /* OPL4 port is free */ + if (signature == 0x06) /* OPL2 */ { - int tmp; - - outb ((0x02), ioaddr - 8); /* Select OPL4 ID register */ - tenmicrosec (devc->osp); - tmp = inb (ioaddr - 7); /* Read it */ - tenmicrosec (devc->osp); - - if (tmp == 0x20) /* OPL4 should return 0x20 here */ - { - detected_model = 4; - - outb ((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ - tenmicrosec (devc->osp); - outb ((0x1B), ioaddr - 7); /* Write value */ - tenmicrosec (devc->osp); - } - else - detected_model = 3; + detected_model = 2; } + else if (signature == 0x00 || signature == 0x0f) /* OPL3 or OPL4 */ + { + unsigned char tmp; - opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, 0); - - } - - for (i = 0; i < 9; i++) - opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* - * Note off - */ + detected_model = 3; - opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl3_command (ioaddr, PERCOSSION_REGISTER, 0x00); /* - * Melodic mode. - */ + /* + * Detect availability of OPL4 (_experimental_). Works probably + * only after a cold boot. In addition the OPL4 port + * of the chip may not be connected to the PC bus at all. + */ + + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00); + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); + + if ((tmp = inb(ioaddr)) == 0x02) /* Have a OPL4 */ + { + detected_model = 4; + } + + if (!check_region(ioaddr - 8, 2)) /* OPL4 port is free */ + { + int tmp; + + outb((0x02), ioaddr - 8); /* Select OPL4 ID register */ + tenmicrosec(devc->osp); + tmp = inb(ioaddr - 7); /* Read it */ + tenmicrosec(devc->osp); + + if (tmp == 0x20) /* OPL4 should return 0x20 here */ + { + detected_model = 4; + outb((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ + tenmicrosec(devc->osp); + outb((0x1B), ioaddr - 7); /* Write value */ + tenmicrosec(devc->osp); + } + else + detected_model = 3; + } + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); + } + for (i = 0; i < 9; i++) + opl3_command(ioaddr, KEYON_BLOCK + i, 0); /* + * Note off + */ - return 1; + opl3_command(ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); + opl3_command(ioaddr, PERCOSSION_REGISTER, 0x00); /* + * Melodic mode. + */ + return 1; } -static int -opl3_kill_note (int devno, int voice, int note, int velocity) +static int opl3_kill_note (int devno, int voice, int note, int velocity) { - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return 0; - - devc->v_alloc->map[voice] = 0; + struct physical_voice_info *map; - map = &pv_map[devc->lv_map[voice]]; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - DEB (printk ("Kill note %d\n", voice)); + devc->v_alloc->map[voice] = 0; - if (map->voice_mode == 0) - return 0; + map = &pv_map[devc->lv_map[voice]]; + DEB(printk("Kill note %d\n", voice)); - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20); + if (map->voice_mode == 0) + return 0; - devc->voc[voice].keyon_byte = 0; - devc->voc[voice].bender = 0; - devc->voc[voice].volume = 64; - devc->voc[voice].panning = 0xffff; /* Not set */ - devc->voc[voice].bender_range = 200; - devc->voc[voice].orig_freq = 0; - devc->voc[voice].current_freq = 0; - devc->voc[voice].mode = 0; - - return 0; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20); + devc->voc[voice].keyon_byte = 0; + devc->voc[voice].bender = 0; + devc->voc[voice].volume = 64; + devc->voc[voice].panning = 0xffff; /* Not set */ + devc->voc[voice].bender_range = 200; + devc->voc[voice].orig_freq = 0; + devc->voc[voice].current_freq = 0; + devc->voc[voice].mode = 0; + return 0; } #define HIHAT 0 @@ -299,28 +283,23 @@ #define UNDEFINED TOMTOM #define DEFAULT TOMTOM -static int -store_instr (int instr_no, struct sbi_instrument *instr) +static int store_instr(int instr_no, struct sbi_instrument *instr) { - - if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || devc->model != 2)) - printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key); - memcpy ((char *) &(devc->i_map[instr_no]), (char *) instr, sizeof (*instr)); - - return 0; + if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || devc->model != 2)) + printk(KERN_WARNING "FM warning: Invalid patch format field (key) 0x%x\n", instr->key); + memcpy((char *) &(devc->i_map[instr_no]), (char *) instr, sizeof(*instr)); + return 0; } -static int -opl3_set_instr (int dev, int voice, int instr_no) +static int opl3_set_instr (int dev, int voice, int instr_no) { - if (voice < 0 || voice >= devc->nr_voice) - return 0; - - if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) - instr_no = 0; /* Acoustic piano (usually) */ + if (voice < 0 || voice >= devc->nr_voice) + return 0; + if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) + instr_no = 0; /* Acoustic piano (usually) */ - devc->act_i[voice] = &devc->i_map[instr_no]; - return 0; + devc->act_i[voice] = &devc->i_map[instr_no]; + return 0; } /* @@ -332,880 +311,911 @@ * volume -8 it was implemented as a table because it is only 128 bytes and * it saves a lot of log() calculations. (RH) */ -static char fm_volume_table[128] = -{-64, -48, -40, -35, -32, -29, -27, -26, - -24, -23, -21, -20, -19, -18, -18, -17, - -16, -15, -15, -14, -13, -13, -12, -12, - -11, -11, -10, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -6, -6, -6, - -5, -5, -5, -5, -4, -4, -4, -4, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -1, -1, -1, -1, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 4, - 4, 4, 4, 4, 4, 4, 4, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 8, 8, 8, 8, 8}; -static void -calc_vol (unsigned char *regbyte, int volume, int main_vol) +static char fm_volume_table[128] = { - int level = (~*regbyte & 0x3f); + -64, -48, -40, -35, -32, -29, -27, -26, + -24, -23, -21, -20, -19, -18, -18, -17, + -16, -15, -15, -14, -13, -13, -12, -12, + -11, -11, -10, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -6, -6, -6, + -5, -5, -5, -5, -4, -4, -4, -4, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -1, -1, -1, -1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8 +}; - if (main_vol > 127) - main_vol = 127; +static void calc_vol(unsigned char *regbyte, int volume, int main_vol) +{ + int level = (~*regbyte & 0x3f); - volume = (volume * main_vol) / 127; + if (main_vol > 127) + main_vol = 127; + volume = (volume * main_vol) / 127; - if (level) - level += fm_volume_table[volume]; + if (level) + level += fm_volume_table[volume]; - if (level > 0x3f) - level = 0x3f; - if (level < 0) - level = 0; + if (level > 0x3f) + level = 0x3f; + if (level < 0) + level = 0; - *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); + *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); } -static void -set_voice_volume (int voice, int volume, int main_vol) +static void set_voice_volume(int voice, int volume, int main_vol) { - unsigned char vol1, vol2, vol3, vol4; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return; - - map = &pv_map[devc->lv_map[voice]]; + unsigned char vol1, vol2, vol3, vol4; + struct sbi_instrument *instr; + struct physical_voice_info *map; - instr = devc->act_i[voice]; + if (voice < 0 || voice >= devc->nr_voice) + return; - if (!instr) - instr = &devc->i_map[0]; + map = &pv_map[devc->lv_map[voice]]; + instr = devc->act_i[voice]; - if (instr->channel < 0) - return; + if (!instr) + instr = &devc->i_map[0]; - if (devc->voc[voice].mode == 0) - return; + if (instr->channel < 0) + return; - if (devc->voc[voice].mode == 2) - { + if (devc->voc[voice].mode == 0) + return; - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - - if ((instr->operators[10] & 0x01)) - { - calc_vol (&vol1, volume, main_vol); - calc_vol (&vol2, volume, main_vol); - } - else + if (devc->voc[voice].mode == 2) { - calc_vol (&vol2, volume, main_vol); + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + if ((instr->operators[10] & 0x01)) + { + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol2, volume, main_vol); + } + else + { + calc_vol(&vol2, volume, main_vol); + } + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); } - - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); - } - else - { /* - * 4 OP voice - */ - int connection; - - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - vol3 = instr->operators[OFFS_4OP + 2]; - vol4 = instr->operators[OFFS_4OP + 3]; - - /* - * The connection method for 4 OP devc->voc is defined by the rightmost - * bits at the offsets 10 and 10+OFFS_4OP - */ - - connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - - switch (connection) - { - case 0: - calc_vol (&vol4, volume, main_vol); - break; - - case 1: - calc_vol (&vol2, volume, main_vol); - calc_vol (&vol4, volume, main_vol); - break; - - case 2: - calc_vol (&vol1, volume, main_vol); - calc_vol (&vol4, volume, main_vol); - break; - - case 3: - calc_vol (&vol1, volume, main_vol); - calc_vol (&vol3, volume, main_vol); - calc_vol (&vol4, volume, main_vol); - break; - - default:; + else + { /* + * 4 OP voice + */ + int connection; + + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + vol3 = instr->operators[OFFS_4OP + 2]; + vol4 = instr->operators[OFFS_4OP + 3]; + + /* + * The connection method for 4 OP devc->voc is defined by the rightmost + * bits at the offsets 10 and 10+OFFS_4OP + */ + + connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + + switch (connection) + { + case 0: + calc_vol(&vol4, volume, main_vol); + break; + + case 1: + calc_vol(&vol2, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + case 2: + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + case 3: + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol3, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + default: + ; + } + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], vol3); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], vol4); } - - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], vol3); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], vol4); - } } -static int -opl3_start_note (int dev, int voice, int note, int volume) +static int opl3_start_note (int dev, int voice, int note, int volume) { - unsigned char data, fpc; - int block, fnum, freq, voice_mode, pan; - struct sbi_instrument *instr; - struct physical_voice_info *map; + unsigned char data, fpc; + int block, fnum, freq, voice_mode, pan; + struct sbi_instrument *instr; + struct physical_voice_info *map; - if (voice < 0 || voice >= devc->nr_voice) - return 0; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - map = &pv_map[devc->lv_map[voice]]; - pan = devc->voc[voice].panning; + map = &pv_map[devc->lv_map[voice]]; + pan = devc->voc[voice].panning; - if (map->voice_mode == 0) - return 0; + if (map->voice_mode == 0) + return 0; - if (note == 255) /* + if (note == 255) /* * Just change the volume */ - { - set_voice_volume (voice, volume, devc->voc[voice].volume); - return 0; - } - - /* - * Kill previous note before playing - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* - * Carrier - * volume to - * min - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* - * Modulator - * volume to - */ + { + set_voice_volume(voice, volume, devc->voc[voice].volume); + return 0; + } - if (map->voice_mode == 4) - { - opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], 0xff); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff); - } + /* + * Kill previous note before playing + */ + + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* + * Carrier + * volume to + * min + */ + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* + * Modulator + * volume to + */ - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* + if (map->voice_mode == 4) + { + opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], 0xff); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], 0xff); + } + + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* * Note * off */ - instr = devc->act_i[voice]; - - if (!instr) - instr = &devc->i_map[0]; + instr = devc->act_i[voice]; + + if (!instr) + instr = &devc->i_map[0]; - if (instr->channel < 0) - { - printk ("OPL3: Initializing voice %d with undefined instrument\n", voice); - return 0; - } + if (instr->channel < 0) + { + printk(KERN_WARNING "OPL3: Initializing voice %d with undefined instrument\n", voice); + return 0; + } - if (map->voice_mode == 2 && instr->key == OPL3_PATCH) - return 0; /* + if (map->voice_mode == 2 && instr->key == OPL3_PATCH) + return 0; /* * Cannot play */ - voice_mode = map->voice_mode; + voice_mode = map->voice_mode; - if (voice_mode == 4) - { - int voice_shift; + if (voice_mode == 4) + { + int voice_shift; - voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; - voice_shift += map->voice_num; + voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; + voice_shift += map->voice_num; - if (instr->key != OPL3_PATCH) /* - * Just 2 OP patch - */ - { - voice_mode = 2; - devc->cmask &= ~(1 << voice_shift); + if (instr->key != OPL3_PATCH) /* + * Just 2 OP patch + */ + { + voice_mode = 2; + devc->cmask &= ~(1 << voice_shift); + } + else + { + devc->cmask |= (1 << voice_shift); + } + + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); } - else + + /* + * Set Sound Characteristics + */ + + opl3_command(map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); + opl3_command(map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); + + /* + * Set Attack/Decay + */ + + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); + + /* + * Set Sustain/Release + */ + + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); + + /* + * Set Wave Select + */ + + opl3_command(map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); + opl3_command(map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); + + /* + * Set Feedback/Connection + */ + + fpc = instr->operators[10]; + + if (pan != 0xffff) { - devc->cmask |= (1 << voice_shift); + fpc &= ~STEREO_BITS; + if (pan < -64) + fpc |= VOICE_TO_LEFT; + else + if (pan > 64) + fpc |= VOICE_TO_RIGHT; + else + fpc |= (VOICE_TO_LEFT | VOICE_TO_RIGHT); } - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - } - - /* - * Set Sound Characteristics - */ - opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); - opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); - - /* - * Set Attack/Decay - */ - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); - - /* - * Set Sustain/Release - */ - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); - - /* - * Set Wave Select - */ - opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); - opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); - - /* - * Set Feedback/Connection - */ - fpc = instr->operators[10]; - - if (pan != 0xffff) - { - fpc &= ~STEREO_BITS; - - if (pan < -64) - fpc |= VOICE_TO_LEFT; - else if (pan > 64) - fpc |= VOICE_TO_RIGHT; - else - fpc |= (VOICE_TO_LEFT | VOICE_TO_RIGHT); - } - - if (!(fpc & 0x30)) - fpc |= 0x30; /* + if (!(fpc & 0x30)) + fpc |= 0x30; /* * Ensure that at least one chn is enabled */ - opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, - fpc); + opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc); - /* - * If the voice is a 4 OP one, initialize the operators 3 and 4 also - */ - - if (voice_mode == 4) - { - - /* - * Set Sound Characteristics - */ - opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); - opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); - - /* - * Set Attack/Decay - */ - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); - - /* - * Set Sustain/Release - */ - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); - - /* - * Set Wave Select - */ - opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); - opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); - - /* - * Set Feedback/Connection - */ - fpc = instr->operators[OFFS_4OP + 10]; - if (!(fpc & 0x30)) - fpc |= 0x30; /* - * Ensure that at least one chn is enabled - */ - opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); - } + /* + * If the voice is a 4 OP one, initialize the operators 3 and 4 also + */ - devc->voc[voice].mode = voice_mode; + if (voice_mode == 4) + { + /* + * Set Sound Characteristics + */ + + opl3_command(map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); + opl3_command(map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); + + /* + * Set Attack/Decay + */ + + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); + + /* + * Set Sustain/Release + */ + + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); + + /* + * Set Wave Select + */ + + opl3_command(map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); + opl3_command(map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); + + /* + * Set Feedback/Connection + */ + + fpc = instr->operators[OFFS_4OP + 10]; + if (!(fpc & 0x30)) + fpc |= 0x30; /* + * Ensure that at least one chn is enabled + */ + opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); + } - set_voice_volume (voice, volume, devc->voc[voice].volume); + devc->voc[voice].mode = voice_mode; + set_voice_volume(voice, volume, devc->voc[voice].volume); - freq = devc->voc[voice].orig_freq = note_to_freq (note) / 1000; + freq = devc->voc[voice].orig_freq = note_to_freq(note) / 1000; - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ - freq = compute_finetune (devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); - devc->voc[voice].current_freq = freq; + freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); + devc->voc[voice].current_freq = freq; - freq_to_fnum (freq, &block, &fnum); + freq_to_fnum(freq, &block, &fnum); - /* - * Play note - */ + /* + * Play note + */ - data = fnum & 0xff; /* + data = fnum & 0xff; /* * Least significant bits of fnumber */ - opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); - if (voice_mode == 4) - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + devc->voc[voice].keyon_byte = data; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); + if (voice_mode == 4) + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); - return 0; + return 0; } -static void -freq_to_fnum (int freq, int *block, int *fnum) +static void freq_to_fnum (int freq, int *block, int *fnum) { - int f, octave; + int f, octave; - /* - * Converts the note frequency to block and fnum values for the FM chip - */ - /* - * First try to compute the block -value (octave) where the note belongs - */ + /* + * Converts the note frequency to block and fnum values for the FM chip + */ + /* + * First try to compute the block -value (octave) where the note belongs + */ - f = freq; + f = freq; - octave = 5; + octave = 5; - if (f == 0) - octave = 0; - else if (f < 261) - { - while (f < 261) + if (f == 0) + octave = 0; + else if (f < 261) { - octave--; - f <<= 1; + while (f < 261) + { + octave--; + f <<= 1; + } } - } - else if (f > 493) - { - while (f > 493) + else if (f > 493) { - octave++; - f >>= 1; + while (f > 493) + { + octave++; + f >>= 1; + } } - } - if (octave > 7) - octave = 7; + if (octave > 7) + octave = 7; - *fnum = freq * (1 << (20 - octave)) / 49716; - *block = octave; + *fnum = freq * (1 << (20 - octave)) / 49716; + *block = octave; } -static void -opl3_command (int io_addr, unsigned int addr, unsigned int val) +static void opl3_command (int io_addr, unsigned int addr, unsigned int val) { - int i; + int i; - /* - * The original 2-OP synth requires a quite long delay after writing to a - * register. The OPL-3 survives with just two INBs - */ + /* + * The original 2-OP synth requires a quite long delay after writing to a + * register. The OPL-3 survives with just two INBs + */ - outb (((unsigned char) (addr & 0xff)), io_addr); + outb(((unsigned char) (addr & 0xff)), io_addr); - if (devc->model != 2) - tenmicrosec (devc->osp); - else - for (i = 0; i < 2; i++) - inb (io_addr); + if (devc->model != 2) + tenmicrosec(devc->osp); + else + for (i = 0; i < 2; i++) + inb(io_addr); - outb (((unsigned char) (val & 0xff)), io_addr + 1); + outb(((unsigned char) (val & 0xff)), io_addr + 1); - if (devc->model != 2) - { - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - } - else - for (i = 0; i < 2; i++) - inb (io_addr); + if (devc->model != 2) + { + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + } + else + for (i = 0; i < 2; i++) + inb(io_addr); } -static void -opl3_reset (int devno) +static void opl3_reset(int devno) { - int i; - - for (i = 0; i < 18; i++) - devc->lv_map[i] = i; - - for (i = 0; i < devc->nr_voice; i++) - { - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); + int i; - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); + for (i = 0; i < 18; i++) + devc->lv_map[i] = i; - if (pv_map[devc->lv_map[i]].voice_mode == 4) + for (i = 0; i < devc->nr_voice; i++) { - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); - opl3_command (pv_map[devc->lv_map[i]].ioaddr, - KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); - } + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); - opl3_kill_note (devno, i, 0, 64); - } + if (pv_map[devc->lv_map[i]].voice_mode == 4) + { + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); + + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); + } - if (devc->model == 2) - { - devc->v_alloc->max_voice = devc->nr_voice = 18; + opl3_kill_note(devno, i, 0, 64); + } - for (i = 0; i < 18; i++) - pv_map[i].voice_mode = 2; + if (devc->model == 2) + { + devc->v_alloc->max_voice = devc->nr_voice = 18; - } + for (i = 0; i < 18; i++) + pv_map[i].voice_mode = 2; + } } -static int -opl3_open (int dev, int mode) +static int opl3_open(int dev, int mode) { - int i; + int i; - if (devc->busy) - return -EBUSY; - devc->busy = 1; + if (devc->busy) + return -EBUSY; + MOD_INC_USE_COUNT; + devc->busy = 1; - devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; - devc->v_alloc->timestamp = 0; + devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; + devc->v_alloc->timestamp = 0; - for (i = 0; i < 18; i++) - { - devc->v_alloc->map[i] = 0; - devc->v_alloc->alloc_times[i] = 0; - } + for (i = 0; i < 18; i++) + { + devc->v_alloc->map[i] = 0; + devc->v_alloc->alloc_times[i] = 0; + } - devc->cmask = 0x00; /* + devc->cmask = 0x00; /* * Just 2 OP mode */ - if (devc->model == 2) - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); - return 0; + if (devc->model == 2) + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); + return 0; } -static void -opl3_close (int dev) +static void opl3_close(int dev) { - devc->busy = 0; - devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; + devc->busy = 0; + devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; - devc->fm_info.nr_drums = 0; - devc->fm_info.perc_mode = 0; + devc->fm_info.nr_drums = 0; + devc->fm_info.perc_mode = 0; - opl3_reset (dev); + opl3_reset(dev); + MOD_DEC_USE_COUNT; } -static void -opl3_hw_control (int dev, unsigned char *event) +static void opl3_hw_control(int dev, unsigned char *event) { } -static int -opl3_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +static int opl3_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - struct sbi_instrument ins; + struct sbi_instrument ins; - if (count < sizeof (ins)) - { - printk ("FM Error: Patch record too short\n"); - return -EINVAL; - } + if (count = SBFM_MAXINSTR) - { - printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; - } - ins.key = format; + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) + { + printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel); + return -EINVAL; + } + ins.key = format; - return store_instr (ins.channel, &ins); + return store_instr(ins.channel, &ins); } -static void -opl3_panning (int dev, int voice, int value) +static void opl3_panning(int dev, int voice, int value) { - devc->voc[voice].panning = value; + devc->voc[voice].panning = value; } -static void -opl3_volume_method (int dev, int mode) +static void opl3_volume_method(int dev, int mode) { } #define SET_VIBRATO(cell) { \ - tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ - if (pressure > 110) \ - tmp |= 0x40; /* Vibrato on */ \ - opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} + tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ + if (pressure > 110) \ + tmp |= 0x40; /* Vibrato on */ \ + opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} -static void -opl3_aftertouch (int dev, int voice, int pressure) +static void opl3_aftertouch(int dev, int voice, int pressure) { - int tmp; - struct sbi_instrument *instr; - struct physical_voice_info *map; - - if (voice < 0 || voice >= devc->nr_voice) - return; + int tmp; + struct sbi_instrument *instr; + struct physical_voice_info *map; - map = &pv_map[devc->lv_map[voice]]; + if (voice < 0 || voice >= devc->nr_voice) + return; - DEB (printk ("Aftertouch %d\n", voice)); + map = &pv_map[devc->lv_map[voice]]; - if (map->voice_mode == 0) - return; + DEB(printk("Aftertouch %d\n", voice)); - /* - * Adjust the amount of vibrato depending the pressure - */ + if (map->voice_mode == 0) + return; - instr = devc->act_i[voice]; + /* + * Adjust the amount of vibrato depending the pressure + */ - if (!instr) - instr = &devc->i_map[0]; + instr = devc->act_i[voice]; - if (devc->voc[voice].mode == 4) - { - int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + if (!instr) + instr = &devc->i_map[0]; - switch (connection) + if (devc->voc[voice].mode == 4) { - case 0: - SET_VIBRATO (4); - break; - - case 1: - SET_VIBRATO (2); - SET_VIBRATO (4); - break; - - case 2: - SET_VIBRATO (1); - SET_VIBRATO (4); - break; - - case 3: - SET_VIBRATO (1); - SET_VIBRATO (3); - SET_VIBRATO (4); - break; + int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + switch (connection) + { + case 0: + SET_VIBRATO(4); + break; + + case 1: + SET_VIBRATO(2); + SET_VIBRATO(4); + break; + + case 2: + SET_VIBRATO(1); + SET_VIBRATO(4); + break; + + case 3: + SET_VIBRATO(1); + SET_VIBRATO(3); + SET_VIBRATO(4); + break; + + } + /* + * Not implemented yet + */ } - /* - * Not implemented yet - */ - } - else - { - SET_VIBRATO (1); + else + { + SET_VIBRATO(1); - if ((instr->operators[10] & 0x01)) /* - * Additive synthesis - */ - SET_VIBRATO (2); - } + if ((instr->operators[10] & 0x01)) /* + * Additive synthesis + */ + SET_VIBRATO(2); + } } #undef SET_VIBRATO -static void -bend_pitch (int dev, int voice, int value) +static void bend_pitch(int dev, int voice, int value) { - unsigned char data; - int block, fnum, freq; - struct physical_voice_info *map; - - map = &pv_map[devc->lv_map[voice]]; - - if (map->voice_mode == 0) - return; - - devc->voc[voice].bender = value; - if (!value) - return; - if (!(devc->voc[voice].keyon_byte & 0x20)) - return; /* - * Not keyed on - */ + unsigned char data; + int block, fnum, freq; + struct physical_voice_info *map; + + map = &pv_map[devc->lv_map[voice]]; + + if (map->voice_mode == 0) + return; - freq = compute_finetune (devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); - devc->voc[voice].current_freq = freq; + devc->voc[voice].bender = value; + if (!value) + return; + if (!(devc->voc[voice].keyon_byte & 0x20)) + return; /* + * Not keyed on + */ - freq_to_fnum (freq, &block, &fnum); + freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0); + devc->voc[voice].current_freq = freq; - data = fnum & 0xff; /* + freq_to_fnum(freq, &block, &fnum); + + data = fnum & 0xff; /* * Least significant bits of fnumber */ - opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - devc->voc[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + devc->voc[voice].keyon_byte = data; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); } -static void -opl3_controller (int dev, int voice, int ctrl_num, int value) +static void opl3_controller (int dev, int voice, int ctrl_num, int value) { - if (voice < 0 || voice >= devc->nr_voice) - return; - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - bend_pitch (dev, voice, value); - break; + if (voice < 0 || voice >= devc->nr_voice) + return; - case CTRL_PITCH_BENDER_RANGE: - devc->voc[voice].bender_range = value; - break; - - case CTL_MAIN_VOLUME: - devc->voc[voice].volume = value / 128; - break; - - case CTL_PAN: - devc->voc[voice].panning = (value * 2) - 128; - break; - } + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + bend_pitch(dev, voice, value); + break; + + case CTRL_PITCH_BENDER_RANGE: + devc->voc[voice].bender_range = value; + break; + + case CTL_MAIN_VOLUME: + devc->voc[voice].volume = value / 128; + break; + + case CTL_PAN: + devc->voc[voice].panning = (value * 2) - 128; + break; + } } -static void -opl3_bender (int dev, int voice, int value) +static void opl3_bender(int dev, int voice, int value) { - if (voice < 0 || voice >= devc->nr_voice) - return; + if (voice < 0 || voice >= devc->nr_voice) + return; - bend_pitch (dev, voice, value - 8192); + bend_pitch(dev, voice, value - 8192); } -static int -opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) +static int opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best, first, avail, best_time = 0x7fffffff; - struct sbi_instrument *instr; - int is4op; - int instr_no; - - if (chn < 0 || chn > 15) - instr_no = 0; - else - instr_no = devc->chn_info[chn].pgm_num; + int i, p, best, first, avail, best_time = 0x7fffffff; + struct sbi_instrument *instr; + int is4op; + int instr_no; - instr = &devc->i_map[instr_no]; - if (instr->channel < 0 || /* Instrument not loaded */ - devc->nr_voice != 12) /* Not in 4 OP mode */ - is4op = 0; - else if (devc->nr_voice == 12) /* 4 OP mode */ - is4op = (instr->key == OPL3_PATCH); - else - is4op = 0; - - if (is4op) - { - first = p = 0; - avail = 6; - } - else - { - if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP only' operators first */ - first = p = 6; - else - first = p = 0; - avail = devc->nr_voice; - } + if (chn < 0 || chn > 15) + instr_no = 0; + else + instr_no = devc->chn_info[chn].pgm_num; - /* - * Now try to find a free voice - */ - best = first; + instr = &devc->i_map[instr_no]; + if (instr->channel < 0 || /* Instrument not loaded */ + devc->nr_voice != 12) /* Not in 4 OP mode */ + is4op = 0; + else if (devc->nr_voice == 12) /* 4 OP mode */ + is4op = (instr->key == OPL3_PATCH); + else + is4op = 0; - for (i = 0; i < avail; i++) - { - if (alloc->map[p] == 0) + if (is4op) { - return p; + first = p = 0; + avail = 6; } - if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ + else { - best_time = alloc->alloc_times[p]; - best = p; + if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP only' operators first */ + first = p = 6; + else + first = p = 0; + avail = devc->nr_voice; } - p = (p + 1) % avail; - } - /* - * Insert some kind of priority mechanism here. - */ + /* + * Now try to find a free voice + */ + best = first; - if (best < 0) - best = 0; - if (best > devc->nr_voice) - best -= devc->nr_voice; + for (i = 0; i < avail; i++) + { + if (alloc->map[p] == 0) + { + return p; + } + if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ + { + best_time = alloc->alloc_times[p]; + best = p; + } + p = (p + 1) % avail; + } - return best; /* All devc->voc in use. Select the first one. */ + /* + * Insert some kind of priority mechanism here. + */ + + if (best < 0) + best = 0; + if (best > devc->nr_voice) + best -= devc->nr_voice; + + return best; /* All devc->voc in use. Select the first one. */ } -static void -opl3_setup_voice (int dev, int voice, int chn) +static void opl3_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; - opl3_set_instr (dev, voice, - info->pgm_num); + opl3_set_instr(dev, voice, info->pgm_num); - devc->voc[voice].bender = 0; - devc->voc[voice].bender_range = info->bender_range; - devc->voc[voice].volume = - info->controllers[CTL_MAIN_VOLUME]; - devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; + devc->voc[voice].bender = 0; + devc->voc[voice].bender_range = info->bender_range; + devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; + devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; } static struct synth_operations opl3_operations = { - "OPL", - NULL, - 0, - SYNTH_TYPE_FM, - FM_TYPE_ADLIB, - opl3_open, - opl3_close, - opl3_ioctl, - opl3_kill_note, - opl3_start_note, - opl3_set_instr, - opl3_reset, - opl3_hw_control, - opl3_load_patch, - opl3_aftertouch, - opl3_controller, - opl3_panning, - opl3_volume_method, - opl3_bender, - opl3_alloc_voice, - opl3_setup_voice + "OPL", + NULL, + 0, + SYNTH_TYPE_FM, + FM_TYPE_ADLIB, + opl3_open, + opl3_close, + opl3_ioctl, + opl3_kill_note, + opl3_start_note, + opl3_set_instr, + opl3_reset, + opl3_hw_control, + opl3_load_patch, + opl3_aftertouch, + opl3_controller, + opl3_panning, + opl3_volume_method, + opl3_bender, + opl3_alloc_voice, + opl3_setup_voice }; -void -opl3_init (int ioaddr, int *osp) +int opl3_init(int ioaddr, int *osp) { - int i; + int i; + int me; + + if (devc == NULL) + { + printk(KERN_ERR "opl3_init: Device control structure not initialized.\n"); + return -1; + } + + if ((me = sound_alloc_synthdev()) == -1) + { + printk(KERN_WARNING "opl3: Too many synthesizers\n"); + return -1; + } + + memset((char *) devc, 0x00, sizeof(*devc)); + devc->osp = osp; + devc->base = ioaddr; + + devc->nr_voice = 9; + strcpy(devc->fm_info.name, "OPL2"); + + devc->fm_info.device = 0; + devc->fm_info.synth_type = SYNTH_TYPE_FM; + devc->fm_info.synth_subtype = FM_TYPE_ADLIB; + devc->fm_info.perc_mode = 0; + devc->fm_info.nr_voices = 9; + devc->fm_info.nr_drums = 0; + devc->fm_info.instr_bank_size = SBFM_MAXINSTR; + devc->fm_info.capabilities = 0; + devc->left_io = ioaddr; + devc->right_io = ioaddr + 2; + + if (detected_model <= 2) + devc->model = 1; + else + { + devc->model = 2; + if (detected_model == 4) + devc->is_opl4 = 1; + } + + opl3_operations.info = &devc->fm_info; + + synth_devs[me] = &opl3_operations; + sequencer_init(); + devc->v_alloc = &opl3_operations.alloc; + devc->chn_info = &opl3_operations.chn_info[0]; - if (num_synths >= MAX_SYNTH_DEV) - { - printk ("OPL3 Error: Too many synthesizers\n"); - return; - } - - if (devc == NULL) - { - printk ("OPL3: Device control structure not initialized.\n"); - return; - } - - memset ((char *) devc, 0x00, sizeof (*devc)); - devc->osp = osp; - devc->base = ioaddr; - - devc->nr_voice = 9; - strcpy (devc->fm_info.name, "OPL2"); - - devc->fm_info.device = 0; - devc->fm_info.synth_type = SYNTH_TYPE_FM; - devc->fm_info.synth_subtype = FM_TYPE_ADLIB; - devc->fm_info.perc_mode = 0; - devc->fm_info.nr_voices = 9; - devc->fm_info.nr_drums = 0; - devc->fm_info.instr_bank_size = SBFM_MAXINSTR; - devc->fm_info.capabilities = 0; - devc->left_io = ioaddr; - devc->right_io = ioaddr + 2; - - if (detected_model <= 2) - devc->model = 1; - else - { - devc->model = 2; - if (detected_model == 4) - devc->is_opl4 = 1; - } - - opl3_operations.info = &devc->fm_info; - - synth_devs[num_synths++] = &opl3_operations; - sequencer_init (); - devc->v_alloc = &opl3_operations.alloc; - devc->chn_info = &opl3_operations.chn_info[0]; - - if (devc->model == 2) - { - if (devc->is_opl4) - conf_printf2 ("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); - else - conf_printf2 ("Yamaha OPL3 FM", ioaddr, 0, -1, -1); - - devc->v_alloc->max_voice = devc->nr_voice = 18; - devc->fm_info.nr_drums = 0; - devc->fm_info.synth_subtype = FM_TYPE_OPL3; - devc->fm_info.capabilities |= SYNTH_CAP_OPL3; - strcpy (devc->fm_info.name, "Yamaha OPL-3"); - - for (i = 0; i < 18; i++) - if (pv_map[i].ioaddr == USE_LEFT) - pv_map[i].ioaddr = devc->left_io; + if (devc->model == 2) + { + if (devc->is_opl4) + conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); + else + conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1); + + devc->v_alloc->max_voice = devc->nr_voice = 18; + devc->fm_info.nr_drums = 0; + devc->fm_info.synth_subtype = FM_TYPE_OPL3; + devc->fm_info.capabilities |= SYNTH_CAP_OPL3; + strcpy(devc->fm_info.name, "Yamaha OPL-3"); + + for (i = 0; i < 18; i++) + { + if (pv_map[i].ioaddr == USE_LEFT) + pv_map[i].ioaddr = devc->left_io; + else + pv_map[i].ioaddr = devc->right_io; + } + opl3_command(devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE); + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x00); + } else - pv_map[i].ioaddr = devc->right_io; + { + conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1); + devc->v_alloc->max_voice = devc->nr_voice = 9; + devc->fm_info.nr_drums = 0; - opl3_command (devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE); - opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, 0x00); - } - else - { - conf_printf2 ("Yamaha OPL2 FM", ioaddr, 0, -1, -1); - devc->v_alloc->max_voice = devc->nr_voice = 9; - devc->fm_info.nr_drums = 0; - - for (i = 0; i < 18; i++) - pv_map[i].ioaddr = devc->left_io; - }; + for (i = 0; i < 18; i++) + pv_map[i].ioaddr = devc->left_io; + }; - for (i = 0; i < SBFM_MAXINSTR; i++) - devc->i_map[i].channel = -1; + for (i = 0; i < SBFM_MAXINSTR; i++) + devc->i_map[i].channel = -1; + return me; } +#ifdef MODULE + +/* + * We provide OPL3 functions. + */ + +int io = -1; +int me; + +int init_module (void) +{ + printk("YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); + if (io != -1) /* User loading pure OPL3 module */ + { + if (!opl3_detect(io, NULL)) + { + return -ENODEV; + } + me = opl3_init(io, NULL); + } + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + if (devc) + { + vfree(devc); + devc = NULL; + sound_unload_synthdev(me); + } + SOUND_LOCK_END; +} + +#else + #endif +#endif + +EXPORT_SYMBOL(opl3_init); +EXPORT_SYMBOL(opl3_detect); +MODULE_PARM(io, "i"); diff -u --recursive --new-file v2.1.66/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c --- v2.1.66/linux/drivers/sound/opl3sa.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/opl3sa.c Sat Nov 29 10:33:21 1997 @@ -30,69 +30,66 @@ static int *opl3sa_osp = NULL; static unsigned char -opl3sa_read (int addr) +opl3sa_read(int addr) { - unsigned long flags; - unsigned char tmp; + unsigned long flags; + unsigned char tmp; - save_flags (flags); - cli (); - outb ((0x1d), 0xf86); /* password */ - outb (((unsigned char) addr), 0xf86); /* address */ - tmp = inb (0xf87); /* data */ - restore_flags (flags); + save_flags(flags); + cli(); + outb((0x1d), 0xf86); /* password */ + outb(((unsigned char) addr), 0xf86); /* address */ + tmp = inb(0xf87); /* data */ + restore_flags(flags); - return tmp; + return tmp; } static void -opl3sa_write (int addr, int data) +opl3sa_write(int addr, int data) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - outb ((0x1d), 0xf86); /* password */ - outb (((unsigned char) addr), 0xf86); /* address */ - outb (((unsigned char) data), 0xf87); /* data */ - restore_flags (flags); + save_flags(flags); + cli(); + outb((0x1d), 0xf86); /* password */ + outb(((unsigned char) addr), 0xf86); /* address */ + outb(((unsigned char) data), 0xf87); /* data */ + restore_flags(flags); } static int -opl3sa_detect (void) +opl3sa_detect(void) { - int tmp; - - if (((tmp = opl3sa_read (0x01)) & 0xc4) != 0x04) - { - DDB (printk ("OPL3-SA detect error 1 (%x)\n", opl3sa_read (0x01))); - /* return 0; */ - } + int tmp; + if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04) + { + DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01))); + /* return 0; */ + } /* * Check that the password feature has any effect */ - if (inb (0xf87) == tmp) - { - DDB (printk ("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb (0xf87))); - return 0; - } - - tmp = (opl3sa_read (0x04) & 0xe0) >> 5; - - if (tmp != 0 && tmp != 1) - { - DDB (printk ("OPL3-SA detect failed 3 (%d)\n", tmp)); - return 0; - } - - DDB (printk ("OPL3-SA mode %x detected\n", tmp)); - - opl3sa_write (0x01, 0x00); /* Disable MSS */ - opl3sa_write (0x02, 0x00); /* Disable SB */ - opl3sa_write (0x03, 0x00); /* Disable MPU */ + if (inb(0xf87) == tmp) + { + DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87))); + return 0; + } + tmp = (opl3sa_read(0x04) & 0xe0) >> 5; + + if (tmp != 0 && tmp != 1) + { + DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp)); + return 0; + } + DDB(printk("OPL3-SA mode %x detected\n", tmp)); + + opl3sa_write(0x01, 0x00); /* Disable MSS */ + opl3sa_write(0x02, 0x00); /* Disable SB */ + opl3sa_write(0x03, 0x00); /* Disable MPU */ - return 1; + return 1; } /* @@ -101,184 +98,177 @@ */ int -probe_opl3sa_wss (struct address_info *hw_config) +probe_opl3sa_wss(struct address_info *hw_config) { - int ret; - unsigned char tmp = 0x24; /* WSS enable */ + int ret; + unsigned char tmp = 0x24; /* WSS enable */ - if (check_region (0xf86, 2)) /* Control port is busy */ - return 0; - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (OPL3-SA for example) - * return 0x00. - */ - if (check_region (hw_config->io_base, 8)) - { - printk ("OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - opl3sa_osp = hw_config->osp; - - if (!opl3sa_detect ()) - { - printk ("OSS: OPL3-SA chip not found\n"); - return 0; - } - - switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0xe80: - tmp |= 0x08; - break; - case 0xf40: - tmp |= 0x10; - break; - case 0x604: - tmp |= 0x18; - break; - default: - printk ("OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); - return 0; - } - - opl3sa_write (0x01, tmp); /* WSS setup register */ - kilroy_was_here = 1; - - ret = probe_ms_sound (hw_config); - if (ret) - request_region (0xf86, 2, "OPL3-SA"); + if (check_region(0xf86, 2)) /* Control port is busy */ + return 0; + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (OPL3-SA for example) + * return 0x00. + */ + if (check_region(hw_config->io_base, 8)) + { + printk("OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + opl3sa_osp = hw_config->osp; + + if (!opl3sa_detect()) + { + printk("OSS: OPL3-SA chip not found\n"); + return 0; + } + switch (hw_config->io_base) + { + case 0x530: + tmp |= 0x00; + break; + case 0xe80: + tmp |= 0x08; + break; + case 0xf40: + tmp |= 0x10; + break; + case 0x604: + tmp |= 0x18; + break; + default: + printk("OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); + return 0; + } + + opl3sa_write(0x01, tmp); /* WSS setup register */ + kilroy_was_here = 1; + + ret = probe_ms_sound(hw_config); + if (ret) + request_region(0xf86, 2, "OPL3-SA"); - return ret; + return ret; } void -attach_opl3sa_wss (struct address_info *hw_config) +attach_opl3sa_wss(struct address_info *hw_config) { - int nm = num_mixers; + int nm = num_mixers; - attach_ms_sound (hw_config); - if (num_mixers > nm) /* A mixer was installed */ - { - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE); - } + attach_ms_sound(hw_config); + if (num_mixers > nm) /* A mixer was installed */ + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } } void -attach_opl3sa_mpu (struct address_info *hw_config) +attach_opl3sa_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - hw_config->name = "OPL3-SA (MPU401)"; - attach_uart401 (hw_config); + hw_config->name = "OPL3-SA (MPU401)"; + attach_uart401(hw_config); #endif } int -probe_opl3sa_mpu (struct address_info *hw_config) +probe_opl3sa_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unsigned char conf; - static char irq_bits[] = - {-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4}; - - if (!kilroy_was_here) - { - return 0; /* OPL3-SA has not been detected earlier */ - } - - if (mpu_initialized) - { - DDB (printk ("OPL3-SA: MPU mode already initialized\n")); - return 0; - } - - if (check_region (hw_config->io_base, 4)) - { - printk ("OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if (hw_config->irq > 10) - { - printk ("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - - if (irq_bits[hw_config->irq] == -1) - { - printk ("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - - switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x332: - conf = 0x20; - break; - case 0x334: - conf = 0x40; - break; - case 0x300: - conf = 0x60; - break; - default: - return 0; /* Invalid port */ - } + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4}; + + if (!kilroy_was_here) + { + return 0; /* OPL3-SA has not been detected earlier */ + } + if (mpu_initialized) + { + DDB(printk("OPL3-SA: MPU mode already initialized\n")); + return 0; + } + if (check_region(hw_config->io_base, 4)) + { + printk("OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + if (hw_config->irq > 10) + { + printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + if (irq_bits[hw_config->irq] == -1) + { + printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x332: + conf = 0x20; + break; + case 0x334: + conf = 0x40; + break; + case 0x300: + conf = 0x60; + break; + default: + return 0; /* Invalid port */ + } - conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */ - conf |= irq_bits[hw_config->irq] << 2; + conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */ + conf |= irq_bits[hw_config->irq] << 2; - opl3sa_write (0x03, conf); + opl3sa_write(0x03, conf); - mpu_initialized = 1; + mpu_initialized = 1; - return probe_uart401 (hw_config); + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } void -unload_opl3sa_wss (struct address_info *hw_config) +unload_opl3sa_wss(struct address_info *hw_config) { - int dma2 = hw_config->dma2; + int dma2 = hw_config->dma2; - if (dma2 == -1) - dma2 = hw_config->dma; + if (dma2 == -1) + dma2 = hw_config->dma; - release_region (0xf86, 2); - release_region (hw_config->io_base, 4); + release_region(0xf86, 2); + release_region(hw_config->io_base, 4); - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - dma2, - 0); + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + dma2, + 0); } void -unload_opl3sa_mpu (struct address_info *hw_config) +unload_opl3sa_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unload_uart401 (hw_config); + unload_uart401(hw_config); #endif } #ifdef SB_OK void -unload_opl3sa_sb (struct address_info *hw_config) +unload_opl3sa_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP - sb_dsp_unload (hw_config); + sb_dsp_unload(hw_config); #endif } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.1.66/linux/drivers/sound/pas2_card.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/pas2_card.c Sat Nov 29 10:33:21 1997 @@ -5,9 +5,11 @@ */ #include +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_PAS +#if defined(CONFIG_PAS) || defined(MODULE) static unsigned char dma_bits[] = {4, 1, 2, 3, 0, 5, 6, 7}; @@ -38,308 +40,359 @@ * These routines perform the I/O address translation required * to support other than the default base address */ -extern void mix_write (unsigned char data, int ioaddr); +extern void mix_write(unsigned char data, int ioaddr); unsigned char -pas_read (int ioaddr) +pas_read(int ioaddr) { - return inb (ioaddr ^ translate_code); + return inb(ioaddr ^ translate_code); } void -pas_write (unsigned char data, int ioaddr) +pas_write(unsigned char data, int ioaddr) { - outb ((data), ioaddr ^ translate_code); + outb((data), ioaddr ^ translate_code); } /******************* Begin of the Interrupt Handler ********************/ static void -pasintr (int irq, void *dev_id, struct pt_regs *dummy) +pasintr(int irq, void *dev_id, struct pt_regs *dummy) { - int status; + int status; - status = pas_read (0x0B89); - pas_write (status, 0x0B89); /* Clear interrupt */ + status = pas_read(0x0B89); + pas_write(status, 0x0B89); /* Clear interrupt */ - if (status & 0x08) - { + if (status & 0x08) + { #ifdef CONFIG_AUDIO - pas_pcm_interrupt (status, 1); + pas_pcm_interrupt(status, 1); #endif - status &= ~0x08; - } - if (status & 0x10) - { -#ifdef CONFIG_MIDI - pas_midi_interrupt (); + status &= ~0x08; + } + if (status & 0x10) + { +#if defined(CONFIG_MIDI) + pas_midi_interrupt(); #endif - status &= ~0x10; - } + status &= ~0x10; + } } int -pas_set_intr (int mask) +pas_set_intr(int mask) { - if (!mask) - return 0; + if (!mask) + return 0; - pas_intr_mask |= mask; + pas_intr_mask |= mask; - pas_write (pas_intr_mask, 0x0B8B); - return 0; + pas_write(pas_intr_mask, 0x0B8B); + return 0; } int -pas_remove_intr (int mask) +pas_remove_intr(int mask) { - if (!mask) - return 0; + if (!mask) + return 0; - pas_intr_mask &= ~mask; - pas_write (pas_intr_mask, 0x0B8B); + pas_intr_mask &= ~mask; + pas_write(pas_intr_mask, 0x0B8B); - return 0; + return 0; } /******************* End of the Interrupt handler **********************/ /******************* Begin of the Initialization Code ******************/ +extern struct address_info sbhw_config; + static int -config_pas_hw (struct address_info *hw_config) +config_pas_hw(struct address_info *hw_config) { - char ok = 1; - unsigned int_ptrs; /* scsi/sound interrupt pointers */ + char ok = 1; + unsigned int_ptrs; /* scsi/sound interrupt pointers */ - pas_irq = hw_config->irq; + pas_irq = hw_config->irq; - pas_write (0x00, 0x0B8B); - pas_write (0x36, 0x138B); - pas_write (0x36, 0x1388); - pas_write (0, 0x1388); - pas_write (0x74, 0x138B); - pas_write (0x74, 0x1389); - pas_write (0, 0x1389); - - pas_write (0x80 | 0x40 | 0x20 | 1, 0x0B8A); - pas_write (0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); - pas_write (0x01 | 0x02 | 0x04 | 0x10 /* - * | - * 0x80 - */ , 0xB88); + pas_write(0x00, 0x0B8B); + pas_write(0x36, 0x138B); + pas_write(0x36, 0x1388); + pas_write(0, 0x1388); + pas_write(0x74, 0x138B); + pas_write(0x74, 0x1389); + pas_write(0, 0x1389); + + pas_write(0x80 | 0x40 | 0x20 | 1, 0x0B8A); + pas_write(0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); + pas_write(0x01 | 0x02 | 0x04 | 0x10 /* + * | + * 0x80 + */ , 0xB88); - pas_write (0x80 + pas_write(0x80 #ifdef PAS_JOYSTICK_ENABLE - | 0x40 + | 0x40 #endif - ,0xF388); + ,0xF388); - if (pas_irq < 0 || pas_irq > 15) - { - printk ("PAS16: Invalid IRQ %d", pas_irq); - ok = 0; - } - else - { - int_ptrs = pas_read (0xF38A); - int_ptrs |= irq_bits[pas_irq] & 0xf; - pas_write (int_ptrs, 0xF38A); - if (!irq_bits[pas_irq]) - { - printk ("PAS16: Invalid IRQ %d", pas_irq); - ok = 0; - } - else - { - if (snd_set_irq_handler (pas_irq, pasintr, "PAS16", hw_config->osp) < 0) - ok = 0; - } - } + if (pas_irq < 0 || pas_irq > 15) + { + printk("PAS16: Invalid IRQ %d", pas_irq); + ok = 0; + } else + { + int_ptrs = pas_read(0xF38A); + int_ptrs |= irq_bits[pas_irq] & 0xf; + pas_write(int_ptrs, 0xF38A); + if (!irq_bits[pas_irq]) + { + printk("PAS16: Invalid IRQ %d", pas_irq); + ok = 0; + } else + { + if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0) + ok = 0; + } + } + + if (hw_config->dma < 0 || hw_config->dma > 7) + { + printk("PAS16: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } else + { + pas_write(dma_bits[hw_config->dma], 0xF389); + if (!dma_bits[hw_config->dma]) + { + printk("PAS16: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } else + { + if (sound_alloc_dma(hw_config->dma, "PAS16")) + { + printk("pas2_card.c: Can't allocate DMA channel\n"); + ok = 0; + } + } + } - if (hw_config->dma < 0 || hw_config->dma > 7) - { - printk ("PAS16: Invalid DMA selection %d", hw_config->dma); - ok = 0; - } - else - { - pas_write (dma_bits[hw_config->dma], 0xF389); - if (!dma_bits[hw_config->dma]) - { - printk ("PAS16: Invalid DMA selection %d", hw_config->dma); - ok = 0; - } - else - { - if (sound_alloc_dma (hw_config->dma, "PAS16")) - { - printk ("pas2_card.c: Can't allocate DMA channel\n"); - ok = 0; - } - } - } - - /* - * This fixes the timing problems of the PAS due to the Symphony chipset - * as per Media Vision. Only define this if your PAS doesn't work correctly. - */ + /* + * This fixes the timing problems of the PAS due to the Symphony chipset + * as per Media Vision. Only define this if your PAS doesn't work correctly. + */ #ifdef SYMPHONY_PAS - outb ((0x05), 0xa8); - outb ((0x60), 0xa9); + outb((0x05), 0xa8); + outb((0x60), 0xa9); #endif #ifdef BROKEN_BUS_CLOCK - pas_write (0x01 | 0x10 | 0x20 | 0x04, 0x8388); + pas_write(0x01 | 0x10 | 0x20 | 0x04, 0x8388); #else - /* - * pas_write(0x01, 0x8388); - */ - pas_write (0x01 | 0x10 | 0x20, 0x8388); -#endif - pas_write (0x18, 0x838A); /* ??? */ - pas_write (0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ - pas_write (8, 0xBF8A); - - mix_write (0x80 | 5, 0x078B); - mix_write (5, 0x078B); - -#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) - - { - struct address_info *sb_config; - - if ((sb_config = sound_getconf (SNDCARD_SB))) - { - unsigned char irq_dma; - /* - * Turn on Sound Blaster compatibility - * bit 1 = SB emulation - * bit 0 = MPU401 emulation (CDPC only :-( ) + * pas_write(0x01, 0x8388); */ - pas_write (0x02, 0xF788); + pas_write(0x01 | 0x10 | 0x20, 0x8388); +#endif + pas_write(0x18, 0x838A); /* ??? */ + pas_write(0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ + pas_write(8, 0xBF8A); - /* - * "Emulation address" - */ - pas_write ((sb_config->io_base >> 4) & 0x0f, 0xF789); - pas_sb_base = sb_config->io_base; + mix_write(0x80 | 5, 0x078B); + mix_write(5, 0x078B); - if (!sb_dma_bits[sb_config->dma]) - printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); +#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) - if (!sb_irq_bits[sb_config->irq]) - printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); + { + struct address_info *sb_config; - irq_dma = sb_dma_bits[sb_config->dma] | - sb_irq_bits[sb_config->irq]; - - pas_write (irq_dma, 0xFB8A); - } - else - pas_write (0x00, 0xF788); - } +#ifndef MODULE + if ((sb_config = sound_getconf(SNDCARD_SB))) #else - pas_write (0x00, 0xF788); + sb_config = &sbhw_config; + if (sb_config->io_base) #endif + { + unsigned char irq_dma; - if (!ok) - printk ("PAS16: Driver not enabled\n"); + /* + * Turn on Sound Blaster compatibility + * bit 1 = SB emulation + * bit 0 = MPU401 emulation (CDPC only :-( ) + */ + pas_write(0x02, 0xF788); + + /* + * "Emulation address" + */ + pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); + pas_sb_base = sb_config->io_base; + + if (!sb_dma_bits[sb_config->dma]) + printk("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); + + if (!sb_irq_bits[sb_config->irq]) + printk("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); + + irq_dma = sb_dma_bits[sb_config->dma] | + sb_irq_bits[sb_config->irq]; + + pas_write(irq_dma, 0xFB8A); + } else + pas_write(0x00, 0xF788); + } +#else + pas_write(0x00, 0xF788); +#endif - return ok; + if (!ok) + printk("PAS16: Driver not enabled\n"); + + return ok; } static int -detect_pas_hw (struct address_info *hw_config) +detect_pas_hw(struct address_info *hw_config) { - unsigned char board_id, foo; + unsigned char board_id, foo; - /* - * WARNING: Setting an option like W:1 or so that disables warm boot reset - * of the card will screw up this detect code something fierce. Adding code - * to handle this means possibly interfering with other cards on the bus if - * you have something on base port 0x388. SO be forewarned. - */ + /* + * WARNING: Setting an option like W:1 or so that disables warm boot reset + * of the card will screw up this detect code something fierce. Adding code + * to handle this means possibly interfering with other cards on the bus if + * you have something on base port 0x388. SO be forewarned. + */ - outb ((0xBC), 0x9A01); /* Activate first board */ - outb ((hw_config->io_base >> 2), 0x9A01); /* Set base address */ - translate_code = 0x388 ^ hw_config->io_base; - pas_write (1, 0xBF88); /* Select one wait states */ + outb((0xBC), 0x9A01); /* Activate first board */ + outb((hw_config->io_base >> 2), 0x9A01); /* Set base address */ + translate_code = 0x388 ^ hw_config->io_base; + pas_write(1, 0xBF88); /* Select one wait states */ - board_id = pas_read (0x0B8B); + board_id = pas_read(0x0B8B); - if (board_id == 0xff) - return 0; + if (board_id == 0xff) + return 0; - /* - * We probably have a PAS-series board, now check for a PAS16-series board - * by trying to change the board revision bits. PAS16-series hardware won't - * let you do this - the bits are read-only. - */ + /* + * We probably have a PAS-series board, now check for a PAS16-series board + * by trying to change the board revision bits. PAS16-series hardware won't + * let you do this - the bits are read-only. + */ - foo = board_id ^ 0xe0; + foo = board_id ^ 0xe0; - pas_write (foo, 0x0B8B); - foo = pas_read (0x0B8B); - pas_write (board_id, 0x0B8B); + pas_write(foo, 0x0B8B); + foo = pas_read(0x0B8B); + pas_write(board_id, 0x0B8B); - if (board_id != foo) - return 0; + if (board_id != foo) + return 0; - pas_model = pas_read (0xFF88); + pas_model = pas_read(0xFF88); - return pas_model; + return pas_model; } void -attach_pas_card (struct address_info *hw_config) +attach_pas_card(struct address_info *hw_config) { - pas_irq = hw_config->irq; + pas_irq = hw_config->irq; - if (detect_pas_hw (hw_config)) - { + if (detect_pas_hw(hw_config)) + { - if ((pas_model = pas_read (0xFF88))) - { - char temp[100]; - - sprintf (temp, - "%s rev %d", pas_model_names[(int) pas_model], - pas_read (0x2789)); - conf_printf (temp, hw_config); - } - - if (config_pas_hw (hw_config)) - { + if ((pas_model = pas_read(0xFF88))) + { + char temp[100]; + + sprintf(temp, + "%s rev %d", pas_model_names[(int) pas_model], + pas_read(0x2789)); + conf_printf(temp, hw_config); + } + if (config_pas_hw(hw_config)) + { #ifdef CONFIG_AUDIO - pas_pcm_init (hw_config); + pas_pcm_init(hw_config); #endif -#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) +#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) - sb_dsp_disable_midi (pas_sb_base); /* No MIDI capability */ + sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif -#ifdef CONFIG_MIDI - pas_midi_init (); +#if defined(CONFIG_MIDI) + pas_midi_init(); #endif - pas_init_mixer (); - } - } + pas_init_mixer(); + } + } } int -probe_pas (struct address_info *hw_config) +probe_pas(struct address_info *hw_config) { - return detect_pas_hw (hw_config); + return detect_pas_hw(hw_config); } void -unload_pas (struct address_info *hw_config) +unload_pas(struct address_info *hw_config) { - sound_free_dma (hw_config->dma); - snd_release_irq (hw_config->irq); + sound_free_dma(hw_config->dma); + snd_release_irq(hw_config->irq); } +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ + +int sb_io = 0; +int sb_irq = -1; +int sb_dma = -1; +int sb_dma16 = -1; + +struct address_info config; +struct address_info sbhw_config; + +int init_module(void) +{ + printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + + sbhw_config.io_base = sb_io; + sbhw_config.irq = sb_irq; + sbhw_config.dma = sb_dma; + sbhw_config.dma2 = sb_dma16; + + if (!probe_pas(&config)) + return -ENODEV; + attach_pas_card(&config); + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + unload_pas(&config); + SOUND_LOCK_END; +} + + +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v2.1.66/linux/drivers/sound/pas2_midi.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/pas2_midi.c Sat Nov 29 10:33:21 1997 @@ -15,8 +15,7 @@ #include "sound_config.h" -#ifdef CONFIG_PAS -#ifdef CONFIG_MIDI +#if ( defined(MODULE) || defined(CONFIG_PAS) ) && defined(CONFIG_MIDI) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -28,90 +27,86 @@ static void (*midi_input_intr) (int dev, unsigned char data); static int -pas_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +pas_midi_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - int err; - unsigned long flags; - unsigned char ctrl; - - - if (midi_busy) - { - printk ("PAS16: Midi busy\n"); - return -EBUSY; - } - - /* - * Reset input and output FIFO pointers - */ - pas_write (0x20 | 0x40, - 0x178b); - - save_flags (flags); - cli (); - - if ((err = pas_set_intr (0x10)) < 0) - { - restore_flags (flags); - return err; - } - - /* - * Enable input available and output FIFO empty interrupts - */ - - ctrl = 0; - input_opened = 0; - midi_input_intr = input; - - if (mode == OPEN_READ || mode == OPEN_READWRITE) - { - ctrl |= 0x04; /* Enable input */ - input_opened = 1; - } - - if (mode == OPEN_WRITE || mode == OPEN_READWRITE) - { - ctrl |= 0x08 | 0x10; /* Enable output */ - } - - pas_write (ctrl, 0x178b); - - /* - * Acknowledge any pending interrupts - */ - - pas_write (0xff, 0x1B88); - - restore_flags (flags); - - midi_busy = 1; - qlen = qhead = qtail = 0; - return 0; + int err; + unsigned long flags; + unsigned char ctrl; + + + if (midi_busy) + { + printk("PAS16: Midi busy\n"); + return -EBUSY; + } + /* + * Reset input and output FIFO pointers + */ + pas_write(0x20 | 0x40, + 0x178b); + + save_flags(flags); + cli(); + + if ((err = pas_set_intr(0x10)) < 0) + { + restore_flags(flags); + return err; + } + /* + * Enable input available and output FIFO empty interrupts + */ + + ctrl = 0; + input_opened = 0; + midi_input_intr = input; + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + { + ctrl |= 0x04; /* Enable input */ + input_opened = 1; + } + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + { + ctrl |= 0x08 | 0x10; /* Enable output */ + } + pas_write(ctrl, 0x178b); + + /* + * Acknowledge any pending interrupts + */ + + pas_write(0xff, 0x1B88); + + restore_flags(flags); + + midi_busy = 1; + qlen = qhead = qtail = 0; + return 0; } static void -pas_midi_close (int dev) +pas_midi_close(int dev) { - /* - * Reset FIFO pointers, disable intrs - */ - pas_write (0x20 | 0x40, 0x178b); + /* + * Reset FIFO pointers, disable intrs + */ + pas_write(0x20 | 0x40, 0x178b); - pas_remove_intr (0x10); - midi_busy = 0; + pas_remove_intr(0x10); + midi_busy = 0; } static int -dump_to_midi (unsigned char midi_byte) +dump_to_midi(unsigned char midi_byte) { - int fifo_space, x; + int fifo_space, x; - fifo_space = ((x = pas_read (0x1B89)) >> 4) & 0x0f; + fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f; /* * The MIDI FIFO space register and it's documentation is nonunderstandable. @@ -121,91 +116,90 @@ * means that the buffer is empty. */ - if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */ - { - return 0; /* Ask upper layers to retry after some time */ - } - - pas_write (midi_byte, 0x178A); + if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */ + { + return 0; /* Ask upper layers to retry after some time */ + } + pas_write(midi_byte, 0x178A); - return 1; + return 1; } static int -pas_midi_out (int dev, unsigned char midi_byte) +pas_midi_out(int dev, unsigned char midi_byte) { - unsigned long flags; + unsigned long flags; - /* - * Drain the local queue first - */ + /* + * Drain the local queue first + */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } - restore_flags (flags); + restore_flags(flags); - /* - * Output the byte if the local queue is empty. - */ + /* + * Output the byte if the local queue is empty. + */ - if (!qlen) - if (dump_to_midi (midi_byte)) - return 1; + if (!qlen) + if (dump_to_midi(midi_byte)) + return 1; - /* - * Put to the local queue - */ + /* + * Put to the local queue + */ - if (qlen >= 256) - return 0; /* Local queue full */ + if (qlen >= 256) + return 0; /* Local queue full */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - tmp_queue[qtail] = midi_byte; - qlen++; - qtail++; + tmp_queue[qtail] = midi_byte; + qlen++; + qtail++; - restore_flags (flags); + restore_flags(flags); - return 1; + return 1; } static int -pas_midi_start_read (int dev) +pas_midi_start_read(int dev) { - return 0; + return 0; } static int -pas_midi_end_read (int dev) +pas_midi_end_read(int dev) { - return 0; + return 0; } static int -pas_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +pas_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -pas_midi_kick (int dev) +pas_midi_kick(int dev) { } static int -pas_buffer_status (int dev) +pas_buffer_status(int dev) { - return qlen; + return qlen; } #define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi" @@ -214,81 +208,76 @@ static struct midi_operations pas_midi_operations = { - {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, - &std_midi_synth, - {0}, - pas_midi_open, - pas_midi_close, - pas_midi_ioctl, - pas_midi_out, - pas_midi_start_read, - pas_midi_end_read, - pas_midi_kick, - NULL, - pas_buffer_status, - NULL + {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, + &std_midi_synth, + {0}, + pas_midi_open, + pas_midi_close, + pas_midi_ioctl, + pas_midi_out, + pas_midi_start_read, + pas_midi_end_read, + pas_midi_kick, + NULL, + pas_buffer_status, + NULL }; void -pas_midi_init (void) +pas_midi_init(void) { - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &pas_midi_operations; - sequencer_init (); + int dev = sound_alloc_mididev(); + + if (dev == -1) + { + printk(KERN_WARNING "pas_midi_init: Too many midi devices detected\n"); + return; + } + std_midi_synth.midi_dev = my_dev = dev; + midi_devs[dev] = &pas_midi_operations; + sequencer_init(); } void -pas_midi_interrupt (void) +pas_midi_interrupt(void) { - unsigned char stat; - int i, incount; - unsigned long flags; - - stat = pas_read (0x1B88); - - if (stat & 0x04) /* Input data available */ - { - incount = pas_read (0x1B89) & 0x0f; /* Input FIFO size */ - if (!incount) - incount = 16; + unsigned char stat; + int i, incount; + unsigned long flags; + + stat = pas_read(0x1B88); - for (i = 0; i < incount; i++) - if (input_opened) + if (stat & 0x04) /* Input data available */ { - midi_input_intr (my_dev, pas_read (0x178A)); + incount = pas_read(0x1B89) & 0x0f; /* Input FIFO size */ + if (!incount) + incount = 16; + + for (i = 0; i < incount; i++) + if (input_opened) + { + midi_input_intr(my_dev, pas_read(0x178A)); + } else + pas_read(0x178A); /* Flush */ } - else - pas_read (0x178A); /* Flush */ - } - - if (stat & (0x08 | 0x10)) - { - save_flags (flags); - cli (); - - while (qlen && dump_to_midi (tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - restore_flags (flags); - } - + if (stat & (0x08 | 0x10)) + { + save_flags(flags); + cli(); - if (stat & 0x40) - { - printk ("MIDI output overrun %x,%x\n", pas_read (0x1B89), stat); - } + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } - pas_write (stat, 0x1B88); /* Acknowledge interrupts */ + restore_flags(flags); + } + if (stat & 0x40) + { + printk("MIDI output overrun %x,%x\n", pas_read(0x1B89), stat); + } + pas_write(stat, 0x1B88); /* Acknowledge interrupts */ } -#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.1.66/linux/drivers/sound/pas2_mixer.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/pas2_mixer.c Sat Nov 29 10:33:21 1997 @@ -1,3 +1,4 @@ + /* * sound/pas2_mixer.c * @@ -15,7 +16,7 @@ #include "sound_config.h" -#ifdef CONFIG_PAS +#if defined(CONFIG_PAS) || defined(MODULE) #ifndef DEB #define DEB(what) /* (what) */ @@ -40,325 +41,317 @@ static int default_levels[32] = { - 0x3232, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x5050, /* FM */ - 0x4b4b, /* PCM */ - 0x3232, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x4b4b, /* Mic */ - 0x4b4b, /* CD */ - 0x6464, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x6464 /* Recording level */ + 0x3232, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x5050, /* FM */ + 0x4b4b, /* PCM */ + 0x3232, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x4b4b, /* Mic */ + 0x4b4b, /* CD */ + 0x6464, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x6464 /* Recording level */ }; void -mix_write (unsigned char data, int ioaddr) +mix_write(unsigned char data, int ioaddr) { - /* - * The Revision D cards have a problem with their MVA508 interface. The - * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and - * MSBs out of the output byte and to do a 16-bit out to the mixer port - - * 1. We need to do this because it isn't timing problem but chip access - * sequence problem. - */ - - if (pas_model == 4) - { - outw (data | (data << 8), (ioaddr ^ translate_code) - 1); - outb ((0x80), 0); - } - else - pas_write (data, ioaddr); + /* + * The Revision D cards have a problem with their MVA508 interface. The + * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and + * MSBs out of the output byte and to do a 16-bit out to the mixer port - + * 1. We need to do this because it isn't timing problem but chip access + * sequence problem. + */ + + if (pas_model == 4) + { + outw(data | (data << 8), (ioaddr ^ translate_code) - 1); + outb((0x80), 0); + } else + pas_write(data, ioaddr); } static int -mixer_output (int right_vol, int left_vol, int div, int bits, - int mixer) /* Input or output mixer */ +mixer_output(int right_vol, int left_vol, int div, int bits, + int mixer) /* Input or output mixer */ { - int left = left_vol * div / 100; - int right = right_vol * div / 100; + int left = left_vol * div / 100; + int right = right_vol * div / 100; - if (bits & 0x10) - { - left |= mixer; - right |= mixer; - } - - if (bits == 0x03 || bits == 0x04) - { - mix_write (0x80 | bits, 0x078B); - mix_write (left, 0x078B); - right_vol = left_vol; - } - else - { - mix_write (0x80 | 0x20 | bits, 0x078B); - mix_write (left, 0x078B); - mix_write (0x80 | 0x40 | bits, 0x078B); - mix_write (right, 0x078B); - } + if (bits & 0x10) + { + left |= mixer; + right |= mixer; + } + if (bits == 0x03 || bits == 0x04) + { + mix_write(0x80 | bits, 0x078B); + mix_write(left, 0x078B); + right_vol = left_vol; + } else + { + mix_write(0x80 | 0x20 | bits, 0x078B); + mix_write(left, 0x078B); + mix_write(0x80 | 0x40 | bits, 0x078B); + mix_write(right, 0x078B); + } - return (left_vol | (right_vol << 8)); + return (left_vol | (right_vol << 8)); } static void -set_mode (int new_mode) +set_mode(int new_mode) { - mix_write (0x80 | 0x05, 0x078B); - mix_write (new_mode, 0x078B); + mix_write(0x80 | 0x05, 0x078B); + mix_write(new_mode, 0x078B); - mode_control = new_mode; + mode_control = new_mode; } static int -pas_mixer_set (int whichDev, unsigned int level) +pas_mixer_set(int whichDev, unsigned int level) { - int left, right, devmask, changed, i, mixer = 0; - - DEB (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); - - left = level & 0x7f; - right = (level & 0x7f00) >> 8; - - if (whichDev < SOUND_MIXER_NRDEVICES) - if ((1 << whichDev) & rec_devices) - mixer = 0x20; - else - mixer = 0x00; - - switch (whichDev) - { - case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ - levels[whichDev] = mixer_output (right, left, 63, 0x01, 0); - break; - - /* - * Note! Bass and Treble are mono devices. Will use just the left - * channel. - */ - case SOUND_MIXER_BASS: /* Bass (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, 0x03, 0); - break; - case SOUND_MIXER_TREBLE: /* Treble (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, 0x04, 0); - break; - - case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x00, mixer); - break; - case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x05, mixer); - break; - case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x07, mixer); - break; - case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x06, mixer); - break; - case SOUND_MIXER_LINE: /* External line (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x02, mixer); - break; - case SOUND_MIXER_CD: /* CD (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x03, mixer); - break; - case SOUND_MIXER_MIC: /* External microphone (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x04, mixer); - break; - case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ - levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x01, - 0x00); - break; - case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ - levels[whichDev] = mixer_output (right, left, 15, 0x02, 0); - break; + int left, right, devmask, changed, i, mixer = 0; + DEB(printk("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); - case SOUND_MIXER_RECSRC: - devmask = level & POSSIBLE_RECORDING_DEVICES; + left = level & 0x7f; + right = (level & 0x7f00) >> 8; - changed = devmask ^ rec_devices; - rec_devices = devmask; + if (whichDev < SOUND_MIXER_NRDEVICES) + if ((1 << whichDev) & rec_devices) + mixer = 0x20; + else + mixer = 0x00; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (changed & (1 << i)) + switch (whichDev) { - pas_mixer_set (i, levels[i]); - } - return rec_devices; - break; + case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ + levels[whichDev] = mixer_output(right, left, 63, 0x01, 0); + break; + + /* + * Note! Bass and Treble are mono devices. Will use just the left + * channel. + */ + case SOUND_MIXER_BASS: /* Bass (0-12) */ + levels[whichDev] = mixer_output(right, left, 12, 0x03, 0); + break; + case SOUND_MIXER_TREBLE: /* Treble (0-12) */ + levels[whichDev] = mixer_output(right, left, 12, 0x04, 0); + break; + + case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x00, mixer); + break; + case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x05, mixer); + break; + case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x07, mixer); + break; + case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x06, mixer); + break; + case SOUND_MIXER_LINE: /* External line (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x02, mixer); + break; + case SOUND_MIXER_CD: /* CD (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x03, mixer); + break; + case SOUND_MIXER_MIC: /* External microphone (0-31) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x04, mixer); + break; + case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ + levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x01, + 0x00); + break; + case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ + levels[whichDev] = mixer_output(right, left, 15, 0x02, 0); + break; + + + case SOUND_MIXER_RECSRC: + devmask = level & POSSIBLE_RECORDING_DEVICES; + + changed = devmask ^ rec_devices; + rec_devices = devmask; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (changed & (1 << i)) + { + pas_mixer_set(i, levels[i]); + } + return rec_devices; + break; - default: - return -EINVAL; - } + default: + return -EINVAL; + } - return (levels[whichDev]); + return (levels[whichDev]); } /*****/ static void -pas_mixer_reset (void) +pas_mixer_reset(void) { - int foo; + int foo; - DEB (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); + DEB(printk("pas2_mixer.c: void pas_mixer_reset(void)\n")); - for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) - pas_mixer_set (foo, levels[foo]); + for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) + pas_mixer_set(foo, levels[foo]); - set_mode (0x04 | 0x01); + set_mode(0x04 | 0x01); } static int -pas_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +pas_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - DEB (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + + if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */ + { + int level; + + level = *(int *) arg; + + if (level == -1) /* Return current settings */ + { + if (mode_control & 0x04) + return (*(int *) arg = 1); + else + return (*(int *) arg = 0); + } else + { + mode_control &= ~0x04; + if (level) + mode_control |= 0x04; + set_mode(mode_control); + return (*(int *) arg = !!level); /* 0 or 1 */ + } + } + if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */ + { + int level; + + level = *(int *) arg; + + if (level == -1) /* Return current settings */ + { + if (!(mode_control & 0x03)) + return (*(int *) arg = 0); + return (*(int *) arg = ((mode_control & 0x03) + 1) * 20); + } else + { + int i = 0; + + level &= 0x7f; + if (level) + i = (level / 20) - 1; + + mode_control &= ~0x03; + mode_control |= i & 0x03; + set_mode(mode_control); + + if (i) + i = (i + 1) * 20; - if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */ - { - int level; - - level = *(int *) arg; - - if (level == -1) /* Return current settings */ - { - if (mode_control & 0x04) - return (*(int *) arg = 1); - else - return (*(int *) arg = 0); - } - else - { - mode_control &= ~0x04; - if (level) - mode_control |= 0x04; - set_mode (mode_control); - return (*(int *) arg = !!level); /* 0 or 1 */ - } - } - - - if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */ - { - int level; - - level = *(int *) arg; - - if (level == -1) /* Return current settings */ - { - if (!(mode_control & 0x03)) - return (*(int *) arg = 0); - return (*(int *) arg = ((mode_control & 0x03) + 1) * 20); - } - else - { - int i = 0; - - level &= 0x7f; - if (level) - i = (level / 20) - 1; - - mode_control &= ~0x03; - mode_control |= i & 0x03; - set_mode (mode_control); - - if (i) - i = (i + 1) * 20; - - return i; - } - } - - if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */ - { - int level; - - level = *(int *) arg; - - if (level == -1) /* Return current settings */ - { - return (*(int *) arg = !(pas_read (0x0B8A) & 0x20)); - } - else - { - if (level) - pas_write (pas_read (0x0B8A) & (~0x20), - 0x0B8A); - else - pas_write (pas_read (0x0B8A) | 0x20, - 0x0B8A); - - return !(pas_read (0x0B8A) & 0x20); - } - } - - if (((cmd >> 8) & 0xff) == 'M') - { - int v; - - v = *(int *) arg; - - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - return (*(int *) arg = pas_mixer_set (cmd & 0xff, v)); - else - { - - switch (cmd & 0xff) - { - - case SOUND_MIXER_RECSRC: - return (*(int *) arg = rec_devices); - break; - - case SOUND_MIXER_STEREODEVS: - return (*(int *) arg = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE)); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = SUPPORTED_MIXER_DEVICES); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = 0); /* No special capabilities */ - break; - - - default: - return (*(int *) arg = levels[cmd & 0xff]); - } - } - } - return -EINVAL; + return i; + } + } + if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */ + { + int level; + + level = *(int *) arg; + + if (level == -1) /* Return current settings */ + { + return (*(int *) arg = !(pas_read(0x0B8A) & 0x20)); + } else + { + if (level) + pas_write(pas_read(0x0B8A) & (~0x20), + 0x0B8A); + else + pas_write(pas_read(0x0B8A) | 0x20, + 0x0B8A); + + return !(pas_read(0x0B8A) & 0x20); + } + } + if (((cmd >> 8) & 0xff) == 'M') + { + int v; + + v = *(int *) arg; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + return (*(int *) arg = pas_mixer_set(cmd & 0xff, v)); + else + { + + switch (cmd & 0xff) + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = rec_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return (*(int *) arg = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE)); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = SUPPORTED_MIXER_DEVICES); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = 0); /* No special capabilities */ + break; + + + default: + return (*(int *) arg = levels[cmd & 0xff]); + } + } + } + return -EINVAL; } static struct mixer_operations pas_mixer_operations = { - "PAS16", - "Pro Audio Spectrum 16", - pas_mixer_ioctl + "PAS16", + "Pro Audio Spectrum 16", + pas_mixer_ioctl }; int -pas_init_mixer (void) +pas_init_mixer(void) { - levels = load_mixer_volumes ("PAS16_1", default_levels, 1); + int d; + + levels = load_mixer_volumes("PAS16_1", default_levels, 1); - pas_mixer_reset (); + pas_mixer_reset(); - if (num_mixers < MAX_MIXER_DEV) - { - audio_devs[pas_audiodev]->mixer_dev = num_mixers; - mixer_devs[num_mixers++] = &pas_mixer_operations; - } - return 1; + if ((d = sound_alloc_mixerdev()) != -1) + { + audio_devs[pas_audiodev]->mixer_dev = d; + mixer_devs[d] = &pas_mixer_operations; + } + return 1; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v2.1.66/linux/drivers/sound/pas2_pcm.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/pas2_pcm.c Sat Nov 29 10:33:21 1997 @@ -12,8 +12,7 @@ #include "sound_config.h" -#ifdef CONFIG_PAS -#ifdef CONFIG_AUDIO +#if defined(MODULE) || ( defined(CONFIG_PAS) && defined(CONFIG_AUDIO) ) #ifndef DEB #define DEB(WHAT) @@ -40,425 +39,418 @@ static int open_mode = 0; static int -pcm_set_speed (int arg) +pcm_set_speed(int arg) { - int foo, tmp; - unsigned long flags; + int foo, tmp; + unsigned long flags; - if (arg == 0) - return pcm_speed; + if (arg == 0) + return pcm_speed; - if (arg > 44100) - arg = 44100; - if (arg < 5000) - arg = 5000; - - if (pcm_channels & 2) - { - foo = (596590 + (arg / 2)) / arg; - arg = (596590 + (foo / 2)) / foo; - } - else - { - foo = (1193180 + (arg / 2)) / arg; - arg = (1193180 + (foo / 2)) / foo; - } - - pcm_speed = arg; - - tmp = pas_read (0x0B8A); - - /* - * Set anti-aliasing filters according to sample rate. You really *NEED* - * to enable this feature for all normal recording unless you want to - * experiment with aliasing effects. - * These filters apply to the selected "recording" source. - * I (pfw) don't know the encoding of these 5 bits. The values shown - * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. - * - * I cleared bit 5 of these values, since that bit controls the master - * mute flag. (Olav Wölfelschneider) - * - */ + if (arg > 44100) + arg = 44100; + if (arg < 5000) + arg = 5000; + + if (pcm_channels & 2) + { + foo = (596590 + (arg / 2)) / arg; + arg = (596590 + (foo / 2)) / foo; + } else + { + foo = (1193180 + (arg / 2)) / arg; + arg = (1193180 + (foo / 2)) / foo; + } + + pcm_speed = arg; + + tmp = pas_read(0x0B8A); + + /* + * Set anti-aliasing filters according to sample rate. You really *NEED* + * to enable this feature for all normal recording unless you want to + * experiment with aliasing effects. + * These filters apply to the selected "recording" source. + * I (pfw) don't know the encoding of these 5 bits. The values shown + * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + * + * I cleared bit 5 of these values, since that bit controls the master + * mute flag. (Olav Wölfelschneider) + * + */ #if !defined NO_AUTO_FILTER_SET - tmp &= 0xe0; - if (pcm_speed >= 2 * 17897) - tmp |= 0x01; - else if (pcm_speed >= 2 * 15909) - tmp |= 0x02; - else if (pcm_speed >= 2 * 11931) - tmp |= 0x09; - else if (pcm_speed >= 2 * 8948) - tmp |= 0x11; - else if (pcm_speed >= 2 * 5965) - tmp |= 0x19; - else if (pcm_speed >= 2 * 2982) - tmp |= 0x04; - pcm_filter = tmp; + tmp &= 0xe0; + if (pcm_speed >= 2 * 17897) + tmp |= 0x01; + else if (pcm_speed >= 2 * 15909) + tmp |= 0x02; + else if (pcm_speed >= 2 * 11931) + tmp |= 0x09; + else if (pcm_speed >= 2 * 8948) + tmp |= 0x11; + else if (pcm_speed >= 2 * 5965) + tmp |= 0x19; + else if (pcm_speed >= 2 * 2982) + tmp |= 0x04; + pcm_filter = tmp; #endif - save_flags (flags); - cli (); + save_flags(flags); + cli(); - pas_write (tmp & ~(0x40 | 0x80), 0x0B8A); - pas_write (0x00 | 0x30 | 0x04, 0x138B); - pas_write (foo & 0xff, 0x1388); - pas_write ((foo >> 8) & 0xff, 0x1388); - pas_write (tmp, 0x0B8A); + pas_write(tmp & ~(0x40 | 0x80), 0x0B8A); + pas_write(0x00 | 0x30 | 0x04, 0x138B); + pas_write(foo & 0xff, 0x1388); + pas_write((foo >> 8) & 0xff, 0x1388); + pas_write(tmp, 0x0B8A); - restore_flags (flags); + restore_flags(flags); - return pcm_speed; + return pcm_speed; } static int -pcm_set_channels (int arg) +pcm_set_channels(int arg) { - if ((arg != 1) && (arg != 2)) - return pcm_channels; + if ((arg != 1) && (arg != 2)) + return pcm_channels; - if (arg != pcm_channels) - { - pas_write (pas_read (0xF8A) ^ 0x20, 0xF8A); + if (arg != pcm_channels) + { + pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A); - pcm_channels = arg; - pcm_set_speed (pcm_speed); /* The speed must be reinitialized */ - } - - return pcm_channels; + pcm_channels = arg; + pcm_set_speed(pcm_speed); /* The speed must be reinitialized */ + } + return pcm_channels; } static int -pcm_set_bits (int arg) +pcm_set_bits(int arg) { - if (arg == 0) - return pcm_bits; - - if ((arg & pcm_bitsok) != arg) - return pcm_bits; + if (arg == 0) + return pcm_bits; - if (arg != pcm_bits) - { - pas_write (pas_read (0x8389) ^ 0x04, 0x8389); + if ((arg & pcm_bitsok) != arg) + return pcm_bits; - pcm_bits = arg; - } + if (arg != pcm_bits) + { + pas_write(pas_read(0x8389) ^ 0x04, 0x8389); - return pcm_bits; + pcm_bits = arg; + } + return pcm_bits; } static int -pas_audio_ioctl (int dev, unsigned int cmd, caddr_t arg) +pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int val; + int val; - DEB (printk ("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - val = *(int *) arg; - return (*(int *) arg = pcm_set_speed (val)); - break; - - case SOUND_PCM_READ_RATE: - return (*(int *) arg = pcm_speed); - break; - - case SNDCTL_DSP_STEREO: - val = *(int *) arg; - return (*(int *) arg = pcm_set_channels (val + 1) - 1); - break; - - case SOUND_PCM_WRITE_CHANNELS: - val = *(int *) arg; - return (*(int *) arg = pcm_set_channels (val)); - break; - - case SOUND_PCM_READ_CHANNELS: - return (*(int *) arg = pcm_channels); - break; - - case SNDCTL_DSP_SETFMT: - val = *(int *) arg; - return (*(int *) arg = pcm_set_bits (val)); - break; - - case SOUND_PCM_READ_BITS: - return (*(int *) arg = pcm_bits); - - default: - return -EINVAL; - } + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + val = *(int *) arg; + return (*(int *) arg = pcm_set_speed(val)); + break; + + case SOUND_PCM_READ_RATE: + return (*(int *) arg = pcm_speed); + break; + + case SNDCTL_DSP_STEREO: + val = *(int *) arg; + return (*(int *) arg = pcm_set_channels(val + 1) - 1); + break; + + case SOUND_PCM_WRITE_CHANNELS: + val = *(int *) arg; + return (*(int *) arg = pcm_set_channels(val)); + break; + + case SOUND_PCM_READ_CHANNELS: + return (*(int *) arg = pcm_channels); + break; + + case SNDCTL_DSP_SETFMT: + val = *(int *) arg; + return (*(int *) arg = pcm_set_bits(val)); + break; + + case SOUND_PCM_READ_BITS: + return (*(int *) arg = pcm_bits); + + default: + return -EINVAL; + } - return -EINVAL; + return -EINVAL; } static void -pas_audio_reset (int dev) +pas_audio_reset(int dev) { - DEB (printk ("pas2_pcm.c: static void pas_audio_reset(void)\n")); + DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n")); - pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ + pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ } static int -pas_audio_open (int dev, int mode) +pas_audio_open(int dev, int mode) { - int err; - unsigned long flags; - - DEB (printk ("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); + int err; + unsigned long flags; - save_flags (flags); - cli (); - if (pcm_busy) - { - restore_flags (flags); - return -EBUSY; - } + DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); - pcm_busy = 1; - restore_flags (flags); + save_flags(flags); + cli(); + if (pcm_busy) + { + restore_flags(flags); + return -EBUSY; + } + pcm_busy = 1; + restore_flags(flags); - if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0) - return err; + if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) + return err; - pcm_count = 0; - open_mode = mode; + pcm_count = 0; + open_mode = mode; - return 0; + return 0; } static void -pas_audio_close (int dev) +pas_audio_close(int dev) { - unsigned long flags; + unsigned long flags; - DEB (printk ("pas2_pcm.c: static void pas_audio_close(void)\n")); + DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n")); - save_flags (flags); - cli (); + save_flags(flags); + cli(); - pas_audio_reset (dev); - pas_remove_intr (PAS_PCM_INTRBITS); - pcm_mode = PCM_NON; + pas_audio_reset(dev); + pas_remove_intr(PAS_PCM_INTRBITS); + pcm_mode = PCM_NON; - pcm_busy = 0; - restore_flags (flags); + pcm_busy = 0; + restore_flags(flags); } static void -pas_audio_output_block (int dev, unsigned long buf, int count, - int intrflag) +pas_audio_output_block(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags, cnt; + unsigned long flags, cnt; - DEB (printk ("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); + DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; + cnt = count; + if (audio_devs[dev]->dmap_out->dma > 3) + cnt >>= 1; - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; + if (audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == pcm_count) + return; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - pas_write (pas_read (0xF8A) & ~0x40, - 0xF8A); + pas_write(pas_read(0xF8A) & ~0x40, + 0xF8A); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; - if (count != pcm_count) - { - pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); - pas_write (0x40 | 0x30 | 0x04, 0x138B); - pas_write (count & 0xff, 0x1389); - pas_write ((count >> 8) & 0xff, 0x1389); - pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); + if (count != pcm_count) + { + pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); + pas_write(0x40 | 0x30 | 0x04, 0x138B); + pas_write(count & 0xff, 0x1389); + pas_write((count >> 8) & 0xff, 0x1389); + pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); - pcm_count = count; - } - pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); + pcm_count = count; + } + pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); + pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); #endif - pcm_mode = PCM_DAC; + pcm_mode = PCM_DAC; - restore_flags (flags); + restore_flags(flags); } static void -pas_audio_start_input (int dev, unsigned long buf, int count, - int intrflag) +pas_audio_start_input(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags; - int cnt; + unsigned long flags; + int cnt; - DEB (printk ("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); + DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); - cnt = count; - if (audio_devs[dev]->dmap_out->dma > 3) - cnt >>= 1; - - if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && - intrflag && - cnt == pcm_count) - return; - - save_flags (flags); - cli (); - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - - if (count != pcm_count) - { - pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); - pas_write (0x40 | 0x30 | 0x04, 0x138B); - pas_write (count & 0xff, 0x1389); - pas_write ((count >> 8) & 0xff, 0x1389); - pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); - - pcm_count = count; - } - pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); + cnt = count; + if (audio_devs[dev]->dmap_out->dma > 3) + cnt >>= 1; + + if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && + intrflag && + cnt == pcm_count) + return; + + save_flags(flags); + cli(); + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + + if (count != pcm_count) + { + pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); + pas_write(0x40 | 0x30 | 0x04, 0x138B); + pas_write(count & 0xff, 0x1389); + pas_write((count >> 8) & 0xff, 0x1389); + pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); + + pcm_count = count; + } + pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); + pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); #endif - pcm_mode = PCM_ADC; + pcm_mode = PCM_ADC; - restore_flags (flags); + restore_flags(flags); } #ifndef NO_TRIGGER static void -pas_audio_trigger (int dev, int state) +pas_audio_trigger(int dev, int state) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - state &= open_mode; - - if (state & PCM_ENABLE_OUTPUT) - pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); - else if (state & PCM_ENABLE_INPUT) - pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); - else - pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); + save_flags(flags); + cli(); + state &= open_mode; + + if (state & PCM_ENABLE_OUTPUT) + pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); + else if (state & PCM_ENABLE_INPUT) + pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); + else + pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); - restore_flags (flags); + restore_flags(flags); } #endif static int -pas_audio_prepare_for_input (int dev, int bsize, int bcount) +pas_audio_prepare_for_input(int dev, int bsize, int bcount) { - pas_audio_reset (dev); - return 0; + pas_audio_reset(dev); + return 0; } static int -pas_audio_prepare_for_output (int dev, int bsize, int bcount) +pas_audio_prepare_for_output(int dev, int bsize, int bcount) { - pas_audio_reset (dev); - return 0; + pas_audio_reset(dev); + return 0; } static struct audio_driver pas_audio_driver = { - pas_audio_open, - pas_audio_close, - pas_audio_output_block, - pas_audio_start_input, - pas_audio_ioctl, - pas_audio_prepare_for_input, - pas_audio_prepare_for_output, - pas_audio_reset, - NULL, - NULL, - NULL, - NULL, - pas_audio_trigger + pas_audio_open, + pas_audio_close, + pas_audio_output_block, + pas_audio_start_input, + pas_audio_ioctl, + pas_audio_prepare_for_input, + pas_audio_prepare_for_output, + pas_audio_reset, + NULL, + NULL, + NULL, + NULL, + pas_audio_trigger }; void -pas_pcm_init (struct address_info *hw_config) +pas_pcm_init(struct address_info *hw_config) { - DEB (printk ("pas2_pcm.c: long pas_pcm_init()\n")); + DEB(printk("pas2_pcm.c: long pas_pcm_init()\n")); - pcm_bitsok = 8; - if (pas_read (0xEF8B) & 0x08) - pcm_bitsok |= 16; - - pcm_set_speed (DSP_DEFAULT_SPEED); - - if (num_audiodevs < MAX_AUDIO_DEV) - { - - if ((pas_audiodev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - "Pro Audio Spectrum", - &pas_audio_driver, - sizeof (struct audio_driver), - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, - NULL, - hw_config->dma, - hw_config->dma)) < 0) - { - return; - } - } - else - printk ("PAS16: Too many PCM devices available\n"); + pcm_bitsok = 8; + if (pas_read(0xEF8B) & 0x08) + pcm_bitsok |= 16; + + pcm_set_speed(DSP_DEFAULT_SPEED); + + if ((pas_audiodev = sound_alloc_audiodev()) != -1) + { + + if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + "Pro Audio Spectrum", + &pas_audio_driver, + sizeof(struct audio_driver), + DMA_AUTOMODE, + AFMT_U8 | AFMT_S16_LE, + NULL, + hw_config->dma, + hw_config->dma)) < 0) + { + return; + } + } else + printk(KERN_WARNING "PAS16: Too many PCM devices available\n"); } void -pas_pcm_interrupt (unsigned char status, int cause) +pas_pcm_interrupt(unsigned char status, int cause) { - if (cause == 1) - { - /* - * Halt the PCM first. Otherwise we don't have time to start a new - * block before the PCM chip proceeds to the next sample - */ - - if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) - { - pas_write (pas_read (0xF8A) & ~0x40, - 0xF8A); - } - - switch (pcm_mode) - { - - case PCM_DAC: - DMAbuf_outputintr (pas_audiodev, 1); - break; - - case PCM_ADC: - DMAbuf_inputintr (pas_audiodev); - break; - - default: - printk ("PAS: Unexpected PCM interrupt\n"); - } - } + if (cause == 1) + { + /* + * Halt the PCM first. Otherwise we don't have time to start a new + * block before the PCM chip proceeds to the next sample + */ + + if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) + { + pas_write(pas_read(0xF8A) & ~0x40, + 0xF8A); + } + switch (pcm_mode) + { + + case PCM_DAC: + DMAbuf_outputintr(pas_audiodev, 1); + break; + + case PCM_ADC: + DMAbuf_inputintr(pas_audiodev); + break; + + default: + printk("PAS: Unexpected PCM interrupt\n"); + } + } } -#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pnp.c linux/drivers/sound/pnp.c --- v2.1.66/linux/drivers/sound/pnp.c Wed May 28 10:51:33 1997 +++ linux/drivers/sound/pnp.c Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * sound/pnp.c - Temporary kludge for PnP soundcards. - * - * Copyright by Hannu Savolainen 1997. - * - * This file is just a temporary solution to be used with - * PnP soundcards until final kernel PnP support gets ready. - * The code contained in this file is largely untested and - * may cause failures in some systems. In particular it will - * cause troubles with other PnP ISA cards such as network cards. - * This file is also incompatible with (future) PnP support in kernel. - * - * For the above reasons I don't want this file to be widely distributed. - * You have permission to use this file with this particular sound driver - * and only for your own evaluation purposes. Any other use of this file - * or parts of it requires written permission by the author. - */ -extern int pnp_trace; -int pnp_trace_io = 0; - -#define UDELAY(x) udelay(x) - -#ifdef TEST_PNP -#include "pnp.h" -#include -#include -#define printk printf - -#define MALLOC(sz) malloc(sz) - -unsigned char res[10000]; -int rp; - -#else -#include "sound_config.h" -#endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pnp.h linux/drivers/sound/pnp.h --- v2.1.66/linux/drivers/sound/pnp.h Wed May 28 10:51:33 1997 +++ linux/drivers/sound/pnp.h Wed Dec 31 16:00:00 1969 @@ -1,112 +0,0 @@ -#ifndef _PNP_H_ -#define _PNP_H_ - -#define MAX_PNP_CARDS 16 - -#define PNP_DEVID(a, b, c, id) \ - ((a-'@')<<26) | ((b-'@')<<21) | ((c-'@') << 16) | (id&0xffff) - -#define NO_PORT 0 -#define NO_IRQ 0 -#define NO_DMA 4 - -struct pnp_port_resource -{ - short range_min, range_max; - unsigned char align, len; -}; - -struct pnp_func - { - struct pnp_dev *dev; - unsigned long flags; - struct pnp_func *next; - int nports; - struct pnp_port_resource ports[8]; - int nirq; - unsigned short irq[2]; - int ndma; - unsigned char dma[2]; - }; - -struct pnp_dev - { - int key; /* A PnP device id identifying this device */ - char *name; /* ANSI identifier string */ - int devno; /* Logical device number within a card */ - int ncompat; /* Number of compatible device idents */ - int compat_keys[8]; /* List of PnP compatible device idents */ - struct pnp_card *card; /* Link to the card which holds this device */ - struct pnp_dev *next; /* Pointer to next logical device or NULL */ - - int nports, nirq, ndma; - - int nfunc; /* Number of dependent function records */ - struct pnp_func *functions; /* List of dependent functions */ - int driver; /* Driver signature or 0 */ - int preconfig; /* 1 if config has been set manully */ - - }; - -struct pnp_card - { - int key; /* Unique PnP device identifier */ - char *name; /* ANSI identifier string of the card */ - int csn; /* Card select number */ - - char pnp_version; - char vendor_version; - - int driven; /* 0=No driver assigned, */ - /* 1=Drivers assigned to some of logical devices */ - /* 2=Card and all of it's devices have a driver */ - int relocated; /* 0=Card is inactive, 1=card is up and running */ - - int ndevs; /* Number of logical devices on the card */ - struct pnp_dev *devices; /* Pointer to first function entry */ - }; - -typedef struct pnp_card_info { - struct pnp_card card; - char name[64]; -} pnp_card_info; - -extern int pnp_card_count; -extern struct pnp_card *pnp_cards[MAX_PNP_CARDS]; -extern struct pnp_dev *pnp_device_list; - -extern int pnp_trace; - -/* - * Callable functions - */ - -extern void pnp_init(void); /* Called by kernel during boot */ -extern void terminate_pnp(void); - -extern int pnp_connect(char *driver_name); -extern void pnp_disconnect(int driver_signature); - -/* - * pnp_get_descr() returns an ASCII desctription string for a device. - * The parameter is an compressed EISA identifier of the device/card. - */ -extern char *pnp_get_descr (int id); - -extern void pnp_enable_device(struct pnp_dev *dev, int state); -extern void pnp_set_port(struct pnp_dev *dev, int selec, unsigned short base); -extern void pnp_set_irq(struct pnp_dev *dev, int selec, unsigned short val); -extern void pnp_set_dma(struct pnp_dev *dev, int selec, unsigned short val); -extern unsigned short pnp_get_port(struct pnp_dev *dev, int selec); -extern unsigned short pnp_get_irq(struct pnp_dev *dev, int selec); -extern unsigned short pnp_get_dma(struct pnp_dev *dev, int selec); -extern int pnp_allocate_device(int driver_sig, struct pnp_dev *dev, int basemask, int irqmask, - int dmamask, int memmask); -extern void pnp_release_device(int driver_sig, struct pnp_dev *dev); -extern int pnp_asc2devid(char *name); -extern char *pnp_devid2asc(int id); -extern void pnp_dump_resources(void); -extern int pnp_device_status (struct pnp_dev *dev); -struct pnp_dev *pnp_get_next_device(int driver_sig, struct pnp_dev *prev); -unsigned char pnp_readreg (struct pnp_dev *dev, int reg); -#endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.1.66/linux/drivers/sound/pss.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/pss.c Sat Nov 29 10:33:21 1997 @@ -11,12 +11,13 @@ * for more info. */ #include - +#include #include "sound_config.h" +#include "sound_firmware.h" +#include "soundmodule.h" -#ifdef CONFIG_PSS -#ifdef CONFIG_AUDIO +#if (defined(CONFIG_PSS) && defined(CONFIG_AUDIO))||defined(MODULE) /* * PSS registers. @@ -61,10 +62,10 @@ typedef struct pss_confdata { - int base; - int irq; - int dma; - int *osp; + int base; + int irq; + int dma; + int *osp; } pss_confdata; @@ -76,819 +77,844 @@ static int nonstandard_microcode = 0; static void -pss_write (int data) +pss_write(int data) { - int i, limit; + int i, limit; - limit = jiffies + 10; /* The timeout is 0.1 seconds */ - /* - * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 5000000 && jiffies < limit; i++) - { - if (inw (devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) - { - outw (devc->base + PSS_DATA, data); - return; - } - } - printk ("PSS: DSP Command (%04x) Timeout.\n", data); + limit = jiffies + 10; /* The timeout is 0.1 seconds */ + /* + * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 5000000 && jiffies < limit; i++) + { + if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) + { + outw(devc->base + PSS_DATA, data); + return; + } + } + printk("PSS: DSP Command (%04x) Timeout.\n", data); } int -probe_pss (struct address_info *hw_config) +probe_pss(struct address_info *hw_config) { - unsigned short id; - int irq, dma; + unsigned short id; + int irq, dma; + + devc->base = hw_config->io_base; + irq = devc->irq = hw_config->irq; + dma = devc->dma = hw_config->dma; + devc->osp = hw_config->osp; - devc->base = hw_config->io_base; - irq = devc->irq = hw_config->irq; - dma = devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - - if (devc->base != 0x220 && devc->base != 0x240) - if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ - return 0; - - if (check_region (devc->base, 16)) - { - printk ("PSS: I/O port conflict\n"); - return 0; - } - - id = inw (REG (PSS_ID)); - if ((id >> 8) != 'E') - { - /* printk( "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ - return 0; - } + if (devc->base != 0x220 && devc->base != 0x240) + if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ + return 0; - return 1; + if (check_region(devc->base, 16)) + { + printk("PSS: I/O port conflict\n"); + return 0; + } + id = inw(REG(PSS_ID)); + if ((id >> 8) != 'E') + { + /* printk( "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ + return 0; + } + return 1; } static int -set_irq (pss_confdata * devc, int dev, int irq) +set_irq(pss_confdata * devc, int dev, int irq) { - static unsigned short irq_bits[16] = - { - 0x0000, 0x0000, 0x0000, 0x0008, - 0x0000, 0x0010, 0x0000, 0x0018, - 0x0000, 0x0020, 0x0028, 0x0030, - 0x0038, 0x0000, 0x0000, 0x0000 - }; - - unsigned short tmp, bits; - - if (irq < 0 || irq > 15) - return 0; - - tmp = inw (REG (dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ - - if ((bits = irq_bits[irq]) == 0 && irq != 0) - { - printk ("PSS: Invalid IRQ %d\n", irq); - return 0; - } + static unsigned short irq_bits[16] = + { + 0x0000, 0x0000, 0x0000, 0x0008, + 0x0000, 0x0010, 0x0000, 0x0018, + 0x0000, 0x0020, 0x0028, 0x0030, + 0x0038, 0x0000, 0x0000, 0x0000 + }; + + unsigned short tmp, bits; - outw (tmp | bits, REG (dev)); - return 1; + if (irq < 0 || irq > 15) + return 0; + + tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ + + if ((bits = irq_bits[irq]) == 0 && irq != 0) + { + printk("PSS: Invalid IRQ %d\n", irq); + return 0; + } + outw(tmp | bits, REG(dev)); + return 1; } static int -set_io_base (pss_confdata * devc, int dev, int base) +set_io_base(pss_confdata * devc, int dev, int base) { - unsigned short tmp = inw (REG (dev)) & 0x003f; - unsigned short bits = (base & 0x0ffc) << 4; + unsigned short tmp = inw(REG(dev)) & 0x003f; + unsigned short bits = (base & 0x0ffc) << 4; - outw (bits | tmp, REG (dev)); + outw(bits | tmp, REG(dev)); - return 1; + return 1; } static int -set_dma (pss_confdata * devc, int dev, int dma) +set_dma(pss_confdata * devc, int dev, int dma) { - static unsigned short dma_bits[8] = - { - 0x0001, 0x0002, 0x0000, 0x0003, - 0x0000, 0x0005, 0x0006, 0x0007 - }; - - unsigned short tmp, bits; + static unsigned short dma_bits[8] = + { + 0x0001, 0x0002, 0x0000, 0x0003, + 0x0000, 0x0005, 0x0006, 0x0007 + }; - if (dma < 0 || dma > 7) - return 0; + unsigned short tmp, bits; - tmp = inw (REG (dev)) & ~0x07; /* Load confreg, mask DMA bits out */ + if (dma < 0 || dma > 7) + return 0; - if ((bits = dma_bits[dma]) == 0 && dma != 4) - { - printk ("PSS: Invalid DMA %d\n", dma); - return 0; - } + tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */ - outw (tmp | bits, REG (dev)); - return 1; + if ((bits = dma_bits[dma]) == 0 && dma != 4) + { + printk("PSS: Invalid DMA %d\n", dma); + return 0; + } + outw(tmp | bits, REG(dev)); + return 1; } static int -pss_reset_dsp (pss_confdata * devc) +pss_reset_dsp(pss_confdata * devc) { - unsigned long i, limit = jiffies + 10; + unsigned long i, limit = jiffies + 10; - outw (0x2000, REG (PSS_CONTROL)); + outw(0x2000, REG(PSS_CONTROL)); - for (i = 0; i < 32768 && jiffies < limit; i++) - inw (REG (PSS_CONTROL)); + for (i = 0; i < 32768 && jiffies < limit; i++) + inw(REG(PSS_CONTROL)); - outw (0x0000, REG (PSS_CONTROL)); + outw(0x0000, REG(PSS_CONTROL)); - return 1; + return 1; } static int -pss_put_dspword (pss_confdata * devc, unsigned short word) +pss_put_dspword(pss_confdata * devc, unsigned short word) { - int i, val; + int i, val; - for (i = 0; i < 327680; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_WRITE_EMPTY) - { - outw (word, REG (PSS_DATA)); - return 1; - } - } - return 0; + for (i = 0; i < 327680; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_WRITE_EMPTY) + { + outw(word, REG(PSS_DATA)); + return 1; + } + } + return 0; } static int -pss_get_dspword (pss_confdata * devc, unsigned short *word) +pss_get_dspword(pss_confdata * devc, unsigned short *word) { - int i, val; + int i, val; - for (i = 0; i < 327680; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_READ_FULL) - { - *word = inw (REG (PSS_DATA)); - return 1; - } - } + for (i = 0; i < 327680; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + { + *word = inw(REG(PSS_DATA)); + return 1; + } + } - return 0; + return 0; } static int -pss_download_boot (pss_confdata * devc, unsigned char *block, int size, int flags) +pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) { - int i, limit, val, count; + int i, limit, val, count; - if (flags & CPF_FIRST) - { + if (flags & CPF_FIRST) + { /*_____ Warn DSP software that a boot is coming */ - outw (0x00fe, REG (PSS_DATA)); - - limit = jiffies + 10; + outw(0x00fe, REG(PSS_DATA)); - for (i = 0; i < 32768 && jiffies < limit; i++) - if (inw (REG (PSS_DATA)) == 0x5500) - break; + limit = jiffies + 10; - outw (*block++, REG (PSS_DATA)); + for (i = 0; i < 32768 && jiffies < limit; i++) + if (inw(REG(PSS_DATA)) == 0x5500) + break; - pss_reset_dsp (devc); - } + outw(*block++, REG(PSS_DATA)); - count = 1; - while (1) - { - int j; + pss_reset_dsp(devc); + } + count = 1; + while (1) + { + int j; - for (j = 0; j < 327670; j++) - { + for (j = 0; j < 327670; j++) + { /*_____ Wait for BG to appear */ - if (inw (REG (PSS_STATUS)) & PSS_FLAG3) - break; - } - - if (j == 327670) - { - /* It's ok we timed out when the file was empty */ - if (count >= size && flags & CPF_LAST) - break; - else - { - printk ("\nPSS: Download timeout problems, byte %d=%d\n", count, size); - return 0; - } - } + if (inw(REG(PSS_STATUS)) & PSS_FLAG3) + break; + } + + if (j == 327670) + { + /* It's ok we timed out when the file was empty */ + if (count >= size && flags & CPF_LAST) + break; + else + { + printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size); + return 0; + } + } /*_____ Send the next byte */ - outw (*block++, REG (PSS_DATA)); - count++; - } + outw(*block++, REG(PSS_DATA)); + count++; + } - if (flags & CPF_LAST) - { + if (flags & CPF_LAST) + { /*_____ Why */ - outw (0, REG (PSS_DATA)); + outw(0, REG(PSS_DATA)); - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - val = inw (REG (PSS_STATUS)); + limit = jiffies + 10; + for (i = 0; i < 32768 && jiffies < limit; i++) + val = inw(REG(PSS_STATUS)); + + limit = jiffies + 10; + for (i = 0; i < 32768 && jiffies < limit; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & 0x4000) + break; + } + + /* now read the version */ + for (i = 0; i < 32000; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + break; + } + if (i == 32000) + return 0; - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & 0x4000) - break; - } - - /* now read the version */ - for (i = 0; i < 32000; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_READ_FULL) - break; - } - if (i == 32000) - return 0; - - val = inw (REG (PSS_DATA)); - /* printk( "", val/16, val % 16); */ - } - - return 1; + val = inw(REG(PSS_DATA)); + /* printk( "", val/16, val % 16); */ + } + return 1; } void -attach_pss (struct address_info *hw_config) +attach_pss(struct address_info *hw_config) { - unsigned short id; - char tmp[100]; + unsigned short id; + char tmp[100]; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - - if (!probe_pss (hw_config)) - return; - - id = inw (REG (PSS_ID)) & 0x00ff; - - /* - * Disable all emulations. Will be enabled later (if required). - */ - outw (0x0000, REG (CONF_PSS)); /* 0x0400 enables joystick */ - outw (0x0000, REG (CONF_WSS)); - outw (0x0000, REG (CONF_SB)); - outw (0x0000, REG (CONF_MIDI)); - outw (0x0000, REG (CONF_CDROM)); + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + devc->osp = hw_config->osp; + + if (!probe_pss(hw_config)) + return; + + id = inw(REG(PSS_ID)) & 0x00ff; + + /* + * Disable all emulations. Will be enabled later (if required). + */ + outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ + outw(0x0000, REG(CONF_WSS)); + outw(0x0000, REG(CONF_SB)); + outw(0x0000, REG(CONF_MIDI)); + outw(0x0000, REG(CONF_CDROM)); #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES - if (sound_alloc_dma (hw_config->dma, "PSS")) - { - printk ("pss.c: Can't allocate DMA channel\n"); - return; - } - - if (!set_irq (devc, CONF_PSS, devc->irq)) - { - printk ("PSS: IRQ error\n"); - return; - } - - if (!set_dma (devc, CONF_PSS, devc->dma)) - { - printk ("PSS: DRQ error\n"); - return; - } + if (sound_alloc_dma(hw_config->dma, "PSS")) + { + printk("pss.c: Can't allocate DMA channel\n"); + return; + } + if (!set_irq(devc, CONF_PSS, devc->irq)) + { + printk("PSS: IRQ error\n"); + return; + } + if (!set_dma(devc, CONF_PSS, devc->dma)) + { + printk("PSS: DRQ error\n"); + return; + } #endif - pss_initialized = 1; - sprintf (tmp, "ECHO-PSS Rev. %d", id); - conf_printf (tmp, hw_config); + pss_initialized = 1; + sprintf(tmp, "ECHO-PSS Rev. %d", id); + conf_printf(tmp, hw_config); } static void -pss_init_speaker (void) +pss_init_speaker(void) { /* Don't ask what are these commands. I really don't know */ - pss_write (0x0010); - pss_write (0x0000 | 252); /* Left master volume */ - pss_write (0x0010); - pss_write (0x0100 | 252); /* Right master volume */ - pss_write (0x0010); - pss_write (0x0200 | 246); /* Bass */ - pss_write (0x0010); - pss_write (0x0300 | 246); /* Treble */ - pss_write (0x0010); - pss_write (0x0800 | 0x00ce); /* Stereo switch? */ + pss_write(0x0010); + pss_write(0x0000 | 252); /* Left master volume */ + pss_write(0x0010); + pss_write(0x0100 | 252); /* Right master volume */ + pss_write(0x0010); + pss_write(0x0200 | 246); /* Bass */ + pss_write(0x0010); + pss_write(0x0300 | 246); /* Treble */ + pss_write(0x0010); + pss_write(0x0800 | 0x00ce); /* Stereo switch? */ } int -probe_pss_mpu (struct address_info *hw_config) +probe_pss_mpu(struct address_info *hw_config) { - int timeout; + int timeout; - if (!pss_initialized) - return 0; + if (!pss_initialized) + return 0; - if (check_region (hw_config->io_base, 2)) - { - printk ("PSS: MPU I/O port conflict\n"); - return 0; - } - - if (!set_io_base (devc, CONF_MIDI, hw_config->io_base)) - { - printk ("PSS: MIDI base error.\n"); - return 0; - } - - if (!set_irq (devc, CONF_MIDI, hw_config->irq)) - { - printk ("PSS: MIDI IRQ error.\n"); - return 0; - } - - if (!pss_synthLen) - { - printk ("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - return 0; - } - - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return 0; - } - - pss_init_speaker (); + if (check_region(hw_config->io_base, 2)) + { + printk("PSS: MPU I/O port conflict\n"); + return 0; + } + if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) + { + printk("PSS: MIDI base error.\n"); + return 0; + } + if (!set_irq(devc, CONF_MIDI, hw_config->irq)) + { + printk("PSS: MIDI IRQ error.\n"); + return 0; + } + if (!pss_synthLen) + { + printk("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); + return 0; + } + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return 0; + } + pss_init_speaker(); /* * Finally wait until the DSP algorithm has initialized itself and * deactivates receive interrupt. */ - for (timeout = 900000; timeout > 0; timeout--) - { - if ((inb (hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ - inb (hw_config->io_base); /* Discard it */ - else - break; /* No more input */ - } + for (timeout = 900000; timeout > 0; timeout--) + { + if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ + inb(hw_config->io_base); /* Discard it */ + else + break; /* No more input */ + } #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - return probe_mpu401 (hw_config); + return probe_mpu401(hw_config); #else - return 0; + return 0; #endif } static int -pss_coproc_open (void *dev_info, int sub_device) +pss_coproc_open(void *dev_info, int sub_device) { - switch (sub_device) - { - case COPR_MIDI: + switch (sub_device) + { + case COPR_MIDI: - if (pss_synthLen == 0) - { - printk ("PSS: MIDI synth microcode not available.\n"); - return -EIO; - } + if (pss_synthLen == 0) + { + printk("PSS: MIDI synth microcode not available.\n"); + return -EIO; + } + if (nonstandard_microcode) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return -EIO; + } + nonstandard_microcode = 0; + break; - if (nonstandard_microcode) - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; + default:; } - nonstandard_microcode = 0; - break; - - default:; - } - return 0; + return 0; } static void -pss_coproc_close (void *dev_info, int sub_device) +pss_coproc_close(void *dev_info, int sub_device) { - return; + return; } static void -pss_coproc_reset (void *dev_info) -{ - if (pss_synthLen) - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - } - nonstandard_microcode = 0; -} - -static int -download_boot_block (void *dev_info, copr_buffer * buf) +pss_coproc_reset(void *dev_info) { - if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; - - if (!pss_download_boot (devc, buf->data, buf->len, buf->flags)) - { - printk ("PSS: Unable to load microcode block to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - - return 0; + if (pss_synthLen) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + } + nonstandard_microcode = 0; } static int -pss_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) +download_boot_block(void *dev_info, copr_buffer * buf) { - /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - - switch (cmd) - { - case SNDCTL_COPR_RESET: - pss_coproc_reset (dev_info); - return 0; - break; - - case SNDCTL_COPR_LOAD: - { - copr_buffer *buf; - int err; - - buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); - if (buf == NULL) - return -ENOSPC; - - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - err = download_boot_block (dev_info, buf); - vfree (buf); - return err; - } - break; - - case SNDCTL_COPR_SENDMSG: - { - copr_msg *buf; - unsigned long flags; - unsigned short *data; - int i; - - buf = (copr_msg *) vmalloc (sizeof (copr_msg)); - if (buf == NULL) - return -ENOSPC; - - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - - data = (unsigned short *) (buf->data); - - save_flags (flags); - cli (); - - for (i = 0; i < buf->len; i++) - { - if (!pss_put_dspword (devc, *data++)) - { - restore_flags (flags); - buf->len = i; /* feed back number of WORDs sent */ - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); - return -EIO; - } - } - - restore_flags (flags); - vfree (buf); - - return 0; - } - break; - - - case SNDCTL_COPR_RCVMSG: - { - copr_msg *buf; - unsigned long flags; - unsigned short *data; - unsigned int i; - int err = 0; - - buf = (copr_msg *) vmalloc (sizeof (copr_msg)); - if (buf == NULL) - return -ENOSPC; - - - data = (unsigned short *) buf->data; - - save_flags (flags); - cli (); - - for (i = 0; i < buf->len; i++) - { - buf->len = i; /* feed back number of WORDs read */ - if (!pss_get_dspword (devc, data++)) - { - if (i == 0) - err = -EIO; - break; - } - } - - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); - - return err; - } - break; - - - case SNDCTL_COPR_RDATA: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; - - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); - - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d0)) - { - restore_flags (flags); - return -EIO; - } - - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } + if (buf->len <= 0 || buf->len > sizeof(buf->data)) + return -EINVAL; - if (!pss_get_dspword (devc, &tmp)) + if (!pss_download_boot(devc, buf->data, buf->len, buf->flags)) { - restore_flags (flags); - return -EIO; + printk("PSS: Unable to load microcode block to DSP.\n"); + return -EIO; } + nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - buf.parm1 = tmp; - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) &buf, sizeof (buf)); return 0; - } - break; - - case SNDCTL_COPR_WDATA: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; - - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); - - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d1)) - { - restore_flags (flags); - return -EIO; - } +} - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } +static int +pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local) +{ + /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - tmp = (unsigned int) buf.parm2 & 0xffff; - if (!pss_put_dspword (devc, tmp)) + switch (cmd) { - restore_flags (flags); - return -EIO; - } - - restore_flags (flags); - return 0; - } - break; - - case SNDCTL_COPR_WCODE: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; - - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); + case SNDCTL_COPR_RESET: + pss_coproc_reset(dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + if (buf == NULL) + return -ENOSPC; + + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + err = download_boot_block(dev_info, buf); + vfree(buf); + return err; + } + break; + + case SNDCTL_COPR_SENDMSG: + { + copr_msg *buf; + unsigned long flags; + unsigned short *data; + int i; + + buf = (copr_msg *) vmalloc(sizeof(copr_msg)); + if (buf == NULL) + return -ENOSPC; + + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + + data = (unsigned short *) (buf->data); + + save_flags(flags); + cli(); + + for (i = 0; i < buf->len; i++) + { + if (!pss_put_dspword(devc, *data++)) + { + restore_flags(flags); + buf->len = i; /* feed back number of WORDs sent */ + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); + return -EIO; + } + } + + restore_flags(flags); + vfree(buf); + + return 0; + } + break; + + + case SNDCTL_COPR_RCVMSG: + { + copr_msg *buf; + unsigned long flags; + unsigned short *data; + unsigned int i; + int err = 0; + + buf = (copr_msg *) vmalloc(sizeof(copr_msg)); + if (buf == NULL) + return -ENOSPC; + + + data = (unsigned short *) buf->data; + + save_flags(flags); + cli(); + + for (i = 0; i < buf->len; i++) + { + buf->len = i; /* feed back number of WORDs read */ + if (!pss_get_dspword(devc, data++)) + { + if (i == 0) + err = -EIO; + break; + } + } + + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); + + return err; + } + break; + + + case SNDCTL_COPR_RDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d0)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) + { + restore_flags(flags); + return -EIO; + } + buf.parm1 = tmp; + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf)); + return 0; + } + break; + + case SNDCTL_COPR_WDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d1)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int) buf.parm2 & 0xffff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + restore_flags(flags); + return 0; + } + break; + + case SNDCTL_COPR_WCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d3)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int) buf.parm2 & 0x00ff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + restore_flags(flags); + return 0; + } + break; + + case SNDCTL_COPR_RCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d2)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) /* Read MSB */ + { + restore_flags(flags); + return -EIO; + } + buf.parm1 = tmp << 8; + + if (!pss_get_dspword(devc, &tmp)) /* Read LSB */ + { + restore_flags(flags); + return -EIO; + } + buf.parm1 |= tmp & 0x00ff; + + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf)); + return 0; + } + break; - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d3)) - { - restore_flags (flags); - return -EIO; + default: + return -EINVAL; } - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } + return -EINVAL; +} - tmp = (unsigned int) buf.parm2 & 0x00ff; - if (!pss_put_dspword (devc, tmp)) - { - restore_flags (flags); - return -EIO; - } +static coproc_operations pss_coproc_operations = +{ + "ADSP-2115", + pss_coproc_open, + pss_coproc_close, + pss_coproc_ioctl, + pss_coproc_reset, + &pss_data +}; - tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; - if (!pss_put_dspword (devc, tmp)) - { - restore_flags (flags); - return -EIO; - } +void +attach_pss_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + { + attach_mpu401(hw_config); /* Slot 1 */ - restore_flags (flags); - return 0; - } - break; + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; + } +#endif +} - case SNDCTL_COPR_RCODE: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; +int +probe_pss_mss(struct address_info *hw_config) +{ + volatile int timeout; - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); + if (!pss_initialized) + return 0; - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d2)) + if (check_region(hw_config->io_base, 8)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS I/O port conflict\n"); + return 0; } - - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS base error.\n"); + return 0; } - - if (!pss_get_dspword (devc, &tmp)) /* Read MSB */ + if (!set_irq(devc, CONF_WSS, hw_config->irq)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS IRQ error.\n"); + return 0; } - - buf.parm1 = tmp << 8; - - if (!pss_get_dspword (devc, &tmp)) /* Read LSB */ + if (!set_dma(devc, CONF_WSS, hw_config->dma)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS DRQ error\n"); + return 0; } + /* + * For some reason the card returns 0xff in the WSS status register + * immediately after boot. Probably MIDI+SB emulation algorithm + * downloaded to the ADSP2115 spends some time initializing the card. + * Let's try to wait until it finishes this task. + */ + for (timeout = 0; + timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04; + timeout++); - buf.parm1 |= tmp & 0x00ff; - - restore_flags (flags); + outb((0x0b), hw_config->io_base + 4); /* Required by some cards */ - memcpy ((&((char *) arg)[0]), (char *) &buf, sizeof (buf)); - return 0; - } - break; + for (timeout = 0; + timeout < 100000; + timeout++); + return probe_ms_sound(hw_config); +} - default: - return -EINVAL; - } +void +attach_pss_mss(struct address_info *hw_config) +{ + attach_ms_sound(hw_config); /* Slot 0 */ - return -EINVAL; + if (hw_config->slots[0] != -1) /* The MSS driver installed itself */ + audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; } -static coproc_operations pss_coproc_operations = +void +unload_pss(struct address_info *hw_config) { - "ADSP-2115", - pss_coproc_open, - pss_coproc_close, - pss_coproc_ioctl, - pss_coproc_reset, - &pss_data -}; +} void -attach_pss_mpu (struct address_info *hw_config) +unload_pss_mpu(struct address_info *hw_config) { #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - { - int prev_devs; - - prev_devs = num_midis; - attach_mpu401 (hw_config); - - if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ - midi_devs[prev_devs]->coproc = &pss_coproc_operations; - } + unload_mpu401(hw_config); #endif } -int -probe_pss_mss (struct address_info *hw_config) +void +unload_pss_mss(struct address_info *hw_config) { - volatile int timeout; + unload_ms_sound(hw_config); +} - if (!pss_initialized) - return 0; +#ifdef MODULE - if (check_region (hw_config->io_base, 8)) - { - printk ("PSS: WSS I/O port conflict\n"); - return 0; - } - - if (!set_io_base (devc, CONF_WSS, hw_config->io_base)) - { - printk ("PSS: WSS base error.\n"); - return 0; - } - - if (!set_irq (devc, CONF_WSS, hw_config->irq)) - { - printk ("PSS: WSS IRQ error.\n"); - return 0; - } - - if (!set_dma (devc, CONF_WSS, hw_config->dma)) - { - printk ("PSS: WSS DRQ error\n"); - return 0; - } - - /* - * For some reason the card returns 0xff in the WSS status register - * immediately after boot. Probably MIDI+SB emulation algorithm - * downloaded to the ADSP2115 spends some time initializing the card. - * Let's try to wait until it finishes this task. - */ - for (timeout = 0; - timeout < 100000 && (inb (hw_config->io_base + 3) & 0x3f) != 0x04; - timeout++); - - outb ((0x0b), hw_config->io_base + 4); /* Required by some cards */ - - for (timeout = 0; - timeout < 100000; - timeout++); - return probe_ms_sound (hw_config); -} +int io = -1; +int irq = -1; +int dma = -1; -void -attach_pss_mss (struct address_info *hw_config) -{ - int prev_devs; +int pssmpu, pssmss; +struct address_info cfg; - prev_devs = num_audiodevs; - attach_ms_sound (hw_config); +static int fw_load = 0; - if (num_audiodevs == (prev_devs + 1)) /* The MSS driver installed itself */ - audio_devs[prev_devs]->coproc = &pss_coproc_operations; -} +/* + * Load a PSS sound card module + */ -void -unload_pss (struct address_info *hw_config) +int +init_module(void) { -} + if (io == -1 || irq == -1 || dma == -1) + { + printk("pss: dma, irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; -void -unload_pss_mpu (struct address_info *hw_config) -{ -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); -#endif + if (!pss_synth) + { + fw_load = 1; + pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); + } + if (probe_pss(&cfg)) + return -ENODEV; + /* + * Attach stuff + */ + if (probe_pss_mpu(&cfg)) + { + pssmpu = 1; + attach_pss_mpu(&cfg); + } + if (probe_pss_mss(&cfg)) + { + pssmss = 1; + attach_pss_mss(&cfg); + } + SOUND_LOCK; + return 0; } -void -unload_pss_mss (struct address_info *hw_config) +void +cleanup_module(void) { - unload_ms_sound (hw_config); + if (fw_load && pss_synth) + kfree(pss_synth); + if (pssmss) + unload_pss_mss(&cfg); + if (pssmpu) + unload_pss_mpu(&cfg); + unload_pss(&cfg); + SOUND_LOCK_END; } - #endif + #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.1.66/linux/drivers/sound/sb.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb.h Sat Nov 29 10:33:21 1997 @@ -125,4 +125,6 @@ void sb_midi_interrupt (sb_devc *devc); int ess_write (sb_devc *devc, unsigned char reg, unsigned char data); int ess_read (sb_devc *devc, unsigned char reg); + +extern int acer; #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.1.66/linux/drivers/sound/sb_audio.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb_audio.c Sat Nov 29 10:33:21 1997 @@ -15,91 +15,88 @@ #include "sound_config.h" -#ifdef CONFIG_SBDSP +#if defined(CONFIG_SBDSP) || defined(MODULE) #include "sb_mixer.h" #include "sb.h" static int -sb_audio_open (int dev, int mode) +sb_audio_open(int dev, int mode) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; - if (devc == NULL) - { - printk ("SB: Incomplete initialization\n"); - return -ENXIO; - } - - if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) - { - printk ("Notice: Recording is not possible with /dev/dsp%d\n", dev); - if (mode == OPEN_READ) - return -EPERM; - } - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - return -EBUSY; - } - - if (devc->dma16 != -1 && devc->dma16 != devc->dma8) - { - if (sound_open_dma (devc->dma16, "Sound Blaster 16 bit")) - { - restore_flags (flags); - return -EBUSY; - } - } - devc->opened = mode; - restore_flags (flags); + if (devc == NULL) + { + printk("SB: Incomplete initialization\n"); + return -ENXIO; + } + if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) + { + printk("Notice: Recording is not possible with /dev/dsp%d\n", dev); + if (mode == OPEN_READ) + return -EPERM; + } + save_flags(flags); + cli(); + if (devc->opened) + { + restore_flags(flags); + return -EBUSY; + } + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + { + if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) + { + restore_flags(flags); + return -EBUSY; + } + } + devc->opened = mode; + restore_flags(flags); - devc->irq_mode = IMODE_NONE; - sb_dsp_reset (devc); + devc->irq_mode = IMODE_NONE; + sb_dsp_reset(devc); - return 0; + return 0; } static void -sb_audio_close (int dev) +sb_audio_close(int dev) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_in->dma = - audio_devs[dev]->dmap_out->dma = - devc->dma8; + audio_devs[dev]->dmap_in->dma = + audio_devs[dev]->dmap_out->dma = + devc->dma8; - if (devc->dma16 != -1 && devc->dma16 != devc->dma8) - sound_close_dma (devc->dma16); + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + sound_close_dma(devc->dma16); - devc->opened = 0; + devc->opened = 0; } static void -sb_set_output_parms (int dev, unsigned long buf, int nr_bytes, - int intrflag) +sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - devc->trg_buf = buf; - devc->trg_bytes = nr_bytes; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_OUTPUT; + devc->trg_buf = buf; + devc->trg_bytes = nr_bytes; + devc->trg_intrflag = intrflag; + devc->irq_mode = IMODE_OUTPUT; } static void -sb_set_input_parms (int dev, unsigned long buf, int count, int intrflag) +sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; + devc->trg_buf = buf; + devc->trg_bytes = count; + devc->trg_intrflag = intrflag; + devc->irq_mode = IMODE_INPUT; } /* @@ -107,183 +104,180 @@ */ static void -sb1_audio_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag) +sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x14)) /* 8 bit DAC using DMA */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - } - else - printk ("SB: Unable to start DAC\n"); - restore_flags (flags); - devc->intr_active = 1; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x14)) /* 8 bit DAC using DMA */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + } else + printk("SB: Unable to start DAC\n"); + restore_flags(flags); + devc->intr_active = 1; } static void -sb1_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag) +sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x24)) /* 8 bit ADC using DMA */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - } - else - printk ("SB Error: Unable to start ADC\n"); - restore_flags (flags); + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; - devc->intr_active = 1; + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x24)) /* 8 bit ADC using DMA */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + } else + printk("SB Error: Unable to start ADC\n"); + restore_flags(flags); + + devc->intr_active = 1; } static void -sb1_audio_trigger (int dev, int bits) +sb1_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; + bits &= devc->irq_mode; - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb1_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb1_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } + } - devc->trigger_bits = bits; + devc->trigger_bits = bits; } static int -sb1_audio_prepare_for_input (int dev, int bsize, int bcount) +sb1_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKOFF); - restore_flags (flags); + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKOFF); + restore_flags(flags); - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } static int -sb1_audio_prepare_for_output (int dev, int bsize, int bcount) +sb1_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKON); - restore_flags (flags); - devc->trigger_bits = 0; - return 0; + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKON); + restore_flags(flags); + devc->trigger_bits = 0; + return 0; } static int -sb1_audio_set_speed (int dev, int speed) +sb1_audio_set_speed(int dev, int speed) { - int max_speed = 23000; - sb_devc *devc = audio_devs[dev]->devc; - int tmp; + int max_speed = 23000; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; - if (devc->opened & OPEN_READ) - max_speed = 13000; + if (devc->opened & OPEN_READ) + max_speed = 13000; - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > max_speed) - speed = max_speed; + if (speed > 0) + { + if (speed < 4000) + speed = 4000; - devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; + if (speed > max_speed) + speed = max_speed; - tmp = 256 - devc->tconst; - speed = (1000000 + tmp / 2) / tmp; + devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - devc->speed = speed; - } + tmp = 256 - devc->tconst; + speed = (1000000 + tmp / 2) / tmp; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } static short -sb1_audio_set_channels (int dev, short channels) +sb1_audio_set_channels(int dev, short channels) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - return devc->channels = 1; + return devc->channels = 1; } static unsigned int -sb1_audio_set_bits (int dev, unsigned int bits) +sb1_audio_set_bits(int dev, unsigned int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - return devc->bits = 8; + return devc->bits = 8; } static void -sb1_audio_halt_xfer (int dev) +sb1_audio_halt_xfer(int dev) { - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; - save_flags (flags); - cli (); - sb_dsp_reset (devc); - restore_flags (flags); + save_flags(flags); + cli(); + sb_dsp_reset(devc); + restore_flags(flags); } /* @@ -291,112 +285,110 @@ */ static void -sb20_audio_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag) +sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_OUTPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= 23000) - cmd = 0x1c; /* 8 bit PCM output */ - else - cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ - - if (!sb_dsp_command (devc, cmd)) - printk ("SB: Unable to start DAC\n"); - - } - else - printk ("SB: Unable to start DAC\n"); - restore_flags (flags); - devc->intr_active = 1; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= 23000) + cmd = 0x1c; /* 8 bit PCM output */ + else + cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ + + if (!sb_dsp_command(devc, cmd)) + printk("SB: Unable to start DAC\n"); + + } else + printk("SB: Unable to start DAC\n"); + restore_flags(flags); + devc->intr_active = 1; } static void -sb20_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag) +sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; - - devc->irq_mode = IMODE_INPUT; - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command (devc, (unsigned char) (count & 0xff)); - sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) - cmd = 0x2c; /* 8 bit PCM input */ - else - cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ - - if (!sb_dsp_command (devc, cmd)) - printk ("SB: Unable to start ADC\n"); - } - else - printk ("SB Error: Unable to start ADC\n"); - restore_flags (flags); + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) + cmd = 0x2c; /* 8 bit PCM input */ + else + cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ + + if (!sb_dsp_command(devc, cmd)) + printk("SB: Unable to start ADC\n"); + } else + printk("SB Error: Unable to start ADC\n"); + restore_flags(flags); - devc->intr_active = 1; + devc->intr_active = 1; } static void -sb20_audio_trigger (int dev, int bits) +sb20_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; + bits &= devc->irq_mode; - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb20_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb20_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } + } - devc->trigger_bits = bits; + devc->trigger_bits = bits; } /* @@ -404,33 +396,32 @@ */ static int -sb201_audio_set_speed (int dev, int speed) +sb201_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - int s = speed * devc->channels; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + int s = speed * devc->channels; - if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > 44100) - speed = 44100; + if (speed > 0) + { + if (speed < 4000) + speed = 4000; - if (devc->opened & OPEN_READ && speed > 15000) - speed = 15000; + if (speed > 44100) + speed = 44100; - devc->tconst = ((65536 - ((256000000 + s / 2) / - s)) >> 8) & 0xff; + if (devc->opened & OPEN_READ && speed > 15000) + speed = 15000; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; - devc->speed = speed; - } + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } /* @@ -438,148 +429,145 @@ */ static int -sbpro_audio_prepare_for_input (int dev, int bsize, int bcount) +sbpro_audio_prepare_for_input(int dev, int bsize, int bcount) { /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char bits = 0; - - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; - - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKOFF); - if (devc->channels == 1) - sb_dsp_command (devc, 0xa0 | bits); /* Mono input */ - else - sb_dsp_command (devc, 0xa8 | bits); /* Stereo input */ - restore_flags (flags); + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == 16 ? devc->dma16 : devc->dma8; + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKOFF); + if (devc->channels == 1) + sb_dsp_command(devc, 0xa0 | bits); /* Mono input */ + else + sb_dsp_command(devc, 0xa8 | bits); /* Stereo input */ + restore_flags(flags); - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } static int -sbpro_audio_prepare_for_output (int dev, int bsize, int bcount) +sbpro_audio_prepare_for_output(int dev, int bsize, int bcount) { /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char tmp; - unsigned char bits = 0; - - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; - if (devc->model == MDL_SBPRO) - sb_mixer_set_stereo (devc, devc->channels == 2); - - save_flags (flags); - cli (); - if (sb_dsp_command (devc, 0x40)) - sb_dsp_command (devc, devc->tconst); - sb_dsp_command (devc, DSP_CMD_SPKON); - - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - { - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - if (devc->channels == 1) - sb_dsp_command (devc, 0xa0 | bits); /* Mono output */ - else - sb_dsp_command (devc, 0xa8 | bits); /* Stereo output */ - } - else - { - tmp = sb_getmixer (devc, 0x0e); - if (devc->channels == 1) - tmp &= ~0x02; - else - tmp |= 0x02; - sb_setmixer (devc, 0x0e, tmp); - } - restore_flags (flags); - devc->trigger_bits = 0; - return 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char tmp; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == 16 ? devc->dma16 : devc->dma8; + if (devc->model == MDL_SBPRO) + sb_mixer_set_stereo(devc, devc->channels == 2); + + save_flags(flags); + cli(); + if (sb_dsp_command(devc, 0x40)) + sb_dsp_command(devc, devc->tconst); + sb_dsp_command(devc, DSP_CMD_SPKON); + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + { + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + if (devc->channels == 1) + sb_dsp_command(devc, 0xa0 | bits); /* Mono output */ + else + sb_dsp_command(devc, 0xa8 | bits); /* Stereo output */ + } else + { + tmp = sb_getmixer(devc, 0x0e); + if (devc->channels == 1) + tmp &= ~0x02; + else + tmp |= 0x02; + sb_setmixer(devc, 0x0e, tmp); + } + restore_flags(flags); + devc->trigger_bits = 0; + return 0; } static int -sbpro_audio_set_speed (int dev, int speed) +sbpro_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - if (speed < 4000) - speed = 4000; + sb_devc *devc = audio_devs[dev]->devc; - if (speed > 44100) - speed = 44100; + if (speed > 0) + { + if (speed < 4000) + speed = 4000; - if (devc->channels > 1 && speed > 22050) - speed = 22050; + if (speed > 44100) + speed = 44100; - sb201_audio_set_speed (dev, speed); - } + if (devc->channels > 1 && speed > 22050) + speed = 22050; - return devc->speed; + sb201_audio_set_speed(dev, speed); + } + return devc->speed; } static short -sbpro_audio_set_channels (int dev, short channels) +sbpro_audio_set_channels(int dev, short channels) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - if (channels == 1 || channels == 2) - if (channels != devc->channels) - { - devc->channels = channels; - if (devc->model == MDL_SBPRO && devc->channels == 2) - { - if (devc->speed > 22050) - printk ("OSS: Application error. Wrong ioctl call order.\n"); - sbpro_audio_set_speed (dev, devc->speed); - } - } - return devc->channels; + if (channels == 1 || channels == 2) + if (channels != devc->channels) + { + devc->channels = channels; + if (devc->model == MDL_SBPRO && devc->channels == 2) + { + if (devc->speed > 22050) + printk("OSS: Application error. Wrong ioctl call order.\n"); + sbpro_audio_set_speed(dev, devc->speed); + } + } + return devc->channels; } static int -jazz16_audio_set_speed (int dev, int speed) +jazz16_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - if (speed > 0) - { - int tmp; - int s = speed * devc->channels; - - if (speed < 5000) - speed = 4000; + if (speed > 0) + { + int tmp; + int s = speed * devc->channels; - if (speed > 44100) - speed = 44100; + if (speed < 5000) + speed = 4000; - devc->tconst = ((65536 - ((256000000 + s / 2) / - s)) >> 8) & 0xff; + if (speed > 44100) + speed = 44100; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; - devc->speed = speed; - } + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } /* @@ -587,620 +575,601 @@ */ static int -ess_audio_set_speed (int dev, int speed) +ess_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - int divider; + sb_devc *devc = audio_devs[dev]->devc; + int divider; - if (speed > 0) - { - if (speed < 5000) - speed = 4000; - - if (speed > 48000) - speed = 48000; + if (speed > 0) + { + if (speed < 5000) + speed = 4000; - if (speed > 22000) - { - divider = (795500 + speed / 2) / speed; - speed = (795500 + divider / 2) / divider; - } - else - { - divider = (397700 + speed / 2) / speed; - speed = (397700 + divider / 2) / divider; - } + if (speed > 48000) + speed = 48000; - devc->speed = speed; - } + if (speed > 22000) + { + divider = (795500 + speed / 2) / speed; + speed = (795500 + divider / 2) / divider; + } else + { + divider = (397700 + speed / 2) / speed; + speed = (397700 + divider / 2) / divider; + } - return devc->speed; + devc->speed = speed; + } + return devc->speed; } static void -ess_speed (sb_devc * devc) +ess_speed(sb_devc * devc) { - int divider; - unsigned char bits = 0; - int speed = devc->speed; - - if (speed < 4000) - speed = 4000; - else if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - } - else - { - divider = 128 - (397700 + speed / 2) / speed; - } + int divider; + unsigned char bits = 0; + int speed = devc->speed; + + if (speed < 4000) + speed = 4000; + else if (speed > 48000) + speed = 48000; - bits |= (unsigned char) divider; - ess_write (devc, 0xa1, bits); + if (speed > 22000) + { + bits = 0x80; + divider = 256 - (795500 + speed / 2) / speed; + } else + { + divider = 128 - (397700 + speed / 2) / speed; + } + + bits |= (unsigned char) divider; + ess_write(devc, 0xa1, bits); /* * Set filter divider register */ - speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ - divider = 256 - 7160000 / (speed * 82); - ess_write (devc, 0xa2, divider); + speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ + divider = 256 - 7160000 / (speed * 82); + ess_write(devc, 0xa2, divider); - return; + return; } static int -ess_audio_prepare_for_input (int dev, int bsize, int bcount) +ess_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - ess_speed (devc); - sb_dsp_command (devc, DSP_CMD_SPKOFF); + ess_speed(devc); + sb_dsp_command(devc, DSP_CMD_SPKOFF); - ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | - (3 - devc->channels)); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ - - if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { /* 8 bit mono */ - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (devc->bits == AFMT_U8) - { /* 8 bit stereo */ - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xbc); - } - } + ess_write(devc, 0xb8, 0x0e); /* Auto init DMA mode */ + ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0xd0); + } else + { /* 16 bit mono */ + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xf4); + } + } else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0x98); + } else + { /* 16 bit stereo */ + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xbc); + } + } - ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); - ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); + ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); + ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static int -ess_audio_prepare_for_output (int dev, int bsize, int bcount) +static int ess_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - sb_dsp_reset (devc); - ess_speed (devc); + sb_dsp_reset(devc); + ess_speed(devc); - ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ - ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | - (3 - devc->channels)); /* Mono/stereo */ - ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ - - if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { /* 8 bit mono */ - ess_write (devc, 0xb6, 0x80); - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (devc, 0xb6, 0x00); - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (devc->bits == AFMT_U8) - { /* 8 bit stereo */ - ess_write (devc, 0xb6, 0x80); - ess_write (devc, 0xb7, 0x51); - ess_write (devc, 0xb7, 0x98); + ess_write(devc, 0xb8, 4); /* Auto init DMA mode */ + ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write(devc, 0xb6, 0x80); + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0xd0); + } else + { /* 16 bit mono */ + ess_write(devc, 0xb6, 0x00); + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xf4); + } } - else - { /* 16 bit stereo */ - ess_write (devc, 0xb6, 0x00); - ess_write (devc, 0xb7, 0x71); - ess_write (devc, 0xb7, 0xbc); + else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write(devc, 0xb6, 0x80); + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write(devc, 0xb6, 0x00); + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xbc); + } } - } - ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); - ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); - sb_dsp_command (devc, DSP_CMD_SPKON); + ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); + ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); + sb_dsp_command(devc, DSP_CMD_SPKON); - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static void -ess_audio_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag) +static void ess_audio_output_block(int dev, unsigned long buf, int nr_bytes, + int intrflag) { - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; - devc->irq_mode = IMODE_OUTPUT; + devc->irq_mode = IMODE_OUTPUT; - ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + ess_write(devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write(devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x05); /* Go */ - devc->intr_active = 1; + ess_write(devc, 0xb8, ess_read(devc, 0xb8) | 0x05); /* Go */ + devc->intr_active = 1; } -static void -ess_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag) +static void ess_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - if (audio_devs[dev]->dmap_out->dma > 3) - count >>= 1; - count--; + if (audio_devs[dev]->dmap_out->dma > 3) + count >>= 1; + count--; - devc->irq_mode = IMODE_INPUT; + devc->irq_mode = IMODE_INPUT; - ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + ess_write(devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write(devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x0f); /* Go */ - devc->intr_active = 1; + ess_write(devc, 0xb8, ess_read(devc, 0xb8) | 0x0f); /* Go */ + devc->intr_active = 1; } -static void -ess_audio_trigger (int dev, int bits) +static void ess_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; + bits &= devc->irq_mode; - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else { - case IMODE_INPUT: - ess_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - ess_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; + switch (devc->irq_mode) + { + case IMODE_INPUT: + ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } } - } - devc->trigger_bits = bits; + devc->trigger_bits = bits; } /* * SB16 specific routines */ -static int -sb16_audio_set_speed (int dev, int speed) +static int sb16_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - - if (speed > 0) - { - if (speed < 5000) - speed = 4000; + sb_devc *devc = audio_devs[dev]->devc; - if (speed > 44100) - speed = 44100; + if (speed > 0) + { + if (speed < 5000) + speed = 4000; - devc->speed = speed; - } + if (speed > 44100) + speed = 44100; - return devc->speed; + devc->speed = speed; + } + return devc->speed; } -static unsigned int -sb16_audio_set_bits (int dev, unsigned int bits) +static unsigned int sb16_audio_set_bits(int dev, unsigned int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - if (bits != 0) - if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE) - devc->bits = bits; - else - devc->bits = AFMT_U8; + if (bits != 0) + { + if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE) + devc->bits = bits; + else + devc->bits = AFMT_U8; + } - return devc->bits; + return devc->bits; } -static int -sb16_audio_prepare_for_input (int dev, int bsize, int bcount) +static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static int -sb16_audio_prepare_for_output (int dev, int bsize, int bcount) +static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; - devc->trigger_bits = 0; - return 0; + devc->trigger_bits = 0; + return 0; } -static void -sb16_audio_output_block (int dev, unsigned long buf, int count, - int intrflag) +static void sb16_audio_output_block(int dev, unsigned long buf, int count, + int intrflag) { - unsigned long flags, cnt; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; - devc->irq_mode = IMODE_OUTPUT; - devc->intr_active = 1; + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ - sb_dsp_command (devc, 0x41); - sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); - sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + sb_dsp_command(devc, 0x41); + sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); - sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); - sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + - (devc->bits == AFMT_S16_LE ? 0x10 : 0))); - sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); - sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); + sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command(devc, (unsigned char) (cnt >> 8)); - restore_flags (flags); + restore_flags(flags); } -static void -sb16_audio_start_input (int dev, unsigned long buf, int count, int intrflag) +static void sb16_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags, cnt; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; - devc->irq_mode = IMODE_INPUT; - devc->intr_active = 1; + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; - cnt = count; - if (devc->bits == AFMT_S16_LE) - cnt >>= 1; - cnt--; + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ - sb_dsp_command (devc, 0x42); - sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); - sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + sb_dsp_command(devc, 0x42); + sb_dsp_command(devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command(devc, (unsigned char) (devc->speed & 0xff)); - sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); - sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + - (devc->bits == AFMT_S16_LE ? 0x10 : 0))); - sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); - sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + sb_dsp_command(devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); + sb_dsp_command(devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command(devc, (unsigned char) (cnt >> 8)); - restore_flags (flags); + restore_flags(flags); } -static void -sb16_audio_trigger (int dev, int bits) +static void sb16_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - bits &= devc->irq_mode; + bits &= devc->irq_mode; - if (!bits) - sb_dsp_command (devc, 0xd0); /* Halt DMA */ - else - { - switch (devc->irq_mode) + if (!bits) + sb_dsp_command(devc, 0xd0); /* Halt DMA */ + else { - case IMODE_INPUT: - sb16_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb16_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb16_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + sb16_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } } - } - devc->trigger_bits = bits; + devc->trigger_bits = bits; } -static int -sb_audio_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int sb_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static struct audio_driver sb1_audio_driver = /* SB1.x */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb1_audio_trigger, - sb1_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb1_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels }; static struct audio_driver sb20_audio_driver = /* SB2.0 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sb1_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels }; static struct audio_driver sb201_audio_driver = /* SB2.01 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb1_audio_prepare_for_input, - sb1_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sb201_audio_set_speed, - sb1_audio_set_bits, - sb1_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb201_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels }; static struct audio_driver sbpro_audio_driver = /* SB Pro */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sbpro_audio_prepare_for_input, - sbpro_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - sbpro_audio_set_speed, - sb1_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sbpro_audio_set_speed, + sb1_audio_set_bits, + sbpro_audio_set_channels }; static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sbpro_audio_prepare_for_input, - sbpro_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb20_audio_trigger, - jazz16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + jazz16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels }; static struct audio_driver sb16_audio_driver = /* SB16 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - sb16_audio_prepare_for_input, - sb16_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb16_audio_trigger, - sb16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb16_audio_prepare_for_input, + sb16_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb16_audio_trigger, + sb16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels }; static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - sb_audio_ioctl, - ess_audio_prepare_for_input, - ess_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - ess_audio_trigger, - ess_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + ess_audio_prepare_for_input, + ess_audio_prepare_for_output, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + ess_audio_trigger, + ess_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels }; -void -sb_audio_init (sb_devc * devc, char *name) +void sb_audio_init(sb_devc * devc, char *name) { - int audio_flags = 0; - int format_mask = AFMT_U8; + int audio_flags = 0; + int format_mask = AFMT_U8; - struct audio_driver *driver = &sb1_audio_driver; + struct audio_driver *driver = &sb1_audio_driver; - switch (devc->model) - { - case MDL_SB1: /* SB1.0 or SB 1.5 */ - DDB (printk ("Will use standard SB1.x driver\n")); - audio_flags = DMA_HARDSTOP; - break; - - case MDL_SB2: - DDB (printk ("Will use SB2.0 driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sb20_audio_driver; - break; - - case MDL_SB201: - DDB (printk ("Will use SB2.01 (high speed) driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sb201_audio_driver; - break; - - case MDL_JAZZ: - case MDL_SMW: - DDB (printk ("Will use Jazz16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &jazz16_audio_driver; - break; - - case MDL_ESS: - DDB (printk ("Will use ESS ES688/1688 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &ess_audio_driver; - break; - - case MDL_SB16: - DDB (printk ("Will use SB16 driver\n")); - audio_flags = DMA_AUTOMODE; - format_mask |= AFMT_S16_LE; - driver = &sb16_audio_driver; - break; - - default: - DDB (printk ("Will use SB Pro driver\n")); - audio_flags = DMA_AUTOMODE; - driver = &sbpro_audio_driver; - } - - if ((devc->my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, - name, - driver, - sizeof (struct audio_driver), - audio_flags, - format_mask, - devc, - devc->dma8, - devc->dma8)) < 0) - { - return; - } + switch (devc->model) + { + case MDL_SB1: /* SB1.0 or SB 1.5 */ + DDB(printk("Will use standard SB1.x driver\n")); + audio_flags = DMA_HARDSTOP; + break; + + case MDL_SB2: + DDB(printk("Will use SB2.0 driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb20_audio_driver; + break; + + case MDL_SB201: + DDB(printk("Will use SB2.01 (high speed) driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb201_audio_driver; + break; + + case MDL_JAZZ: + case MDL_SMW: + DDB(printk("Will use Jazz16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &jazz16_audio_driver; + break; + + case MDL_ESS: + DDB(printk("Will use ESS ES688/1688 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &ess_audio_driver; + break; + + case MDL_SB16: + DDB(printk("Will use SB16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &sb16_audio_driver; + break; + + default: + DDB(printk("Will use SB Pro driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sbpro_audio_driver; + } - audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev; - audio_devs[devc->my_dev]->min_fragment = 5; + if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + name, + driver, + sizeof(struct audio_driver), + audio_flags, + format_mask, + devc, + devc->dma8, + devc->dma8)) < 0) + { + printk(KERN_ERR "sb: unable to install audio.\n"); + return; + } + audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev; + audio_devs[devc->my_dev]->min_fragment = 5; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.1.66/linux/drivers/sound/sb_card.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb_card.c Sat Nov 29 10:33:21 1997 @@ -11,39 +11,150 @@ * for more info. */ #include +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_SBDSP +#if defined(CONFIG_SBDSP) || defined (MODULE) #include "sb_mixer.h" #include "sb.h" void -attach_sb_card (struct address_info *hw_config) +attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) - sb_dsp_init (hw_config); + sb_dsp_init(hw_config); #endif } int -probe_sb (struct address_info *hw_config) +probe_sb(struct address_info *hw_config) { - if (check_region (hw_config->io_base, 16)) - { - printk ("\n\nsb_dsp.c: I/O port %x already in use\n\n", hw_config->io_base); - return 0; - } + if (check_region(hw_config->io_base, 16)) + { + printk("\n\nsb_dsp.c: I/O port %x already in use\n\n", hw_config->io_base); + return 0; + } + return sb_dsp_detect(hw_config); +} + +void +unload_sb(struct address_info *hw_config) +{ + sb_dsp_unload(hw_config); +} + +#ifdef MODULE + +static struct address_info config; +static struct address_info config_mpu; + +/* + * Note DMA2 of -1 has the right meaning in the SB16 driver as well + * as here. It will cause either an error if it is needed or a fallback + * to the 8bit channel. + */ + +int mpu_io = 0; +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int sm_games = 0; /* Mixer - see sb_mixer.c */ +int acer = 0; /* Do acer notebook init */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(mad16, "i"); +MODULE_PARM(trix, "i"); +MODULE_PARM(pas2, "i"); +MODULE_PARM(sm_games, "i"); + +static int sbmpu = 0; + +void *smw_free = NULL; + +int +init_module(void) +{ + printk("Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - return sb_dsp_detect (hw_config); + if (mad16 == 0 && trix == 0 && pas2 == 0) + { + if (io == -1 || dma == -1 || irq == -1) + { + printk("I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; + config.card_subtype = type; + + if (!probe_sb(&config)) + return -ENODEV; + attach_sb_card(&config); +#ifdef CONFIG_MIDI + config_mpu.io_base = mpu_io; + if (mpu_io && probe_sbmpu(&config_mpu)) + sbmpu = 1; +#endif +#ifdef CONFIG_MIDI + if (sbmpu) + attach_sbmpu(&config_mpu); +#endif + } + SOUND_LOCK; + return 0; } void -unload_sb (struct address_info *hw_config) +cleanup_module(void) { - sb_dsp_unload (hw_config); + if (smw_free) + kfree(smw_free); + if (!mad16 && !trix && !pas2) + unload_sb(&config); + if (sbmpu) + unload_sbmpu(&config_mpu); + SOUND_LOCK_END; } +#else + +#ifdef SM_GAMES +int sm_games = 1; + +#else +int sm_games = 0; + #endif +#ifdef SB_ACER +int acer = 1; + +#else +int acer = 0; + +#endif +#endif +#endif + +EXPORT_SYMBOL(sb_dsp_init); +EXPORT_SYMBOL(sb_dsp_detect); +EXPORT_SYMBOL(sb_dsp_unload); +EXPORT_SYMBOL(sb_dsp_disable_midi); +EXPORT_SYMBOL(attach_sb_card); +EXPORT_SYMBOL(probe_sb); +EXPORT_SYMBOL(unload_sb); diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.66/linux/drivers/sound/sb_common.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb_common.c Sat Nov 29 10:33:21 1997 @@ -14,8 +14,9 @@ #include "sound_config.h" +#include "sound_firmware.h" -#ifdef CONFIG_SBDSP +#if defined(CONFIG_SBDSP) || defined(MODULE) #ifndef CONFIG_AUDIO #error You will need to configure the sound driver with CONFIG_AUDIO option. @@ -54,830 +55,838 @@ int -sb_dsp_command (sb_devc * devc, unsigned char val) +sb_dsp_command(sb_devc * devc, unsigned char val) { - int i; - unsigned long limit; + int i; + unsigned long limit; - limit = jiffies + HZ / 10; /* Timeout */ - /* - * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb (DSP_STATUS) & 0x80) == 0) - { - outb ((val), DSP_COMMAND); - return 1; - } - } + limit = jiffies + HZ / 10; /* Timeout */ + /* + * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 500000 && jiffies < limit; i++) + { + if ((inb(DSP_STATUS) & 0x80) == 0) + { + outb((val), DSP_COMMAND); + return 1; + } + } - printk ("Sound Blaster: DSP Command(%x) Timeout.\n", val); - return 0; + printk("Sound Blaster: DSP Command(%x) Timeout.\n", val); + return 0; } static int -sb_dsp_get_byte (sb_devc * devc) +sb_dsp_get_byte(sb_devc * devc) { - int i; + int i; - for (i = 1000; i; i--) - if (inb (DSP_DATA_AVAIL) & 0x80) - { - return inb (DSP_READ); - } - - return 0xffff; + for (i = 1000; i; i--) + if (inb(DSP_DATA_AVAIL) & 0x80) + { + return inb(DSP_READ); + } + return 0xffff; } int -ess_write (sb_devc * devc, unsigned char reg, unsigned char data) +ess_write(sb_devc * devc, unsigned char reg, unsigned char data) { - /* Write a byte to an extended mode register of ES1688 */ + /* Write a byte to an extended mode register of ES1688 */ - if (!sb_dsp_command (devc, reg)) - return 0; + if (!sb_dsp_command(devc, reg)) + return 0; - return sb_dsp_command (devc, data); + return sb_dsp_command(devc, data); } int -ess_read (sb_devc * devc, unsigned char reg) +ess_read(sb_devc * devc, unsigned char reg) { /* Read a byte from an extended mode register of ES1688 */ - if (!sb_dsp_command (devc, 0xc0)) /* Read register command */ - return -1; + if (!sb_dsp_command(devc, 0xc0)) /* Read register command */ + return -1; - if (!sb_dsp_command (devc, reg)) - return -1; + if (!sb_dsp_command(devc, reg)) + return -1; - return sb_dsp_get_byte (devc); + return sb_dsp_get_byte(devc); } static void -sbintr (int irq, void *dev_id, struct pt_regs *dummy) +sbintr(int irq, void *dev_id, struct pt_regs *dummy) { - int status; - unsigned char src = 0xff; - - sb_devc *devc = irq2devc[irq]; + int status; + unsigned char src = 0xff; - if (devc == NULL || devc->irq != irq) - { - DEB (printk ("sbintr: Bogus interrupt IRQ%d\n", irq)); - return; - } + sb_devc *devc = irq2devc[irq]; - devc->irq_ok = 1; + if (devc == NULL || devc->irq != irq) + { + DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq)); + return; + } + devc->irq_ok = 1; - if (devc->model == MDL_SB16) - { + if (devc->model == MDL_SB16) + { - src = sb_getmixer (devc, IRQ_STAT); /* Interrupt source register */ + src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - if (src & 4) - uart401intr (devc->irq, NULL, NULL); /* MPU401 interrupt */ +#if defined(CONFIG_MIDI)&& (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + if (src & 4) + uart401intr(devc->irq, NULL, NULL); /* MPU401 interrupt */ #endif - if (!(src & 3)) - return; /* Not a DSP interrupt */ - } - - if (devc->intr_active) - switch (devc->irq_mode) - { - case IMODE_OUTPUT: - DMAbuf_outputintr (devc->dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr (devc->dev); - break; - - case IMODE_INIT: - break; - - case IMODE_MIDI: -#ifdef CONFIG_MIDI - sb_midi_interrupt (devc); + if (!(src & 3)) + return; /* Not a DSP interrupt */ + } + if (devc->intr_active) + switch (devc->irq_mode) + { + case IMODE_OUTPUT: + DMAbuf_outputintr(devc->dev, 1); + break; + + case IMODE_INPUT: + DMAbuf_inputintr(devc->dev); + break; + + case IMODE_INIT: + break; + + case IMODE_MIDI: +#if defined(CONFIG_MIDI) + sb_midi_interrupt(devc); #endif - break; + break; - default: - /* printk( "Sound Blaster: Unexpected interrupt\n"); */ - ; - } + default: + /* printk( "Sound Blaster: Unexpected interrupt\n"); */ + ; + } /* * Acknowledge interrupts */ - if (src & 0x01) - status = inb (DSP_DATA_AVAIL); + if (src & 0x01) + status = inb(DSP_DATA_AVAIL); - if (devc->model == MDL_SB16 && src & 0x02) - status = inb (DSP_DATA_AVL16); + if (devc->model == MDL_SB16 && src & 0x02) + status = inb(DSP_DATA_AVL16); } int -sb_dsp_reset (sb_devc * devc) +sb_dsp_reset(sb_devc * devc) { - int loopc; + int loopc; - DEB (printk ("Entered sb_dsp_reset()\n")); + DEB(printk("Entered sb_dsp_reset()\n")); - if (devc->model == MDL_ESS) - outb ((3), DSP_RESET); /* Reset FIFO too */ - else - outb ((1), DSP_RESET); + if (devc->model == MDL_ESS) + outb((3), DSP_RESET); /* Reset FIFO too */ + else + outb((1), DSP_RESET); - tenmicrosec (devc->osp); - outb ((0), DSP_RESET); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); + tenmicrosec(devc->osp); + outb((0), DSP_RESET); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); - for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); + for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++); - if (inb (DSP_READ) != 0xAA) - { - DDB (printk ("sb: No response to RESET\n")); - return 0; /* Sorry */ - } - - if (devc->model == MDL_ESS) - sb_dsp_command (devc, 0xc6); /* Enable extended mode */ + if (inb(DSP_READ) != 0xAA) + { + DDB(printk("sb: No response to RESET\n")); + return 0; /* Sorry */ + } + if (devc->model == MDL_ESS) + sb_dsp_command(devc, 0xc6); /* Enable extended mode */ - DEB (printk ("sb_dsp_reset() OK\n")); - return 1; + DEB(printk("sb_dsp_reset() OK\n")); + return 1; } static void -dsp_get_vers (sb_devc * devc) +dsp_get_vers(sb_devc * devc) { - int i; + int i; - unsigned long flags; + unsigned long flags; - DDB (printk ("Entered dsp_get_vers()\n")); - save_flags (flags); - cli (); - devc->major = devc->minor = 0; - sb_dsp_command (devc, 0xe1); /* Get version */ + DDB(printk("Entered dsp_get_vers()\n")); + save_flags(flags); + cli(); + devc->major = devc->minor = 0; + sb_dsp_command(devc, 0xe1); /* Get version */ - for (i = 100000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { - if (devc->major == 0) - devc->major = inb (DSP_READ); - else - { - devc->minor = inb (DSP_READ); - break; - } - } - } - DDB (printk ("DSP version %d.%d\n", devc->major, devc->minor)); - restore_flags (flags); + for (i = 100000; i; i--) + { + if (inb(DSP_DATA_AVAIL) & 0x80) + { + if (devc->major == 0) + devc->major = inb(DSP_READ); + else + { + devc->minor = inb(DSP_READ); + break; + } + } + } + DDB(printk("DSP version %d.%d\n", devc->major, devc->minor)); + restore_flags(flags); } static int -sb16_set_dma_hw (sb_devc * devc) +sb16_set_dma_hw(sb_devc * devc) { - int bits; + int bits; - if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) - { - printk ("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); - return 0; - } - - bits = (1 << devc->dma8); + if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) + { + printk("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); + return 0; + } + bits = (1 << devc->dma8); - if (devc->dma16 >= 5 && devc->dma16 <= 7) - bits |= (1 << devc->dma16); + if (devc->dma16 >= 5 && devc->dma16 <= 7) + bits |= (1 << devc->dma16); - sb_setmixer (devc, DMA_NR, bits); - return 1; + sb_setmixer(devc, DMA_NR, bits); + return 1; } #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) static void -sb16_set_mpu_port (sb_devc * devc, struct address_info *hw_config) +sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) { /* * This routine initializes new MIDI port setup register of SB Vibra (CT2502). */ - unsigned char bits = sb_getmixer (devc, 0x84) & ~0x06; + unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; - switch (hw_config->io_base) - { - case 0x300: - sb_setmixer (devc, 0x84, bits | 0x04); - break; - - case 0x330: - sb_setmixer (devc, 0x84, bits | 0x00); - break; - - default: - sb_setmixer (devc, 0x84, bits | 0x02); /* Disable MPU */ - printk ("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); - } + switch (hw_config->io_base) + { + case 0x300: + sb_setmixer(devc, 0x84, bits | 0x04); + break; + + case 0x330: + sb_setmixer(devc, 0x84, bits | 0x00); + break; + + default: + sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ + printk("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); + } } #endif static int -sb16_set_irq_hw (sb_devc * devc, int level) +sb16_set_irq_hw(sb_devc * devc, int level) { - int ival; + int ival; - switch (level) - { - case 5: - ival = 2; - break; - case 7: - ival = 4; - break; - case 9: - ival = 1; - break; - case 10: - ival = 8; - break; - default: - printk ("SB16 IRQ%d is not possible\n", level); - return 0; - } - sb_setmixer (devc, IRQ_NR, ival); - return 1; + switch (level) + { + case 5: + ival = 2; + break; + case 7: + ival = 4; + break; + case 9: + ival = 1; + break; + case 10: + ival = 8; + break; + default: + printk("SB16 IRQ%d is not possible\n", level); + return 0; + } + sb_setmixer(devc, IRQ_NR, ival); + return 1; } static void -relocate_Jazz16 (sb_devc * devc, struct address_info *hw_config) +relocate_Jazz16(sb_devc * devc, struct address_info *hw_config) { - unsigned char bits = 0; - unsigned long flags; + unsigned char bits = 0; + unsigned long flags; - if (jazz16_base != 0 && jazz16_base != hw_config->io_base) - return; + if (jazz16_base != 0 && jazz16_base != hw_config->io_base) + return; - switch (hw_config->io_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - - default: - return; - } + switch (hw_config->io_base) + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + + default: + return; + } - bits = jazz16_bits = bits << 5; + bits = jazz16_bits = bits << 5; - jazz16_base = hw_config->io_base; + jazz16_base = hw_config->io_base; /* * Magic wake up sequence by writing to 0x201 (aka Joystick port) */ - save_flags (flags); - cli (); - outb ((0xAF), 0x201); - outb ((0x50), 0x201); - outb ((bits), 0x201); - restore_flags (flags); + save_flags(flags); + cli(); + outb((0xAF), 0x201); + outb((0x50), 0x201); + outb((bits), 0x201); + restore_flags(flags); } static int -init_Jazz16 (sb_devc * devc, struct address_info *hw_config) +init_Jazz16(sb_devc * devc, struct address_info *hw_config) { - char name[100]; + char name[100]; /* * First try to check that the card has Jazz16 chip. It identifies itself * by returning 0x12 as response to DSP command 0xfa. */ - if (!sb_dsp_command (devc, 0xfa)) - return 0; + if (!sb_dsp_command(devc, 0xfa)) + return 0; - if (sb_dsp_get_byte (devc) != 0x12) - return 0; + if (sb_dsp_get_byte(devc) != 0x12) + return 0; /* * OK so far. Now configure the IRQ and DMA channel used by the card. */ - if (hw_config->irq < 1 || hw_config->irq > 15 || - jazz_irq_bits[hw_config->irq] == 0) - { - printk ("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); - return 0; - } - - if (hw_config->dma < 0 || hw_config->dma > 3 || - jazz_dma_bits[hw_config->dma] == 0) - { - printk ("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); - return 0; - } - - if (hw_config->dma2 < 0) - { - printk ("Jazz16: No 16 bit DMA channel defined\n"); - return 0; - } - - if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || - jazz_dma_bits[hw_config->dma2] == 0) - { - printk ("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); - return 0; - } - - devc->dma16 = hw_config->dma2; - - if (!sb_dsp_command (devc, 0xfb)) - return 0; - - if (!sb_dsp_command (devc, jazz_dma_bits[hw_config->dma] | - (jazz_dma_bits[hw_config->dma2] << 4))) - return 0; + if (hw_config->irq < 1 || hw_config->irq > 15 || + jazz_irq_bits[hw_config->irq] == 0) + { + printk("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); + return 0; + } + if (hw_config->dma < 0 || hw_config->dma > 3 || + jazz_dma_bits[hw_config->dma] == 0) + { + printk("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); + return 0; + } + if (hw_config->dma2 < 0) + { + printk("Jazz16: No 16 bit DMA channel defined\n"); + return 0; + } + if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || + jazz_dma_bits[hw_config->dma2] == 0) + { + printk("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); + return 0; + } + devc->dma16 = hw_config->dma2; + + if (!sb_dsp_command(devc, 0xfb)) + return 0; - if (!sb_dsp_command (devc, jazz_irq_bits[hw_config->irq])) - return 0; + if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] | + (jazz_dma_bits[hw_config->dma2] << 4))) + return 0; + + if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq])) + return 0; /* * Now we have configured a standard Jazz16 device. */ - devc->model = MDL_JAZZ; - strcpy (name, "Jazz16"); + devc->model = MDL_JAZZ; + strcpy(name, "Jazz16"); - hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1))); - sound_mem_sizes[sound_nblocks] = strlen (name + 1); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (hw_config->name != NULL) - strcpy (hw_config->name, name); - devc->caps |= SB_NO_MIDI; - return 1; + hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc(strlen(name + 1))); + sound_mem_sizes[sound_nblocks] = strlen(name + 1); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy(hw_config->name, name); + devc->caps |= SB_NO_MIDI; + return 1; } static void -relocate_ess1688 (sb_devc * devc) +relocate_ess1688(sb_devc * devc) { - unsigned char bits; + unsigned char bits; - switch (devc->base) - { - case 0x220: - bits = 0x04; - break; - case 0x230: - bits = 0x05; - break; - case 0x240: - bits = 0x06; - break; - case 0x250: - bits = 0x07; - break; - default: - return; /* Wrong port */ - } + switch (devc->base) + { + case 0x220: + bits = 0x04; + break; + case 0x230: + bits = 0x05; + break; + case 0x240: + bits = 0x06; + break; + case 0x250: + bits = 0x07; + break; + default: + return; /* Wrong port */ + } - DDB (printk ("Doing ESS1688 address selection\n")); + DDB(printk("Doing ESS1688 address selection\n")); /* * ES1688 supports two alternative ways for software address config. * First try the so called Read-Sequence-Key method. */ - /* Reset the sequence logic */ - inb (0x229); - inb (0x229); - inb (0x229); - - /* Perform the read sequence */ - inb (0x22b); - inb (0x229); - inb (0x22b); - inb (0x229); - inb (0x229); - inb (0x22b); - inb (0x229); - - /* Select the base address by reading from it. Then probe using the port. */ - inb (devc->base); - if (sb_dsp_reset (devc)) /* Bingo */ - return; + /* Reset the sequence logic */ + inb(0x229); + inb(0x229); + inb(0x229); + + /* Perform the read sequence */ + inb(0x22b); + inb(0x229); + inb(0x22b); + inb(0x229); + inb(0x229); + inb(0x22b); + inb(0x229); + + /* Select the base address by reading from it. Then probe using the port. */ + inb(devc->base); + if (sb_dsp_reset(devc)) /* Bingo */ + return; #if 0 /* This causes system lockups (Nokia 386/25 at least) */ /* * The last resort is the system control register method. */ - outb ((0x00), 0xfb); /* 0xFB is the unlock register */ - outb ((0x00), 0xe0); /* Select index 0 */ - outb ((bits), 0xe1); /* Write the config bits */ - outb ((0x00), 0xf9); /* 0xFB is the lock register */ + outb((0x00), 0xfb); /* 0xFB is the unlock register */ + outb((0x00), 0xe0); /* Select index 0 */ + outb((bits), 0xe1); /* Write the config bits */ + outb((0x00), 0xf9); /* 0xFB is the lock register */ #endif } static int -ess_init (sb_devc * devc, struct address_info *hw_config) +ess_init(sb_devc * devc, struct address_info *hw_config) { - unsigned char cfg, irq_bits = 0, dma_bits = 0; - int ess_major = 0, ess_minor = 0; - int i; - char name[100]; + unsigned char cfg, irq_bits = 0, dma_bits = 0; + int ess_major = 0, ess_minor = 0; + int i; + char name[100]; /* * Try to detect ESS chips. */ - sb_dsp_command (devc, 0xe7); /* Return identification */ + sb_dsp_command(devc, 0xe7); /* Return identification */ - for (i = 1000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { - if (ess_major == 0) - ess_major = inb (DSP_READ); - else - { - ess_minor = inb (DSP_READ); - break; - } - } - } + for (i = 1000; i; i--) + { + if (inb(DSP_DATA_AVAIL) & 0x80) + { + if (ess_major == 0) + ess_major = inb(DSP_READ); + else + { + ess_minor = inb(DSP_READ); + break; + } + } + } + + if (ess_major == 0) + return 0; + + if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) + { + sprintf(name, "ESS ES488 AudioDrive (rev %d)", + ess_minor & 0x0f); + hw_config->name = name; + devc->model = MDL_SBPRO; + return 1; + } else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) + { + char *chip = "ES688"; - if (ess_major == 0) - return 0; + if ((ess_minor & 0x0f) >= 8) + chip = "ES1688"; - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) - { - sprintf (name, "ESS ES488 AudioDrive (rev %d)", - ess_minor & 0x0f); - hw_config->name = name; - devc->model = MDL_SBPRO; - return 1; - } - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) - { - char *chip = "ES688"; - - if ((ess_minor & 0x0f) >= 8) - chip = "ES1688"; - - sprintf (name, - "ESS %s AudioDrive (rev %d)", - chip, ess_minor & 0x0f); - } - else - strcpy (name, "Jazz16"); - - devc->model = MDL_ESS; - devc->submodel = ess_minor & 0x0f; - - hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1))); - sound_mem_sizes[sound_nblocks] = strlen (name + 1); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (hw_config->name != NULL) - strcpy (hw_config->name, name); + sprintf(name, + "ESS %s AudioDrive (rev %d)", + chip, ess_minor & 0x0f); + } else + strcpy(name, "Jazz16"); + devc->model = MDL_ESS; + devc->submodel = ess_minor & 0x0f; - sb_dsp_reset (devc); /* Turn on extended mode */ + hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc(strlen(name + 1))); + sound_mem_sizes[sound_nblocks] = strlen(name + 1); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy(hw_config->name, name); + + + sb_dsp_reset(devc); /* Turn on extended mode */ /* * Set IRQ configuration register */ - cfg = 0x50; /* Enable only DMA counter interrupt */ + cfg = 0x50; /* Enable only DMA counter interrupt */ - switch (devc->irq) - { - case 2: - case 9: - irq_bits = 0; - break; - - case 5: - irq_bits = 1; - break; - - case 7: - irq_bits = 2; - break; - - case 10: - irq_bits = 3; - break; - - default: - irq_bits = 0; - cfg = 0x10; /* Disable all interrupts */ - printk ("\nESS1688: Invalid IRQ %d\n", devc->irq); - return 0; - } + switch (devc->irq) + { + case 2: + case 9: + irq_bits = 0; + break; + + case 5: + irq_bits = 1; + break; + + case 7: + irq_bits = 2; + break; + + case 10: + irq_bits = 3; + break; + + default: + irq_bits = 0; + cfg = 0x10; /* Disable all interrupts */ + printk("\nESS1688: Invalid IRQ %d\n", devc->irq); + return 0; + } - if (!ess_write (devc, 0xb1, cfg | (irq_bits << 2))) - printk ("\nESS1688: Failed to write to IRQ config register\n"); + if (!ess_write(devc, 0xb1, cfg | (irq_bits << 2))) + printk("\nESS1688: Failed to write to IRQ config register\n"); /* * Set DMA configuration register */ - cfg = 0x50; /* Extended mode DMA enable */ + cfg = 0x50; /* Extended mode DMA enable */ - if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2) - { - dma_bits = 0; - cfg = 0x00; /* Disable all DMA */ - printk ("\nESS1688: Invalid DMA %d\n", devc->dma8); - } - else - { - if (devc->dma8 == 3) - dma_bits = 3; - else - dma_bits = devc->dma8 + 1; - } + if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2) + { + dma_bits = 0; + cfg = 0x00; /* Disable all DMA */ + printk("\nESS1688: Invalid DMA %d\n", devc->dma8); + } else + { + if (devc->dma8 == 3) + dma_bits = 3; + else + dma_bits = devc->dma8 + 1; + } - if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) - printk ("\nESS1688: Failed to write to DMA config register\n"); + if (!ess_write(devc, 0xb2, cfg | (dma_bits << 2))) + printk("\nESS1688: Failed to write to DMA config register\n"); /* * Enable joystick and OPL3 */ - cfg = sb_getmixer (devc, 0x40); - sb_setmixer (devc, 0x40, cfg | 0x03); - if (devc->submodel >= 8) /* ES1688 */ - devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ - sb_dsp_reset (devc); - return 1; + cfg = sb_getmixer(devc, 0x40); + sb_setmixer(devc, 0x40, cfg | 0x03); + if (devc->submodel >= 8) /* ES1688 */ + devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ + sb_dsp_reset(devc); + return 1; } int -sb_dsp_detect (struct address_info *hw_config) +sb_dsp_detect(struct address_info *hw_config) { - sb_devc sb_info; - sb_devc *devc = &sb_info; + sb_devc sb_info; + sb_devc *devc = &sb_info; + sb_info.my_mididev = -1; + sb_info.my_mixerdev = -1; + sb_info.my_dev = -1; /* * Initialize variables */ - DDB (printk ("sb_dsp_detect(%x) entered\n", hw_config->io_base)); - if (check_region (hw_config->io_base, 16)) - return 0; - - memset ((char *) &sb_info, 0, sizeof (sb_info)); /* Zero everything */ + DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base)); + if (check_region(hw_config->io_base, 16)) + { +#ifdef MODULE + printk("sb: I/O region in use.\n"); +#endif + return 0; + } + memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ - devc->type = hw_config->card_subtype; + devc->type = hw_config->card_subtype; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma8 = hw_config->dma; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma8 = hw_config->dma; - devc->dma16 = -1; + devc->dma16 = -1; + if (acer) + { + cli(); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x00); + sti(); + } /* * Detect the device */ - if (sb_dsp_reset (devc)) - dsp_get_vers (devc); - else - devc->major = 0; - - if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) - if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) - relocate_Jazz16 (devc, hw_config); - - if (devc->major == 0 && (devc->type == MDL_ESS || devc->type == 0)) - relocate_ess1688 (devc); - - if (!sb_dsp_reset (devc)) - { - DDB (printk ("SB reset failed\n")); - return 0; - } - - if (devc->major == 0) - dsp_get_vers (devc); - - if (devc->major == 3 && devc->minor == 1) - { - if (devc->type == MDL_AZTECH) /* SG Washington? */ - { - if (sb_dsp_command (devc, 0x09)) - if (sb_dsp_command (devc, 0x00)) /* Enter WSS mode */ - { - int i; - - /* Have some delay */ - for (i = 0; i < 10000; i++) - inb (DSP_DATA_AVAIL); - devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ - devc->model = MDL_AZTECH; - } - } - } + if (sb_dsp_reset(devc)) + dsp_get_vers(devc); + else + devc->major = 0; + + if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) + if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) + relocate_Jazz16(devc, hw_config); + + if (devc->major == 0 && (devc->type == MDL_ESS || devc->type == 0)) + relocate_ess1688(devc); + + if (!sb_dsp_reset(devc)) + { + DDB(printk("SB reset failed\n")); +#ifdef MODULE + printk("sb: dsp reset failed.\n"); +#endif + return 0; + } + if (devc->major == 0) + dsp_get_vers(devc); + if (devc->major == 3 && devc->minor == 1) + { + if (devc->type == MDL_AZTECH) /* SG Washington? */ + { + if (sb_dsp_command(devc, 0x09)) + if (sb_dsp_command(devc, 0x00)) /* Enter WSS mode */ + { + int i; + + /* Have some delay */ + for (i = 0; i < 10000; i++) + inb(DSP_DATA_AVAIL); + devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ + devc->model = MDL_AZTECH; + } + } + } /* * Save device information for sb_dsp_init() */ - detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (sb_devc))); - sound_mem_sizes[sound_nblocks] = sizeof (sb_devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - - if (detected_devc == NULL) - { - printk ("sb: Can't allocate memory for device information\n"); - return 0; - } + detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(sb_devc))); + sound_mem_sizes[sound_nblocks] = sizeof(sb_devc); + if (sound_nblocks < 1024) + sound_nblocks++;; - memcpy ((char *) detected_devc, (char *) devc, sizeof (sb_devc)); + if (detected_devc == NULL) + { + printk(KERN_ERR "sb: Can't allocate memory for device information\n"); + return 0; + } + memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc)); - DDB (printk ("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); - return 1; + MDB(printk("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); + return 1; } void -sb_dsp_init (struct address_info *hw_config) +sb_dsp_init(struct address_info *hw_config) { - sb_devc *devc; - char name[100]; - extern int sb_be_quiet; + sb_devc *devc; + char name[100]; + extern int sb_be_quiet; /* * Check if we had detected a SB device earlier */ - DDB (printk ("sb_dsp_init(%x) entered\n", hw_config->io_base)); - name[0] = 0; + DDB(printk("sb_dsp_init(%x) entered\n", hw_config->io_base)); + name[0] = 0; - if (detected_devc == NULL) - { - DDB (printk ("No detected device\n")); - return; - } - - - devc = detected_devc; - detected_devc = NULL; - - if (devc->base != hw_config->io_base) - { - DDB (printk ("I/O port mismatch\n")); - return; - } + if (detected_devc == NULL) + { + MDB(printk("No detected device\n")); + return; + } + devc = detected_devc; + detected_devc = NULL; + if (devc->base != hw_config->io_base) + { + DDB(printk("I/O port mismatch\n")); + return; + } /* * Now continue initialization of the device */ - devc->dev = num_audiodevs; - devc->caps = hw_config->driver_use_1; - - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && - hw_config->irq > 0) - { /* IRQ setup */ - if (snd_set_irq_handler (hw_config->irq, - sbintr, "soundblaster", devc->osp) < 0) - { - printk ("SB: Can't allocate IRQ%d\n", hw_config->irq); - return; - } - - irq2devc[hw_config->irq] = devc; - devc->irq_ok = 0; - - if (devc->major == 4) - if (!sb16_set_irq_hw (devc, devc->irq)) /* Unsupported IRQ */ + devc->dev = sound_alloc_audiodev(); + if (devc->dev == -1) { - snd_release_irq (devc->irq); - irq2devc[hw_config->irq] = NULL; - return; - } - - if ((devc->type == 0 || devc->type == MDL_ESS) && - devc->major == 3 && devc->minor == 1) - { /* Handle various chipsets which claim they are SB Pro compatible */ - if ((devc->type != 0 && devc->type != MDL_ESS) || - !ess_init (devc, hw_config)) - if ((devc->type != 0 && devc->type != MDL_JAZZ && - devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config)) - { - DDB (printk ("This is a genuine SB Pro\n")); - } - } + printk(KERN_WARNING "sb: too many audio devices.\n"); + return; + } + devc->caps = hw_config->driver_use_1; + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && + hw_config->irq > 0) + { /* IRQ setup */ + if (snd_set_irq_handler(hw_config->irq, + sbintr, "soundblaster", devc->osp) < 0) + { + printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); + sound_unload_audiodev(devc->dev); + return; + } + irq2devc[hw_config->irq] = devc; + devc->irq_ok = 0; + + if (devc->major == 4) + if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ + { + snd_release_irq(devc->irq); + sound_unload_audiodev(devc->dev); + irq2devc[hw_config->irq] = NULL; + return; + } + if ((devc->type == 0 || devc->type == MDL_ESS) && + devc->major == 3 && devc->minor == 1) + { /* Handle various chipsets which claim they are SB Pro compatible */ + if ((devc->type != 0 && devc->type != MDL_ESS) || + !ess_init(devc, hw_config)) + if ((devc->type != 0 && devc->type != MDL_JAZZ && + devc->type != MDL_SMW) || !init_Jazz16(devc, hw_config)) + { + DDB(printk("This is a genuine SB Pro\n")); + } + } #if defined(__SMP__) || defined(__FreeBSD__) - /* Skip IRQ detection if SMP (doesn't work) */ - devc->irq_ok = 1; + /* Skip IRQ detection if SMP (doesn't work) */ + devc->irq_ok = 1; #else - if (devc->major == 4 && devc->minor <= 11) /* Won't work */ - devc->irq_ok = 1; - else - { - int n; - - for (n = 0; n < 3 && devc->irq_ok == 0; n++) - if (sb_dsp_command (devc, 0xf2)) /* Cause interrupt immediately */ - { - int i; - - for (i = 0; !devc->irq_ok && i < 10000; i++); - } - - if (!devc->irq_ok) - { - printk ("sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); - } - else - { - DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq)); - } - - } -#endif /* __SMP__ */ - } /* IRQ setup */ - - request_region (hw_config->io_base, 16, "soundblaster"); + if (devc->major == 4 && devc->minor <= 11) /* Won't work */ + devc->irq_ok = 1; + else + { + int n; + + for (n = 0; n < 3 && devc->irq_ok == 0; n++) + if (sb_dsp_command(devc, 0xf2)) /* Cause interrupt immediately */ + { + int i; + + for (i = 0; !devc->irq_ok && i < 10000; i++); + } + if (!devc->irq_ok) + { + printk("sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); + } else + { + DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq)); + } + + } +#endif /* __SMP__ */ + } /* IRQ setup */ + request_region(hw_config->io_base, 16, "soundblaster"); - switch (devc->major) - { - case 1: /* SB 1.0 or 1.5 */ - devc->model = hw_config->card_subtype = MDL_SB1; - break; - - case 2: /* SB 2.x */ - if (devc->minor == 0) - devc->model = hw_config->card_subtype = MDL_SB2; - else - devc->model = hw_config->card_subtype = MDL_SB201; - break; - - case 3: /* SB Pro and most clones */ - if (devc->model == 0) - { - devc->model = hw_config->card_subtype = MDL_SBPRO; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; - } - break; + switch (devc->major) + { + case 1: /* SB 1.0 or 1.5 */ + devc->model = hw_config->card_subtype = MDL_SB1; + break; + + case 2: /* SB 2.x */ + if (devc->minor == 0) + devc->model = hw_config->card_subtype = MDL_SB2; + else + devc->model = hw_config->card_subtype = MDL_SB201; + break; + + case 3: /* SB Pro and most clones */ + if (devc->model == 0) + { + devc->model = hw_config->card_subtype = MDL_SBPRO; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; + } + break; + + case 4: + devc->model = hw_config->card_subtype = MDL_SB16; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster 16"; + + if (hw_config->dma2 == -1) + devc->dma16 = devc->dma8; + else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) + { + printk("SB16: Bad or missing 16 bit DMA channel\n"); + devc->dma16 = devc->dma8; + } else + devc->dma16 = hw_config->dma2; - case 4: - devc->model = hw_config->card_subtype = MDL_SB16; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16"; - - if (hw_config->dma2 == -1) - devc->dma16 = devc->dma8; - else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) - { - printk ("SB16: Bad or missing 16 bit DMA channel\n"); - devc->dma16 = devc->dma8; - } - else - devc->dma16 = hw_config->dma2; + sb16_set_dma_hw(devc); + devc->caps |= SB_NO_MIDI; + } - sb16_set_dma_hw (devc); - devc->caps |= SB_NO_MIDI; - } - - if (!(devc->caps & SB_NO_MIXER)) - if (devc->major == 3 || devc->major == 4) - sb_mixer_init (devc); - -#ifdef CONFIG_MIDI - if (!(devc->caps & SB_NO_MIDI)) - sb_dsp_midi_init (devc); + if (!(devc->caps & SB_NO_MIXER)) + if (devc->major == 3 || devc->major == 4) + sb_mixer_init(devc); + +#if defined(CONFIG_MIDI) + if (!(devc->caps & SB_NO_MIDI)) + sb_dsp_midi_init(devc); #endif - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; - sprintf (name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); - conf_printf (name, hw_config); + sprintf(name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); + conf_printf(name, hw_config); /* * Assuming that a soundcard is Sound Blaster (compatible) is the most common @@ -886,84 +895,86 @@ * used in Unix. See Readme.cards for more information about configuring OSS/Free * properly. */ - if (devc->model <= MDL_SBPRO) - if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1 (rare ones may have 3.2). */ - { - printk ("This soundcard may not be fully Sound Blaster Pro compatible.\n"); - printk ("In many cases there is another way to configure OSS so that\n"); - printk ("it works properly with OSS (for example in 16 bit mode).\n"); - printk ("Please ignore this message if you _really_ have a SB Pro.\n"); - } - else if (!sb_be_quiet && devc->model == MDL_SBPRO) - { - printk ("SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); - printk ("several years old (8 bit only device)\n"); - printk ("or alternatively the sound driver is incorrectly configured.\n"); - } - - hw_config->card_subtype = devc->model; - last_devc = devc; /* For SB MPU detection */ - - if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) - { - if (sound_alloc_dma (devc->dma8, "SoundBlaster8")) - { - printk ("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); - } - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - if (sound_alloc_dma (devc->dma16, "SoundBlaster16")) + if (devc->model <= MDL_SBPRO) + if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1 (rare ones may have 3.2). */ + { + printk("This soundcard may not be fully Sound Blaster Pro compatible.\n"); + printk("In many cases there is another way to configure OSS so that\n"); + printk("it works properly with OSS (for example in 16 bit mode).\n"); + printk("Please ignore this message if you _really_ have a SB Pro.\n"); + } else if (!sb_be_quiet && devc->model == MDL_SBPRO) + { + printk("SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); + printk("several years old (8 bit only device)\n"); + printk("or alternatively the sound driver is incorrectly configured.\n"); + } + hw_config->card_subtype = devc->model; + last_devc = devc; /* For SB MPU detection */ + + if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) + { + if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) + { + printk("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); + } + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) + { + printk("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + } + sb_audio_init(devc, name); + } else { - printk ("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + MDB(printk("sb: No audio devices found.\n")); } - sb_audio_init (devc, name); - } } void -sb_dsp_disable_midi (int io_base) +sb_dsp_disable_midi(int io_base) { } void -sb_dsp_disable_recording (int io_base) +sb_dsp_disable_recording(int io_base) { } void -sb_dsp_unload (struct address_info *hw_config) +sb_dsp_unload(struct address_info *hw_config) { - sb_devc *devc; - int irq = hw_config->irq; - - if (irq < 0) - irq *= -1; + sb_devc *devc; + int irq = hw_config->irq; - if (irq > 2 && irq < 16) - devc = irq2devc[irq]; - else - devc = NULL; + if (irq < 0) + irq *= -1; - if (devc && devc->base == hw_config->io_base) - { - release_region (devc->base, 16); - - if (!(devc->caps & SB_NO_AUDIO)) - { - sound_free_dma (devc->dma8); + if (irq > 2 && irq < 16) + devc = irq2devc[irq]; + else + devc = NULL; - if (devc->dma16 >= 0) - sound_free_dma (devc->dma16); - } + if (devc && devc->base == hw_config->io_base) + { + release_region(devc->base, 16); - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && - devc->irq > 0) - { - snd_release_irq (devc->irq); - irq2devc[devc->irq] = NULL; - } - } - else - release_region (hw_config->io_base, 16); + if (!(devc->caps & SB_NO_AUDIO)) + { + sound_free_dma(devc->dma8); + + if (devc->dma16 >= 0) + sound_free_dma(devc->dma16); + } + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && + devc->irq > 0) + { + snd_release_irq(devc->irq); + irq2devc[devc->irq] = NULL; + sound_unload_mixerdev(devc->my_mixerdev); + sound_unload_mididev(devc->my_mididev); + sound_unload_audiodev(devc->my_dev); + } + } else + release_region(hw_config->io_base, 16); } @@ -972,402 +983,404 @@ */ void -sb_setmixer (sb_devc * devc, unsigned int port, unsigned int value) +sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - outb (((unsigned char) (port & 0xff)), MIXER_ADDR); - - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - outb (((unsigned char) (value & 0xff)), MIXER_DATA); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - restore_flags (flags); + save_flags(flags); + cli(); + outb(((unsigned char) (port & 0xff)), MIXER_ADDR); + + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + outb(((unsigned char) (value & 0xff)), MIXER_DATA); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + restore_flags(flags); } unsigned int -sb_getmixer (sb_devc * devc, unsigned int port) +sb_getmixer(sb_devc * devc, unsigned int port) { - unsigned int val; - unsigned long flags; + unsigned int val; + unsigned long flags; - save_flags (flags); - cli (); - outb (((unsigned char) (port & 0xff)), MIXER_ADDR); + save_flags(flags); + cli(); + outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - val = inb (MIXER_DATA); - tenmicrosec (devc->osp); - tenmicrosec (devc->osp); - restore_flags (flags); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + val = inb(MIXER_DATA); + tenmicrosec(devc->osp); + tenmicrosec(devc->osp); + restore_flags(flags); - return val; + return val; } -#ifdef CONFIG_MIDI +#if defined(CONFIG_MIDI) /* * MPU401 MIDI initialization. */ static void -smw_putmem (sb_devc * devc, int base, int addr, unsigned char val) +smw_putmem(sb_devc * devc, int base, int addr, unsigned char val) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((addr & 0xff), base + 1); /* Low address bits */ - outb ((addr >> 8), base + 2); /* High address bits */ - outb ((val), base); /* Data */ + outb((addr & 0xff), base + 1); /* Low address bits */ + outb((addr >> 8), base + 2); /* High address bits */ + outb((val), base); /* Data */ - restore_flags (flags); + restore_flags(flags); } static unsigned char -smw_getmem (sb_devc * devc, int base, int addr) +smw_getmem(sb_devc * devc, int base, int addr) { - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - outb ((addr & 0xff), base + 1); /* Low address bits */ - outb ((addr >> 8), base + 2); /* High address bits */ - val = inb (base); /* Data */ + outb((addr & 0xff), base + 1); /* Low address bits */ + outb((addr >> 8), base + 2); /* High address bits */ + val = inb(base); /* Data */ - restore_flags (flags); - return val; + restore_flags(flags); + return val; } static int -smw_midi_init (sb_devc * devc, struct address_info *hw_config) +smw_midi_init(sb_devc * devc, struct address_info *hw_config) { - int mpu_base = hw_config->io_base; - int mp_base = mpu_base + 4; /* Microcontroller base */ - int i; - unsigned char control; - - - /* - * Reset the microcontroller so that the RAM can be accessed - */ - - control = inb (mpu_base + 7); - outb ((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */ - outb (((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */ - - for (i = 0; i < 300; i++) /* Wait at least 1ms */ - tenmicrosec (devc->osp); - - outb ((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ - - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem (devc, mp_base, 0, 0x00); - smw_putmem (devc, mp_base, 1, 0xff); - tenmicrosec (devc->osp); - - if (smw_getmem (devc, mp_base, 0) != 0x00 || smw_getmem (devc, mp_base, 1) != 0xff) - { - DDB (printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem (devc, mp_base, 0), smw_getmem (devc, mp_base, 1))); - return 0; /* No RAM */ - } - - /* - * There is RAM so assume it's really a SM Wave - */ - - devc->model = MDL_SMW; - smw_mixer_init (devc); - - if (smw_ucodeLen > 0) - { - if (smw_ucodeLen != 8192) - { - printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); - return 1; - } + int mpu_base = hw_config->io_base; + int mp_base = mpu_base + 4; /* Microcontroller base */ + int i; + unsigned char control; + + + /* + * Reset the microcontroller so that the RAM can be accessed + */ - /* - * Download microcode - */ + control = inb(mpu_base + 7); + outb((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */ + outb(((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */ - for (i = 0; i < 8192; i++) - smw_putmem (devc, mp_base, i, smw_ucode[i]); + for (i = 0; i < 300; i++) /* Wait at least 1ms */ + tenmicrosec(devc->osp); - /* - * Verify microcode - */ + outb((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ - for (i = 0; i < 8192; i++) - if (smw_getmem (devc, mp_base, i) != smw_ucode[i]) + /* + * Detect microcontroller by probing the 8k RAM area + */ + smw_putmem(devc, mp_base, 0, 0x00); + smw_putmem(devc, mp_base, 1, 0xff); + tenmicrosec(devc->osp); + + if (smw_getmem(devc, mp_base, 0) != 0x00 || smw_getmem(devc, mp_base, 1) != 0xff) { - printk ("SM Wave: Microcode verification failed\n"); - return 0; + DDB(printk("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(devc, mp_base, 0), smw_getmem(devc, mp_base, 1))); + return 0; /* No RAM */ } - } + /* + * There is RAM so assume it's really a SM Wave + */ + + devc->model = MDL_SMW; + smw_mixer_init(devc); - control = 0; +#ifdef MODULE + if (!smw_ucode) + { + extern void *smw_free; + + smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); + smw_free = smw_ucode; + } +#endif + if (smw_ucodeLen > 0) + { + if (smw_ucodeLen != 8192) + { + printk("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); + return 1; + } + /* + * Download microcode + */ + + for (i = 0; i < 8192; i++) + smw_putmem(devc, mp_base, i, smw_ucode[i]); + + /* + * Verify microcode + */ + + for (i = 0; i < 8192; i++) + if (smw_getmem(devc, mp_base, i) != smw_ucode[i]) + { + printk("SM Wave: Microcode verification failed\n"); + return 0; + } + } + control = 0; #ifdef SMW_SCSI_IRQ - /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. - */ - { - static unsigned char scsi_irq_bits[] = - {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; + /* + * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt + * is disabled by default. + * + * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. + */ + { + static unsigned char scsi_irq_bits[] = + {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; - control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; - } + control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; + } #endif #ifdef SMW_OPL4_ENABLE - /* - * Make the OPL4 chip visible on the PC bus at 0x380. - * - * There is no need to enable this feature since this driver - * doesn't support OPL4 yet. Also there is no RAM in SM Wave so - * enabling OPL4 is pretty useless. - */ - control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ - /* control |= 0x20; Uncomment this if you want to use IRQ7 */ + /* + * Make the OPL4 chip visible on the PC bus at 0x380. + * + * There is no need to enable this feature since this driver + * doesn't support OPL4 yet. Also there is no RAM in SM Wave so + * enabling OPL4 is pretty useless. + */ + control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ + /* control |= 0x20; Uncomment this if you want to use IRQ7 */ #endif - outb ((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ - hw_config->name = "SoundMan Wave"; - return 1; + outb((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ + hw_config->name = "SoundMan Wave"; + return 1; } static int -ess_midi_init (sb_devc * devc, struct address_info *hw_config) +ess_midi_init(sb_devc * devc, struct address_info *hw_config) { - unsigned char cfg, tmp; + unsigned char cfg, tmp; - cfg = sb_getmixer (devc, 0x40) & 0x03; + cfg = sb_getmixer(devc, 0x40) & 0x03; - if (devc->submodel < 8) - { - sb_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ - return 0; /* ES688 doesn't support MPU401 mode */ - } - - tmp = (hw_config->io_base & 0x0f0) >> 4; - - if (tmp > 3) - { - sb_setmixer (devc, 0x40, cfg); - return 0; - } - - cfg |= tmp << 3; - - tmp = 1; /* MPU enabled without interrupts */ - - switch (hw_config->irq) - { - case 9: - tmp = 0x4; - break; - case 5: - tmp = 0x5; - break; - case 7: - tmp = 0x6; - break; - case 10: - tmp = 0x7; - break; - default: - return 0; - } + if (devc->submodel < 8) + { + sb_setmixer(devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ + return 0; /* ES688 doesn't support MPU401 mode */ + } + tmp = (hw_config->io_base & 0x0f0) >> 4; - cfg |= tmp << 5; + if (tmp > 3) + { + sb_setmixer(devc, 0x40, cfg); + return 0; + } + cfg |= tmp << 3; + + tmp = 1; /* MPU enabled without interrupts */ + + switch (hw_config->irq) + { + case 9: + tmp = 0x4; + break; + case 5: + tmp = 0x5; + break; + case 7: + tmp = 0x6; + break; + case 10: + tmp = 0x7; + break; + default: + return 0; + } - sb_setmixer (devc, 0x40, cfg | 0x03); - return 1; + cfg |= tmp << 5; + + sb_setmixer(devc, 0x40, cfg | 0x03); + return 1; } static int -init_Jazz16_midi (sb_devc * devc, struct address_info *hw_config) +init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config) { - int mpu_base = hw_config->io_base; - int sb_base = devc->base; - int irq = hw_config->irq; - - unsigned char bits = 0; - unsigned long flags; - - if (irq < 0) - irq *= -1; - - if (irq < 1 || irq > 15 || - jazz_irq_bits[irq] == 0) - { - printk ("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); - return 0; - } - - switch (sb_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - - default: - return 0; - } - - bits = jazz16_bits = bits << 5; - - switch (mpu_base) - { - case 0x310: - bits |= 1; - break; - case 0x320: - bits |= 2; - break; - case 0x330: - bits |= 3; - break; - - default: - printk ("Jazz16: Invalid MIDI I/O port %x\n", mpu_base); - return 0; - } + int mpu_base = hw_config->io_base; + int sb_base = devc->base; + int irq = hw_config->irq; + + unsigned char bits = 0; + unsigned long flags; + + if (irq < 0) + irq *= -1; + + if (irq < 1 || irq > 15 || + jazz_irq_bits[irq] == 0) + { + printk("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); + return 0; + } + switch (sb_base) + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + + default: + return 0; + } + + bits = jazz16_bits = bits << 5; + + switch (mpu_base) + { + case 0x310: + bits |= 1; + break; + case 0x320: + bits |= 2; + break; + case 0x330: + bits |= 3; + break; + + default: + printk("Jazz16: Invalid MIDI I/O port %x\n", mpu_base); + return 0; + } /* * Magic wake up sequence by writing to 0x201 (aka Joystick port) */ - save_flags (flags); - cli (); - outb ((0xAF), 0x201); - outb ((0x50), 0x201); - outb ((bits), 0x201); - restore_flags (flags); - - hw_config->name = "Jazz16"; - smw_midi_init (devc, hw_config); - - if (!sb_dsp_command (devc, 0xfb)) - return 0; - - if (!sb_dsp_command (devc, jazz_dma_bits[devc->dma8] | - (jazz_dma_bits[devc->dma16] << 4))) - return 0; - - if (!sb_dsp_command (devc, jazz_irq_bits[devc->irq] | - (jazz_irq_bits[irq] << 4))) - return 0; + save_flags(flags); + cli(); + outb((0xAF), 0x201); + outb((0x50), 0x201); + outb((bits), 0x201); + restore_flags(flags); + + hw_config->name = "Jazz16"; + smw_midi_init(devc, hw_config); + + if (!sb_dsp_command(devc, 0xfb)) + return 0; + + if (!sb_dsp_command(devc, jazz_dma_bits[devc->dma8] | + (jazz_dma_bits[devc->dma16] << 4))) + return 0; + + if (!sb_dsp_command(devc, jazz_irq_bits[devc->irq] | + (jazz_irq_bits[irq] << 4))) + return 0; - return 1; + return 1; } void -attach_sbmpu (struct address_info *hw_config) +attach_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - attach_uart401 (hw_config); +#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + attach_uart401(hw_config); #endif } int -probe_sbmpu (struct address_info *hw_config) +probe_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - sb_devc *devc = last_devc; +#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + sb_devc *devc = last_devc; - if (last_devc == NULL) - return 0; + if (last_devc == NULL) + return 0; - last_devc = 0; + last_devc = 0; - if (hw_config->io_base <= 0) - return 0; - - if (check_region (hw_config->io_base, 4)) - { - printk ("sbmpu: I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - switch (devc->model) - { - case MDL_SB16: - if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) - { - printk ("SB16: Invalid MIDI port %x\n", hw_config->irq); - return 0; - } - hw_config->name = "Sound Blaster 16"; - hw_config->irq = -devc->irq; + if (hw_config->io_base <= 0) + return 0; + + if (check_region(hw_config->io_base, 4)) + { + printk("sbmpu: I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + switch (devc->model) + { + case MDL_SB16: + if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) + { + printk("SB16: Invalid MIDI port %x\n", hw_config->irq); + return 0; + } + hw_config->name = "Sound Blaster 16"; + hw_config->irq = -devc->irq; #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - if (devc->minor > 12) /* What is Vibra's version??? */ - sb16_set_mpu_port (devc, hw_config); + if (devc->minor > 12) /* What is Vibra's version??? */ + sb16_set_mpu_port(devc, hw_config); #endif - break; + break; - case MDL_ESS: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!ess_midi_init (devc, hw_config)) - return 0; - hw_config->name = "ESS ES1688"; - break; + case MDL_ESS: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!ess_midi_init(devc, hw_config)) + return 0; + hw_config->name = "ESS ES1688"; + break; + + case MDL_JAZZ: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!init_Jazz16_midi(devc, hw_config)) + return 0; + break; - case MDL_JAZZ: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!init_Jazz16_midi (devc, hw_config)) - return 0; - break; - - default: - return 0; - } + default: + return 0; + } - return probe_uart401 (hw_config); + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } -void -unload_sbmpu (struct address_info *hw_config) +void +unload_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - unload_uart401 (hw_config); +#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) + unload_uart401(hw_config); #endif } -#else /* !CONFIG_MIDI */ +#else /* !CONFIG_MIDI */ -void -unload_sbmpu (struct address_info *hw_config) +void +unload_sbmpu(struct address_info *hw_config) { } int -probe_sbmpu (struct address_info *hw_config) +probe_sbmpu(struct address_info *hw_config) { - return 0; + return 0; } void -attach_sbmpu (struct address_info *hw_config) +attach_sbmpu(struct address_info *hw_config) { } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v2.1.66/linux/drivers/sound/sb_midi.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb_midi.c Sat Nov 29 10:33:21 1997 @@ -31,129 +31,126 @@ static int -sb_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +sb_midi_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; - if (devc == NULL) - return -ENXIO; + if (devc == NULL) + return -ENXIO; - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - return -EBUSY; - } - devc->opened = 1; - restore_flags (flags); - - devc->irq_mode = IMODE_MIDI; - devc->midi_broken = 0; - - sb_dsp_reset (devc); - - if (!sb_dsp_command (devc, 0x35)) /* Start MIDI UART mode */ - { - devc->opened = 0; - return -EIO; - } - - devc->intr_active = 1; - - if (mode & OPEN_READ) - { - devc->input_opened = 1; - devc->midi_input_intr = input; - } - - return 0; + save_flags(flags); + cli(); + if (devc->opened) + { + restore_flags(flags); + return -EBUSY; + } + devc->opened = 1; + restore_flags(flags); + + devc->irq_mode = IMODE_MIDI; + devc->midi_broken = 0; + + sb_dsp_reset(devc); + + if (!sb_dsp_command(devc, 0x35)) /* Start MIDI UART mode */ + { + devc->opened = 0; + return -EIO; + } + devc->intr_active = 1; + + if (mode & OPEN_READ) + { + devc->input_opened = 1; + devc->midi_input_intr = input; + } + return 0; } static void -sb_midi_close (int dev) +sb_midi_close(int dev) { - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; - if (devc == NULL) - return; + if (devc == NULL) + return; - save_flags (flags); - cli (); - sb_dsp_reset (devc); - devc->intr_active = 0; - devc->input_opened = 0; - devc->opened = 0; - restore_flags (flags); + save_flags(flags); + cli(); + sb_dsp_reset(devc); + devc->intr_active = 0; + devc->input_opened = 0; + devc->opened = 0; + restore_flags(flags); } static int -sb_midi_out (int dev, unsigned char midi_byte) +sb_midi_out(int dev, unsigned char midi_byte) { - sb_devc *devc = midi_devs[dev]->devc; - - if (devc == NULL) - return 1; + sb_devc *devc = midi_devs[dev]->devc; - if (devc->midi_broken) - return 1; + if (devc == NULL) + return 1; - if (!sb_dsp_command (devc, midi_byte)) - { - devc->midi_broken = 1; - return 1; - } - - return 1; + if (devc->midi_broken) + return 1; + + if (!sb_dsp_command(devc, midi_byte)) + { + devc->midi_broken = 1; + return 1; + } + return 1; } static int -sb_midi_start_read (int dev) +sb_midi_start_read(int dev) { - return 0; + return 0; } static int -sb_midi_end_read (int dev) +sb_midi_end_read(int dev) { - sb_devc *devc = midi_devs[dev]->devc; + sb_devc *devc = midi_devs[dev]->devc; - if (devc == NULL) - return -ENXIO; + if (devc == NULL) + return -ENXIO; - sb_dsp_reset (devc); - devc->intr_active = 0; - return 0; + sb_dsp_reset(devc); + devc->intr_active = 0; + return 0; } static int -sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +sb_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EPERM; + return -EPERM; } void -sb_midi_interrupt (sb_devc * devc) +sb_midi_interrupt(sb_devc * devc) { - unsigned long flags; - unsigned char data; + unsigned long flags; + unsigned char data; - if (devc == NULL) - return; + if (devc == NULL) + return; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - data = inb (DSP_READ); - if (devc->input_opened) - devc->midi_input_intr (devc->my_mididev, data); + data = inb(DSP_READ); + if (devc->input_opened) + devc->midi_input_intr(devc->my_mididev, data); - restore_flags (flags); + restore_flags(flags); } #define MIDI_SYNTH_NAME "Sound Blaster Midi" @@ -162,74 +159,76 @@ static struct midi_operations sb_midi_operations = { - {"Sound Blaster", 0, 0, SNDCARD_SB}, - &std_midi_synth, - {0}, - sb_midi_open, - sb_midi_close, - sb_midi_ioctl, - sb_midi_out, - sb_midi_start_read, - sb_midi_end_read, - NULL, - NULL, - NULL, - NULL + {"Sound Blaster", 0, 0, SNDCARD_SB}, + &std_midi_synth, + {0}, + sb_midi_open, + sb_midi_close, + sb_midi_ioctl, + sb_midi_out, + sb_midi_start_read, + sb_midi_end_read, + NULL, + NULL, + NULL, + NULL }; void -sb_dsp_midi_init (sb_devc * devc) +sb_dsp_midi_init(sb_devc * devc) { - if (devc->model < 2) /* No MIDI support for SB 1.x */ - return; - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } + int dev; - std_midi_synth.midi_dev = num_midis; - devc->my_mididev = num_midis; + if (devc->model < 2) /* No MIDI support for SB 1.x */ + return; - std_midi_synth.midi_dev = devc->my_mididev = num_midis; + dev = sound_alloc_mididev(); + if (dev == -1) + { + printk("Sound: Too many midi devices detected\n"); + return; + } + std_midi_synth.midi_dev = dev; + devc->my_mididev = dev; - midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct midi_operations); + std_midi_synth.midi_dev = devc->my_mididev = dev; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (midi_devs[num_midis] == NULL) - { - printk ("sb MIDI: Failed to allocate memory\n"); - return; - } - memcpy ((char *) midi_devs[num_midis], (char *) &sb_midi_operations, - sizeof (struct midi_operations)); + midi_devs[dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations); - midi_devs[num_midis]->devc = devc; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[dev] == NULL) + { + printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n"); + sound_unload_mididev(dev); + return; + } + memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, + sizeof(struct midi_operations)); + midi_devs[dev]->devc = devc; - midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations); - if (sound_nblocks < 1024) - sound_nblocks++;; + midi_devs[dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - if (midi_devs[num_midis]->converter == NULL) - { - printk ("sb MIDI: Failed to allocate memory\n"); - return; - } + if (sound_nblocks < 1024) + sound_nblocks++;; - memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); + if (midi_devs[dev]->converter == NULL) + { + printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n"); + sound_unload_mididev(dev); + return; + } + memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth, + sizeof(struct synth_operations)); - midi_devs[num_midis]->converter->id = "SBMIDI"; - num_midis++; - sequencer_init (); + midi_devs[dev]->converter->id = "SBMIDI"; + sequencer_init(); } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.1.66/linux/drivers/sound/sb_mixer.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb_mixer.c Sat Nov 29 10:33:21 1997 @@ -16,7 +16,7 @@ #include "sound_config.h" -#ifdef CONFIG_SBDSP +#if defined(CONFIG_SBDSP) || defined(MODULE) #define __SB_MIXER_C__ #include "sb.h" @@ -24,434 +24,432 @@ static int sbmixnum = 1; -static void sb_mixer_reset (sb_devc * devc); +static void sb_mixer_reset(sb_devc * devc); void -sb_mixer_set_stereo (sb_devc * devc, int mode) +sb_mixer_set_stereo(sb_devc * devc, int mode) { - sb_setmixer (devc, OUT_FILTER, ((sb_getmixer (devc, OUT_FILTER) & ~STEREO_DAC) - | (mode ? STEREO_DAC : MONO_DAC))); + sb_setmixer(devc, OUT_FILTER, ((sb_getmixer(devc, OUT_FILTER) & ~STEREO_DAC) + | (mode ? STEREO_DAC : MONO_DAC))); } static int -detect_mixer (sb_devc * devc) +detect_mixer(sb_devc * devc) { - /* Just trust the mixer is there */ - return 1; + /* Just trust the mixer is there */ + return 1; } static void -change_bits (sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) +change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) { - unsigned char mask; - int shift; + unsigned char mask; + int shift; - mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* Scale */ + mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; + newval = (int) ((newval * mask) + 50) / 100; /* Scale */ - shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; + shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; - *regval &= ~(mask << shift); /* Mask out previous value */ - *regval |= (newval & mask) << shift; /* Set the new value */ + *regval &= ~(mask << shift); /* Mask out previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ } static int -sb_mixer_get (sb_devc * devc, int dev) +sb_mixer_get(sb_devc * devc, int dev) { - if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; + if (!((1 << dev) & devc->supported_devices)) + return -EINVAL; - return devc->levels[dev]; + return devc->levels[dev]; } void -smw_mixer_init (sb_devc * devc) +smw_mixer_init(sb_devc * devc) { - int i; + int i; - sb_setmixer (devc, 0x00, 0x18); /* Mute unused (Telephone) line */ - sb_setmixer (devc, 0x10, 0x38); /* Config register 2 */ + sb_setmixer(devc, 0x00, 0x18); /* Mute unused (Telephone) line */ + sb_setmixer(devc, 0x10, 0x38); /* Config register 2 */ - devc->supported_devices = 0; - for (i = 0; i < sizeof (smw_mix_regs); i++) - if (smw_mix_regs[i] != 0) - devc->supported_devices |= (1 << i); + devc->supported_devices = 0; + for (i = 0; i < sizeof(smw_mix_regs); i++) + if (smw_mix_regs[i] != 0) + devc->supported_devices |= (1 << i); - devc->supported_rec_devices = devc->supported_devices & - ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | - SOUND_MASK_VOLUME); + devc->supported_rec_devices = devc->supported_devices & + ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | + SOUND_MASK_VOLUME); - sb_mixer_reset (devc); + sb_mixer_reset(devc); } static int -smw_mixer_set (sb_devc * devc, int dev, int value) +smw_mixer_set(sb_devc * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int reg, val; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if (dev > 31) - return -EINVAL; - - if (!(devc->supported_devices & (1 << dev))) /* Not supported */ - return -EINVAL; - - switch (dev) - { - case SOUND_MIXER_VOLUME: - sb_setmixer (devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ - sb_setmixer (devc, 0x0c, 96 - (96 * right / 100)); - break; - - case SOUND_MIXER_BASS: - case SOUND_MIXER_TREBLE: - devc->levels[dev] = left | (right << 8); - - /* Set left bass and treble values */ - val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; - val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (devc, 0x0d, val); - - /* Set right bass and treble values */ - val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; - val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (devc, 0x0e, val); - break; - - default: - reg = smw_mix_regs[dev]; - if (reg == 0) - return -EINVAL; - sb_setmixer (devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ - sb_setmixer (devc, reg + 1, (24 - (24 * right / 100)) | 0x40); - } + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int reg, val; - devc->levels[dev] = left | (right << 8); - return left | (right << 8); + if (left > 100) + left = 100; + if (right > 100) + right = 100; + + if (dev > 31) + return -EINVAL; + + if (!(devc->supported_devices & (1 << dev))) /* Not supported */ + return -EINVAL; + + switch (dev) + { + case SOUND_MIXER_VOLUME: + sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); + break; + + case SOUND_MIXER_BASS: + case SOUND_MIXER_TREBLE: + devc->levels[dev] = left | (right << 8); + + /* Set left bass and treble values */ + val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; + val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer(devc, 0x0d, val); + + /* Set right bass and treble values */ + val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; + val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer(devc, 0x0e, val); + break; + + default: + reg = smw_mix_regs[dev]; + if (reg == 0) + return -EINVAL; + sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); + } + + devc->levels[dev] = left | (right << 8); + return left | (right << 8); } static int -sb_mixer_set (sb_devc * devc, int dev, int value) +sb_mixer_set(sb_devc * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; - int regoffs; - unsigned char val; + int regoffs; + unsigned char val; - if (devc->model == MDL_SMW) - return smw_mixer_set (devc, dev, value); + if (devc->model == MDL_SMW) + return smw_mixer_set(devc, dev, value); - if (left > 100) - left = 100; - if (right > 100) - right = 100; + if (left > 100) + left = 100; + if (right > 100) + right = 100; - if (dev > 31) - return -EINVAL; + if (dev > 31) + return -EINVAL; - if (!(devc->supported_devices & (1 << dev))) /* - * Not supported - */ - return -EINVAL; + if (!(devc->supported_devices & (1 << dev))) /* + * Not supported + */ + return -EINVAL; - regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; + regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; - if (regoffs == 0) - return -EINVAL; + if (regoffs == 0) + return -EINVAL; - val = sb_getmixer (devc, regoffs); - change_bits (devc, &val, dev, LEFT_CHN, left); + val = sb_getmixer(devc, regoffs); + change_bits(devc, &val, dev, LEFT_CHN, left); - devc->levels[dev] = left | (left << 8); + devc->levels[dev] = left | (left << 8); - if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* - * Change register + if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* + * Change register + */ + { + sb_setmixer(devc, regoffs, val); /* + * Save the old one */ - { - sb_setmixer (devc, regoffs, val); /* - * Save the old one - */ - regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; - - if (regoffs == 0) - return left | (left << 8); /* - * Just left channel present - */ + regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; - val = sb_getmixer (devc, regoffs); /* - * Read the new one - */ - } + if (regoffs == 0) + return left | (left << 8); /* + * Just left channel present + */ - change_bits (devc, &val, dev, RIGHT_CHN, right); + val = sb_getmixer(devc, regoffs); /* + * Read the new one + */ + } + change_bits(devc, &val, dev, RIGHT_CHN, right); - sb_setmixer (devc, regoffs, val); + sb_setmixer(devc, regoffs, val); - devc->levels[dev] = left | (right << 8); - return left | (right << 8); + devc->levels[dev] = left | (right << 8); + return left | (right << 8); } static void -set_recsrc (sb_devc * devc, int src) +set_recsrc(sb_devc * devc, int src) { - sb_setmixer (devc, RECORD_SRC, (sb_getmixer (devc, RECORD_SRC) & ~7) | (src & 0x7)); + sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); } static int -set_recmask (sb_devc * devc, int mask) +set_recmask(sb_devc * devc, int mask) { - int devmask, i; - unsigned char regimageL, regimageR; + int devmask, i; + unsigned char regimageL, regimageR; - devmask = mask & devc->supported_rec_devices; + devmask = mask & devc->supported_rec_devices; - switch (devc->model) - { - case MDL_SBPRO: - case MDL_ESS: - case MDL_JAZZ: - case MDL_SMW: - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* + switch (devc->model) + { + case MDL_SBPRO: + case MDL_ESS: + case MDL_JAZZ: + case MDL_SMW: + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* * More than one devices selected. Drop the * * previous selection */ - devmask &= ~devc->recmask; - } - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* + devmask &= ~devc->recmask; + } + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* * More than one devices selected. Default to * * mic */ - devmask = SOUND_MASK_MIC; - } - - - if (devmask ^ devc->recmask) /* - * Input source changed - */ - { - switch (devmask) - { - - case SOUND_MASK_MIC: - set_recsrc (devc, SRC__MIC); - break; - - case SOUND_MASK_LINE: - set_recsrc (devc, SRC__LINE); - break; - - case SOUND_MASK_CD: - set_recsrc (devc, SRC__CD); - break; - - default: - set_recsrc (devc, SRC__MIC); - } - } - - break; - - case MDL_SB16: - if (!devmask) - devmask = SOUND_MASK_MIC; - - regimageL = regimageR = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if ((1 << i) & devmask) - { - regimageL |= sb16_recmasks_L[i]; - regimageR |= sb16_recmasks_R[i]; + devmask = SOUND_MASK_MIC; + } + if (devmask ^ devc->recmask) /* + * Input source changed + */ + { + switch (devmask) + { + + case SOUND_MASK_MIC: + set_recsrc(devc, SRC__MIC); + break; + + case SOUND_MASK_LINE: + set_recsrc(devc, SRC__LINE); + break; + + case SOUND_MASK_CD: + set_recsrc(devc, SRC__CD); + break; + + default: + set_recsrc(devc, SRC__MIC); + } + } + break; + + case MDL_SB16: + if (!devmask) + devmask = SOUND_MASK_MIC; + + regimageL = regimageR = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if ((1 << i) & devmask) + { + regimageL |= sb16_recmasks_L[i]; + regimageR |= sb16_recmasks_R[i]; + } + sb_setmixer(devc, SB16_IMASK_L, regimageL); + sb_setmixer(devc, SB16_IMASK_R, regimageR); + break; } - sb_setmixer (devc, SB16_IMASK_L, regimageL); - sb_setmixer (devc, SB16_IMASK_R, regimageR); - break; - } - devc->recmask = devmask; - return devc->recmask; + devc->recmask = devmask; + return devc->recmask; } static int -sb_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - sb_devc *devc = mixer_devs[dev]->devc; - int val; + sb_devc *devc = mixer_devs[dev]->devc; + int val; /* * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). */ - if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) - { - int tmp; - - tmp = *(int *) arg; - - sb_setmixer (devc, 0x43, (~tmp) & 0x01); - return 0; - } - - if (((cmd >> 8) & 0xff) == 'M') - { - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - switch (cmd & 0xff) + if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) { - case SOUND_MIXER_RECSRC: - val = *(int *) arg; - return (*(int *) arg = set_recmask (devc, val)); - break; + int tmp; - default: + tmp = *(int *) arg; - val = *(int *) arg; - return (*(int *) arg = sb_mixer_set (devc, cmd & 0xff, val)); + sb_setmixer(devc, 0x43, (~tmp) & 0x01); + return 0; } - else - switch (cmd & 0xff) + if (((cmd >> 8) & 0xff) == 'M') { - - case SOUND_MIXER_RECSRC: - return (*(int *) arg = devc->recmask); - break; - - case SOUND_MIXER_DEVMASK: - return (*(int *) arg = devc->supported_devices); - break; - - case SOUND_MIXER_STEREODEVS: - if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - return (*(int *) arg = devc->supported_devices); - else - return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); - break; - - case SOUND_MIXER_RECMASK: - return (*(int *) arg = devc->supported_rec_devices); - break; - - case SOUND_MIXER_CAPS: - return (*(int *) arg = devc->mixer_caps); - break; - - default: - return (*(int *) arg = sb_mixer_get (devc, cmd & 0xff)); - } - } - else - return -EINVAL; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + val = *(int *) arg; + return (*(int *) arg = set_recmask(devc, val)); + break; + + default: + + val = *(int *) arg; + return (*(int *) arg = sb_mixer_set(devc, cmd & 0xff, val)); + } else + switch (cmd & 0xff) + { + + case SOUND_MIXER_RECSRC: + return (*(int *) arg = devc->recmask); + break; + + case SOUND_MIXER_DEVMASK: + return (*(int *) arg = devc->supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + return (*(int *) arg = devc->supported_devices); + else + return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); + break; + + case SOUND_MIXER_RECMASK: + return (*(int *) arg = devc->supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return (*(int *) arg = devc->mixer_caps); + break; + + default: + return (*(int *) arg = sb_mixer_get(devc, cmd & 0xff)); + } + } else + return -EINVAL; } static struct mixer_operations sb_mixer_operations = { - "SB", - "Sound Blaster", - sb_mixer_ioctl + "SB", + "Sound Blaster", + sb_mixer_ioctl }; static void -sb_mixer_reset (sb_devc * devc) +sb_mixer_reset(sb_devc * devc) { - char name[32]; - int i; + char name[32]; + int i; + extern int sm_games; - sprintf (name, "SB_%d", devc->sbmixnum); + sprintf(name, "SB_%d", devc->sbmixnum); - devc->levels = load_mixer_volumes (name, default_levels, 1); + if (sm_games) + devc->levels = load_mixer_volumes(name, smg_default_levels, 1); + else + devc->levels = load_mixer_volumes(name, sb_default_levels, 1); - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - sb_mixer_set (devc, i, devc->levels[i]); + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + sb_mixer_set(devc, i, devc->levels[i]); - set_recmask (devc, SOUND_MASK_MIC); + set_recmask(devc, SOUND_MASK_MIC); } int -sb_mixer_init (sb_devc * devc) +sb_mixer_init(sb_devc * devc) { - int mixer_type = 0; + int mixer_type = 0; + int m; + + devc->sbmixnum = sbmixnum++; + devc->levels = NULL; + + sb_setmixer(devc, 0x00, 0); /* Reset mixer */ + + if (!(mixer_type = detect_mixer(devc))) + return 0; /* No mixer. Why? */ - devc->sbmixnum = sbmixnum++; - devc->levels = NULL; + switch (devc->model) + { + case MDL_SBPRO: + case MDL_AZTECH: + case MDL_JAZZ: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = SBPRO_MIXER_DEVICES; + devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; + devc->iomap = &sbpro_mix; + break; + + case MDL_ESS: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = ES688_MIXER_DEVICES; + devc->supported_rec_devices = ES688_RECORDING_DEVICES; + devc->iomap = &es688_mix; + break; + + case MDL_SMW: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = 0; + devc->supported_rec_devices = 0; + devc->iomap = &sbpro_mix; + smw_mixer_init(devc); + break; + + case MDL_SB16: + devc->mixer_caps = 0; + devc->supported_devices = SB16_MIXER_DEVICES; + devc->supported_rec_devices = SB16_RECORDING_DEVICES; + devc->iomap = &sb16_mix; + break; + + default: + printk("SB Warning: Unsupported mixer type %d\n", devc->model); + return 0; + } + + m = sound_alloc_mixerdev(); + if (m == -1) + return 0; + + + mixer_devs[m] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (mixer_devs[m] == NULL) + { + printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); + sound_unload_mixerdev(m); + return 0; + } + memcpy((char *) mixer_devs[m], (char *) &sb_mixer_operations, + sizeof(struct mixer_operations)); - sb_setmixer (devc, 0x00, 0); /* Reset mixer */ + mixer_devs[m]->devc = devc; - if (!(mixer_type = detect_mixer (devc))) - return 0; /* No mixer. Why? */ - - switch (devc->model) - { - case MDL_SBPRO: - case MDL_AZTECH: - case MDL_JAZZ: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = SBPRO_MIXER_DEVICES; - devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; - devc->iomap = &sbpro_mix; - break; - - case MDL_ESS: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = ES688_MIXER_DEVICES; - devc->supported_rec_devices = ES688_RECORDING_DEVICES; - devc->iomap = &es688_mix; - break; - - case MDL_SMW: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = 0; - devc->supported_rec_devices = 0; - devc->iomap = &sbpro_mix; - smw_mixer_init (devc); - break; - - case MDL_SB16: - devc->mixer_caps = 0; - devc->supported_devices = SB16_MIXER_DEVICES; - devc->supported_rec_devices = SB16_RECORDING_DEVICES; - devc->iomap = &sb16_mix; - break; - - default: - printk ("SB Warning: Unsupported mixer type %d\n", devc->model); - return 0; - } - - if (num_mixers >= MAX_MIXER_DEV) - return 0; - - - mixer_devs[num_mixers] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct mixer_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - if (mixer_devs[num_mixers] == NULL) - { - printk ("sb_mixer: Can't allocate memory\n"); - return 0; - } - - memcpy ((char *) mixer_devs[num_mixers], (char *) &sb_mixer_operations, - sizeof (struct mixer_operations)); - - mixer_devs[num_mixers]->devc = devc; - - sb_mixer_reset (devc); - devc->my_mixerdev = num_mixers++; - return 1; + devc->my_mixerdev = m; + sb_mixer_reset(devc); + return 1; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v2.1.66/linux/drivers/sound/sb_mixer.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sb_mixer.h Sat Nov 29 10:33:21 1997 @@ -169,11 +169,11 @@ MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) }; -#ifdef SM_GAMES /* Master volume is lower and PCM & FM volumes +/* SM_GAMES Master volume is lower and PCM & FM volumes higher than with SB Pro. This improves the sound quality */ -static int default_levels[32] = +static int smg_default_levels[32] = { 0x2020, /* Master Volume */ 0x4b4b, /* Bass */ @@ -194,9 +194,7 @@ 0x1515 /* Line3 */ }; -#else /* If the user selected just plain SB Pro */ - -static int default_levels[32] = +static int sb_default_levels[32] = { 0x5a5a, /* Master Volume */ 0x4b4b, /* Bass */ @@ -216,7 +214,6 @@ 0x4040, /* Line2 */ 0x1515 /* Line3 */ }; -#endif /* SM_GAMES */ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = { diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.66/linux/drivers/sound/sequencer.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sequencer.c Sat Nov 29 10:33:21 1997 @@ -16,7 +16,7 @@ #define SEQUENCER_C #include "sound_config.h" -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) #include "softoss.h" int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL; @@ -77,438 +77,423 @@ static int pre_event_timeout; static unsigned synth_open_mask; -static int seq_queue (unsigned char *note, char nonblock); -static void seq_startplay (void); -static int seq_sync (void); -static void seq_reset (void); +static int seq_queue(unsigned char *note, char nonblock); +static void seq_startplay(void); +static int seq_sync(void); +static void seq_reset(void); #if MAX_SYNTH_DEV > 15 #error Too many synthesizer devices enabled. #endif int -sequencer_read (int dev, struct fileinfo *file, char *buf, int count) +sequencer_read(int dev, struct fileinfo *file, char *buf, int count) { - int c = count, p = 0; - int ev_len; - unsigned long flags; - - dev = dev >> 4; - - ev_len = seq_mode == SEQ_1 ? 4 : 8; - - save_flags (flags); - cli (); - if (!iqlen) - { - if ((file->flags & (O_NONBLOCK) ? - 1 : 0)) - { - restore_flags (flags); - return -EAGAIN; - } + int c = count, p = 0; + int ev_len; + unsigned long flags; + dev = dev >> 4; - { - unsigned long tlimit; + ev_len = seq_mode == SEQ_1 ? 4 : 8; - if (pre_event_timeout) - current->timeout = tlimit = jiffies + (pre_event_timeout); - else - tlimit = (unsigned long) -1; - midi_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&midi_sleeper); - if (!(midi_sleep_flag.opts & WK_WAKEUP)) + save_flags(flags); + cli(); + if (!iqlen) { - if (jiffies >= tlimit) - midi_sleep_flag.opts |= WK_TIMEOUT; + if ((file->flags & (O_NONBLOCK) ? + 1 : 0)) + { + restore_flags(flags); + return -EAGAIN; + } + { + unsigned long tlimit; + + if (pre_event_timeout) + current->timeout = tlimit = jiffies + (pre_event_timeout); + else + tlimit = (unsigned long) -1; + midi_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&midi_sleeper); + if (!(midi_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + midi_sleep_flag.opts |= WK_TIMEOUT; + } + midi_sleep_flag.opts &= ~WK_SLEEP; + }; + + if (!iqlen) + { + restore_flags(flags); + return 0; + } } - midi_sleep_flag.opts &= ~WK_SLEEP; - }; + while (iqlen && c >= ev_len) + { - if (!iqlen) - { - restore_flags (flags); - return 0; - } - } - - while (iqlen && c >= ev_len) - { - - { - char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; - - copy_to_user (&(buf)[p], fixit, ev_len); - }; - p += ev_len; - c -= ev_len; - - iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; - iqlen--; - } - restore_flags (flags); + { + char *fixit = (char *) &iqueue[iqhead * IEV_SZ]; - return count - c; + copy_to_user(&(buf)[p], fixit, ev_len); + }; + p += ev_len; + c -= ev_len; + + iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; + iqlen--; + } + restore_flags(flags); + + return count - c; } static void -sequencer_midi_output (int dev) +sequencer_midi_output(int dev) { - /* - * Currently NOP - */ + /* + * Currently NOP + */ } void -seq_copy_to_input (unsigned char *event_rec, int len) +seq_copy_to_input(unsigned char *event_rec, int len) { - unsigned long flags; + unsigned long flags; - /* - * Verify that the len is valid for the current mode. - */ - - if (len != 4 && len != 8) - return; - if ((seq_mode == SEQ_1) != (len == 4)) - return; - - if (iqlen >= (SEQ_MAX_QUEUE - 1)) - return; /* Overflow */ - - save_flags (flags); - cli (); - memcpy (&iqueue[iqtail * IEV_SZ], event_rec, len); - iqlen++; - iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - - if ((midi_sleep_flag.opts & WK_SLEEP)) - { - { - midi_sleep_flag.opts = WK_WAKEUP; - wake_up (&midi_sleeper); - }; - } - restore_flags (flags); + /* + * Verify that the len is valid for the current mode. + */ + + if (len != 4 && len != 8) + return; + if ((seq_mode == SEQ_1) != (len == 4)) + return; + + if (iqlen >= (SEQ_MAX_QUEUE - 1)) + return; /* Overflow */ + + save_flags(flags); + cli(); + memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); + iqlen++; + iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; + + if ((midi_sleep_flag.opts & WK_SLEEP)) + { + { + midi_sleep_flag.opts = WK_WAKEUP; + wake_up(&midi_sleeper); + }; + } + restore_flags(flags); } static void -sequencer_midi_input (int dev, unsigned char data) +sequencer_midi_input(int dev, unsigned char data) { - unsigned int tstamp; - unsigned char event_rec[4]; - - if (data == 0xfe) /* Ignore active sensing */ - return; + unsigned int tstamp; + unsigned char event_rec[4]; - if (softsynthp != NULL) - tstamp = softsynthp (SSYN_GETTIME, 0, 0, 0); - else - tstamp = jiffies - seq_time; + if (data == 0xfe) /* Ignore active sensing */ + return; - if (tstamp != prev_input_time) - { - tstamp = (tstamp << 8) | SEQ_WAIT; + if (softsynthp != NULL) + tstamp = softsynthp(SSYN_GETTIME, 0, 0, 0); + else + tstamp = jiffies - seq_time; - seq_copy_to_input ((unsigned char *) &tstamp, 4); - prev_input_time = tstamp; - } + if (tstamp != prev_input_time) + { + tstamp = (tstamp << 8) | SEQ_WAIT; - event_rec[0] = SEQ_MIDIPUTC; - event_rec[1] = data; - event_rec[2] = dev; - event_rec[3] = 0; + seq_copy_to_input((unsigned char *) &tstamp, 4); + prev_input_time = tstamp; + } + event_rec[0] = SEQ_MIDIPUTC; + event_rec[1] = data; + event_rec[2] = dev; + event_rec[3] = 0; - seq_copy_to_input (event_rec, 4); + seq_copy_to_input(event_rec, 4); } void -seq_input_event (unsigned char *event_rec, int len) +seq_input_event(unsigned char *event_rec, int len) { - unsigned long this_time; + unsigned long this_time; - if (seq_mode == SEQ_2) - this_time = tmr->get_time (tmr_no); - else if (softsynthp != NULL) - this_time = softsynthp (SSYN_GETTIME, 0, 0, 0); - else - this_time = jiffies - seq_time; - - if (this_time != prev_input_time) - { - unsigned char tmp_event[8]; - - tmp_event[0] = EV_TIMING; - tmp_event[1] = TMR_WAIT_ABS; - tmp_event[2] = 0; - tmp_event[3] = 0; - *(unsigned int *) &tmp_event[4] = this_time; - - seq_copy_to_input (tmp_event, 8); - prev_input_time = this_time; - } + if (seq_mode == SEQ_2) + this_time = tmr->get_time(tmr_no); + else if (softsynthp != NULL) + this_time = softsynthp(SSYN_GETTIME, 0, 0, 0); + else + this_time = jiffies - seq_time; + + if (this_time != prev_input_time) + { + unsigned char tmp_event[8]; - seq_copy_to_input (event_rec, len); + tmp_event[0] = EV_TIMING; + tmp_event[1] = TMR_WAIT_ABS; + tmp_event[2] = 0; + tmp_event[3] = 0; + *(unsigned int *) &tmp_event[4] = this_time; + + seq_copy_to_input(tmp_event, 8); + prev_input_time = this_time; + } + seq_copy_to_input(event_rec, len); } int -sequencer_write (int dev, struct fileinfo *file, const char *buf, int count) +sequencer_write(int dev, struct fileinfo *file, const char *buf, int count) { - unsigned char event_rec[EV_SZ], ev_code; - int p = 0, c, ev_size; - int err; - int mode = file->mode & O_ACCMODE; - - dev = dev >> 4; - - DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); - - if (mode == OPEN_READ) - return -EIO; - - c = count; - - while (c >= 4) - { - copy_from_user ((char *) event_rec, &(buf)[p], 4); - ev_code = event_rec[0]; - - if (ev_code == SEQ_FULLSIZE) - { - int err, fmt; - - dev = *(unsigned short *) &event_rec[2]; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; - - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; - - fmt = (*(short *) &event_rec[0]) & 0xffff; - err = synth_devs[dev]->load_patch (dev, fmt, buf, p + 4, c, 0); - if (err < 0) - return err; - - return err; - } - - if (ev_code >= 128) - { - if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) - { - printk ("Sequencer: Invalid level 2 event %x\n", ev_code); - return -EINVAL; - } - - ev_size = 8; - - if (c < ev_size) - { - if (!seq_playing) - seq_startplay (); - return count - c; - } - - copy_from_user ((char *) &event_rec[4], &(buf)[p + 4], 4); - - } - else - { - if (seq_mode == SEQ_2) - { - printk ("Sequencer: 4 byte event in level 2 mode\n"); - return -EINVAL; - } - ev_size = 4; - - if (event_rec[0] != SEQ_MIDIPUTC) - obsolete_api_used = 1; - } - - if (event_rec[0] == SEQ_MIDIPUTC) - { - - if (!midi_opened[event_rec[2]]) - { - int mode; - int dev = event_rec[2]; - - if (dev >= max_mididev) - { - printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); - return -ENXIO; - } + unsigned char event_rec[EV_SZ], ev_code; + int p = 0, c, ev_size; + int err; + int mode = file->mode & O_ACCMODE; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; - if ((err = midi_devs[dev]->open (dev, mode, - sequencer_midi_input, sequencer_midi_output)) < 0) - { - seq_reset (); - printk ("Sequencer Error: Unable to open Midi #%d\n", dev); - return err; - } + DEB(printk("sequencer_write(dev=%d, count=%d)\n", dev, count)); - midi_opened[dev] = 1; - } + if (mode == OPEN_READ) + return -EIO; - } + c = count; - if (!seq_queue (event_rec, (file->flags & (O_NONBLOCK) ? - 1 : 0))) - { - int processed = count - c; - - if (!seq_playing) - seq_startplay (); + while (c >= 4) + { + copy_from_user((char *) event_rec, &(buf)[p], 4); + ev_code = event_rec[0]; - if (!processed && (file->flags & (O_NONBLOCK) ? - 1 : 0)) - return -EAGAIN; - else - return processed; - } - - p += ev_size; - c -= ev_size; - } + if (ev_code == SEQ_FULLSIZE) + { + int err, fmt; + + dev = *(unsigned short *) &event_rec[2]; + if (dev < 0 || dev >= max_synthdev || synth_devs[dev] == NULL) + return -ENXIO; + + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; + + fmt = (*(short *) &event_rec[0]) & 0xffff; + err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); + if (err < 0) + return err; + + return err; + } + if (ev_code >= 128) + { + if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) + { + printk("Sequencer: Invalid level 2 event %x\n", ev_code); + return -EINVAL; + } + ev_size = 8; + + if (c < ev_size) + { + if (!seq_playing) + seq_startplay(); + return count - c; + } + copy_from_user((char *) &event_rec[4], &(buf)[p + 4], 4); + + } else + { + if (seq_mode == SEQ_2) + { + printk("Sequencer: 4 byte event in level 2 mode\n"); + return -EINVAL; + } + ev_size = 4; + + if (event_rec[0] != SEQ_MIDIPUTC) + obsolete_api_used = 1; + } + + if (event_rec[0] == SEQ_MIDIPUTC) + { + + if (!midi_opened[event_rec[2]]) + { + int mode; + int dev = event_rec[2]; + + if (dev >= max_mididev) + { + printk("Sequencer Error: Nonexistent MIDI device %d\n", dev); + return -ENXIO; + } + mode = file->mode & O_ACCMODE; + + if ((err = midi_devs[dev]->open(dev, mode, + sequencer_midi_input, sequencer_midi_output)) < 0) + { + seq_reset(); + printk("Sequencer Error: Unable to open Midi #%d\n", dev); + return err; + } + midi_opened[dev] = 1; + } + } + if (!seq_queue(event_rec, (file->flags & (O_NONBLOCK) ? + 1 : 0))) + { + int processed = count - c; + + if (!seq_playing) + seq_startplay(); + + if (!processed && (file->flags & (O_NONBLOCK) ? + 1 : 0)) + return -EAGAIN; + else + return processed; + } + p += ev_size; + c -= ev_size; + } - if (!seq_playing) - seq_startplay (); + if (!seq_playing) + seq_startplay(); - return count; + return count; } static int -seq_queue (unsigned char *note, char nonblock) +seq_queue(unsigned char *note, char nonblock) { - /* - * Test if there is space in the queue - */ + /* + * Test if there is space in the queue + */ - if (qlen >= SEQ_MAX_QUEUE) - if (!seq_playing) - seq_startplay (); /* - * Give chance to drain the queue - */ + if (qlen >= SEQ_MAX_QUEUE) + if (!seq_playing) + seq_startplay(); /* + * Give chance to drain the queue + */ - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP)) - { - /* - * Sleep until there is enough space on the queue - */ - - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - seq_sleep_flag.opts &= ~WK_SLEEP;; - } - - if (qlen >= SEQ_MAX_QUEUE) - { - return 0; /* + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP)) + { + /* + * Sleep until there is enough space on the queue + */ + + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + seq_sleep_flag.opts &= ~WK_SLEEP;; + } + if (qlen >= SEQ_MAX_QUEUE) + { + return 0; /* * To be sure */ - } - memcpy (&queue[qtail * EV_SZ], note, EV_SZ); + } + memcpy(&queue[qtail * EV_SZ], note, EV_SZ); - qtail = (qtail + 1) % SEQ_MAX_QUEUE; - qlen++; + qtail = (qtail + 1) % SEQ_MAX_QUEUE; + qlen++; - return 1; + return 1; } static int -extended_event (unsigned char *q) +extended_event(unsigned char *q) { - int dev = q[2]; - - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + int dev = q[2]; - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; - switch (q[1]) - { - case SEQ_NOTEOFF: - synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]); - break; + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; - case SEQ_NOTEON: - if (q[4] > 127 && q[4] != 255) - return 0; + switch (q[1]) + { + case SEQ_NOTEOFF: + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_NOTEON: + if (q[4] > 127 && q[4] != 255) + return 0; + + if (q[5] == 0) + { + synth_devs[dev]->kill_note(dev, q[3], q[4], q[5]); + break; + } + synth_devs[dev]->start_note(dev, q[3], q[4], q[5]); + break; + + case SEQ_PGMCHANGE: + synth_devs[dev]->set_instr(dev, q[3], q[4]); + break; + + case SEQ_AFTERTOUCH: + synth_devs[dev]->aftertouch(dev, q[3], q[4]); + break; + + case SEQ_BALANCE: + synth_devs[dev]->panning(dev, q[3], (char) q[4]); + break; + + case SEQ_CONTROLLER: + synth_devs[dev]->controller(dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); + break; + + case SEQ_VOLMODE: + if (synth_devs[dev]->volume_method != NULL) + synth_devs[dev]->volume_method(dev, q[3]); + break; - if (q[5] == 0) - { - synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]); - break; - } - synth_devs[dev]->start_note (dev, q[3], q[4], q[5]); - break; - - case SEQ_PGMCHANGE: - synth_devs[dev]->set_instr (dev, q[3], q[4]); - break; - - case SEQ_AFTERTOUCH: - synth_devs[dev]->aftertouch (dev, q[3], q[4]); - break; - - case SEQ_BALANCE: - synth_devs[dev]->panning (dev, q[3], (char) q[4]); - break; - - case SEQ_CONTROLLER: - synth_devs[dev]->controller (dev, q[3], q[4], (short) (q[5] | (q[6] << 8))); - break; - - case SEQ_VOLMODE: - if (synth_devs[dev]->volume_method != NULL) - synth_devs[dev]->volume_method (dev, q[3]); - break; - - default: - return -EINVAL; - } + default: + return -EINVAL; + } - return 0; + return 0; } static int -find_voice (int dev, int chn, int note) +find_voice(int dev, int chn, int note) { - unsigned short key; - int i; + unsigned short key; + int i; - key = (chn << 8) | (note + 1); + key = (chn << 8) | (note + 1); - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if (synth_devs[dev]->alloc.map[i] == key) - return i; + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if (synth_devs[dev]->alloc.map[i] == key) + return i; - return -1; + return -1; } static int -alloc_voice (int dev, int chn, int note) +alloc_voice(int dev, int chn, int note) { - unsigned short key; - int voice; + unsigned short key; + int voice; - key = (chn << 8) | (note + 1); + key = (chn << 8) | (note + 1); - voice = synth_devs[dev]->alloc_voice (dev, chn, note, - &synth_devs[dev]->alloc); - synth_devs[dev]->alloc.map[voice] = key; - synth_devs[dev]->alloc.alloc_times[voice] = - synth_devs[dev]->alloc.timestamp++; - return voice; + voice = synth_devs[dev]->alloc_voice(dev, chn, note, + &synth_devs[dev]->alloc); + synth_devs[dev]->alloc.map[voice] = key; + synth_devs[dev]->alloc.alloc_times[voice] = + synth_devs[dev]->alloc.timestamp++; + return voice; } static void -seq_chn_voice_event (unsigned char *event_rec) +seq_chn_voice_event(unsigned char *event_rec) { #define dev event_rec[1] #define cmd event_rec[2] @@ -516,73 +501,70 @@ #define note event_rec[4] #define parm event_rec[5] - int voice = -1; + int voice = -1; - if ((int) dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - if (seq_mode == SEQ_2) - { - if (synth_devs[dev]->alloc_voice) - voice = find_voice (dev, chn, note); - - if (cmd == MIDI_NOTEON && parm == 0) - { - cmd = MIDI_NOTEOFF; - parm = 64; - } - } - - switch (cmd) - { - case MIDI_NOTEON: - if (note > 127 && note != 255) /* Not a seq2 feature */ - return; - - if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) - { /* Internal synthesizer (FM, GUS, etc) */ - voice = alloc_voice (dev, chn, note); - } + if ((int) dev > max_synthdev || synth_devs[dev] == NULL) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; - if (voice == -1) - voice = chn; + if (seq_mode == SEQ_2) + { + if (synth_devs[dev]->alloc_voice) + voice = find_voice(dev, chn, note); - if (seq_mode == SEQ_2 && (int) dev < num_synths) - { - /* - * The MIDI channel 10 is a percussive channel. Use the note - * number to select the proper patch (128 to 255) to play. - */ - - if (chn == 9) - { - synth_devs[dev]->set_instr (dev, voice, 128 + note); - synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; - } - synth_devs[dev]->setup_voice (dev, voice, chn); - } - - synth_devs[dev]->start_note (dev, voice, note, parm); - break; - - case MIDI_NOTEOFF: - if (voice == -1) - voice = chn; - synth_devs[dev]->kill_note (dev, voice, note, parm); - break; - - case MIDI_KEY_PRESSURE: - if (voice == -1) - voice = chn; - synth_devs[dev]->aftertouch (dev, voice, parm); - break; + if (cmd == MIDI_NOTEON && parm == 0) + { + cmd = MIDI_NOTEOFF; + parm = 64; + } + } + switch (cmd) + { + case MIDI_NOTEON: + if (note > 127 && note != 255) /* Not a seq2 feature */ + return; + + if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) + { /* Internal synthesizer (FM, GUS, etc) */ + voice = alloc_voice(dev, chn, note); + } + if (voice == -1) + voice = chn; + + if (seq_mode == SEQ_2 && (int) dev < num_synths) + { + /* + * The MIDI channel 10 is a percussive channel. Use the note + * number to select the proper patch (128 to 255) to play. + */ + + if (chn == 9) + { + synth_devs[dev]->set_instr(dev, voice, 128 + note); + synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; + } + synth_devs[dev]->setup_voice(dev, voice, chn); + } + synth_devs[dev]->start_note(dev, voice, note, parm); + break; + + case MIDI_NOTEOFF: + if (voice == -1) + voice = chn; + synth_devs[dev]->kill_note(dev, voice, note, parm); + break; + + case MIDI_KEY_PRESSURE: + if (voice == -1) + voice = chn; + synth_devs[dev]->aftertouch(dev, voice, parm); + break; - default:; - } + default:; + } #undef dev #undef cmd #undef chn @@ -592,1455 +574,1422 @@ static void -seq_chn_common_event (unsigned char *event_rec) +seq_chn_common_event(unsigned char *event_rec) { - unsigned char dev = event_rec[1]; - unsigned char cmd = event_rec[2]; - unsigned char chn = event_rec[3]; - unsigned char p1 = event_rec[4]; - - /* unsigned char p2 = event_rec[5]; */ - unsigned short w14 = *(short *) &event_rec[6]; - - if ((int) dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - switch (cmd) - { - case MIDI_PGM_CHANGE: - if (seq_mode == SEQ_2) - { - synth_devs[dev]->chn_info[chn].pgm_num = p1; - if ((int) dev >= num_synths) - synth_devs[dev]->set_instr (dev, chn, p1); - } - else - synth_devs[dev]->set_instr (dev, chn, p1); + unsigned char dev = event_rec[1]; + unsigned char cmd = event_rec[2]; + unsigned char chn = event_rec[3]; + unsigned char p1 = event_rec[4]; - break; + /* unsigned char p2 = event_rec[5]; */ + unsigned short w14 = *(short *) &event_rec[6]; - case MIDI_CTL_CHANGE: - if (seq_mode == SEQ_2) - { - if (chn > 15 || p1 > 127) - break; - - synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; - - if (p1 < 32) /* Setting MSB should clear LSB to 0 */ - synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; - - if ((int) dev < num_synths) - { - int val = w14 & 0x7f; - int i, key; - - if (p1 < 64) /* Combine MSB and LSB */ - { - val = ((synth_devs[dev]-> - chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) - | (synth_devs[dev]-> - chn_info[chn].controllers[p1 | 32] & 0x7f); - p1 &= ~32; - } - - /* Handle all playing notes on this channel */ - - key = ((int) chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->controller (dev, i, p1, val); - } - else - synth_devs[dev]->controller (dev, chn, p1, w14); - } - else /* Mode 1 */ - synth_devs[dev]->controller (dev, chn, p1, w14); - break; - - case MIDI_PITCH_BEND: - if (seq_mode == SEQ_2) - { - synth_devs[dev]->chn_info[chn].bender_value = w14; + if ((int) dev > max_synthdev || synth_devs[dev] == NULL) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; - if ((int) dev < num_synths) - { /* Handle all playing notes on this channel */ - int i, key; - - key = (chn << 8); - - for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) - if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) - synth_devs[dev]->bender (dev, i, w14); - } - else - synth_devs[dev]->bender (dev, chn, w14); - } - else /* MODE 1 */ - synth_devs[dev]->bender (dev, chn, w14); - break; + switch (cmd) + { + case MIDI_PGM_CHANGE: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].pgm_num = p1; + if ((int) dev >= num_synths) + synth_devs[dev]->set_instr(dev, chn, p1); + } else + synth_devs[dev]->set_instr(dev, chn, p1); + + break; + + case MIDI_CTL_CHANGE: + if (seq_mode == SEQ_2) + { + if (chn > 15 || p1 > 127) + break; + + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; + + if (p1 < 32) /* Setting MSB should clear LSB to 0 */ + synth_devs[dev]->chn_info[chn].controllers[p1 + 32] = 0; + + if ((int) dev < num_synths) + { + int val = w14 & 0x7f; + int i, key; + + if (p1 < 64) /* Combine MSB and LSB */ + { + val = ((synth_devs[dev]-> + chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) + | (synth_devs[dev]-> + chn_info[chn].controllers[p1 | 32] & 0x7f); + p1 &= ~32; + } + /* Handle all playing notes on this channel */ + + key = ((int) chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->controller(dev, i, p1, val); + } else + synth_devs[dev]->controller(dev, chn, p1, w14); + } else /* Mode 1 */ + synth_devs[dev]->controller(dev, chn, p1, w14); + break; + + case MIDI_PITCH_BEND: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].bender_value = w14; + + if ((int) dev < num_synths) + { /* Handle all playing notes on this channel */ + int i, key; + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->bender(dev, i, w14); + } else + synth_devs[dev]->bender(dev, chn, w14); + } else /* MODE 1 */ + synth_devs[dev]->bender(dev, chn, w14); + break; - default:; - } + default:; + } } static int -seq_timing_event (unsigned char *event_rec) +seq_timing_event(unsigned char *event_rec) { - unsigned char cmd = event_rec[1]; - unsigned int parm = *(int *) &event_rec[4]; - - if (seq_mode == SEQ_2) - { - int ret; + unsigned char cmd = event_rec[1]; + unsigned int parm = *(int *) &event_rec[4]; - if ((ret = tmr->event (tmr_no, event_rec)) == TIMER_ARMED) - { - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } - } - return ret; - } - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - - /* - * NOTE! No break here. Execution of TMR_WAIT_REL continues in the - * next case (TMR_WAIT_ABS) - */ - - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - time = parm; - prev_event_time = time; + if (seq_mode == SEQ_2) + { + int ret; - seq_playing = 1; - if (softsynthp != NULL) - softsynthp (SSYN_REQUEST, time, 0, 0); - else - request_sound_timer (time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } - - return TIMER_ARMED; - } - break; + if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) + { + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } + } + return ret; + } + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; - case TMR_START: - if (softsynthp != NULL) - { - softsynthp (SSYN_START, 0, 0, 0); - seq_time = 0; - } - else - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - break; - - case TMR_STOP: - break; - - case TMR_CONTINUE: - break; - - case TMR_TEMPO: - break; - - case TMR_ECHO: - if (seq_mode == SEQ_2) - seq_copy_to_input (event_rec, 8); - else - { - parm = (parm << 8 | SEQ_ECHO); - seq_copy_to_input ((unsigned char *) &parm, 4); - } - break; + /* + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ + + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + time = parm; + prev_event_time = time; + + seq_playing = 1; + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, time, 0, 0); + else + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } + return TIMER_ARMED; + } + break; + + case TMR_START: + if (softsynthp != NULL) + { + softsynthp(SSYN_START, 0, 0, 0); + seq_time = 0; + } else + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + break; + + case TMR_STOP: + break; + + case TMR_CONTINUE: + break; + + case TMR_TEMPO: + break; + + case TMR_ECHO: + if (seq_mode == SEQ_2) + seq_copy_to_input(event_rec, 8); + else + { + parm = (parm << 8 | SEQ_ECHO); + seq_copy_to_input((unsigned char *) &parm, 4); + } + break; - default:; - } + default:; + } - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static void -seq_local_event (unsigned char *event_rec) +seq_local_event(unsigned char *event_rec) { - unsigned char cmd = event_rec[1]; - unsigned int parm = *((unsigned int *) &event_rec[4]); + unsigned char cmd = event_rec[1]; + unsigned int parm = *((unsigned int *) &event_rec[4]); - switch (cmd) - { - case LOCL_STARTAUDIO: + switch (cmd) + { + case LOCL_STARTAUDIO: #ifdef CONFIG_AUDIO - DMAbuf_start_devices (parm); + DMAbuf_start_devices(parm); #endif - break; + break; - default:; - } + default:; + } } static void -seq_sysex_message (unsigned char *event_rec) +seq_sysex_message(unsigned char *event_rec) { - int dev = event_rec[1]; - int i, l = 0; - unsigned char *buf = &event_rec[2]; - - if ((int) dev > max_synthdev) - return; - if (!(synth_open_mask & (1 << dev))) - return; - if (!synth_devs[dev]) - return; - - l = 0; - for (i = 0; i < 6 && buf[i] != 0xff; i++) - l = i + 1; - - if (!synth_devs[dev]->send_sysex) - return; - if (l > 0) - synth_devs[dev]->send_sysex (dev, buf, l); + int dev = event_rec[1]; + int i, l = 0; + unsigned char *buf = &event_rec[2]; + + if ((int) dev > max_synthdev) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + l = 0; + for (i = 0; i < 6 && buf[i] != 0xff; i++) + l = i + 1; + + if (!synth_devs[dev]->send_sysex) + return; + if (l > 0) + synth_devs[dev]->send_sysex(dev, buf, l); } static int -play_event (unsigned char *q) +play_event(unsigned char *q) { - /* - * NOTE! This routine returns - * 0 = normal event played. - * 1 = Timer armed. Suspend playback until timer callback. - * 2 = MIDI output buffer full. Restore queue and suspend until timer - */ - unsigned int *delay; - - switch (q[0]) - { - case SEQ_NOTEOFF: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->kill_note (0, q[1], 255, q[3]); - break; - - case SEQ_NOTEON: - if (q[4] < 128 || q[4] == 255) - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->start_note (0, q[1], q[2], q[3]); - break; - - case SEQ_WAIT: - delay = (unsigned int *) q; /* - * Bytes 1 to 3 are containing the * - * delay in 'ticks' - */ - *delay = (*delay >> 8) & 0xffffff; + /* + * NOTE! This routine returns + * 0 = normal event played. + * 1 = Timer armed. Suspend playback until timer callback. + * 2 = MIDI output buffer full. Restore queue and suspend until timer + */ + unsigned int *delay; - if (*delay > 0) - { - long time; - - seq_playing = 1; - time = *delay; - prev_event_time = time; - - if (softsynthp != NULL) - softsynthp (SSYN_REQUEST, time, 0, 0); - else - request_sound_timer (time); - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } - /* - * The timer is now active and will reinvoke this function - * after the timer expires. Return to the caller now. - */ - return 1; - } - break; - - case SEQ_PGMCHANGE: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->set_instr (0, q[1], q[2]); - break; + switch (q[0]) + { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note(0, q[1], 255, q[3]); + break; + + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note(0, q[1], q[2], q[3]); + break; + + case SEQ_WAIT: + delay = (unsigned int *) q; /* + * Bytes 1 to 3 are containing the * + * delay in 'ticks' + */ + *delay = (*delay >> 8) & 0xffffff; + + if (*delay > 0) + { + long time; + + seq_playing = 1; + time = *delay; + prev_event_time = time; + + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, time, 0, 0); + else + request_sound_timer(time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + { + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. + */ + return 1; + } + break; + + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr(0, q[1], q[2]); + break; - case SEQ_SYNCTIMER: /* - * Reset timer + case SEQ_SYNCTIMER: /* + * Reset timer */ - if (softsynthp != NULL) - seq_time = 0; - else - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; - if (softsynthp != NULL) - softsynthp (SSYN_START, 0, 0, 0); - break; + if (softsynthp != NULL) + seq_time = 0; + else + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; + if (softsynthp != NULL) + softsynthp(SSYN_START, 0, 0, 0); + break; - case SEQ_MIDIPUTC: /* + case SEQ_MIDIPUTC: /* * Put a midi character */ - if (midi_opened[q[2]]) - { - int dev; - - dev = q[2]; - - if (dev < 0 || dev >= num_midis) - break; + if (midi_opened[q[2]]) + { + int dev; + + dev = q[2]; + + if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) + break; + + if (!midi_devs[dev]->outputc(dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ + + seq_playing = 1; + if (softsynthp != NULL) + softsynthp(SSYN_REQUEST, -1, 0, 0); + else + request_sound_timer(-1); + return 2; + } else + midi_written[dev] = 1; + } + break; + + case SEQ_ECHO: + seq_copy_to_input(q, 4); /* + * Echo back to the process + */ + break; + + case SEQ_PRIVATE: + if ((int) q[1] < max_synthdev) + synth_devs[q[1]]->hw_control(q[1], q); + break; + + case SEQ_EXTENDED: + extended_event(q); + break; + + case EV_CHN_VOICE: + seq_chn_voice_event(q); + break; + + case EV_CHN_COMMON: + seq_chn_common_event(q); + break; + + case EV_TIMING: + if (seq_timing_event(q) == TIMER_ARMED) + { + return 1; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event(q); + break; + + case EV_SYSEX: + seq_sysex_message(q); + break; - if (!midi_devs[dev]->outputc (dev, q[1])) - { - /* - * Output FIFO is full. Wait one timer cycle and try again. - */ - - seq_playing = 1; - if (softsynthp != NULL) - softsynthp (SSYN_REQUEST, -1, 0, 0); - else - request_sound_timer (-1); - return 2; - } - else - midi_written[dev] = 1; - } - break; - - case SEQ_ECHO: - seq_copy_to_input (q, 4); /* - * Echo back to the process - */ - break; - - case SEQ_PRIVATE: - if ((int) q[1] < max_synthdev) - synth_devs[q[1]]->hw_control (q[1], q); - break; - - case SEQ_EXTENDED: - extended_event (q); - break; - - case EV_CHN_VOICE: - seq_chn_voice_event (q); - break; - - case EV_CHN_COMMON: - seq_chn_common_event (q); - break; - - case EV_TIMING: - if (seq_timing_event (q) == TIMER_ARMED) - { - return 1; - } - break; - - case EV_SEQ_LOCAL: - seq_local_event (q); - break; - - case EV_SYSEX: - seq_sysex_message (q); - break; - - default:; - } + default:; + } - return 0; + return 0; } static void -seq_startplay (void) +seq_startplay(void) { - unsigned long flags; - int this_one, action; + unsigned long flags; + int this_one, action; - while (qlen > 0) - { + while (qlen > 0) + { - save_flags (flags); - cli (); - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - restore_flags (flags); - - seq_playing = 1; - - if ((action = play_event (&queue[this_one * EV_SZ]))) - { /* Suspend playback. Next timer routine invokes this routine again */ - if (action == 2) - { - qlen++; - qhead = this_one; - } - return; - } - - } - - seq_playing = 0; - - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { + save_flags(flags); + cli(); + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + restore_flags(flags); + + seq_playing = 1; + + if ((action = play_event(&queue[this_one * EV_SZ]))) + { /* Suspend playback. Next timer routine invokes this routine again */ + if (action == 2) + { + qlen++; + qhead = this_one; + } + return; + } + } + + seq_playing = 0; + + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); - } + unsigned long flags; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); + } } static void -reset_controllers (int dev, unsigned char *controller, int update_dev) +reset_controllers(int dev, unsigned char *controller, int update_dev) { - int i; + int i; - for (i = 0; i < 128; i++) - controller[i] = ctrl_def_values[i]; + for (i = 0; i < 128; i++) + controller[i] = ctrl_def_values[i]; } static void -setup_mode2 (void) +setup_mode2(void) { - int dev; - - max_synthdev = num_synths; + int dev; - for (dev = 0; dev < num_midis; dev++) - if (midi_devs[dev]->converter != NULL) - { - synth_devs[max_synthdev++] = - midi_devs[dev]->converter; - } + max_synthdev = num_synths; - for (dev = 0; dev < max_synthdev; dev++) - { - int chn; + for (dev = 0; dev < num_midis; dev++) + if (midi_devs[dev] && midi_devs[dev]->converter != NULL) + { + synth_devs[max_synthdev++] = + midi_devs[dev]->converter; + } + for (dev = 0; dev < max_synthdev; dev++) + { + int chn; - synth_devs[dev]->sysex_ptr = 0; - synth_devs[dev]->emulation = 0; + synth_devs[dev]->sysex_ptr = 0; + synth_devs[dev]->emulation = 0; - for (chn = 0; chn < 16; chn++) - { - synth_devs[dev]->chn_info[chn].pgm_num = 0; - reset_controllers (dev, - synth_devs[dev]->chn_info[chn].controllers, - 0); - synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ - synth_devs[dev]->chn_info[chn].bender_range = 200; - } - } + for (chn = 0; chn < 16; chn++) + { + synth_devs[dev]->chn_info[chn].pgm_num = 0; + reset_controllers(dev, + synth_devs[dev]->chn_info[chn].controllers, + 0); + synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ + synth_devs[dev]->chn_info[chn].bender_range = 200; + } + } - max_mididev = 0; - seq_mode = SEQ_2; + max_mididev = 0; + seq_mode = SEQ_2; } int -sequencer_open (int dev, struct fileinfo *file) +sequencer_open(int dev, struct fileinfo *file) { - int retval, mode, i; - int level, tmp; - unsigned long flags; + int retval, mode, i; + int level, tmp; + unsigned long flags; - if (!sequencer_ok) - sequencer_init (); + if (!sequencer_ok) + sequencer_init(); - level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; + level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - DEB (printk ("sequencer_open(dev=%d)\n", dev)); + DEB(printk("sequencer_open(dev=%d)\n", dev)); - if (!sequencer_ok) - { - printk ("Soundcard: Sequencer not initialized\n"); - return -ENXIO; - } + if (!sequencer_ok) + { + printk("Soundcard: Sequencer not initialized\n"); + return -ENXIO; + } + if (dev) /* Patch manager device (obsolete) */ + { + return -ENXIO; + } + if (mode == OPEN_READ) + if (!num_midis) + { + printk("Sequencer: No MIDI devices. Input not possible\n"); + sequencer_busy = 0; + return -ENXIO; + } + save_flags(flags); + cli(); + if (sequencer_busy) + { + restore_flags(flags); + return -EBUSY; + } + sequencer_busy = 1; + obsolete_api_used = 0; + restore_flags(flags); + + max_mididev = num_midis; + max_synthdev = num_synths; + pre_event_timeout = 0; + seq_mode = SEQ_1; - if (dev) /* Patch manager device (obsolete) */ - { - return -ENXIO; - } + if (pending_timer != -1) + { + tmr_no = pending_timer; + pending_timer = -1; + } + if (tmr_no == -1) /* Not selected yet */ + { + int i, best; - if (mode == OPEN_READ) - if (!num_midis) - { - printk ("Sequencer: No MIDI devices. Input not possible\n"); - sequencer_busy = 0; - return -ENXIO; - } + best = -1; + for (i = 0; i < num_sound_timers; i++) + if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) + { + tmr_no = i; + best = sound_timer_devs[i]->priority; + } + if (tmr_no == -1) /* Should not be */ + tmr_no = 0; + } + tmr = sound_timer_devs[tmr_no]; - save_flags (flags); - cli (); - if (sequencer_busy) - { - restore_flags (flags); - return -EBUSY; - } - sequencer_busy = 1; - obsolete_api_used = 0; - restore_flags (flags); - - max_mididev = num_midis; - max_synthdev = num_synths; - pre_event_timeout = 0; - seq_mode = SEQ_1; - - if (pending_timer != -1) - { - tmr_no = pending_timer; - pending_timer = -1; - } - - if (tmr_no == -1) /* Not selected yet */ - { - int i, best; - - best = -1; - for (i = 0; i < num_sound_timers; i++) - if (sound_timer_devs[i]->priority > best) - { - tmr_no = i; - best = sound_timer_devs[i]->priority; - } - - if (tmr_no == -1) /* Should not be */ - tmr_no = 0; - } - - tmr = sound_timer_devs[tmr_no]; - - if (level == 2) - { - if (tmr == NULL) - { - printk ("sequencer: No timer for level 2\n"); - sequencer_busy = 0; - return -ENXIO; - } - setup_mode2 (); - } - - if (!max_synthdev && !max_mididev) - return -ENXIO; - - synth_open_mask = 0; - - for (i = 0; i < max_mididev; i++) - { - midi_opened[i] = 0; - midi_written[i] = 0; - } - - for (i = 0; i < max_synthdev; i++) - { - if ((tmp = synth_devs[i]->open (i, mode)) < 0) - { - printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); - if (synth_devs[i]->midi_dev) - printk ("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); - } - else - { - synth_open_mask |= (1 << i); - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 1; - } - } - - if (softsynthp != NULL) - seq_time = 0; - else - seq_time = jiffies; - - prev_input_time = 0; - prev_event_time = 0; - if (softsynthp != NULL) - softsynthp (SSYN_START, 0, 0, 0); + if (level == 2) + { + if (tmr == NULL) + { + printk("sequencer: No timer for level 2\n"); + sequencer_busy = 0; + return -ENXIO; + } + setup_mode2(); + } + if (!max_synthdev && !max_mididev) + return -ENXIO; - if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) - { /* - * Initialize midi input devices - */ - for (i = 0; i < max_mididev; i++) - if (!midi_opened[i]) + synth_open_mask = 0; + + for (i = 0; i < max_mididev; i++) { - if ((retval = midi_devs[i]->open (i, mode, - sequencer_midi_input, sequencer_midi_output)) >= 0) - midi_opened[i] = 1; + midi_opened[i] = 0; + midi_written[i] = 0; } - } - if (seq_mode == SEQ_2) - { - tmr->open (tmr_no, seq_mode); - } + for (i = 0; i < max_synthdev; i++) + { + if ((tmp = synth_devs[i]->open(i, mode)) < 0) + { + printk("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); + if (synth_devs[i]->midi_dev) + printk("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); + } else + { + synth_open_mask |= (1 << i); + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 1; + } + } - seq_sleep_flag.opts = WK_NONE; - midi_sleep_flag.opts = WK_NONE; - output_threshold = SEQ_MAX_QUEUE / 2; + if (softsynthp != NULL) + seq_time = 0; + else + seq_time = jiffies; + + prev_input_time = 0; + prev_event_time = 0; + if (softsynthp != NULL) + softsynthp(SSYN_START, 0, 0, 0); - return 0; + if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) + { /* + * Initialize midi input devices + */ + for (i = 0; i < max_mididev; i++) + if (!midi_opened[i]) + { + if ((retval = midi_devs[i]->open(i, mode, + sequencer_midi_input, sequencer_midi_output)) >= 0) + midi_opened[i] = 1; + } + } + if (seq_mode == SEQ_2) + { + tmr->open(tmr_no, seq_mode); + } + seq_sleep_flag.opts = WK_NONE; + midi_sleep_flag.opts = WK_NONE; + output_threshold = SEQ_MAX_QUEUE / 2; + + return 0; } void -seq_drain_midi_queues (void) +seq_drain_midi_queues(void) { - int i, n; + int i, n; - /* - * Give the Midi drivers time to drain their output queues - */ - - n = 1; - - while (!(current->signal & ~current->blocked) && n) - { - n = 0; - - for (i = 0; i < max_mididev; i++) - if (midi_opened[i] && midi_written[i]) - if (midi_devs[i]->buffer_status != NULL) - if (midi_devs[i]->buffer_status (i)) - n++; - - /* - * Let's have a delay - */ - if (n) - { + /* + * Give the Midi drivers time to drain their output queues + */ + + n = 1; + while (!(current->signal & ~current->blocked) && n) { - unsigned long tlimit; + n = 0; - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - } - } + for (i = 0; i < max_mididev; i++) + if (midi_opened[i] && midi_written[i]) + if (midi_devs[i]->buffer_status != NULL) + if (midi_devs[i]->buffer_status(i)) + n++; + + /* + * Let's have a delay + */ + if (n) + { + + { + unsigned long tlimit; + + if (HZ / 10) + current->timeout = tlimit = jiffies + (HZ / 10); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + } + } } void -sequencer_release (int dev, struct fileinfo *file) +sequencer_release(int dev, struct fileinfo *file) { - int i; - int mode = file->mode & O_ACCMODE; + int i; + int mode = file->mode & O_ACCMODE; - dev = dev >> 4; + dev = dev >> 4; - DEB (printk ("sequencer_release(dev=%d)\n", dev)); + DEB(printk("sequencer_release(dev=%d)\n", dev)); - /* - * Wait until the queue is empty (if we don't have nonblock) - */ + /* + * Wait until the queue is empty (if we don't have nonblock) + */ - if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? - 1 : 0)) - while (!(current->signal & ~current->blocked) && qlen > 0) - { - seq_sync (); + if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? + 1 : 0)) + while (!(current->signal & ~current->blocked) && qlen > 0) + { + seq_sync(); - { - unsigned long tlimit; + { + unsigned long tlimit; - if (3 * HZ) - current->timeout = tlimit = jiffies + (3 * HZ); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; /* Extra delay */ - } - - if (mode != OPEN_READ) - seq_drain_midi_queues (); /* - * Ensure the output queues are empty - */ - seq_reset (); - if (mode != OPEN_READ) - seq_drain_midi_queues (); /* - * Flush the all notes off messages - */ + if (3 * HZ) + current->timeout = tlimit = jiffies + (3 * HZ); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; /* Extra delay */ + } + if (mode != OPEN_READ) + seq_drain_midi_queues(); /* + * Ensure the output queues are empty + */ + seq_reset(); + if (mode != OPEN_READ) + seq_drain_midi_queues(); /* + * Flush the all notes off messages + */ - for (i = 0; i < max_synthdev; i++) - { - if (synth_open_mask & (1 << i)) /* - * Actually opened - */ - if (synth_devs[i]) - { - synth_devs[i]->close (i); - - if (synth_devs[i]->midi_dev) - midi_opened[synth_devs[i]->midi_dev] = 0; - } - } - - for (i = 0; i < max_mididev; i++) - { - if (midi_opened[i]) - midi_devs[i]->close (i); - } - - if (seq_mode == SEQ_2) - tmr->close (tmr_no); - - if (obsolete_api_used) - printk ("/dev/music: Obsolete (4 byte) API was used by this program\n"); - sequencer_busy = 0; + for (i = 0; i < max_synthdev; i++) + { + if (synth_open_mask & (1 << i)) /* + * Actually opened + */ + if (synth_devs[i]) + { + synth_devs[i]->close(i); + + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 0; + } + } + + for (i = 0; i < max_mididev; i++) + { + if (midi_opened[i]) + midi_devs[i]->close(i); + } + + if (seq_mode == SEQ_2) + tmr->close(tmr_no); + + if (obsolete_api_used) + printk("/dev/music: Obsolete (4 byte) API was used by this program\n"); + sequencer_busy = 0; } static int -seq_sync (void) +seq_sync(void) { - unsigned long flags; + unsigned long flags; - if (qlen && !seq_playing && !(current->signal & ~current->blocked)) - seq_startplay (); + if (qlen && !seq_playing && !(current->signal & ~current->blocked)) + seq_startplay(); - save_flags (flags); - cli (); - if (qlen > 0) - { + save_flags(flags); + cli(); + if (qlen > 0) + { - { - unsigned long tlimit; + { + unsigned long tlimit; - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - } - restore_flags (flags); + if (HZ) + current->timeout = tlimit = jiffies + (HZ); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + } + restore_flags(flags); - return qlen; + return qlen; } static void -midi_outc (int dev, unsigned char data) +midi_outc(int dev, unsigned char data) { - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ - - int n; - unsigned long flags; - - /* - * This routine sends one byte to the Midi channel. - * If the output FIFO is full, it waits until there - * is space in the queue - */ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ - n = 3 * HZ; /* Timeout */ + int n; + unsigned long flags; - save_flags (flags); - cli (); - while (n && !midi_devs[dev]->outputc (dev, data)) - { + /* + * This routine sends one byte to the Midi channel. + * If the output FIFO is full, it waits until there + * is space in the queue + */ + + n = 3 * HZ; /* Timeout */ + + save_flags(flags); + cli(); + while (n && !midi_devs[dev]->outputc(dev, data)) + { - { - unsigned long tlimit; + { + unsigned long tlimit; - if (4) - current->timeout = tlimit = jiffies + (4); - else - tlimit = (unsigned long) -1; - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - }; - n--; - } - restore_flags (flags); + if (4) + current->timeout = tlimit = jiffies + (4); + else + tlimit = (unsigned long) -1; + seq_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&seq_sleeper); + if (!(seq_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + seq_sleep_flag.opts |= WK_TIMEOUT; + } + seq_sleep_flag.opts &= ~WK_SLEEP; + }; + n--; + } + restore_flags(flags); } static void -seq_reset (void) +seq_reset(void) { - /* - * NOTE! Calls sleep(). Don't call this from interrupt. - */ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ - int i; - int chn; - unsigned long flags; + int i; + int chn; + unsigned long flags; - if (softsynthp != NULL) - softsynthp (SSYN_STOP, 0, 0, 0); - else - sound_stop_timer (); + if (softsynthp != NULL) + softsynthp(SSYN_STOP, 0, 0, 0); + else + sound_stop_timer(); - seq_time = jiffies; - prev_input_time = 0; - prev_event_time = 0; + seq_time = jiffies; + prev_input_time = 0; + prev_event_time = 0; - qlen = qhead = qtail = 0; - iqlen = iqhead = iqtail = 0; + qlen = qhead = qtail = 0; + iqlen = iqhead = iqtail = 0; - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - synth_devs[i]->reset (i); + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + synth_devs[i]->reset(i); - if (seq_mode == SEQ_2) - { + if (seq_mode == SEQ_2) + { - for (chn = 0; chn < 16; chn++) - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - { - synth_devs[i]->controller (i, chn, 123, 0); /* All notes off */ - synth_devs[i]->controller (i, chn, 121, 0); /* Reset all ctl */ - synth_devs[i]->bender (i, chn, 1 << 13); /* Bender off */ - } - - } - else - /* seq_mode == SEQ_1 */ - { - for (i = 0; i < max_mididev; i++) - if (midi_written[i]) /* - * Midi used. Some notes may still be playing - */ + for (chn = 0; chn < 16; chn++) + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + { + synth_devs[i]->controller(i, chn, 123, 0); /* All notes off */ + synth_devs[i]->controller(i, chn, 121, 0); /* Reset all ctl */ + synth_devs[i]->bender(i, chn, 1 << 13); /* Bender off */ + } + } else + /* seq_mode == SEQ_1 */ { - /* - * Sending just a ACTIVE SENSING message should be enough to stop all - * playing notes. Since there are devices not recognizing the - * active sensing, we have to send some all notes off messages also. - */ - midi_outc (i, 0xfe); - - for (chn = 0; chn < 16; chn++) - { - midi_outc (i, - (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ - midi_outc (i, 0x7b); /* All notes off */ - midi_outc (i, 0); /* Dummy parameter */ - } - - midi_devs[i]->close (i); - - midi_written[i] = 0; - midi_opened[i] = 0; - } - } - - seq_playing = 0; - - save_flags (flags); - cli (); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up (&seq_sleeper); - }; - } - restore_flags (flags); + for (i = 0; i < max_mididev; i++) + if (midi_written[i]) /* + * Midi used. Some notes may still be playing + */ + { + /* + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ + midi_outc(i, 0xfe); + + for (chn = 0; chn < 16; chn++) + { + midi_outc(i, + (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ + midi_outc(i, 0x7b); /* All notes off */ + midi_outc(i, 0); /* Dummy parameter */ + } + + midi_devs[i]->close(i); + + midi_written[i] = 0; + midi_opened[i] = 0; + } + } + + seq_playing = 0; + + save_flags(flags); + cli(); + if ((seq_sleep_flag.opts & WK_SLEEP)) + { + /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ + { + seq_sleep_flag.opts = WK_WAKEUP; + wake_up(&seq_sleeper); + }; + } + restore_flags(flags); } static void -seq_panic (void) +seq_panic(void) { - /* - * This routine is called by the application in case the user - * wants to reset the system to the default state. - */ - - seq_reset (); - - /* - * Since some of the devices don't recognize the active sensing and - * all notes off messages, we have to shut all notes manually. - * - * TO BE IMPLEMENTED LATER - */ - - /* - * Also return the controllers to their default states - */ + /* + * This routine is called by the application in case the user + * wants to reset the system to the default state. + */ + + seq_reset(); + + /* + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER + */ + + /* + * Also return the controllers to their default states + */ } int -sequencer_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +sequencer_ioctl(int dev, struct fileinfo *file, + unsigned int cmd, caddr_t arg) { - int midi_dev, orig_dev, val; - int mode = file->mode & O_ACCMODE; - - orig_dev = dev = dev >> 4; - - switch (cmd) - { - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SOURCE: - - if (seq_mode != SEQ_2) - return -EINVAL; - return tmr->ioctl (tmr_no, cmd, arg); - break; - - case SNDCTL_TMR_SELECT: - - if (seq_mode != SEQ_2) - return -EINVAL; - pending_timer = *(int *) arg; - - if (pending_timer < 0 || pending_timer >= num_sound_timers) - { - pending_timer = -1; - return -EINVAL; - } - - return (*(int *) arg = pending_timer); - break; - - case SNDCTL_SEQ_PANIC: - seq_panic (); - break; - - case SNDCTL_SEQ_SYNC: + int midi_dev, orig_dev, val; + int mode = file->mode & O_ACCMODE; - if (mode == OPEN_READ) - return 0; - while (qlen > 0 && !(current->signal & ~current->blocked)) - seq_sync (); - if (qlen) - return -EINTR; - else - return 0; - break; - - case SNDCTL_SEQ_RESET: - - seq_reset (); - return 0; - break; - - case SNDCTL_SEQ_TESTMIDI: - midi_dev = *(int *) arg; - if (midi_dev < 0 || midi_dev >= max_mididev) - return -ENXIO; + orig_dev = dev = dev >> 4; - if (!midi_opened[midi_dev]) - { - int err, mode; - - mode = file->mode & O_ACCMODE; - if ((err = midi_devs[midi_dev]->open (midi_dev, mode, - sequencer_midi_input, - sequencer_midi_output)) < 0) - return err; - } - - midi_opened[midi_dev] = 1; + switch (cmd) + { + case SNDCTL_TMR_TIMEBASE: + case SNDCTL_TMR_TEMPO: + case SNDCTL_TMR_START: + case SNDCTL_TMR_STOP: + case SNDCTL_TMR_CONTINUE: + case SNDCTL_TMR_METRONOME: + case SNDCTL_TMR_SOURCE: + + if (seq_mode != SEQ_2) + return -EINVAL; + return tmr->ioctl(tmr_no, cmd, arg); + break; + + case SNDCTL_TMR_SELECT: + + if (seq_mode != SEQ_2) + return -EINVAL; + pending_timer = *(int *) arg; + + if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) + { + pending_timer = -1; + return -EINVAL; + } + return (*(int *) arg = pending_timer); + break; + + case SNDCTL_SEQ_PANIC: + seq_panic(); + break; + + case SNDCTL_SEQ_SYNC: + + if (mode == OPEN_READ) + return 0; + while (qlen > 0 && !(current->signal & ~current->blocked)) + seq_sync(); + if (qlen) + return -EINTR; + else + return 0; + break; + + case SNDCTL_SEQ_RESET: + + seq_reset(); + return 0; + break; + + case SNDCTL_SEQ_TESTMIDI: + midi_dev = *(int *) arg; + if (midi_dev < 0 || midi_dev >= max_mididev) + return -ENXIO; + + if (!midi_opened[midi_dev]) + { + int err, mode; + + mode = file->mode & O_ACCMODE; + if ((err = midi_devs[midi_dev]->open(midi_dev, mode, + sequencer_midi_input, + sequencer_midi_output)) < 0) + return err; + } + midi_opened[midi_dev] = 1; + + return 0; + break; + + case SNDCTL_SEQ_GETINCOUNT: + if (mode == OPEN_WRITE) + return 0; + return (*(int *) arg = iqlen); + break; + + case SNDCTL_SEQ_GETOUTCOUNT: + + if (mode == OPEN_READ) + return 0; + return (*(int *) arg = SEQ_MAX_QUEUE - qlen); + break; + + case SNDCTL_SEQ_GETTIME: + if (seq_mode == SEQ_2) + return tmr->ioctl(tmr_no, cmd, arg); + + if (softsynthp != NULL) + return (*(int *) arg = softsynthp(SSYN_GETTIME, 0, 0, 0)); + else + return (*(int *) arg = jiffies - seq_time); + break; + + case SNDCTL_SEQ_CTRLRATE: + /* + * If *arg == 0, just return the current rate + */ + if (seq_mode == SEQ_2) + return tmr->ioctl(tmr_no, cmd, arg); + + val = *(int *) arg; + if (val != 0) + return -EINVAL; + + return (*(int *) arg = HZ); + break; + + case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SYNTH_REMOVESAMPLE: + case SNDCTL_SYNTH_CONTROL: + { + int err; - return 0; - break; + dev = *(int *) arg; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + { + return -ENXIO; + } + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + { + return -EBUSY; + } + err = synth_devs[dev]->ioctl(dev, cmd, arg); + return err; + } + break; + + case SNDCTL_SEQ_NRSYNTHS: + return (*(int *) arg = max_synthdev); + break; + + case SNDCTL_SEQ_NRMIDIS: + return (*(int *) arg = max_mididev); + break; - case SNDCTL_SEQ_GETINCOUNT: - if (mode == OPEN_WRITE) - return 0; - return (*(int *) arg = iqlen); - break; + case SNDCTL_SYNTH_MEMAVL: + { + int dev; - case SNDCTL_SEQ_GETOUTCOUNT: + dev = *(int *) arg; - if (mode == OPEN_READ) - return 0; - return (*(int *) arg = SEQ_MAX_QUEUE - qlen); - break; + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; - case SNDCTL_SEQ_GETTIME: - if (seq_mode == SEQ_2) - return tmr->ioctl (tmr_no, cmd, arg); - - if (softsynthp != NULL) - return (*(int *) arg = softsynthp (SSYN_GETTIME, 0, 0, 0)); - else - return (*(int *) arg = jiffies - seq_time); - break; - - case SNDCTL_SEQ_CTRLRATE: - /* - * If *arg == 0, just return the current rate - */ - if (seq_mode == SEQ_2) - return tmr->ioctl (tmr_no, cmd, arg); + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; - val = *(int *) arg; - if (val != 0) - return -EINVAL; + return (*(int *) arg = synth_devs[dev]->ioctl(dev, cmd, arg)); + } + break; - return (*(int *) arg = HZ); - break; + case SNDCTL_FM_4OP_ENABLE: + { + int dev; - case SNDCTL_SEQ_RESETSAMPLES: - case SNDCTL_SYNTH_REMOVESAMPLE: - case SNDCTL_SYNTH_CONTROL: - { - int err; + dev = *(int *) arg; - dev = *(int *) arg; - if (dev < 0 || dev >= num_synths) - { - return -ENXIO; - } + if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL) + return -ENXIO; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - { - return -EBUSY; - } + if (!(synth_open_mask & (1 << dev))) + return -ENXIO; - err = synth_devs[dev]->ioctl (dev, cmd, arg); - return err; - } - break; + synth_devs[dev]->ioctl(dev, cmd, arg); + return 0; + } + break; - case SNDCTL_SEQ_NRSYNTHS: - return (*(int *) arg = max_synthdev); - break; + case SNDCTL_SYNTH_INFO: + { + struct synth_info inf; + int dev; - case SNDCTL_SEQ_NRMIDIS: - return (*(int *) arg = max_mididev); - break; + memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf)); + dev = inf.device; - case SNDCTL_SYNTH_MEMAVL: - { - int dev; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; - dev = *(int *) arg; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; - if (dev < 0 || dev >= num_synths) - return -ENXIO; + return synth_devs[dev]->ioctl(dev, cmd, arg); + } + break; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; - return (*(int *) arg = synth_devs[dev]->ioctl (dev, cmd, arg)); - } - break; + /* Like SYNTH_INFO but returns ID in the name field */ + case SNDCTL_SYNTH_ID: + { + struct synth_info inf; + int dev; - case SNDCTL_FM_4OP_ENABLE: - { - int dev; + memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf)); + dev = inf.device; - dev = *(int *) arg; + if (dev < 0 || dev >= max_synthdev) + return -ENXIO; - if (dev < 0 || dev >= num_synths) - return -ENXIO; + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return -EBUSY; + + memcpy((char *) &inf, (char *) synth_devs[dev]->info, sizeof(inf)); + strcpy(inf.name, synth_devs[dev]->id); + inf.device = dev; + memcpy((&((char *) arg)[0]), (char *) &inf, sizeof(inf)); + return 0; + } + break; - if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + case SNDCTL_SEQ_OUTOFBAND: + { + struct seq_event_rec event_rec; + unsigned long flags; - synth_devs[dev]->ioctl (dev, cmd, arg); - return 0; - } - break; + memcpy((char *) &event_rec, (&((char *) arg)[0]), sizeof(event_rec)); - case SNDCTL_SYNTH_INFO: - { - struct synth_info inf; - int dev; + save_flags(flags); + cli(); + play_event(event_rec.arr); + restore_flags(flags); - memcpy ((char *) &inf, (&((char *) arg)[0]), sizeof (inf)); - dev = inf.device; + return 0; + } + break; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + case SNDCTL_MIDI_INFO: + { + struct midi_info inf; + int dev; + char *pp; + + memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf)); + dev = inf.device; + + if (dev < 0 || dev >= max_mididev) + return -ENXIO; + + midi_devs[dev]->info.device = dev; + pp = (char *) &midi_devs[dev]->info; + memcpy((&((char *) arg)[0]), pp, sizeof(inf)); + return 0; + } + break; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + case SNDCTL_SEQ_THRESHOLD: + { + int tmp; - return synth_devs[dev]->ioctl (dev, cmd, arg); - } - break; + tmp = *(int *) arg; + if (tmp < 1) + tmp = 1; + if (tmp >= SEQ_MAX_QUEUE) + tmp = SEQ_MAX_QUEUE - 1; + output_threshold = tmp; + return 0; + } + break; - /* Like SYNTH_INFO but returns ID in the name field */ - case SNDCTL_SYNTH_ID: - { - struct synth_info inf; - int dev; + case SNDCTL_MIDI_PRETIME: + { + int val; - memcpy ((char *) &inf, (&((char *) arg)[0]), sizeof (inf)); - dev = inf.device; + val = *(int *) arg; - if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + if (val < 0) + val = 0; - if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + val = (HZ * val) / 10; + pre_event_timeout = val; + return (*(int *) arg = val); + } + break; + + default: + if (mode == OPEN_READ) + return -EIO; + + if (!synth_devs[0]) + return -ENXIO; + if (!(synth_open_mask & (1 << 0))) + return -ENXIO; + return synth_devs[0]->ioctl(0, cmd, arg); + break; + } - memcpy ((char *) &inf, (char *) synth_devs[dev]->info, sizeof (inf)); - strcpy (inf.name, synth_devs[dev]->id); - inf.device = dev; - memcpy ((&((char *) arg)[0]), (char *) &inf, sizeof (inf)); - return 0; - } - break; + return -EINVAL; +} - case SNDCTL_SEQ_OUTOFBAND: - { - struct seq_event_rec event_rec; +int +sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +{ unsigned long flags; - memcpy ((char *) &event_rec, (&((char *) arg)[0]), sizeof (event_rec)); - - save_flags (flags); - cli (); - play_event (event_rec.arr); - restore_flags (flags); - - return 0; - } - break; - - case SNDCTL_MIDI_INFO: - { - struct midi_info inf; - int dev; - char *pp; - - memcpy ((char *) &inf, (&((char *) arg)[0]), sizeof (inf)); - dev = inf.device; + dev = dev >> 4; - if (dev < 0 || dev >= max_mididev) - return -ENXIO; + switch (sel_type) + { + case SEL_IN: + save_flags(flags); + cli(); + if (!iqlen) + { + + midi_sleep_flag.opts = WK_SLEEP; + poll_wait(&midi_sleeper, wait); + restore_flags(flags); + return 0; + } + restore_flags(flags); + return 1; + break; + + case SEL_OUT: + save_flags(flags); + cli(); + if ((SEQ_MAX_QUEUE - qlen) < output_threshold) + { + + seq_sleep_flag.opts = WK_SLEEP; + poll_wait(&seq_sleeper, wait); + restore_flags(flags); + return 0; + } + restore_flags(flags); + return 1; + break; - midi_devs[dev]->info.device = dev; - pp = (char *) &midi_devs[dev]->info; - memcpy ((&((char *) arg)[0]), pp, sizeof (inf)); - return 0; - } - break; + case SEL_EX: + return 0; + } - case SNDCTL_SEQ_THRESHOLD: - { - int tmp; - - tmp = *(int *) arg; - - if (tmp < 1) - tmp = 1; - if (tmp >= SEQ_MAX_QUEUE) - tmp = SEQ_MAX_QUEUE - 1; - output_threshold = tmp; return 0; - } - break; +} - case SNDCTL_MIDI_PRETIME: - { - int val; - - val = *(int *) arg; - - if (val < 0) - val = 0; - - val = (HZ * val) / 10; - pre_event_timeout = val; - return (*(int *) arg = val); - } - break; - - default: - if (mode == OPEN_READ) - return -EIO; - - if (!synth_devs[0]) - return -ENXIO; - if (!(synth_open_mask & (1 << 0))) - return -ENXIO; - return synth_devs[0]->ioctl (0, cmd, arg); - break; - } - return -EINVAL; +void +sequencer_timer(unsigned long dummy) +{ + seq_startplay(); } int -sequencer_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) +note_to_freq(int note_num) { - unsigned long flags; - dev = dev >> 4; + /* + * This routine converts a midi note to a frequency (multiplied by 1000) + */ - switch (sel_type) - { - case SEL_IN: - save_flags (flags); - cli (); - if (!iqlen) + int note, octave, note_freq; + static int notes[] = { + 261632, 277189, 293671, 311132, 329632, 349232, + 369998, 391998, 415306, 440000, 466162, 493880 + }; - midi_sleep_flag.opts = WK_SLEEP; - poll_wait (&midi_sleeper, wait); - restore_flags (flags); - return 0; - } - restore_flags (flags); - return 1; - break; - - case SEL_OUT: - save_flags (flags); - cli (); - if ((SEQ_MAX_QUEUE - qlen) < output_threshold) - { +#define BASE_OCTAVE 5 - seq_sleep_flag.opts = WK_SLEEP; - poll_wait (&seq_sleeper, wait); - restore_flags (flags); - return 0; - } - restore_flags (flags); - return 1; - break; - - case SEL_EX: - return 0; - } + octave = note_num / 12; + note = note_num % 12; - return 0; -} + note_freq = notes[note]; + if (octave < BASE_OCTAVE) + note_freq >>= (BASE_OCTAVE - octave); + else if (octave > BASE_OCTAVE) + note_freq <<= (octave - BASE_OCTAVE); -void -sequencer_timer (unsigned long dummy) -{ - seq_startplay (); + /* + * note_freq >>= 1; + */ + + return note_freq; } -int -note_to_freq (int note_num) +unsigned long +compute_finetune(unsigned long base_freq, int bend, int range, + int vibrato_cents) { + unsigned long amount; + int negative, semitones, cents, multiplier = 1; - /* - * This routine converts a midi note to a frequency (multiplied by 1000) - */ - - int note, octave, note_freq; - static int notes[] = - { - 261632, 277189, 293671, 311132, 329632, 349232, - 369998, 391998, 415306, 440000, 466162, 493880 - }; + if (!bend) + return base_freq; + if (!range) + return base_freq; -#define BASE_OCTAVE 5 + if (!base_freq) + return base_freq; - octave = note_num / 12; - note = note_num % 12; + if (range >= 8192) + range = 8192; - note_freq = notes[note]; + bend = bend * range / 8192; /* Convert to cents */ + bend += vibrato_cents; - if (octave < BASE_OCTAVE) - note_freq >>= (BASE_OCTAVE - octave); - else if (octave > BASE_OCTAVE) - note_freq <<= (octave - BASE_OCTAVE); + if (!bend) + return base_freq; - /* - * note_freq >>= 1; - */ + negative = bend < 0 ? 1 : 0; - return note_freq; -} + if (bend < 0) + bend *= -1; + if (bend > range) + bend = range; -unsigned long -compute_finetune (unsigned long base_freq, int bend, int range, - int vibrato_cents) -{ - unsigned long amount; - int negative, semitones, cents, multiplier = 1; + /* + if (bend > 2399) + bend = 2399; + */ + while (bend > 2399) + { + multiplier *= 4; + bend -= 2400; + } - if (!bend) - return base_freq; - if (!range) - return base_freq; - - if (!base_freq) - return base_freq; - - if (range >= 8192) - range = 8192; - - bend = bend * range / 8192; /* Convert to cents */ - bend += vibrato_cents; - - if (!bend) - return base_freq; - - negative = bend < 0 ? 1 : 0; - - if (bend < 0) - bend *= -1; - if (bend > range) - bend = range; - - /* - if (bend > 2399) - bend = 2399; - */ - while (bend > 2399) - { - multiplier *= 4; - bend -= 2400; - } - - semitones = bend / 100; - if (semitones > 99) - semitones = 99; - cents = bend % 100; - - amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) - / 10000; - - if (negative) - return (base_freq * 10000) / amount; /* Bend down */ - else - return (base_freq * amount) / 10000; /* Bend up */ + semitones = bend / 100; + if (semitones > 99) + semitones = 99; + cents = bend % 100; + + amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) + / 10000; + + if (negative) + return (base_freq * 10000) / amount; /* Bend down */ + else + return (base_freq * amount) / 10000; /* Bend up */ } void -sequencer_init (void) +sequencer_init(void) { - if (sequencer_ok) - return; + if (sequencer_ok) + return; #ifdef CONFIG_MIDI - MIDIbuf_init (); + MIDIbuf_init(); #endif - queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * EV_SZ)); - sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * EV_SZ; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (queue == NULL) - { - printk ("Sound: Can't allocate memory for sequencer output queue\n"); - return; - } - - - iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * IEV_SZ)); - sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * IEV_SZ; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (iqueue == NULL) - { - printk ("Sound: Can't allocate memory for sequencer input queue\n"); - return; - } - - - sequencer_ok = 1; + queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc(SEQ_MAX_QUEUE * EV_SZ)); + sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * EV_SZ; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (queue == NULL) + { + printk("Sound: Can't allocate memory for sequencer output queue\n"); + return; + } + iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc(SEQ_MAX_QUEUE * IEV_SZ)); + sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * IEV_SZ; + if (sound_nblocks < 1024) + sound_nblocks++;; + if (iqueue == NULL) + { + printk("Sound: Can't allocate memory for sequencer input queue\n"); + return; + } + sequencer_ok = 1; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.1.66/linux/drivers/sound/softoss.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/softoss.c Sat Nov 29 10:33:21 1997 @@ -11,7 +11,7 @@ * for more info. */ #include - +#include /* * When POLLED_MODE is defined, the resampling loop is run using a timer @@ -26,10 +26,11 @@ #define NO_SAMPLE 0xffff #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_SOFTOSS +#if defined(CONFIG_SOFTOSS) || defined(MODULE) #include "softoss.h" -#include +#include int softsynth_disabled = 0; @@ -49,42 +50,42 @@ */ static int tremolo_table[128] = { - 0, 39, 158, 355, 630, 982, 1411, 1915, - 2494, 3146, 3869, 4662, 5522, 6448, 7438, 8489, - 9598, 10762, 11980, 13248, 14563, 15922, 17321, 18758, - 20228, 21729, 23256, 24806, 26375, 27960, 29556, 31160, - 32768, 34376, 35980, 37576, 39161, 40730, 42280, 43807, - 45308, 46778, 48215, 49614, 50973, 52288, 53556, 54774, - 55938, 57047, 58098, 59088, 60014, 60874, 61667, 62390, - 63042, 63621, 64125, 64554, 64906, 65181, 65378, 65497, - 65536, 65497, 65378, 65181, 64906, 64554, 64125, 63621, - 63042, 62390, 61667, 60874, 60014, 59087, 58098, 57047, - 55938, 54774, 53556, 52288, 50973, 49614, 48215, 46778, - 45308, 43807, 42280, 40730, 39161, 37576, 35980, 34376, - 32768, 31160, 29556, 27960, 26375, 24806, 23256, 21729, - 20228, 18758, 17321, 15922, 14563, 13248, 11980, 10762, - 9598, 8489, 7438, 6448, 5522, 4662, 3869, 3146, - 2494, 1915, 1411, 982, 630, 355, 158, 39 + 0, 39, 158, 355, 630, 982, 1411, 1915, + 2494, 3146, 3869, 4662, 5522, 6448, 7438, 8489, + 9598, 10762, 11980, 13248, 14563, 15922, 17321, 18758, + 20228, 21729, 23256, 24806, 26375, 27960, 29556, 31160, + 32768, 34376, 35980, 37576, 39161, 40730, 42280, 43807, + 45308, 46778, 48215, 49614, 50973, 52288, 53556, 54774, + 55938, 57047, 58098, 59088, 60014, 60874, 61667, 62390, + 63042, 63621, 64125, 64554, 64906, 65181, 65378, 65497, + 65536, 65497, 65378, 65181, 64906, 64554, 64125, 63621, + 63042, 62390, 61667, 60874, 60014, 59087, 58098, 57047, + 55938, 54774, 53556, 52288, 50973, 49614, 48215, 46778, + 45308, 43807, 42280, 40730, 39161, 37576, 35980, 34376, + 32768, 31160, 29556, 27960, 26375, 24806, 23256, 21729, + 20228, 18758, 17321, 15922, 14563, 13248, 11980, 10762, + 9598, 8489, 7438, 6448, 5522, 4662, 3869, 3146, + 2494, 1915, 1411, 982, 630, 355, 158, 39 }; static int vibrato_table[128] = { - 0, 1608, 3212, 4808, 6393, 7962, 9512, 11039, - 12540, 14010, 15447, 16846, 18205, 19520, 20788, 22006, - 23170, 24279, 25330, 26320, 27246, 28106, 28899, 29622, - 30274, 30853, 31357, 31786, 32138, 32413, 32610, 32729, - 32768, 32729, 32610, 32413, 32138, 31786, 31357, 30853, - 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279, - 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010, - 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, - 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039, - -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006, - -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, - -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729, - -32768, -32729, -32610, -32413, -32138, -31786, -31357, -30853, - -30274, -29622, -28899, -28106, -27246, -26320, -25330, -24279, - -23170, -22006, -20788, -19520, -18205, -16846, -15447, -14010, - -12540, -11039, -9512, -7962, -6393, -4808, -3212, -1608 + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11039, + 12540, 14010, 15447, 16846, 18205, 19520, 20788, 22006, + 23170, 24279, 25330, 26320, 27246, 28106, 28899, 29622, + 30274, 30853, 31357, 31786, 32138, 32413, 32610, 32729, + 32768, 32729, 32610, 32413, 32138, 31786, 31357, 30853, + 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279, + 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010, + 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, + 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039, + -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006, + -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, + -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729, + -32768, -32729, -32610, -32413, -32138, -31786, -31357, -30853, + -30274, -29622, -28899, -28106, -27246, -26320, -25330, -24279, + -23170, -22006, -20788, -19520, -18205, -16846, -15447, -14010, + -12540, -11039, -9512, -7962, -6393, -4808, -3212, -1608 }; #endif @@ -106,1386 +107,1347 @@ static struct voice_alloc_info *voice_alloc; -static int softsyn_open (int synthdev, int mode); -static void init_voice (softsyn_devc * devc, int voice); -static void compute_step (int voice); +static int softsyn_open(int synthdev, int mode); +static void init_voice(softsyn_devc * devc, int voice); +static void compute_step(int voice); static volatile int tmr_running = 0; static int voice_limit = 24; static void -set_max_voices (int nr) +set_max_voices(int nr) { - int i; + int i; - if (nr < 4) - nr = 4; + if (nr < 4) + nr = 4; - if (nr > voice_limit) - nr = voice_limit; + if (nr > voice_limit) + nr = voice_limit; - voice_alloc->max_voice = devc->maxvoice = nr; - devc->afterscale = 5; + voice_alloc->max_voice = devc->maxvoice = nr; + devc->afterscale = 5; - for (i = 31; i > 0; i--) - if (nr & (1 << i)) - { - devc->afterscale = i + 1; - return; - } + for (i = 31; i > 0; i--) + if (nr & (1 << i)) + { + devc->afterscale = i + 1; + return; + } } static void -update_vibrato (int voice) +update_vibrato(int voice) { - voice_info *v = &softoss_voices[voice]; + voice_info *v = &softoss_voices[voice]; #ifdef HANDLE_LFO - int x; + int x; - x = vibrato_table[v->vibrato_phase >> 8]; - v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff; + x = vibrato_table[v->vibrato_phase >> 8]; + v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff; - x = (x * v->vibrato_depth) >> 15; - v->vibrato_level = (x * 600) >> 8; + x = (x * v->vibrato_depth) >> 15; + v->vibrato_level = (x * 600) >> 8; - compute_step (voice); + compute_step(voice); #else - v->vibrato_level = 0; + v->vibrato_level = 0; #endif } #ifdef HANDLE_LFO static void -update_tremolo (int voice) +update_tremolo(int voice) { - voice_info *v = &softoss_voices[voice]; - int x; + voice_info *v = &softoss_voices[voice]; + int x; - x = tremolo_table[v->tremolo_phase >> 8]; - v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff; + x = tremolo_table[v->tremolo_phase >> 8]; + v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff; - v->tremolo_level = (x * v->tremolo_depth) >> 20; + v->tremolo_level = (x * v->tremolo_depth) >> 20; } #endif static void -start_vibrato (int voice) +start_vibrato(int voice) { - voice_info *v = &softoss_voices[voice]; - int rate; + voice_info *v = &softoss_voices[voice]; + int rate; - if (!v->vibrato_depth) - return; + if (!v->vibrato_depth) + return; - rate = v->vibrato_rate * 6 * 128; - v->vibrato_step = (rate * devc->control_rate) / devc->speed; + rate = v->vibrato_rate * 6 * 128; + v->vibrato_step = (rate * devc->control_rate) / devc->speed; - devc->vibratomap |= (1 << voice); /* Enable vibrato */ + devc->vibratomap |= (1 << voice); /* Enable vibrato */ } static void -start_tremolo (int voice) +start_tremolo(int voice) { - voice_info *v = &softoss_voices[voice]; - int rate; + voice_info *v = &softoss_voices[voice]; + int rate; - if (!v->tremolo_depth) - return; + if (!v->tremolo_depth) + return; - rate = v->tremolo_rate * 6 * 128; - v->tremolo_step = (rate * devc->control_rate) / devc->speed; + rate = v->tremolo_rate * 6 * 128; + v->tremolo_step = (rate * devc->control_rate) / devc->speed; - devc->tremolomap |= (1 << voice); /* Enable tremolo */ + devc->tremolomap |= (1 << voice); /* Enable tremolo */ } static void -update_volume (int voice) +update_volume(int voice) { - voice_info *v = &softoss_voices[voice]; - unsigned int vol; + voice_info *v = &softoss_voices[voice]; + unsigned int vol; /* * Compute plain volume */ - vol = (v->velocity * v->expression_vol * v->main_vol) >> 12; + vol = (v->velocity * v->expression_vol * v->main_vol) >> 12; #ifdef HANDLE_LFO /* * Handle LFO */ - if (devc->tremolomap & (1 << voice)) - { - int t; - - t = 32768 - v->tremolo_level; - vol = (vol * t) >> 15; - update_tremolo (voice); - } + if (devc->tremolomap & (1 << voice)) + { + int t; + + t = 32768 - v->tremolo_level; + vol = (vol * t) >> 15; + update_tremolo(voice); + } #endif /* * Envelope */ - if (v->mode & WAVE_ENVELOPES && !v->percussive_voice) - vol = (vol * (v->envelope_vol >> 16)) >> 19; - else - vol >>= 4; + if (v->mode & WAVE_ENVELOPES && !v->percussive_voice) + vol = (vol * (v->envelope_vol >> 16)) >> 19; + else + vol >>= 4; /* * Handle panning */ - if (v->panning < 0) /* Pan left */ - v->rightvol = (vol * (128 + v->panning)) / 128; - else - v->rightvol = vol; - - if (v->panning > 0) /* Pan right */ - v->leftvol = (vol * (128 - v->panning)) / 128; - else - v->leftvol = vol; -} - -static void -step_envelope (int voice, int do_release, int velocity) -{ - voice_info *v = &softoss_voices[voice]; - int r, rate, time, dif; - unsigned int vol; - unsigned long flags; - - save_flags (flags); - cli (); - - if (!voice_active[voice] || v->sample == NULL) - { - restore_flags (flags); - return; - } - - if (!do_release) - if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2) - { /* Stop envelope until note off */ - v->envelope_volstep = 0; - v->envelope_time = 0x7fffffff; - if (v->mode & WAVE_VIBRATO) - start_vibrato (voice); - if (v->mode & WAVE_TREMOLO) - start_tremolo (voice); - restore_flags (flags); - return; - } - - if (do_release) - v->envelope_phase = 3; - else - v->envelope_phase++; - - if (v->envelope_phase >= 5) /* Finished */ - { - init_voice (devc, voice); - restore_flags (flags); - return; - } - - vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22; - - - rate = v->sample->env_rate[v->envelope_phase]; - r = 3 - ((rate >> 6) & 0x3); - r *= 3; - r = (int) (rate & 0x3f) << r; - rate = (((r * 44100) / devc->speed) * devc->control_rate) << 8; - - if (rate < (1 << 20)) /* Avoid infinitely "releasing" voices */ - rate = 1 << 20; - - dif = (v->envelope_vol - vol); - if (dif < 0) - dif *= -1; - if (dif < rate * 2) /* Too close */ - { - step_envelope (voice, 0, 60); - restore_flags (flags); - return; - } - - if (vol > v->envelope_vol) - { - v->envelope_volstep = rate; - time = (vol - v->envelope_vol) / rate; - } - else - { - v->envelope_volstep = -rate; - time = (v->envelope_vol - vol) / rate; - } - - time--; - if (time <= 0) - time = 1; - - v->envelope_time = time; + if (v->panning < 0) /* Pan left */ + v->rightvol = (vol * (128 + v->panning)) / 128; + else + v->rightvol = vol; + + if (v->panning > 0) /* Pan right */ + v->leftvol = (vol * (128 - v->panning)) / 128; + else + v->leftvol = vol; +} + +static void +step_envelope(int voice, int do_release, int velocity) +{ + voice_info *v = &softoss_voices[voice]; + int r, rate, time, dif; + unsigned int vol; + unsigned long flags; + + save_flags(flags); + cli(); + + if (!voice_active[voice] || v->sample == NULL) + { + restore_flags(flags); + return; + } + if (!do_release) + if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2) + { /* Stop envelope until note off */ + v->envelope_volstep = 0; + v->envelope_time = 0x7fffffff; + if (v->mode & WAVE_VIBRATO) + start_vibrato(voice); + if (v->mode & WAVE_TREMOLO) + start_tremolo(voice); + restore_flags(flags); + return; + } + if (do_release) + v->envelope_phase = 3; + else + v->envelope_phase++; + + if (v->envelope_phase >= 5) /* Finished */ + { + init_voice(devc, voice); + restore_flags(flags); + return; + } + vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22; + + + rate = v->sample->env_rate[v->envelope_phase]; + r = 3 - ((rate >> 6) & 0x3); + r *= 3; + r = (int) (rate & 0x3f) << r; + rate = (((r * 44100) / devc->speed) * devc->control_rate) << 8; + + if (rate < (1 << 20)) /* Avoid infinitely "releasing" voices */ + rate = 1 << 20; + + dif = (v->envelope_vol - vol); + if (dif < 0) + dif *= -1; + if (dif < rate * 2) /* Too close */ + { + step_envelope(voice, 0, 60); + restore_flags(flags); + return; + } + if (vol > v->envelope_vol) + { + v->envelope_volstep = rate; + time = (vol - v->envelope_vol) / rate; + } else + { + v->envelope_volstep = -rate; + time = (v->envelope_vol - vol) / rate; + } + + time--; + if (time <= 0) + time = 1; + + v->envelope_time = time; - restore_flags (flags); + restore_flags(flags); } static void -step_envelope_lfo (int voice) +step_envelope_lfo(int voice) { - voice_info *v = &softoss_voices[voice]; + voice_info *v = &softoss_voices[voice]; /* * Update pitch (vibrato) LFO */ - if (devc->vibratomap & (1 << voice)) - update_vibrato (voice); + if (devc->vibratomap & (1 << voice)) + update_vibrato(voice); /* * Update envelope */ - if (v->mode & WAVE_ENVELOPES) - { - v->envelope_vol += v->envelope_volstep; - /* Overshoot protection */ - if (v->envelope_vol < 0) - { - v->envelope_vol = v->envelope_target; - v->envelope_volstep = 0; - } - - if (v->envelope_time-- <= 0) - { - v->envelope_vol = v->envelope_target; - step_envelope (voice, 0, 60); - } - } -} - -static void -compute_step (int voice) -{ - voice_info *v = &softoss_voices[voice]; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - v->current_freq = compute_finetune (v->orig_freq, - v->bender, - v->bender_range, - v->vibrato_level); - v->step = (((v->current_freq << 9) + (devc->speed >> 1)) / devc->speed); - - if (v->mode & WAVE_LOOP_BACK) - v->step *= -1; /* Reversed playback */ -} - -static void -init_voice (softsyn_devc * devc, int voice) -{ - voice_info *v = &softoss_voices[voice]; - unsigned long flags; - - save_flags (flags); - cli (); - voice_active[voice] = 0; - devc->vibratomap &= ~(1 << voice); - devc->tremolomap &= ~(1 << voice); - v->mode = 0; - v->wave = NULL; - v->sample = NULL; - v->ptr = 0; - v->step = 0; - v->startloop = 0; - v->startbackloop = 0; - v->endloop = 0; - v->looplen = 0; - v->bender = 0; - v->bender_range = 200; - v->panning = 0; - v->main_vol = 127; - v->expression_vol = 127; - v->patch_vol = 127; - v->percussive_voice = 0; - v->sustain_mode = 0; - v->envelope_phase = 1; - v->envelope_vol = 1 << 24; - v->envelope_volstep = 256; - v->envelope_time = 0; - v->vibrato_phase = 0; - v->vibrato_step = 0; - v->vibrato_level = 0; - v->vibrato_rate = 0; - v->vibrato_depth = 0; - v->tremolo_phase = 0; - v->tremolo_step = 0; - v->tremolo_level = 0; - v->tremolo_rate = 0; - v->tremolo_depth = 0; - voice_alloc->map[voice] = 0; - voice_alloc->alloc_times[voice] = 0; - restore_flags (flags); -} - -static void -reset_samples (softsyn_devc * devc) -{ - int i; - - for (i = 0; i < MAX_VOICE; i++) - voice_active[i] = 0; - for (i = 0; i < devc->maxvoice; i++) - { - init_voice (devc, i); - softoss_voices[i].instr = 0; - } - - devc->ram_used = 0; - - for (i = 0; i < MAX_PATCH; i++) - devc->programs[i] = NO_SAMPLE; - - for (i = 0; i < devc->nrsamples; i++) - { - vfree (devc->samples[i]); - vfree (devc->wave[i]); - devc->samples[i] = NULL; - devc->wave[i] = NULL; - } - - devc->nrsamples = 0; -} - -static void -init_engine (softsyn_devc * devc) -{ - int i, fz, srate, sz = devc->channels; - - set_max_voices (devc->default_max_voices); - voice_alloc->timestamp = 0; - - if (devc->bits == 16) - sz *= 2; - - fz = devc->fragsize / sz; /* Samples per fragment */ - devc->samples_per_fragment = fz; - - devc->usecs = 0; - devc->usecs_per_frag = (1000000 * fz) / devc->speed; - - for (i = 0; i < devc->maxvoice; i++) - { - init_voice (devc, i); - softoss_voices[i].instr = 0; - } + if (v->mode & WAVE_ENVELOPES) + { + v->envelope_vol += v->envelope_volstep; + /* Overshoot protection */ + if (v->envelope_vol < 0) + { + v->envelope_vol = v->envelope_target; + v->envelope_volstep = 0; + } + if (v->envelope_time-- <= 0) + { + v->envelope_vol = v->envelope_target; + step_envelope(voice, 0, 60); + } + } +} + +static void +compute_step(int voice) +{ + voice_info *v = &softoss_voices[voice]; + + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ + + v->current_freq = compute_finetune(v->orig_freq, + v->bender, + v->bender_range, + v->vibrato_level); + v->step = (((v->current_freq << 9) + (devc->speed >> 1)) / devc->speed); + + if (v->mode & WAVE_LOOP_BACK) + v->step *= -1; /* Reversed playback */ +} + +static void +init_voice(softsyn_devc * devc, int voice) +{ + voice_info *v = &softoss_voices[voice]; + unsigned long flags; + + save_flags(flags); + cli(); + voice_active[voice] = 0; + devc->vibratomap &= ~(1 << voice); + devc->tremolomap &= ~(1 << voice); + v->mode = 0; + v->wave = NULL; + v->sample = NULL; + v->ptr = 0; + v->step = 0; + v->startloop = 0; + v->startbackloop = 0; + v->endloop = 0; + v->looplen = 0; + v->bender = 0; + v->bender_range = 200; + v->panning = 0; + v->main_vol = 127; + v->expression_vol = 127; + v->patch_vol = 127; + v->percussive_voice = 0; + v->sustain_mode = 0; + v->envelope_phase = 1; + v->envelope_vol = 1 << 24; + v->envelope_volstep = 256; + v->envelope_time = 0; + v->vibrato_phase = 0; + v->vibrato_step = 0; + v->vibrato_level = 0; + v->vibrato_rate = 0; + v->vibrato_depth = 0; + v->tremolo_phase = 0; + v->tremolo_step = 0; + v->tremolo_level = 0; + v->tremolo_rate = 0; + v->tremolo_depth = 0; + voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; + restore_flags(flags); +} + +static void +reset_samples(softsyn_devc * devc) +{ + int i; + + for (i = 0; i < MAX_VOICE; i++) + voice_active[i] = 0; + for (i = 0; i < devc->maxvoice; i++) + { + init_voice(devc, i); + softoss_voices[i].instr = 0; + } + + devc->ram_used = 0; + + for (i = 0; i < MAX_PATCH; i++) + devc->programs[i] = NO_SAMPLE; + + for (i = 0; i < devc->nrsamples; i++) + { + vfree(devc->samples[i]); + vfree(devc->wave[i]); + devc->samples[i] = NULL; + devc->wave[i] = NULL; + } + + devc->nrsamples = 0; +} + +static void +init_engine(softsyn_devc * devc) +{ + int i, fz, srate, sz = devc->channels; + + set_max_voices(devc->default_max_voices); + voice_alloc->timestamp = 0; + + if (devc->bits == 16) + sz *= 2; + + fz = devc->fragsize / sz; /* Samples per fragment */ + devc->samples_per_fragment = fz; + + devc->usecs = 0; + devc->usecs_per_frag = (1000000 * fz) / devc->speed; + + for (i = 0; i < devc->maxvoice; i++) + { + init_voice(devc, i); + softoss_voices[i].instr = 0; + } - devc->engine_state = ES_STOPPED; + devc->engine_state = ES_STOPPED; /* * Initialize delay */ - for (i = 0; i < DELAY_SIZE; i++) - left_delay[i] = right_delay[i] = 0; - delayp = 0; - srate = (devc->speed / 10000); /* 1 to 4 */ - if (srate <= 0) - srate = 1; - devc->delay_size = (DELAY_SIZE * srate) / 4; - if (devc->delay_size == 0 || devc->delay_size > DELAY_SIZE) - devc->delay_size = DELAY_SIZE; + for (i = 0; i < DELAY_SIZE; i++) + left_delay[i] = right_delay[i] = 0; + delayp = 0; + srate = (devc->speed / 10000); /* 1 to 4 */ + if (srate <= 0) + srate = 1; + devc->delay_size = (DELAY_SIZE * srate) / 4; + if (devc->delay_size == 0 || devc->delay_size > DELAY_SIZE) + devc->delay_size = DELAY_SIZE; } void -softsyn_control_loop (void) +softsyn_control_loop(void) { - int voice; + int voice; /* * Recompute envlope, LFO, etc. */ - for (voice = 0; voice < devc->maxvoice; voice++) - if (voice_active[voice]) - { - update_volume (voice); - step_envelope_lfo (voice); - } - else - voice_alloc->map[voice] = 0; -} - -static void start_engine (softsyn_devc * devc); - -static void -do_resample (int dummy) -{ - struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; - struct voice_info *vinfo; - unsigned long flags, jif; - - int voice, loops; - short *buf; - - if (softsynth_disabled) - return; - - save_flags (flags); - cli (); - - if (is_running) - { - printk ("SoftOSS: Playback overrun\n"); - restore_flags (flags); - return; - } - - jif = jiffies; - if (jif == last_resample_jiffies) - { - if (resample_counter++ > 50) - { - for (voice = 0; voice < devc->maxvoice; voice++) - init_voice (devc, voice); - voice_limit--; - resample_counter = 0; - printk ("SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit); - - if (voice_limit < 10) - { - voice_limit = 10; - devc->speed = (devc->speed * 2) / 3; - - printk ("SoftOSS: Dropping sampling rate and stopping the device.\n"); - softsynth_disabled = 1; - } - } - } - else - { - last_resample_jiffies = jif; - resample_counter = 0; - } - - /* is_running = 1; */ - - if (dmap->qlen > devc->max_playahead) - { - printk ("SoftOSS: audio buffers full\n"); - is_running = 0; - restore_flags (flags); - return; - } - + for (voice = 0; voice < devc->maxvoice; voice++) + if (voice_active[voice]) + { + update_volume(voice); + step_envelope_lfo(voice); + } else + voice_alloc->map[voice] = 0; +} + +static void start_engine(softsyn_devc * devc); + +static void +do_resample(int dummy) +{ + struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; + struct voice_info *vinfo; + unsigned long flags, jif; + + int voice, loops; + short *buf; + + if (softsynth_disabled) + return; + + save_flags(flags); + cli(); + + if (is_running) + { + printk("SoftOSS: Playback overrun\n"); + restore_flags(flags); + return; + } + jif = jiffies; + if (jif == last_resample_jiffies) + { + if (resample_counter++ > 50) + { + for (voice = 0; voice < devc->maxvoice; voice++) + init_voice(devc, voice); + voice_limit--; + resample_counter = 0; + printk("SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit); + + if (voice_limit < 10) + { + voice_limit = 10; + devc->speed = (devc->speed * 2) / 3; + + printk("SoftOSS: Dropping sampling rate and stopping the device.\n"); + softsynth_disabled = 1; + } + } + } else + { + last_resample_jiffies = jif; + resample_counter = 0; + } + + /* is_running = 1; */ + + if (dmap->qlen > devc->max_playahead) + { + printk("SoftOSS: audio buffers full\n"); + is_running = 0; + restore_flags(flags); + return; + } /* * First verify that all active voices are valid (do this just once per block). */ - for (voice = 0; voice < devc->maxvoice; voice++) - if (voice_active[voice]) - { - int ptr; - - vinfo = &softoss_voices[voice]; - ptr = vinfo->ptr >> 9; - - if (vinfo->wave == NULL || - ptr < 0 || - ptr > vinfo->sample->len) - init_voice (devc, voice); - else if (!(vinfo->mode & WAVE_LOOPING) && - (vinfo->ptr + vinfo->step) > vinfo->endloop) - voice_active[voice] = 0; - } - + for (voice = 0; voice < devc->maxvoice; voice++) + if (voice_active[voice]) + { + int ptr; + + vinfo = &softoss_voices[voice]; + ptr = vinfo->ptr >> 9; + + if (vinfo->wave == NULL || + ptr < 0 || + ptr > vinfo->sample->len) + init_voice(devc, voice); + else if (!(vinfo->mode & WAVE_LOOPING) && + (vinfo->ptr + vinfo->step) > vinfo->endloop) + voice_active[voice] = 0; + } /* * Start the resampling process */ - loops = devc->samples_per_fragment; - buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size)); - - softsynth_resample_loop (buf, loops); /* In Xsoftsynth_rs.c */ + loops = devc->samples_per_fragment; + buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size)); - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - dmap->user_counter += dmap->fragment_size; + softsynth_resample_loop(buf, loops); /* In Xsoftsynth_rs.c */ - devc->usecs += devc->usecs_per_frag; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + dmap->qlen++; + dmap->user_counter += dmap->fragment_size; - if (tmr_running) - { - sound_timer_interrupt (); - } + devc->usecs += devc->usecs_per_frag; + if (tmr_running) + { + sound_timer_interrupt(); + } /* * Execute timer */ - if (!tmr_running) - if (devc->usecs >= devc->next_event_usecs) - { - devc->next_event_usecs = ~0; - sequencer_timer (0); - } - is_running = 0; - restore_flags (flags); + if (!tmr_running) + if (devc->usecs >= devc->next_event_usecs) + { + devc->next_event_usecs = ~0; + sequencer_timer(0); + } + is_running = 0; + restore_flags(flags); } static void -delayed_resample (int dummy) +delayed_resample(int dummy) { - struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; - int n = 0; + struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; + int n = 0; - if (is_running) - return; + if (is_running) + return; - while (devc->engine_state != ES_STOPPED && - dmap->qlen < devc->max_playahead && n++ < 2) - do_resample (0); - intr_pending = 0; + while (devc->engine_state != ES_STOPPED && + dmap->qlen < devc->max_playahead && n++ < 2) + do_resample(0); + intr_pending = 0; } #ifdef POLLED_MODE static void -softsyn_poll (unsigned long dummy) +softsyn_poll(unsigned long dummy) { - delayed_resample (0); + delayed_resample(0); - if (devc->engine_state != ES_STOPPED) + if (devc->engine_state != ES_STOPPED) - { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; } #else static void -softsyn_callback (int dev, int parm) +softsyn_callback(int dev, int parm) { - delayed_resample (0); + delayed_resample(0); } #endif static void -start_engine (softsyn_devc * devc) +start_engine(softsyn_devc * devc) { - struct dma_buffparms *dmap; + struct dma_buffparms *dmap; - if (!devc->audio_opened) - if (softsyn_open (devc->synthdev, 0) < 0) - return; + if (!devc->audio_opened) + if (softsyn_open(devc->synthdev, 0) < 0) + return; - if (devc->audiodev >= num_audiodevs) - return; + if (devc->audiodev >= num_audiodevs) + return; - dmap = audio_devs[devc->audiodev]->dmap_out; + dmap = audio_devs[devc->audiodev]->dmap_out; - devc->usecs = 0; - devc->next_event_usecs = ~0; - devc->control_rate = 64; - devc->control_counter = 0; + devc->usecs = 0; + devc->next_event_usecs = ~0; + devc->control_rate = 64; + devc->control_counter = 0; - if (devc->engine_state == ES_STOPPED) - { - int trig, n = 0; + if (devc->engine_state == ES_STOPPED) + { + int trig, n = 0; - trig = 0; - dma_ioctl (devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t) & trig); + trig = 0; + dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t) & trig); #ifdef POLLED_MODE - ; + ; - { - poll_timer.expires = (1) + jiffies; - add_timer (&poll_timer); - }; /* Start polling */ + { + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + }; /* Start polling */ #else - dmap->audio_callback = softsyn_callback; - dmap->qhead = dmap->qtail = dmap->qlen = 0; + dmap->audio_callback = softsyn_callback; + dmap->qhead = dmap->qtail = dmap->qlen = 0; #endif - while (dmap->qlen < devc->max_playahead && n++ < 2) - do_resample (0); + while (dmap->qlen < devc->max_playahead && n++ < 2) + do_resample(0); - devc->engine_state = ES_STARTED; - last_resample_jiffies = jiffies; - resample_counter = 0; + devc->engine_state = ES_STARTED; + last_resample_jiffies = jiffies; + resample_counter = 0; - trig = PCM_ENABLE_OUTPUT; - if (dma_ioctl (devc->audiodev, SNDCTL_DSP_SETTRIGGER, - (caddr_t) & trig) < 0) - { - printk ("SoftOSS: Trigger failed\n"); - } - - - } + trig = PCM_ENABLE_OUTPUT; + if (dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, + (caddr_t) & trig) < 0) + { + printk("SoftOSS: Trigger failed\n"); + } + } } static void -stop_engine (softsyn_devc * devc) +stop_engine(softsyn_devc * devc) { } static void -request_engine (softsyn_devc * devc, int ticks) +request_engine(softsyn_devc * devc, int ticks) { - if (ticks < 0) /* Relative time */ - devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ); - else - devc->next_event_usecs = ticks * (1000000 / HZ); + if (ticks < 0) /* Relative time */ + devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ); + else + devc->next_event_usecs = ticks * (1000000 / HZ); } /* * Softsync hook serves mode1 (timing) calls made by sequencer.c */ static int -softsynth_hook (int cmd, int parm1, int parm2, unsigned long parm3) +softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3) { - switch (cmd) - { - case SSYN_START: - start_engine (devc); - break; - - case SSYN_STOP: - stop_engine (devc); - break; - - case SSYN_REQUEST: - request_engine (devc, parm1); - break; - - case SSYN_GETTIME: - return devc->usecs / (1000000 / HZ); - break; - - default: - printk ("SoftOSS: Unknown request %d\n", cmd); - } + switch (cmd) + { + case SSYN_START: + start_engine(devc); + break; + + case SSYN_STOP: + stop_engine(devc); + break; + + case SSYN_REQUEST: + request_engine(devc, parm1); + break; + + case SSYN_GETTIME: + return devc->usecs / (1000000 / HZ); + break; + + default: + printk("SoftOSS: Unknown request %d\n", cmd); + } - return 0; + return 0; } static int -softsyn_ioctl (int dev, - unsigned int cmd, caddr_t arg) +softsyn_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - switch (cmd) - { + switch (cmd) + { - case SNDCTL_SYNTH_INFO: - softsyn_info.nr_voices = devc->maxvoice; + case SNDCTL_SYNTH_INFO: + softsyn_info.nr_voices = devc->maxvoice; - memcpy ((&((char *) arg)[0]), (char *) &softsyn_info, sizeof (softsyn_info)); - return 0; - break; - - case SNDCTL_SEQ_RESETSAMPLES: - stop_engine (devc); - reset_samples (devc); - return 0; - break; - - case SNDCTL_SYNTH_MEMAVL: - return devc->ram_size - devc->ram_used; - break; - - default: - return -EINVAL; - } + memcpy((&((char *) arg)[0]), (char *) &softsyn_info, sizeof(softsyn_info)); + return 0; + break; + + case SNDCTL_SEQ_RESETSAMPLES: + stop_engine(devc); + reset_samples(devc); + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return devc->ram_size - devc->ram_used; + break; + + default: + return -EINVAL; + } } static int -softsyn_kill_note (int devno, int voice, int note, int velocity) +softsyn_kill_note(int devno, int voice, int note, int velocity) { - if (voice < 0 || voice > devc->maxvoice) - return 0; - voice_alloc->map[voice] = 0xffff; /* Releasing */ - - if (softoss_voices[voice].sustain_mode & 1) /* Sustain controller on */ - { - softoss_voices[voice].sustain_mode = 3; /* Note off pending */ - return 0; - } - - if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE) - { - init_voice (devc, voice); /* Mark it inactive */ - return 0; - } - - if (softoss_voices[voice].mode & WAVE_ENVELOPES) - step_envelope (voice, 1, velocity); /* Enter sustain phase */ - else - init_voice (devc, voice); /* Mark it inactive */ - return 0; + if (voice < 0 || voice > devc->maxvoice) + return 0; + voice_alloc->map[voice] = 0xffff; /* Releasing */ + + if (softoss_voices[voice].sustain_mode & 1) /* Sustain controller on */ + { + softoss_voices[voice].sustain_mode = 3; /* Note off pending */ + return 0; + } + if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE) + { + init_voice(devc, voice); /* Mark it inactive */ + return 0; + } + if (softoss_voices[voice].mode & WAVE_ENVELOPES) + step_envelope(voice, 1, velocity); /* Enter sustain phase */ + else + init_voice(devc, voice); /* Mark it inactive */ + return 0; } static int -softsyn_set_instr (int dev, int voice, int instr) +softsyn_set_instr(int dev, int voice, int instr) { - if (voice < 0 || voice > devc->maxvoice) - return 0; - - if (instr < 0 || instr > MAX_PATCH) - { - printk ("SoftOSS: Invalid instrument number %d\n", instr); - return 0; - } + if (voice < 0 || voice > devc->maxvoice) + return 0; - softoss_voices[voice].instr = instr; + if (instr < 0 || instr > MAX_PATCH) + { + printk("SoftOSS: Invalid instrument number %d\n", instr); + return 0; + } + softoss_voices[voice].instr = instr; - return 0; + return 0; } static int -softsyn_start_note (int dev, int voice, int note, int volume) +softsyn_start_note(int dev, int voice, int note, int volume) { - int instr = 0; - int best_sample, best_delta, delta_freq, selected; - unsigned long note_freq, freq, base_note, flags; - voice_info *v = &softoss_voices[voice]; - - struct patch_info *sample; - - if (voice < 0 || voice > devc->maxvoice) - return 0; - - if (volume == 0) /* Actually note off */ - softsyn_kill_note (dev, voice, note, volume); - - save_flags (flags); - cli (); - - if (note == 255) - { /* Just volume update */ - v->velocity = volume; - if (voice_active[voice]) - update_volume (voice); - restore_flags (flags); - return 0; - } - - voice_active[voice] = 0; /* Stop the voice for a while */ - devc->vibratomap &= ~(1 << voice); - devc->tremolomap &= ~(1 << voice); - - instr = v->instr; - if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE) - { - printk ("SoftOSS: Undefined MIDI instrument %d\n", instr); - restore_flags (flags); - return 0; - } - - instr = devc->programs[instr]; - - if (instr < 0 || instr >= devc->nrsamples) - { - printk ("SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr); - restore_flags (flags); - return 0; - } - - note_freq = note_to_freq (note); - - selected = -1; - - best_sample = instr; - best_delta = 1000000; - - while (instr != NO_SAMPLE && instr >= 0 && selected == -1) - { - delta_freq = note_freq - devc->samples[instr]->base_note; - - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = instr; - best_delta = delta_freq; - } - if (devc->samples[instr]->low_note <= note_freq && - note_freq <= devc->samples[instr]->high_note) - selected = instr; - else - instr = devc->samples[instr]->key; /* Link to next sample */ - - if (instr < 0 || instr >= devc->nrsamples) - instr = NO_SAMPLE; - } - - if (selected == -1) - instr = best_sample; - else - instr = selected; - - if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples) - { - printk ("SoftOSS: Unresolved MIDI instrument %d\n", v->instr); - restore_flags (flags); - return 0; - } - - sample = devc->samples[instr]; - v->sample = sample; - - if (v->percussive_voice) /* No key tracking */ - { - v->orig_freq = sample->base_freq; /* Fixed pitch */ - } - else - { - base_note = sample->base_note / 100; - note_freq /= 100; - - freq = sample->base_freq * note_freq / base_note; - v->orig_freq = freq; - } - - if (!(sample->mode & WAVE_LOOPING)) - { - sample->loop_end = sample->len; - } - - v->wave = devc->wave[instr]; - - if (volume < 0) - volume = 0; - else if (volume > 127) - volume = 127; - - v->ptr = 0; - v->startloop = sample->loop_start * 512; - v->startbackloop = 0; - v->endloop = sample->loop_end * 512; - v->looplen = (sample->loop_end - sample->loop_start) * 512; - v->leftvol = 64; - v->rightvol = 64; - v->patch_vol = sample->volume; - v->velocity = volume; - v->mode = sample->mode; - v->vibrato_phase = 0; - v->vibrato_step = 0; - v->vibrato_level = 0; - v->vibrato_rate = 0; - v->vibrato_depth = 0; - v->tremolo_phase = 0; - v->tremolo_step = 0; - v->tremolo_level = 0; - v->tremolo_rate = 0; - v->tremolo_depth = 0; - - if (!(v->mode & WAVE_LOOPING)) - v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK); - else if (v->mode & WAVE_LOOP_BACK) - { - v->ptr = sample->len; - v->startbackloop = v->startloop; - } - - if (v->mode & WAVE_VIBRATO) - { - v->vibrato_rate = sample->vibrato_rate; - v->vibrato_depth = sample->vibrato_depth; - } - - if (v->mode & WAVE_TREMOLO) - { - v->tremolo_rate = sample->tremolo_rate; - v->tremolo_depth = sample->tremolo_depth; - } - - if (v->mode & WAVE_ENVELOPES) - { - v->envelope_phase = -1; - v->envelope_vol = 0; - step_envelope (voice, 0, 60); - } - update_volume (voice); - compute_step (voice); + int instr = 0; + int best_sample, best_delta, delta_freq, selected; + unsigned long note_freq, freq, base_note, flags; + voice_info *v = &softoss_voices[voice]; + + struct patch_info *sample; + + if (voice < 0 || voice > devc->maxvoice) + return 0; + + if (volume == 0) /* Actually note off */ + softsyn_kill_note(dev, voice, note, volume); + + save_flags(flags); + cli(); + + if (note == 255) + { /* Just volume update */ + v->velocity = volume; + if (voice_active[voice]) + update_volume(voice); + restore_flags(flags); + return 0; + } + voice_active[voice] = 0; /* Stop the voice for a while */ + devc->vibratomap &= ~(1 << voice); + devc->tremolomap &= ~(1 << voice); + + instr = v->instr; + if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE) + { + printk("SoftOSS: Undefined MIDI instrument %d\n", instr); + restore_flags(flags); + return 0; + } + instr = devc->programs[instr]; + + if (instr < 0 || instr >= devc->nrsamples) + { + printk("SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr); + restore_flags(flags); + return 0; + } + note_freq = note_to_freq(note); + + selected = -1; + + best_sample = instr; + best_delta = 1000000; + + while (instr != NO_SAMPLE && instr >= 0 && selected == -1) + { + delta_freq = note_freq - devc->samples[instr]->base_note; + + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = instr; + best_delta = delta_freq; + } + if (devc->samples[instr]->low_note <= note_freq && + note_freq <= devc->samples[instr]->high_note) + selected = instr; + else + instr = devc->samples[instr]->key; /* Link to next sample */ + + if (instr < 0 || instr >= devc->nrsamples) + instr = NO_SAMPLE; + } + + if (selected == -1) + instr = best_sample; + else + instr = selected; + + if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples) + { + printk("SoftOSS: Unresolved MIDI instrument %d\n", v->instr); + restore_flags(flags); + return 0; + } + sample = devc->samples[instr]; + v->sample = sample; + + if (v->percussive_voice) /* No key tracking */ + { + v->orig_freq = sample->base_freq; /* Fixed pitch */ + } else + { + base_note = sample->base_note / 100; + note_freq /= 100; + + freq = sample->base_freq * note_freq / base_note; + v->orig_freq = freq; + } + + if (!(sample->mode & WAVE_LOOPING)) + { + sample->loop_end = sample->len; + } + v->wave = devc->wave[instr]; + + if (volume < 0) + volume = 0; + else if (volume > 127) + volume = 127; + + v->ptr = 0; + v->startloop = sample->loop_start * 512; + v->startbackloop = 0; + v->endloop = sample->loop_end * 512; + v->looplen = (sample->loop_end - sample->loop_start) * 512; + v->leftvol = 64; + v->rightvol = 64; + v->patch_vol = sample->volume; + v->velocity = volume; + v->mode = sample->mode; + v->vibrato_phase = 0; + v->vibrato_step = 0; + v->vibrato_level = 0; + v->vibrato_rate = 0; + v->vibrato_depth = 0; + v->tremolo_phase = 0; + v->tremolo_step = 0; + v->tremolo_level = 0; + v->tremolo_rate = 0; + v->tremolo_depth = 0; + + if (!(v->mode & WAVE_LOOPING)) + v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK); + else if (v->mode & WAVE_LOOP_BACK) + { + v->ptr = sample->len; + v->startbackloop = v->startloop; + } + if (v->mode & WAVE_VIBRATO) + { + v->vibrato_rate = sample->vibrato_rate; + v->vibrato_depth = sample->vibrato_depth; + } + if (v->mode & WAVE_TREMOLO) + { + v->tremolo_rate = sample->tremolo_rate; + v->tremolo_depth = sample->tremolo_depth; + } + if (v->mode & WAVE_ENVELOPES) + { + v->envelope_phase = -1; + v->envelope_vol = 0; + step_envelope(voice, 0, 60); + } + update_volume(voice); + compute_step(voice); - voice_active[voice] = 1; /* Mark it active */ + voice_active[voice] = 1; /* Mark it active */ - restore_flags (flags); - return 0; + restore_flags(flags); + return 0; } static int -softsyn_open (int synthdev, int mode) +softsyn_open(int synthdev, int mode) { - int err; - extern int softoss_dev; - int frags = 0x7fff0007; /* fragment size of 128 bytes */ + int err; + extern int softoss_dev; + int frags = 0x7fff0007; /* fragment size of 128 bytes */ - if (devc->audio_opened) /* Already opened */ - return 0; + if (devc->audio_opened) /* Already opened */ + return 0; - softsynth_disabled = 0; - devc->finfo.mode = OPEN_WRITE; - devc->finfo.flags = 0; + softsynth_disabled = 0; + devc->finfo.mode = OPEN_WRITE; + devc->finfo.flags = 0; - if (softoss_dev >= num_audiodevs) - softoss_dev = num_audiodevs - 1; + if (softoss_dev >= num_audiodevs) + softoss_dev = num_audiodevs - 1; - if (softoss_dev < 0) - softoss_dev = 0; - if (softoss_dev >= num_audiodevs) - return -ENXIO; - devc->audiodev = softoss_dev; + if (softoss_dev < 0) + softoss_dev = 0; + if (softoss_dev >= num_audiodevs) + return -ENXIO; + devc->audiodev = softoss_dev; - if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE)) - { - printk ("SoftOSS: The audio device doesn't support 16 bits\n"); - return -ENXIO; - } - if ((err = audio_open ((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0) - return err; + if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE)) + { + printk("SoftOSS: The audio device doesn't support 16 bits\n"); + return -ENXIO; + } + if ((err = audio_open((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0) + return err; - devc->speed = audio_devs[devc->audiodev]->d->set_speed ( - devc->audiodev, devc->speed); - devc->channels = audio_devs[devc->audiodev]->d->set_channels ( - devc->audiodev, devc->channels); - devc->bits = audio_devs[devc->audiodev]->d->set_bits ( - devc->audiodev, devc->bits); + devc->speed = audio_devs[devc->audiodev]->d->set_speed( + devc->audiodev, devc->speed); + devc->channels = audio_devs[devc->audiodev]->d->set_channels( + devc->audiodev, devc->channels); + devc->bits = audio_devs[devc->audiodev]->d->set_bits( + devc->audiodev, devc->bits); - DDB (printk ("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels)); + DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels)); - dma_ioctl (devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags); - dma_ioctl (devc->audiodev, SNDCTL_DSP_GETBLKSIZE, (caddr_t) & devc->fragsize); + dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags); + dma_ioctl(devc->audiodev, SNDCTL_DSP_GETBLKSIZE, (caddr_t) & devc->fragsize); - if (devc->bits != 16 || devc->channels != 2) - { - audio_release ((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); - printk ("SoftOSS: A 16 bit stereo soundcard is required\n"); - return 0; - } + if (devc->bits != 16 || devc->channels != 2) + { + audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); + printk("SoftOSS: A 16 bit stereo soundcard is required\n"); + return 0; + } + if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs) + devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs; - if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs) - devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs; + DDB(printk("SoftOSS: Using %d fragments of %d bytes\n", devc->max_playahead, devc->fragsize)); - DDB (printk ("SoftOSS: Using %d fragments of %d bytes\n", devc->max_playahead, devc->fragsize)); - - init_engine (devc); - devc->audio_opened = 1; - devc->sequencer_mode = mode; - return 0; + init_engine(devc); + devc->audio_opened = 1; + devc->sequencer_mode = mode; + return 0; } static void -softsyn_close (int synthdev) +softsyn_close(int synthdev) { - devc->engine_state = ES_STOPPED; + devc->engine_state = ES_STOPPED; #ifdef POLLED_MODE - del_timer (&poll_timer);; + del_timer(&poll_timer);; #endif - dma_ioctl (devc->audiodev, SNDCTL_DSP_RESET, 0); - if (devc->audio_opened) - audio_release ((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); - devc->audio_opened = 0; + dma_ioctl(devc->audiodev, SNDCTL_DSP_RESET, 0); + if (devc->audio_opened) + audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); + devc->audio_opened = 0; } static void -softsyn_hw_control (int dev, unsigned char *event_rec) +softsyn_hw_control(int dev, unsigned char *event_rec) { - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; - cmd = event_rec[2]; - voice = event_rec[3]; - p1 = *(unsigned short *) &event_rec[4]; - p2 = *(unsigned short *) &event_rec[6]; - plong = *(unsigned int *) &event_rec[4]; + cmd = event_rec[2]; + voice = event_rec[3]; + p1 = *(unsigned short *) &event_rec[4]; + p2 = *(unsigned short *) &event_rec[6]; + plong = *(unsigned int *) &event_rec[4]; - switch (cmd) - { + switch (cmd) + { - case _GUS_NUMVOICES: - set_max_voices (p1); - break; + case _GUS_NUMVOICES: + set_max_voices(p1); + break; - default:; - } + default:; + } } static int -softsyn_load_patch (int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) +softsyn_load_patch(int dev, int format, const char *addr, + int offs, int count, int pmgr_flag) { - struct patch_info *patch = NULL; - - int i, p, instr; - long sizeof_patch; - int memlen, adj; - unsigned short data; - short *wave = NULL; - - sizeof_patch = (long) &patch->data[0] - (long) patch; /* Header size */ - - if (format != GUS_PATCH) - { - printk ("SoftOSS: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } - - if (count < sizeof_patch) - { - printk ("SoftOSS: Patch header too short\n"); - return -EINVAL; - } - - count -= sizeof_patch; - - if (devc->nrsamples >= MAX_SAMPLE) - { - printk ("SoftOSS: Sample table full\n"); - return -ENOSPC; - } - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - patch = vmalloc (sizeof (*patch)); - - if (patch == NULL) - { - printk ("SoftOSS: Out of memory\n"); - return -ENOSPC; - } - - copy_from_user (&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs); - - if (patch->mode & WAVE_ROM) - { - vfree (patch); - return -EINVAL; - } - - instr = patch->instr_no; - - if (instr < 0 || instr > MAX_PATCH) - { - printk ("SoftOSS: Invalid patch number %d\n", instr); - vfree (patch); - return -EINVAL; - } - - if (count < patch->len) - { - printk ("SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len); - patch->len = count; - } - - if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used)) - { - printk ("SoftOSS: Invalid sample length %d\n", (int) patch->len); - vfree (patch); - return -EINVAL; - } - - if (patch->mode & WAVE_LOOPING) - { - if (patch->loop_start < 0 || patch->loop_start >= patch->len) - { - printk ("SoftOSS: Invalid loop start %d\n", patch->loop_start); - vfree (patch); - return -EINVAL; - } - - if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len) - { - printk ("SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end); - vfree (patch); - return -EINVAL; - } - } + struct patch_info *patch = NULL; + int i, p, instr; + long sizeof_patch; + int memlen, adj; + unsigned short data; + short *wave = NULL; + + sizeof_patch = (long) &patch->data[0] - (long) patch; /* Header size */ + + if (format != GUS_PATCH) + { + printk("SoftOSS: Invalid patch format (key) 0x%x\n", format); + return -EINVAL; + } + if (count < sizeof_patch) + { + printk("SoftOSS: Patch header too short\n"); + return -EINVAL; + } + count -= sizeof_patch; + + if (devc->nrsamples >= MAX_SAMPLE) + { + printk("SoftOSS: Sample table full\n"); + return -ENOSPC; + } + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ + + patch = vmalloc(sizeof(*patch)); + + if (patch == NULL) + { + printk("SoftOSS: Out of memory\n"); + return -ENOSPC; + } + copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs); + + if (patch->mode & WAVE_ROM) + { + vfree(patch); + return -EINVAL; + } + instr = patch->instr_no; + + if (instr < 0 || instr > MAX_PATCH) + { + printk("SoftOSS: Invalid patch number %d\n", instr); + vfree(patch); + return -EINVAL; + } + if (count < patch->len) + { + printk("SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len); + patch->len = count; + } + if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used)) + { + printk("SoftOSS: Invalid sample length %d\n", (int) patch->len); + vfree(patch); + return -EINVAL; + } + if (patch->mode & WAVE_LOOPING) + { + if (patch->loop_start < 0 || patch->loop_start >= patch->len) + { + printk("SoftOSS: Invalid loop start %d\n", patch->loop_start); + vfree(patch); + return -EINVAL; + } + if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len) + { + printk("SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end); + vfree(patch); + return -EINVAL; + } + } /* * Next load the wave data to memory */ - memlen = patch->len; - adj = 1; + memlen = patch->len; + adj = 1; - if (!(patch->mode & WAVE_16_BITS)) - memlen *= 2; - else - adj = 2; - - wave = vmalloc (memlen); - - if (wave == NULL) - { - printk ("SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen); - vfree (patch); - return -ENOSPC; - } - - p = 0; - for (i = 0; i < memlen / 2; i++) /* Handle words */ - { - unsigned char tmp; - - data = 0; - - if (patch->mode & WAVE_16_BITS) - { - get_user (*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */ - data = tmp; - get_user (*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */ - if (patch->mode & WAVE_UNSIGNED) - tmp ^= 0x80; /* Convert to signed */ - data |= (tmp << 8); - } - else - { - get_user (*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); - if (patch->mode & WAVE_UNSIGNED) - tmp ^= 0x80; /* Convert to signed */ - data = (tmp << 8); /* Convert to 16 bits */ - } + if (!(patch->mode & WAVE_16_BITS)) + memlen *= 2; + else + adj = 2; + + wave = vmalloc(memlen); + + if (wave == NULL) + { + printk("SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen); + vfree(patch); + return -ENOSPC; + } + p = 0; + for (i = 0; i < memlen / 2; i++) /* Handle words */ + { + unsigned char tmp; + + data = 0; + + if (patch->mode & WAVE_16_BITS) + { + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */ + data = tmp; + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */ + if (patch->mode & WAVE_UNSIGNED) + tmp ^= 0x80; /* Convert to signed */ + data |= (tmp << 8); + } else + { + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); + if (patch->mode & WAVE_UNSIGNED) + tmp ^= 0x80; /* Convert to signed */ + data = (tmp << 8); /* Convert to 16 bits */ + } - wave[i] = (short) data; - } + wave[i] = (short) data; + } - devc->ram_used += patch->len; + devc->ram_used += patch->len; /* * Convert pointers to 16 bit indexes */ - patch->len /= adj; - patch->loop_start /= adj; - patch->loop_end /= adj; + patch->len /= adj; + patch->loop_start /= adj; + patch->loop_end /= adj; /* * Finally link the loaded patch to the chain */ - patch->key = devc->programs[instr]; - devc->programs[instr] = devc->nrsamples; - devc->wave[devc->nrsamples] = (short *) wave; - devc->samples[devc->nrsamples++] = patch; + patch->key = devc->programs[instr]; + devc->programs[instr] = devc->nrsamples; + devc->wave[devc->nrsamples] = (short *) wave; + devc->samples[devc->nrsamples++] = patch; - return 0; + return 0; } static void -softsyn_panning (int dev, int voice, int pan) +softsyn_panning(int dev, int voice, int pan) { - if (voice < 0 || voice > devc->maxvoice) - return; + if (voice < 0 || voice > devc->maxvoice) + return; - if (pan < -128) - pan = -128; - if (pan > 127) - pan = 127; + if (pan < -128) + pan = -128; + if (pan > 127) + pan = 127; - softoss_voices[voice].panning = pan; - if (voice_active[voice]) - update_volume (voice); + softoss_voices[voice].panning = pan; + if (voice_active[voice]) + update_volume(voice); } static void -softsyn_volume_method (int dev, int mode) +softsyn_volume_method(int dev, int mode) { } static void -softsyn_aftertouch (int dev, int voice, int pressure) +softsyn_aftertouch(int dev, int voice, int pressure) { - if (voice < 0 || voice > devc->maxvoice) - return; + if (voice < 0 || voice > devc->maxvoice) + return; - if (voice_active[voice]) - update_volume (voice); + if (voice_active[voice]) + update_volume(voice); } static void -softsyn_controller (int dev, int voice, int ctrl_num, int value) +softsyn_controller(int dev, int voice, int ctrl_num, int value) { - unsigned long flags; + unsigned long flags; - if (voice < 0 || voice > devc->maxvoice) - return; - save_flags (flags); - cli (); + if (voice < 0 || voice > devc->maxvoice) + return; + save_flags(flags); + cli(); - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - softoss_voices[voice].bender = value; + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + softoss_voices[voice].bender = value; - if (voice_active[voice]) - compute_step (voice); /* Update pitch */ - break; + if (voice_active[voice]) + compute_step(voice); /* Update pitch */ + break; - case CTRL_PITCH_BENDER_RANGE: - softoss_voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - softoss_voices[voice].expression_vol = value; - if (voice_active[voice]) - update_volume (voice); - break; + case CTRL_PITCH_BENDER_RANGE: + softoss_voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + softoss_voices[voice].expression_vol = value; + if (voice_active[voice]) + update_volume(voice); + break; - case CTL_PAN: - softsyn_panning (dev, voice, (value * 2) - 128); - break; + case CTL_PAN: + softsyn_panning(dev, voice, (value * 2) - 128); + break; - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; - case CTRL_MAIN_VOLUME: - softoss_voices[voice].main_vol = value; - if (voice_active[voice]) - update_volume (voice); - break; + case CTRL_MAIN_VOLUME: + softoss_voices[voice].main_vol = value; + if (voice_active[voice]) + update_volume(voice); + break; - default: - break; - } + default: + break; + } - restore_flags (flags); + restore_flags(flags); } static void -softsyn_bender (int dev, int voice, int value) +softsyn_bender(int dev, int voice, int value) { - if (voice < 0 || voice > devc->maxvoice) - return; + if (voice < 0 || voice > devc->maxvoice) + return; - softoss_voices[voice].bender = value - 8192; - if (voice_active[voice]) - compute_step (voice); /* Update pitch */ + softoss_voices[voice].bender = value - 8192; + if (voice_active[voice]) + compute_step(voice); /* Update pitch */ } static int -softsyn_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) +softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best = -1, best_time = 0x7fffffff; + int i, p, best = -1, best_time = 0x7fffffff; - p = alloc->ptr; - /* - * First look for a completely stopped voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - voice_active[p] = 0; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } - - /* - * Then look for a releasing voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - voice_active[p] = 0; - return p; - } - p = (p + 1) % alloc->max_voice; - } - - if (best >= 0) - p = best; - - alloc->ptr = p; - voice_active[p] = 0; - return p; -} - -static void -softsyn_setup_voice (int dev, int voice, int chn) -{ - unsigned long flags; - - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; - - save_flags (flags); - cli (); - /* init_voice(devc, voice); */ - softsyn_set_instr (dev, voice, info->pgm_num); - - softoss_voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just MSB */ - softoss_voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - softsyn_panning (dev, voice, (info->controllers[CTL_PAN] * 2) - 128); - softoss_voices[voice].bender = 0; /* info->bender_value; */ - softoss_voices[voice].bender_range = info->bender_range; - - if (chn == 9) - softoss_voices[voice].percussive_voice = 1; - restore_flags (flags); -} - -static void -softsyn_reset (int devno) -{ - int i; - unsigned long flags; - - save_flags (flags); - cli (); - - for (i = 0; i < devc->maxvoice; i++) - init_voice (devc, i); - restore_flags (flags); + p = alloc->ptr; + /* + * First look for a completely stopped voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + voice_active[p] = 0; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } + + /* + * Then look for a releasing voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + voice_active[p] = 0; + return p; + } + p = (p + 1) % alloc->max_voice; + } + + if (best >= 0) + p = best; + + alloc->ptr = p; + voice_active[p] = 0; + return p; +} + +static void +softsyn_setup_voice(int dev, int voice, int chn) +{ + unsigned long flags; + + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + save_flags(flags); + cli(); + /* init_voice(devc, voice); */ + softsyn_set_instr(dev, voice, info->pgm_num); + + softoss_voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just MSB */ + softoss_voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + softsyn_panning(dev, voice, (info->controllers[CTL_PAN] * 2) - 128); + softoss_voices[voice].bender = 0; /* info->bender_value; */ + softoss_voices[voice].bender_range = info->bender_range; + + if (chn == 9) + softoss_voices[voice].percussive_voice = 1; + restore_flags(flags); +} + +static void +softsyn_reset(int devno) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + for (i = 0; i < devc->maxvoice; i++) + init_voice(devc, i); + restore_flags(flags); } static struct synth_operations softsyn_operations = { - "SoftOSS", - &softsyn_info, - 0, - SYNTH_TYPE_SAMPLE, - 0, - softsyn_open, - softsyn_close, - softsyn_ioctl, - softsyn_kill_note, - softsyn_start_note, - softsyn_set_instr, - softsyn_reset, - softsyn_hw_control, - softsyn_load_patch, - softsyn_aftertouch, - softsyn_controller, - softsyn_panning, - softsyn_volume_method, - softsyn_bender, - softsyn_alloc_voice, - softsyn_setup_voice + "SoftOSS", + &softsyn_info, + 0, + SYNTH_TYPE_SAMPLE, + 0, + softsyn_open, + softsyn_close, + softsyn_ioctl, + softsyn_kill_note, + softsyn_start_note, + softsyn_set_instr, + softsyn_reset, + softsyn_hw_control, + softsyn_load_patch, + softsyn_aftertouch, + softsyn_controller, + softsyn_panning, + softsyn_volume_method, + softsyn_bender, + softsyn_alloc_voice, + softsyn_setup_voice }; /* @@ -1493,101 +1455,126 @@ */ static unsigned int -soft_tmr_start (int dev, unsigned int usecs) +soft_tmr_start(int dev, unsigned int usecs) { - tmr_running = 1; - start_engine (devc); - return devc->usecs_per_frag; + tmr_running = 1; + start_engine(devc); + return devc->usecs_per_frag; } static void -soft_tmr_disable (int dev) +soft_tmr_disable(int dev) { - stop_engine (devc); - tmr_running = 0; + stop_engine(devc); + tmr_running = 0; } static void -soft_tmr_restart (int dev) +soft_tmr_restart(int dev) { - tmr_running = 1; + tmr_running = 1; } static struct sound_lowlev_timer soft_tmr = { - 0, - 9999, - soft_tmr_start, - soft_tmr_disable, - soft_tmr_restart + 0, + 9999, + soft_tmr_start, + soft_tmr_disable, + soft_tmr_restart }; int -probe_softsyn (struct address_info *hw_config) +probe_softsyn(struct address_info *hw_config) { - int i; + int i; - if (softsynth_loaded) - return 0; + if (softsynth_loaded) + return 0; - devc->ram_size = 8 * 1024 * 1024; - devc->ram_used = 0; - devc->nrsamples = 0; - for (i = 0; i < MAX_PATCH; i++) - { - devc->programs[i] = NO_SAMPLE; - devc->wave[i] = NULL; - } - - devc->maxvoice = DEFAULT_VOICES; - - devc->audiodev = 0; - devc->audio_opened = 0; - devc->channels = 2; - devc->bits = 16; - devc->max_playahead = 32; + devc->ram_size = 8 * 1024 * 1024; + devc->ram_used = 0; + devc->nrsamples = 0; + for (i = 0; i < MAX_PATCH; i++) + { + devc->programs[i] = NO_SAMPLE; + devc->wave[i] = NULL; + } + + devc->maxvoice = DEFAULT_VOICES; + + devc->audiodev = 0; + devc->audio_opened = 0; + devc->channels = 2; + devc->bits = 16; + devc->max_playahead = 32; #ifdef SOFTOSS_RATE - devc->speed = SOFTOSS_RATE; + devc->speed = SOFTOSS_RATE; #else - devc->speed = 32000; + devc->speed = 32000; #endif #ifdef SOFTOSS_VOICES - devc->default_max_voices = SOFTOSS_VOICES; + devc->default_max_voices = SOFTOSS_VOICES; #else - devc->default_max_voices = 32; + devc->default_max_voices = 32; #endif - softsynth_loaded = 1; - return 1; + softsynth_loaded = 1; + return 1; } void -attach_softsyn_card (struct address_info *hw_config) +attach_softsyn_card(struct address_info *hw_config) { - voice_alloc = &softsyn_operations.alloc; - synth_devs[num_synths++] = &softsyn_operations; - sequencer_init (); - sound_timer_init (&soft_tmr, "SoftOSS"); - devc->synthdev = num_synths; - softsynthp = softsynth_hook; + voice_alloc = &softsyn_operations.alloc; + synth_devs[devc->synthdev = num_synths++] = &softsyn_operations; + sequencer_init(); + sound_timer_init(&soft_tmr, "SoftOSS"); + devc->timerdev = num_sound_timers; + softsynthp = softsynth_hook; #ifndef POLLED_MODE #endif } void -unload_softsyn (struct address_info *hw_config) +unload_softsyn(struct address_info *hw_config) { - if (!softsynth_loaded) - return; + if (!softsynth_loaded) + return; #ifndef POLLED_MODE #endif - softsynthp = NULL; - reset_samples (devc); + softsynthp = NULL; + softsynth_loaded = 0; + reset_samples(devc); +} + +#ifdef MODULE + +static struct address_info config; + +int +init_module(void) +{ + printk("SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n"); + if (!probe_softsyn(&config)) + return -ENODEV; + attach_softsyn_card(&config); + SOUND_LOCK; + return 0; } +void +cleanup_module(void) +{ + unload_softsyn(&config); + sound_unload_synthdev(devc->synthdev); + sound_unload_timerdev(devc->timerdev); + SOUND_LOCK_END; +} +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/softoss.h linux/drivers/sound/softoss.h --- v2.1.66/linux/drivers/sound/softoss.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/softoss.h Sat Nov 29 10:33:21 1997 @@ -92,6 +92,7 @@ int ram_used; int synthdev; + int timerdev; int sequencer_mode; /* * Audio parameters diff -u --recursive --new-file v2.1.66/linux/drivers/sound/softoss_rs.c linux/drivers/sound/softoss_rs.c --- v2.1.66/linux/drivers/sound/softoss_rs.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/softoss_rs.c Sat Nov 29 10:33:21 1997 @@ -1,3 +1,4 @@ + /* * sound/softoss_rs.c * @@ -17,123 +18,119 @@ #include "sound_config.h" -#ifdef CONFIG_SOFTOSS +#if defined(CONFIG_SOFTOSS) || defined(MODULE) #include "softoss.h" void -softsynth_resample_loop (short *buf, int loops) +softsynth_resample_loop(short *buf, int loops) { - int iloop, voice; - volatile voice_info *v; + int iloop, voice; + volatile voice_info *v; #ifdef OSS_BIG_ENDIAN - unsigned char *cbuf = (unsigned char *) buf; + unsigned char *cbuf = (unsigned char *) buf; #endif - for (iloop = 0; iloop < loops; iloop++) - { /* Mix one sample */ + for (iloop = 0; iloop < loops; iloop++) + { /* Mix one sample */ - int accum, left = 0, right = 0; - int ix, position; + int accum, left = 0, right = 0; + int ix, position; - for (voice = 0; voice < devc->maxvoice; voice++) - if (voice_active[voice]) - { /* Compute voice */ + for (voice = 0; voice < devc->maxvoice; voice++) + if (voice_active[voice]) + { /* Compute voice */ - v = &softoss_voices[voice]; + v = &softoss_voices[voice]; #ifdef SOFTOSS_TEST - ix = iloop << 3; - position = v->ptr; + ix = iloop << 3; + position = v->ptr; #else - ix = (position = v->ptr) >> 9; + ix = (position = v->ptr) >> 9; #endif - /* Interpolation (resolution of 512 steps) */ - { - int fract = v->ptr & 0x1f; /* 9 bits */ - - /* This method works with less arithmetic operations */ - register int v1 = v->wave[ix]; - - accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9); - } - - left += (accum * v->leftvol); - right += (accum * v->rightvol); - - /* Update sample pointer */ - - position += v->step; - if (position <= v->endloop) - v->ptr = position; - else if (v->mode & WAVE_LOOPING) - { - if (v->mode & WAVE_BIDIR_LOOP) - { - v->mode ^= WAVE_LOOP_BACK; /* Turn around */ - v->step *= -1; - } - else - { - position -= v->looplen; - v->ptr = position; - } - } - /* else leave the voice looping the current sample */ - - if (v->mode & WAVE_LOOP_BACK && position < v->startloop) - { - if (v->mode & WAVE_BIDIR_LOOP) - { - v->mode ^= WAVE_LOOP_BACK; /* Turn around */ - v->step *= -1; - } - else - { - position += v->looplen; - v->ptr = position; - } - } - - } /* Compute voice */ - + /* Interpolation (resolution of 512 steps) */ + { + int fract = v->ptr & 0x1f; /* 9 bits */ + + /* This method works with less arithmetic operations */ + register int v1 = v->wave[ix]; + + accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9); + } + + left += (accum * v->leftvol); + right += (accum * v->rightvol); + + /* Update sample pointer */ + + position += v->step; + if (position <= v->endloop) + v->ptr = position; + else if (v->mode & WAVE_LOOPING) + { + if (v->mode & WAVE_BIDIR_LOOP) + { + v->mode ^= WAVE_LOOP_BACK; /* Turn around */ + v->step *= -1; + } else + { + position -= v->looplen; + v->ptr = position; + } + } + /* else leave the voice looping the current sample */ + + if (v->mode & WAVE_LOOP_BACK && position < v->startloop) + { + if (v->mode & WAVE_BIDIR_LOOP) + { + v->mode ^= WAVE_LOOP_BACK; /* Turn around */ + v->step *= -1; + } else + { + position += v->looplen; + v->ptr = position; + } + } + } /* Compute voice */ #if 1 /* Delay */ - left += left_delay[delayp]; - right += right_delay[delayp]; + left += left_delay[delayp]; + right += right_delay[delayp]; - left_delay[delayp] = right >> 2; - right_delay[delayp] = left >> 2; - delayp = (delayp + 1) % devc->delay_size; + left_delay[delayp] = right >> 2; + right_delay[delayp] = left >> 2; + delayp = (delayp + 1) % devc->delay_size; #endif #define AFTERSCALE devc->afterscale; - left >>= AFTERSCALE; - right >>= AFTERSCALE; + left >>= AFTERSCALE; + right >>= AFTERSCALE; - if (left > 32767) - left = 32767; - if (left < -32768) - left = -32768; - if (right > 32767) - right = 32767; - if (right < -32768) - right = -32768; + if (left > 32767) + left = 32767; + if (left < -32768) + left = -32768; + if (right > 32767) + right = 32767; + if (right < -32768) + right = -32768; #ifdef OSS_BIG_ENDIAN - *cbuf++ = left & 0xff; - *cbuf++ = (left >> 8) & 0xff; - *cbuf++ = right & 0xff; - *cbuf++ = (right >> 8) & 0xff; + *cbuf++ = left & 0xff; + *cbuf++ = (left >> 8) & 0xff; + *cbuf++ = right & 0xff; + *cbuf++ = (right >> 8) & 0xff; #else - *buf++ = left; - *buf++ = right; + *buf++ = left; + *buf++ = right; #endif - if (devc->control_counter++ >= devc->control_rate) - { - devc->control_counter = 0; - softsyn_control_loop (); - } - } /* Mix one sample */ + if (devc->control_counter++ >= devc->control_rate) + { + devc->control_counter = 0; + softsyn_control_loop(); + } + } /* Mix one sample */ } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.1.66/linux/drivers/sound/sound_calls.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sound_calls.h Sat Nov 29 10:33:21 1997 @@ -108,7 +108,7 @@ /* From opl3.c */ int opl3_detect (int ioaddr, int *osp); -void opl3_init(int ioaddr, int *osp); +int opl3_init(int ioaddr, int *osp); /* From sb_card.c */ void attach_sb_card(struct address_info *hw_config); @@ -161,7 +161,7 @@ /* From gus_wave.c */ int gus_wave_detect(int baseaddr); void gus_wave_init(struct address_info *hw_config); -void gus_wave_unload (void); +void gus_wave_unload (struct address_info *hw_config); void gus_voice_irq(void); void gus_write8(int reg, unsigned int data); void guswave_dma_irq(void); @@ -170,7 +170,7 @@ void gus_timer_command (unsigned int addr, unsigned int val); /* From gus_midi.c */ -void gus_midi_init(void); +void gus_midi_init(struct address_info *hw_config); void gus_midi_interrupt(int dummy); /* From mpu401.c */ @@ -186,14 +186,14 @@ void enable_opl3_mode(int left, int right, int both); /* From ics2101.c */ -void ics2101_mixer_init(void); +int ics2101_mixer_init(void); /* From sound_timer.c */ void sound_timer_interrupt(void); void sound_timer_syncinterval(unsigned int new_usecs); /* From ad1848.c */ -void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp); +int ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp); void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); int ad1848_detect (int io_base, int *flags, int *osp); diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v2.1.66/linux/drivers/sound/sound_config.h Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sound_config.h Sat Nov 29 10:33:21 1997 @@ -11,7 +11,7 @@ */ -#include "local.h" +#include "local.h.master" #include "os.h" #include "soundvers.h" @@ -116,7 +116,9 @@ int driver_use_1; /* Driver defined field 1 */ int driver_use_2; /* Driver defined field 2 */ int *osp; /* OS specific info */ - int card_subtype; /* Driver spesific. Usually 0 */ + int card_subtype; /* Driver specific. Usually 0 */ + void *memptr; /* Module memory chainer */ + int slots[6]; /* To remember driver slot ids */ }; #define SYNTH_MAX_VOICES 32 @@ -163,5 +165,17 @@ #define DDB(x) {} #endif +#ifndef MDB +#ifdef MODULE +#define MDB(x) x +#else +#define MDB(x) +#endif +#endif + #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 + + + + diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_firmware.c linux/drivers/sound/sound_firmware.c --- v2.1.66/linux/drivers/sound/sound_firmware.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/sound_firmware.c Sat Nov 29 10:33:21 1997 @@ -0,0 +1,58 @@ +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include + +static int errno; + +static int do_mod_firmware_load(const char *fn, char **fp) +{ + int fd; + long l; + char *dp; + + fd = open(fn, 0, 0); + if (fd == -1) + { + printk(KERN_INFO "Unable to load '%s'.\n", fn); + return 0; + } + l = lseek(fd, 0L, 2); + if (l <= 0 || l > 65535) + { + printk(KERN_INFO "Invalid firmware '%s'\n", fn); + sys_close(fd); + return 0; + } + lseek(fd, 0L, 0); + dp = kmalloc(l, GFP_KERNEL); + if (dp == NULL) + { + printk(KERN_INFO "Out of memory loading '%s'.\n", fn); + sys_close(fd); + return 0; + } + if (read(fd, dp, l) != l) + { + printk(KERN_INFO "Failed to read '%s'.\n", fn); + kfree(dp); + sys_close(fd); + return 0; + } + close(fd); + *fp = dp; + return (int) l; +} + +int mod_firmware_load(const char *fn, char **fp) +{ + int r; + unsigned long fs = get_fs(); + + set_fs(get_ds()); + r = do_mod_firmware_load(fn, fp); + set_fs(fs); + return r; +} diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_firmware.h linux/drivers/sound/sound_firmware.h --- v2.1.66/linux/drivers/sound/sound_firmware.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/sound_firmware.h Sat Nov 29 10:33:21 1997 @@ -0,0 +1,2 @@ +extern int mod_firmware_load(const char *fn, char **fp); + diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_pnp.c linux/drivers/sound/sound_pnp.c --- v2.1.66/linux/drivers/sound/sound_pnp.c Wed May 28 10:51:33 1997 +++ linux/drivers/sound/sound_pnp.c Wed Dec 31 16:00:00 1969 @@ -1,1513 +0,0 @@ -/* - * sound/sound_pnp.c - * - * PnP soundcard support (Linux spesific) - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -#include - -#include "sound_config.h" - -#if defined(CONFIG_SPNP) - - -static struct wait_queue *maui_sleeper = NULL; -static volatile struct snd_wait maui_sleep_flag = -{0}; - -extern unsigned long init_pnp (unsigned long, int *); - -#include "pnp.h" -extern int *sound_osp; - -extern int (*pnp_ioctl) (unsigned int cmd, caddr_t arg); - -extern int sound_pnp_port; -static int disabled_devices[] = -{ - PNP_DEVID ('G', 'R', 'V', 0x0003), /* GUS SB emulation */ - PNP_DEVID ('G', 'R', 'V', 0x0004), /* GUS MPU emulation */ - 0 -}; - -static int special_devices[] = -{ - PNP_DEVID ('C', 'S', 'C', 0x0010), /* CS4232/6 control port */ - PNP_DEVID ('C', 'S', 'C', 0x0002), /* CS4232/6 control port */ - 0 -}; - -static int pnp_sig = 0; - -static void -pnp_delay (long t) -{ - t = (t * HZ) / 1000000; /* Convert to jiffies */ - - - { - unsigned long tlimit; - - if (t) - current->timeout = tlimit = jiffies + (t); - else - tlimit = (unsigned long) -1; - maui_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&maui_sleeper); - if (!(maui_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - maui_sleep_flag.opts |= WK_TIMEOUT; - } - maui_sleep_flag.opts &= ~WK_SLEEP; - }; -} - -void -cs4232_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - int old_num_mixers = num_mixers; - int is_4232 = 0; /* CS4232 (not CS4236 or something better) */ - - int portmask = 0xff; - int irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver; - - - if (pnp_trace) - printk ("CS4232/6 driver waking up\n"); - - if (dev->card->key == (PNP_DEVID ('C', 'S', 'C', 0x4232))) - is_4232 = 1; - -#ifndef USE_HOT_PNP_INIT - if (is_4232) /* CS4232 may cause lockups */ - if (pnp_get_port (dev, 0) == NO_PORT || - pnp_get_port (dev, 1) == NO_PORT || - pnp_get_irq (dev, 0) == NO_IRQ || - pnp_get_dma (dev, 0) == NO_DMA - ) - { - printk ("Sound: CS4232 in PnP mode requires prior initialization by PnP BIOS\n"); - return; - } -#endif - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x02; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!is_4232) - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - { - printk ("sound_pnp: Failed to find free resources\n"); - return; - } - - { - struct address_info hw_config; - int wss_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 0); - opl3_base = pnp_get_port (dev, 1); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - - if (num_mixers > old_num_mixers) - { /* Assume the mixer map is as suggested in the CS4232 spec */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM */ - } - } - } -} - -void -opti82C924_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver; - - if (pnp_trace) - printk ("OPTi 82C924 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x02; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int wss_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 1); - opl3_base = pnp_get_port (dev, 2); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (2000000); - - if (pnp_trace) - { - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base + 8; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base + 4; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - } - } -} - -void -opl3sa2_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver, mpu_driver; - - if (pnp_trace) - printk ("OPL3-SA2 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x02; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x04; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x08; /* OPL3 */ - else - printk ("Sound: PnP UART401 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int wss_base, opl3_base, mpu_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 1); - opl3_base = pnp_get_port (dev, 2); - mpu_base = pnp_get_port (dev, 3); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("I/O3 %03x\n", mpu_base); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base + 4; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -static unsigned char -C931_read (int base, int reg) -{ - unsigned char data; - unsigned long flags; - - save_flags (flags); - cli (); - outb ((0xE4), base); - outb ((reg), base + 2); - data = inb (base + 3); - restore_flags (flags); - return data; -} - -static void -C931_write (int base, int reg, unsigned char data) -{ - unsigned long flags; - - save_flags (flags); - cli (); - outb ((0xE4), base); - outb ((reg), base + 2); - outb ((data), base + 3); - restore_flags (flags); -} - -void -opti82C931_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int opl3_driver, wss_driver; - - if (pnp_trace) - printk ("OPTi 82C931 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP WSS"; - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MSS */ - else - printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x02; /* OPL3 */ - else - printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); - - /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int wss_base, opl3_base, master_ctl; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - wss_base = pnp_get_port (dev, 0); - opl3_base = pnp_get_port (dev, 1); - master_ctl = pnp_get_port (dev, 3); - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - if (pnp_trace) - { - int i; - - printk ("I/O0 %03x\n", wss_base); - printk ("I/O1 %03x\n", opl3_base); - printk ("Master control port %x\n", master_ctl); - for (i = 0; i < 4; i++) - printk ("Port %x = %x\n", master_ctl + i, inb (master_ctl + i)); - printk ("IRQ %d\n", irq); - printk ("DMA0 %d\n", dma1); - printk ("DMA1 %d\n", dma2); - } - { - unsigned char tmp; - - tmp = C931_read (master_ctl, 5) | 0x20; /* Enable codec registers I16 to I31 */ - C931_write (master_ctl, 5, tmp); - - tmp = 0x82; /* MPU and WSS enabled, SB disabled */ - C931_write (master_ctl, 6, tmp); - } - - pnp_delay (2000000); - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base + 8; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (wss_base && wss_driver) - { - hw_config.io_base = wss_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - - ad1848_control (AD1848_SET_C930_PWD, master_ctl); - } - } -} - -void -opti82C924mpu_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int mpu_driver; - - if (pnp_trace) - printk ("OPTi 82C924/C925/C931 MPU driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP MPU"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; /* MPU401 */ - else - printk ("Sound: PnP MPU device detected but no driver enabled\n"); - - /* printk ("MPU driver %d\n", mpu_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - irq = pnp_get_irq (dev, 0); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O %03x\n", mpu_base); - printk ("IRQ %d\n", irq); - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -void -cs4236mpu_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; - int mpu_driver; - - if (dev->card->key == (PNP_DEVID ('C', 'S', 'C', 0x4232))) /* CS4232 */ - return; - - if (pnp_trace) - printk ("CS4236 MPU driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "PnP MPU"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; /* MPU401 */ - else - printk ("Sound: CS4236 PnP MPU device detected but no driver enabled\n"); - - /* printk ("MPU driver %d\n", mpu_driver); */ - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - irq = pnp_get_irq (dev, 0); - - pnp_delay (1500000); - - if (pnp_trace) - { - printk ("I/O %03x\n", mpu_base); - printk ("IRQ %d\n", irq); - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -void -soundscape_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0xff, irqmask = 0x03, dmamask = 0x01; - int sscape_driver, wss_driver; - - if (pnp_trace) - printk ("Soundscape PnP driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SoundScape PnP"; - - if ((sscape_driver = sndtable_identify_card ("SSCAPE"))) - portmask |= 0x01; /* MPU401 */ - else - printk ("Sound: Soundscape PnP device detected but no driver enabled\n"); - - /* printk ("Soundscape driver %d\n", sscape_driver); */ - - if ((wss_driver = sndtable_identify_card ("SSCAPEMSS"))) - portmask |= 0x01; - else - printk ("Sound: Soundscape codec device detected but no driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sscape_base; - int irq, irq2, dma, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sscape_base = pnp_get_port (dev, 0); - irq = pnp_get_irq (dev, 0); - irq2 = pnp_get_irq (dev, 1); - dma = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - pnp_delay (1000000); - - if (pnp_trace) - { - printk ("I/O %03x\n", sscape_base); - printk ("IRQ %d\n", irq); - printk ("IRQ2 %d\n", irq2); - printk ("DMA %d\n", dma); - printk ("DMA2 %d\n", dma2); - } - - if (sscape_base && sscape_driver) - { - hw_config.io_base = sscape_base; - hw_config.irq = irq; - hw_config.dma = dma; - hw_config.dma2 = dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0x12345678; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (sscape_driver, &hw_config); - } - - if (sscape_base && wss_driver) - { - hw_config.io_base = sscape_base + 8; /* The codec base */ - hw_config.irq = irq2; - hw_config.dma = dma; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - ad1848_control (AD1848_SET_XTAL, 1); /* 14.3 MHz is used */ - } - } -} - -void -soundscape_vivo (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x07, irqmask = 0x03, dmamask = 0x03; - int mpu_driver, wss_driver, vivo_driver; - int is_vivo_classic = 0; - - if (pnp_trace) - printk ("Soundscape VIVO driver waking up\n"); - - if (dev->card->key == (PNP_DEVID ('E', 'N', 'S', 0x4080))) - is_vivo_classic = 1; - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SoundScape VIVO"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; /* MPU401 */ - - /* printk ("MPU driver %d\n", mpu_driver); */ - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x02; - else - printk ("Sound: Soundscape codec device detected but no driver enabled\n"); - - if ((vivo_driver = sndtable_identify_card ("VIVO"))) - portmask |= 0x07; - else - printk ("Sound: Soundscape VIVO/OTTO device detected but no driver installed\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base, mss_base, otto_base; - int irq, irq2, dma, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - mss_base = pnp_get_port (dev, 1); - otto_base = pnp_get_port (dev, 2); - irq = pnp_get_irq (dev, 0); - irq2 = pnp_get_irq (dev, 1); - dma = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - if (dma2 == NO_DMA) - dma2 = dma; - - if (pnp_trace) - { - printk ("I/O %03x\n", mpu_base); - printk ("MSS I/O %03x\n", mss_base); - printk ("OTTO I/O %03x\n", otto_base); - printk ("IRQ %d\n", irq); - printk ("IRQ2 %d\n", irq2); - printk ("DMA %d\n", dma); - printk ("DMA2 %d\n", dma2); - } - - - if (mss_base && wss_driver) - { - hw_config.io_base = mss_base + 4; /* The codec base */ - hw_config.irq = irq; - hw_config.dma = dma; - hw_config.dma2 = dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (wss_driver, &hw_config); - } - - if (otto_base && vivo_driver) - { - hw_config.io_base = otto_base; - hw_config.irq = irq2; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = mpu_base; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (vivo_driver, &hw_config); - - if (is_vivo_classic) - { - /* - * The original VIVO uses XCTL0 pin of AD1845 as a synth (un)mute bit. Turn it - * on _after_ the synth is initialized. Btw, XCTL1 controls 30 dB mic boost - * circuit. - */ - - ad1848_control (AD1848_SET_XCTL0, 1); /* Unmute */ - } - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); /* AUX1 is OTTO input */ - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE); /* Line in */ - - } - } -} - -void -gus_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int gus_driver, wss_driver; - - if (pnp_trace) - printk ("GUS PnP driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "Ultrasound PnP"; - - if ((gus_driver = sndtable_identify_card ("GUSPNP"))) - portmask |= 0x07; - else - printk ("Sound: GUS PnP device detected but no driver enabled\n"); - - if ((wss_driver = sndtable_identify_card ("AD1848"))) - portmask |= 0x01; /* MAX */ - else - printk ("Sound: GUS PnP codec device detected but no driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int gus_base; - int irq; - int dma1, dma2; - - gus_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - if (pnp_trace) - printk ("Device activation OK (P%x I%d D%d d%d)\n", - gus_base, irq, dma1, dma2); - - if (gus_base && gus_driver) - { - - hw_config.io_base = gus_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (gus_driver, &hw_config); - } - } -} - -void -sb_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int sb_driver, mpu_driver, opl3_driver; - - if (pnp_trace) - printk ("SB PnP driver waking up\n"); - pnp_delay (1000000); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SoundBlaster PnP"; - - if ((sb_driver = sndtable_identify_card ("SBPNP"))) - portmask |= 0x01; - else - printk ("Sound: SB PnP device detected but no driver enabled\n"); - - if ((mpu_driver = sndtable_identify_card ("SBMPU"))) - portmask |= 0x02; - else - printk ("Sound: SB PnP device detected but SB MPU driver not enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x04; - else - printk ("Sound: SB PnP device detected but OPL3 driver not enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sb_base, mpu_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sb_base = pnp_get_port (dev, 0); - mpu_base = pnp_get_port (dev, 1); - opl3_base = pnp_get_port (dev, 2); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - dma2 = pnp_get_dma (dev, 1); - - if (sb_base && sb_driver) - { - hw_config.io_base = sb_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (sb_driver, &hw_config); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -void -als_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int sb_driver; - - if (pnp_trace) - printk ("ALS### PnP driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SB16 clone"; - - if ((sb_driver = sndtable_identify_card ("SBPNP"))) - portmask |= 0x01; - else - printk ("Sound: ALS PnP device detected but no driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sb_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sb_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 1); - dma2 = pnp_get_dma (dev, 0); - - if (sb_base && sb_driver) - { - hw_config.io_base = sb_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (sb_driver, &hw_config); - } - } -} - -void -als_pnp_mpu (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int mpu_driver; - - if (pnp_trace) - printk ("ALS### PnP MPU driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SB16 clone"; - - if ((mpu_driver = sndtable_identify_card ("UART401"))) - portmask |= 0x01; - else - printk ("Sound: ALS PnP device detected but no MPU driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int mpu_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - mpu_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - } - } -} - -void -als_pnp_opl (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; - int opl3_driver; - - if (pnp_trace) - printk ("ALS### PnP OPL3 driver waking up\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "SB16 clone"; - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x01; - else - printk ("Sound: ALS PnP device detected but no OPL3 driver enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int opl3_base; - int irq; - - if (pnp_trace) - printk ("Device activation OK\n"); - opl3_base = pnp_get_port (dev, 0); - - irq = pnp_get_irq (dev, 0); - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = sound_osp; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - } - } -} - -void -ess_pnp (void *parm) -{ - struct pnp_dev *dev = (struct pnp_dev *) parm; - char *name; - - int portmask = 0x03, irqmask = 0x01, dmamask = 0x03; - int sb_driver, mpu_driver, opl3_driver; - - if (pnp_trace) - printk ("ESS PnP driver waking up\n"); - - if (pnp_trace) - { - printk ("ESS1868: IRQB,IRQA = %x\n", pnp_readreg (dev, 0x20)); - printk ("ESS1868: IRQD,IRQC = %x\n", pnp_readreg (dev, 0x21)); - printk ("ESS1868: IRQF,IRQE = %x\n", pnp_readreg (dev, 0x22)); - printk ("ESS1868: DRQB,DRQA = %x\n", pnp_readreg (dev, 0x23)); - printk ("ESS1868: DRQD,DRQC = %x\n", pnp_readreg (dev, 0x24)); - printk ("ESS1868: Configuration ROM Header 0 = %x\n", pnp_readreg (dev, 0x25)); - printk ("ESS1868: Configuration ROM Header 1 = %x\n", pnp_readreg (dev, 0x26)); - printk ("ESS1868: HW Volume IRQ = %x\n", pnp_readreg (dev, 0x27)); - printk ("ESS1868: MPU401 IRQ = %x\n", pnp_readreg (dev, 0x28)); - } - - if (pnp_readreg (dev, 0x27) & 0x01) /* MPU401 is at logical device #3 */ - printk ("Nonstandard ESS1868 implementation - contact support@4front-tech.com\n"); - - if (dev->card && dev->card->name) - name = dev->card->name; - else - name = "ESS AudioDrive PnP"; - - if ((sb_driver = sndtable_identify_card ("SBLAST"))) - portmask |= 0x01; - else - printk ("Sound: SB PnP device detected but no driver enabled\n"); - - if ((mpu_driver = sndtable_identify_card ("SBMPU"))) - portmask |= 0x02; - else - printk ("Sound: SB PnP device detected but SB MPU driver not enabled\n"); - - if ((opl3_driver = sndtable_identify_card ("OPL3"))) - portmask |= 0x04; - else - printk ("Sound: SB PnP device detected but OPL3 driver not enabled\n"); - - if (!portmask) /* No drivers available */ - return; - - if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) - printk ("sound_pnp: Failed to find free resources\n"); - else - { - struct address_info hw_config; - int sb_base, mpu_base, opl3_base; - int irq; - int dma1, dma2; - - if (pnp_trace) - printk ("Device activation OK\n"); - sb_base = pnp_get_port (dev, 0); - opl3_base = pnp_get_port (dev, 1); - mpu_base = pnp_get_port (dev, 2); - - irq = pnp_get_irq (dev, 0); - dma1 = pnp_get_dma (dev, 0); - /* dma2 = pnp_get_dma (dev, 1); */ dma2 = -1; - - if (pnp_trace) - { - printk ("ESS PnP at %x/%x/%x, %d, %d/%d\n", - sb_base, mpu_base, opl3_base, - irq, dma1, dma2); - } - - if (sb_base && sb_driver) - { - hw_config.io_base = sb_base; - hw_config.irq = irq; - hw_config.dma = dma1; - hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; - hw_config.always_detect = 0; - hw_config.name = name; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = NULL; - hw_config.card_subtype = 0; - - sndtable_start_card (sb_driver, &hw_config); - } - - if (opl3_base && opl3_driver) - { - hw_config.io_base = opl3_base; - hw_config.irq = 0; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = NULL; - hw_config.card_subtype = 0; - - sndtable_start_card (opl3_driver, &hw_config); - - } - - if (mpu_base && mpu_driver) - { - hw_config.io_base = mpu_base; - hw_config.irq = -irq; - hw_config.dma = -1; - hw_config.dma2 = -1; - hw_config.always_detect = 0; - hw_config.name = ""; - hw_config.driver_use_1 = 0; - hw_config.driver_use_2 = 0; - hw_config.osp = NULL; - hw_config.card_subtype = 0; - - sndtable_start_card (mpu_driver, &hw_config); - - } - } -} - -static struct pnp_sounddev pnp_devs[] = -{ - {PNP_DEVID ('C', 'S', 'C', 0x0000), cs4232_pnp, "CS4232"}, - {PNP_DEVID ('C', 'S', 'C', 0x0003), cs4236mpu_pnp, "CS4236MPU"}, - {PNP_DEVID ('G', 'R', 'V', 0x0000), gus_pnp, "GUS"}, - {PNP_DEVID ('R', 'V', 'L', 0x0010), gus_pnp, "WAVXTREME"}, - {PNP_DEVID ('A', 'D', 'V', 0x0010), gus_pnp, "IWAVE"}, - {PNP_DEVID ('D', 'X', 'P', 0x0010), gus_pnp, "IWAVE"}, - {PNP_DEVID ('Y', 'M', 'H', 0x0021), opl3sa2_pnp, "OPL3SA2"}, - {PNP_DEVID ('O', 'P', 'T', 0x0000), opti82C924_pnp, "82C924"}, - {PNP_DEVID ('O', 'P', 'T', 0x9250), opti82C924_pnp, "82C925"}, - {PNP_DEVID ('O', 'P', 'T', 0x9310), opti82C931_pnp, "82C931"}, - {PNP_DEVID ('O', 'P', 'T', 0x0002), opti82C924mpu_pnp, "82C924MPU"}, - {PNP_DEVID ('E', 'N', 'S', 0x0000), soundscape_pnp, "SSCAPE"}, - {PNP_DEVID ('N', 'E', 'C', 0x0000), soundscape_pnp, "NEC"}, - {PNP_DEVID ('E', 'N', 'S', 0x1010), soundscape_vivo, "SSCAPE"}, - {PNP_DEVID ('E', 'N', 'S', 0x1011), soundscape_vivo, "SSCAPE"}, - {PNP_DEVID ('C', 'T', 'L', 0x0031), sb_pnp, "SB"}, - {PNP_DEVID ('C', 'T', 'L', 0x0001), sb_pnp, "SB"}, - {PNP_DEVID ('C', 'T', 'L', 0x0041), sb_pnp, "SB"}, /* SB32 (new revision) */ - {PNP_DEVID ('C', 'T', 'L', 0x0042), sb_pnp, "SB"}, /* SB64 */ - {PNP_DEVID ('C', 'T', 'L', 0x0044), sb_pnp, "SB"}, /* SB64 Gold */ - {PNP_DEVID ('@', '@', '@', 0x0001), als_pnp, "SB"}, - {PNP_DEVID ('@', 'X', '@', 0x0001), als_pnp_mpu, "SB"}, - {PNP_DEVID ('@', 'H', '@', 0x0001), als_pnp_opl, "SB"}, - {PNP_DEVID ('E', 'S', 'S', 0x1868), ess_pnp, "ESS"} -}; - -static int nr_pnpdevs = sizeof (pnp_devs) / sizeof (struct pnp_sounddev); - -static int -pnp_activate (int id, struct pnp_dev *dev) -{ - int i; - - for (i = 0; i < nr_pnpdevs; i++) - if (pnp_devs[i].id == id) - { - - if (pnp_trace) - printk ("PnP dev: %08x, %s\n", id, - pnp_devid2asc (id)); - - pnp_devs[i].setup ((void *) dev); - return 1; - } - - return 0; -} - -void -cs423x_special (struct pnp_dev *dev) -{ -} - -void -sound_pnp_init (int *osp) -{ - - struct pnp_dev *dev; - - if (pnp_sig == 0) - init_pnp (0, osp); - - if (pnp_sig == 0) - if ((pnp_sig = pnp_connect ("sound")) == -1) - { - printk ("Sound: Can't connect to kernel PnP services.\n"); - return; - } - -/* - * First handle some special configuration ports. - */ - dev = NULL; - while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) - { - int i; - - for (i = 0; special_devices[i] != 0; i++) - if (special_devices[i] == dev->key) - switch (i) - { - case 0: - case 1: - cs423x_special (dev); - break; - } - } - -/* - * Next disable some unused sound devices so that they don't consume - * valuable IRQ and DMA resources. - */ - dev = NULL; - while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) - { - int i; - - for (i = 0; disabled_devices[i] != 0; i++) - if (disabled_devices[i] == dev->key) - pnp_enable_device (dev, 0); /* Disable it */ - } - -/* - * Then initialize drivers for known PnP devices. - */ - dev = NULL; - while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) - { - if (!pnp_activate (dev->key, dev)) - { - /* Scan all compatible devices */ - - int i; - - for (i = 0; i < dev->ncompat; i++) - if (pnp_activate (dev->compat_keys[i], dev)) - break; - } - } -} - -void -sound_pnp_disconnect (void) -{ - pnp_disconnect (pnp_sig); -} - - -#endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c --- v2.1.66/linux/drivers/sound/sound_switch.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sound_switch.c Sat Nov 29 10:33:21 1997 @@ -33,702 +33,702 @@ int * -load_mixer_volumes (char *name, int *levels, int present) +load_mixer_volumes(char *name, int *levels, int present) { - int i, n; + int i, n; + + for (i = 0; i < num_mixer_volumes; i++) + if (strcmp(name, mixer_vols[i].name) == 0) + { + if (present) + mixer_vols[i].num = i; + return mixer_vols[i].levels; + } + if (num_mixer_volumes >= MAX_MIXER_DEV) + { + printk("Sound: Too many mixers (%s)\n", name); + return levels; + } + n = num_mixer_volumes++; + + strcpy(mixer_vols[n].name, name); - for (i = 0; i < num_mixer_volumes; i++) - if (strcmp (name, mixer_vols[i].name) == 0) - { if (present) - mixer_vols[i].num = i; - return mixer_vols[i].levels; - } - - if (num_mixer_volumes >= MAX_MIXER_DEV) - { - printk ("Sound: Too many mixers (%s)\n", name); - return levels; - } - - n = num_mixer_volumes++; - - strcpy (mixer_vols[n].name, name); - - if (present) - mixer_vols[n].num = n; - else - mixer_vols[n].num = -1; - - for (i = 0; i < 32; i++) - mixer_vols[n].levels[i] = levels[i]; - return mixer_vols[n].levels; + mixer_vols[n].num = n; + else + mixer_vols[n].num = -1; + + for (i = 0; i < 32; i++) + mixer_vols[n].levels[i] = levels[i]; + return mixer_vols[n].levels; } static int -set_mixer_levels (caddr_t arg) +set_mixer_levels(caddr_t arg) { - mixer_vol_table *buf = NULL; - int err = 0; + mixer_vol_table *buf = NULL; + int err = 0; - if ((buf = (mixer_vol_table *) vmalloc (sizeof (mixer_vol_table))) == NULL) - return -ENOSPC; + if ((buf = (mixer_vol_table *) vmalloc(sizeof(mixer_vol_table))) == NULL) + return -ENOSPC; - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); - load_mixer_volumes (buf->name, buf->levels, 0); + load_mixer_volumes(buf->name, buf->levels, 0); - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); - return err; + return err; } static int -get_mixer_levels (caddr_t arg) +get_mixer_levels(caddr_t arg) { - mixer_vol_table *buf = NULL; - int n, err = 0; + mixer_vol_table *buf = NULL; + int n, err = 0; - if ((buf = (mixer_vol_table *) vmalloc (sizeof (mixer_vol_table))) == NULL) - return -ENOSPC; + if ((buf = (mixer_vol_table *) vmalloc(sizeof(mixer_vol_table))) == NULL) + return -ENOSPC; - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); - n = buf->num; - if (n < 0 || n >= num_mixer_volumes) - err = -EINVAL; - else - { - memcpy ((char *) buf, (char *) &mixer_vols[n], sizeof (*buf)); - } + n = buf->num; + if (n < 0 || n >= num_mixer_volumes) + err = -EINVAL; + else + { + memcpy((char *) buf, (char *) &mixer_vols[n], sizeof(*buf)); + } - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); - return err; + return err; } static int -put_status (char *s) +put_status(char *s) { - int l = strlen (s); + int l = strlen(s); - if (status_len + l >= 4000) - return 0; + if (status_len + l >= 4000) + return 0; - memcpy (&status_buf[status_len], s, l); - status_len += l; + memcpy(&status_buf[status_len], s, l); + status_len += l; - return 1; + return 1; } static int -put_status_int (unsigned int val, int radix) +put_status_int(unsigned int val, int radix) { - int l, v; + int l, v; - static char hx[] = "0123456789abcdef"; - char buf[11]; + static char hx[] = "0123456789abcdef"; + char buf[11]; - if (!val) - return put_status ("0"); + if (!val) + return put_status("0"); - l = 0; - buf[10] = 0; + l = 0; + buf[10] = 0; - while (val) - { - v = val % radix; - val = val / radix; + while (val) + { + v = val % radix; + val = val / radix; - buf[9 - l] = hx[v]; - l++; - } + buf[9 - l] = hx[v]; + l++; + } - if (status_len + l >= 4000) - return 0; + if (status_len + l >= 4000) + return 0; - memcpy (&status_buf[status_len], &buf[10 - l], l); - status_len += l; + memcpy(&status_buf[status_len], &buf[10 - l], l); + status_len += l; - return 1; + return 1; } static void -init_status (void) +init_status(void) { - /* - * Write the status information to the status_buf and update status_len. - * There is a limit of 4000 bytes for the data. - */ + /* + * Write the status information to the status_buf and update status_len. + * There is a limit of 4000 bytes for the data. + */ - int i; + int i; - status_ptr = 0; + status_ptr = 0; #ifdef SOUND_UNAME_A - put_status ("OSS/Free" SOUND_VERSION_STRING - " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n" - SOUND_UNAME_A ")" - "\n"); + put_status("OSS/Free" SOUND_VERSION_STRING + " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n" + SOUND_UNAME_A ")" + "\n"); #else - put_status ("OSS/Free:" SOUND_VERSION_STRING - " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" - SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" - "\n"); + put_status("OSS/Free:" SOUND_VERSION_STRING +#if 0 + " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" + SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" +#endif + "\n"); #endif #ifdef MODULE - put_status ("Load type: Driver loaded as a module.\n"); + put_status("Load type: Driver loaded as a module.\n"); #else - put_status ("Load type: Driver compiled into kernel\n"); + put_status("Load type: Driver compiled into kernel\n"); #endif - put_status ("Kernel: "); - put_status (system_utsname.sysname); - put_status (" "); - put_status (system_utsname.nodename); - put_status (" "); - put_status (system_utsname.release); - put_status (" "); - put_status (system_utsname.version); - put_status (" "); - put_status (system_utsname.machine); - put_status ("\n"); - - - if (!put_status ("Config options: ")) - return; - if (!put_status_int (SELECTED_SOUND_OPTIONS, 16)) - return; - - if (!put_status ("\n\nInstalled drivers: \n")) - return; - - for (i = 0; i < num_sound_drivers; i++) - if (sound_drivers[i].card_type != 0) - { - if (!put_status ("Type ")) - return; - if (!put_status_int (sound_drivers[i].card_type, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (sound_drivers[i].name)) - return; - - if (!put_status ("\n")) - return; - } - - - if (!put_status ("\nCard config: \n")) - return; - - for (i = 0; i < num_sound_cards; i++) - if (snd_installed_cards[i].card_type != 0) - { - int drv, tmp; - - if (!snd_installed_cards[i].enabled) - if (!put_status ("(")) - return; - - /* - * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return; - * if (!put_status (": ")) return; - */ - - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) - if (!put_status (sound_drivers[drv].name)) - return; - - if (snd_installed_cards[i].config.io_base) - { - if (!put_status (" at 0x")) - return; - if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) - return; - } - - tmp = snd_installed_cards[i].config.irq; - if (tmp != 0) - { - if (!put_status (" irq ")) - return; - if (tmp < 0) - tmp = -tmp; - if (!put_status_int (tmp, 10)) - return; - } - - if (snd_installed_cards[i].config.dma != -1) - { - if (!put_status (" drq ")) - return; - if (!put_status_int (snd_installed_cards[i].config.dma, 10)) - return; - if (snd_installed_cards[i].config.dma2 != -1) - { - if (!put_status (",")) - return; - if (!put_status_int (snd_installed_cards[i].config.dma2, 10)) + put_status("Kernel: "); + put_status(system_utsname.sysname); + put_status(" "); + put_status(system_utsname.nodename); + put_status(" "); + put_status(system_utsname.release); + put_status(" "); + put_status(system_utsname.version); + put_status(" "); + put_status(system_utsname.machine); + put_status("\n"); + + + if (!put_status("Config options: ")) + return; + if (!put_status_int(SELECTED_SOUND_OPTIONS, 16)) + return; + + if (!put_status("\n\nInstalled drivers: \n")) + return; + + for (i = 0; i < num_sound_drivers; i++) + if (sound_drivers[i].card_type != 0) + { + if (!put_status("Type ")) + return; + if (!put_status_int(sound_drivers[i].card_type, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(sound_drivers[i].name)) + return; + + if (!put_status("\n")) + return; + } + if (!put_status("\nCard config: \n")) + return; + + for (i = 0; i < num_sound_cards; i++) + if (snd_installed_cards[i].card_type != 0) + { + int drv, tmp; + + if (!snd_installed_cards[i].enabled) + if (!put_status("(")) + return; + + /* + * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return; + * if (!put_status (": ")) return; + */ + + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1) + if (!put_status(sound_drivers[drv].name)) + return; + + if (snd_installed_cards[i].config.io_base) + { + if (!put_status(" at 0x")) + return; + if (!put_status_int(snd_installed_cards[i].config.io_base, 16)) + return; + } + tmp = snd_installed_cards[i].config.irq; + if (tmp != 0) + { + if (!put_status(" irq ")) + return; + if (tmp < 0) + tmp = -tmp; + if (!put_status_int(tmp, 10)) + return; + } + if (snd_installed_cards[i].config.dma != -1) + { + if (!put_status(" drq ")) + return; + if (!put_status_int(snd_installed_cards[i].config.dma, 10)) + return; + if (snd_installed_cards[i].config.dma2 != -1) + { + if (!put_status(",")) + return; + if (!put_status_int(snd_installed_cards[i].config.dma2, 10)) + return; + } + } + if (!snd_installed_cards[i].enabled) + if (!put_status(")")) + return; + + if (!put_status("\n")) + return; + } + if (!sound_started) + { + put_status("\n\n***** Sound driver not started *****\n\n"); return; - } } - - if (!snd_installed_cards[i].enabled) - if (!put_status (")")) - return; - - if (!put_status ("\n")) - return; - } - - if (!sound_started) - { - put_status ("\n\n***** Sound driver not started *****\n\n"); - return; - } - #ifndef CONFIG_AUDIO - if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n")) - return; + if (!put_status("\nAudio devices: NOT ENABLED IN CONFIG\n")) + return; #else - if (!put_status ("\nAudio devices:\n")) - return; + if (!put_status("\nAudio devices:\n")) + return; - for (i = 0; i < num_audiodevs; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (audio_devs[i]->name)) - return; - - if (audio_devs[i]->flags & DMA_DUPLEX) - if (!put_status (" (DUPLEX)")) - return; - - if (!put_status ("\n")) - return; - } + for (i = 0; i < num_audiodevs; i++) + { + if (audio_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(audio_devs[i]->name)) + return; + + if (audio_devs[i]->flags & DMA_DUPLEX) + if (!put_status(" (DUPLEX)")) + return; + + if (!put_status("\n")) + return; + } #endif #ifndef CONFIG_SEQUENCER - if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n")) - return; + if (!put_status("\nSynth devices: NOT ENABLED IN CONFIG\n")) + return; #else - if (!put_status ("\nSynth devices:\n")) - return; + if (!put_status("\nSynth devices:\n")) + return; - for (i = 0; i < num_synths; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (synth_devs[i]->info->name)) - return; - if (!put_status ("\n")) - return; - } + for (i = 0; i < num_synths; i++) + { + if (synth_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(synth_devs[i]->info->name)) + return; + if (!put_status("\n")) + return; + } #endif #ifndef CONFIG_MIDI - if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n")) - return; + if (!put_status("\nMidi devices: NOT ENABLED IN CONFIG\n")) + return; #else - if (!put_status ("\nMidi devices:\n")) - return; + if (!put_status("\nMidi devices:\n")) + return; - for (i = 0; i < num_midis; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (midi_devs[i]->info.name)) - return; - if (!put_status ("\n")) - return; - } + for (i = 0; i < num_midis; i++) + { + if (midi_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(midi_devs[i]->info.name)) + return; + if (!put_status("\n")) + return; + } #endif #ifdef CONFIG_SEQUENCER - if (!put_status ("\nTimers:\n")) - return; + if (!put_status("\nTimers:\n")) + return; - for (i = 0; i < num_sound_timers; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (sound_timer_devs[i]->info.name)) - return; - if (!put_status ("\n")) - return; - } -#endif - - if (!put_status ("\nMixers:\n")) - return; - - for (i = 0; i < num_mixers; i++) - { - if (!put_status_int (i, 10)) - return; - if (!put_status (": ")) - return; - if (!put_status (mixer_devs[i]->name)) - return; - if (!put_status ("\n")) - return; - } + for (i = 0; i < num_sound_timers; i++) + { + if (sound_timer_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(sound_timer_devs[i]->info.name)) + return; + if (!put_status("\n")) + return; + } +#endif + + if (!put_status("\nMixers:\n")) + return; + + for (i = 0; i < num_mixers; i++) + { + if (mixer_devs[i] == NULL) + continue; + if (!put_status_int(i, 10)) + return; + if (!put_status(": ")) + return; + if (!put_status(mixer_devs[i]->name)) + return; + if (!put_status("\n")) + return; + } } static int -read_status (char *buf, int count) +read_status(char *buf, int count) { - /* - * Return at most 'count' bytes from the status_buf. - */ - int l, c; + /* + * Return at most 'count' bytes from the status_buf. + */ + int l, c; - l = count; - c = status_len - status_ptr; + l = count; + c = status_len - status_ptr; - if (l > c) - l = c; - if (l <= 0) - return 0; + if (l > c) + l = c; + if (l <= 0) + return 0; - { - char *fixit = &status_buf[status_ptr]; + { + char *fixit = &status_buf[status_ptr]; - copy_to_user (&(buf)[0], fixit, l); - }; - status_ptr += l; + copy_to_user(&(buf)[0], fixit, l); + }; + status_ptr += l; - return l; + return l; } int -sound_read_sw (int dev, struct fileinfo *file, char *buf, int count) +sound_read_sw(int dev, struct fileinfo *file, char *buf, int count) { - DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count)); + DEB(printk("sound_read_sw(dev=%d, count=%d)\n", dev, count)); - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - return read_status (buf, count); - break; + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return read_status(buf, count); + break; #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return audio_read (dev, file, buf, count); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_read(dev, file, buf, count); + break; #endif #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_read (dev, file, buf, count); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_read(dev, file, buf, count); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_read (dev, file, buf, count); + case SND_DEV_MIDIN: + return MIDIbuf_read(dev, file, buf, count); #endif - default:; - } + default:; + } - return -EINVAL; + return -EINVAL; } int -sound_write_sw (int dev, struct fileinfo *file, const char *buf, int count) +sound_write_sw(int dev, struct fileinfo *file, const char *buf, int count) { - DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count)); + DEB(printk("sound_write_sw(dev=%d, count=%d)\n", dev, count)); - switch (dev & 0x0f) - { + switch (dev & 0x0f) + { #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_write (dev, file, buf, count); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_write(dev, file, buf, count); + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return audio_write (dev, file, buf, count); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_write(dev, file, buf, count); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_write (dev, file, buf, count); + case SND_DEV_MIDIN: + return MIDIbuf_write(dev, file, buf, count); #endif - } + } - return -EINVAL; + return -EINVAL; } int -sound_open_sw (int dev, struct fileinfo *file) +sound_open_sw(int dev, struct fileinfo *file) { - int retval; + int retval; - DEB (printk ("sound_open_sw(dev=%d)\n", dev)); + DEB(printk("sound_open_sw(dev=%d)\n", dev)); - if ((dev >= SND_NDEVS) || (dev < 0)) - { - printk ("Invalid minor device %d\n", dev); - return -ENXIO; - } - - - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - if (status_busy) - return -EBUSY; - status_busy = 1; - if ((status_buf = (char *) vmalloc (4000)) == NULL) - { - status_busy = 0; - return -EIO; - } - status_len = status_ptr = 0; - init_status (); - break; - - case SND_DEV_CTL: - if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) - return -ENXIO; - return 0; - break; + if ((dev >= SND_NDEVS) || (dev < 0)) + { + printk("Invalid minor device %d\n", dev); + return -ENXIO; + } + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_busy) + return -EBUSY; + status_busy = 1; + if ((status_buf = (char *) vmalloc(4000)) == NULL) + { + status_busy = 0; + return -EIO; + } + status_len = status_ptr = 0; + init_status(); + break; + + case SND_DEV_CTL: + if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) + return -ENXIO; + return 0; + break; #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - if ((retval = sequencer_open (dev, file)) < 0) - return retval; - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + if ((retval = sequencer_open(dev, file)) < 0) + return retval; + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - if ((retval = MIDIbuf_open (dev, file)) < 0) - return retval; - break; + case SND_DEV_MIDIN: + if ((retval = MIDIbuf_open(dev, file)) < 0) + return retval; + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - if ((retval = audio_open (dev, file)) < 0) - return retval; - break; -#endif - - default: - printk ("Invalid minor device %d\n", dev); - return -ENXIO; - } + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + if ((retval = audio_open(dev, file)) < 0) + return retval; + break; +#endif + + default: + printk("Invalid minor device %d\n", dev); + return -ENXIO; + } - in_use++; + in_use++; - return 0; + return 0; } void -sound_release_sw (int dev, struct fileinfo *file) +sound_release_sw(int dev, struct fileinfo *file) { - DEB (printk ("sound_release_sw(dev=%d)\n", dev)); + DEB(printk("sound_release_sw(dev=%d)\n", dev)); - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - if (status_buf) - vfree (status_buf); - status_buf = NULL; - status_busy = 0; - break; + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_buf) + vfree(status_buf); + status_buf = NULL; + status_busy = 0; + break; - case SND_DEV_CTL: - break; + case SND_DEV_CTL: + break; #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - sequencer_release (dev, file); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + sequencer_release(dev, file); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - MIDIbuf_release (dev, file); - break; + case SND_DEV_MIDIN: + MIDIbuf_release(dev, file); + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - audio_release (dev, file); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + audio_release(dev, file); + break; #endif - default: - printk ("Sound error: Releasing unknown device 0x%02x\n", dev); - } - in_use--; + default: + printk("Sound error: Releasing unknown device 0x%02x\n", dev); + } + in_use--; } static int -get_mixer_info (int dev, caddr_t arg) +get_mixer_info(int dev, caddr_t arg) { - mixer_info info; - int i; + mixer_info info; + int i; - if (dev < 0 || dev >= num_mixers) - return -ENXIO; + if (dev < 0 || dev >= num_mixers) + return -ENXIO; - strcpy (info.id, mixer_devs[dev]->id); - for (i = 0; i < 32 && mixer_devs[dev]->name; i++) - info.name[i] = mixer_devs[dev]->name[i]; - info.name[i] = 0; - info.modify_counter = mixer_devs[dev]->modify_counter; + strcpy(info.id, mixer_devs[dev]->id); + for (i = 0; i < 32 && mixer_devs[dev]->name; i++) + info.name[i] = mixer_devs[dev]->name[i]; + info.name[i] = 0; + info.modify_counter = mixer_devs[dev]->modify_counter; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; } static int -get_old_mixer_info (int dev, caddr_t arg) +get_old_mixer_info(int dev, caddr_t arg) { - _old_mixer_info info; - int i; + _old_mixer_info info; + int i; - if (dev < 0 || dev >= num_mixers) - return -ENXIO; + if (dev < 0 || dev >= num_mixers) + return -ENXIO; - strcpy (info.id, mixer_devs[dev]->id); - for (i = 0; i < 32 && mixer_devs[dev]->name; i++) - info.name[i] = mixer_devs[dev]->name[i]; - info.name[i] = 0; + strcpy(info.id, mixer_devs[dev]->id); + for (i = 0; i < 32 && mixer_devs[dev]->name; i++) + info.name[i] = mixer_devs[dev]->name[i]; + info.name[i] = 0; - memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - return 0; + memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info)); + return 0; } static int -sound_mixer_ioctl (int mixdev, - unsigned int cmd, caddr_t arg) +sound_mixer_ioctl(int mixdev, + unsigned int cmd, caddr_t arg) { - if (cmd == SOUND_MIXER_INFO) - return get_mixer_info (mixdev, arg); - if (cmd == SOUND_OLD_MIXER_INFO) - return get_old_mixer_info (mixdev, arg); + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info(mixdev, arg); + if (cmd == SOUND_OLD_MIXER_INFO) + return get_old_mixer_info(mixdev, arg); - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - mixer_devs[mixdev]->modify_counter++; + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + mixer_devs[mixdev]->modify_counter++; - return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); + return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); } int -sound_ioctl_sw (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +sound_ioctl_sw(int dev, struct fileinfo *file, + unsigned int cmd, caddr_t arg) { - DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); + DEB(printk("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - if (cmd == OSS_GETVERSION) - return (*(int *) arg = SOUND_VERSION); + if (cmd == OSS_GETVERSION) + return (*(int *) arg = SOUND_VERSION); - if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ - if ((dev & 0x0f) != SND_DEV_CTL) - { - int dtype = dev & 0x0f; - int mixdev; + if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ + if ((dev & 0x0f) != SND_DEV_CTL) + { + int dtype = dev & 0x0f; + int mixdev; - switch (dtype) - { + switch (dtype) + { #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - mixdev = audio_devs[dev >> 4]->mixer_dev; - if (mixdev < 0 || mixdev >= num_mixers) - return -ENXIO; - return sound_mixer_ioctl (mixdev, cmd, arg); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + mixdev = audio_devs[dev >> 4]->mixer_dev; + if (mixdev < 0 || mixdev >= num_mixers) + return -ENXIO; + return sound_mixer_ioctl(mixdev, cmd, arg); + break; #endif - default: - return sound_mixer_ioctl (dev, cmd, arg); - } - } - - switch (dev & 0x0f) - { - - case SND_DEV_CTL: - if (cmd == SOUND_MIXER_GETLEVELS) - return get_mixer_levels (arg); - if (cmd == SOUND_MIXER_SETLEVELS) - return set_mixer_levels (arg); + default: + return sound_mixer_ioctl(dev, cmd, arg); + } + } + switch (dev & 0x0f) + { - if (!num_mixers) - return -ENXIO; + case SND_DEV_CTL: + if (cmd == SOUND_MIXER_GETLEVELS) + return get_mixer_levels(arg); + if (cmd == SOUND_MIXER_SETLEVELS) + return set_mixer_levels(arg); + + if (!num_mixers) + return -ENXIO; - dev = dev >> 4; + dev = dev >> 4; - if (dev >= num_mixers) - return -ENXIO; + if (dev >= num_mixers) + return -ENXIO; - return sound_mixer_ioctl (dev, cmd, arg); - break; + return sound_mixer_ioctl(dev, cmd, arg); + break; #ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_ioctl (dev, file, cmd, arg); - break; + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_ioctl(dev, file, cmd, arg); + break; #endif #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return audio_ioctl (dev, file, cmd, arg); - break; + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_ioctl(dev, file, cmd, arg); + break; #endif #ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_ioctl (dev, file, cmd, arg); - break; + case SND_DEV_MIDIN: + return MIDIbuf_ioctl(dev, file, cmd, arg); + break; #endif - } + } - return -EINVAL; + return -EINVAL; } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.1.66/linux/drivers/sound/sound_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/sound_syms.c Sat Nov 29 10:33:21 1997 @@ -0,0 +1,78 @@ +/* + * The sound core exports the following symbols to the rest of + * modulespace. + * + * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL + */ + +#include +#include +#include "sound_config.h" +#define _MIDI_SYNTH_C_ +#include "midi_synth.h" +#include +#include "sound_firmware.h" + +extern struct notifier_block *sound_locker; + +EXPORT_SYMBOL(mixer_devs); +EXPORT_SYMBOL(audio_devs); +EXPORT_SYMBOL(num_audiodevs); + +EXPORT_SYMBOL(note_to_freq); +EXPORT_SYMBOL(compute_finetune); +EXPORT_SYMBOL(seq_copy_to_input); +EXPORT_SYMBOL(sequencer_timer); + +EXPORT_SYMBOL(sound_install_audiodrv); +EXPORT_SYMBOL(sound_install_mixer); +EXPORT_SYMBOL(sound_alloc_dma); +EXPORT_SYMBOL(sound_free_dma); +EXPORT_SYMBOL(snd_set_irq_handler); +EXPORT_SYMBOL(snd_release_irq); +EXPORT_SYMBOL(sound_alloc_audiodev); +EXPORT_SYMBOL(sound_alloc_mididev); +EXPORT_SYMBOL(sound_alloc_mixerdev); +EXPORT_SYMBOL(sound_alloc_timerdev); +EXPORT_SYMBOL(sound_alloc_synthdev); +EXPORT_SYMBOL(sound_unload_audiodev); +EXPORT_SYMBOL(sound_unload_mididev); +EXPORT_SYMBOL(sound_unload_mixerdev); +EXPORT_SYMBOL(sound_unload_timerdev); +EXPORT_SYMBOL(sound_unload_synthdev); + +EXPORT_SYMBOL(DMAbuf_start_dma); +EXPORT_SYMBOL(DMAbuf_inputintr); +EXPORT_SYMBOL(DMAbuf_outputintr); +EXPORT_SYMBOL(dma_ioctl); + +EXPORT_SYMBOL(conf_printf2); + +EXPORT_SYMBOL(sound_timer_init); +EXPORT_SYMBOL(sound_timer_interrupt); +EXPORT_SYMBOL(sound_timer_syncinterval); + +/* Locking */ +EXPORT_SYMBOL(sound_locker); + +/* MIDI symbols */ +EXPORT_SYMBOL(midi_devs); +EXPORT_SYMBOL(num_midis); +EXPORT_SYMBOL(synth_devs); +EXPORT_SYMBOL(num_synths); + +EXPORT_SYMBOL(do_midi_msg); +EXPORT_SYMBOL(midi_synth_open); +EXPORT_SYMBOL(midi_synth_close); +EXPORT_SYMBOL(midi_synth_ioctl); +EXPORT_SYMBOL(midi_synth_kill_note); +EXPORT_SYMBOL(midi_synth_start_note); +EXPORT_SYMBOL(midi_synth_set_instr); +EXPORT_SYMBOL(midi_synth_reset); +EXPORT_SYMBOL(midi_synth_hw_control); +EXPORT_SYMBOL(midi_synth_aftertouch); +EXPORT_SYMBOL(midi_synth_controller); +EXPORT_SYMBOL(midi_synth_panning); +EXPORT_SYMBOL(midi_synth_setup_voice); +EXPORT_SYMBOL(midi_synth_send_sysex); +EXPORT_SYMBOL(midi_synth_bender); diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.1.66/linux/drivers/sound/sound_timer.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sound_timer.c Sat Nov 29 10:33:21 1997 @@ -1,3 +1,5 @@ + + /* * sound/sound_timer.c */ @@ -13,7 +15,7 @@ #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) +#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) static volatile int initialized = 0, opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; @@ -27,320 +29,315 @@ static struct sound_lowlev_timer *tmr = NULL; static unsigned long -tmr2ticks (int tmr_value) +tmr2ticks(int tmr_value) { - /* - * Convert timer ticks to MIDI ticks - */ + /* + * Convert timer ticks to MIDI ticks + */ - unsigned long tmp; - unsigned long scale; + unsigned long tmp; + unsigned long scale; - tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ + tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ - scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ + scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ - return (tmp + (scale / 2)) / scale; + return (tmp + (scale / 2)) / scale; } static void -reprogram_timer (void) +reprogram_timer(void) { - unsigned long usecs_per_tick; + unsigned long usecs_per_tick; - usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); + usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); - /* - * Don't kill the system by setting too high timer rate - */ - if (usecs_per_tick < 2000) - usecs_per_tick = 2000; + /* + * Don't kill the system by setting too high timer rate + */ + if (usecs_per_tick < 2000) + usecs_per_tick = 2000; - usecs_per_tmr = tmr->tmr_start (tmr->dev, usecs_per_tick); + usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick); } void -sound_timer_syncinterval (unsigned int new_usecs) +sound_timer_syncinterval(unsigned int new_usecs) { /* * This routine is called by the hardware level if * the clock frequency has changed for some reason. */ - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; - usecs_per_tmr = new_usecs; + usecs_per_tmr = new_usecs; } static void -tmr_reset (void) +tmr_reset(void) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - restore_flags (flags); + save_flags(flags); + cli(); + tmr_offs = 0; + ticks_offs = 0; + tmr_ctr = 0; + next_event_time = (unsigned long) -1; + prev_event_time = 0; + curr_ticks = 0; + restore_flags(flags); } static int -timer_open (int dev, int mode) +timer_open(int dev, int mode) { - if (opened) - return -EBUSY; + if (opened) + return -EBUSY; - tmr_reset (); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - reprogram_timer (); + tmr_reset(); + curr_tempo = 60; + curr_timebase = 100; + opened = 1; + reprogram_timer(); - return 0; + return 0; } static void -timer_close (int dev) +timer_close(int dev) { - opened = tmr_running = 0; - tmr->tmr_disable (tmr->dev); + opened = tmr_running = 0; + tmr->tmr_disable(tmr->dev); } static int -timer_event (int dev, unsigned char *event) +timer_event(int dev, unsigned char *event) { - unsigned char cmd = event[1]; - unsigned long parm = *(int *) &event[4]; + unsigned char cmd = event[1]; + unsigned long parm = *(int *) &event[4]; - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - tmr_reset (); - tmr_running = 1; - reprogram_timer (); - break; - - case TMR_STOP: - tmr_running = 0; - break; - - case TMR_CONTINUE: - tmr_running = 1; - reprogram_timer (); - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 250) - parm = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = parm; - reprogram_timer (); - } - break; - - case TMR_ECHO: - seq_copy_to_input (event, 8); - break; + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + tmr_reset(); + tmr_running = 1; + reprogram_timer(); + break; + + case TMR_STOP: + tmr_running = 0; + break; + + case TMR_CONTINUE: + tmr_running = 1; + reprogram_timer(); + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = parm; + reprogram_timer(); + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; - default:; - } + default:; + } - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static unsigned long -timer_get_time (int dev) +timer_get_time(int dev) { - if (!opened) - return 0; + if (!opened) + return 0; - return curr_ticks; + return curr_ticks; } static int -timer_ioctl (int dev, - unsigned int cmd, caddr_t arg) +timer_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - int val; - - switch (cmd) - { - case SNDCTL_TMR_SOURCE: - return (*(int *) arg = TMR_INTERNAL); - break; - - case SNDCTL_TMR_START: - tmr_reset (); - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - val = *(int *) arg; - - if (val) - { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - - return (*(int *) arg = curr_timebase); - break; - - case SNDCTL_TMR_TEMPO: - val = *(int *) arg; - - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = val; - reprogram_timer (); - } + int val; - return (*(int *) arg = curr_tempo); - break; + switch (cmd) + { + case SNDCTL_TMR_SOURCE: + return (*(int *) arg = TMR_INTERNAL); + break; + + case SNDCTL_TMR_START: + tmr_reset(); + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + val = *(int *) arg; + + if (val) + { + if (val < 1) + val = 1; + if (val > 1000) + val = 1000; + curr_timebase = val; + } + return (*(int *) arg = curr_timebase); + break; + + case SNDCTL_TMR_TEMPO: + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = val; + reprogram_timer(); + } + return (*(int *) arg = curr_tempo); + break; + + case SNDCTL_SEQ_CTRLRATE: + val = *(int *) arg; + + if (val != 0) /* Can't change */ + return -EINVAL; + + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + break; + + case SNDCTL_TMR_METRONOME: + /* NOP */ + break; - case SNDCTL_SEQ_CTRLRATE: - val = *(int *) arg; + default:; + } - if (val != 0) /* Can't change */ return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - - default:; - } - - return -EINVAL; } static void -timer_arm (int dev, long time) +timer_arm(int dev, long time) { - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; - next_event_time = prev_event_time = time; + next_event_time = prev_event_time = time; - return; + return; } static struct sound_timer_operations sound_timer = { - {"Sound Timer", 0}, - 1, /* Priority */ - 0, /* Local device link */ - timer_open, - timer_close, - timer_event, - timer_get_time, - timer_ioctl, - timer_arm + {"Sound Timer", 0}, + 1, /* Priority */ + 0, /* Local device link */ + timer_open, + timer_close, + timer_event, + timer_get_time, + timer_ioctl, + timer_arm }; void -sound_timer_interrupt (void) +sound_timer_interrupt(void) { - if (!opened) - return; + if (!opened) + return; - tmr->tmr_restart (tmr->dev); + tmr->tmr_restart(tmr->dev); - if (!tmr_running) - return; + if (!tmr_running) + return; - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks (tmr_ctr); + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer (0); - } + if (curr_ticks >= next_event_time) + { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } } -void -sound_timer_init (struct sound_lowlev_timer *t, char *name) +void +sound_timer_init(struct sound_lowlev_timer *t, char *name) { - int n; - - if (initialized) - { - if (t->priority <= tmr->priority) - return; /* There is already a similar or better timer */ - tmr = t; - return; - } - initialized = 1; - - tmr = t; + int n; - if (num_sound_timers >= MAX_TIMER_DEV) - n = 0; /* Overwrite the system timer */ - else - n = num_sound_timers++; + if (initialized) + { + if (t->priority <= tmr->priority) + return; /* There is already a similar or better timer */ + tmr = t; + return; + } + initialized = 1; - strcpy (sound_timer.info.name, name); + tmr = t; - sound_timer_devs[n] = &sound_timer; + n = sound_alloc_timerdev(); + if (n == -1) + n = 0; /* Overwrite the system timer */ + strcpy(sound_timer.info.name, name); + sound_timer_devs[n] = &sound_timer; } #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.66/linux/drivers/sound/soundcard.c Tue Nov 18 17:22:07 1997 +++ linux/drivers/sound/soundcard.c Sat Nov 29 10:33:21 1997 @@ -25,11 +25,19 @@ #include #include #include -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ #include -#include +#define SOUND_CORE + +#include "soundmodule.h" +#include +#ifdef MODULE +#define modular 1 +#else +#define modular 0 +#endif static int chrdev_registered = 0; static int sound_major = SOUND_MAJOR; @@ -56,298 +64,270 @@ -static ssize_t -sound_read (struct file *file, char *buf, size_t count, loff_t *ppos) +static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - int dev; - struct inode *inode = file->f_dentry->d_inode; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - return (ssize_t)sound_read_sw (dev, &files[dev], buf, count); + return sound_read_sw(dev, &files[dev], buf, count); } -static ssize_t -sound_write (struct file *file, const char *buf, size_t count, loff_t *ppos) +static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int dev; - struct inode *inode = file->f_dentry->d_inode; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - return (ssize_t)sound_write_sw (dev, &files[dev], buf, count); + return sound_write_sw(dev, &files[dev], buf, count); } -static long long -sound_lseek (struct file *file, long long offset, int orig) +static long long sound_lseek(struct file *file, long long offset, int orig) { - return -EPERM; + return -ESPIPE; } -static int -sound_open (struct inode *inode, struct file *file) +static int sound_open(struct inode *inode, struct file *file) { - int dev, retval; - struct fileinfo tmp_file; - - if (is_unloading) - { - printk ("Sound: Driver partially removed. Can't open device\n"); - return -EBUSY; - } - - dev = MINOR (inode->i_rdev); + int dev, retval; + struct fileinfo tmp_file; - if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) - { - printk ("SoundCard Error: The soundcard system has not been configured\n"); - return -ENXIO; - } + if (is_unloading) + { +/* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/ + return -EBUSY; + } + dev = MINOR(inode->i_rdev); - tmp_file.mode = 0; - tmp_file.flags = file->f_flags; + if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) + { +/* printk("SoundCard Error: The soundcard system has not been configured\n");*/ + return -ENXIO; + } + tmp_file.mode = 0; + tmp_file.flags = file->f_flags; - if ((tmp_file.flags & O_ACCMODE) == O_RDWR) - tmp_file.mode = OPEN_READWRITE; - if ((tmp_file.flags & O_ACCMODE) == O_RDONLY) - tmp_file.mode = OPEN_READ; - if ((tmp_file.flags & O_ACCMODE) == O_WRONLY) - tmp_file.mode = OPEN_WRITE; + if ((tmp_file.flags & O_ACCMODE) == O_RDWR) + tmp_file.mode = OPEN_READWRITE; + if ((tmp_file.flags & O_ACCMODE) == O_RDONLY) + tmp_file.mode = OPEN_READ; + if ((tmp_file.flags & O_ACCMODE) == O_WRONLY) + tmp_file.mode = OPEN_WRITE; - if ((retval = sound_open_sw (dev, &tmp_file)) < 0) - return retval; + if ((retval = sound_open_sw(dev, &tmp_file)) < 0) + return retval; #ifdef MODULE - MOD_INC_USE_COUNT; + SOUND_INC_USE_COUNT; #endif - memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file)); - return retval; + memcpy((char *) &files[dev], (char *) &tmp_file, sizeof(tmp_file)); + return retval; } -static int -sound_release (struct inode *inode, struct file *file) +static int sound_release(struct inode *inode, struct file *file) { - int dev; + int dev; - dev = MINOR (inode->i_rdev); + dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - sound_release_sw (dev, &files[dev]); + sound_release_sw(dev, &files[dev]); #ifdef MODULE - MOD_DEC_USE_COUNT; + SOUND_DEC_USE_COUNT; #endif - return 0; + return 0; } -static int -sound_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int sound_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - int dev, err; - int len = 0; - int alloced = 0; - char *ptr = (char *) arg; + int dev, err; + int len = 0; + int alloced = 0; + char *ptr = (char *) arg; - dev = MINOR (inode->i_rdev); + dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - if (_SIOC_DIR (cmd) != _SIOC_NONE && _SIOC_DIR (cmd) != 0) - { - /* - * Have to validate the address given by the process. - */ + if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) + { + /* + * Have to validate the address given by the process. + */ + + len = _SIOC_SIZE(cmd); + if (len < 1 || len > 65536 || arg == 0) + return -EFAULT; + + ptr = vmalloc(len); + alloced = 1; + if (ptr == NULL) + return -EFAULT; + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { + if ((err = verify_area(VERIFY_READ, (void *) arg, len)) < 0) + return err; + copy_from_user(ptr, (char *) arg, len); + } + if (_SIOC_DIR(cmd) & _SIOC_READ) + { + if ((err = verify_area(VERIFY_WRITE, (void *) arg, len)) < 0) + return err; + } + } + err = sound_ioctl_sw(dev, &files[dev], cmd, (caddr_t) ptr); - len = _SIOC_SIZE (cmd); - if (len < 1 || len > 65536 || arg == 0) - return -EFAULT; + if (_SIOC_DIR(cmd) & _SIOC_READ) + copy_to_user((char *) arg, ptr, len); - ptr = vmalloc (len); - alloced = 1; - if (ptr == NULL) - return -EFAULT; + if (ptr != NULL && alloced) + vfree(ptr); - if (_SIOC_DIR (cmd) & _SIOC_WRITE) - { - if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0) - return err; - copy_from_user (ptr, (char *) arg, len); - } + return ((err < 0) ? err : 0); +} + +static int sound_select(struct inode *inode, struct file *file, int sel_type, poll_table * wait) +{ + int dev; + + dev = MINOR(inode->i_rdev); - if (_SIOC_DIR (cmd) & _SIOC_READ) + files[dev].flags = file->f_flags; + + DEB(printk("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); + + switch (dev & 0x0f) { - if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0) - return err; - } +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_select(dev, &files[dev], sel_type, wait); + break; +#endif - } +#if defined(CONFIG_MIDI) + case SND_DEV_MIDIN: + return MIDIbuf_select(dev, &files[dev], sel_type, wait); + break; +#endif + +#if defined(CONFIG_AUDIO) || defined(MODULE) + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait); + break; +#endif + + default: + return 0; + } - err = sound_ioctl_sw (dev, &files[dev], cmd, (caddr_t) ptr); + return 0; +} - if (_SIOC_DIR (cmd) & _SIOC_READ) - { - copy_to_user ((char *) arg, ptr, len); - } +static unsigned int sound_poll(struct file *file, poll_table * wait) +{ + struct inode *inode; + int ret = 0; - if (ptr != NULL && alloced) - vfree (ptr); + inode = file->f_dentry->d_inode; - return ((err < 0) ? err : 0); + if (sound_select(inode, file, SEL_IN, wait)) + ret |= POLLIN; + if (sound_select(inode, file, SEL_OUT, wait)) + ret |= POLLOUT; + return ret; } -static int -sound_select (struct inode *inode, struct file *file, int sel_type, poll_table * wait) +static int sound_mmap(struct file *file, struct vm_area_struct *vma) { - int dev; + int dev, dev_class; + unsigned long size; + struct dma_buffparms *dmap = NULL; - dev = MINOR (inode->i_rdev); + dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; + files[dev].flags = file->f_flags; - DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); + dev_class = dev & 0x0f; + dev >>= 4; - switch (dev & 0x0f) - { -#ifdef CONFIG_SEQUENCER - case SND_DEV_SEQ: - case SND_DEV_SEQ2: - return sequencer_select (dev, &files[dev], sel_type, wait); - break; -#endif + if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) + { +/* printk("Sound: mmap() not supported for other than audio devices\n");*/ + return -EINVAL; + } + if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ + dmap = audio_devs[dev]->dmap_out; + else if (vma->vm_flags & VM_READ) + dmap = audio_devs[dev]->dmap_in; + else + { +/* printk("Sound: Undefined mmap() access\n");*/ + return -EINVAL; + } -#ifdef CONFIG_MIDI - case SND_DEV_MIDIN: - return MIDIbuf_select (dev, &files[dev], sel_type, wait); - break; -#endif + if (dmap == NULL) + { +/* printk("Sound: mmap() error. dmap == NULL\n");*/ + return -EIO; + } + if (dmap->raw_buf == NULL) + { +/* printk("Sound: mmap() called when raw_buf == NULL\n");*/ + return -EIO; + } + if (dmap->mapping_flags) + { +/* printk("Sound: mmap() called twice for the same DMA buffer\n");*/ + return -EIO; + } + if (vma->vm_offset != 0) + { +/* printk("Sound: mmap() offset must be 0.\n");*/ + return -EINVAL; + } + size = vma->vm_end - vma->vm_start; -#ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - return DMAbuf_select (dev >> 4, &files[dev], sel_type, wait); - break; -#endif - - default: - return 0; - } - - return 0; -} - -static unsigned int -sound_poll (struct file *file, poll_table * wait) -{ - struct inode *inode; - int ret = 0; - - inode = file->f_dentry->d_inode; - - if (sound_select (inode, file, SEL_IN, wait)) - ret |= POLLIN; - if (sound_select (inode, file, SEL_OUT, wait)) - ret |= POLLOUT; - return ret; -} - -static int -sound_mmap (struct file *file, struct vm_area_struct *vma) -{ - int dev, dev_class; - unsigned long size; - struct dma_buffparms *dmap = NULL; - - dev = MINOR (file->f_dentry->d_inode->i_rdev); - - files[dev].flags = file->f_flags; - - dev_class = dev & 0x0f; - dev >>= 4; - - if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) - { - printk ("Sound: mmap() not supported for other than audio devices\n"); - return -EINVAL; - } - - if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ - { - dmap = audio_devs[dev]->dmap_out; - } - else if (vma->vm_flags & VM_READ) - { - dmap = audio_devs[dev]->dmap_in; - } - else - { - printk ("Sound: Undefined mmap() access\n"); - return -EINVAL; - } - - if (dmap == NULL) - { - printk ("Sound: mmap() error. dmap == NULL\n"); - return -EIO; - } - - if (dmap->raw_buf == NULL) - { - printk ("Sound: mmap() called when raw_buf == NULL\n"); - return -EIO; - } - - if (dmap->mapping_flags) - { - printk ("Sound: mmap() called twice for the same DMA buffer\n"); - return -EIO; - } - - if (vma->vm_offset != 0) - { - printk ("Sound: mmap() offset must be 0.\n"); - return -EINVAL; - } - - size = vma->vm_end - vma->vm_start; - - if (size != dmap->bytes_in_use) - { - printk ("Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); - } - - if (remap_page_range (vma->vm_start, virt_to_phys (dmap->raw_buf), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - vma->vm_dentry = dget(file->f_dentry); - - dmap->mapping_flags |= DMA_MAP_MAPPED; - - memset (dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); - return 0; + if (size != dmap->bytes_in_use) + { + printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); + } + if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + vma->vm_dentry = dget(file->f_dentry); + + dmap->mapping_flags |= DMA_MAP_MAPPED; + + memset(dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); + return 0; } static struct file_operations sound_fops = { - sound_lseek, - sound_read, - sound_write, - NULL, /* sound_readdir */ - sound_poll, - sound_ioctl, - sound_mmap, - sound_open, - sound_release + sound_lseek, + sound_read, + sound_write, + NULL, /* sound_readdir */ + sound_poll, + sound_ioctl, + sound_mmap, + sound_open, + sound_release }; #ifdef MODULE @@ -355,26 +335,28 @@ #else void #endif -soundcard_init (void) +soundcard_init(void) { #ifndef MODULE - register_chrdev (sound_major, "sound", &sound_fops); - chrdev_registered = 1; + register_chrdev(sound_major, "sound", &sound_fops); + chrdev_registered = 1; #endif - soundcard_configured = 1; + soundcard_configured = 1; - sndtable_init (); /* Initialize call tables and detect cards */ + sndtable_init(); /* Initialize call tables and detect cards */ - if (sndtable_get_cardcount () == 0) - return; /* No cards detected */ +#ifdef FIXME + if (sndtable_get_cardcount() == 0) + return; /* No cards detected */ +#endif -#ifdef CONFIG_AUDIO - if (num_audiodevs) /* Audio devices present */ - { - audio_init_devices (); - } +#if defined(CONFIG_AUDIO) + if (num_audiodevs || modular) /* Audio devices present */ + { + audio_init_devices(); + } #endif @@ -384,17 +366,19 @@ #ifdef MODULE static void -free_all_irqs (void) +free_all_irqs(void) { - int i; + int i; - for (i = 0; i < 31; i++) - if (irqs & (1ul << i)) - { - printk ("Sound warning: IRQ%d was left allocated - fixed.\n", i); - snd_release_irq (i); - } - irqs = 0; + for (i = 0; i < 31; i++) + { + if (irqs & (1ul << i)) + { + printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i); + snd_release_irq(i); + } + } + irqs = 0; } char kernel_version[] = UTS_RELEASE; @@ -406,277 +390,249 @@ static int sound[20] = {0}; -int -init_module (void) +int init_module(void) { - int err; - int ints[21]; - int i; - - if (0 < 0) - { - printk ("Sound: Incompatible kernel (wrapper) version\n"); - return -EINVAL; - } - - /* - * "sound=" command line handling by Harald Milz. - */ - i = 0; - while (i < 20 && sound[i]) - ints[i + 1] = sound[i++]; - ints[0] = i; - - if (i) - sound_setup ("sound=", ints); - - err = register_chrdev (sound_major, "sound", &sound_fops); - if (err) - { - printk ("sound: driver already loaded/included in kernel\n"); - return err; - } + int err; + int ints[21]; + int i; + + /* + * "sound=" command line handling by Harald Milz. + */ + i = 0; + while (i < 20 && sound[i]) + ints[i + 1] = sound[i++]; + ints[0] = i; - chrdev_registered = 1; - soundcard_init (); + if (i) + sound_setup("sound=", ints); - if (sound_nblocks >= 1024) - printk ("Sound warning: Deallocation table was too small.\n"); + err = register_chrdev(sound_major, "sound", &sound_fops); + if (err) + { + printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); + return err; + } + chrdev_registered = 1; + soundcard_init(); + + if (sound_nblocks >= 1024) + printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); - return 0; + return 0; } #ifdef MODULE -void -cleanup_module (void) +void cleanup_module(void) { - int i; - - if (MOD_IN_USE) - { - return; - } + int i; - if (chrdev_registered) - unregister_chrdev (sound_major, "sound"); + if (MOD_IN_USE) + { + return; + } + if (chrdev_registered) + unregister_chrdev(sound_major, "sound"); -#ifdef CONFIG_SEQUENCER - sound_stop_timer (); +#if defined(CONFIG_SEQUENCER) || defined(MODULE) + sound_stop_timer(); #endif #ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_unload_lowlevel_drivers (void); + { + extern void sound_unload_lowlevel_drivers(void); - sound_unload_lowlevel_drivers (); - } + sound_unload_lowlevel_drivers(); + } #endif - sound_unload_drivers (); - - free_all_irqs (); /* If something was left allocated by accident */ + sound_unload_drivers(); - for (i = 0; i < 8; i++) - if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) - { - printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i); - sound_free_dma (i); - } + free_all_irqs(); /* If something was left allocated by accident */ - - for (i = 0; i < sound_nblocks; i++) - { - vfree (sound_mem_blocks[i]); - } + for (i = 0; i < 8; i++) + { + if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) + { + printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i); + sound_free_dma(i); + } + } + for (i = 0; i < sound_nblocks; i++) + { + vfree(sound_mem_blocks[i]); + } } #endif -void -tenmicrosec (int *osp) +void tenmicrosec(int *osp) { - udelay (10); + udelay(10); } -int -snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) +int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) { - int retcode; - unsigned long flags; + int retcode; + unsigned long flags; - save_flags (flags); - cli (); - retcode = request_irq (interrupt_level, iproc, 0, name, NULL); - if (retcode < 0) - { - printk ("Sound: IRQ%d already in use\n", interrupt_level); - } - else - irqs |= (1ul << interrupt_level); + save_flags(flags); + cli(); + retcode = request_irq(interrupt_level, iproc, 0, name, NULL); + + if (retcode < 0) + { + printk(KERN_ERR "Sound: IRQ%d already in use\n", interrupt_level); + } + else + irqs |= (1ul << interrupt_level); - restore_flags (flags); - return retcode; + restore_flags(flags); + return retcode; } -void -snd_release_irq (int vect) +void snd_release_irq(int vect) { - if (!(irqs & (1ul << vect))) - return; + if (!(irqs & (1ul << vect))) + return; - irqs &= ~(1ul << vect); - free_irq (vect, NULL); + irqs &= ~(1ul << vect); + free_irq(vect, NULL); } -int -sound_alloc_dma (int chn, char *deviceID) +int sound_alloc_dma(int chn, char *deviceID) { - int err; + int err; - if ((err = request_dma (chn, deviceID)) != 0) - return err; + if ((err = request_dma(chn, deviceID)) != 0) + return err; - dma_alloc_map[chn] = DMA_MAP_FREE; + dma_alloc_map[chn] = DMA_MAP_FREE; - return 0; + return 0; } -int -sound_open_dma (int chn, char *deviceID) +int sound_open_dma(int chn, char *deviceID) { - unsigned long flags; + unsigned long flags; + + if (chn < 0 || chn > 7 || chn == 4) + { + printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); + return 1; + } + save_flags(flags); + cli(); - if (chn < 0 || chn > 7 || chn == 4) - { - printk ("sound_open_dma: Invalid DMA channel %d\n", chn); - return 1; - } - - save_flags (flags); - cli (); - - if (dma_alloc_map[chn] != DMA_MAP_FREE) - { - printk ("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); - restore_flags (flags); - return 1; - } - - dma_alloc_map[chn] = DMA_MAP_BUSY; - restore_flags (flags); - return 0; + if (dma_alloc_map[chn] != DMA_MAP_FREE) + { + printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); + restore_flags(flags); + return 1; + } + dma_alloc_map[chn] = DMA_MAP_BUSY; + restore_flags(flags); + return 0; } -void -sound_free_dma (int chn) +void sound_free_dma(int chn) { - if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) - { - /* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */ - return; - } - free_dma (chn); - dma_alloc_map[chn] = DMA_MAP_UNAVAIL; + if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) + { + /* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */ + return; + } + free_dma(chn); + dma_alloc_map[chn] = DMA_MAP_UNAVAIL; } -void -sound_close_dma (int chn) +void sound_close_dma(int chn) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - if (dma_alloc_map[chn] != DMA_MAP_BUSY) - { - printk ("sound_close_dma: Bad access to DMA channel %d\n", chn); - restore_flags (flags); - return; - } - dma_alloc_map[chn] = DMA_MAP_FREE; - restore_flags (flags); + if (dma_alloc_map[chn] != DMA_MAP_BUSY) + { + printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); + restore_flags(flags); + return; + } + dma_alloc_map[chn] = DMA_MAP_FREE; + restore_flags(flags); } -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) -static void -do_sequencer_timer (unsigned long dummy) +static void do_sequencer_timer(unsigned long dummy) { - sequencer_timer (0); + sequencer_timer(0); } static struct timer_list seq_timer = {NULL, NULL, 0, 0, do_sequencer_timer}; -void -request_sound_timer (int count) +void request_sound_timer(int count) { - extern unsigned long seq_time; - - if (count < 0) - { + extern unsigned long seq_time; - { - seq_timer.expires = (-count) + jiffies; - add_timer (&seq_timer); - }; - return; - } - - count += seq_time; - - count -= jiffies; + if (count < 0) + { + seq_timer.expires = (-count) + jiffies; + add_timer(&seq_timer); + return; + } + count += seq_time; - if (count < 1) - count = 1; + count -= jiffies; + if (count < 1) + count = 1; - { - seq_timer.expires = (count) + jiffies; - add_timer (&seq_timer); - }; + seq_timer.expires = (count) + jiffies; + add_timer(&seq_timer); } -void -sound_stop_timer (void) +void sound_stop_timer(void) { - del_timer (&seq_timer);; + del_timer(&seq_timer);; } #endif #ifdef CONFIG_AUDIO -static int dma_buffsize = DSP_BUFFSIZE; +static int dma_buffsize = DSP_BUFFSIZE; int -sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) +sound_alloc_dmap(int dev, struct dma_buffparms *dmap, int chan) { - char *start_addr, *end_addr; - int i, dma_pagesize; + char *start_addr, *end_addr; + int i, dma_pagesize; - dmap->mapping_flags &= ~DMA_MAP_MAPPED; + dmap->mapping_flags &= ~DMA_MAP_MAPPED; - if (dmap->raw_buf != NULL) - return 0; /* Already done */ + if (dmap->raw_buf != NULL) + return 0; /* Already done */ - if (dma_buffsize < 4096) - dma_buffsize = 4096; + if (dma_buffsize < 4096) + dma_buffsize = 4096; - if (chan < 4) - dma_pagesize = 64 * 1024; - else - dma_pagesize = 128 * 1024; + if (chan < 4) + dma_pagesize = 64 * 1024; + else + dma_pagesize = 128 * 1024; - dmap->raw_buf = NULL; + dmap->raw_buf = NULL; - dmap->buffsize = dma_buffsize; + dmap->buffsize = dma_buffsize; - if (dmap->buffsize > dma_pagesize) - dmap->buffsize = dma_pagesize; + if (dmap->buffsize > dma_pagesize) + dmap->buffsize = dma_pagesize; - start_addr = NULL; + start_addr = NULL; /* * Now loop until we get a free buffer. Try to get smaller buffer if @@ -684,147 +640,142 @@ * reasons. */ - while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) - { - int sz, size; - - for (sz = 0, size = PAGE_SIZE; - size < dmap->buffsize; - sz++, size <<= 1); - - dmap->buffsize = PAGE_SIZE * (1 << sz); - - if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL) - dmap->buffsize /= 2; - } - - if (start_addr == NULL) - { - printk ("Sound error: Couldn't allocate DMA buffer\n"); - return -ENOMEM; - } - else - { - /* make some checks */ - end_addr = start_addr + dmap->buffsize - 1; - - if (debugmem) - printk ("sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); - - /* now check if it fits into the same dma-pagesize */ - - if (((long) start_addr & ~(dma_pagesize - 1)) - != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) - { - printk ("sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); - return -EFAULT; - } - } - 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++) - { - set_bit (PG_reserved, &mem_map[i].flags);; - } + while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) + { + int sz, size; + + for (sz = 0, size = PAGE_SIZE; + size < dmap->buffsize; + sz++, size <<= 1); + + dmap->buffsize = PAGE_SIZE * (1 << sz); + + if ((start_addr = (char *) __get_free_pages(GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL) + dmap->buffsize /= 2; + } + + if (start_addr == NULL) + { + printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n"); + return -ENOMEM; + } + else + { + /* make some checks */ + end_addr = start_addr + dmap->buffsize - 1; + + if (debugmem) + printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); + + /* now check if it fits into the same dma-pagesize */ - return 0; + if (((long) start_addr & ~(dma_pagesize - 1)) + != ((long) end_addr & ~(dma_pagesize - 1)) + || end_addr >= (char *) (MAX_DMA_ADDRESS)) + { + printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); + return -EFAULT; + } + } + 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++) + { + set_bit(PG_reserved, &mem_map[i].flags);; + } + + return 0; } -void -sound_free_dmap (int dev, struct dma_buffparms *dmap, int chan) +void sound_free_dmap(int dev, struct dma_buffparms *dmap, int chan) { - int sz, size, i; - unsigned long start_addr, end_addr; + int sz, size, i; + unsigned long start_addr, end_addr; - if (dmap->raw_buf == NULL) - return; + if (dmap->raw_buf == NULL) + return; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return; /* Don't free mmapped buffer. Will use it next time */ + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return; /* Don't free mmapped buffer. Will use it next time */ - for (sz = 0, size = PAGE_SIZE; - size < dmap->buffsize; - sz++, size <<= 1); + for (sz = 0, size = PAGE_SIZE; + size < dmap->buffsize; + sz++, size <<= 1); - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + dmap->buffsize; + 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++) - { - clear_bit (PG_reserved, &mem_map[i].flags);; - } + 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); - dmap->raw_buf = NULL; + free_pages((unsigned long) dmap->raw_buf, sz); + dmap->raw_buf = NULL; } /* Intel version !!!!!!!!! */ -int -sound_start_dma (int dev, struct dma_buffparms *dmap, int chan, - unsigned long physaddr, - int count, int dma_mode, int autoinit) -{ - unsigned long flags; - - /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - if (autoinit) - dma_mode |= DMA_AUTOINIT; - save_flags (flags); - cli (); - disable_dma (chan); - clear_dma_ff (chan); - set_dma_mode (chan, dma_mode); - set_dma_addr (chan, physaddr); - set_dma_count (chan, count); - enable_dma (chan); - restore_flags (flags); - return 0; +int sound_start_dma(int dev, struct dma_buffparms *dmap, int chan, + unsigned long physaddr, + int count, int dma_mode, int autoinit) +{ + unsigned long flags; + + /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ + if (autoinit) + dma_mode |= DMA_AUTOINIT; + save_flags(flags); + cli(); + disable_dma(chan); + clear_dma_ff(chan); + set_dma_mode(chan, dma_mode); + set_dma_addr(chan, physaddr); + set_dma_count(chan, count); + enable_dma(chan); + restore_flags(flags); + + return 0; } #endif -void -conf_printf (char *name, struct address_info *hw_config) +void conf_printf(char *name, struct address_info *hw_config) { - if (!trace_init) - return; + if (!trace_init) + return; - printk ("<%s> at 0x%03x", name, hw_config->io_base); + printk("<%s> at 0x%03x", name, hw_config->io_base); - if (hw_config->irq) - printk (" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); + if (hw_config->irq) + printk(" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); - if (hw_config->dma != -1 || hw_config->dma2 != -1) - { - printk (" dma %d", hw_config->dma); - if (hw_config->dma2 != -1) - printk (",%d", hw_config->dma2); - } - - printk ("\n"); + if (hw_config->dma != -1 || hw_config->dma2 != -1) + { + printk(" dma %d", hw_config->dma); + if (hw_config->dma2 != -1) + printk(",%d", hw_config->dma2); + } + printk("\n"); } -void -conf_printf2 (char *name, int base, int irq, int dma, int dma2) +void conf_printf2(char *name, int base, int irq, int dma, int dma2) { - if (!trace_init) - return; + if (!trace_init) + return; - printk ("<%s> at 0x%03x", name, base); + printk("<%s> at 0x%03x", name, base); - if (irq) - printk (" irq %d", (irq > 0) ? irq : -irq); + if (irq) + printk(" irq %d", (irq > 0) ? irq : -irq); - if (dma != -1 || dma2 != -1) - { - printk (" dma %d", dma); - if (dma2 != -1) - printk (",%d", dma2); - } - - printk ("\n"); + if (dma != -1 || dma2 != -1) + { + printk(" dma %d", dma); + if (dma2 != -1) + printk(",%d", dma2); + } + printk("\n"); } diff -u --recursive --new-file v2.1.66/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h --- v2.1.66/linux/drivers/sound/soundmodule.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/soundmodule.h Sat Nov 29 10:33:21 1997 @@ -0,0 +1,41 @@ +#ifndef _SOUNDMODULE_H +#define _SOUNDMODULE_H + +#ifdef MODULE + +#include + +#ifdef SOUND_CORE + +struct notifier_block *sound_locker=(struct notifier_block *)0; + +#define SOUND_INC_USE_COUNT notifier_call_chain(&sound_locker, 1, 0) +#define SOUND_DEC_USE_COUNT notifier_call_chain(&sound_locker, 0, 0) + +#else + +#define SOUND_LOCK notifier_chain_register(&sound_locker, &sound_notifier) +#define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier) + +extern struct notifier_block *sound_locker; + + +static int my_notifier_call(struct notifier_block *b, unsigned long foo, void *bar) +{ + if(foo) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; + return NOTIFY_DONE; +} + +static struct notifier_block sound_notifier= +{ + my_notifier_call, + (void *)0, + 0 +}; + +#endif +#endif +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.1.66/linux/drivers/sound/sscape.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/sscape.c Sat Nov 29 10:33:21 1997 @@ -11,11 +11,12 @@ * for more info. */ #include - +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_SSCAPEHW +#if defined(CONFIG_SSCAPEHW) || defined(MODULE) #include "coproc.h" @@ -73,25 +74,28 @@ #define CMD_ACK 0x80 typedef struct sscape_info - { - int base, irq, dma; - int ok; /* Properly detected */ - int failed; - int dma_allocated; - int codec_audiodev; - int opened; - int *osp; - } -sscape_info; +{ + int base, irq, dma; + int ok; /* Properly detected */ + int failed; + int dma_allocated; + int codec_audiodev; + int opened; + int *osp; + int my_audiodev; +} sscape_info; + +static struct sscape_info adev_info = { + 0 +}; -static struct sscape_info adev_info = -{0}; static struct sscape_info *devc = &adev_info; static int sscape_mididev = -1; static struct wait_queue *sscape_sleeper = NULL; -static volatile struct snd_wait sscape_sleep_flag = -{0}; +static volatile struct snd_wait sscape_sleep_flag = { + 0 +}; /* Some older cards have assigned interrupt bits differently than new ones */ static char valid_interrupts_old[] = @@ -110,156 +114,153 @@ #endif -static unsigned char -sscape_read (struct sscape_info *devc, int reg) +static unsigned char sscape_read(struct sscape_info *devc, int reg) { - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; - save_flags (flags); - cli (); - outb ((reg), PORT (ODIE_ADDR)); - val = inb (PORT (ODIE_DATA)); - restore_flags (flags); - return val; + save_flags(flags); + cli(); + outb((reg), PORT(ODIE_ADDR)); + val = inb(PORT(ODIE_DATA)); + restore_flags(flags); + return val; } static void -sscape_write (struct sscape_info *devc, int reg, int data) +sscape_write(struct sscape_info *devc, int reg, int data) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - outb ((reg), PORT (ODIE_ADDR)); - outb ((data), PORT (ODIE_DATA)); - restore_flags (flags); + save_flags(flags); + cli(); + outb((reg), PORT(ODIE_ADDR)); + outb((data), PORT(ODIE_DATA)); + restore_flags(flags); } static void -host_open (struct sscape_info *devc) +host_open(struct sscape_info *devc) { - outb ((0x00), PORT (HOST_CTRL)); /* Put the board to the host mode */ + outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */ } static void -host_close (struct sscape_info *devc) +host_close(struct sscape_info *devc) { - outb ((0x03), PORT (HOST_CTRL)); /* Put the board to the MIDI mode */ + outb((0x03), PORT(HOST_CTRL)); /* Put the board to the MIDI mode */ } static int -host_write (struct sscape_info *devc, unsigned char *data, int count) +host_write(struct sscape_info *devc, unsigned char *data, int count) { - unsigned long flags; - int i, timeout_val; + unsigned long flags; + int i, timeout_val; - save_flags (flags); - cli (); + save_flags(flags); + cli(); - /* - * Send the command and data bytes - */ - - for (i = 0; i < count; i++) - { - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb (PORT (HOST_CTRL)) & TX_READY) - break; - - if (timeout_val <= 0) - { - restore_flags (flags); - return 0; - } + /* + * Send the command and data bytes + */ - outb ((data[i]), PORT (HOST_DATA)); - } + for (i = 0; i < count; i++) + { + for (timeout_val = 10000; timeout_val > 0; timeout_val--) + if (inb(PORT(HOST_CTRL)) & TX_READY) + break; + + if (timeout_val <= 0) + { + restore_flags(flags); + return 0; + } + outb((data[i]), PORT(HOST_DATA)); + } - restore_flags (flags); + restore_flags(flags); - return 1; + return 1; } static int -host_read (struct sscape_info *devc) +host_read(struct sscape_info *devc) { - unsigned long flags; - int timeout_val; - unsigned char data; - - save_flags (flags); - cli (); + unsigned long flags; + int timeout_val; + unsigned char data; - /* - * Read a byte - */ + save_flags(flags); + cli(); - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb (PORT (HOST_CTRL)) & RX_READY) - break; + /* + * Read a byte + */ - if (timeout_val <= 0) - { - restore_flags (flags); - return -1; - } + for (timeout_val = 10000; timeout_val > 0; timeout_val--) + if (inb(PORT(HOST_CTRL)) & RX_READY) + break; - data = inb (PORT (HOST_DATA)); + if (timeout_val <= 0) + { + restore_flags(flags); + return -1; + } + data = inb(PORT(HOST_DATA)); - restore_flags (flags); + restore_flags(flags); - return data; + return data; } static int -host_command2 (struct sscape_info *devc, int cmd, int parm1) +host_command2(struct sscape_info *devc, int cmd, int parm1) { - unsigned char buf[10]; + unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); - return host_write (devc, buf, 2); + return host_write(devc, buf, 2); } static int -host_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2) +host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2) { - unsigned char buf[10]; + unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - buf[2] = (unsigned char) (parm2 & 0xff); + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + buf[2] = (unsigned char) (parm2 & 0xff); - return host_write (devc, buf, 3); + return host_write(devc, buf, 3); } static void -set_mt32 (struct sscape_info *devc, int value) +set_mt32(struct sscape_info *devc, int value) { - host_open (devc); - host_command2 (devc, CMD_SET_MT32, - value ? 1 : 0); - if (host_read (devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */ - } - host_close (devc); + host_open(devc); + host_command2(devc, CMD_SET_MT32, + value ? 1 : 0); + if (host_read(devc) != CMD_ACK) + { + /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */ + } + host_close(devc); } static void -set_control (struct sscape_info *devc, int ctrl, int value) +set_control(struct sscape_info *devc, int ctrl, int value) { - host_open (devc); - host_command3 (devc, CMD_SET_CONTROL, ctrl, value); - if (host_read (devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */ - } - host_close (devc); + host_open(devc); + host_command3(devc, CMD_SET_CONTROL, ctrl, value); + if (host_read(devc) != CMD_ACK) + { + /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */ + } + host_close(devc); } @@ -267,378 +268,370 @@ static void -do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) +do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) { - unsigned char temp; + unsigned char temp; - if (dma_chan != SSCAPE_DMA_A) - { - printk ("SSCAPE: Tried to use DMA channel != A. Why?\n"); - return; - } - - audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; - DMAbuf_start_dma (devc->codec_audiodev, - buf, - blk_size, mode); - audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; - - temp = devc->dma << 4; /* Setup DMA channel select bits */ - if (devc->dma <= 3) - temp |= 0x80; /* 8 bit DMA channel */ - - temp |= 1; /* Trigger DMA */ - sscape_write (devc, GA_DMAA_REG, temp); - temp &= 0xfe; /* Clear DMA trigger */ - sscape_write (devc, GA_DMAA_REG, temp); + if (dma_chan != SSCAPE_DMA_A) + { + printk("SSCAPE: Tried to use DMA channel != A. Why?\n"); + return; + } + audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; + DMAbuf_start_dma(devc->codec_audiodev, + buf, + blk_size, mode); + audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; + + temp = devc->dma << 4; /* Setup DMA channel select bits */ + if (devc->dma <= 3) + temp |= 0x80; /* 8 bit DMA channel */ + + temp |= 1; /* Trigger DMA */ + sscape_write(devc, GA_DMAA_REG, temp); + temp &= 0xfe; /* Clear DMA trigger */ + sscape_write(devc, GA_DMAA_REG, temp); } static int -verify_mpu (struct sscape_info *devc) +verify_mpu(struct sscape_info *devc) { - /* - * The SoundScape board could be in three modes (MPU, 8250 and host). - * If the card is not in the MPU mode, enabling the MPU driver will - * cause infinite loop (the driver believes that there is always some - * received data in the buffer. - * - * Detect this by looking if there are more than 10 received MIDI bytes - * (0x00) in the buffer. - */ - - int i; - - for (i = 0; i < 10; i++) - { - if (inb (devc->base + HOST_CTRL) & 0x80) - return 1; + /* + * The SoundScape board could be in three modes (MPU, 8250 and host). + * If the card is not in the MPU mode, enabling the MPU driver will + * cause infinite loop (the driver believes that there is always some + * received data in the buffer. + * + * Detect this by looking if there are more than 10 received MIDI bytes + * (0x00) in the buffer. + */ - if (inb (devc->base) != 0x00) - return 1; - } + int i; + + for (i = 0; i < 10; i++) + { + if (inb(devc->base + HOST_CTRL) & 0x80) + return 1; - printk ("SoundScape: The device is not in the MPU-401 mode\n"); - return 0; + if (inb(devc->base) != 0x00) + return 1; + } + + printk("SoundScape: The device is not in the MPU-401 mode\n"); + return 0; } static int -sscape_coproc_open (void *dev_info, int sub_device) +sscape_coproc_open(void *dev_info, int sub_device) { - if (sub_device == COPR_MIDI) - { - set_mt32 (devc, 0); - if (!verify_mpu (devc)) - return -EIO; - } - - sscape_sleep_flag.opts = WK_NONE; - return 0; + if (sub_device == COPR_MIDI) + { + set_mt32(devc, 0); + if (!verify_mpu(devc)) + return -EIO; + } + sscape_sleep_flag.opts = WK_NONE; + return 0; } static void -sscape_coproc_close (void *dev_info, int sub_device) +sscape_coproc_close(void *dev_info, int sub_device) { - struct sscape_info *devc = dev_info; - unsigned long flags; + struct sscape_info *devc = dev_info; + unsigned long flags; - save_flags (flags); - cli (); - if (devc->dma_allocated) - { - sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ - devc->dma_allocated = 0; - } - sscape_sleep_flag.opts = WK_NONE; - restore_flags (flags); + save_flags(flags); + cli(); + if (devc->dma_allocated) + { + sscape_write(devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ + devc->dma_allocated = 0; + } + sscape_sleep_flag.opts = WK_NONE; + restore_flags(flags); - return; + return; } static void -sscape_coproc_reset (void *dev_info) +sscape_coproc_reset(void *dev_info) { } static int -sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag) +sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag) { - unsigned long flags; - unsigned char temp; - volatile int done, timeout_val; - static unsigned char codec_dma_bits = 0; - - if (flag & CPF_FIRST) - { - /* - * First block. Have to allocate DMA and to reset the board - * before continuing. - */ - - save_flags (flags); - cli (); - codec_dma_bits = sscape_read (devc, GA_CDCFG_REG); - - if (devc->dma_allocated == 0) - { - devc->dma_allocated = 1; - } - restore_flags (flags); - - sscape_write (devc, GA_HMCTL_REG, - (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - sscape_read (devc, GA_HMCTL_REG); /* Delay */ - - /* Take board out of reset */ - sscape_write (devc, GA_HMCTL_REG, - (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80); - } - - /* - * Transfer one code block using DMA - */ - if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) - { - printk ("SSCAPE: Error: DMA buffer not available\n"); - return 0; - } + unsigned long flags; + unsigned char temp; + volatile int done, timeout_val; + static unsigned char codec_dma_bits = 0; - memcpy (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); + if (flag & CPF_FIRST) + { + /* + * First block. Have to allocate DMA and to reset the board + * before continuing. + */ + + save_flags(flags); + cli(); + codec_dma_bits = sscape_read(devc, GA_CDCFG_REG); + + if (devc->dma_allocated == 0) + { + devc->dma_allocated = 1; + } + restore_flags(flags); + + sscape_write(devc, GA_HMCTL_REG, + (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ + + for (timeout_val = 10000; timeout_val > 0; timeout_val--) + sscape_read(devc, GA_HMCTL_REG); /* Delay */ + + /* Take board out of reset */ + sscape_write(devc, GA_HMCTL_REG, + (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80); + } + /* + * Transfer one code block using DMA + */ + if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) + { + printk("SSCAPE: Error: DMA buffer not available\n"); + return 0; + } + memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); - save_flags (flags); - cli (); + save_flags(flags); + cli(); /******** INTERRUPTS DISABLED NOW ********/ - do_dma (devc, SSCAPE_DMA_A, - audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, - size, DMA_MODE_WRITE); - - /* - * Wait until transfer completes. - */ - sscape_sleep_flag.opts = WK_NONE; - done = 0; - timeout_val = 30; - while (!done && timeout_val-- > 0) - { - int resid; - - { - unsigned long tlimit; - - if (HZ / 50) - current->timeout = tlimit = jiffies + (HZ / 50); - else - tlimit = (unsigned long) -1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; - }; - clear_dma_ff (devc->dma); - if ((resid = get_dma_residue (devc->dma)) == 0) - { - done = 1; - } - } - - restore_flags (flags); - if (!done) - return 0; - - if (flag & CPF_LAST) - { - /* - * Take the board out of reset - */ - outb ((0x00), PORT (HOST_CTRL)); - outb ((0x00), PORT (MIDI_CTRL)); - - temp = sscape_read (devc, GA_HMCTL_REG); - temp |= 0x40; - sscape_write (devc, GA_HMCTL_REG, temp); /* Kickstart the board */ - - /* - * Wait until the ODB wakes up - */ - - save_flags (flags); - cli (); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - - + do_dma(devc, SSCAPE_DMA_A, + audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, + size, DMA_MODE_WRITE); + + /* + * Wait until transfer completes. + */ + sscape_sleep_flag.opts = WK_NONE; + done = 0; + timeout_val = 30; + while (!done && timeout_val-- > 0) { - unsigned long tlimit; + int resid; - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; - }; - x = inb (PORT (HOST_DATA)); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - DDB (printk ("Soundscape: Acknowledge = %x\n", x)); - done = 1; - } - } - sscape_write (devc, GA_CDCFG_REG, codec_dma_bits); + { + unsigned long tlimit; - restore_flags (flags); - if (!done) - { - printk ("SoundScape: The OBP didn't respond after code download\n"); - return 0; - } + if (HZ / 50) + current->timeout = tlimit = jiffies + (HZ / 50); + else + tlimit = (unsigned long) -1; + sscape_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sscape_sleeper); + if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sscape_sleep_flag.opts |= WK_TIMEOUT; + } + sscape_sleep_flag.opts &= ~WK_SLEEP; + }; + clear_dma_ff(devc->dma); + if ((resid = get_dma_residue(devc->dma)) == 0) + { + done = 1; + } + } - save_flags (flags); - cli (); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { + restore_flags(flags); + if (!done) + return 0; + if (flag & CPF_LAST) { - unsigned long tlimit; - - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; - }; - if (inb (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ - done = 1; - } - restore_flags (flags); - if (!done) - { - printk ("SoundScape: OBP Initialization failed.\n"); - return 0; - } - - printk ("SoundScape board initialized OK\n"); - set_control (devc, CTL_MASTER_VOL, 100); - set_control (devc, CTL_SYNTH_VOL, 100); + /* + * Take the board out of reset + */ + outb((0x00), PORT(HOST_CTRL)); + outb((0x00), PORT(MIDI_CTRL)); + + temp = sscape_read(devc, GA_HMCTL_REG); + temp |= 0x40; + sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */ + + /* + * Wait until the ODB wakes up + */ + + save_flags(flags); + cli(); + done = 0; + timeout_val = 5 * HZ; + while (!done && timeout_val-- > 0) + { + unsigned char x; + + + { + unsigned long tlimit; + + if (1) + current->timeout = tlimit = jiffies + (1); + else + tlimit = (unsigned long) -1; + sscape_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sscape_sleeper); + if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sscape_sleep_flag.opts |= WK_TIMEOUT; + } + sscape_sleep_flag.opts &= ~WK_SLEEP; + }; + x = inb(PORT(HOST_DATA)); + if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ + { + DDB(printk("Soundscape: Acknowledge = %x\n", x)); + done = 1; + } + } + sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); + + restore_flags(flags); + if (!done) + { + printk("SoundScape: The OBP didn't respond after code download\n"); + return 0; + } + save_flags(flags); + cli(); + done = 0; + timeout_val = 5 * HZ; + while (!done && timeout_val-- > 0) + { + + { + unsigned long tlimit; + + if (1) + current->timeout = tlimit = jiffies + (1); + else + tlimit = (unsigned long) -1; + sscape_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on(&sscape_sleeper); + if (!(sscape_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + sscape_sleep_flag.opts |= WK_TIMEOUT; + } + sscape_sleep_flag.opts &= ~WK_SLEEP; + }; + if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ + done = 1; + } + restore_flags(flags); + if (!done) + { + printk("SoundScape: OBP Initialization failed.\n"); + return 0; + } + printk("SoundScape board initialized OK\n"); + set_control(devc, CTL_MASTER_VOL, 100); + set_control(devc, CTL_SYNTH_VOL, 100); #ifdef SSCAPE_DEBUG3 - /* - * Temporary debugging aid. Print contents of the registers after - * downloading the code. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); - } + /* + * Temporary debugging aid. Print contents of the registers after + * downloading the code. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); + } #endif - } - - return 1; + } + return 1; } static int -download_boot_block (void *dev_info, copr_buffer * buf) +download_boot_block(void *dev_info, copr_buffer * buf) { - if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; + if (buf->len <= 0 || buf->len > sizeof(buf->data)) + return -EINVAL; - if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) - { - printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); - return -EIO; - } - - return 0; + if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) + { + printk("SSCAPE: Unable to load microcode block to the OBP.\n"); + return -EIO; + } + return 0; } static int -sscape_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) +sscape_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local) { - switch (cmd) - { - case SNDCTL_COPR_RESET: - sscape_coproc_reset (dev_info); - return 0; - break; - - case SNDCTL_COPR_LOAD: - { - copr_buffer *buf; - int err; - - buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); - if (buf == NULL) - return -ENOSPC; - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - err = download_boot_block (dev_info, buf); - vfree (buf); - return err; - } - break; - - default: - return -EINVAL; - } + switch (cmd) + { + case SNDCTL_COPR_RESET: + sscape_coproc_reset(dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + if (buf == NULL) + return -ENOSPC; + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + err = download_boot_block(dev_info, buf); + vfree(buf); + return err; + } + break; + + default: + return -EINVAL; + } } static coproc_operations sscape_coproc_operations = { - "SoundScape M68K", - sscape_coproc_open, - sscape_coproc_close, - sscape_coproc_ioctl, - sscape_coproc_reset, - &adev_info + "SoundScape M68K", + sscape_coproc_open, + sscape_coproc_close, + sscape_coproc_ioctl, + sscape_coproc_reset, + &adev_info }; static int sscape_detected = 0; void -attach_sscape (struct address_info *hw_config) +attach_sscape(struct address_info *hw_config) { #ifndef SSCAPE_REGS - /* - * Config register values for Spea/V7 Media FX and Ensoniq S-2000. - * These values are card - * dependent. If you have another SoundScape based card, you have to - * find the correct values. Do the following: - * - Compile this driver with SSCAPE_DEBUG1 defined. - * - Shut down and power off your machine. - * - Boot with DOS so that the SSINIT.EXE program is run. - * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed - * when detecting the SoundScape. - * - Modify the following list to use the values printed during boot. - * Undefine the SSCAPE_DEBUG1 - */ + /* + * Config register values for Spea/V7 Media FX and Ensoniq S-2000. + * These values are card + * dependent. If you have another SoundScape based card, you have to + * find the correct values. Do the following: + * - Compile this driver with SSCAPE_DEBUG1 defined. + * - Shut down and power off your machine. + * - Boot with DOS so that the SSINIT.EXE program is run. + * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed + * when detecting the SoundScape. + * - Modify the following list to use the values printed during boot. + * Undefine the SSCAPE_DEBUG1 + */ #define SSCAPE_REGS { \ /* I0 */ 0x00, \ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ @@ -653,356 +646,400 @@ } #endif - unsigned long flags; - static unsigned char regs[10] = SSCAPE_REGS; + unsigned long flags; + static unsigned char regs[10] = SSCAPE_REGS; - int i, irq_bits = 0xff; + int i, irq_bits = 0xff; - if (sscape_detected != hw_config->io_base) - return; + if (sscape_detected != hw_config->io_base) + return; - request_region (devc->base + 2, 6, "SoundScape"); - if (old_hardware) - { - valid_interrupts = valid_interrupts_old; - conf_printf ("Ensoniq SoundScape (old)", hw_config); - } - else - conf_printf ("Ensoniq SoundScape", hw_config); - - for (i = 0; i < sizeof (valid_interrupts); i++) - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - - if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) - { - printk ("Invalid IRQ%d\n", hw_config->irq); - return; - } - - save_flags (flags); - cli (); - - for (i = 1; i < 10; i++) - switch (i) - { - case 1: /* Host interrupt enable */ - sscape_write (devc, i, 0xf0); /* All interrupts enabled */ - break; - - case 2: /* DMA A status/trigger register */ - case 3: /* DMA B status/trigger register */ - sscape_write (devc, i, 0x20); /* DMA channel disabled */ - break; - - case 4: /* Host interrupt config reg */ - sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits); - break; - - case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ - sscape_write (devc, i, (regs[i] & 0x3f) | - (sscape_read (devc, i) & 0xc0)); - break; - - case 6: /* CD-ROM config (WSS codec actually) */ - sscape_write (devc, i, regs[i]); - break; - - case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ - sscape_write (devc, i, - (sscape_read (devc, i) & 0xf0) | 0x08); - break; - - default: - sscape_write (devc, i, regs[i]); - } + request_region(devc->base + 2, 6, "SoundScape"); + if (old_hardware) + { + valid_interrupts = valid_interrupts_old; + conf_printf("Ensoniq SoundScape (old)", hw_config); + } else + conf_printf("Ensoniq SoundScape", hw_config); + + for (i = 0; i < sizeof(valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) + { + printk("Invalid IRQ%d\n", hw_config->irq); + return; + } + save_flags(flags); + cli(); - restore_flags (flags); + for (i = 1; i < 10; i++) + switch (i) + { + case 1: /* Host interrupt enable */ + sscape_write(devc, i, 0xf0); /* All interrupts enabled */ + break; + + case 2: /* DMA A status/trigger register */ + case 3: /* DMA B status/trigger register */ + sscape_write(devc, i, 0x20); /* DMA channel disabled */ + break; + + case 4: /* Host interrupt config reg */ + sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits); + break; + + case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ + sscape_write(devc, i, (regs[i] & 0x3f) | + (sscape_read(devc, i) & 0xc0)); + break; + + case 6: /* CD-ROM config (WSS codec actually) */ + sscape_write(devc, i, regs[i]); + break; + + case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ + sscape_write(devc, i, + (sscape_read(devc, i) & 0xf0) | 0x08); + break; + + default: + sscape_write(devc, i, regs[i]); + } + + restore_flags(flags); #ifdef SSCAPE_DEBUG2 - /* - * Temporary debugging aid. Print contents of the registers after - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); - } + /* + * Temporary debugging aid. Print contents of the registers after + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); + } #endif #if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) - if (probe_mpu401 (hw_config)) - hw_config->always_detect = 1; - { - int prev_devs; - - prev_devs = num_midis; - hw_config->name = "SoundScape"; - - hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401 (hw_config); - hw_config->irq *= -1; /* Restore it */ - - if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ - { - sscape_mididev = prev_devs; - midi_devs[prev_devs]->coproc = &sscape_coproc_operations; - } - } + if (probe_mpu401(hw_config)) + hw_config->always_detect = 1; + { + hw_config->name = "SoundScape"; + + hw_config->irq *= -1; /* Negative value signals IRQ sharing */ + attach_mpu401(hw_config); + hw_config->irq *= -1; /* Restore it */ + + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + { + sscape_mididev = hw_config->slots[1]; + midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; + } + } #endif - sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - devc->ok = 1; - devc->failed = 0; + sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ + devc->ok = 1; + devc->failed = 0; } static int -detect_ga (sscape_info * devc) +detect_ga(sscape_info * devc) { - unsigned char save; + unsigned char save; + + DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base)); - DDB (printk ("Entered Soundscape detect_ga(%x)\n", devc->base)); + if (check_region(devc->base, 8)) + return 0; - if (check_region (devc->base, 8)) - return 0; + /* + * First check that the address register of "ODIE" is + * there and that it has exactly 4 writable bits. + * First 4 bits + */ + if ((save = inb(PORT(ODIE_ADDR))) & 0xf0) + { + DDB(printk("soundscape: Detect error A\n")); + return 0; + } + outb((0x00), PORT(ODIE_ADDR)); + if (inb(PORT(ODIE_ADDR)) != 0x00) + { + DDB(printk("soundscape: Detect error B\n")); + return 0; + } + outb((0xff), PORT(ODIE_ADDR)); + if (inb(PORT(ODIE_ADDR)) != 0x0f) + { + DDB(printk("soundscape: Detect error C\n")); + return 0; + } + outb((save), PORT(ODIE_ADDR)); - /* - * First check that the address register of "ODIE" is - * there and that it has exactly 4 writable bits. - * First 4 bits - */ - if ((save = inb (PORT (ODIE_ADDR))) & 0xf0) - { - DDB (printk ("soundscape: Detect error A\n")); - return 0; - } - - outb ((0x00), PORT (ODIE_ADDR)); - if (inb (PORT (ODIE_ADDR)) != 0x00) - { - DDB (printk ("soundscape: Detect error B\n")); - return 0; - } - - outb ((0xff), PORT (ODIE_ADDR)); - if (inb (PORT (ODIE_ADDR)) != 0x0f) - { - DDB (printk ("soundscape: Detect error C\n")); - return 0; - } - - outb ((save), PORT (ODIE_ADDR)); - - /* - * Now verify that some indirect registers return zero on some bits. - * This may break the driver with some future revisions of "ODIE" but... - */ - - if (sscape_read (devc, 0) & 0x0c) - { - DDB (printk ("soundscape: Detect error D (%x)\n", sscape_read (devc, 0))); - return 0; - } - - if (sscape_read (devc, 1) & 0x0f) - { - DDB (printk ("soundscape: Detect error E\n")); - return 0; - } - - if (sscape_read (devc, 5) & 0x0f) - { - DDB (printk ("soundscape: Detect error F\n")); - return 0; - } + /* + * Now verify that some indirect registers return zero on some bits. + * This may break the driver with some future revisions of "ODIE" but... + */ - return 1; + if (sscape_read(devc, 0) & 0x0c) + { + DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0))); + return 0; + } + if (sscape_read(devc, 1) & 0x0f) + { + DDB(printk("soundscape: Detect error E\n")); + return 0; + } + if (sscape_read(devc, 5) & 0x0f) + { + DDB(printk("soundscape: Detect error F\n")); + return 0; + } + return 1; } int -probe_sscape (struct address_info *hw_config) +probe_sscape(struct address_info *hw_config) { - if (sscape_detected != 0 && sscape_detected != hw_config->io_base) - return 0; + if (sscape_detected != 0 && sscape_detected != hw_config->io_base) + return 0; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + devc->osp = hw_config->osp; #ifdef SSCAPE_DEBUG1 - /* - * Temporary debugging aid. Print contents of the registers before - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i)); - } -#endif - + /* + * Temporary debugging aid. Print contents of the registers before + * changing them. + */ + { + int i; - devc->failed = 1; + for (i = 0; i < 13; i++) + printk("I%d = %02x (old value)\n", i, sscape_read(devc, i)); + } +#endif - if (!detect_ga (devc)) - return 0; - if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ - { - unsigned char tmp; - int cc; + devc->failed = 1; - if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0)) - { - sscape_write (devc, GA_HMCTL_REG, tmp | 0x80); - for (cc = 0; cc < 200000; ++cc) - inb (devc->base + ODIE_ADDR); - } - } + if (!detect_ga(devc)) + return 0; + if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ + { + unsigned char tmp; + int cc; - sscape_detected = hw_config->io_base; + if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0)) + { + sscape_write(devc, GA_HMCTL_REG, tmp | 0x80); + for (cc = 0; cc < 200000; ++cc) + inb(devc->base + ODIE_ADDR); + } + } + sscape_detected = hw_config->io_base; - return 1; + return 1; } int -probe_ss_ms_sound (struct address_info *hw_config) +probe_ss_ms_sound(struct address_info *hw_config) { - int i, irq_bits = 0xff; - int ad_flags = 0; + int i, irq_bits = 0xff; + int ad_flags = 0; - if (devc->failed) - { - printk ("Soundscape: Card not detected\n"); - return 0; - } - - if (devc->ok == 0) - { - printk ("SoundScape: Invalid initialization order.\n"); - return 0; - } - - for (i = 0; i < sizeof (valid_interrupts); i++) - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - if (hw_config->irq > 15 || irq_bits == 0xff) - { - printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); - return 0; - } - - - if (old_hardware) - ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ - return ad1848_detect (hw_config->io_base, &ad_flags, hw_config->osp); + if (devc->failed) + { + printk("Soundscape: Card not detected\n"); + return 0; + } + if (devc->ok == 0) + { + printk("SoundScape: Invalid initialization order.\n"); + return 0; + } + for (i = 0; i < sizeof(valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + if (hw_config->irq > 15 || irq_bits == 0xff) + { + printk("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); + return 0; + } + if (old_hardware) + ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ + return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp); } void -attach_ss_ms_sound (struct address_info *hw_config) +attach_ss_ms_sound(struct address_info *hw_config) { - /* - * This routine configures the SoundScape card for use with the - * Win Sound System driver. The AD1848 codec interface uses the CD-ROM - * config registers of the "ODIE". - */ - - int i, irq_bits = 0xff; - - int prev_devs = num_audiodevs; - - hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ - - /* - * Setup the DMA polarity. - */ - sscape_write (devc, GA_DMACFG_REG, 0x50); - - /* - * Take the gate-array off of the DMA channel. - */ - sscape_write (devc, GA_DMAB_REG, 0x20); - - /* - * Init the AD1848 (CD-ROM) config reg. - */ - - for (i = 0; i < sizeof (valid_interrupts); i++) - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - - sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | - (irq_bits << 1)); - - if (hw_config->irq == devc->irq) - printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); - - ad1848_init ("SoundScape", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); - - if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ - { - audio_devs[prev_devs]->coproc = &sscape_coproc_operations; - devc->codec_audiodev = prev_devs; - - /* Set proper routings here (what are they) */ - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - } + /* + * This routine configures the SoundScape card for use with the + * Win Sound System driver. The AD1848 codec interface uses the CD-ROM + * config registers of the "ODIE". + */ + + int i, irq_bits = 0xff; + + hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ + + /* + * Setup the DMA polarity. + */ + sscape_write(devc, GA_DMACFG_REG, 0x50); + + /* + * Take the gate-array off of the DMA channel. + */ + sscape_write(devc, GA_DMAB_REG, 0x20); + + /* + * Init the AD1848 (CD-ROM) config reg. + */ + + for (i = 0; i < sizeof(valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | + (irq_bits << 1)); + + if (hw_config->irq == devc->irq) + printk("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); + + hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, + 0, + devc->osp); + if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ + { + audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations; + devc->codec_audiodev = hw_config->slots[0]; + devc->my_audiodev = hw_config->slots[0]; + + /* Set proper routings here (what are they) */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + } #ifdef SSCAPE_DEBUG5 - /* - * Temporary debugging aid. Print contents of the registers - * after the AD1848 device has been initialized. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x\n", i, sscape_read (devc, i)); - } + /* + * Temporary debugging aid. Print contents of the registers + * after the AD1848 device has been initialized. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk("I%d = %02x\n", i, sscape_read(devc, i)); + } #endif } void -unload_sscape (struct address_info *hw_config) +unload_sscape(struct address_info *hw_config) { - release_region (devc->base + 2, 6); + release_region(devc->base + 2, 6); #if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); + unload_mpu401(hw_config); #endif } void -unload_ss_ms_sound (struct address_info *hw_config) +unload_ss_ms_sound(struct address_info *hw_config) +{ + ad1848_unload(hw_config->io_base, + hw_config->irq, + devc->dma, + devc->dma, + 0); + sound_unload_audiodev(hw_config->slots[0]); +} + +#ifdef MODULE + +int dma = -1; +int irq = -1; +int io = -1; + +int mpu_irq = -1; +int mpu_io = -1; + +static int mss = 0; + +MODULE_PARM(dma, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(mpu_irq, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(mss, "i"); + +struct address_info config; +struct address_info mpu_config; + +int +init_module(void) { - ad1848_unload (hw_config->io_base, - hw_config->irq, - devc->dma, - devc->dma, - 0); + printk("Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + if (dma == -1 || irq == -1 || io == -1) + { + printk("DMA, IRQ, and IO port must be specified.\n"); + return -EINVAL; + } + if (mpu_irq == -1 && mpu_io != -1) + { + printk("MPU_IRQ must be specified if MPU_IO is set.\n"); + return -EINVAL; + } + config.irq = irq; + config.dma = dma; + config.io_base = io; + + mpu_config.irq = mpu_irq; + mpu_config.io_base = mpu_io; + + if (probe_sscape(&mpu_config) == 0) + return -ENODEV; + + attach_sscape(&mpu_config); + + mss = probe_ss_ms_sound(&config); + + if (mss) + attach_ss_ms_sound(&config); + SOUND_LOCK; + return 0; } +void +cleanup_module(void) +{ + if (mss) + unload_ss_ms_sound(&config); + SOUND_LOCK_END; + unload_sscape(&config); +} +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c --- v2.1.66/linux/drivers/sound/sys_timer.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sys_timer.c Sat Nov 29 10:33:21 1997 @@ -16,7 +16,7 @@ #include "sound_config.h" -#ifdef CONFIG_SEQUENCER +#if defined(CONFIG_SEQUENCER) || defined(MODULE) static volatile int opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; @@ -26,281 +26,279 @@ static volatile unsigned long next_event_time; static unsigned long prev_event_time; -static void poll_def_tmr (unsigned long dummy); +static void poll_def_tmr(unsigned long dummy); static struct timer_list def_tmr = {NULL, NULL, 0, 0, poll_def_tmr}; static unsigned long -tmr2ticks (int tmr_value) +tmr2ticks(int tmr_value) { - /* - * Convert system timer ticks (HZ) to MIDI ticks - * (divide # of MIDI ticks/minute by # of system ticks/minute). - */ + /* + * Convert system timer ticks (HZ) to MIDI ticks + * (divide # of MIDI ticks/minute by # of system ticks/minute). + */ - return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ); + return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ); } static void -poll_def_tmr (unsigned long dummy) +poll_def_tmr(unsigned long dummy) { - if (opened) - { - - { - def_tmr.expires = (1) + jiffies; - add_timer (&def_tmr); - }; - - if (tmr_running) - { - tmr_ctr++; - curr_ticks = ticks_offs + tmr2ticks (tmr_ctr); + if (opened) + { - if (curr_ticks >= next_event_time) - { - next_event_time = (unsigned long) -1; - sequencer_timer (0); - } - } - } + { + def_tmr.expires = (1) + jiffies; + add_timer(&def_tmr); + }; + + if (tmr_running) + { + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); + + if (curr_ticks >= next_event_time) + { + next_event_time = (unsigned long) -1; + sequencer_timer(0); + } + } + } } static void -tmr_reset (void) +tmr_reset(void) { - unsigned long flags; + unsigned long flags; - save_flags (flags); - cli (); - tmr_offs = 0; - ticks_offs = 0; - tmr_ctr = 0; - next_event_time = (unsigned long) -1; - prev_event_time = 0; - curr_ticks = 0; - restore_flags (flags); + save_flags(flags); + cli(); + tmr_offs = 0; + ticks_offs = 0; + tmr_ctr = 0; + next_event_time = (unsigned long) -1; + prev_event_time = 0; + curr_ticks = 0; + restore_flags(flags); } static int -def_tmr_open (int dev, int mode) +def_tmr_open(int dev, int mode) { - if (opened) - return -EBUSY; + if (opened) + return -EBUSY; + + tmr_reset(); + curr_tempo = 60; + curr_timebase = 100; + opened = 1; + + ; - tmr_reset (); - curr_tempo = 60; - curr_timebase = 100; - opened = 1; - - ; - - { - def_tmr.expires = (1) + jiffies; - add_timer (&def_tmr); - }; + { + def_tmr.expires = (1) + jiffies; + add_timer(&def_tmr); + }; - return 0; + return 0; } static void -def_tmr_close (int dev) +def_tmr_close(int dev) { - opened = tmr_running = 0; - del_timer (&def_tmr);; + opened = tmr_running = 0; + del_timer(&def_tmr);; } static int -def_tmr_event (int dev, unsigned char *event) +def_tmr_event(int dev, unsigned char *event) { - unsigned char cmd = event[1]; - unsigned long parm = *(int *) &event[4]; - - switch (cmd) - { - case TMR_WAIT_REL: - parm += prev_event_time; - case TMR_WAIT_ABS: - if (parm > 0) - { - long time; - - if (parm <= curr_ticks) /* It's the time */ - return TIMER_NOT_ARMED; - - time = parm; - next_event_time = prev_event_time = time; - - return TIMER_ARMED; - } - break; - - case TMR_START: - tmr_reset (); - tmr_running = 1; - break; + unsigned char cmd = event[1]; + unsigned long parm = *(int *) &event[4]; - case TMR_STOP: - tmr_running = 0; - break; - - case TMR_CONTINUE: - tmr_running = 1; - break; - - case TMR_TEMPO: - if (parm) - { - if (parm < 8) - parm = 8; - if (parm > 360) - parm = 360; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = parm; - } - break; - - case TMR_ECHO: - seq_copy_to_input (event, 8); - break; + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + tmr_reset(); + tmr_running = 1; + break; + + case TMR_STOP: + tmr_running = 0; + break; + + case TMR_CONTINUE: + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 360) + parm = 360; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input(event, 8); + break; - default:; - } + default:; + } - return TIMER_NOT_ARMED; + return TIMER_NOT_ARMED; } static unsigned long -def_tmr_get_time (int dev) +def_tmr_get_time(int dev) { - if (!opened) - return 0; + if (!opened) + return 0; - return curr_ticks; + return curr_ticks; } static int -def_tmr_ioctl (int dev, - unsigned int cmd, caddr_t arg) +def_tmr_ioctl(int dev, + unsigned int cmd, caddr_t arg) { - switch (cmd) - { - case SNDCTL_TMR_SOURCE: - return (*(int *) arg = TMR_INTERNAL); - break; - - case SNDCTL_TMR_START: - tmr_reset (); - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_STOP: - tmr_running = 0; - return 0; - break; - - case SNDCTL_TMR_CONTINUE: - tmr_running = 1; - return 0; - break; - - case SNDCTL_TMR_TIMEBASE: - { - int val; - - val = *(int *) arg; - - if (val) + switch (cmd) { - if (val < 1) - val = 1; - if (val > 1000) - val = 1000; - curr_timebase = val; - } - - return (*(int *) arg = curr_timebase); - } - break; - - case SNDCTL_TMR_TEMPO: - { - int val; - - val = *(int *) arg; + case SNDCTL_TMR_SOURCE: + return (*(int *) arg = TMR_INTERNAL); + break; + + case SNDCTL_TMR_START: + tmr_reset(); + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val; + + val = *(int *) arg; + + if (val) + { + if (val < 1) + val = 1; + if (val > 1000) + val = 1000; + curr_timebase = val; + } + return (*(int *) arg = curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val; + + val = *(int *) arg; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks(tmr_ctr); + tmr_ctr = 0; + curr_tempo = val; + } + return (*(int *) arg = curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + { + int val; + + val = *(int *) arg; + if (val != 0) /* Can't change */ + return -EINVAL; + + return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); + } + break; + + case SNDCTL_SEQ_GETTIME: + return (*(int *) arg = curr_ticks); + break; + + case SNDCTL_TMR_METRONOME: + /* NOP */ + break; - if (val) - { - if (val < 8) - val = 8; - if (val > 250) - val = 250; - tmr_offs = tmr_ctr; - ticks_offs += tmr2ticks (tmr_ctr); - tmr_ctr = 0; - curr_tempo = val; + default:; } - return (*(int *) arg = curr_tempo); - } - break; - - case SNDCTL_SEQ_CTRLRATE: - { - int val; - - val = *(int *) arg; - if (val != 0) /* Can't change */ - return -EINVAL; - - return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60); - } - break; - - case SNDCTL_SEQ_GETTIME: - return (*(int *) arg = curr_ticks); - break; - - case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - - default:; - } - - return -EINVAL; + return -EINVAL; } static void -def_tmr_arm (int dev, long time) +def_tmr_arm(int dev, long time) { - if (time < 0) - time = curr_ticks + 1; - else if (time <= curr_ticks) /* It's the time */ - return; + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; - next_event_time = prev_event_time = time; + next_event_time = prev_event_time = time; - return; + return; } struct sound_timer_operations default_sound_timer = { - {"System clock", 0}, - 0, /* Priority */ - 0, /* Local device link */ - def_tmr_open, - def_tmr_close, - def_tmr_event, - def_tmr_get_time, - def_tmr_ioctl, - def_tmr_arm + {"System clock", 0}, + 0, /* Priority */ + 0, /* Local device link */ + def_tmr_open, + def_tmr_close, + def_tmr_event, + def_tmr_get_time, + def_tmr_ioctl, + def_tmr_arm }; #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.1.66/linux/drivers/sound/trix.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/trix.c Sat Nov 29 10:33:21 1997 @@ -12,12 +12,20 @@ * for more info. */ #include - +#include #include "sound_config.h" +#include "soundmodule.h" #include "sb.h" +#include "sound_firmware.h" + +#if defined(CONFIG_TRIX) || defined (MODULE) -#ifdef CONFIG_TRIX +#if defined(CONFIG_UART401) || defined(CONFIG_UART401_MODULE) +#if defined(CONFIG_MIDI) +#define DO_MIDI +#endif +#endif #ifdef INCLUDE_TRIX_BOOT #include "trix_boot.h" @@ -35,100 +43,98 @@ static int *trix_osp = NULL; static unsigned char -trix_read (int addr) +trix_read(int addr) { - outb (((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ - return inb (0x391); /* MT-0002-PC ASIC data */ + outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ + return inb(0x391); /* MT-0002-PC ASIC data */ } static void -trix_write (int addr, int data) +trix_write(int addr, int data) { - outb (((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ - outb (((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ + outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ + outb(((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ } static void -download_boot (int base) +download_boot(int base) { - int i = 0, n = trix_boot_len; + int i = 0, n = trix_boot_len; - if (trix_boot_len == 0) - return; + if (trix_boot_len == 0) + return; - trix_write (0xf8, 0x00); /* ??????? */ - outb ((0x01), base + 6); /* Clear the internal data pointer */ - outb ((0x00), base + 6); /* Restart */ - - /* - * Write the boot code to the RAM upload/download register. - * Each write increments the internal data pointer. - */ - outb ((0x01), base + 6); /* Clear the internal data pointer */ - outb ((0x1A), 0x390); /* Select RAM download/upload port */ - - for (i = 0; i < n; i++) - outb ((trix_boot[i]), 0x391); - for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ - outb ((0x00), 0x391); - outb ((0x00), base + 6); /* Reset */ - outb ((0x50), 0x390); /* ?????? */ + trix_write(0xf8, 0x00); /* ??????? */ + outb((0x01), base + 6); /* Clear the internal data pointer */ + outb((0x00), base + 6); /* Restart */ + + /* + * Write the boot code to the RAM upload/download register. + * Each write increments the internal data pointer. + */ + outb((0x01), base + 6); /* Clear the internal data pointer */ + outb((0x1A), 0x390); /* Select RAM download/upload port */ + + for (i = 0; i < n; i++) + outb((trix_boot[i]), 0x391); + for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ + outb((0x00), 0x391); + outb((0x00), base + 6); /* Reset */ + outb((0x50), 0x390); /* ?????? */ } static int -trix_set_wss_port (struct address_info *hw_config) +trix_set_wss_port(struct address_info *hw_config) { - unsigned char addr_bits; + unsigned char addr_bits; - if (check_region (0x390, 2)) - { - printk ("AudioTrix: Config port I/O conflict\n"); - return 0; - } - - if (kilroy_was_here) /* Already initialized */ - return 0; - - if (trix_read (0x15) != 0x71) /* No ASIC signature */ - { - DDB (printk ("No AudioTrix ASIC signature found\n")); - return 0; - } - - kilroy_was_here = 1; - - /* - * Reset some registers. - */ - - trix_write (0x13, 0); - trix_write (0x14, 0); - - /* - * Configure the ASIC to place the codec to the proper I/O location - */ - - switch (hw_config->io_base) - { - case 0x530: - addr_bits = 0; - break; - case 0x604: - addr_bits = 1; - break; - case 0xE80: - addr_bits = 2; - break; - case 0xF40: - addr_bits = 3; - break; - default: - return 0; - } + if (check_region(0x390, 2)) + { + printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); + return 0; + } + if (kilroy_was_here) /* Already initialized */ + return 0; + + if (trix_read(0x15) != 0x71) /* No ASIC signature */ + { + MDB(printk("No AudioTrix ASIC signature found\n")); + return 0; + } + kilroy_was_here = 1; + + /* + * Reset some registers. + */ + + trix_write(0x13, 0); + trix_write(0x14, 0); + + /* + * Configure the ASIC to place the codec to the proper I/O location + */ + + switch (hw_config->io_base) + { + case 0x530: + addr_bits = 0; + break; + case 0x604: + addr_bits = 1; + break; + case 0xE80: + addr_bits = 2; + break; + case 0xF40: + addr_bits = 3; + break; + default: + return 0; + } - trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits); - return 1; + trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits); + return 1; } /* @@ -137,339 +143,421 @@ */ int -probe_trix_wss (struct address_info *hw_config) +probe_trix_wss(struct address_info *hw_config) { - int ret; - - /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. - */ - if (check_region (hw_config->io_base, 8)) - { - printk ("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - trix_osp = hw_config->osp; - - if (!trix_set_wss_port (hw_config)) - return 0; - - if ((inb (hw_config->io_base + 3) & 0x3f) != 0x00) - { - DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base)); - return 0; - } - - if (hw_config->irq > 11) - { - printk ("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); - return 0; - } - - if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk ("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); - return 0; - } - - if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) - if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) - { - printk ("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); - return 0; - } - - /* - * Check that DMA0 is not in use with a 8 bit board. - */ - - if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); - return 0; - } - - if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) - { - printk ("AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); - return 0; - } + int ret; - ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00. + */ + if (check_region(hw_config->io_base, 8)) + { + printk("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + trix_osp = hw_config->osp; + + if (!trix_set_wss_port(hw_config)) + return 0; + + if ((inb(hw_config->io_base + 3) & 0x3f) != 0x00) + { + MDB(printk("No MSS signature detected on port 0x%x\n", hw_config->io_base)); + return 0; + } + if (hw_config->irq > 11) + { + printk("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); + return 0; + } + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); + return 0; + } + if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) + if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) + { + printk("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); + return 0; + } + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) + { + printk("AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); + return 0; + } + if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) + { + printk("AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); + return 0; + } + ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); - if (ret) - { + if (ret) + { #ifdef TRIX_ENABLE_JOYSTICK - trix_write (0x15, 0x80); + trix_write(0x15, 0x80); #endif - request_region (0x390, 2, "AudioTrix"); - } - - return ret; + request_region(0x390, 2, "AudioTrix"); + } + return ret; } void -attach_trix_wss (struct address_info *hw_config) +attach_trix_wss(struct address_info *hw_config) { - static unsigned char interrupt_bits[12] = - {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; - char bits; - - static unsigned char dma_bits[4] = - {1, 2, 0, 3}; - - int config_port = hw_config->io_base + 0; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; - - trix_osp = hw_config->osp; - - if (!kilroy_was_here) - { - DDB (printk ("AudioTrix: Attach called but not probed yet???\n")); - return; - } - - /* - * Set the IRQ and DMA addresses. - */ - - bits = interrupt_bits[hw_config->irq]; - if (bits == 0) - { - printk ("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); - return; - } - - outb ((bits | 0x40), config_port); - - if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) - { - bits |= dma_bits[dma1]; - dma2 = dma1; - } - else - { - unsigned char tmp; - - tmp = trix_read (0x13) & ~30; - trix_write (0x13, tmp | 0x80 | (dma1 << 4)); - - tmp = trix_read (0x14) & ~30; - trix_write (0x14, tmp | 0x80 | (dma2 << 4)); - } - - outb ((bits), config_port); /* Write IRQ+DMA setup */ - - ad1848_init ("AudioTrix Pro", hw_config->io_base + 4, - hw_config->irq, - dma1, - dma2, - 0, - hw_config->osp); - request_region (hw_config->io_base, 4, "MSS config"); - - if (num_mixers > old_num_mixers) /* Mixer got installed */ - { - AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ - AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ - AD1848_REROUTE (SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ - } + static unsigned char interrupt_bits[12] = + {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; + char bits; + + static unsigned char dma_bits[4] = + {1, 2, 0, 3}; + + int config_port = hw_config->io_base + 0; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int old_num_mixers = num_mixers; + + trix_osp = hw_config->osp; + + if (!kilroy_was_here) + { + DDB(printk("AudioTrix: Attach called but not probed yet???\n")); + return; + } + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == 0) + { + printk("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); + return; + } + outb((bits | 0x40), config_port); + + if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) + { + bits |= dma_bits[dma1]; + dma2 = dma1; + } else + { + unsigned char tmp; + + tmp = trix_read(0x13) & ~30; + trix_write(0x13, tmp | 0x80 | (dma1 << 4)); + + tmp = trix_read(0x14) & ~30; + trix_write(0x14, tmp | 0x80 | (dma2 << 4)); + } + + outb((bits), config_port); /* Write IRQ+DMA setup */ + + hw_config->slots[0] = ad1848_init("AudioTrix Pro", hw_config->io_base + 4, + hw_config->irq, + dma1, + dma2, + 0, + hw_config->osp); + request_region(hw_config->io_base, 4, "MSS config"); + + if (num_mixers > old_num_mixers) /* Mixer got installed */ + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ + AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ + } } int -probe_trix_sb (struct address_info *hw_config) +probe_trix_sb(struct address_info *hw_config) { - int tmp; - unsigned char conf; - static char irq_translate[] = - {-1, -1, -1, 0, 1, 2, -1, 3}; - - if (trix_boot_len == 0) - return 0; /* No boot code -> no fun */ - - if (!kilroy_was_here) - return 0; /* AudioTrix Pro has not been detected earlier */ - - if (sb_initialized) - return 0; - - if (check_region (hw_config->io_base, 16)) - { - printk ("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if ((hw_config->io_base & 0xffffff8f) != 0x200) - return 0; - - tmp = hw_config->irq; - if (tmp > 7) - return 0; - if (irq_translate[tmp] == -1) - return 0; + int tmp; + unsigned char conf; + static char irq_translate[] = + {-1, -1, -1, 0, 1, 2, -1, 3}; + + if (trix_boot_len == 0) + return 0; /* No boot code -> no fun */ + + if (!kilroy_was_here) + return 0; /* AudioTrix Pro has not been detected earlier */ + + if (sb_initialized) + return 0; + + if (check_region(hw_config->io_base, 16)) + { + printk("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + if ((hw_config->io_base & 0xffffff8f) != 0x200) + return 0; + + tmp = hw_config->irq; + if (tmp > 7) + return 0; + if (irq_translate[tmp] == -1) + return 0; + + tmp = hw_config->dma; + if (tmp != 1 && tmp != 3) + return 0; + + conf = 0x84; /* DMA and IRQ enable */ + conf |= hw_config->io_base & 0x70; /* I/O address bits */ + conf |= irq_translate[hw_config->irq]; + if (hw_config->dma == 3) + conf |= 0x08; + trix_write(0x1b, conf); - tmp = hw_config->dma; - if (tmp != 1 && tmp != 3) - return 0; + download_boot(hw_config->io_base); + sb_initialized = 1; - conf = 0x84; /* DMA and IRQ enable */ - conf |= hw_config->io_base & 0x70; /* I/O address bits */ - conf |= irq_translate[hw_config->irq]; - if (hw_config->dma == 3) - conf |= 0x08; - trix_write (0x1b, conf); - - download_boot (hw_config->io_base); - sb_initialized = 1; - - hw_config->name = "AudioTrix SB"; + hw_config->name = "AudioTrix SB"; #ifdef CONFIG_SBDSP - return sb_dsp_detect (hw_config); + return sb_dsp_detect(hw_config); #else - return 0; + return 0; #endif } void -attach_trix_sb (struct address_info *hw_config) +attach_trix_sb(struct address_info *hw_config) { - extern int sb_be_quiet; - int old_quiet; + extern int sb_be_quiet; + int old_quiet; #ifdef CONFIG_SBDSP - hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; + hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; - /* Prevent false alarms */ - old_quiet = sb_be_quiet; - sb_be_quiet = 1; + /* Prevent false alarms */ + old_quiet = sb_be_quiet; + sb_be_quiet = 1; - sb_dsp_init (hw_config); + sb_dsp_init(hw_config); - sb_be_quiet = old_quiet; + sb_be_quiet = old_quiet; #endif } void -attach_trix_mpu (struct address_info *hw_config) +attach_trix_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - hw_config->name = "AudioTrix Pro"; - attach_uart401 (hw_config); + hw_config->name = "AudioTrix Pro"; + attach_uart401(hw_config); #endif } int -probe_trix_mpu (struct address_info *hw_config) +probe_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unsigned char conf; - static char irq_bits[] = - {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; - - if (!kilroy_was_here) - { - DDB (printk ("Trix: WSS and SB modes must be initialized before MPU\n")); - return 0; /* AudioTrix Pro has not been detected earlier */ - } - - if (!sb_initialized) - { - DDB (printk ("Trix: SB mode must be initialized before MPU\n")); - return 0; - } - - if (mpu_initialized) - { - DDB (printk ("Trix: MPU mode already initialized\n")); - return 0; - } - - if (check_region (hw_config->io_base, 4)) - { - printk ("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } - - if (hw_config->irq > 9) - { - printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - - if (irq_bits[hw_config->irq] == -1) - { - printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } - - switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x370: - conf = 0x04; - break; - case 0x3b0: - conf = 0x08; - break; - case 0x3f0: - conf = 0x0c; - break; - default: - return 0; /* Invalid port */ - } +#ifdef DO_MIDI + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; + + if (!kilroy_was_here) + { + DDB(printk("Trix: WSS and SB modes must be initialized before MPU\n")); + return 0; /* AudioTrix Pro has not been detected earlier */ + } + if (!sb_initialized) + { + DDB(printk("Trix: SB mode must be initialized before MPU\n")); + return 0; + } + if (mpu_initialized) + { + DDB(printk("Trix: MPU mode already initialized\n")); + return 0; + } + if (check_region(hw_config->io_base, 4)) + { + printk("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + if (hw_config->irq > 9) + { + printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + if (irq_bits[hw_config->irq] == -1) + { + printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x370: + conf = 0x04; + break; + case 0x3b0: + conf = 0x08; + break; + case 0x3f0: + conf = 0x0c; + break; + default: + return 0; /* Invalid port */ + } - conf |= irq_bits[hw_config->irq] << 4; + conf |= irq_bits[hw_config->irq] << 4; - trix_write (0x19, (trix_read (0x19) & 0x83) | conf); + trix_write(0x19, (trix_read(0x19) & 0x83) | conf); - mpu_initialized = 1; + mpu_initialized = 1; - return probe_uart401 (hw_config); + return probe_uart401(hw_config); #else - return 0; + return 0; #endif } void -unload_trix_wss (struct address_info *hw_config) +unload_trix_wss(struct address_info *hw_config) { - int dma2 = hw_config->dma2; - - if (dma2 == -1) - dma2 = hw_config->dma; + int dma2 = hw_config->dma2; - release_region (0x390, 2); - release_region (hw_config->io_base, 4); + if (dma2 == -1) + dma2 = hw_config->dma; - ad1848_unload (hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - dma2, - 0); + release_region(0x390, 2); + release_region(hw_config->io_base, 4); + + ad1848_unload(hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + dma2, + 0); + sound_unload_audiodev(hw_config->slots[0]); } void -unload_trix_mpu (struct address_info *hw_config) +unload_trix_mpu(struct address_info *hw_config) { -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unload_uart401 (hw_config); +#ifdef DO_MIDI + unload_uart401(hw_config); #endif } void -unload_trix_sb (struct address_info *hw_config) +unload_trix_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP - sb_dsp_unload (hw_config); + sb_dsp_unload(hw_config); #endif } +#ifdef MODULE +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; /* Set this for modules that need it */ + +int sb_io = -1; +int sb_dma = -1; +int sb_irq = -1; + +int mpu_io = -1; +int mpu_irq = -1; + +struct address_info config; +struct address_info sb_config; +struct address_info mpu_config; + +static int mpu = 0; +static int sb = 0; + +static int fw_load; + +int +init_module(void) +{ + printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + + if (io == -1 || dma == -1 || irq == -1) + { + printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma2; + + sb_config.io_base = sb_io; + sb_config.irq = sb_irq; + sb_config.dma = sb_dma; + + mpu_config.io_base = mpu_io; + mpu_config.irq = mpu_irq; + + if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1)) + { + printk(KERN_INFO "SB_IRQ and SB_DMA must be specified if SB_IO is set.\n"); + return -EINVAL; + } + if (mpu_io != -1 && mpu_irq == -1) + { + printk(KERN_INFO "MPU_IRQ must be specified if MPU_IO is set.\n"); + return -EINVAL; + } + if (!trix_boot) + { + fw_load = 1; + trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", + (char **) &trix_boot); + } + if (!probe_trix_wss(&config)) + return -ENODEV; + attach_trix_wss(&config); + + /* + * We must attach in the right order to get the firmware + * loaded up in time. + */ + + if (sb_io != -1) + { + sb = probe_trix_sb(&sb_config); + if (sb) + attach_trix_sb(&sb_config); + } + if (mpu_io != -1) + { + mpu = probe_trix_mpu(&mpu_config); + if (mpu) + attach_trix_mpu(&mpu_config); + } + SOUND_LOCK; + return 0; +} + +void +cleanup_module(void) +{ + if (fw_load && trix_boot) + kfree(trix_boot); + if (sb) + unload_trix_sb(&sb_config); + if (mpu) + unload_trix_mpu(&mpu_config); + unload_trix_wss(&config); + SOUND_LOCK_END; +} + +#endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.1.66/linux/drivers/sound/uart401.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/uart401.c Sat Nov 29 10:33:21 1997 @@ -11,23 +11,23 @@ * for more info. */ #include - +#include #include "sound_config.h" +#include "soundmodule.h" -#ifdef CONFIG_UART401 -#ifdef CONFIG_MIDI +#if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE) typedef struct uart401_devc { - int base; - int irq; - int *osp; - void (*midi_input_intr) (int dev, unsigned char data); - int opened, disabled; - volatile unsigned char input_byte; - int my_dev; - int share_irq; + int base; + int irq; + int *osp; + void (*midi_input_intr) (int dev, unsigned char data); + int opened, disabled; + volatile unsigned char input_byte; + int my_dev; + int share_irq; } uart401_devc; @@ -39,27 +39,27 @@ #define COMDPORT (devc->base+1) #define STATPORT (devc->base+1) -static int -uart401_status (uart401_devc * devc) +static int +uart401_status(uart401_devc * devc) { - return inb (STATPORT); + return inb(STATPORT); } #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) #define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) -static void -uart401_cmd (uart401_devc * devc, unsigned char cmd) +static void +uart401_cmd(uart401_devc * devc, unsigned char cmd) { - outb ((cmd), COMDPORT); + outb((cmd), COMDPORT); } -static int -uart401_read (uart401_devc * devc) +static int +uart401_read(uart401_devc * devc) { - return inb (DATAPORT); + return inb(DATAPORT); } -static void -uart401_write (uart401_devc * devc, unsigned char byte) +static void +uart401_write(uart401_devc * devc, unsigned char byte) { - outb ((byte), DATAPORT); + outb((byte), DATAPORT); } #define OUTPUT_READY 0x40 @@ -68,141 +68,139 @@ #define MPU_RESET 0xFF #define UART_MODE_ON 0x3F -static int reset_uart401 (uart401_devc * devc); -static void enter_uart_mode (uart401_devc * devc); +static int reset_uart401(uart401_devc * devc); +static void enter_uart_mode(uart401_devc * devc); static void -uart401_input_loop (uart401_devc * devc) +uart401_input_loop(uart401_devc * devc) { - while (input_avail (devc)) - { - unsigned char c = uart401_read (devc); - - if (c == MPU_ACK) - devc->input_byte = c; - else if (devc->opened & OPEN_READ && devc->midi_input_intr) - devc->midi_input_intr (devc->my_dev, c); - } + while (input_avail(devc)) + { + unsigned char c = uart401_read(devc); + + if (c == MPU_ACK) + devc->input_byte = c; + else if (devc->opened & OPEN_READ && devc->midi_input_intr) + devc->midi_input_intr(devc->my_dev, c); + } } void -uart401intr (int irq, void *dev_id, struct pt_regs *dummy) +uart401intr(int irq, void *dev_id, struct pt_regs *dummy) { - uart401_devc *devc; + uart401_devc *devc; - if (irq < 1 || irq > 15) - return; + if (irq < 1 || irq > 15) + return; - devc = irq2devc[irq]; + devc = irq2devc[irq]; - if (devc == NULL) - return; + if (devc == NULL) + return; - if (input_avail (devc)) - uart401_input_loop (devc); + if (input_avail(devc)) + uart401_input_loop(devc); } static int -uart401_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +uart401_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; - if (devc->opened) - { - return -EBUSY; - } - - while (input_avail (devc)) - uart401_read (devc); - - devc->midi_input_intr = input; - devc->opened = mode; - enter_uart_mode (devc); - devc->disabled = 0; + if (devc->opened) + { + return -EBUSY; + } + while (input_avail(devc)) + uart401_read(devc); + + devc->midi_input_intr = input; + devc->opened = mode; + enter_uart_mode(devc); + devc->disabled = 0; - return 0; + return 0; } static void -uart401_close (int dev) +uart401_close(int dev) { - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; - reset_uart401 (devc); - devc->opened = 0; + reset_uart401(devc); + devc->opened = 0; } static int -uart401_out (int dev, unsigned char midi_byte) +uart401_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; - uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; - - if (devc->disabled) - return 1; - /* - * Test for input since pending input seems to block the output. - */ - - save_flags (flags); - cli (); - - if (input_avail (devc)) - uart401_input_loop (devc); - - restore_flags (flags); - - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); - - if (!output_ready (devc)) - { - printk ("MPU-401: Timeout - Device not responding\n"); - devc->disabled = 1; - reset_uart401 (devc); - enter_uart_mode (devc); - return 1; - } - - uart401_write (devc, midi_byte); - return 1; + int timeout; + unsigned long flags; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + if (devc->disabled) + return 1; + /* + * Test for input since pending input seems to block the output. + */ + + save_flags(flags); + cli(); + + if (input_avail(devc)) + uart401_input_loop(devc); + + restore_flags(flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); + + if (!output_ready(devc)) + { + printk("MPU-401: Timeout - Device not responding\n"); + devc->disabled = 1; + reset_uart401(devc); + enter_uart_mode(devc); + return 1; + } + uart401_write(devc, midi_byte); + return 1; } static int -uart401_start_read (int dev) +uart401_start_read(int dev) { - return 0; + return 0; } static int -uart401_end_read (int dev) +uart401_end_read(int dev) { - return 0; + return 0; } static int -uart401_ioctl (int dev, unsigned cmd, caddr_t arg) +uart401_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -uart401_kick (int dev) +uart401_kick(int dev) { } static int -uart401_buffer_status (int dev) +uart401_buffer_status(int dev) { - return 0; + return 0; } #define MIDI_SYNTH_NAME "MPU-401 UART" @@ -211,256 +209,300 @@ static struct midi_operations uart401_operations = { - {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, - &std_midi_synth, - {0}, - uart401_open, - uart401_close, - uart401_ioctl, - uart401_out, - uart401_start_read, - uart401_end_read, - uart401_kick, - NULL, - uart401_buffer_status, - NULL + {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + &std_midi_synth, + {0}, + uart401_open, + uart401_close, + uart401_ioctl, + uart401_out, + uart401_start_read, + uart401_end_read, + uart401_kick, + NULL, + uart401_buffer_status, + NULL }; static void -enter_uart_mode (uart401_devc * devc) +enter_uart_mode(uart401_devc * devc) { - int ok, timeout; - unsigned long flags; + int ok, timeout; + unsigned long flags; - save_flags (flags); - cli (); - for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); - - devc->input_byte = 0; - uart401_cmd (devc, UART_MODE_ON); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) - ok = 1; - else if (input_avail (devc)) - if (uart401_read (devc) == MPU_ACK) - ok = 1; + save_flags(flags); + cli(); + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); + + devc->input_byte = 0; + uart401_cmd(devc, UART_MODE_ON); + + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) + ok = 1; + else if (input_avail(devc)) + if (uart401_read(devc) == MPU_ACK) + ok = 1; - restore_flags (flags); + restore_flags(flags); } void -attach_uart401 (struct address_info *hw_config) +attach_uart401(struct address_info *hw_config) { - uart401_devc *devc; - char *name = "MPU-401 (UART) MIDI"; - - if (hw_config->name) - name = hw_config->name; - - if (detected_devc == NULL) - return; - - - devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (uart401_devc))); - sound_mem_sizes[sound_nblocks] = sizeof (uart401_devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (devc == NULL) - { - printk ("uart401: Can't allocate memory\n"); - return; - } + uart401_devc *devc; + char *name = "MPU-401 (UART) MIDI"; - memcpy ((char *) devc, (char *) detected_devc, sizeof (uart401_devc)); - detected_devc = NULL; + if (hw_config->name) + name = hw_config->name; - devc->irq = hw_config->irq; - if (devc->irq < 0) - { - devc->share_irq = 1; - devc->irq *= -1; - } - else - devc->share_irq = 0; - - if (devc->irq < 1 || devc->irq > 15) - return; - - if (!devc->share_irq) - if (snd_set_irq_handler (devc->irq, uart401intr, "MPU-401 UART", devc->osp) < 0) - { - printk ("uart401: Failed to allocate IRQ%d\n", devc->irq); - devc->share_irq = 1; - } - - irq2devc[devc->irq] = devc; - devc->my_dev = num_midis; - - request_region (hw_config->io_base, 4, "MPU-401 UART"); - enter_uart_mode (devc); - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - conf_printf (name, hw_config); + if (detected_devc == NULL) + return; + + + devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(uart401_devc))); + sound_mem_sizes[sound_nblocks] = sizeof(uart401_devc); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (devc == NULL) + { + printk(KERN_WARNING "uart401: Can't allocate memory\n"); + return; + } + memcpy((char *) devc, (char *) detected_devc, sizeof(uart401_devc)); + detected_devc = NULL; + + devc->irq = hw_config->irq; + if (devc->irq < 0) + { + devc->share_irq = 1; + devc->irq *= -1; + } else + devc->share_irq = 0; + + if (devc->irq < 1 || devc->irq > 15) + return; + + if (!devc->share_irq) + if (snd_set_irq_handler(devc->irq, uart401intr, "MPU-401 UART", devc->osp) < 0) + { + printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); + devc->share_irq = 1; + } + irq2devc[devc->irq] = devc; + devc->my_dev = sound_alloc_mididev(); + + request_region(hw_config->io_base, 4, "MPU-401 UART"); + enter_uart_mode(devc); + + if (devc->my_dev == -1) + { + printk(KERN_INFO "uart401: Too many midi devices detected\n"); + return; + } + conf_printf(name, hw_config); + + std_midi_synth.midi_dev = devc->my_dev; + + + midi_devs[devc->my_dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[devc->my_dev] == NULL) + { + printk("uart401: Failed to allocate memory\n"); + sound_unload_mididev(devc->my_dev); + return; + } + memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations, + sizeof(struct midi_operations)); + + midi_devs[devc->my_dev]->devc = devc; + + + midi_devs[devc->my_dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); + sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); + + if (sound_nblocks < 1024) + sound_nblocks++; + + if (midi_devs[devc->my_dev]->converter == NULL) + { + printk(KERN_WARNING "uart401: Failed to allocate memory\n"); + sound_unload_mididev(devc->my_dev); + return; + } + memcpy((char *) midi_devs[devc->my_dev]->converter, (char *) &std_midi_synth, + sizeof(struct synth_operations)); + + strcpy(midi_devs[devc->my_dev]->info.name, name); + midi_devs[devc->my_dev]->converter->id = "UART401"; + hw_config->slots[4] = devc->my_dev; + sequencer_init(); + devc->opened = 0; +} - std_midi_synth.midi_dev = devc->my_dev = num_midis; +static int +reset_uart401(uart401_devc * devc) +{ + int ok, timeout, n; + /* + * Send the RESET command. Try again if no success at the first time. + */ - midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct midi_operations); + ok = 0; - if (sound_nblocks < 1024) - sound_nblocks++;; - if (midi_devs[num_midis] == NULL) - { - printk ("uart401: Failed to allocate memory\n"); - return; - } + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - memcpy ((char *) midi_devs[num_midis], (char *) &uart401_operations, - sizeof (struct midi_operations)); + devc->input_byte = 0; + uart401_cmd(devc, MPU_RESET); - midi_devs[num_midis]->devc = devc; + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) /* Interrupt */ + ok = 1; + else if (input_avail(devc)) + if (uart401_read(devc) == MPU_ACK) + ok = 1; - midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof (struct synth_operations); + } - if (sound_nblocks < 1024) - sound_nblocks++;; - if (midi_devs[num_midis]->converter == NULL) - { - printk ("uart401: Failed to allocate memory\n"); - return; - } + if (ok) + { + DEB(printk("Reset UART401 OK\n")); + } else + DDB(printk("Reset UART401 failed - No hardware detected.\n")); - memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, - sizeof (struct synth_operations)); + if (ok) + uart401_input_loop(devc); /* + * Flush input before enabling interrupts + */ - strcpy (midi_devs[num_midis]->info.name, name); - midi_devs[num_midis]->converter->id = "UART401"; - num_midis++; - sequencer_init (); - devc->opened = 0; + return ok; } -static int -reset_uart401 (uart401_devc * devc) +int +probe_uart401(struct address_info *hw_config) { - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); + int ok = 0; + unsigned long flags; - devc->input_byte = 0; - uart401_cmd (devc, MPU_RESET); + static uart401_devc hw_info; + uart401_devc *devc = &hw_info; - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ + DDB(printk("Entered probe_uart401()\n")); - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail (devc)) - if (uart401_read (devc) == MPU_ACK) - ok = 1; + detected_devc = NULL; - } + if (check_region(hw_config->io_base, 4)) + return 0; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->osp = hw_config->osp; + devc->midi_input_intr = NULL; + devc->opened = 0; + devc->input_byte = 0; + devc->my_dev = 0; + devc->share_irq = 0; - if (ok) - { - DEB (printk ("Reset UART401 OK\n")); - } - else - DDB (printk ("Reset UART401 failed - No hardware detected.\n")); + save_flags(flags); + cli(); + ok = reset_uart401(devc); + restore_flags(flags); - if (ok) - uart401_input_loop (devc); /* - * Flush input before enabling interrupts - */ + if (ok) + detected_devc = devc; - return ok; + return ok; } -int -probe_uart401 (struct address_info *hw_config) +void +unload_uart401(struct address_info *hw_config) { - int ok = 0; - unsigned long flags; - - static uart401_devc hw_info; - uart401_devc *devc = &hw_info; - - DDB (printk ("Entered probe_uart401()\n")); + uart401_devc *devc; - detected_devc = NULL; + int irq = hw_config->irq; - if (check_region (hw_config->io_base, 4)) - return 0; + if (irq < 0) + { + irq *= -1; + } + if (irq < 1 || irq > 15) + return; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->osp = hw_config->osp; - devc->midi_input_intr = NULL; - devc->opened = 0; - devc->input_byte = 0; - devc->my_dev = 0; - devc->share_irq = 0; + devc = irq2devc[irq]; + if (devc == NULL) + return; - save_flags (flags); - cli (); - ok = reset_uart401 (devc); - restore_flags (flags); + reset_uart401(devc); + release_region(hw_config->io_base, 4); - if (ok) - detected_devc = devc; + if (!devc->share_irq) + snd_release_irq(devc->irq); - return ok; + /* Free device too !! - AC FIXME: CHECK THIS IS RIGHT */ + if (devc) + vfree(devc); + sound_unload_mididev(hw_config->slots[4]); } -void -unload_uart401 (struct address_info *hw_config) -{ - uart401_devc *devc; - - int irq = hw_config->irq; +#ifdef MODULE - if (irq < 0) - { - irq *= -1; - } +int io = -1; +int irq = -1; - if (irq < 1 || irq > 15) - return; +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +struct address_info hw; - devc = irq2devc[irq]; - if (devc == NULL) - return; - - reset_uart401 (devc); - release_region (hw_config->io_base, 4); +int +init_module(void) +{ + /* Can be loaded either for module use or to provide functions + to others */ + if (io != -1 && irq != -1) + { + printk("MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); + hw.irq = irq; + hw.io_base = io; + if (probe_uart401(&hw) == 0) + return -ENODEV; + attach_uart401(&hw); + } + SOUND_LOCK; + return 0; +} - if (!devc->share_irq) - snd_release_irq (devc->irq); +void +cleanup_module(void) +{ + if (io != -1 && irq != -1) + { + unload_uart401(&hw); + } + /* FREE SYMTAB */ + SOUND_LOCK_END; } +#else #endif + #endif + +EXPORT_SYMBOL(attach_uart401); +EXPORT_SYMBOL(probe_uart401); +EXPORT_SYMBOL(unload_uart401); +EXPORT_SYMBOL(uart401intr); diff -u --recursive --new-file v2.1.66/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.1.66/linux/drivers/sound/uart6850.c Wed Nov 12 13:34:27 1997 +++ linux/drivers/sound/uart6850.c Sat Nov 29 10:33:21 1997 @@ -1,3 +1,6 @@ + + + /* * sound/uart6850.c */ @@ -7,17 +10,20 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver. + * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2. + * */ #include +#include /* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: * added 6850 support, used with COVOX SoundMaster II and custom cards. */ #include "sound_config.h" - -#ifdef CONFIG_UART6850 -#ifdef CONFIG_MIDI +#include "soundmodule.h" +#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) || defined(MODULE) static int uart6850_base = 0x330; @@ -27,27 +33,27 @@ #define COMDPORT (uart6850_base+1) #define STATPORT (uart6850_base+1) -static int -uart6850_status (void) +static int +uart6850_status(void) { - return inb (STATPORT); + return inb(STATPORT); } #define input_avail() (uart6850_status()&INPUT_AVAIL) #define output_ready() (uart6850_status()&OUTPUT_READY) -static void -uart6850_cmd (unsigned char cmd) +static void +uart6850_cmd(unsigned char cmd) { - outb ((cmd), COMDPORT); + outb((cmd), COMDPORT); } -static int -uart6850_read (void) +static int +uart6850_read(void) { - return inb (DATAPORT); + return inb(DATAPORT); } -static void -uart6850_write (unsigned char byte) +static void +uart6850_write(unsigned char byte) { - outb ((byte), DATAPORT); + outb((byte), DATAPORT); } #define OUTPUT_READY 0x02 /* Mask for data ready Bit */ @@ -61,43 +67,42 @@ static int uart6850_detected = 0; static int my_dev; -static int reset_uart6850 (void); +static int reset_uart6850(void); static void (*midi_input_intr) (int dev, unsigned char data); -static void poll_uart6850 (unsigned long dummy); +static void poll_uart6850(unsigned long dummy); static struct timer_list uart6850_timer = {NULL, NULL, 0, 0, poll_uart6850}; static void -uart6850_input_loop (void) +uart6850_input_loop(void) { - int count; + int count; - count = 10; + count = 10; - while (count) /* + while (count) /* * Not timed out */ - if (input_avail ()) - { - unsigned char c = uart6850_read (); - - count = 100; - - if (uart6850_opened & OPEN_READ) - midi_input_intr (my_dev, c); - } - else - while (!input_avail () && count) - count--; + if (input_avail()) + { + unsigned char c = uart6850_read(); + + count = 100; + + if (uart6850_opened & OPEN_READ) + midi_input_intr(my_dev, c); + } else + while (!input_avail() && count) + count--; } void -m6850intr (int irq, void *dev_id, struct pt_regs *dummy) +m6850intr(int irq, void *dev_id, struct pt_regs *dummy) { - if (input_avail ()) - uart6850_input_loop (); + if (input_avail()) + uart6850_input_loop(); } /* @@ -106,135 +111,136 @@ */ static void -poll_uart6850 (unsigned long dummy) +poll_uart6850(unsigned long dummy) { - unsigned long flags; + unsigned long flags; - if (!(uart6850_opened & OPEN_READ)) - return; /* Device has been closed */ + if (!(uart6850_opened & OPEN_READ)) + return; /* Device has been closed */ - save_flags (flags); - cli (); + save_flags(flags); + cli(); - if (input_avail ()) - uart6850_input_loop (); + if (input_avail()) + uart6850_input_loop(); - { - uart6850_timer.expires = (1) + jiffies; - add_timer (&uart6850_timer); - }; /* + { + uart6850_timer.expires = (1) + jiffies; + add_timer(&uart6850_timer); + }; /* * Come back later */ - restore_flags (flags); + restore_flags(flags); } static int -uart6850_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) +uart6850_open(int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) ) { - if (uart6850_opened) - { - printk ("Midi6850: Midi busy\n"); - return -EBUSY; - } - - ; - uart6850_cmd (UART_RESET); - - uart6850_input_loop (); - - midi_input_intr = input; - uart6850_opened = mode; - poll_uart6850 (0); /* + if (uart6850_opened) + { + printk("Midi6850: Midi busy\n"); + return -EBUSY; + }; + + MOD_INC_USE_COUNT; + uart6850_cmd(UART_RESET); + + uart6850_input_loop(); + + midi_input_intr = input; + uart6850_opened = mode; + poll_uart6850(0); /* * Enable input polling */ - return 0; + return 0; } static void -uart6850_close (int dev) +uart6850_close(int dev) { - uart6850_cmd (UART_MODE_ON); + uart6850_cmd(UART_MODE_ON); - del_timer (&uart6850_timer);; - uart6850_opened = 0; + del_timer(&uart6850_timer);; + uart6850_opened = 0; + + MOD_DEC_USE_COUNT; } static int -uart6850_out (int dev, unsigned char midi_byte) +uart6850_out(int dev, unsigned char midi_byte) { - int timeout; - unsigned long flags; - - /* - * Test for input since pending input seems to block the output. - */ - - save_flags (flags); - cli (); - - if (input_avail ()) - uart6850_input_loop (); - - restore_flags (flags); + int timeout; + unsigned long flags; - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* - * Wait - */ - - if (!output_ready ()) - { - printk ("Midi6850: Timeout\n"); - return 0; - } - - uart6850_write (midi_byte); - return 1; + /* + * Test for input since pending input seems to block the output. + */ + + save_flags(flags); + cli(); + + if (input_avail()) + uart6850_input_loop(); + + restore_flags(flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* + * Wait + */ + + if (!output_ready()) + { + printk("Midi6850: Timeout\n"); + return 0; + } + uart6850_write(midi_byte); + return 1; } static int -uart6850_command (int dev, unsigned char *midi_byte) +uart6850_command(int dev, unsigned char *midi_byte) { - return 1; + return 1; } static int -uart6850_start_read (int dev) +uart6850_start_read(int dev) { - return 0; + return 0; } static int -uart6850_end_read (int dev) +uart6850_end_read(int dev) { - return 0; + return 0; } static int -uart6850_ioctl (int dev, unsigned cmd, caddr_t arg) +uart6850_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -EINVAL; } static void -uart6850_kick (int dev) +uart6850_kick(int dev) { } static int -uart6850_buffer_status (int dev) +uart6850_buffer_status(int dev) { - return 0; /* + return 0; /* * No data in buffers */ } @@ -245,92 +251,127 @@ static struct midi_operations uart6850_operations = { - {"6850 UART", 0, 0, SNDCARD_UART6850}, - &std_midi_synth, - {0}, - uart6850_open, - uart6850_close, - uart6850_ioctl, - uart6850_out, - uart6850_start_read, - uart6850_end_read, - uart6850_kick, - uart6850_command, - uart6850_buffer_status + {"6850 UART", 0, 0, SNDCARD_UART6850}, + &std_midi_synth, + {0}, + uart6850_open, + uart6850_close, + uart6850_ioctl, + uart6850_out, + uart6850_start_read, + uart6850_end_read, + uart6850_kick, + uart6850_command, + uart6850_buffer_status }; void -attach_uart6850 (struct address_info *hw_config) +attach_uart6850(struct address_info *hw_config) { - int ok, timeout; - unsigned long flags; - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } + int ok, timeout; + unsigned long flags; - uart6850_base = hw_config->io_base; - uart6850_osp = hw_config->osp; - uart6850_irq = hw_config->irq; - - if (!uart6850_detected) - return; - - save_flags (flags); - cli (); - - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* - * Wait - */ - uart6850_cmd (UART_MODE_ON); - - ok = 1; - - restore_flags (flags); - - conf_printf ("6850 Midi Interface", hw_config); - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &uart6850_operations; - sequencer_init (); + if ((my_dev = sound_alloc_mididev()) == -1) + { + printk(KERN_INFO "uart6850: Too many midi devices detected\n"); + return; + } + uart6850_base = hw_config->io_base; + uart6850_osp = hw_config->osp; + uart6850_irq = hw_config->irq; + + if (!uart6850_detected) + { + sound_unload_mididev(my_dev); + return; + } + save_flags(flags); + cli(); + + for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* + * Wait + */ + uart6850_cmd(UART_MODE_ON); + + ok = 1; + + restore_flags(flags); + + conf_printf("6850 Midi Interface", hw_config); + + std_midi_synth.midi_dev = my_dev; + hw_config->slots[4] = my_dev; + midi_devs[my_dev] = &uart6850_operations; + sequencer_init(); } static int -reset_uart6850 (void) +reset_uart6850(void) { - uart6850_read (); - return 1; /* + uart6850_read(); + return 1; /* * OK */ } int -probe_uart6850 (struct address_info *hw_config) +probe_uart6850(struct address_info *hw_config) { - int ok = 0; + int ok = 0; - uart6850_osp = hw_config->osp; - uart6850_base = hw_config->io_base; - uart6850_irq = hw_config->irq; + uart6850_osp = hw_config->osp; + uart6850_base = hw_config->io_base; + uart6850_irq = hw_config->irq; - if (snd_set_irq_handler (uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0) - return 0; + if (snd_set_irq_handler(uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0) + return 0; - ok = reset_uart6850 (); + ok = reset_uart6850(); - uart6850_detected = ok; - return ok; + uart6850_detected = ok; + return ok; } void -unload_uart6850 (struct address_info *hw_config) +unload_uart6850(struct address_info *hw_config) +{ + snd_release_irq(hw_config->irq); + sound_unload_mididev(hw_config->slots[4]); +} + + +#ifdef MODULE + +int io = -1; +int irq = -1; + +struct address_info cfg; + +int +init_module(void) { - snd_release_irq (hw_config->irq); + if (io == -1 || irq == -1) + { + printk("uart6850: irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + + if (probe_uart6850(&cfg)) + return -ENODEV; + + SOUND_LOCK; + return 0; } +void +cleanup_module(void) +{ + unload_uart6850(&cfg); + SOUND_LOCK_END; +} #endif #endif diff -u --recursive --new-file v2.1.66/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.1.66/linux/drivers/video/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/Config.in Mon Nov 24 01:18:47 1997 @@ -0,0 +1,76 @@ +# +# Video configuration +# + +if [ "$CONFIG_FB" = "y" ]; then + + mainmenu_option next_comment + comment 'Frame buffer devices' + + if [ "$CONFIG_AMIGA" = "y" ]; then + bool 'Amiga native chipset support' CONFIG_FB_AMIGA + if [ "$CONFIG_FB_AMIGA" != "n" ]; then + bool 'Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS + bool 'Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS + bool 'Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA + fi + tristate 'Amiga Cybervision support' CONFIG_FB_CYBER + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 + fi + fi + if [ "$CONFIG_ATARI" = "y" ]; then + bool 'Atari native chipset support' CONFIG_FB_ATARI +# tristate 'Mach64 Frame Buffer support' CONFIG_FB_MACH64 + fi + if [ "$CONFIG_CHRP" = "y" -o "$CONFIG_PMAC" = "y" ]; then + bool 'Open Firmware frame buffer device support' CONFIG_FB_OPEN_FIRMWARE + fi + tristate 'Virtual Frame Buffer support' CONFIG_FB_VIRTUAL + + bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED + if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then + tristate 'Monochrome support' CONFIG_FBCON_MFB + tristate 'Interleaved bitplanes support' CONFIG_FBCON_ILBM + tristate 'Normal bitplanes support' CONFIG_FBCON_AFB + tristate 'Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2 + tristate 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4 + tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 + tristate '8 bpp packed pixel support' CONFIG_FBCON_CFB8 + tristate '16 bpp packed pixel support' CONFIG_FBCON_CFB16 + tristate 'Cybervision support (accelerated)' CONFIG_FBCON_CYBER + tristate 'RetinaZ3 support (accelerated)' CONFIG_FBCON_RETINAZ3 + else + if [ "$CONFIG_FB_AMIGA" != "n" -o "$CONFIG_FB_ATARI" != "n" -o \ + "$CONFIG_FB_CYBER" != "n" -o "$CONFIG_FB_RETINAZ3" != "n" -o \ + "$CONFIG_FB_VIRTUAL" != "n" ]; then + define_bool CONFIG_FBCON_MFB y + fi + if [ "$CONFIG_FB_AMIGA" = "y" -o "$CONFIG_FB_AMIGA" = "m" ]; then + define_bool CONFIG_FBCON_ILBM y + define_bool CONFIG_FBCON_AFB y + fi + if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" ]; then + define_bool CONFIG_FBCON_IPLAN2P2 y + define_bool CONFIG_FBCON_IPLAN2P4 y + define_bool CONFIG_FBCON_IPLAN2P8 y + fi + if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \ + "$CONFIG_FB_OPEN_FIRMWARE" = "y" -o \ + "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + define_bool CONFIG_FBCON_CFB8 y + fi + if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \ + "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then + define_bool CONFIG_FBCON_CFB16 y + fi + if [ "$CONFIG_FB_CYBER" = "y" -o "$CONFIG_FB_CYBER" = "m" ]; then + define_bool CONFIG_FBCON_CYBER y + fi + if [ "$CONFIG_FB_RETINAZ3" = "y" -o "$CONFIG_FB_RETINAZ3" = "m" ]; then + define_bool CONFIG_FBCON_RETINAZ3 y + fi + fi + + endmenu +fi diff -u --recursive --new-file v2.1.66/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.1.66/linux/drivers/video/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/Makefile Tue Nov 25 02:37:04 1997 @@ -0,0 +1,199 @@ +# +# Makefile for the kernel video drivers. +# +# 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 definitions are now inherited from the +# parent makes.. +# + +GSPA = gspa +GSPH2C = gspahextoc + +L_TARGET := video.a +L_OBJS := +M_OBJS := +LX_OBJS := +MX_OBJS := +MOD_LIST_NAME := VIDEO_MODULES + +# Frame Buffer Console + +ifeq ($(CONFIG_FB),y) + L_OBJS += fonts.o font_8x8.o font_8x16.o pearl_8x8.o + LX_OBJS += fbcon.o fbcmap.o +endif + +# Frame buffer devices + +ifeq ($(CONFIG_APOLLO),y) +L_OBJS += dn_fb.o +endif + +ifeq ($(CONFIG_FB_AMIGA),y) +L_OBJS += amifb.o +else + ifeq ($(CONFIG_FB_AMIGA),m) + M_OBJS += amifb.o + endif +endif + +ifeq ($(CONFIG_FB_ATARI),y) +L_OBJS += atafb.o +else + ifeq ($(CONFIG_FB_ATARI),m) + M_OBJS += atafb.o + endif +endif + +ifeq ($(CONFIG_FB_CYBER),y) +LX_OBJS += cyberfb.o +else + ifeq ($(CONFIG_FB_CYBER),m) + MX_OBJS += cyberfb.o + endif +endif + +ifeq ($(CONFIG_FB_RETINAZ3),y) +LX_OBJS += retz3fb.o +else + ifeq ($(CONFIG_FB_RETINAZ3),m) + MX_OBJS += retz3fb.o + endif +endif + +ifeq ($(CONFIG_FB_VIRTUAL),y) +L_OBJS += vfb.o +else + ifeq ($(CONFIG_FB_VIRTUAL),m) + M_OBJS += vfb.o + endif +endif + +ifeq ($(CONFIG_FB_OPEN_FIRMWARE),y) +L_OBJS += offb.o +endif + +ifeq ($(CONFIG_FB_MACH64),y) +L_OBJS += mach64fb.o +else + ifeq ($(CONFIG_FB_MACH64),m) + M_OBJS += mach64fb.o + endif +endif + +ifeq ($(CONFIG_FB_TGA),y) +L_OBJS += tgafb.o +endif + +# Low level drivers + +ifeq ($(CONFIG_FBCON_AFB),y) +L_OBJS += fbcon-afb.o +else + ifeq ($(CONFIG_FBCON_AFB),m) + M_OBJS += fbcon-afb.o + endif +endif + +ifeq ($(CONFIG_FBCON_CFB8),y) +L_OBJS += fbcon-cfb8.o +else + ifeq ($(CONFIG_FBCON_CFB8),m) + M_OBJS += fbcon-cfb8.o + endif +endif + +ifeq ($(CONFIG_FBCON_CFB16),y) +LX_OBJS += fbcon-cfb16.o +else + ifeq ($(CONFIG_FBCON_CFB16),m) + MX_OBJS += fbcon-cfb16.o + endif +endif + +ifeq ($(CONFIG_FBCON_ILBM),y) +L_OBJS += fbcon-ilbm.o +else + ifeq ($(CONFIG_FBCON_ILBM),m) + M_OBJS += fbcon-ilbm.o + endif +endif + +ifeq ($(CONFIG_FBCON_IPLAN2P2),y) +L_OBJS += fbcon-iplan2p2.o +else + ifeq ($(CONFIG_FBCON_IPLAN2P2),m) + M_OBJS += fbcon-iplan2p2.o + endif +endif + +ifeq ($(CONFIG_FBCON_IPLAN2P4),y) +L_OBJS += fbcon-iplan2p4.o +else + ifeq ($(CONFIG_FBCON_IPLAN2P4),m) + M_OBJS += fbcon-iplan2p4.o + endif +endif + +ifeq ($(CONFIG_FBCON_IPLAN2P8),y) +L_OBJS += fbcon-iplan2p8.o +else + ifeq ($(CONFIG_FBCON_IPLAN2P8),m) + M_OBJS += fbcon-iplan2p8.o + endif +endif + +ifeq ($(CONFIG_FBCON_MFB),y) +L_OBJS += fbcon-mfb.o +else + ifeq ($(CONFIG_FBCON_MFB),m) + M_OBJS += fbcon-mfb.o + endif +endif + +ifeq ($(CONFIG_FBCON_CYBER),y) +L_OBJS += fbcon-cyber.o +else + ifeq ($(CONFIG_FBCON_CYBER),m) + M_OBJS += fbcon-cyber.o + endif +endif + +ifeq ($(CONFIG_FBCON_RETINAZ3),y) +L_OBJS += fbcon-retz3.o +else + ifeq ($(CONFIG_FBCON_RETINAZ3),m) + M_OBJS += fbcon-retz3.o + endif +endif + +ifeq ($(CONFIG_FBCON_MACH64),y) +L_OBJS += fbcon-mach64.o +else + ifeq ($(CONFIG_FBCON_MACH64),m) + M_OBJS += fbcon-mach64.o + endif +endif + +# GSP Console + +ifdef CONFIG_AMIGA_GSP +L_OBJS := $(L_OBJS) gspcon.o gspcore.o +endif + +# VGA Console + +ifdef CONFIG_ABSTRACT_CONSOLE +ifdef CONFIG_VGA_CONSOLE +L_OBJS := $(L_OBJS) vgacon.o +endif +endif + +include $(TOPDIR)/Rules.make + +gspcore.c: gspcore.gsp + $(GSPA) $< > $*.hex + $(GSPH2C) $*.hex > gspcore.c diff -u --recursive --new-file v2.1.66/linux/drivers/video/amifb.c linux/drivers/video/amifb.c --- v2.1.66/linux/drivers/video/amifb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/amifb.c Mon Nov 24 01:18:49 1997 @@ -0,0 +1,3520 @@ +/* + * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * with work by Roman Zippel + * + * + * This file is based on the Atari frame buffer device (atafb.c): + * + * Copyright (C) 1994 Martin Schaller + * Roman Hodek + * + * with work by Andreas Schwab + * Guenther Kelleter + * + * and on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * + * + * History: + * + * - 24 Jul 96: Copper generates now vblank interrupt and + * VESA Power Saving Protocol is fully implemented + * - 14 Jul 96: Rework and hopefully last ECS bugs fixed + * - 7 Mar 96: Hardware sprite support by Roman Zippel + * - 18 Feb 96: OCS and ECS support by Roman Zippel + * Hardware functions completely rewritten + * - 2 Dec 95: AGA version by Geert Uytterhoeven + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DEBUG + +#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA) +#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */ +#endif + +#if !defined(CONFIG_FB_AMIGA_OCS) +# define IS_OCS (0) +#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA) +# define IS_OCS (chipset == TAG_OCS) +#else +# define CONFIG_FB_AMIGA_OCS_ONLY +# define IS_OCS (1) +#endif + +#if !defined(CONFIG_FB_AMIGA_ECS) +# define IS_ECS (0) +#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA) +# define IS_ECS (chipset == TAG_ECS) +#else +# define CONFIG_FB_AMIGA_ECS_ONLY +# define IS_ECS (1) +#endif + +#if !defined(CONFIG_FB_AMIGA_AGA) +# define IS_AGA (0) +#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS) +# define IS_AGA (chipset == TAG_AGA) +#else +# define CONFIG_FB_AMIGA_AGA_ONLY +# define IS_AGA (1) +#endif + +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/******************************************************************************* + + + Generic video timings + --------------------- + + Timings used by the frame buffer interface: + + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |upper_margin | | | + | | ¥ | | | + +----------###############################################----------+-------+ + | # ^ # | | + | # | # | | + | # | # | | + | # | # | | + | left # | # right | hsync | + | margin # | xres # margin | len | + |<-------->#<---------------+--------------------------->#<-------->|<----->| + | # | # | | + | # | # | | + | # | # | | + | # |yres # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # ¥ # | | + +----------###############################################----------+-------+ + | | ^ | | | + | | |lower_margin | | | + | | ¥ | | | + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | ¥ | | | + +----------+---------------------------------------------+----------+-------+ + + + Amiga video timings + ------------------- + + The Amiga native chipsets uses another timing scheme: + + - hsstrt: Start of horizontal synchronization pulse + - hsstop: End of horizontal synchronization pulse + - htotal: Last value on the line (i.e. line length = htotal+1) + - vsstrt: Start of vertical synchronization pulse + - vsstop: End of vertical synchronization pulse + - vtotal: Last line value (i.e. number of lines = vtotal+1) + - hcenter: Start of vertical retrace for interlace + + You can specify the blanking timings independently. Currently I just set + them equal to the respective synchronization values: + + - hbstrt: Start of horizontal blank + - hbstop: End of horizontal blank + - vbstrt: Start of vertical blank + - vbstop: End of vertical blank + + Horizontal values are in color clock cycles (280 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Amiga visible window definitions + -------------------------------- + + Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to + make corrections and/or additions. + + Within the above synchronization specifications, the visible window is + defined by the following parameters (actual register resolutions may be + different; all horizontal values are normalized with respect to the pixel + clock): + + - diwstrt_h: Horizontal start of the visible window + - diwstop_h: Horizontal stop+1(*) of the visible window + - diwstrt_v: Vertical start of the visible window + - diwstop_v: Vertical stop of the visible window + - ddfstrt: Horizontal start of display DMA + - ddfstop: Horizontal stop of display DMA + - hscroll: Horizontal display output delay + + Sprite positioning: + + - sprstrt_h: Horizontal start-4 of sprite + - sprstrt_v: Vertical start of sprite + + (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. + + Horizontal values are in dotclock cycles (35 ns), vertical values are in + scanlines. + + (0, 0) is somewhere in the upper-left corner :-) + + + Dependencies (AGA, SHRES (35 ns dotclock)) + ------------------------------------------- + + Since there are much more parameters for the Amiga display than for the + frame buffer interface, there must be some dependencies among the Amiga + display parameters. Here's what I found out: + + - ddfstrt and ddfstop are best aligned to 64 pixels. + - the chipset needs 64+4 horizontal pixels after the DMA start before the + first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to + display the first pixel on the line too. Increase diwstrt_h for virtual + screen panning. + - the display DMA always fetches 64 pixels at a time (fmode = 3). + - ddfstop is ddfstrt+#pixels-64. + - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1 + more than htotal. + - hscroll simply adds a delay to the display output. Smooth horizontal + panning needs an extra 64 pixels on the left to prefetch the pixels that + `fall off' on the left. + - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane + DMA, so it's best to make the DMA start as late as possible. + - you really don't want to make ddfstrt < 128, since this will steal DMA + cycles from the other DMA channels (audio, floppy and Chip RAM refresh). + - I make diwstop_h and diwstop_v as large as possible. + + General dependencies + -------------------- + + - all values are SHRES pixel (35ns) + + table 1:fetchstart table 2:prefetch table 3:fetchsize + ------------------ ---------------- ----------------- + Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES + -------------#------+-----+------#------+-----+------#------+-----+------ + Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 + Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128 + Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256 + + - chipset needs 4 pixels before the first pixel is output + - ddfstrt must be aligned to fetchstart (table 1) + - chipset needs also prefetch (table 2) to get first pixel data, so + ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch + - for horizontal panning decrease diwstrt_h + - the length of a fetchline must be aligned to fetchsize (table 3) + - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit + moved to optimize use of dma (usefull for OCS/ECS overscan displays) + - ddfstop is ddfstrt+ddfsize-fetchsize + - If C= didn't change anything for AGA, then at following positions the + dma bus is allready used: + ddfstrt < 48 -> memory refresh + < 96 -> disk dma + < 160 -> audio dma + < 192 -> sprite 0 dma + < 416 -> sprite dma (32 per sprite) + - in accordance with the hardware reference manual a hardware stop is at + 192, but AGA (ECS?) can go below this. + + DMA priorities + -------------- + + Since there are limits on the earliest start value for display DMA and the + display of sprites, I use the following policy on horizontal panning and + the hardware cursor: + + - if you want to start display DMA too early, you loose the ability to + do smooth horizontal panning (xpanstep 1 -> 64). + - if you want to go even further, you loose the hardware cursor too. + + IMHO a hardware cursor is more important for X than horizontal scrolling, + so that's my motivation. + + + Implementation + -------------- + + ami_decode_var() converts the frame buffer values to the Amiga values. It's + just a `straightforward' implementation of the above rules. + + + Standard VGA timings + -------------------- + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + 80x25 720 400 27 45 35 12 108 2 + 80x30 720 480 27 45 30 9 108 2 + + These were taken from a XFree86 configuration file, recalculated for a 28 MHz + dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer + generic timings. + + As a comparison, graphics/monitor.h suggests the following: + + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- + + VGA 640 480 52 112 24 19 112 - 2 + + VGA70 640 400 52 112 27 21 112 - 2 - + + + Sync polarities + --------------- + + VSYNC HSYNC Vertical size Vertical total + ----- ----- ------------- -------------- + + + Reserved Reserved + + - 400 414 + - + 350 362 + - - 480 496 + + Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 + + + Broadcast video timings + ----------------------- + + According to the CCIR and RETMA specifications, we have the following values: + + CCIR -> PAL + ----------- + + - a scanline is 64 µs long, of which 52.48 µs are visible. This is about + 736 visible 70 ns pixels per line. + - we have 625 scanlines, of which 575 are visible (interlaced); after + rounding this becomes 576. + + RETMA -> NTSC + ------------- + + - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about + 736 visible 70 ns pixels per line. + - we have 525 scanlines, of which 485 are visible (interlaced); after + rounding this becomes 484. + + Thus if you want a PAL compatible display, you have to do the following: + + - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast + timings are to be used. + - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an + interlaced, 312 for a non-interlaced and 156 for a doublescanned + display. + - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES, + 908 for a HIRES and 454 for a LORES display. + - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), + left_margin+2*hsync_len must be greater or equal. + - the upper visible part begins at 48 (interlaced; non-interlaced:24, + doublescanned:12), upper_margin+2*vsync_len must be greater or equal. + - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync + of 4 scanlines + + The settings for a NTSC compatible display are straightforward. + + Note that in a strict sense the PAL and NTSC standards only define the + encoding of the color part (chrominance) of the video signal and don't say + anything about horizontal/vertical synchronization nor refresh rates. + + + -- Geert -- + +*******************************************************************************/ + + + /* + * Custom Chipset Definitions + */ + +#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) + + /* + * BPLCON0 -- Bitplane Control Register 0 + */ + +#define BPC0_HIRES (0x8000) +#define BPC0_BPU2 (0x4000) /* Bit plane used count */ +#define BPC0_BPU1 (0x2000) +#define BPC0_BPU0 (0x1000) +#define BPC0_HAM (0x0800) /* HAM mode */ +#define BPC0_DPF (0x0400) /* Double playfield */ +#define BPC0_COLOR (0x0200) /* Enable colorburst */ +#define BPC0_GAUD (0x0100) /* Genlock audio enable */ +#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ +#define BPC0_SHRES (0x0040) /* Super hi res mode */ +#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ +#define BPC0_BPU3 (0x0010) /* AGA */ +#define BPC0_LPEN (0x0008) /* Light pen enable */ +#define BPC0_LACE (0x0004) /* Interlace */ +#define BPC0_ERSY (0x0002) /* External resync */ +#define BPC0_ECSENA (0x0001) /* ECS enable */ + + /* + * BPLCON2 -- Bitplane Control Register 2 + */ + +#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ +#define BPC2_ZDBPSEL1 (0x2000) +#define BPC2_ZDBPSEL0 (0x1000) +#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ +#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ +#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ +#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ +#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ +#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ +#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ +#define BPC2_PF2P1 (0x0010) +#define BPC2_PF2P0 (0x0008) +#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ +#define BPC2_PF1P1 (0x0002) +#define BPC2_PF1P0 (0x0001) + + /* + * BPLCON3 -- Bitplane Control Register 3 (AGA) + */ + +#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ +#define BPC3_BANK1 (0x4000) +#define BPC3_BANK0 (0x2000) +#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ +#define BPC3_PF2OF1 (0x0800) +#define BPC3_PF2OF0 (0x0400) +#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ +#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ +#define BPC3_SPRES0 (0x0040) +#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ +#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ +#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ +#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ +#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ + + /* + * BPLCON4 -- Bitplane Control Register 4 (AGA) + */ + +#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ +#define BPC4_BPLAM6 (0x4000) +#define BPC4_BPLAM5 (0x2000) +#define BPC4_BPLAM4 (0x1000) +#define BPC4_BPLAM3 (0x0800) +#define BPC4_BPLAM2 (0x0400) +#define BPC4_BPLAM1 (0x0200) +#define BPC4_BPLAM0 (0x0100) +#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ +#define BPC4_ESPRM6 (0x0040) +#define BPC4_ESPRM5 (0x0020) +#define BPC4_ESPRM4 (0x0010) +#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ +#define BPC4_OSPRM6 (0x0004) +#define BPC4_OSPRM5 (0x0002) +#define BPC4_OSPRM4 (0x0001) + + /* + * BEAMCON0 -- Beam Control Register + */ + +#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ +#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ +#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ +#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ +#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ +#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ +#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ +#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ +#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */ +#define BMC0_PAL (0x0020) /* Set decodes for PAL */ +#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ +#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ +#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ +#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ +#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ + + + /* + * FMODE -- Fetch Mode Control Register (AGA) + */ + +#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ +#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ +#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ +#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ +#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ +#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ + + /* + * Tags used to indicate a specific Pixel Clock + * + * clk_shift is the shift value to get the timings in 35 ns units + */ + +enum { TAG_SHRES, TAG_HIRES, TAG_LORES }; + + /* + * Tags used to indicate the specific chipset + */ + +enum { TAG_OCS, TAG_ECS, TAG_AGA }; + + /* + * Tags used to indicate the memory bandwidth + */ + +enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 }; + + + /* + * Clock Definitions, Maximum Display Depth + * + * These depend on the E-Clock or the Chipset, so they are filled in + * dynamically + */ + +static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ +static u_short maxfmode, chipset; + + + /* + * Broadcast Video Timings + * + * Horizontal values are in 35 ns (SHRES) units + * Vertical values are in interlaced scanlines + */ + +#define PAL_DIWSTRT_H (360) /* PAL Window Limits */ +#define PAL_DIWSTRT_V (48) +#define PAL_HTOTAL (1816) +#define PAL_VTOTAL (625) + +#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */ +#define NTSC_DIWSTRT_V (40) +#define NTSC_HTOTAL (1816) +#define NTSC_VTOTAL (525) + + + /* + * Monitor Specifications + * + * These are typical for a `generic' Amiga monitor (e.g. A1960) + */ + +static long vfmin = 50, vfmax = 90, hfmin = 15000, hfmax = 38000; + + + /* + * Various macros + */ + +#define up2(v) (((v)+1) & -2) +#define down2(v) ((v) & -2) +#define div2(v) ((v)>>1) +#define mod2(v) ((v) & 1) + +#define up4(v) (((v)+3) & -4) +#define down4(v) ((v) & -4) +#define mul4(v) ((v)<<2) +#define div4(v) ((v)>>2) +#define mod4(v) ((v) & 3) + +#define up8(v) (((v)+7) & -8) +#define down8(v) ((v) & -8) +#define div8(v) ((v)>>3) +#define mod8(v) ((v) & 7) + +#define up16(v) (((v)+15) & -16) +#define down16(v) ((v) & -16) +#define div16(v) ((v)>>4) +#define mod16(v) ((v) & 15) + +#define up32(v) (((v)+31) & -32) +#define down32(v) ((v) & -32) +#define div32(v) ((v)>>5) +#define mod32(v) ((v) & 31) + +#define up64(v) (((v)+63) & -64) +#define down64(v) ((v) & -64) +#define div64(v) ((v)>>6) +#define mod64(v) ((v) & 63) + +#define upx(x,v) (((v)+(x)-1) & -(x)) +#define downx(x,v) ((v) & -(x)) +#define modx(x,v) ((v) & ((x)-1)) + +/* if x1 is not a constant, this macro won't make real sense :-) */ +#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ + "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;}) + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#define highw(x) ((u_long)(x)>>16 & 0xffff) +#define loww(x) ((u_long)(x) & 0xffff) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER +#define VBlankOff() custom.intena = IF_COPER + + + /* + * Chip RAM we reserve for the Frame Buffer + * + * This defines the Maximum Virtual Screen Size + * (Setable per kernel options?) + */ + +#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */ +#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */ +#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */ +#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ +#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ + +#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ +#define DUMMYSPRITEMEMSIZE (8) + +#define CHIPRAM_SAFETY_LIMIT (16384) + +static u_long videomemory, spritememory; +static u_long videomemorysize; + + /* + * This is the earliest allowed start of fetching display data. + * Only if you really want no hardware cursor and audio, + * set this to 128, but let it better at 192 + */ + +static u_long min_fstrt = 192; + +#define assignchunk(name, type, ptr, size) \ +{ \ + (name) = (type)(ptr); \ + ptr += size; \ +} + + + /* + * Copper Instructions + */ + +#define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val)) +#define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val)) +#define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe) +#define CEND (0xfffffffe) + + +typedef union { + u_long l; + u_short w[2]; +} copins; + +static struct copdisplay { + copins *init; + copins *wait; + copins *list[2][2]; + copins *rebuild[2]; +} copdisplay; + +static u_short currentcop = 0; + + /* + * Hardware Cursor + */ + +static int cursorrate = 20; /* Number of frames/flash toggle */ +static u_short cursorstate = -1; +static u_short cursormode = FB_CURSOR_OFF; + +static u_short *lofsprite, *shfsprite, *dummysprite; + + /* + * Current Video Mode + */ + +static struct amiga_fb_par { + + /* General Values */ + + int xres; /* vmode */ + int yres; /* vmode */ + int vxres; /* vmode */ + int vyres; /* vmode */ + int xoffset; /* vmode */ + int yoffset; /* vmode */ + u_short bpp; /* vmode */ + u_short clk_shift; /* vmode */ + u_short line_shift; /* vmode */ + int vmode; /* vmode */ + u_short diwstrt_h; /* vmode */ + u_short diwstop_h; /* vmode */ + u_short diwstrt_v; /* vmode */ + u_short diwstop_v; /* vmode */ + u_long next_line; /* modulo for next line */ + u_long next_plane; /* modulo for next plane */ + + /* Cursor Values */ + + struct { + short crsr_x; /* movecursor */ + short crsr_y; /* movecursor */ + short spot_x; + short spot_y; + u_short height; + u_short width; + u_short fmode; + } crsr; + + /* OCS Hardware Registers */ + + u_long bplpt0; /* vmode, pan (Note: physical address) */ + u_long bplpt0wrap; /* vmode, pan (Note: physical address) */ + u_short ddfstrt; + u_short ddfstop; + u_short bpl1mod; + u_short bpl2mod; + u_short bplcon0; /* vmode */ + u_short bplcon1; /* vmode */ + u_short htotal; /* vmode */ + u_short vtotal; /* vmode */ + + /* Additional ECS Hardware Registers */ + + u_short bplcon3; /* vmode */ + u_short beamcon0; /* vmode */ + u_short hsstrt; /* vmode */ + u_short hsstop; /* vmode */ + u_short hbstrt; /* vmode */ + u_short hbstop; /* vmode */ + u_short vsstrt; /* vmode */ + u_short vsstop; /* vmode */ + u_short vbstrt; /* vmode */ + u_short vbstop; /* vmode */ + u_short hcenter; /* vmode */ + + /* Additional AGA Hardware Registers */ + + u_short fmode; /* vmode */ +} currentpar; + +static int currcon = 0; + +static struct display disp; +static struct fb_info fb_info; + + + /* + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * (Imported from arch/m68k/amiga/amisound.c) + */ + +extern volatile u_short amiga_audio_min_period; + + /* + * Since we can't read the palette on OCS/ECS, and since reading one + * single color palette entry require 5 expensive custom chip bus accesses + * on AGA, we keep a copy of the current palette. + */ + +#if defined(CONFIG_FB_AMIGA_AGA) +static struct { u_char red, green, blue, pad; } palette[256]; +#else +static struct { u_char red, green, blue, pad; } palette[32]; +#endif + +#if defined(CONFIG_FB_AMIGA_ECS) +static u_short ecs_palette[32]; +#endif + + /* + * Latches for Display Changes during VBlank + */ + +static u_short do_vmode_full = 0; /* Change the Video Mode */ +static u_short do_vmode_pan = 0; /* Update the Video Mode */ +static short do_blank = 0; /* (Un)Blank the Screen (±1) */ +static u_short do_cursor = 0; /* Move the Cursor */ + + + /* + * Various Flags + */ + +static u_short is_blanked = 0; /* Screen is Blanked */ +static u_short is_lace = 0; /* Screen is laced */ + + /* + * Frame Buffer Name + * + * The rest of the name is filled in during initialization + */ + +static char amiga_fb_name[16] = "Amiga "; + + /* + * Predefined Video Mode Names + * + * The a2024-?? modes don't work yet because there's no A2024 driver. + */ + +static char *amiga_fb_modenames[] = { + + /* + * Autodetect (Default) Video Mode + */ + + "default", + + /* + * AmigaOS Video Modes + */ + + "ntsc", /* 640x200, 15 kHz, 60 Hz (NTSC) */ + "ntsc-lace", /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ + "pal", /* 640x256, 15 kHz, 50 Hz (PAL) */ + "pal-lace", /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ + "multiscan", /* 640x480, 29 kHz, 57 Hz */ + "multiscan-lace", /* 640x960, 29 kHz, 57 Hz interlaced */ + "a2024-10", /* 1024x800, 10 Hz (Not yet supported) */ + "a2024-15", /* 1024x800, 15 Hz (Not yet supported) */ + "euro36", /* 640x200, 15 kHz, 72 Hz */ + "euro36-lace", /* 640x400, 15 kHz, 72 Hz interlaced */ + "euro72", /* 640x400, 29 kHz, 68 Hz */ + "euro72-lace", /* 640x800, 29 kHz, 68 Hz interlaced */ + "super72", /* 800x300, 23 kHz, 70 Hz */ + "super72-lace", /* 800x600, 23 kHz, 70 Hz interlaced */ + "dblntsc", /* 640x200, 27 kHz, 57 Hz doublescan */ + "dblntsc-ff", /* 640x400, 27 kHz, 57 Hz */ + "dblntsc-lace", /* 640x800, 27 kHz, 57 Hz interlaced */ + "dblpal", /* 640x256, 27 kHz, 47 Hz doublescan */ + "dblpal-ff", /* 640x512, 27 kHz, 47 Hz */ + "dblpal-lace", /* 640x1024, 27 kHz, 47 Hz interlaced */ + + /* + * VGA Video Modes + */ + + "vga", /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga70", /* 640x400, 31 kHz, 70 Hz (VGA) */ + + /* + * User Defined Video Modes: to be set after boot up using e.g. fbset + */ + + "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7" +}; + +static struct fb_var_screeninfo amiga_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { 0, }, + + /* + * AmigaOS Video Modes + */ + + { + /* ntsc */ + 640, 200, 640, 200, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 44, 16, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* ntsc-lace */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 88, 33, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* pal */ + 640, 256, 640, 256, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 40, 14, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* pal-lace */ + 640, 512, 640, 512, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 106, 86, 80, 29, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* multiscan */ + 640, 480, 640, 480, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 29, 8, 72, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + + }, { + /* multiscan-lace */ + 640, 960, 640, 960, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 96, 112, 58, 16, 72, 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* a2024-10 (Not yet supported) */ + 1024, 800, 1024, 800, 0, 0, 2, 0, + {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* a2024-15 (Not yet supported) */ + 1024, 800, 1024, 800, 0, 0, 2, 0, + {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* euro36 */ + 640, 200, 640, 200, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 6, 6, 52, 5, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* euro36-lace */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_HIRES, 92, 124, 12, 12, 52, 10, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* euro72 */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* euro72-lace */ + 640, 800, 640, 800, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 164, 92, 18, 18, 80, 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* super72 */ + 800, 300, 800, 300, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 10, 11, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* super72-lace */ + 800, 600, 800, 600, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 212, 140, 20, 22, 80, 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* dblntsc */ + 640, 200, 640, 200, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 18, 17, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* dblntsc-ff */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 36, 35, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* dblntsc-lace */ + 640, 800, 640, 800, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 72, 70, 80, 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* dblpal */ + 640, 256, 640, 256, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 14, 13, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* dblpal-ff */ + 640, 512, 640, 512, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 28, 27, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* dblpal-lace */ + 640, 1024, 640, 1024, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 196, 124, 56, 54, 80, 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, + + /* + * VGA Video Modes + */ + + { + /* vga */ + 640, 480, 640, 480, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 30, 9, 112, 2, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* vga70 */ + 640, 400, 640, 400, 0, 0, 4, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, TAG_SHRES, 64, 96, 35, 12, 112, 2, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, + + /* + * User Defined Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + +#define NUM_USER_MODES (8) +#define NUM_TOTAL_MODES arraysize(amiga_fb_predefined) +#define NUM_PREDEF_MODES (NUM_TOTAL_MODES-NUM_USER_MODES) + +static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ + +static int amifb_inverse = 0; +static int amifb_usermode = 0; + + /* + * Some default modes + */ + +#define DEFMODE_PAL "pal" /* for PAL OCS/ECS */ +#define DEFMODE_NTSC "ntsc" /* for NTSC OCS/ECS */ +#define DEFMODE_AMBER_PAL "pal-lace" /* for flicker fixed PAL (A3000) */ +#define DEFMODE_AMBER_NTSC "ntsc-lace" /* for flicker fixed NTSC (A3000) */ +#define DEFMODE_AGA "vga70" /* for AGA */ + + /* + * Macros for the conversion from real world values to hardware register + * values + * + * This helps us to keep our attention on the real stuff... + * + * Hardware limits for AGA: + * + * parameter min max step + * --------- --- ---- ---- + * diwstrt_h 0 2047 1 + * diwstrt_v 0 2047 1 + * diwstop_h 0 4095 1 + * diwstop_v 0 4095 1 + * + * ddfstrt 0 2032 16 + * ddfstop 0 2032 16 + * + * htotal 8 2048 8 + * hsstrt 0 2040 8 + * hsstop 0 2040 8 + * vtotal 1 4096 1 + * vsstrt 0 4095 1 + * vsstop 0 4095 1 + * hcenter 0 2040 8 + * + * hbstrt 0 2047 1 + * hbstop 0 2047 1 + * vbstrt 0 4095 1 + * vbstop 0 4095 1 + * + * Horizontal values are in 35 ns (SHRES) pixels + * Vertical values are in half scanlines + */ + +/* bplcon1 (smooth scrolling) */ + +#define hscroll2hw(hscroll) \ + (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ + ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f)) + +/* diwstrt/diwstop/diwhigh (visible display window) */ + +#define diwstrt2hw(diwstrt_h, diwstrt_v) \ + (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) +#define diwstop2hw(diwstop_h, diwstop_v) \ + (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) +#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ + (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ + ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ + ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) + +/* ddfstrt/ddfstop (display DMA) */ + +#define ddfstrt2hw(ddfstrt) div8(ddfstrt) +#define ddfstop2hw(ddfstop) div8(ddfstop) + +/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */ + +#define hsstrt2hw(hsstrt) (div8(hsstrt)) +#define hsstop2hw(hsstop) (div8(hsstop)) +#define htotal2hw(htotal) (div8(htotal)-1) +#define vsstrt2hw(vsstrt) (div2(vsstrt)) +#define vsstop2hw(vsstop) (div2(vsstop)) +#define vtotal2hw(vtotal) (div2(vtotal)-1) +#define hcenter2hw(htotal) (div8(htotal)) + +/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ + +#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) +#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) +#define vbstrt2hw(vbstrt) (div2(vbstrt)) +#define vbstop2hw(vbstop) (div2(vbstop)) + +/* colour */ + +#define rgb2hw8_high(red, green, blue) \ + (((red)<<4 & 0xf00) | ((green) & 0x0f0) | ((blue)>>4 & 0x00f)) +#define rgb2hw8_low(red, green, blue) \ + (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f)) +#define rgb2hw4(red, green, blue) \ + (((red)<<8 & 0xf00) | ((green)<<4 & 0x0f0) | ((blue) & 0x00f)) +#define rgb2hw2(red, green, blue) \ + (((red)<<10 & 0xc00) | ((green)<<6 & 0x0c0) | ((blue)<<2 & 0x00c)) + +/* sprpos/sprctl (sprite positioning) */ + +#define spr2hw_pos(start_v, start_h) \ + (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff)) +#define spr2hw_ctl(start_v, start_h, stop_v) \ + (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \ + ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \ + ((start_h)>>2&0x0001)) + +/* get current vertical position of beam */ +#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) + + /* + * Copper Initialisation List + */ + +#define COPINITSIZE (sizeof(copins)*40) + +enum { + cip_bplcon0 +}; + + /* + * Long Frame/Short Frame Copper List + * Don't change the order, build_copper()/rebuild_copper() rely on this + */ + +#define COPLISTSIZE (sizeof(copins)*64) + +enum { + cop_wait, cop_bplcon0, + cop_spr0ptrh, cop_spr0ptrl, + cop_diwstrt, cop_diwstop, + cop_diwhigh, +}; + + /* + * Pixel modes for Bitplanes and Sprites + */ + +static u_short bplpixmode[3] = { + BPC0_SHRES, /* 35 ns */ + BPC0_HIRES, /* 70 ns */ + 0 /* 140 ns */ +}; + +static u_short sprpixmode[3] = { + BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ + BPC3_SPRES1, /* 70 ns */ + BPC3_SPRES0 /* 140 ns */ +}; + + /* + * Fetch modes for Bitplanes and Sprites + */ + +static u_short bplfetchmode[3] = { + 0, /* 1x */ + FMODE_BPL32, /* 2x */ + FMODE_BPAGEM | FMODE_BPL32 /* 4x */ +}; + +static u_short sprfetchmode[3] = { + 0, /* 1x */ + FMODE_SPR32, /* 2x */ + FMODE_SPAGEM | FMODE_SPR32 /* 4x */ +}; + + + /* + * Interface used by the world + */ + +void amiga_video_setup(char *options, int *ints); + +static int amiga_fb_open(int fbidx); +static int amiga_fb_release(int fbidx); +static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con); +static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con); +static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int amiga_fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con); + +static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con); +static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con); +static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con); +static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con); +static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con); + + /* + * Interface to the low level console driver + */ + +unsigned long amiga_fb_init(unsigned long mem_start); +static int amifbcon_switch(int con); +static int amifbcon_updatevar(int con); +static void amifbcon_blank(int blank); +static int amifbcon_setcmap(struct fb_cmap *cmap, int con); + + /* + * Internal routines + */ + +static void do_install_cmap(int con); +static int flash_cursor(void); +static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp); +static void get_video_mode(const char *name); +static void check_default_mode(void); +static u_long chipalloc(u_long size); +static char *strtoke(char *s,const char *ct); + + /* + * Hardware routines + */ + +static int ami_encode_fix(struct fb_fix_screeninfo *fix, + struct amiga_fb_par *par); +static int ami_decode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par); +static int ami_encode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par); +static void ami_get_par(struct amiga_fb_par *par); +static void ami_set_var(struct fb_var_screeninfo *var); +#ifdef DEBUG +static void ami_set_par(struct amiga_fb_par *par); +#endif +static void ami_pan_var(struct fb_var_screeninfo *var); +static int ami_update_par(void); +static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); +static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); +static void ami_update_display(void); +static void ami_init_display(void); +static void ami_do_blank(void); +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con); +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con); +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con); +static int ami_get_cursorstate(struct fb_cursorstate *state, int con); +static int ami_set_cursorstate(struct fb_cursorstate *state, int con); +static void ami_set_sprite(void); +static void ami_init_copper(void); +static void ami_reinit_copper(void); +static void ami_build_copper(void); +static void ami_rebuild_copper(void); + + + /* + * External references + */ + +extern unsigned short ami_intena_vals[]; + + +static struct fb_ops amiga_fb_ops = { + amiga_fb_open, amiga_fb_release, amiga_fb_get_fix, amiga_fb_get_var, + amiga_fb_set_var, amiga_fb_get_cmap, amiga_fb_set_cmap, + amiga_fb_pan_display, amiga_fb_ioctl +}; + +struct useropts { + long xres; + long yres; + long xres_virtual; + long yres_virtual; + long bits_per_pixel; + long left_margin; + long right_margin; + long upper_margin; + long lower_margin; + long hsync_len; + long vsync_len; +} useropts __initdata = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +__initfunc(void amiga_video_setup(char *options, int *ints)) +{ + char *this_opt; + char mcap_spec[80]; + + mcap_spec[0] = '\0'; + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) { + char *p; + + if (!strcmp(this_opt, "inverse")) { + amifb_inverse = 1; + fb_invert_cmaps(); + } else if (!strcmp(this_opt, "ilbm")) + amifb_ilbm = 1; + else if (!strncmp(this_opt, "monitorcap:", 11)) + strcpy(mcap_spec, this_opt+11); + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else if (!strncmp(this_opt, "fstart:", 7)) + min_fstrt = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "depth:", 6)) + useropts.bits_per_pixel = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "size:", 5)) { + p = this_opt + 5; + if (*p != ';') + useropts.xres = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p != ';') + useropts.yres = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p != ';') + useropts.xres_virtual = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p != ';') + useropts.yres_virtual = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p) + useropts.bits_per_pixel = simple_strtoul(p, NULL, 0); + } else if (!strncmp(this_opt, "timing:", 7)) { + p = this_opt + 7; + if (*p != ';') + useropts.left_margin = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p != ';') + useropts.right_margin = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p != ';') + useropts.upper_margin = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p) + useropts.lower_margin = simple_strtoul(p, NULL, 0); + } else if (!strncmp(this_opt, "sync:", 5)) { + p = this_opt + 5; + if (*p != ';') + useropts.hsync_len = simple_strtoul(p, NULL, 0); + if (!(p = strchr(p, ';'))) + continue; + if (*++p) + useropts.vsync_len = simple_strtoul(p, NULL, 0); + } else + get_video_mode(this_opt); + } + + if (min_fstrt < 48) + min_fstrt = 48; + + if (*mcap_spec) { + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: ;;; + * vertical freq. in Hz + * horizontal freq. in kHz + */ + + if (!(p = strtoke(mcap_spec, ";")) || !*p) + goto cap_invalid; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) + goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) + goto cap_invalid; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) + goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) + goto cap_invalid; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) + goto cap_invalid; + if (!(p = strtoke(NULL, "")) || !*p) + goto cap_invalid; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) + goto cap_invalid; + + vfmin = vmin; + vfmax = vmax; + hfmin = hmin; + hfmax = hmax; +cap_invalid: + ; + } +} + + /* + * Open/Release the frame buffer device + */ + +static int amiga_fb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int amiga_fb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + + + /* + * Get the Fixed Part of the Display + */ + +static int amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct amiga_fb_par par; + + if (con == -1) + ami_get_par(&par); + else { + int err; + + if ((err = ami_decode_var(&fb_display[con].var, &par))) + return err; + } + return ami_encode_fix(fix, &par); +} + + /* + * Get the User Defined Part of the Display + */ + +static int amiga_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + int err = 0; + + if (con == -1) { + struct amiga_fb_par par; + + ami_get_par(&par); + err = ami_encode_var(var, &par); + } else + *var = fb_display[con].var; + return err; +} + + /* + * Set the User Defined Part of the Display + */ + +static int amiga_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, activate = var->activate; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp; + struct amiga_fb_par par; + + struct display *display; + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = display->var.xoffset; + var->yoffset = display->var.yoffset; + } + if ((err = ami_decode_var(var, &par))) + return err; + ami_encode_var(var, &par); + if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + display->var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + struct fb_fix_screeninfo fix; + + ami_encode_fix(&fix, &par); + display->screen_base = fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = amifb_inverse; + if (fb_info.changevar) + (*fb_info.changevar)(con); + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con); + } + if (con == currcon) + ami_set_var(&display->var); + } + return 0; +} + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int amiga_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) + return -EINVAL; + } else { + /* + * TODO: There will be problems when xpan!=1, so some columns + * on the right side will never be seen + */ + if (var->xoffset+fb_display[con].var.xres > upx(16<yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) + return -EINVAL; + } + if (con == currcon) + ami_pan_var(var); + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + fb_display[con].var.vmode |= FB_VMODE_YWRAP; + else + fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + + /* + * Get the Colormap + */ + +static int amiga_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, &fb_display[con].var, kspc, + ami_getcolreg); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + /* + * Set the Colormap + */ + +static int amiga_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<data, con); + copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar)); + } + return i; + } + case FBIOPUT_VCURSORINFO : { + struct fb_var_cursorinfo crsrvar; + + i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar)); + if (!i) { + copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar)); + i = amiga_fb_set_var_cursorinfo(&crsrvar, + ((struct fb_var_cursorinfo *)arg)->data, con); + } + return i; + } + case FBIOGET_CURSORSTATE : { + struct fb_cursorstate crsrstate; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate)); + if (!i) { + i = amiga_fb_get_cursorstate(&crsrstate, con); + copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate)); + } + return i; + } + case FBIOPUT_CURSORSTATE : { + struct fb_cursorstate crsrstate; + + i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate)); + if (!i) { + copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate)); + i = amiga_fb_set_cursorstate(&crsrstate, con); + } + return i; + } +#ifdef DEBUG + case FBCMD_GET_CURRENTPAR : { + struct amiga_fb_par par; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amiga_fb_par)); + if (!i) { + ami_get_par(&par); + copy_to_user((void *)arg, &par, sizeof(struct amiga_fb_par)); + } + return i; + } + case FBCMD_SET_CURRENTPAR : { + struct amiga_fb_par par; + + i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amiga_fb_par)); + if (!i) { + copy_from_user(&par, (void *)arg, sizeof(struct amiga_fb_par)); + ami_set_par(&par); + } + return i; + } +#endif */ DEBUG */ + } + return -EINVAL; +} + + /* + * Hardware Cursor + */ + +static int amiga_fb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) +{ + return ami_get_fix_cursorinfo(fix, con); +} + +static int amiga_fb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +{ + return ami_get_var_cursorinfo(var, data, con); +} + +static int amiga_fb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +{ + return ami_set_var_cursorinfo(var, data, con); +} + +static int amiga_fb_get_cursorstate(struct fb_cursorstate *state, int con) +{ + return ami_get_cursorstate(state, con); +} + +static int amiga_fb_set_cursorstate(struct fb_cursorstate *state, int con) +{ + return ami_set_cursorstate(state, con); +} + + + /* + * Initialisation + */ + +__initfunc(unsigned long amiga_fb_init(unsigned long mem_start)) +{ + int err, tag, i; + u_long chipptr; + + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) + return mem_start; + + /* + * TODO: where should we put this? The DMI Resolver doesn't have a + * frame buffer accessible by the CPU + */ + +#ifdef CONFIG_GSP_RESOLVER + if (amifb_resolver){ + custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; + return mem_start; + } +#endif + + custom.dmacon = DMAF_ALL | DMAF_MASTER; + + switch (amiga_chipset) { +#ifdef CONFIG_FB_AMIGA_OCS + case CS_OCS: + strcat(amiga_fb_name, "OCS"); +default_chipset: + chipset = TAG_OCS; + maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + if (!amifb_usermode) /* Set the Default Video Mode */ + get_video_mode(amiga_vblank == 50 ? + DEFMODE_PAL : DEFMODE_NTSC); + videomemorysize = VIDEOMEMSIZE_OCS; + break; +#endif /* CONFIG_FB_AMIGA_OCS */ + +#ifdef CONFIG_FB_AMIGA_ECS + case CS_ECS: + strcat(amiga_fb_name, "ECS"); + chipset = TAG_ECS; + maxdepth[TAG_SHRES] = 2; + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + if (!amifb_usermode) { /* Set the Default Video Mode */ + if (AMIGAHW_PRESENT(AMBER_FF)) + get_video_mode(amiga_vblank == 50 ? + DEFMODE_AMBER_PAL : DEFMODE_AMBER_NTSC); + else + get_video_mode(amiga_vblank == 50 ? + DEFMODE_PAL : DEFMODE_NTSC); + } + if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_ECS_1M) + videomemorysize = VIDEOMEMSIZE_ECS_2M; + else + videomemorysize = VIDEOMEMSIZE_ECS_1M; + break; +#endif /* CONFIG_FB_AMIGA_ECS */ + +#ifdef CONFIG_FB_AMIGA_AGA + case CS_AGA: + strcat(amiga_fb_name, "AGA"); + chipset = TAG_AGA; + maxdepth[TAG_SHRES] = 8; + maxdepth[TAG_HIRES] = 8; + maxdepth[TAG_LORES] = 8; + maxfmode = TAG_FMODE_4; + if (!amifb_usermode) /* Set the Default Video Mode */ + get_video_mode(DEFMODE_AGA); + if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_AGA_1M) + videomemorysize = VIDEOMEMSIZE_AGA_2M; + else + videomemorysize = VIDEOMEMSIZE_AGA_1M; + break; +#endif /* CONFIG_FB_AMIGA_AGA */ + + default: +#ifdef CONFIG_FB_AMIGA_OCS + printk("Unknown graphics chipset, defaulting to OCS\n"); + strcat(amiga_fb_name, "Unknown"); + goto default_chipset; +#else /* CONFIG_FB_AMIGA_OCS */ + return mem_start; +#endif /* CONFIG_FB_AMIGA_OCS */ + break; + } + + /* + * Calculate the Pixel Clock Values for this Machine + */ + + pixclock[TAG_SHRES] = DIVUL(25E9, amiga_eclock); /* SHRES: 35 ns / 28 MHz */ + pixclock[TAG_HIRES] = DIVUL(50E9, amiga_eclock); /* HIRES: 70 ns / 14 MHz */ + pixclock[TAG_LORES] = DIVUL(100E9, amiga_eclock); /* LORES: 140 ns / 7 MHz */ + + /* + * Replace the Tag Values with the Real Pixel Clock Values + */ + + for (i = 0; i < NUM_PREDEF_MODES; i++) { + tag = amiga_fb_predefined[i].pixclock; + if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { + amiga_fb_predefined[i].pixclock = pixclock[tag]; + if (amiga_fb_predefined[i].bits_per_pixel > maxdepth[tag]) + amiga_fb_predefined[i].bits_per_pixel = maxdepth[tag]; + } + } + + strcpy(fb_info.modename, amiga_fb_name); + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &amiga_fb_ops; + fb_info.fbvar_num = NUM_TOTAL_MODES; + fb_info.fbvar = amiga_fb_predefined; + fb_info.disp = &disp; + fb_info.switch_con = &amifbcon_switch; + fb_info.updatevar = &amifbcon_updatevar; + fb_info.blank = &amifbcon_blank; + fb_info.setcmap = &amifbcon_setcmap; + + err = register_framebuffer(&fb_info); + if (err < 0) + return mem_start; + + chipptr = chipalloc(videomemorysize+ + SPRITEMEMSIZE+ + DUMMYSPRITEMEMSIZE+ + COPINITSIZE+ + 4*COPLISTSIZE); + + assignchunk(videomemory, u_long, chipptr, videomemorysize); + assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); + assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); + assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); + assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE); + assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE); + + memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); + + /* + * Enable Display DMA + */ + + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; + + /* + * Make sure the Copper has something to do + */ + + ami_init_copper(); + + check_default_mode(); + + if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, IRQ_FLG_LOCK, + "fb vertb handler", NULL)) + panic("Couldn't add vblank interrupt\n"); + ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER; + ami_intena_vals[IRQ_AMIGA_COPPER] = 0; + custom.intena = IF_VERTB; + custom.intena = IF_SETCLR | IF_COPER; + + amiga_fb_set_var(&amiga_fb_predefined[0], -1); + + printk("%s frame buffer device, using %ldK of video memory\n", + fb_info.modename, videomemorysize>>10); + + /* TODO: This driver cannot be unloaded yet */ + MOD_INC_USE_COUNT; + + return mem_start; +} + +static int amifbcon_switch(int con) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, + &fb_display[currcon].var, 1, ami_getcolreg); + + currcon = con; + ami_set_var(&fb_display[con].var); + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int amifbcon_updatevar(int con) +{ + ami_pan_var(&fb_display[con].var); + return 0; +} + + /* + * Blank the display. + */ + +static void amifbcon_blank(int blank) +{ + do_blank = blank ? blank : -1; +} + + /* + * Set the colormap + */ + +static int amifbcon_setcmap(struct fb_cmap *cmap, int con) +{ + return(amiga_fb_set_cmap(cmap, 1, con)); +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + ami_setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &fb_display[con].var, 1, + ami_setcolreg); +} + +static int flash_cursor(void) +{ + static int cursorcount = 1; + + if (cursormode == FB_CURSOR_FLASH) { + if (!--cursorcount) { + cursorstate = -cursorstate; + cursorcount = cursorrate; + if (!is_blanked) + return 1; + } + } + return 0; +} + + /* + * VBlank Display Interrupt + */ + +static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + u_short ints = custom.intreqr & custom.intenar; + static struct irq_server server = {0, 0}; + unsigned long flags; + + if (ints & IF_BLIT) { + custom.intreq = IF_BLIT; + amiga_do_irq(IRQ_AMIGA_BLIT, fp); + } + + if (ints & IF_COPER) { + custom.intreq = IF_COPER; + if (do_vmode_pan || do_vmode_full) + ami_update_display(); + + if (do_vmode_full) + ami_init_display(); + + if (do_vmode_pan) { + flash_cursor(); + ami_rebuild_copper(); + do_cursor = do_vmode_pan = 0; + } else if (do_cursor) { + flash_cursor(); + ami_set_sprite(); + do_cursor = 0; + } else { + if (flash_cursor()) + ami_set_sprite(); + } + + save_flags(flags); + cli(); + if (get_vbpos() < down2(currentpar.diwstrt_v - 6)) + custom.copjmp2 = 0; + restore_flags(flags); + + if (do_blank) { + ami_do_blank(); + do_blank = 0; + } + + if (do_vmode_full) { + ami_reinit_copper(); + do_vmode_full = 0; + } + amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); + } + + if (ints & IF_VERTB) { + printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__); + custom.intena = IF_VERTB; + } +} + + /* + * Get a Video Mode + */ + +__initfunc(static void get_video_mode(const char *name)) +{ + int i; + + for (i = 1; i < NUM_PREDEF_MODES; i++) { + if (!strcmp(name, amiga_fb_modenames[i])) { + amiga_fb_predefined[0] = amiga_fb_predefined[i]; + + if (useropts.xres != -1) + amiga_fb_predefined[0].xres = useropts.xres; + if (useropts.yres != -1) + amiga_fb_predefined[0].yres = useropts.yres; + if (useropts.xres_virtual != -1) + amiga_fb_predefined[0].xres_virtual = useropts.xres_virtual; + if (useropts.yres_virtual != -1) + amiga_fb_predefined[0].yres_virtual = useropts.yres_virtual; + if (useropts.bits_per_pixel != -1) + amiga_fb_predefined[0].bits_per_pixel = useropts.bits_per_pixel; + if (useropts.left_margin != -1) + amiga_fb_predefined[0].left_margin = useropts.left_margin; + if (useropts.right_margin != -1) + amiga_fb_predefined[0].right_margin = useropts.right_margin; + if (useropts.upper_margin != -1) + amiga_fb_predefined[0].upper_margin = useropts.upper_margin; + if (useropts.lower_margin != -1) + amiga_fb_predefined[0].lower_margin = useropts.lower_margin; + if (useropts.hsync_len != -1) + amiga_fb_predefined[0].hsync_len = useropts.hsync_len; + if (useropts.vsync_len != -1) + amiga_fb_predefined[0].vsync_len = useropts.vsync_len; + + amifb_usermode = i; + return; + } + } +} + + /* + * Probe the Video Modes + */ + +__initfunc(static void check_default_mode(void)) +{ + struct amiga_fb_par par; + int mode; + + for (mode = 0; mode < NUM_PREDEF_MODES; mode++) { + if (!ami_decode_var(&amiga_fb_predefined[mode], &par)) { + if (mode) + amiga_fb_predefined[0] = amiga_fb_predefined[mode]; + return; + } + if (!mode) + printk("Can't use default video mode. Probing video modes...\n"); + } + panic("Can't find any usable video mode"); +} + + /* + * Allocate, Clear and Align a Block of Chip Memory + */ + +__initfunc(static u_long chipalloc(u_long size)) +{ + u_long ptr; + + size += PAGE_SIZE-1; + if (!(ptr = (u_long)amiga_chip_alloc(size))) + panic("No Chip RAM for frame buffer"); + memset((void *)ptr, 0, size); + ptr = PAGE_ALIGN(ptr); + + return ptr; +} + + /* + * A strtok which returns empty strings, too + */ + +__initfunc(static char *strtoke(char *s,const char *ct)) +{ + char *sbegin, *send; + static char *ssave = NULL; + + sbegin = s ? s : ssave; + if (!sbegin) + return NULL; + if (*sbegin == '\0') { + ssave = NULL; + return NULL; + } + send = strpbrk(sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ssave = send; + return sbegin; +} + +/* --------------------------- Hardware routines --------------------------- */ + + /* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int ami_encode_fix(struct fb_fix_screeninfo *fix, + struct amiga_fb_par *par) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, amiga_fb_name); + fix->smem_start = (char *)videomemory; + fix->smem_len = videomemorysize; + + if (amifb_ilbm) { + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = par->next_line; + } else { + fix->type = FB_TYPE_PLANES; + fix->type_aux = 0; + } + fix->line_length = div8(upx(16<vxres)); + fix->visual = FB_VISUAL_PSEUDOCOLOR; + + if (par->vmode & FB_VMODE_YWRAP) { + fix->ywrapstep = 1; + fix->xpanstep = fix->ypanstep = 0; + } else { + fix->ywrapstep = 0; + if (par->vmode &= FB_VMODE_SMOOTH_XPAN) + fix->xpanstep = 1; + else + fix->xpanstep = 16<ypanstep = 1; + } + return 0; +} + + /* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int ami_decode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par) +{ + u_short clk_shift, line_shift; + u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; + u_long hrate = 0, vrate = 0; + + /* + * Find a matching Pixel Clock + */ + + for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) + if (var->pixclock <= pixclock[clk_shift]) + break; + if (clk_shift > TAG_LORES) { + DPRINTK("pixclock too high\n"); + return -EINVAL; + } + par->clk_shift = clk_shift; + + /* + * Check the Geometry Values + */ + + if ((par->xres = var->xres) < 64) + par->xres = 64; + if ((par->yres = var->yres) < 64) + par->yres = 64; + if ((par->vxres = var->xres_virtual) < par->xres) + par->vxres = par->xres; + if ((par->vyres = var->yres_virtual) < par->yres) + par->vyres = par->yres; + + par->bpp = var->bits_per_pixel; + if (!var->nonstd) { + if (par->bpp < 1) + par->bpp = 1; + if (par->bpp > maxdepth[clk_shift]) { + DPRINTK("invalid bpp\n"); + return -EINVAL; + } + } else if (var->nonstd == FB_NONSTD_HAM) { + if (par->bpp < 6) + par->bpp = 6; + if (par->bpp != 6) { + if (par->bpp < 8) + par->bpp = 8; + if (par->bpp != 8 || !IS_AGA) { + DPRINTK("invalid bpp for ham mode\n"); + return -EINVAL; + } + } + } else { + DPRINTK("unknown nonstd mode\n"); + return -EINVAL; + } + + /* + * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing + * checks failed and smooth scrolling is not possible + */ + + par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + line_shift = 0; + break; + case FB_VMODE_NONINTERLACED: + line_shift = 1; + break; + case FB_VMODE_DOUBLE: + if (!IS_AGA) { + DPRINTK("double mode only possible with aga\n"); + return -EINVAL; + } + line_shift = 2; + break; + default: + DPRINTK("unknown video mode\n"); + return -EINVAL; + break; + } + par->line_shift = line_shift; + + /* + * Vertical and Horizontal Timings + */ + + xres_n = par->xres<yres<htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<bplcon3 = sprpixmode[clk_shift]; + else + par->bplcon3 = 0; + if (var->sync & FB_SYNC_BROADCAST) { + par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<diwstop_h += mod4(var->hsync_len); + else + par->diwstop_h = down4(par->diwstop_h); + + par->diwstrt_h = par->diwstop_h - xres_n; + par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<diwstrt_v = par->diwstop_v - yres_n; + if (par->diwstop_h >= par->htotal+8) { + DPRINTK("invalid diwstop_h\n"); + return -EINVAL; + } + if (par->diwstop_v > par->vtotal) { + DPRINTK("invaild diwstop_v\n"); + return -EINVAL; + } + + if (!IS_OCS) { + /* Initialize sync with some reasonable values for pwrsave */ + par->hsstrt = 160; + par->hsstop = 320; + par->vsstrt = 30; + par->vsstop = 34; + } else { + par->hsstrt = 0; + par->hsstop = 0; + par->vsstrt = 0; + par->vsstop = 0; + } + if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) { + /* PAL video mode */ + if (par->htotal != PAL_HTOTAL) { + DPRINTK("htotal invalid for pal\n"); + return -EINVAL; + } + if (par->diwstrt_h < PAL_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for pal\n"); + return -EINVAL; + } + if (par->diwstrt_v < PAL_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for pal\n"); + return -EINVAL; + } + hrate = 15625; + vrate = 50; + if (!IS_OCS) { + par->beamcon0 = BMC0_PAL; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = BMC0_PAL; + par->hsstop = 1; + } else if (amiga_vblank != 50) { + DPRINTK("pal not supported by this chipset\n"); + return -EINVAL; + } + } else { + /* NTSC video mode + * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK + * and NTSC activated, so than better let diwstop_h <= 1812 + */ + if (par->htotal != NTSC_HTOTAL) { + DPRINTK("htotal invalid for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_h < NTSC_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_v < NTSC_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for ntsc\n"); + return -EINVAL; + } + hrate = 15750; + vrate = 60; + if (!IS_OCS) { + par->beamcon0 = 0; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = 0; + par->hsstop = 1; + } else if (amiga_vblank != 60) { + DPRINTK("ntsc not supported by this chipset\n"); + return -EINVAL; + } + } + if (IS_OCS) { + if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || + par->diwstrt_v >= 512 || par->diwstop_v < 256) { + DPRINTK("invalid position for display on ocs\n"); + return -EINVAL; + } + } + } else if (!IS_OCS) { + /* Programmable video mode */ + par->hsstrt = var->right_margin<hsstop = (var->right_margin+var->hsync_len)<diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); + if (!IS_AGA) + par->diwstop_h = down4(par->diwstop_h) - 16; + par->diwstrt_h = par->diwstop_h - xres_n; + par->hbstop = par->diwstrt_h + 4; + par->hbstrt = par->diwstop_h + 4; + if (par->hbstrt >= par->htotal + 8) + par->hbstrt -= par->htotal; + par->hcenter = par->hsstrt + (par->htotal >> 1); + par->vsstrt = var->lower_margin<vsstop = (var->lower_margin+var->vsync_len)<diwstop_v = par->vtotal; + if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + par->diwstop_v -= 2; + par->diwstrt_v = par->diwstop_v - yres_n; + par->vbstop = par->diwstrt_v - 2; + par->vbstrt = par->diwstop_v - 2; + if (par->vtotal > 2048) { + DPRINTK("vtotal too high\n"); + return -EINVAL; + } + if (par->htotal > 2048) { + DPRINTK("htotal too high\n"); + return -EINVAL; + } + par->bplcon3 |= BPC3_EXTBLKEN; + par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | + BMC0_PAL | BMC0_VARCSYEN; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->beamcon0 |= BMC0_HSYTRUE; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->beamcon0 |= BMC0_VSYTRUE; + if (var->sync & FB_SYNC_COMP_HIGH_ACT) + par->beamcon0 |= BMC0_CSYTRUE; + hrate = (amiga_masterclock+par->htotal/2)/par->htotal; + vrate = div2(par->vtotal) * par->htotal; + vrate = (amiga_masterclock+vrate/2)/vrate; + } else { + DPRINTK("only broadcast modes possible for ocs\n"); + return -EINVAL; + } + + /* + * Checking the DMA timing + */ + + fconst = 16<diwstrt_h-4) - fsize; + if (fstrt < min_fstrt) { + DPRINTK("fetch start too low\n"); + return -EINVAL; + } + + /* + * smallest window start value where smooth scrolling is possible + */ + + fstrt = downx(fconst, par->diwstrt_h-fconst+(1<vmode &= ~FB_VMODE_SMOOTH_XPAN; + + maxfetchstop = down16(par->htotal - 80); + + fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst; + fsize = upx(fconst, xres_n + modx(fconst, downx(1<diwstrt_h-4))); + if (fstrt + fsize > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = upx(fconst, xres_n); + if (fstrt + fsize > maxfetchstop) { + DPRINTK("fetch stop too high\n"); + return -EINVAL; + } + + if (maxfmode + clk_shift <= 1) { + fsize = up64(xres_n + fconst - 1); + if (min_fstrt + fsize - 64 > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = up64(xres_n); + if (min_fstrt + fsize - 64 > maxfetchstop) { + DPRINTK("fetch size too high\n"); + return -EINVAL; + } + + fsize -= 64; + } else + fsize -= fconst; + + /* + * Check if there is enough time to update the bitplane pointers for ywrap + */ + + if (par->htotal-fsize-64 < par->bpp*64) + par->vmode &= ~FB_VMODE_YWRAP; + + /* + * Bitplane calculations and check the Memory Requirements + */ + + if (amifb_ilbm) { + par->next_plane = div8(upx(16<vxres)); + par->next_line = par->bpp*par->next_plane; + if (par->next_line * par->vyres > videomemorysize) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } else { + par->next_line = div8(upx(16<vxres)); + par->next_plane = par->vyres*par->next_line; + if (par->next_plane * par->bpp > videomemorysize) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } + + /* + * Hardware Register Values + */ + + par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; + if (!IS_OCS) + par->bplcon0 |= BPC0_ECSENA; + if (par->bpp == 8) + par->bplcon0 |= BPC0_BPU3; + else + par->bplcon0 |= par->bpp<<12; + if (var->nonstd == FB_NONSTD_HAM) + par->bplcon0 |= BPC0_HAM; + if (var->sync & FB_SYNC_EXT) + par->bplcon0 |= BPC0_ERSY; + + if (IS_AGA) + par->fmode = bplfetchmode[maxfmode]; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bplcon0 |= BPC0_LACE; + break; + case FB_VMODE_DOUBLE: + if (IS_AGA) + par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; + break; + } + + if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres) + par->xoffset = par->yoffset = 0; + } else { + if (par->xoffset < 0 || par->xoffset > upx(16<vxres-par->xres) || + par->yoffset < 0 || par->yoffset > par->vyres-par->yres) + par->xoffset = par->yoffset = 0; + } + } else + par->xoffset = par->yoffset = 0; + + par->crsr.crsr_x = par->crsr.crsr_y = 0; + par->crsr.spot_x = par->crsr.spot_y = 0; + par->crsr.height = par->crsr.width = 0; + + if (hrate < hfmin || hrate > hfmax || vrate < vfmin || vrate > vfmax) { + DPRINTK("mode doesn't fit for monitor\n"); + return -EINVAL; + } + + return 0; +} + + /* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int ami_encode_var(struct fb_var_screeninfo *var, + struct amiga_fb_par *par) +{ + u_short clk_shift, line_shift; + int i; + + clk_shift = par->clk_shift; + line_shift = par->line_shift; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + if (IS_AGA) { + var->red.offset = 0; + var->red.length = 8; + var->red.msb_right = 0; + } else { + if (clk_shift == TAG_SHRES) { + var->red.offset = 0; + var->red.length = 2; + var->red.msb_right = 0; + } else { + var->red.offset = 0; + var->red.length = 4; + var->red.msb_right = 0; + } + } + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + if (par->bplcon0 & BPC0_HAM) + var->nonstd = FB_NONSTD_HAM; + else + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + var->accel = 0; + + var->pixclock = pixclock[clk_shift]; + + if (IS_AGA && par->fmode & FMODE_BSCAN2) + var->vmode = FB_VMODE_DOUBLE; + else if (par->bplcon0 & BPC0_LACE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { + var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift; + var->right_margin = par->hsstrt>>clk_shift; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift; + var->lower_margin = par->vsstrt>>line_shift; + var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; + var->sync = 0; + if (par->beamcon0 & BMC0_HSYTRUE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->beamcon0 & BMC0_VSYTRUE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (par->beamcon0 & BMC0_CSYTRUE) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + } else { + var->sync = FB_SYNC_BROADCAST; + var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); + var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = 4>>line_shift; + var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; + var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - + var->lower_margin - var->vsync_len; + } + + if (par->bplcon0 & BPC0_ERSY) + var->sync |= FB_SYNC_EXT; + if (par->vmode & FB_VMODE_YWRAP) + var->vmode |= FB_VMODE_YWRAP; + + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + return 0; +} + + /* + * Get current hardware setting + */ + +static void ami_get_par(struct amiga_fb_par *par) +{ + *par = currentpar; +} + + /* + * Set new videomode + */ + +static void ami_set_var(struct fb_var_screeninfo *var) +{ + do_vmode_pan = 0; + do_vmode_full = 0; + ami_decode_var(var, ¤tpar); + ami_build_copper(); + do_vmode_full = 1; +} + +#ifdef DEBUG +static void ami_set_par(struct amiga_fb_par *par) +{ + do_vmode_pan = 0; + do_vmode_full = 0; + currentpar = *par; + ami_build_copper(); + do_vmode_full = 1; +} +#endif + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + * in `var'. + */ + +static void ami_pan_var(struct fb_var_screeninfo *var) +{ + struct amiga_fb_par *par = ¤tpar; + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + par->vmode |= FB_VMODE_YWRAP; + else + par->vmode &= ~FB_VMODE_YWRAP; + + do_vmode_pan = 0; + ami_update_par(); + do_vmode_pan = 1; +} + + /* + * Update hardware + */ + +static int ami_update_par(void) +{ + struct amiga_fb_par *par = ¤tpar; + short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; + + clk_shift = par->clk_shift; + + if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) + par->xoffset = upx(16<xoffset); + + fconst = 16<xoffset); + fstrt = par->diwstrt_h - (vshift<xres+vshift)<xoffset)); + if (maxfmode + clk_shift > 1) { + fstrt = downx(fconst, fstrt) - 64; + fsize = upx(fconst, fsize); + fstop = fstrt + fsize - fconst; + } else { + mod = fstrt = downx(fconst, fstrt) - fconst; + fstop = fstrt + upx(fconst, fsize) - 64; + fsize = up64(fsize); + fstrt = fstop - fsize + 64; + if (fstrt < min_fstrt) { + fstop += min_fstrt - fstrt; + fstrt = min_fstrt; + } + move = move - div8((mod-fstrt)>>clk_shift); + } + mod = par->next_line - div8(fsize>>clk_shift); + par->ddfstrt = fstrt; + par->ddfstop = fstop; + par->bplcon1 = hscroll2hw(shift); + par->bpl2mod = mod; + if (par->bplcon0 & BPC0_LACE) + par->bpl2mod += par->next_line; + if (IS_AGA && (par->fmode & FMODE_BSCAN2)) + par->bpl1mod = -div8(fsize>>clk_shift); + else + par->bpl1mod = par->bpl2mod; + + if (par->yoffset) { + par->bplpt0 = ZTWO_PADDR((u_long)videomemory + par->next_line*par->yoffset + move); + if (par->vmode & FB_VMODE_YWRAP) { + if (par->yoffset > par->vyres-par->yres) { + par->bplpt0wrap = ZTWO_PADDR((u_long)videomemory + move); + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset)) + par->bplpt0wrap += par->next_line; + } + } + } else + par->bplpt0 = ZTWO_PADDR((u_long)videomemory + move); + + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) + par->bplpt0 += par->next_line; + + return 0; +} + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp) +{ + if (IS_AGA) { + if (regno > 255) + return 1; + } else { + if (regno > 31) + return 1; + } + + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp) +{ +#if defined(CONFIG_FB_AMIGA_AGA) + u_short bplcon3 = currentpar.bplcon3; + + if (IS_AGA) { + if (regno > 255) + return 1; + } else +#endif + if (regno > 31) + return 1; + + /* + * Update the corresponding Hardware Color Register, unless it's Color + * Register 0 and the screen is blanked. + * + * VBlank is switched off to protect bplcon3 or ecs_palette[] from + * being changed by ami_do_blank() during the VBlank. + */ + + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + if (regno || !is_blanked) { +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + VBlankOff(); + custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); + custom.color[regno&31] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT; + custom.color[regno&31] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + VBlankOn(); + } else +#endif + { +#if defined(CONFIG_FB_AMIGA_ECS) + if (currentpar.bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + VBlankOff(); + for (i = regno+12; i >= (int)regno; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<=2; color >>= 2; + regno = down16(regno)+mul4(mod4(regno)); + for (i = regno+3; i >= (int)regno; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + VBlankOn(); + } else +#endif + custom.color[regno] = rgb2hw4(red, green, blue); + } + } + return 0; +} + +static void ami_update_display(void) +{ + struct amiga_fb_par *par = ¤tpar; + + custom.bplcon1 = par->bplcon1; + custom.bpl1mod = par->bpl1mod; + custom.bpl2mod = par->bpl2mod; + custom.ddfstrt = ddfstrt2hw(par->ddfstrt); + custom.ddfstop = ddfstop2hw(par->ddfstop); +} + + /* + * Change the video mode (called by VBlank interrupt) + */ + +static void ami_init_display(void) +{ + struct amiga_fb_par *par = ¤tpar; + + custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; + custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; + if (!IS_OCS) { + custom.bplcon3 = par->bplcon3; + if (IS_AGA) + custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; + if (par->beamcon0 & BMC0_VARBEAMEN) { + custom.htotal = htotal2hw(par->htotal); + custom.hbstrt = hbstrt2hw(par->hbstrt); + custom.hbstop = hbstop2hw(par->hbstop); + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.hcenter = hcenter2hw(par->hcenter); + custom.vtotal = vtotal2hw(par->vtotal); + custom.vbstrt = vbstrt2hw(par->vbstrt); + custom.vbstop = vbstop2hw(par->vbstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + } + } + if (!IS_OCS || par->hsstop) + custom.beamcon0 = par->beamcon0; + if (IS_AGA) + custom.fmode = par->fmode; + + /* + * The minimum period for audio depends on htotal + */ + + amiga_audio_min_period = div16(par->htotal); + + is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; +#if 1 + if (is_lace) { + if (custom.vposr & 0x8000) + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]); + else + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]); + } else { + custom.vposw = custom.vposr | 0x8000; + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]); + } +#else + custom.vposw = custom.vposr | 0x8000; + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]); +#endif +} + + /* + * (Un)Blank the screen (called by VBlank interrupt) + */ + +static void ami_do_blank(void) +{ + struct amiga_fb_par *par = ¤tpar; +#if defined(CONFIG_FB_AMIGA_AGA) + u_short bplcon3 = par->bplcon3; +#endif + u_char red, green, blue; + + if (do_blank > 0) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + red = green = blue = 0; + if (!IS_OCS && do_blank > 1) { + switch (do_blank) { + case 2 : /* suspend vsync */ + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vtotal+4); + custom.vsstop = vsstop2hw(par->vtotal+4); + break; + case 3 : /* suspend hsync */ + custom.hsstrt = hsstrt2hw(par->htotal+16); + custom.hsstop = hsstop2hw(par->htotal+16); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstrt2hw(par->vsstop); + break; + case 4 : /* powerdown */ + custom.hsstrt = hsstrt2hw(par->htotal+16); + custom.hsstop = hsstop2hw(par->htotal+16); + custom.vsstrt = vsstrt2hw(par->vtotal+4); + custom.vsstop = vsstop2hw(par->vtotal+4); + break; + } + if (!(par->beamcon0 & BMC0_VARBEAMEN)) { + custom.htotal = htotal2hw(par->htotal); + custom.vtotal = vtotal2hw(par->vtotal); + custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; + } + } + } else { + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; + red = palette[0].red; + green = palette[0].green; + blue = palette[0].blue; + if (!IS_OCS) { + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + custom.beamcon0 = par->beamcon0; + } + } +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + custom.bplcon3 = bplcon3; + custom.color[0] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | BPC3_LOCT; + custom.color[0] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + } else +#endif + { +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + for (i = 12; i >= 0; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<=2; color >>= 2; + for (i = 3; i >= 0; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + } else +#endif + custom.color[0] = rgb2hw4(red, green, blue); + } + is_blanked = do_blank > 0 ? do_blank : 0; +} + + /* + * Flash the cursor (called by VBlank interrupt) + */ + +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) +{ + struct amiga_fb_par *par = ¤tpar; + + fix->crsr_width = fix->crsr_xsize = par->crsr.width; + fix->crsr_height = fix->crsr_ysize = par->crsr.height; + fix->crsr_color1 = 17; + fix->crsr_color2 = 18; + return 0; +} + +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +{ + struct amiga_fb_par *par = ¤tpar; + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + register u_char color; + short height, width, bits, words; + int i, size, alloc; + + size = par->crsr.height*par->crsr.width; + alloc = var->height*var->width; + var->height = par->crsr.height; + var->width = par->crsr.width; + var->xspot = par->crsr.spot_x; + var->yspot = par->crsr.spot_y; + if (size > var->height*var->width) + return -ENAMETOOLONG; + if ((i = verify_area(VERIFY_WRITE, (void *)data, size))) + return i; + delta = 1<crsr.fmode; + lspr = lofsprite + (delta<<1); + if (par->bplcon0 & BPC0_LACE) + sspr = shfsprite + (delta<<1); + else + sspr = 0; + for (height = (short)var->height-1; height >= 0; height--) { + bits = 0; words = delta; datawords = 0; + for (width = (short)var->width-1; width >= 0; width--) { + if (bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" + : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); +#else + datawords = (*(lspr+delta) << 16) | (*lspr++); +#endif + } + --bits; +#ifdef __mc68000__ + asm volatile ( + "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " + "swap %1 ; lslw #1,%1 ; roxlb #1,%0" + : "=d" (color), "=d" (datawords) : "1" (datawords)); +#else + color = (((datawords >> 30) & 2) + | ((datawords >> 15) & 1)); + datawords <<= 1; +#endif + put_user(color, data++); + } + if (bits > 0) { + --words; ++lspr; + } + while (--words >= 0) + ++lspr; +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + return 0; +} + +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +{ + struct amiga_fb_par *par = ¤tpar; + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + u_short fmode; + short height, width, bits, words; + int i; + + if (!var->width) + return -EINVAL; + else if (var->width <= 16) + fmode = TAG_FMODE_1; + else if (var->width <= 32) + fmode = TAG_FMODE_2; + else if (var->width <= 64) + fmode = TAG_FMODE_4; + else + return -EINVAL; + if (fmode > maxfmode) + return -EINVAL; + if (!var->height) + return -EINVAL; + if ((i = verify_area(VERIFY_READ, (void *)data, var->width*var->height))) + return i; + delta = 1<bplcon0 & BPC0_LACE) { + if (((var->height+4)< SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height+4)<height+5)&-2)<height+2)< SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height+2)<height-1; height >= 0; height--) { + bits = 16; words = delta; datawords = 0; + for (width = (short)var->width-1; width >= 0; width--) { + unsigned long tdata = 0; + get_user(tdata, (char *)data); + data++; +#ifdef __mc68000__ + asm volatile ( + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" + : "=d" (datawords) + : "0" (datawords), "d" (tdata)); +#else + datawords = ((datawords << 1) & 0xfffefffe); + datawords |= tdata & 1; + datawords |= (tdata & 2) << (16-1); +#endif + if (--bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); +#else + *(lspr+delta) = (u_short) (datawords >> 16); + *lspr++ = (u_short) (datawords & 0xffff); +#endif + } + } + if (bits < 16) { + --words; +#ifdef __mc68000__ + asm volatile ( + "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " + "swap %2 ; lslw %4,%2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); +#else + *(lspr+delta) = (u_short) (datawords >> (16+bits)); + *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); +#endif + } + while (--words >= 0) { +#ifdef __mc68000__ + asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); +#else + *(lspr+delta) = 0; + *lspr++ = 0; +#endif + } +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + par->crsr.height = var->height; + par->crsr.width = var->width; + par->crsr.spot_x = var->xspot; + par->crsr.spot_y = var->yspot; + par->crsr.fmode = fmode; + if (IS_AGA) { + par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); + par->fmode |= sprfetchmode[fmode]; + custom.fmode = par->fmode; + } + return 0; +} + +static int ami_get_cursorstate(struct fb_cursorstate *state, int con) +{ + struct amiga_fb_par *par = ¤tpar; + + state->xoffset = par->crsr.crsr_x; + state->yoffset = par->crsr.crsr_y; + state->mode = cursormode; + return 0; +} + +static int ami_set_cursorstate(struct fb_cursorstate *state, int con) +{ + struct amiga_fb_par *par = ¤tpar; + + par->crsr.crsr_x = state->xoffset; + par->crsr.crsr_y = state->yoffset; + if ((cursormode = state->mode) == FB_CURSOR_OFF) + cursorstate = -1; + do_cursor = 1; + return 0; +} + +static void ami_set_sprite(void) +{ + struct amiga_fb_par *par = ¤tpar; + copins *copl, *cops; + u_short hs, vs, ve; + u_long pl, ps, pt; + short mx, my; + + cops = copdisplay.list[currentcop][0]; + copl = copdisplay.list[currentcop][1]; + ps = pl = ZTWO_PADDR(dummysprite); + mx = par->crsr.crsr_x-par->crsr.spot_x; + my = par->crsr.crsr_y-par->crsr.spot_y; + if (!(par->vmode & FB_VMODE_YWRAP)) { + mx -= par->xoffset; + my -= par->yoffset; + } + if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && + mx > -(short)par->crsr.width && mx < par->xres && + my > -(short)par->crsr.height && my < par->yres) { + pl = ZTWO_PADDR(lofsprite); + hs = par->diwstrt_h + (mx<clk_shift) - 4; + vs = par->diwstrt_v + (my<line_shift); + ve = vs + (par->crsr.height<line_shift); + if (par->bplcon0 & BPC0_LACE) { + ps = ZTWO_PADDR(shfsprite); + lofsprite[0] = spr2hw_pos(vs, hs); + shfsprite[0] = spr2hw_pos(vs+1, hs); + if (mod2(vs)) { + lofsprite[1<crsr.fmode] = spr2hw_ctl(vs, hs, ve); + shfsprite[1<crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1); + pt = pl; pl = ps; ps = pt; + } else { + lofsprite[1<crsr.fmode] = spr2hw_ctl(vs, hs, ve+1); + shfsprite[1<crsr.fmode] = spr2hw_ctl(vs+1, hs, ve); + } + } else { + lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); + lofsprite[1<crsr.fmode] = spr2hw_ctl(vs, hs, ve); + } + } + copl[cop_spr0ptrh].w[1] = highw(pl); + copl[cop_spr0ptrl].w[1] = loww(pl); + if (par->bplcon0 & BPC0_LACE) { + cops[cop_spr0ptrh].w[1] = highw(ps); + cops[cop_spr0ptrl].w[1] = loww(ps); + } +} + + /* + * Initialise the Copper Initialisation List + */ + +__initfunc(static void ami_init_copper(void)) +{ + copins *cop = copdisplay.init; + u_long p; + int i; + + if (!IS_OCS) { + (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); + (cop++)->l = CMOVE(0x0181, diwstrt); + (cop++)->l = CMOVE(0x0281, diwstop); + (cop++)->l = CMOVE(0x0000, diwhigh); + } else + (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); + p = ZTWO_PADDR(dummysprite); + for (i = 0; i < 8; i++) { + (cop++)->l = CMOVE(0, spr[i].pos); + (cop++)->l = CMOVE(highw(p), sprpt[i]); + (cop++)->l = CMOVE2(loww(p), sprpt[i]); + } + + (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); + copdisplay.wait = cop; + (cop++)->l = CEND; + (cop++)->l = CMOVE(0, copjmp2); + cop->l = CEND; + + custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); + custom.copjmp1 = 0; +} + +static void ami_reinit_copper(void) +{ + struct amiga_fb_par *par = ¤tpar; + + copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; + copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4); +} + + /* + * Build the Copper List + */ + +static void ami_build_copper(void) +{ + struct amiga_fb_par *par = ¤tpar; + copins *copl, *cops; + u_long p; + + currentcop = 1 - currentcop; + + copl = copdisplay.list[currentcop][1]; + + (copl++)->l = CWAIT(0, 10); + (copl++)->l = CMOVE(par->bplcon0, bplcon0); + (copl++)->l = CMOVE(0, sprpt[0]); + (copl++)->l = CMOVE2(0, sprpt[0]); + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.list[currentcop][0]; + + (cops++)->l = CWAIT(0, 10); + (cops++)->l = CMOVE(par->bplcon0, bplcon0); + (cops++)->l = CMOVE(0, sprpt[0]); + (cops++)->l = CMOVE2(0, sprpt[0]); + + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop); + (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1, + par->diwstop_h, par->diwstop_v+1), diwhigh); + (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop); + (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + p = ZTWO_PADDR(copdisplay.list[currentcop][0]); + (copl++)->l = CMOVE(highw(p), cop2lc); + (copl++)->l = CMOVE2(loww(p), cop2lc); + p = ZTWO_PADDR(copdisplay.list[currentcop][1]); + (cops++)->l = CMOVE(highw(p), cop2lc); + (cops++)->l = CMOVE2(loww(p), cop2lc); + copdisplay.rebuild[0] = cops; + } else { + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + } + copdisplay.rebuild[1] = copl; + + ami_update_par(); + ami_rebuild_copper(); +} + + /* + * Rebuild the Copper List + * + * We only change the things that are not static + */ + +static void ami_rebuild_copper(void) +{ + struct amiga_fb_par *par = ¤tpar; + copins *copl, *cops; + u_short line, h_end1, h_end2; + short i; + u_long p; + + if (IS_AGA && maxfmode + par->clk_shift == 0) + h_end1 = par->diwstrt_h-64; + else + h_end1 = par->htotal-32; + h_end2 = par->ddfstop+64; + + ami_set_sprite(); + + copl = copdisplay.rebuild[1]; + p = par->bplpt0; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres-par->yres) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres-par->yoffset)<line_shift) - 1; + while (line >= 512) { + (copl++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (copl++)->l = CWAIT(h_end1, line); + else + (copl++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + } + } else p = par->bplpt0wrap; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + copl->l = CEND; + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.rebuild[0]; + p = par->bplpt0; + if (mod2(par->diwstrt_v)) + p -= par->next_line; + else + p += par->next_line; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres-par->yres+1) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres-par->yoffset)<line_shift) - 2; + while (line >= 512) { + (cops++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (cops++)->l = CWAIT(h_end1, line); + else + (cops++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + if (mod2(par->diwstrt_v+par->vyres-par->yoffset)) + p -= par->next_line; + else + p += par->next_line; + } + } else p = par->bplpt0wrap - par->next_line; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + cops->l = CEND; + } +} + + +#ifdef MODULE +int init_module(void) +{ + return(amiga_fb_init(NULL)); +} + +void cleanup_module(void) +{ + /* Not reached because the usecount will never + be decremented to zero */ + unregister_framebuffer(&fb_info); + /* TODO: clean up ... */ +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/atafb.c linux/drivers/video/atafb.c --- v2.1.66/linux/drivers/video/atafb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/atafb.c Mon Nov 24 01:18:51 1997 @@ -0,0 +1,3152 @@ +/* + * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device + * + * Copyright (C) 1994 Martin Schaller & Roman Hodek + * + * 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. + * + * History: + * - 03 Jan 95: Original version by Martin Schaller: The TT driver and + * all the device independent stuff + * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch) + * and wrote the Falcon, ST(E), and External drivers + * based on the original TT driver. + * - 07 May 95: Martin: Added colormap operations for the external driver + * - 21 May 95: Martin: Added support for overscan + * Andreas: some bug fixes for this + * - Jul 95: Guenther Kelleter : + * Programmable Falcon video modes + * (thanks to Christian Cartus for documentation + * of VIDEL registers). + * - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]" + * on minor 24...31. "user0" may be set on commandline by + * "R;;". (Makes sense only on Falcon) + * Video mode switch on Falcon now done at next VBL interrupt + * to avoid the annoying right shift of the screen. + * - 23 Sep 97: Juergen: added xres_virtual for cards like ProMST + * The external-part is legacy, therefore hardware-specific + * functions like panning/hardwarescrolling/blanking isn't + * supported. + * - 29 Sep 97: Juergen: added Romans suggestion for pan_display + * (var->xoffset was changed even if no set_screen_base avail.) + * - 05 Oct 97: Juergen: extfb (PACKED_PIXEL) is FB_PSEUDOCOLOR 'cause + * we know how to set the colors + * ext_*palette: read from ext_colors (former MV300_colors) + * write to ext_colors and RAMDAC + * + * To do: + * - For the Falcon it is not possible to set random video modes on + * SM124 and SC/TV, only the bootup resolution is supported. + * + */ + +#define ATAFB_TT +#define ATAFB_STE +#define ATAFB_EXT +#define ATAFB_FALCON + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ +#define SWITCH_SND6 0x40 +#define SWITCH_SND7 0x80 +#define SWITCH_NONE 0x00 + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define up(x, r) (((x) + (r) - 1) & ~((r)-1)) + + +static int default_par=0; /* default resolution (0=none) */ + +static unsigned long default_mem_req=0; + +static int hwscroll=-1; + +static int use_hwscroll = 1; + +static int sttt_xres=640,st_yres=400,tt_yres=480; +static int sttt_xres_virtual=640,sttt_yres_virtual=400; +static int ovsc_offset=0, ovsc_addlen=0; +int ovsc_switchmode=0; + +static struct atari_fb_par { + unsigned long screen_base; + int yres_virtual; + union { + struct { + int mode; + int sync; + } tt, st; + struct falcon_hw { + /* Here are fields for storing a video mode, as direct + * parameters for the hardware. + */ + short sync; + short line_width; + short line_offset; + short st_shift; + short f_shift; + short vid_control; + short vid_mode; + short xoffset; + short hht, hbb, hbe, hdb, hde, hss; + short vft, vbb, vbe, vdb, vde, vss; + /* auxiliary information */ + short mono; + short ste_mode; + short bpp; + } falcon; + /* Nothing needed for external mode */ + } hw; +} current_par; + +/* Don't calculate an own resolution, and thus don't change the one found when + * booting (currently used for the Falcon to keep settings for internal video + * hardware extensions (e.g. ScreenBlaster) */ +static int DontCalcRes = 0; + +#define HHT hw.falcon.hht +#define HBB hw.falcon.hbb +#define HBE hw.falcon.hbe +#define HDB hw.falcon.hdb +#define HDE hw.falcon.hde +#define HSS hw.falcon.hss +#define VFT hw.falcon.vft +#define VBB hw.falcon.vbb +#define VBE hw.falcon.vbe +#define VDB hw.falcon.vdb +#define VDE hw.falcon.vde +#define VSS hw.falcon.vss +#define VCO_CLOCK25 0x04 +#define VCO_CSYPOS 0x10 +#define VCO_VSYPOS 0x20 +#define VCO_HSYPOS 0x40 +#define VCO_SHORTOFFS 0x100 +#define VMO_DOUBLE 0x01 +#define VMO_INTER 0x02 +#define VMO_PREMASK 0x0c + +static struct fb_info fb_info; + +static unsigned long screen_base; /* base address of screen */ +static unsigned long real_screen_base; /* (only for Overscan) */ + +static int screen_len; + +static int current_par_valid=0; + +static int currcon=0; + +static int mono_moni=0; + +static struct display disp; + + +#ifdef ATAFB_EXT +/* external video handling */ + +static unsigned external_xres; +static unsigned external_xres_virtual; +static unsigned external_yres; +/* not needed - atafb will never support panning/hardwarescroll with external + * static unsigned external_yres_virtual; +*/ + +static unsigned external_depth; +static int external_pmode; +static unsigned long external_addr = 0; +static unsigned long external_len; +static unsigned long external_vgaiobase = 0; +static unsigned int external_bitspercol = 6; + +/* +JOE : +added card type for external driver, is only needed for +colormap handling. +*/ + +enum cardtype { IS_VGA, IS_MV300 }; +static enum cardtype external_card_type = IS_VGA; + +/* +The MV300 mixes the color registers. So we need an array of munged +indices in order to acces the correct reg. +*/ +static int MV300_reg_1bit[2]={0,1}; +static int MV300_reg_4bit[16]={ +0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; +static int MV300_reg_8bit[256]={ +0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, +8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, +4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, +12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, +2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, +10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, +6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, +14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, +1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, +9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, +5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, +13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, +3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, +11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, +7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, +15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; + +static int *MV300_reg = MV300_reg_8bit; + +/* +And on the MV300 it's difficult to read out the hardware palette. So we +just keep track of the set colors in our own array here, and use that! +*/ + +static struct { unsigned char red,green,blue,pad; } ext_color[256]; +#endif /* ATAFB_EXT */ + + +static int inverse=0; + +extern int fontheight_8x8; +extern int fontwidth_8x8; +extern unsigned char fontdata_8x8[]; + +extern int fontheight_8x16; +extern int fontwidth_8x16; +extern unsigned char fontdata_8x16[]; + +/* import first 16 colors from fbcon.c */ +extern unsigned short packed16_cmap[16]; + + +/* ++roman: This structure abstracts from the underlying hardware (ST(e), + * TT, or Falcon. + * + * int (*detect)( void ) + * This function should detect the current video mode settings and + * store them in atari_fb_predefined[0] for later reference by the + * user. Return the index+1 of an equivalent predefined mode or 0 + * if there is no such. + * + * int (*encode_fix)( struct fb_fix_screeninfo *fix, + * struct atari_fb_par *par ) + * This function should fill in the 'fix' structure based on the + * values in the 'par' structure. + * + * int (*decode_var)( struct fb_var_screeninfo *var, + * struct atari_fb_par *par ) + * Get the video params out of 'var'. If a value doesn't fit, round + * it up, if it's too big, return EINVAL. + * Round up in the following order: bits_per_pixel, xres, yres, + * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + * horizontal timing, vertical timing. + * + * int (*encode_var)( struct fb_var_screeninfo *var, + * struct atari_fb_par *par ); + * Fill the 'var' structure based on the values in 'par' and maybe + * other values read out of the hardware. + * + * void (*get_par)( struct atari_fb_par *par ) + * Fill the hardware's 'par' structure. + * + * void (*set_par)( struct atari_fb_par *par ) + * Set the hardware according to 'par'. + * + * int (*setcolreg)( unsigned regno, unsigned red, + * unsigned green, unsigned blue, + * unsigned transp ) + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + * + * int (*getcolreg)( unsigned regno, unsigned *red, + * unsigned *green, unsigned *blue, + * unsigned *transp ) + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + * + * void (*set_screen_base)( unsigned long s_base ) + * Set the base address of the displayed frame buffer. Only called + * if yres_virtual > yres or xres_virtual > xres. + * + * int (*blank)( int blank_mode ) + * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then + * the caller blanks by setting the CLUT to all black. Return 0 if blanking + * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which + * doesn't support it. Implements VESA suspend and powerdown modes on + * hardware that supports disabling hsync/vsync: + * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown. + */ + +static struct fb_hwswitch { + int (*detect)( void ); + int (*encode_fix)( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ); + int (*decode_var)( struct fb_var_screeninfo *var, + struct atari_fb_par *par ); + int (*encode_var)( struct fb_var_screeninfo *var, + struct atari_fb_par *par ); + void (*get_par)( struct atari_fb_par *par ); + void (*set_par)( struct atari_fb_par *par ); + int (*getcolreg)( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ); + int (*setcolreg)( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ); + void (*set_screen_base)( unsigned long s_base ); + int (*blank)( int blank_mode ); + int (*pan_display)( struct fb_var_screeninfo *var, + struct atari_fb_par *par); +} *fbhw; + +static char *autodetect_names[] = {"autodetect", NULL}; +static char *stlow_names[] = {"stlow", NULL}; +static char *stmid_names[] = {"stmid", "default5", NULL}; +static char *sthigh_names[] = {"sthigh", "default4", NULL}; +static char *ttlow_names[] = {"ttlow", NULL}; +static char *ttmid_names[]= {"ttmid", "default1", NULL}; +static char *tthigh_names[]= {"tthigh", "default2", NULL}; +static char *vga2_names[] = {"vga2", NULL}; +static char *vga4_names[] = {"vga4", NULL}; +static char *vga16_names[] = {"vga16", "default3", NULL}; +static char *vga256_names[] = {"vga256", NULL}; +static char *falh2_names[] = {"falh2", NULL}; +static char *falh16_names[] = {"falh16", NULL}; +static char *user0_names[] = {"user0", NULL}; +static char *user1_names[] = {"user1", NULL}; +static char *user2_names[] = {"user2", NULL}; +static char *user3_names[] = {"user3", NULL}; +static char *user4_names[] = {"user4", NULL}; +static char *user5_names[] = {"user5", NULL}; +static char *user6_names[] = {"user6", NULL}; +static char *user7_names[] = {"user7", NULL}; +static char *dummy_names[] = {"dummy", NULL}; + +static char **fb_var_names[] = { + /* Writing the name arrays directly in this array (via "(char *[]){...}") + * crashes gcc 2.5.8 (sigsegv) if the inner array + * contains more than two items. I've also seen that all elements + * were identical to the last (my cross-gcc) :-(*/ + autodetect_names, + stlow_names, + stmid_names, + sthigh_names, + ttlow_names, + ttmid_names, + tthigh_names, + vga2_names, + vga4_names, + vga16_names, + vga256_names, + falh2_names, + falh16_names, + dummy_names, dummy_names, dummy_names, dummy_names, + dummy_names, dummy_names, dummy_names, dummy_names, + dummy_names, dummy_names, + user0_names, + user1_names, + user2_names, + user3_names, + user4_names, + user5_names, + user6_names, + user7_names, + NULL + /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ +}; + +static struct fb_var_screeninfo atari_fb_predefined[] = { + /* + * yres_virtual==0 means use hw-scrolling if possible, else yres + */ + { /* autodetect */ + 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st low */ + 320, 200, 320, 0, 0, 0, 4, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st mid */ + 640, 200, 640, 0, 0, 0, 2, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* st high */ + 640, 400, 640, 0, 0, 0, 1, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt low */ + 320, 480, 320, 0, 0, 0, 8, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt mid */ + 640, 480, 640, 0, 0, 0, 4, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* tt high */ + 1280, 960, 1280, 0, 0, 0, 1, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga2 */ + 640, 480, 640, 0, 0, 0, 1, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga4 */ + 640, 480, 640, 0, 0, 0, 2, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga16 */ + 640, 480, 640, 0, 0, 0, 4, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* vga256 */ + 640, 480, 640, 0, 0, 0, 8, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* falh2 */ + 896, 608, 896, 0, 0, 0, 1, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* falh16 */ + 896, 608, 896, 0, 0, 0, 4, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* Minor 14..23 free for more standard video modes */ + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + { 0, }, + /* Minor 24..31 reserved for user defined video modes */ + { /* user0, initialized to Rx;y;d from commandline, if supplied */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user1 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user2 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user3 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user4 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user5 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user6 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { /* user7 */ + 0, 0, 0, 0, 0, 0, 0, 0, + {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +static int num_atari_fb_predefined=arraysize(atari_fb_predefined); + + +static int +get_video_mode(char *vname) +{ + char ***name_list; + char **name; + int i; + name_list=fb_var_names; + for (i = 0 ; i < num_atari_fb_predefined ; i++) { + name=*(name_list++); + if (! name || ! *name) + break; + while (*name) { + if (! strcmp(vname, *name)) + return i+1; + name++; + } + } + return 0; +} + + + +/* ------------------- TT specific functions ---------------------- */ + +#ifdef ATAFB_TT + +static int tt_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) + +{ + int mode; + + strcpy(fix->id,"Atari Builtin"); + fix->smem_start = (char *)real_screen_base; + fix->smem_len = screen_len; + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK; + if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) { + fix->type=FB_TYPE_PACKED_PIXELS; + fix->type_aux=0; + if (mode == TT_SHIFTER_TTHIGH) + fix->visual=FB_VISUAL_MONO01; + } + fix->xpanstep=0; + fix->ypanstep=1; + fix->ywrapstep=0; + fix->line_length = 0; + return 0; +} + + +static int tt_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int xres=var->xres; + int yres=var->yres; + int bpp=var->bits_per_pixel; + int linelen; + int yres_virtual = var->yres_virtual; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_TTHIGH; + xres=sttt_xres*2; + yres=tt_yres*2; + bpp=1; + } else { + if (bpp > 8 || xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (bpp > 4) { + if (xres > sttt_xres/2 || yres > tt_yres) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_TTLOW; + xres=sttt_xres/2; + yres=tt_yres; + bpp=8; + } + else if (bpp > 2) { + if (xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (xres > sttt_xres/2 || yres > st_yres/2) { + par->hw.tt.mode=TT_SHIFTER_TTMID; + xres=sttt_xres; + yres=tt_yres; + bpp=4; + } + else { + par->hw.tt.mode=TT_SHIFTER_STLOW; + xres=sttt_xres/2; + yres=st_yres/2; + bpp=4; + } + } + else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres/2) + return -EINVAL; + par->hw.tt.mode=TT_SHIFTER_STMID; + xres=sttt_xres; + yres=st_yres/2; + bpp=2; + } + else if (var->xres > sttt_xres || var->yres > st_yres) { + return -EINVAL; + } + else { + par->hw.tt.mode=TT_SHIFTER_STHIGH; + xres=sttt_xres; + yres=st_yres; + bpp=1; + } + } + if (yres_virtual <= 0) + yres_virtual = 0; + else if (yres_virtual < yres) + yres_virtual = yres; + if (var->sync & FB_SYNC_EXT) + par->hw.tt.sync=0; + else + par->hw.tt.sync=1; + linelen=xres*bpp/8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; + par->screen_base = screen_base + var->yoffset * linelen; + return 0; +} + +static int tt_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int linelen, i; + var->red.offset=0; + var->red.length=4; + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these may be incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + if (par->hw.tt.sync & 1) + var->sync=0; + else + var->sync=FB_SYNC_EXT; + + switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) { + case TT_SHIFTER_STLOW: + var->xres=sttt_xres/2; + var->xres_virtual=sttt_xres_virtual/2; + var->yres=st_yres/2; + var->bits_per_pixel=4; + break; + case TT_SHIFTER_STMID: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=st_yres/2; + var->bits_per_pixel=2; + break; + case TT_SHIFTER_STHIGH: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=st_yres; + var->bits_per_pixel=1; + break; + case TT_SHIFTER_TTLOW: + var->xres=sttt_xres/2; + var->xres_virtual=sttt_xres_virtual/2; + var->yres=tt_yres; + var->bits_per_pixel=8; + break; + case TT_SHIFTER_TTMID: + var->xres=sttt_xres; + var->xres_virtual=sttt_xres_virtual; + var->yres=tt_yres; + var->bits_per_pixel=4; + break; + case TT_SHIFTER_TTHIGH: + var->red.length=0; + var->xres=sttt_xres*2; + var->xres_virtual=sttt_xres_virtual*2; + var->yres=tt_yres*2; + var->bits_per_pixel=1; + break; + } + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + linelen=var->xres_virtual * var->bits_per_pixel / 8; + if (! use_hwscroll) + var->yres_virtual=var->yres; + else if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else + /* yres_virtual==0 means use maximum */ + var->yres_virtual = screen_len / linelen; + } else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static void tt_get_par( struct atari_fb_par *par ) +{ + unsigned long addr; + par->hw.tt.mode=shifter_tt.tt_shiftmode; + par->hw.tt.sync=shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8) | + ((shifter.bas_lo & 0xff)); + par->screen_base = PTOV(addr); +} + +static void tt_set_par( struct atari_fb_par *par ) +{ + shifter_tt.tt_shiftmode=par->hw.tt.mode; + shifter.syncmode=par->hw.tt.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); +} + + +static int tt_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) +{ + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; + if (regno > 255) + return 1; + *blue = tt_palette[regno]; + *green = (*blue >> 4) & 0xf; + *red = (*blue >> 8) & 0xf; + *blue &= 0xf; + *transp = 0; + return 0; +} + + +static int tt_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) +{ + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; + if (regno > 255) + return 1; + tt_palette[regno] = (red << 8) | (green << 4) | blue; + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == + TT_SHIFTER_STHIGH && regno == 254) + tt_palette[0] = 0; + return 0; +} + + +static int tt_detect( void ) + +{ struct atari_fb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound + * Done Signal and the Monochrome Detect are XORed together! + * + * Even on a TT, we should look if there is a DMA sound. It was + * announced that the Eagle is TT compatible, but only the PCM is + * missing... + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + + tt_get_par(&par); + tt_encode_var(&atari_fb_predefined[0], &par); + + return 1; +} + +#endif /* ATAFB_TT */ + +/* ------------------- Falcon specific functions ---------------------- */ + +#ifdef ATAFB_FALCON + +static int mon_type; /* Falcon connected monitor */ +static int f030_bus_width; /* Falcon ram bus width (for vid_control) */ +#define F_MON_SM 0 +#define F_MON_SC 1 +#define F_MON_VGA 2 +#define F_MON_TV 3 + +/* Multisync monitor capabilities */ +/* Atari-TOS defaults if no boot option present */ +static long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000; + +static struct pixel_clock { + unsigned long f; /* f/[Hz] */ + unsigned long t; /* t/[ps] (=1/f) */ + int right, hsync, left; /* standard timing in clock cycles, not pixel */ + /* hsync initialized in falcon_detect() */ + int sync_mask; /* or-mask for hw.falcon.sync to set this clock */ + int control_mask; /* ditto, for hw.falcon.vid_control */ +} +f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25}, +f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, +fext = { 0, 0, 18, 0, 42, 0x1, 0}; + +/* VIDEL-prescale values [mon_type][pixel_length from VCO] */ +static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; + +/* Default hsync timing [mon_type] in picoseconds */ +static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000}; + + +static inline int hxx_prescale(struct falcon_hw *hw) +{ + return hw->ste_mode ? 16 : + vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; +} + +static int falcon_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) +{ + strcpy(fix->id, "Atari Builtin"); + fix->smem_start = (char *)real_screen_base; + fix->smem_len = screen_len; + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + if (par->hw.falcon.mono) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + /* no smooth scrolling with longword aligned video mem */ + fix->xpanstep = 32; + } + else if (par->hw.falcon.f_shift & 0x100) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + /* Is this ok or should it be DIRECTCOLOR? */ + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 2; + } + fix->line_length = 0; + return 0; +} + + +static int falcon_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int bpp = var->bits_per_pixel; + int xres = var->xres; + int yres = var->yres; + int xres_virtual = var->xres_virtual; + int yres_virtual = var->yres_virtual; + int left_margin, right_margin, hsync_len; + int upper_margin, lower_margin, vsync_len; + int linelen; + int interlace = 0, doubleline = 0; + struct pixel_clock *pclock; + int plen; /* width of pixel in clock cycles */ + int xstretch; + int prescale; + int longoffset = 0; + int hfreq, vfreq; + +/* + Get the video params out of 'var'. If a value doesn't fit, round + it up, if it's too big, return EINVAL. + Round up in the following order: bits_per_pixel, xres, yres, + xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + horizontal timing, vertical timing. + + There is a maximum of screen resolution determined by pixelclock + and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock. + In interlace mode this is " * " *vfmin <= pixelclock. + Additional constraints: hfreq. + Frequency range for multisync monitors is given via command line. + For TV and SM124 both frequencies are fixed. + + X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0) + Y % 16 == 0 to fit 8x16 font + Y % 8 == 0 if Y<400 + + Currently interlace and doubleline mode in var are ignored. + On SM124 and TV only the standard resolutions can be used. +*/ + + /* Reject uninitialized mode */ + if (!xres || !yres || !bpp) + return -EINVAL; + + if (mon_type == F_MON_SM && bpp != 1) { + return -EINVAL; + } + else if (bpp <= 1) { + bpp = 1; + par->hw.falcon.f_shift = 0x400; + par->hw.falcon.st_shift = 0x200; + } + else if (bpp <= 2) { + bpp = 2; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x100; + } + else if (bpp <= 4) { + bpp = 4; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x000; + } + else if (bpp <= 8) { + bpp = 8; + par->hw.falcon.f_shift = 0x010; + } + else if (bpp <= 16) { + bpp = 16; /* packed pixel mode */ + par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ + } + else + return -EINVAL; + par->hw.falcon.bpp = bpp; + + if (mon_type == F_MON_SM || DontCalcRes) { + /* Skip all calculations. VGA/TV/SC1224 only supported. */ + struct fb_var_screeninfo *myvar = &atari_fb_predefined[0]; + + if (bpp > myvar->bits_per_pixel || + var->xres > myvar->xres || + var->yres > myvar->yres) + return -EINVAL; + fbhw->get_par(par); /* Current par will be new par */ + goto set_screen_base; /* Don't forget this */ + } + + /* Only some fixed resolutions < 640x400 */ + if (xres <= 320) + xres = 320; + else if (xres <= 640 && bpp != 16) + xres = 640; + if (yres <= 200) + yres = 200; + else if (yres <= 240) + yres = 240; + else if (yres <= 400) + yres = 400; + + /* 2 planes must use STE compatibility mode */ + par->hw.falcon.ste_mode = bpp==2; + par->hw.falcon.mono = bpp==1; + + /* Total and visible scanline length must be a multiple of one longword, + * this and the console fontwidth yields the alignment for xres and + * xres_virtual. + * TODO: this way "odd" fontheights are not supported + * + * Special case in STE mode: blank and graphic positions don't align, + * avoid trash at right margin + */ + if (par->hw.falcon.ste_mode) + xres = (xres + 63) & ~63; + else if (bpp == 1) + xres = (xres + 31) & ~31; + else + xres = (xres + 15) & ~15; + if (yres >= 400) + yres = (yres + 15) & ~15; + else + yres = (yres + 7) & ~7; + + if (xres_virtual < xres) + xres_virtual = xres; + else if (bpp == 1) + xres_virtual = (xres_virtual + 31) & ~31; + else + xres_virtual = (xres_virtual + 15) & ~15; + + if (yres_virtual <= 0) + yres_virtual = 0; + else if (yres_virtual < yres) + yres_virtual = yres; + + /* backward bug-compatibility */ + if (var->pixclock > 1) + var->pixclock -= 1; + + par->hw.falcon.line_width = bpp * xres / 16; + par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16; + + /* single or double pixel width */ + xstretch = (xres < 640) ? 2 : 1; + +#if 0 /* SM124 supports only 640x400, this is rejected above */ + if (mon_type == F_MON_SM) { + if (xres != 640 && yres != 400) + return -EINVAL; + plen = 1; + pclock = &f32; + /* SM124-mode is special */ + par->hw.falcon.ste_mode = 1; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x200; + left_margin = hsync_len = 128 / plen; + right_margin = 0; + /* TODO set all margins */ + } + else +#endif + if (mon_type == F_MON_SC || mon_type == F_MON_TV) { + plen = 2 * xstretch; + if (var->pixclock > f32.t * plen) + return -EINVAL; + pclock = &f32; + if (yres > 240) + interlace = 1; + if (var->pixclock == 0) { + /* set some minimal margins which center the screen */ + left_margin = 32; + right_margin = 18; + hsync_len = pclock->hsync / plen; + upper_margin = 31; + lower_margin = 14; + vsync_len = interlace ? 3 : 4; + } else { + left_margin = var->left_margin; + right_margin = var->right_margin; + hsync_len = var->hsync_len; + upper_margin = var->upper_margin; + lower_margin = var->lower_margin; + vsync_len = var->vsync_len; + if (var->vmode & FB_VMODE_INTERLACED) { + upper_margin = (upper_margin + 1) / 2; + lower_margin = (lower_margin + 1) / 2; + vsync_len = (vsync_len + 1) / 2; + } else if (var->vmode & FB_VMODE_DOUBLE) { + upper_margin *= 2; + lower_margin *= 2; + vsync_len *= 2; + } + } + } + else + { /* F_MON_VGA */ + if (bpp == 16) + xstretch = 2; /* Double pixel width only for hicolor */ + /* Default values are used for vert./hor. timing if no pixelclock given. */ + if (var->pixclock == 0) { + int linesize; + + /* Choose master pixelclock depending on hor. timing */ + plen = 1 * xstretch; + if ((plen * xres + f25.right+f25.hsync+f25.left) * hfmin < f25.f) + pclock = &f25; + else if ((plen * xres + f32.right+f32.hsync+f32.left) * hfmin < f32.f) + pclock = &f32; + else if ((plen * xres + fext.right+fext.hsync+fext.left) * hfmin < fext.f + && fext.f) + pclock = &fext; + else + return -EINVAL; + + left_margin = pclock->left / plen; + right_margin = pclock->right / plen; + hsync_len = pclock->hsync / plen; + linesize = left_margin + xres + right_margin + hsync_len; + upper_margin = 31; + lower_margin = 11; + vsync_len = 3; + } + else { + /* Choose largest pixelclock <= wanted clock */ + int i; + unsigned long pcl = ULONG_MAX; + pclock = 0; + for (i=1; i <= 4; i *= 2) { + if (f25.t*i >= var->pixclock && f25.t*i < pcl) { + pcl = f25.t * i; + pclock = &f25; + } + if (f32.t*i >= var->pixclock && f32.t*i < pcl) { + pcl = f32.t * i; + pclock = &f32; + } + if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) { + pcl = fext.t * i; + pclock = &fext; + } + } + if (!pclock) + return -EINVAL; + plen = pcl / pclock->t; + + left_margin = var->left_margin; + right_margin = var->right_margin; + hsync_len = var->hsync_len; + upper_margin = var->upper_margin; + lower_margin = var->lower_margin; + vsync_len = var->vsync_len; + /* Internal unit is [single lines per (half-)frame] */ + if (var->vmode & FB_VMODE_INTERLACED) { + /* # lines in half frame */ + /* External unit is [lines per full frame] */ + upper_margin = (upper_margin + 1) / 2; + lower_margin = (lower_margin + 1) / 2; + vsync_len = (vsync_len + 1) / 2; + } + else if (var->vmode & FB_VMODE_DOUBLE) { + /* External unit is [double lines per frame] */ + upper_margin *= 2; + lower_margin *= 2; + vsync_len *= 2; + } + } + if (pclock == &fext) + longoffset = 1; /* VIDEL doesn't synchronize on short offset */ + } + /* Is video bus bandwidth (32MB/s) too low for this resolution? */ + /* this is definitely wrong if bus clock != 32MHz */ + if (pclock->f / plen / 8 * bpp > 32000000L) + return -EINVAL; + + if (vsync_len < 1) + vsync_len = 1; + + /* include sync lengths in right/lower margin for all calculations */ + right_margin += hsync_len; + lower_margin += vsync_len; + + /* ! In all calculations of margins we use # of lines in half frame + * (which is a full frame in non-interlace mode), so we can switch + * between interlace and non-interlace without messing around + * with these. + */ + again: + /* Set base_offset 128 and video bus width */ + par->hw.falcon.vid_control = mon_type | f030_bus_width; + if (!longoffset) + par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */ + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->hw.falcon.vid_control |= VCO_HSYPOS; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->hw.falcon.vid_control |= VCO_VSYPOS; + /* Pixelclock */ + par->hw.falcon.vid_control |= pclock->control_mask; + /* External or internal clock */ + par->hw.falcon.sync = pclock->sync_mask | 0x2; + /* Pixellength and prescale */ + par->hw.falcon.vid_mode = (2/plen) << 2; + if (doubleline) + par->hw.falcon.vid_mode |= VMO_DOUBLE; + if (interlace) + par->hw.falcon.vid_mode |= VMO_INTER; + + /********************* + Horizontal timing: unit = [master clock cycles] + unit of hxx-registers: [master clock cycles * prescale] + Hxx-registers are 9 bit wide + + 1 line = ((hht + 2) * 2 * prescale) clock cycles + + graphic output = hdb & 0x200 ? + ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: + ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff + (this must be a multiple of plen*128/bpp, on VGA pixels + to the right may be cut off with a bigger right margin) + + start of graphics relative to start of 1st halfline = hdb & 0x200 ? + (hdb - hht - 2) * prescale + hdboff : + hdb * prescale + hdboff + + end of graphics relative to start of 1st halfline = + (hde + hht + 2) * prescale + hdeoff + *********************/ + /* Calculate VIDEL registers */ + { + int hdb_off, hde_off, base_off; + int gstart, gend1, gend2, align; + + prescale = hxx_prescale(&par->hw.falcon); + base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; + + /* Offsets depend on video mode */ + /* Offsets are in clock cycles, divide by prescale to + * calculate hd[be]-registers + */ + if (par->hw.falcon.f_shift & 0x100) { + align = 1; + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; + } + else { + align = 128 / bpp; + hde_off = ((128 / bpp + 2) * plen); + if (par->hw.falcon.ste_mode) + hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale; + else + hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; + } + + gstart = (prescale/2 + plen * left_margin) / prescale; + /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ + gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; + /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ + gend2 = gstart + xres * plen / prescale; + par->HHT = plen * (left_margin + xres + right_margin) / + (2 * prescale) - 2; +/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ + + par->HDB = gstart - hdb_off/prescale; + par->HBE = gstart; + if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; + par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; + par->HBB = gend2 - par->HHT - 2; +#if 0 + /* One more Videl constraint: data fetch of two lines must not overlap */ + if (par->HDB & 0x200 && par->HDB & ~0x200 - par->HDE <= 5) { + /* if this happens increase margins, decrease hfreq. */ + } +#endif + if (hde_off % prescale) + par->HBB++; /* compensate for non matching hde and hbb */ + par->HSS = par->HHT + 2 - plen * hsync_len / prescale; + if (par->HSS < par->HBB) + par->HSS = par->HBB; + } + + /* check hor. frequency */ + hfreq = pclock->f / ((par->HHT+2)*prescale*2); + if (hfreq > hfmax && mon_type!=F_MON_VGA) { + /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ + /* Too high -> enlarge margin */ + left_margin += 1; + right_margin += 1; + goto again; + } + if (hfreq > hfmax || hfreq < hfmin) + return -EINVAL; + + /* Vxx-registers */ + /* All Vxx must be odd in non-interlace, since frame starts in the middle + * of the first displayed line! + * One frame consists of VFT+1 half lines. VFT+1 must be even in + * non-interlace, odd in interlace mode for synchronisation. + * Vxx-registers are 11 bit wide + */ + par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ + par->VDB = par->VBE; + par->VDE = yres; + if (!interlace) par->VDE <<= 1; + if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ + par->VDE += par->VDB; + par->VBB = par->VDE; + par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; + par->VSS = par->VFT+1 - (vsync_len * 2 - 1); + /* vbb,vss,vft must be even in interlace mode */ + if (interlace) { + par->VBB++; + par->VSS++; + par->VFT++; + } + + /* V-frequency check, hope I didn't create any loop here. */ + /* Interlace and doubleline are mutually exclusive. */ + vfreq = (hfreq * 2) / (par->VFT + 1); + if (vfreq > vfmax && !doubleline && !interlace) { + /* Too high -> try again with doubleline */ + doubleline = 1; + goto again; + } + else if (vfreq < vfmin && !interlace && !doubleline) { + /* Too low -> try again with interlace */ + interlace = 1; + goto again; + } + else if (vfreq < vfmin && doubleline) { + /* Doubleline too low -> clear doubleline and enlarge margins */ + int lines; + doubleline = 0; + for (lines=0; (hfreq*2)/(par->VFT+1+4*lines-2*yres)>vfmax; lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq > vfmax && doubleline) { + /* Doubleline too high -> enlarge margins */ + int lines; + for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines+=2) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq > vfmax && interlace) { + /* Interlace, too high -> enlarge margins */ + int lines; + for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; + } + else if (vfreq < vfmin || vfreq > vfmax) + return -EINVAL; + + set_screen_base: + linelen = xres_virtual * bpp / 8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; + par->screen_base = screen_base + var->yoffset * linelen; + par->hw.falcon.xoffset = 0; + + return 0; +} + +static int falcon_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ +/* !!! only for VGA !!! */ + int linelen, i; + int prescale, plen; + int hdb_off, hde_off, base_off; + struct falcon_hw *hw = &par->hw.falcon; + + /* possible frequencies: 25.175 or 32MHz */ + var->pixclock = hw->sync & 0x1 ? fext.t : + hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; + + var->height=-1; + var->width=-1; + + var->sync=0; + if (hw->vid_control & VCO_HSYPOS) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (hw->vid_control & VCO_VSYPOS) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + var->vmode = FB_VMODE_NONINTERLACED; + if (hw->vid_mode & VMO_INTER) + var->vmode |= FB_VMODE_INTERLACED; + if (hw->vid_mode & VMO_DOUBLE) + var->vmode |= FB_VMODE_DOUBLE; + + /* visible y resolution: + * Graphics display starts at line VDB and ends at line + * VDE. If interlace mode off unit of VC-registers is + * half lines, else lines. + */ + var->yres = hw->vde - hw->vdb; + if (!(var->vmode & FB_VMODE_INTERLACED)) + var->yres >>= 1; + if (var->vmode & FB_VMODE_DOUBLE) + var->yres >>= 1; + + /* to get bpp, we must examine f_shift and st_shift. + * f_shift is valid if any of bits no. 10, 8 or 4 + * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. + * if bit 10 set then bit 8 and bit 4 don't care... + * If all these bits are 0 get display depth from st_shift + * (as for ST and STE) + */ + if (hw->f_shift & 0x400) /* 2 colors */ + var->bits_per_pixel = 1; + else if (hw->f_shift & 0x100) /* hicolor */ + var->bits_per_pixel = 16; + else if (hw->f_shift & 0x010) /* 8 bitplanes */ + var->bits_per_pixel = 8; + else if (hw->st_shift == 0) + var->bits_per_pixel = 4; + else if (hw->st_shift == 0x100) + var->bits_per_pixel = 2; + else /* if (hw->st_shift == 0x200) */ + var->bits_per_pixel = 1; + + var->xres = hw->line_width * 16 / var->bits_per_pixel; + var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel; + if (hw->xoffset) + var->xres_virtual += 16; + + if (var->bits_per_pixel == 16) { + var->red.offset=11; + var->red.length=5; + var->red.msb_right=0; + var->green.offset=5; + var->green.length=6; + var->green.msb_right=0; + var->blue.offset=0; + var->blue.length=5; + var->blue.msb_right=0; + } + else { + var->red.offset=0; + var->red.length = hw->ste_mode ? 4 : 6; + var->red.msb_right=0; + var->grayscale=0; + var->blue=var->green=var->red; + } + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + + linelen = var->xres_virtual * var->bits_per_pixel / 8; + if (screen_len) + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else + /* yres_virtual==0 means use maximum */ + var->yres_virtual = screen_len / linelen; + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; /* TODO change this */ + + /* hdX-offsets */ + prescale = hxx_prescale(hw); + plen = 4 >> (hw->vid_mode >> 2 & 0x3); + base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128; + if (hw->f_shift & 0x100) { + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; + } + else { + hde_off = ((128 / var->bits_per_pixel + 2) * plen); + if (hw->ste_mode) + hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen) + + prescale; + else + hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen) + + prescale; + } + + /* Right margin includes hsync */ + var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) - + (hw->hdb & 0x200 ? 2+hw->hht : 0)); + if (hw->ste_mode || mon_type!=F_MON_VGA) + var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; + else + /* can't use this in ste_mode, because hbb is +1 off */ + var->right_margin = prescale * (hw->hht + 2 - hw->hbb); + var->hsync_len = prescale * (hw->hht + 2 - hw->hss); + + /* Lower margin includes vsync */ + var->upper_margin = hw->vdb / 2 ; /* round down to full lines */ + var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */ + var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */ + if (var->vmode & FB_VMODE_INTERLACED) { + var->upper_margin *= 2; + var->lower_margin *= 2; + var->vsync_len *= 2; + } + else if (var->vmode & FB_VMODE_DOUBLE) { + var->upper_margin = (var->upper_margin + 1) / 2; + var->lower_margin = (var->lower_margin + 1) / 2; + var->vsync_len = (var->vsync_len + 1) / 2; + } + + var->pixclock *= plen; + var->left_margin /= plen; + var->right_margin /= plen; + var->hsync_len /= plen; + + var->right_margin -= var->hsync_len; + var->lower_margin -= var->vsync_len; + + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; /* what is this for? */ + var->activate=0; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static int f_change_mode = 0; +static struct falcon_hw f_new_mode; +static int f_pan_display = 0; + +static void falcon_get_par( struct atari_fb_par *par ) +{ + unsigned long addr; + struct falcon_hw *hw = &par->hw.falcon; + + hw->line_width = shifter_f030.scn_width; + hw->line_offset = shifter_f030.off_next; + hw->st_shift = videl.st_shift & 0x300; + hw->f_shift = videl.f_shift; + hw->vid_control = videl.control; + hw->vid_mode = videl.mode; + hw->sync = shifter.syncmode & 0x1; + hw->xoffset = videl.xoffset & 0xf; + hw->hht = videl.hht; + hw->hbb = videl.hbb; + hw->hbe = videl.hbe; + hw->hdb = videl.hdb; + hw->hde = videl.hde; + hw->hss = videl.hss; + hw->vft = videl.vft; + hw->vbb = videl.vbb; + hw->vbe = videl.vbe; + hw->vdb = videl.vdb; + hw->vde = videl.vde; + hw->vss = videl.vss; + + addr = (shifter.bas_hi & 0xff) << 16 | + (shifter.bas_md & 0xff) << 8 | + (shifter.bas_lo & 0xff); + par->screen_base = PTOV(addr); + + /* derived parameters */ + hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100; + hw->mono = (hw->f_shift & 0x400) || + ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200); +} + +static void falcon_set_par( struct atari_fb_par *par ) +{ + f_change_mode = 0; + + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); + + /* Don't touch any other registers if we keep the default resolution */ + if (DontCalcRes) + return; + + /* Tell vbl-handler to change video mode. + * We change modes only on next VBL, to avoid desynchronisation + * (a shift to the right and wrap around by a random number of pixels + * in all monochrome modes). + * This seems to work on my Falcon. + */ + f_new_mode = par->hw.falcon; + f_change_mode = 1; +} + + +static void falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp ) +{ + struct falcon_hw *hw = &f_new_mode; + + if (f_change_mode) { + f_change_mode = 0; + + if (hw->sync & 0x1) { + /* Enable external pixelclock. This code only for ScreenWonder */ + *(volatile unsigned short*)0xffff9202 = 0xffbf; + } + else { + /* Turn off external clocks. Read sets all output bits to 1. */ + *(volatile unsigned short*)0xffff9202; + } + shifter.syncmode = hw->sync; + + videl.hht = hw->hht; + videl.hbb = hw->hbb; + videl.hbe = hw->hbe; + videl.hdb = hw->hdb; + videl.hde = hw->hde; + videl.hss = hw->hss; + videl.vft = hw->vft; + videl.vbb = hw->vbb; + videl.vbe = hw->vbe; + videl.vdb = hw->vdb; + videl.vde = hw->vde; + videl.vss = hw->vss; + + videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ + if (hw->ste_mode) { + videl.st_shift = hw->st_shift; /* write enables STE palette */ + } + else { + /* IMPORTANT: + * set st_shift 0, so we can tell the screen-depth if f_shift==0. + * Writing 0 to f_shift enables 4 plane Falcon mode but + * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible + * with Falcon palette. + */ + videl.st_shift = 0; + /* now back to Falcon palette mode */ + videl.f_shift = hw->f_shift; + } + /* writing to st_shift changed scn_width and vid_mode */ + videl.xoffset = hw->xoffset; + shifter_f030.scn_width = hw->line_width; + shifter_f030.off_next = hw->line_offset; + videl.control = hw->vid_control; + videl.mode = hw->vid_mode; + } + if (f_pan_display) { + f_pan_display = 0; + videl.xoffset = current_par.hw.falcon.xoffset; + shifter_f030.off_next = current_par.hw.falcon.line_offset; + } +} + + +static int falcon_pan_display( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int xoffset; + int bpp = fb_display[currcon].var.bits_per_pixel; + + if (bpp == 1) + var->xoffset = up(var->xoffset, 32); + if (bpp != 16) + par->hw.falcon.xoffset = var->xoffset & 15; + else { + par->hw.falcon.xoffset = 0; + var->xoffset = up(var->xoffset, 2); + } + par->hw.falcon.line_offset = bpp * + (fb_display[currcon].var.xres_virtual - fb_display[currcon].var.xres) / 16; + if (par->hw.falcon.xoffset) + par->hw.falcon.line_offset -= bpp; + xoffset = var->xoffset - par->hw.falcon.xoffset; + + par->screen_base = screen_base + + (var->yoffset * fb_display[currcon].var.xres_virtual + xoffset) * bpp / 8; + if (fbhw->set_screen_base) + fbhw->set_screen_base (par->screen_base); + else + return -EINVAL; /* shouldn't happen */ + f_pan_display = 1; + return 0; +} + + +static int falcon_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) +{ unsigned long col; + + if (regno > 255) + return 1; + /* This works in STE-mode (with 4bit/color) since f030_col-registers + * hold up to 6bit/color. + * Even with hicolor r/g/b=5/6/5 bit! + */ + col = f030_col[regno]; + *red = (col >> 26) & 0x3f; + *green = (col >> 18) & 0x3f; + *blue = (col >> 2) & 0x3f; + *transp = 0; + return 0; +} + + +static int falcon_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) +{ + if (regno > 255) + return 1; + f030_col[regno] = (red << 26) | (green << 18) | (blue << 2); + if (regno < 16) { + shifter_tt.color_reg[regno] = + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); +#ifdef CONFIG_FBCON_CFB16 + packed16_cmap[regno] = (red << 11) | (green << 5) | blue; +#endif + } + return 0; +} + + +static int falcon_blank( int blank_mode ) +{ +/* ++guenther: we can switch off graphics by changing VDB and VDE, + * so VIDEL doesn't hog the bus while saving. + * (this may affect usleep()). + */ + int vdb, vss, hbe, hss; + + if (mon_type == F_MON_SM) /* this doesn't work on SM124 */ + return 1; + + vdb = current_par.VDB; + vss = current_par.VSS; + hbe = current_par.HBE; + hss = current_par.HSS; + + if (blank_mode >= 1) { + /* disable graphics output (this speeds up the CPU) ... */ + vdb = current_par.VFT + 1; + /* ... and blank all lines */ + hbe = current_par.HHT + 2; + } + /* use VESA suspend modes on VGA monitors */ + if (mon_type == F_MON_VGA) { + if (blank_mode == 2 || blank_mode == 4) + vss = current_par.VFT + 1; + if (blank_mode == 3 || blank_mode == 4) + hss = current_par.HHT + 2; + } + + videl.vdb = vdb; + videl.vss = vss; + videl.hbe = hbe; + videl.hss = hss; + + return 0; +} + + +static int falcon_detect( void ) +{ + struct atari_fb_par par; + unsigned char fhw; + + /* Determine connected monitor and set monitor parameters */ + fhw = *(unsigned char*)0xffff8006; + mon_type = fhw >> 6 & 0x3; + /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */ + f030_bus_width = fhw << 6 & 0x80; + switch (mon_type) { + case F_MON_SM: + vfmin = 70; + vfmax = 72; + hfmin = 35713; + hfmax = 35715; + break; + case F_MON_SC: + case F_MON_TV: + /* PAL...NTSC */ + vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ + vfmax = 60; + hfmin = 15620; + hfmax = 15755; + break; + } + /* initialize hsync-len */ + f25.hsync = h_syncs[mon_type] / f25.t; + f32.hsync = h_syncs[mon_type] / f32.t; + if (fext.t) + fext.hsync = h_syncs[mon_type] / fext.t; + + falcon_get_par(&par); + falcon_encode_var(&atari_fb_predefined[0], &par); + + /* Detected mode is always the "autodetect" slot */ + return 1; +} + +#endif /* ATAFB_FALCON */ + +/* ------------------- ST(E) specific functions ---------------------- */ + +#ifdef ATAFB_STE + +static int stste_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) + +{ + int mode; + + strcpy(fix->id,"Atari Builtin"); + fix->smem_start = (char *)real_screen_base; + fix->smem_len = screen_len; + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.st.mode & 3; + if (mode == ST_HIGH) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = FB_VISUAL_MONO10; + } + if (ATARIHW_PRESENT(EXTD_SHIFTER)) { + fix->xpanstep = 16; + fix->ypanstep = 1; + } else { + fix->xpanstep = 0; + fix->ypanstep = 0; + } + fix->ywrapstep = 0; + fix->line_length = 0; + return 0; +} + + +static int stste_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int xres=var->xres; + int yres=var->yres; + int bpp=var->bits_per_pixel; + int linelen; + int yres_virtual = var->yres_virtual; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + par->hw.st.mode=ST_HIGH; + xres=sttt_xres; + yres=st_yres; + bpp=1; + } else { + if (bpp > 4 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + if (bpp > 2) { + if (xres > sttt_xres/2 || yres > st_yres/2) + return -EINVAL; + par->hw.st.mode=ST_LOW; + xres=sttt_xres/2; + yres=st_yres/2; + bpp=4; + } + else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres/2) + return -EINVAL; + par->hw.st.mode=ST_MID; + xres=sttt_xres; + yres=st_yres/2; + bpp=2; + } + else + return -EINVAL; + } + if (yres_virtual <= 0) + yres_virtual = 0; + else if (yres_virtual < yres) + yres_virtual = yres; + if (var->sync & FB_SYNC_EXT) + par->hw.st.sync=(par->hw.st.sync & ~1) | 1; + else + par->hw.st.sync=(par->hw.st.sync & ~1); + linelen=xres*bpp/8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) + return -EINVAL; + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; + par->screen_base=screen_base+ var->yoffset*linelen; + return 0; +} + +static int stste_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int linelen, i; + var->red.offset=0; + var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these are incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + if (!(par->hw.st.sync & 1)) + var->sync=0; + else + var->sync=FB_SYNC_EXT; + + switch (par->hw.st.mode & 3) { + case ST_LOW: + var->xres=sttt_xres/2; + var->yres=st_yres/2; + var->bits_per_pixel=4; + break; + case ST_MID: + var->xres=sttt_xres; + var->yres=st_yres/2; + var->bits_per_pixel=2; + break; + case ST_HIGH: + var->xres=sttt_xres; + var->yres=st_yres; + var->bits_per_pixel=1; + break; + } + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->xres_virtual=sttt_xres_virtual; + linelen=var->xres_virtual * var->bits_per_pixel / 8; + ovsc_addlen=linelen*(sttt_yres_virtual - st_yres); + + if (! use_hwscroll) + var->yres_virtual=var->yres; + else if (screen_len) + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else + /* yres_virtual==0 means use maximum */ + var->yres_virtual = screen_len / linelen; + else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else + var->yres_virtual=var->yres+hwscroll * 16; + } + var->xoffset=0; + if (screen_base) + var->yoffset=(par->screen_base - screen_base)/linelen; + else + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static void stste_get_par( struct atari_fb_par *par ) +{ + unsigned long addr; + par->hw.st.mode=shifter_tt.st_shiftmode; + par->hw.st.sync=shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + addr |= (shifter.bas_lo & 0xff); + par->screen_base = PTOV(addr); +} + +static void stste_set_par( struct atari_fb_par *par ) +{ + shifter_tt.st_shiftmode=par->hw.st.mode; + shifter.syncmode=par->hw.st.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); +} + + +static int stste_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) +{ unsigned col; + + if (regno > 15) + return 1; + col = shifter_tt.color_reg[regno]; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) { + *red = ((col >> 7) & 0xe) | ((col >> 11) & 1); + *green = ((col >> 3) & 0xe) | ((col >> 7) & 1); + *blue = ((col << 1) & 0xe) | ((col >> 3) & 1); + } + else { + *red = (col >> 8) & 0x7; + *green = (col >> 4) & 0x7; + *blue = col & 0x7; + } + *transp = 0; + return 0; +} + + +static int stste_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) +{ + if (regno > 15) + return 1; + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + shifter_tt.color_reg[regno] = + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); + else + shifter_tt.color_reg[regno] = + ((red & 0x7) << 8) | + ((green & 0x7) << 4) | + (blue & 0x7); + return 0; +} + + +static int stste_detect( void ) + +{ struct atari_fb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound + * Done Signal and the Monochrome Detect are XORed together! + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + + stste_get_par(&par); + stste_encode_var(&atari_fb_predefined[0], &par); + + if (!ATARIHW_PRESENT(EXTD_SHIFTER)) + use_hwscroll = 0; + return 1; +} + +static void stste_set_screen_base(unsigned long s_base) +{ + unsigned long addr; + addr= VTOP(s_base); + /* Setup Screen Memory */ + shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); + shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) + shifter.bas_lo=(unsigned char) (addr & 0x0000ff); +} + +#endif /* ATAFB_STE */ + +/* Switching the screen size should be done during vsync, otherwise + * the margins may get messed up. This is a well known problem of + * the ST's video system. + * + * Unfortunately there is hardly any way to find the vsync, as the + * vertical blank interrupt is no longer in time on machines with + * overscan type modifications. + * + * We can, however, use Timer B to safely detect the black shoulder, + * but then we've got to guess an appropriate delay to find the vsync. + * This might not work on every machine. + * + * martin_rogge @ ki.maus.de, 8th Aug 1995 + */ + +#define LINE_DELAY (mono_moni ? 30 : 70) +#define SYNC_DELAY (mono_moni ? 1500 : 2000) + +/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */ +static void st_ovsc_switch(int switchmode) +{ + unsigned long flags; + register unsigned char old, new; + + if ((switchmode & (SWITCH_ACIA | SWITCH_SND6 | SWITCH_SND7)) == 0) + return; + save_flags(flags); + cli(); + + mfp.tim_ct_b = 0x10; + mfp.active_edge |= 8; + mfp.tim_ct_b = 0; + mfp.tim_dt_b = 0xf0; + mfp.tim_ct_b = 8; + while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ + ; + new = mfp.tim_dt_b; + do { + udelay(LINE_DELAY); + old = new; + new = mfp.tim_dt_b; + } while (old != new); + mfp.tim_ct_b = 0x10; + udelay(SYNC_DELAY); + + if (switchmode == SWITCH_ACIA) + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE); + else { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | switchmode; + } + restore_flags(flags); +} + +/* ------------------- External Video ---------------------- */ + +#ifdef ATAFB_EXT + +static int ext_encode_fix( struct fb_fix_screeninfo *fix, + struct atari_fb_par *par ) + +{ + strcpy(fix->id,"Unknown Extern"); + fix->smem_start=(char *)external_addr; + fix->smem_len=(external_len + PAGE_SIZE -1) & PAGE_MASK; + if (external_depth == 1) { + fix->type = FB_TYPE_PACKED_PIXELS; + /* The letters 'n' and 'i' in the "atavideo=external:" stand + * for "normal" and "inverted", rsp., in the monochrome case */ + fix->visual = + (external_pmode == FB_TYPE_INTERLEAVED_PLANES || + external_pmode == FB_TYPE_PACKED_PIXELS) ? + FB_VISUAL_MONO10 : + FB_VISUAL_MONO01; + } + else { + /* Use STATIC if we don't know how to access color registers */ + int visual = external_vgaiobase ? + FB_VISUAL_PSEUDOCOLOR : + FB_VISUAL_STATIC_PSEUDOCOLOR; + switch (external_pmode) { + case -1: /* truecolor */ + fix->type=FB_TYPE_PACKED_PIXELS; + fix->visual=FB_VISUAL_TRUECOLOR; + break; + case FB_TYPE_PACKED_PIXELS: + fix->type=FB_TYPE_PACKED_PIXELS; + fix->visual=visual; + break; + case FB_TYPE_PLANES: + fix->type=FB_TYPE_PLANES; + fix->visual=visual; + break; + case FB_TYPE_INTERLEAVED_PLANES: + fix->type=FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux=2; + fix->visual=visual; + break; + } + } + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + return 0; +} + + +static int ext_decode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + struct fb_var_screeninfo *myvar = &atari_fb_predefined[0]; + + if (var->bits_per_pixel > myvar->bits_per_pixel || + var->xres > myvar->xres || + var->xres_virtual > myvar->xres_virtual || + var->yres > myvar->yres || + var->xoffset > 0 || + var->yoffset > 0) + return -EINVAL; + return 0; +} + + +static int ext_encode_var( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + int i; + + var->red.offset=0; + var->red.length=(external_pmode == -1) ? external_depth/3 : + (external_vgaiobase ? external_bitspercol : 0); + var->red.msb_right=0; + var->grayscale=0; + + var->pixclock=31041; + var->left_margin=120; /* these are surely incorrect */ + var->right_margin=100; + var->upper_margin=8; + var->lower_margin=16; + var->hsync_len=140; + var->vsync_len=30; + + var->height=-1; + var->width=-1; + + var->sync=0; + + var->xres = external_xres; + var->yres = external_yres; + var->xres_virtual = external_xres_virtual; + var->bits_per_pixel = external_depth; + + var->blue=var->green=var->red; + var->transp.offset=0; + var->transp.length=0; + var->transp.msb_right=0; + var->yres_virtual=var->yres; + var->xoffset=0; + var->yoffset=0; + var->nonstd=0; + var->activate=0; + var->vmode=FB_VMODE_NONINTERLACED; + for (i=0; ireserved); i++) + var->reserved[i]=0; + return 0; +} + + +static void ext_get_par( struct atari_fb_par *par ) +{ + par->screen_base = external_addr; +} + +static void ext_set_par( struct atari_fb_par *par ) +{ +} + +#define OUTB(port,val) \ + *((unsigned volatile char *) ((port)+external_vgaiobase))=(val) +#define INB(port) \ + (*((unsigned volatile char *) ((port)+external_vgaiobase))) +#define DACDelay \ + do { \ + unsigned char tmp=INB(0x3da); \ + tmp=INB(0x3da); \ + } while (0) + +static int ext_getcolreg( unsigned regno, unsigned *red, + unsigned *green, unsigned *blue, + unsigned *transp ) + +{ unsigned char colmask = (1 << external_bitspercol) - 1; + + if (! external_vgaiobase) + return 1; + + *red = ext_color[regno].red; + *green = ext_color[regno].green; + *blue = ext_color[regno].blue; + *transp=0; + return 0; +} + +static int ext_setcolreg( unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp ) + +{ unsigned char colmask = (1 << external_bitspercol) - 1; + + if (! external_vgaiobase) + return 1; + + ext_color[regno].red = red; + ext_color[regno].green = green; + ext_color[regno].blue = blue; + + switch (external_card_type) { + case IS_VGA: + OUTB(0x3c8, regno); + DACDelay; + OUTB(0x3c9, red & colmask); + DACDelay; + OUTB(0x3c9, green & colmask); + DACDelay; + OUTB(0x3c9, blue & colmask); + DACDelay; + return 0; + + case IS_MV300: + OUTB((MV300_reg[regno] << 2)+1, red); + OUTB((MV300_reg[regno] << 2)+1, green); + OUTB((MV300_reg[regno] << 2)+1, blue); + return 0; + + default: + return 1; + } +} + + +static int ext_detect( void ) + +{ + struct fb_var_screeninfo *myvar = &atari_fb_predefined[0]; + struct atari_fb_par dummy_par; + + myvar->xres = external_xres; + myvar->xres_virtual = external_xres_virtual; + myvar->yres = external_yres; + myvar->bits_per_pixel = external_depth; + ext_encode_var(myvar, &dummy_par); + return 1; +} + +#endif /* ATAFB_EXT */ + +/* ------ This is the same for most hardware types -------- */ + +static void set_screen_base(unsigned long s_base) +{ + unsigned long addr; + addr= VTOP(s_base); + /* Setup Screen Memory */ + shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); + shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + shifter.bas_lo=(unsigned char) (addr & 0x0000ff); +} + + +static int pan_display( struct fb_var_screeninfo *var, + struct atari_fb_par *par ) +{ + if (!fbhw->set_screen_base || + (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) + return -EINVAL; + var->xoffset = up(var->xoffset, 16); + par->screen_base = screen_base + + (var->yoffset * fb_display[currcon].var.xres_virtual + var->xoffset) + * fb_display[currcon].var.bits_per_pixel / 8; + fbhw->set_screen_base (par->screen_base); + return 0; +} + + +/* ------------ Interfaces to hardware functions ------------ */ + + +#ifdef ATAFB_TT +static struct fb_hwswitch tt_switch = { + tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, + tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg, + set_screen_base, NULL, pan_display +}; +#endif + +#ifdef ATAFB_FALCON +static struct fb_hwswitch falcon_switch = { + falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, + falcon_get_par, falcon_set_par, falcon_getcolreg, + falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display +}; +#endif + +#ifdef ATAFB_STE +static struct fb_hwswitch st_switch = { + stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, + stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg, + stste_set_screen_base, NULL, pan_display +}; +#endif + +#ifdef ATAFB_EXT +static struct fb_hwswitch ext_switch = { + ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, + ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL +}; +#endif + + + +static void atari_fb_get_par( struct atari_fb_par *par ) +{ + if (current_par_valid) { + *par=current_par; + } + else + fbhw->get_par(par); +} + + +static void atari_fb_set_par( struct atari_fb_par *par ) +{ + fbhw->set_par(par); + current_par=*par; + current_par_valid=1; +} + + + +/* =========================================================== */ +/* ============== Hardware Independent Functions ============= */ +/* =========================================================== */ + + +/* used for hardware scrolling */ + +static int +fb_update_var(int con) +{ + int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual* + fb_display[con].var.bits_per_pixel>>3; + + current_par.screen_base=screen_base + off; + + if (fbhw->set_screen_base) + fbhw->set_screen_base(current_par.screen_base); + return 0; +} + +static int +do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err,activate; + struct atari_fb_par par; + if ((err=fbhw->decode_var(var, &par))) + return err; + activate=var->activate; + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) + atari_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate=activate; + return 0; +} + +/* Functions for handling colormap */ + +static void +do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &(fb_display[con].var), 1, + fbhw->setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &(fb_display[con].var), 1, + fbhw->setcolreg); +} + + + /* + * Open/Release the frame buffer device + */ + +static int atari_fb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int atari_fb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + + +static int +atari_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct atari_fb_par par; + if (con == -1) + atari_fb_get_par(&par); + else + fbhw->decode_var(&fb_display[con].var,&par); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + return fbhw->encode_fix(fix, &par); +} + +static int +atari_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct atari_fb_par par; + if (con == -1) { + atari_fb_get_par(&par); + fbhw->encode_var(var, &par); + } + else + *var=fb_display[con].var; + return 0; +} + +static void +atari_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + atari_fb_get_fix(&fix, con); + if (con == -1) + con=0; + display->screen_base = (u_char *)fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + if (fix.visual != FB_VISUAL_PSEUDOCOLOR && + fix.visual != FB_VISUAL_DIRECTCOLOR) + display->can_soft_blank = 0; + else + display->can_soft_blank = 1; + display->inverse = + (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); +} + +static int +atari_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err,oldxres,oldyres,oldbpp,oldxres_virtual, + oldyres_virtual,oldyoffset; + if ((err=do_fb_set_var(var, con==currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres=fb_display[con].var.xres; + oldyres=fb_display[con].var.yres; + oldxres_virtual=fb_display[con].var.xres_virtual; + oldyres_virtual=fb_display[con].var.yres_virtual; + oldbpp=fb_display[con].var.bits_per_pixel; + oldyoffset=fb_display[con].var.yoffset; + fb_display[con].var=*var; + if (oldxres != var->xres || oldyres != var->yres + || oldxres_virtual != var->xres_virtual + || oldyres_virtual != var->yres_virtual + || oldbpp != var->bits_per_pixel + || oldyoffset != var->yoffset) { + atari_fb_set_disp(con); + (*fb_info.changevar)(con); + fb_alloc_cmap(&fb_display[con].cmap, 0, 0); + do_install_cmap(con); + } + } + var->activate=0; + return 0; +} + + + +static int +atari_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console ? */ + return fb_get_cmap(cmap, &(fb_display[con].var), kspc, + fbhw->getcolreg); + else + if (fb_display[con].cmap.len) /* non default colormap ? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + +static int +atari_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + if (! fb_display[con].cmap.len) { /* no colormap allocated ? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1 << fb_display[con].var.bits_per_pixel, + 0))) + return err; + } + if (con == currcon) /* current console ? */ + return fb_set_cmap(cmap, &(fb_display[con].var), kspc, + fbhw->setcolreg); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + return 0; +} + +static int +atari_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + int xoffset = var->xoffset; + int yoffset = var->yoffset; + int err; + + if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual + || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) + return -EINVAL; + + if (con == currcon) { + if (fbhw->pan_display) { + if ((err = fbhw->pan_display(var, ¤t_par))) + return err; + } + else + return -EINVAL; + } + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + return 0; +} + +static int +atari_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con) +{ + switch (cmd) { +#ifdef FBCMD_GET_CURRENTPAR + case FBCMD_GET_CURRENTPAR: + if (copy_to_user((void *)arg, (void *)¤t_par, + sizeof(struct atari_fb_par))) + return -EFAULT; + return 0; +#endif +#ifdef FBCMD_SET_CURRENTPAR + case FBCMD_SET_CURRENTPAR: + if (copy_from_user((void *)¤t_par, (void *)arg, + sizeof(struct atari_fb_par))) + return -EFAULT; + atari_fb_set_par(¤t_par); + return 0; +#endif + } + return -EINVAL; +} + +static struct fb_ops atari_fb_ops = { + atari_fb_open, atari_fb_release, atari_fb_get_fix, atari_fb_get_var, + atari_fb_set_var, atari_fb_get_cmap, atari_fb_set_cmap, + atari_fb_pan_display, atari_fb_ioctl +}; + +static void +check_default_par( int detected_mode ) +{ + char default_name[10]; + int i; + struct fb_var_screeninfo var; + unsigned long min_mem; + + /* First try the user supplied mode */ + if (default_par) { + var=atari_fb_predefined[default_par-1]; + var.activate = FB_ACTIVATE_TEST; + if (do_fb_set_var(&var,1)) + default_par=0; /* failed */ + } + /* Next is the autodetected one */ + if (! default_par) { + var=atari_fb_predefined[detected_mode-1]; /* autodetect */ + var.activate = FB_ACTIVATE_TEST; + if (!do_fb_set_var(&var,1)) + default_par=detected_mode; + } + /* If that also failed, try some default modes... */ + if (! default_par) { + /* try default1, default2... */ + for (i=1 ; i < 10 ; i++) { + sprintf(default_name,"default%d",i); + default_par=get_video_mode(default_name); + if (! default_par) + panic("can't set default video mode\n"); + var=atari_fb_predefined[default_par-1]; + var.activate = FB_ACTIVATE_TEST; + if (! do_fb_set_var(&var,1)) + break; /* ok */ + } + } + min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8; + if (default_mem_req < min_mem) + default_mem_req=min_mem; +} + +static int +atafb_switch(int con) +{ + /* Do we have to save the colormap ? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, + &(fb_display[currcon].var), 1, fbhw->getcolreg); + do_fb_set_var(&fb_display[con].var,1); + currcon=con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + +/* (un)blank/poweroff + * 0 = unblank + * 1 = blank + * 2 = suspend vsync + * 3 = suspend hsync + * 4 = off + */ +static void +atafb_blank(int blank) +{ + unsigned short black[16]; + struct fb_cmap cmap; + if (fbhw->blank && !fbhw->blank(blank)) + return; + if (blank) { + memset(black, 0, 16*sizeof(unsigned short)); + cmap.red=black; + cmap.green=black; + cmap.blue=black; + cmap.transp=NULL; + cmap.start=0; + cmap.len=16; + fb_set_cmap(&cmap, &(fb_display[currcon].var), 1, + fbhw->setcolreg); + } + else + do_install_cmap(currcon); +} + +static int +atafb_setcmap(struct fb_cmap *cmap, int con) +{ + return(atari_fb_set_cmap(cmap, 1, con)); +} + +__initfunc(unsigned long atari_fb_init(unsigned long mem_start)) +{ + int err; + int pad; + int detected_mode; + unsigned long mem_req; + + if (!MACH_IS_ATARI) + return mem_start; + + do { +#ifdef ATAFB_EXT + if (external_addr) { + fbhw = &ext_switch; + break; + } +#endif +#ifdef ATAFB_TT + if (ATARIHW_PRESENT(TT_SHIFTER)) { + fbhw = &tt_switch; + break; + } +#endif +#ifdef ATAFB_FALCON + if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { + fbhw = &falcon_switch; + request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, + "framebuffer/modeswitch", falcon_vbl_switcher); + break; + } +#endif +#ifdef ATAFB_STE + if (ATARIHW_PRESENT(STND_SHIFTER) || + ATARIHW_PRESENT(EXTD_SHIFTER)) { + fbhw = &st_switch; + break; + } + fbhw = &st_switch; + printk("Cannot determine video hardware; defaulting to ST(e)\n"); +#else /* ATAFB_STE */ + /* no default driver included */ + /* Nobody will ever see this message :-) */ + panic("Cannot initialize video hardware\n"); +#endif + } while (0); + detected_mode = fbhw->detect(); + check_default_par(detected_mode); +#ifdef ATAFB_EXT + if (!external_addr) { +#endif /* ATAFB_EXT */ + mem_req = default_mem_req + ovsc_offset + + ovsc_addlen; + mem_req = ((mem_req + PAGE_SIZE - 1) & PAGE_MASK) + PAGE_SIZE; + screen_base = (unsigned long) atari_stram_alloc(mem_req, &mem_start); + memset((char *) screen_base, 0, mem_req); + pad = ((screen_base + PAGE_SIZE-1) & PAGE_MASK) - screen_base; + screen_base+=pad; + real_screen_base=screen_base+ovsc_offset; + screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; + st_ovsc_switch(ovsc_switchmode); + if (CPU_IS_040_OR_060) { + /* On a '040+, the cache mode of video RAM must be set to + * write-through also for internal video hardware! */ + cache_push( VTOP(screen_base), screen_len ); + kernel_set_cachemode( screen_base, screen_len, + KERNELMAP_NO_COPYBACK ); + } +#ifdef ATAFB_EXT + } + else { + /* Map the video memory (physical address given) to somewhere + * in the kernel address space. + */ + mem_start = PAGE_ALIGN(mem_start); + external_addr = kernel_map(external_addr, external_len, + KERNELMAP_NO_COPYBACK, &mem_start); + if (external_vgaiobase) + external_vgaiobase = kernel_map(external_vgaiobase, + 0x10000, KERNELMAP_NOCACHE_SER, &mem_start); + mem_start += PAGE_SIZE; + screen_base = + real_screen_base = external_addr; + screen_len = external_len & PAGE_MASK; + memset ((char *) screen_base, 0, external_len); + } +#endif /* ATAFB_EXT */ + + strcpy(fb_info.modename, "Atari Builtin "); + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &atari_fb_ops; + fb_info.fbvar_num = num_atari_fb_predefined; + fb_info.fbvar = atari_fb_predefined; + fb_info.disp = &disp; + fb_info.switch_con = &atafb_switch; + fb_info.updatevar = &fb_update_var; + fb_info.blank = &atafb_blank; + fb_info.setcmap = &atafb_setcmap; + do_fb_set_var(&atari_fb_predefined[default_par-1], 1); + strcat(fb_info.modename, fb_var_names[default_par-1][0]); + + err=register_framebuffer(&fb_info); + if (err < 0) + return(err); + + atari_fb_get_var(&disp.var, -1); + atari_fb_set_disp(-1); + printk("Determined %dx%d, depth %d\n", + disp.var.xres, disp.var.yres, disp.var.bits_per_pixel); + if ((disp.var.xres != disp.var.xres_virtual) || + (disp.var.yres != disp.var.yres_virtual)) + printk(" virtual %dx%d\n", + disp.var.xres_virtual, disp.var.yres_virtual); + do_install_cmap(0); + printk("%s frame buffer device, using %dK of video memory\n", + fb_info.modename, screen_len>>10); + + /* TODO: This driver cannot be unloaded yet */ + MOD_INC_USE_COUNT; + + return mem_start; +} + +/* a strtok which returns empty strings, too */ + +static char * strtoke(char * s,const char * ct) +{ + char *sbegin, *send; + static char *ssave = NULL; + + sbegin = s ? s : ssave; + if (!sbegin) { + return NULL; + } + if (*sbegin == '\0') { + ssave = NULL; + return NULL; + } + send = strpbrk(sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ssave = send; + return sbegin; +} + +__initfunc(void atari_video_setup( char *options, int *ints )) +{ + char *this_opt; + int temp; + char ext_str[80], int_str[100]; + char mcap_spec[80]; + char user_mode[80]; + + ext_str[0] = + int_str[0] = + mcap_spec[0] = + user_mode[0] = + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + if (!*this_opt) continue; + if ((temp=get_video_mode(this_opt))) + default_par=temp; + else if (! strcmp(this_opt, "inverse")) + inverse=1; + else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else if (! strncmp(this_opt, "hwscroll_",9)) { + hwscroll=simple_strtoul(this_opt+9, NULL, 10); + if (hwscroll < 0) + hwscroll = 0; + if (hwscroll > 200) + hwscroll = 200; + } + else if (! strncmp(this_opt, "sw_",3)) { + if (! strcmp(this_opt+3, "acia")) + ovsc_switchmode = SWITCH_ACIA; + else if (! strcmp(this_opt+3, "snd6")) + ovsc_switchmode = SWITCH_SND6; + else if (! strcmp(this_opt+3, "snd7")) + ovsc_switchmode = SWITCH_SND7; + else ovsc_switchmode = SWITCH_NONE; + } +#ifdef ATAFB_EXT + else if (!strcmp(this_opt,"mv300")) { + external_bitspercol = 8; + external_card_type = IS_MV300; + } + else if (!strncmp(this_opt,"external:",9)) + strcpy(ext_str, this_opt+9); +#endif + else if (!strncmp(this_opt,"internal:",9)) + strcpy(int_str, this_opt+9); +#ifdef ATAFB_FALCON + else if (!strncmp(this_opt, "eclock:", 7)) { + fext.f = simple_strtoul(this_opt+7, NULL, 10); + /* external pixelclock in kHz --> ps */ + fext.t = 1000000000/fext.f; + fext.f *= 1000; + } + else if (!strncmp(this_opt, "monitorcap:", 11)) + strcpy(mcap_spec, this_opt+11); +#endif + else if (!strcmp(this_opt, "keep")) + DontCalcRes = 1; + else if (!strncmp(this_opt, "R", 1)) + strcpy(user_mode, this_opt+1); + } + + if (*int_str) { + /* Format to config extended internal video hardware like OverScan: + ",internal:;;;;" + Explanation: + type to switch on higher resolution + sw_acia : via keyboard ACIA + sw_snd6 : via bit 6 of the soundchip port + sw_snd7 : via bit 7 of the soundchip port + : x-resolution + : y-resolution + The following are only needed if you have an overscan which + needs a black border: + : max. length of a line in pixels your OverScan hardware would allow + : max. number of lines your OverScan hardware would allow + : Offset from physical beginning to visible beginning + of screen in bytes + */ + int xres; + char *p; + + if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid; + xres = simple_strtoul(p, NULL, 10); + if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid; + sttt_xres=xres; + tt_yres=st_yres=simple_strtoul(p, NULL, 10); + if ((p=strtoke(NULL, ";")) && *p) { + sttt_xres_virtual=simple_strtoul(p, NULL, 10); + } + if ((p=strtoke(NULL, ";")) && *p) { + sttt_yres_virtual=simple_strtoul(p, NULL, 0); + } + if ((p=strtoke(NULL, ";")) && *p) { + ovsc_offset=simple_strtoul(p, NULL, 0); + } + + if (ovsc_offset || (sttt_yres_virtual != st_yres)) + use_hwscroll=0; + } + else + int_invalid: ovsc_switchmode = SWITCH_NONE; + +#ifdef ATAFB_EXT + if (*ext_str) { + int xres, xres_virtual, yres, depth, planes; + unsigned long addr, len; + char *p; + + /* Format is: ;;;; + * + * [;[;[;[; + * [;]]]]] + * + * 09/23/97 Juergen + * : hardware's x-resolution (f.e. ProMST) + * + * Even xres_virtual is available, we neither support panning nor hw-scrolling! + */ + if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid; + xres_virtual = xres = simple_strtoul(p, NULL, 10); + if (xres <= 0) goto ext_invalid; + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + yres = simple_strtoul(p, NULL, 10); + if (yres <= 0) goto ext_invalid; + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + depth = simple_strtoul(p, NULL, 10); + if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && + depth != 16 && depth != 24) goto ext_invalid; + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + if (*p == 'i') + planes = FB_TYPE_INTERLEAVED_PLANES; + else if (*p == 'p') + planes = FB_TYPE_PACKED_PIXELS; + else if (*p == 'n') + planes = FB_TYPE_PLANES; + else if (*p == 't') + planes = -1; /* true color */ + else + goto ext_invalid; + + + if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + addr = simple_strtoul(p, NULL, 0); + + if (!(p = strtoke(NULL, ";")) ||!*p) + len = xres*yres*depth/8; + else + len = simple_strtoul(p, NULL, 0); + + if ((p = strtoke(NULL, ";")) && *p) { + external_vgaiobase=simple_strtoul(p, NULL, 0); + } + + if ((p = strtoke(NULL, ";")) && *p) { + external_bitspercol = simple_strtoul(p, NULL, 0); + if (external_bitspercol > 8) + external_bitspercol = 8; + else if (external_bitspercol < 1) + external_bitspercol = 1; + } + + if ((p = strtoke(NULL, ";")) && *p) { + if (!strcmp(p, "vga")) + external_card_type = IS_VGA; + if (!strcmp(p, "mv300")) + external_card_type = IS_MV300; + } + + if ((p = strtoke(NULL, ";")) && *p) { + xres_virtual = simple_strtoul(p, NULL, 10); + if (xres_virtual < xres) + xres_virtual = xres; + if (xres_virtual*yres*depth/8 > len) + len=xres_virtual*yres*depth/8; + } + + external_xres = xres; + external_xres_virtual = xres_virtual; + external_yres = yres; + external_depth = depth; + external_pmode = planes; + external_addr = addr; + external_len = len; + + if (external_card_type == IS_MV300) + switch (external_depth) { + case 1: + MV300_reg = MV300_reg_1bit; + break; + case 4: + MV300_reg = MV300_reg_4bit; + break; + case 8: + MV300_reg = MV300_reg_8bit; + break; + } + + ext_invalid: + ; + } +#endif /* ATAFB_EXT */ + +#ifdef ATAFB_FALCON + if (*mcap_spec) { + char *p; + int vmin, vmax, hmin, hmax; + + /* Format for monitor capabilities is: ;;; + * vertical freq. in Hz + * horizontal freq. in kHz + */ + if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid; + vmin = simple_strtoul(p, NULL, 10); + if (vmin <= 0) goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid; + vmax = simple_strtoul(p, NULL, 10); + if (vmax <= 0 || vmax <= vmin) goto cap_invalid; + if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid; + hmin = 1000 * simple_strtoul(p, NULL, 10); + if (hmin <= 0) goto cap_invalid; + if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid; + hmax = 1000 * simple_strtoul(p, NULL, 10); + if (hmax <= 0 || hmax <= hmin) goto cap_invalid; + + vfmin = vmin; + vfmax = vmax; + hfmin = hmin; + hfmax = hmax; + cap_invalid: + ; + } +#endif + + if (*user_mode) { + /* Format of user defined video mode is: ;; + */ + char *p; + int xres, yres, depth, temp; + + if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid; + xres = simple_strtoul(p, NULL, 10); + if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid; + yres = simple_strtoul(p, NULL, 10); + if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid; + depth = simple_strtoul(p, NULL, 10); + if ((temp=get_video_mode("user0"))) { + default_par=temp; + atari_fb_predefined[default_par-1].xres = xres; + atari_fb_predefined[default_par-1].yres = yres; + atari_fb_predefined[default_par-1].bits_per_pixel = depth; + } + + user_invalid: + ; + } +} + +#ifdef MODULE +int init_module(void) +{ + return(atari_fb_init(NULL)); +} + +void cleanup_module(void) +{ + /* Not reached because the usecount will never + be decremented to zero */ + unregister_framebuffer(&fb_info); + /* TODO: clean up ... */ +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c --- v2.1.66/linux/drivers/video/cyberfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/cyberfb.c Fri Oct 31 07:59:40 1997 @@ -0,0 +1,1129 @@ +/* + * linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device + * + * Copyright (C) 1996 Martin Apel + * Geert Uytterhoeven + * + * + * This file is based on the Amiga frame buffer device (amifb.c): + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * History: + * - 22 Dec 95: Original version by Martin Apel + * - 05 Jan 96: Geert: integration into the current source tree + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "s3blit.h" + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +struct Cyber_fb_par { + int xres; + int yres; + int bpp; +}; + +static struct Cyber_fb_par current_par; + +static int current_par_valid = 0; +static int currcon = 0; + +static struct display disp; +static struct fb_info fb_info; + + +/* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialisation */ + + int (*init)(void); + + /* Display Control */ + + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct Cyber_fb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct Cyber_fb_par *par); + int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); + int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); + void (*blank)(int blank); +} *fbhw; + + +/* + * Frame Buffer Name + */ + +static char Cyber_fb_name[16] = "Cybervision"; + + +/* + * Cybervision Graphics Board + */ + +#define CYBER8_WIDTH 1152 +#define CYBER8_HEIGHT 886 +#define CYBER8_PIXCLOCK 12500 /* ++Geert: Just a guess */ + +#if 0 +#define CYBER16_WIDTH 800 +#define CYBER16_HEIGHT 600 +#endif +#define CYBER16_PIXCLOCK 25000 /* ++Geert: Just a guess */ + + +static unsigned int CyberKey = 0; +static unsigned char Cyber_colour_table [256][4]; +static unsigned long CyberMem; +static unsigned long CyberSize; +static volatile char *CyberRegs; + + +/* + * Predefined Video Mode Names + */ + +static char *Cyber_fb_modenames[] = { + + /* + * Autodetect (Default) Video Mode + */ + + "default", + + /* + * Predefined Video Modes + */ + + "cyber8", /* Cybervision 8 bpp */ + "cyber16", /* Cybervision 16 bpp */ + "800x600x8", + "640x480x8", + + /* + * Dummy Video Modes + */ + + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", + + /* + * User Defined Video Modes + * + * This doesn't work yet!! + */ + + "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7" +}; + + +/* + * Predefined Video Mode Definitions + */ + +static struct fb_var_screeninfo cyber_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { 0, }, + + /* + * Predefined Video Modes + */ + + { + /* Cybervision 8 bpp */ + CYBER8_WIDTH, CYBER8_HEIGHT, CYBER8_WIDTH, CYBER8_HEIGHT, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* Cybervision 16 bpp */ + 800, 600, 800, 600, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, CYBER16_PIXCLOCK, 64, 96, 35, 12, 112, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* Cybervision 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, { + /* Cybervision 8 bpp */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, CYBER8_PIXCLOCK, 64, 96, 35, 12, 112, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + * Dummy Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + + /* + * User Defined Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + + +#define NUM_TOTAL_MODES arraysize(cyber_fb_predefined) +#define NUM_PREDEF_MODES (5) + + +static int Cyberfb_inverse = 0; +#if 0 +static int Cyberfb_Cyber8 = 0; /* Use Cybervision board */ +static int Cyberfb_Cyber16 = 0; /* Use Cybervision board */ +#endif +static int Cyberfb_mode = 0; + + +/* + * Some default modes + */ + +#define CYBER8_DEFMODE (1) +#define CYBER16_DEFMODE (2) + + +/* + * Interface used by the world + */ + +void Cyber_video_setup(char *options, int *ints); + +static int Cyber_fb_open(int fbidx); +static int Cyber_fb_release(int fbidx); +static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con); +static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con); +static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int Cyber_fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con); + + +/* + * Interface to the low level console driver + */ + +unsigned long Cyber_fb_init(unsigned long mem_start); +static int Cyberfb_switch(int con); +static int Cyberfb_updatevar(int con); +static void Cyberfb_blank(int blank); +static int Cyberfb_setcmap(struct fb_cmap *cmap, int con); + + +/* + * Accelerated Functions used by the low level console driver + */ + +void Cyber_WaitQueue(u_short fifo); +void Cyber_WaitBlit(void); +void Cyber_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short mode); +void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short mode, u_short color); +void Cyber_MoveCursor(u_short x, u_short y); + + +/* + * Hardware Specific Routines + */ + +static int Cyber_init(void); +static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, + struct Cyber_fb_par *par); +static int Cyber_decode_var(struct fb_var_screeninfo *var, + struct Cyber_fb_par *par); +static int Cyber_encode_var(struct fb_var_screeninfo *var, + struct Cyber_fb_par *par); +static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); +static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); +static void Cyber_blank(int blank); + + +/* + * Internal routines + */ + +static void Cyber_fb_get_par(struct Cyber_fb_par *par); +static void Cyber_fb_set_par(struct Cyber_fb_par *par); +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static void do_install_cmap(int con); +static void Cyber_fb_set_disp(int con); +static int get_video_mode(const char *name); + + +/* -------------------- Hardware specific routines ------------------------- */ + + +/* + * Initialization + * + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int Cyber_init(void) +{ + int i; + char size; + volatile u_long *CursorBase; + +#if 0 + if (Cyberfb_mode == -1) + { + if (Cyberfb_Cyber8) + Cyberfb_mode = CYBER8_DEFMODE; + else + Cyberfb_mode = CYBER16_DEFMODE; + } +#endif + + for (i = 0; i < 256; i++) + + for (i = 0; i < 256; i++) + { + Cyber_colour_table [i][0] = i; + Cyber_colour_table [i][1] = i; + Cyber_colour_table [i][2] = i; + Cyber_colour_table [i][3] = 0; + } + + /* + * Just clear the thing for the biggest mode. + */ + + memset ((char*)CyberMem, 0, CYBER8_WIDTH * CYBER8_HEIGHT); + + /* Disable hardware cursor */ + *(CyberRegs + S3_CRTC_ADR) = S3_REG_LOCK2; + *(CyberRegs + S3_CRTC_DATA) = 0xa0; + *(CyberRegs + S3_CRTC_ADR) = S3_HGC_MODE; + *(CyberRegs + S3_CRTC_DATA) = 0x00; + *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_DX; + *(CyberRegs + S3_CRTC_DATA) = 0x00; + *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_DY; + *(CyberRegs + S3_CRTC_DATA) = 0x00; + + /* Get memory size (if not 2MB it is 4MB) */ + *(CyberRegs + S3_CRTC_ADR) = S3_LAW_CTL; + size = *(CyberRegs + S3_CRTC_DATA); + if ((size & 0x03) == 0x02) + CyberSize = 0x00200000; /* 2 MB */ + else + CyberSize = 0x00400000; /* 4 MB */ + + /* Initialize hardware cursor */ + CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400); + for (i=0; i < 8; i++) + { + *(CursorBase +(i*4)) = 0xffffff00; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + for (i=8; i < 64; i++) + { + *(CursorBase +(i*4)) = 0xffff0000; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + + Cyber_setcolreg (255, 56, 100, 160, 0); + Cyber_setcolreg (254, 0, 0, 0, 0); + + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int Cyber_encode_fix(struct fb_fix_screeninfo *fix, + struct Cyber_fb_par *par) +{ + int i; + + strcpy(fix->id, Cyber_fb_name); + fix->smem_start = (caddr_t)CyberMem; + fix->smem_len = CyberSize; + fix->mmio_start = (unsigned char *)CyberRegs; + fix->mmio_len = 0x10000; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->bpp == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_DIRECTCOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + + for (i = 0; i < arraysize(fix->reserved); i++) + fix->reserved[i] = 0; + + return(0); +} + + +/* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int Cyber_decode_var(struct fb_var_screeninfo *var, + struct Cyber_fb_par *par) +{ +#if 1 + par->xres = var->xres; + par->yres = var->yres; + par->bpp = var->bits_per_pixel; +#else + if (Cyberfb_Cyber8) { + par->xres = CYBER8_WIDTH; + par->yres = CYBER8_HEIGHT; + par->bpp = 8; + } else { + par->xres = CYBER16_WIDTH; + par->yres = CYBER16_HEIGHT; + par->bpp = 16; + } +#endif + return(0); +} + + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int Cyber_encode_var(struct fb_var_screeninfo *var, + struct Cyber_fb_par *par) +{ + int i; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->xres; + var->yres_virtual = par->yres; + var->xoffset = 0; + var->yoffset = 0; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + if (par->bpp == 8) { + var->red.offset = 0; + var->red.length = 8; + var->red.msb_right = 0; + var->blue = var->green = var->red; + } else { + var->red.offset = 11; + var->red.length = 5; + var->red.msb_right = 0; + var->green.offset = 5; + var->green.length = 6; + var->green.msb_right = 0; + var->blue.offset = 0; + var->blue.length = 5; + var->blue.msb_right = 0; + } + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + var->accel = FB_ACCEL_CYBERVISION; + var->vmode = FB_VMODE_NONINTERLACED; + + /* Dummy values */ + + if (par->bpp == 8) + var->pixclock = CYBER8_PIXCLOCK; + else + var->pixclock = CYBER16_PIXCLOCK; + var->sync = 0; + var->left_margin = 64; + var->right_margin = 96; + var->upper_margin = 35; + var->lower_margin = 12; + var->hsync_len = 112; + var->vsync_len = 2; + + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + return(0); +} + + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp) +{ + if (regno > 255) + return (1); + + *(CyberRegs + 0x3c8) = (char)regno; + Cyber_colour_table [regno][0] = red & 0xff; + Cyber_colour_table [regno][1] = green & 0xff; + Cyber_colour_table [regno][2] = blue & 0xff; + Cyber_colour_table [regno][3] = transp; + + *(CyberRegs + 0x3c9) = (red & 0xff) >> 2; + *(CyberRegs + 0x3c9) = (green & 0xff) >> 2; + *(CyberRegs + 0x3c9) = (blue & 0xff) >> 2; + + return (0); +} + + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp) +{ + if (regno >= 256) + return (1); + *red = Cyber_colour_table [regno][0]; + *green = Cyber_colour_table [regno][1]; + *blue = Cyber_colour_table [regno][2]; + *transp = Cyber_colour_table [regno][3]; + return (0); +} + + +/* + * (Un)Blank the screen + */ + +void Cyber_blank(int blank) +{ + int i; + + if (blank) + for (i = 0; i < 256; i++) + { + *(CyberRegs + 0x3c8) = i; + *(CyberRegs + 0x3c9) = 0; + *(CyberRegs + 0x3c9) = 0; + *(CyberRegs + 0x3c9) = 0; + } + else + for (i = 0; i < 256; i++) + { + *(CyberRegs + 0x3c8) = i; + *(CyberRegs + 0x3c9) = Cyber_colour_table [i][0] >> 2; + *(CyberRegs + 0x3c9) = Cyber_colour_table [i][1] >> 2; + *(CyberRegs + 0x3c9) = Cyber_colour_table [i][2] >> 2; + } +} + + +/************************************************************** + * We are waiting for "fifo" FIFO-slots empty + */ +void Cyber_WaitQueue (u_short fifo) +{ + u_short status; + + do + { + status = *((u_short volatile *)(CyberRegs + S3_GP_STAT)); + } + while (status & fifo); +} + +/************************************************************** + * We are waiting for Hardware (Graphics Engine) not busy + */ +void Cyber_WaitBlit (void) +{ + u_short status; + + do + { + status = *((u_short volatile *)(CyberRegs + S3_GP_STAT)); + } + while (status & S3_HDW_BUSY); +} + +/************************************************************** + * BitBLT - Through the Plane + */ +void Cyber_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short mode) +{ + u_short blitcmd = S3_BITBLT; + + /* Set drawing direction */ + /* -Y, X maj, -X (default) */ + if (curx > destx) + blitcmd |= 0x0020; /* Drawing direction +X */ + else + { + curx += (width - 1); + destx += (width - 1); + } + + if (cury > desty) + blitcmd |= 0x0080; /* Drawing direction +Y */ + else + { + cury += (height - 1); + desty += (height - 1); + } + + Cyber_WaitQueue (0x8000); + + *((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000; + *((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0060 | mode); + + *((u_short volatile *)(CyberRegs + S3_CUR_X)) = curx; + *((u_short volatile *)(CyberRegs + S3_CUR_Y)) = cury; + + *((u_short volatile *)(CyberRegs + S3_DESTX_DIASTP)) = destx; + *((u_short volatile *)(CyberRegs + S3_DESTY_AXSTP)) = desty; + + *((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1; + *((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1; + + *((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd; +} + +/************************************************************** + * Rectangle Fill Solid + */ +void Cyber_RectFill (u_short x, u_short y, u_short width, u_short height, + u_short mode, u_short color) +{ + u_short blitcmd = S3_FILLEDRECT; + + Cyber_WaitQueue (0x8000); + + *((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000; + *((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0020 | mode); + + *((u_short volatile *)(CyberRegs + S3_MULT_MISC)) = 0xe000; + *((u_short volatile *)(CyberRegs + S3_FRGD_COLOR)) = color; + + *((u_short volatile *)(CyberRegs + S3_CUR_X)) = x; + *((u_short volatile *)(CyberRegs + S3_CUR_Y)) = y; + + *((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1; + *((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width - 1; + + *((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd; +} + + +/************************************************************** + * Move cursor to x, y + */ +void Cyber_MoveCursor (u_short x, u_short y) +{ + *(CyberRegs + S3_CRTC_ADR) = 0x39; + *(CyberRegs + S3_CRTC_DATA) = 0xa0; + + *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGX_H; + *(CyberRegs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8); + *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGX_L; + *(CyberRegs + S3_CRTC_DATA) = (char)(x & 0x00ff); + + *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_H; + *(CyberRegs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8); + *(CyberRegs + S3_CRTC_ADR) = S3_HWGC_ORGY_L; + *(CyberRegs + S3_CRTC_DATA) = (char)(y & 0x00ff); +} + + +/* -------------------- Interfaces to hardware functions -------------------- */ + + +static struct fb_hwswitch Cyber_switch = { + Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var, + Cyber_getcolreg, Cyber_setcolreg, Cyber_blank +}; + + +/* -------------------- Generic routines ------------------------------------ */ + + +/* + * Fill the hardware's `par' structure. + */ + +static void Cyber_fb_get_par(struct Cyber_fb_par *par) +{ + if (current_par_valid) + *par = current_par; + else + fbhw->decode_var(&cyber_fb_predefined[Cyberfb_mode], par); +} + + +static void Cyber_fb_set_par(struct Cyber_fb_par *par) +{ + current_par = *par; + current_par_valid = 1; +} + + +static void cyber_set_video(struct fb_var_screeninfo *var) +{ + /* Set clipping rectangle to current screen size */ + *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x1000; + *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x2000; + + *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x3000 | (var->yres - 1); + *((u_short volatile *)(CyberRegs + 0xbee8)) = 0x4000 | (var->xres - 1); +} + + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct Cyber_fb_par par; + + if ((err = fbhw->decode_var(var, &par))) + return(err); + activate = var->activate; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + Cyber_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate = activate; + + cyber_set_video(var); + return 0; +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + fbhw->setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &fb_display[con].var, 1, fbhw->setcolreg); +} + + +/* + * Open/Release the frame buffer device + */ + +static int Cyber_fb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int Cyber_fb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + + +/* + * Get the Fixed Part of the Display + */ + +static int Cyber_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct Cyber_fb_par par; + int error = 0; + + if (con == -1) + Cyber_fb_get_par(&par); + else + error = fbhw->decode_var(&fb_display[con].var, &par); + return(error ? error : fbhw->encode_fix(fix, &par)); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int Cyber_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct Cyber_fb_par par; + int error = 0; + + if (con == -1) { + Cyber_fb_get_par(&par); + error = fbhw->encode_var(var, &par); + } else + *var = fb_display[con].var; + return(error); +} + + +static void Cyber_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + Cyber_fb_get_fix(&fix, con); + if (con == -1) + con = 0; + display->screen_base = (u_char *)fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->can_soft_blank = 1; + display->inverse = Cyberfb_inverse; +} + + +/* + * Set the User Defined Part of the Display + */ + +static int Cyber_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; + + if ((err = do_fb_set_var(var, con == currcon))) + return(err); + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = fb_display[con].var.xres; + oldyres = fb_display[con].var.yres; + oldvxres = fb_display[con].var.xres_virtual; + oldvyres = fb_display[con].var.yres_virtual; + oldbpp = fb_display[con].var.bits_per_pixel; + fb_display[con].var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + Cyber_fb_set_disp(con); + (*fb_info.changevar)(con); + fb_alloc_cmap(&fb_display[con].cmap, 0, 0); + do_install_cmap(con); + } + } + var->activate = 0; + return(0); +} + + +/* + * Get the Colormap + */ + +static int Cyber_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return(fb_get_cmap(cmap, &fb_display[con].var, + kspc, fbhw->getcolreg)); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return(0); +} + + +/* + * Set the Colormap + */ + +static int Cyber_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<setcolreg)); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + return(0); +} + + +/* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int Cyber_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + return(-EINVAL); +} + + +/* + * Cybervision Frame Buffer Specific ioctls + */ + +static int Cyber_fb_ioctl(struct inode *inode, struct file *file, + u_int cmd, u_long arg, int con) +{ + return(-EINVAL); +} + + +static struct fb_ops Cyber_fb_ops = { + Cyber_fb_open, Cyber_fb_release, Cyber_fb_get_fix, Cyber_fb_get_var, + Cyber_fb_set_var, Cyber_fb_get_cmap, Cyber_fb_set_cmap, + Cyber_fb_pan_display, Cyber_fb_ioctl +}; + + +__initfunc(void Cyber_video_setup(char *options, int *ints)) +{ + char *this_opt; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) + if (!strcmp(this_opt, "inverse")) { + Cyberfb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); +#if 0 + else if (!strcmp (this_opt, "cyber8")) + Cyberfb_Cyber8 = 1; + else if (!strcmp (this_opt, "cyber16")) + Cyberfb_Cyber16 = 1; +#endif + else + Cyberfb_mode = get_video_mode(this_opt); +} + + +/* + * Initialization + */ + +__initfunc(unsigned long Cyber_fb_init(unsigned long mem_start)) +{ + int err; + struct Cyber_fb_par par; + unsigned long board_addr; + const struct ConfigDev *cd; + + if (!(CyberKey = zorro_find(ZORRO_PROD_PHASE5_CYBERVISION64, 0, 0))) + return mem_start; + + cd = zorro_get_board (CyberKey); + zorro_config_board (CyberKey, 0); + board_addr = (unsigned long)cd->cd_BoardAddr; + + /* This includes the video memory as well as the S3 register set */ + CyberMem = kernel_map (board_addr + 0x01400000, 0x01000000, + KERNELMAP_NOCACHE_SER, &mem_start); + CyberRegs = (char*) (CyberMem + 0x00c00000); + + fbhw = &Cyber_switch; + + strcpy(fb_info.modename, Cyber_fb_name); + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &Cyber_fb_ops; + fb_info.fbvar_num = NUM_TOTAL_MODES; + fb_info.fbvar = cyber_fb_predefined; + fb_info.disp = &disp; + fb_info.switch_con = &Cyberfb_switch; + fb_info.updatevar = &Cyberfb_updatevar; + fb_info.blank = &Cyberfb_blank; + fb_info.setcmap = &Cyberfb_setcmap; + + err = register_framebuffer(&fb_info); + if (err < 0) + return mem_start; + + fbhw->init(); + fbhw->decode_var(&cyber_fb_predefined[Cyberfb_mode], &par); + fbhw->encode_var(&cyber_fb_predefined[0], &par); + + do_fb_set_var(&cyber_fb_predefined[0], 1); + Cyber_fb_get_var(&fb_display[0].var, -1); + Cyber_fb_set_disp(-1); + do_install_cmap(0); + + printk("%s frame buffer device, using %ldK of video memory\n", + fb_info.modename, CyberSize>>10); + + /* TODO: This driver cannot be unloaded yet */ + MOD_INC_USE_COUNT; + + return mem_start; +} + + +static int Cyberfb_switch(int con) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, + fbhw->getcolreg); + + do_fb_set_var(&fb_display[con].var, 1); + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return(0); +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int Cyberfb_updatevar(int con) +{ + return(0); +} + + +/* + * Blank the display. + */ + +static void Cyberfb_blank(int blank) +{ + fbhw->blank(blank); +} + + +/* + * Set the colormap + */ + +static int Cyberfb_setcmap(struct fb_cmap *cmap, int con) +{ + return(Cyber_fb_set_cmap(cmap, 1, con)); +} + + +/* + * Get a Video Mode + */ + +static int get_video_mode(const char *name) +{ + int i; + + for (i = 1; i < NUM_PREDEF_MODES; i++) + if (!strcmp(name, Cyber_fb_modenames[i])) + cyber_fb_predefined[0] = cyber_fb_predefined[i]; + return(i); + return(0); +} + + +#ifdef MODULE +int init_module(void) +{ + return(Cyber_fb_init(NULL)); +} + +void cleanup_module(void) +{ + /* Not reached because the usecount will never be + decremented to zero */ + unregister_framebuffer(&fb_info); + /* TODO: clean up ... */ +} +#endif /* MODULE */ + + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(Cyber_BitBLT); +EXPORT_SYMBOL(Cyber_RectFill); +EXPORT_SYMBOL(Cyber_WaitBlit); diff -u --recursive --new-file v2.1.66/linux/drivers/video/dn_fb.c linux/drivers/video/dn_fb.c --- v2.1.66/linux/drivers/video/dn_fb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/dn_fb.c Mon Nov 24 01:18:53 1997 @@ -0,0 +1,389 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* apollo video HW definitions */ + +/* + * Control Registers. IOBASE + $x + * + * Note: these are the Memory/IO BASE definitions for a mono card set to the + * alternate address + * + * Control 3A and 3B serve identical functions except that 3A + * deals with control 1 and 3b deals with Color LUT reg. + */ + +#define AP_IOBASE 0x5d80 /* Base address of 1 plane board. */ +#define AP_STATUS 0x5d80 /* Status register. Read */ +#define AP_WRITE_ENABLE 0x5d80 /* Write Enable Register Write */ +#define AP_DEVICE_ID 0x5d81 /* Device ID Register. Read */ +#define AP_ROP_1 0x5d82 /* Raster Operation reg. Write Word */ +#define AP_DIAG_MEM_REQ 0x5d84 /* Diagnostic Memory Request. Write Word */ +#define AP_CONTROL_0 0x5d88 /* Control Register 0. Read/Write */ +#define AP_CONTROL_1 0x5d8a /* Control Register 1. Read/Write */ +#define AP_CONTROL_3A 0x5d8e /* Control Register 3a. Read/Write */ +#define AP_CONTROL_2 0x5d8c /* Control Register 2. Read/Write */ + + +#define FRAME_BUFFER_START 0x0FA0000 +#define FRAME_BUFFER_LEN 0x40000 + +/* CREG 0 */ +#define VECTOR_MODE 0x40 /* 010x.xxxx */ +#define DBLT_MODE 0x80 /* 100x.xxxx */ +#define NORMAL_MODE 0xE0 /* 111x.xxxx */ +#define SHIFT_BITS 0x1F /* xxx1.1111 */ + /* other bits are Shift value */ + +/* CREG 1 */ +#define AD_BLT 0x80 /* 1xxx.xxxx */ +#define NORMAL 0x80 /* 1xxx.xxxx */ /* What is happening here ?? */ +#define INVERSE 0x00 /* 0xxx.xxxx */ /* Clearing this reverses the screen */ +#define PIX_BLT 0x00 /* 0xxx.xxxx */ + +#define AD_HIBIT 0x40 /* xIxx.xxxx */ + +#define ROP_EN 0x10 /* xxx1.xxxx */ +#define DST_EQ_SRC 0x00 /* xxx0.xxxx */ +#define nRESET_SYNC 0x08 /* xxxx.1xxx */ +#define SYNC_ENAB 0x02 /* xxxx.xx1x */ + +#define BLANK_DISP 0x00 /* xxxx.xxx0 */ +#define ENAB_DISP 0x01 /* xxxx.xxx1 */ + +#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */ + +/* CREG 2 */ + +/* + * Following 3 defines are common to 1, 4 and 8 plane. + */ + +#define S_DATA_1s 0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */ +#define S_DATA_PIX 0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */ +#define S_DATA_PLN 0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in + one plane of image mem */ + +/* CREG 3A/CREG 3B */ +# define RESET_CREG 0x80 /* 1000.0000 */ + +/* ROP REG - all one nibble */ +/* ********* NOTE : this is used r0,r1,r2,r3 *********** */ +#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) ) +#define DEST_ZERO 0x0 +#define SRC_AND_DEST 0x1 +#define SRC_AND_nDEST 0x2 +#define SRC 0x3 +#define nSRC_AND_DEST 0x4 +#define DEST 0x5 +#define SRC_XOR_DEST 0x6 +#define SRC_OR_DEST 0x7 +#define SRC_NOR_DEST 0x8 +#define SRC_XNOR_DEST 0x9 +#define nDEST 0xA +#define SRC_OR_nDEST 0xB +#define nSRC 0xC +#define nSRC_OR_DEST 0xD +#define SRC_NAND_DEST 0xE +#define DEST_ONE 0xF + +#define SWAP(A) ((A>>8) | ((A&0xff) <<8)) + +#if 0 +#define outb(a,d) *(char *)(a)=(d) +#define outw(a,d) *(unsigned short *)a=d +#endif + + +void dn_video_setup(char *options, int *ints); + +/* frame buffer operations */ + +static int dn_fb_open(int fbidx); +static int dn_fb_release(int fbidx); +static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int dn_fb_get_var(struct fb_var_screeninfo *var, int con); +static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con); +static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con); +static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con); + +static int dnfbcon_switch(int con); +static int dnfbcon_updatevar(int con); +static void dnfbcon_blank(int blank); + +static void dn_fb_set_disp(int con); + +static struct display disp[MAX_NR_CONSOLES]; +static struct fb_info fb_info; +static struct fb_ops dn_fb_ops = { + dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var, + dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl +}; + +static int currcon=0; + +#define NUM_TOTAL_MODES 1 +struct fb_var_screeninfo dn_fb_predefined[] = { + + { 0, }, + +}; + +static char dn_fb_name[]="Apollo "; + +static int dn_fb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int dn_fb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + +static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con) { + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id,"Apollo Mono"); + fix->smem_start=(char*)(FRAME_BUFFER_START+IO_BASE); + fix->smem_len=FRAME_BUFFER_LEN; + fix->type=FB_TYPE_PACKED_PIXELS; + fix->type_aux=0; + fix->visual=FB_VISUAL_MONO10; + fix->xpanstep=0; + fix->ypanstep=0; + fix->ywrapstep=0; + fix->line_length=256; + + return 0; + +} + +static int dn_fb_get_var(struct fb_var_screeninfo *var, int con) { + + var->xres=1280; + var->yres=1024; + var->xres_virtual=2048; + var->yres_virtual=1024; + var->xoffset=0; + var->yoffset=0; + var->bits_per_pixel=1; + var->grayscale=0; + var->nonstd=0; + var->activate=0; + var->height=-1; + var->width=-1; + var->pixclock=0; + var->left_margin=0; + var->right_margin=0; + var->hsync_len=0; + var->vsync_len=0; + var->sync=0; + var->vmode=FB_VMODE_NONINTERLACED; + var->accel=FB_ACCEL_NONE; + + return 0; + +} + +static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive) { + + printk("fb_set_var\n"); + if(var->xres!=1280) + return -EINVAL; + if(var->yres!=1024) + return -EINVAL; + if(var->xres_virtual!=2048) + return -EINVAL; + if(var->yres_virtual!=1024) + return -EINVAL; + if(var->xoffset!=0) + return -EINVAL; + if(var->yoffset!=0) + return -EINVAL; + if(var->bits_per_pixel!=1) + return -EINVAL; + if(var->grayscale!=0) + return -EINVAL; + if(var->nonstd!=0) + return -EINVAL; + if(var->activate!=0) + return -EINVAL; + if(var->pixclock!=0) + return -EINVAL; + if(var->left_margin!=0) + return -EINVAL; + if(var->right_margin!=0) + return -EINVAL; + if(var->hsync_len!=0) + return -EINVAL; + if(var->vsync_len!=0) + return -EINVAL; + if(var->sync!=0) + return -EINVAL; + if(var->vmode!=FB_VMODE_NONINTERLACED) + return -EINVAL; + if(var->accel!=FB_ACCEL_NONE) + return -EINVAL; + + return 0; + +} + +static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con) { + + printk("get cmap not supported\n"); + + return -EINVAL; +} + +static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con) { + + printk("set cmap not supported\n"); + + return -EINVAL; + +} + +static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con) { + + printk("panning not supported\n"); + + return -EINVAL; + +} + +static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, int con) { + + printk("no IOCTLs as of yet.\n"); + + return -EINVAL; + +} + +static void dn_fb_set_disp(int con) { + + struct fb_fix_screeninfo fix; + + dn_fb_get_fix(&fix,con); + if(con==-1) + con=0; + + disp[con].screen_base = (u_char *)fix.smem_start; +printk("screenbase: %p\n",fix.smem_start); + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].can_soft_blank = 1; + disp[con].inverse = 0; + disp[con].line_length = fix.line_length; +} + +unsigned long dn_fb_init(unsigned long mem_start) { + + int err; + +printk("dn_fb_init\n"); + + fb_info.changevar=NULL; + strcpy(&fb_info.modename[0],dn_fb_name); + fb_info.fontname[0]=0; + fb_info.disp=disp; + fb_info.switch_con=&dnfbcon_switch; + fb_info.updatevar=&dnfbcon_updatevar; + fb_info.blank=&dnfbcon_blank; + fb_info.node = -1; + fb_info.fbops = &dn_fb_ops; + fb_info.fbvar = dn_fb_predefined; + fb_info.fbvar_num = NUM_TOTAL_MODES; + +printk("dn_fb_init: register\n"); + err=register_framebuffer(&fb_info); + if(err < 0) { + panic("unable to register apollo frame buffer\n"); + } + + /* now we have registered we can safely setup the hardware */ + + outb(RESET_CREG, AP_CONTROL_3A); + outw(0x0, AP_WRITE_ENABLE); + outb(NORMAL_MODE,AP_CONTROL_0); + outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1); + outb(S_DATA_PLN, AP_CONTROL_2); + outw(SWAP(0x3),AP_ROP_1); + + printk("apollo frame buffer alive and kicking !\n"); + + + dn_fb_get_var(&disp[0].var,0); + + dn_fb_set_disp(-1); + + return mem_start; + +} + + +static int dnfbcon_switch(int con) { + + currcon=con; + + return 0; + +} + +static int dnfbcon_updatevar(int con) { + + return 0; + +} + +static void dnfbcon_blank(int blank) { + + printk("dnfbcon_blank: %d\n",blank); + if(blank) { + outb(0, AP_CONTROL_3A); + outb((AD_BLT | DST_EQ_SRC | NORM_CREG1) & ~ENAB_DISP, + AP_CONTROL_1); + } + else { + outb(1, AP_CONTROL_3A); + outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1); + } + + return ; + +} + +void dn_video_setup(char *options, int *ints) { + + return; + +} + diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcmap.c linux/drivers/video/fbcmap.c --- v2.1.66/linux/drivers/video/fbcmap.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcmap.c Tue Sep 16 02:29:26 1997 @@ -0,0 +1,323 @@ +/* + * linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices + * + * Created 15 Jun 1997 by Geert Uytterhoeven + * + * 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 + + +static void memcpy_fs(int fsfromto, void *to, void *from, int len) +{ + switch (fsfromto) { + case 0: + memcpy(to, from, len); + return; + case 1: + copy_from_user(to, from, len); + return; + case 2: + copy_to_user(to, from, len); + return; + } +} + +#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) +#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ + ((1<<(width))-1)) : 0)) + +static u_short red2[] = { + 0x0000, 0xaaaa +}; +static u_short green2[] = { + 0x0000, 0xaaaa +}; +static u_short blue2[] = { + 0x0000, 0xaaaa +}; + +static u_short red4[] = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; +static u_short green4[] = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; +static u_short blue4[] = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; + +static u_short red8[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa +}; +static u_short green8[] = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa +}; +static u_short blue8[] = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa +}; + +static u_short red16[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, + 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff +}; +static u_short green16[] = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa, + 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff +}; +static u_short blue16[] = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, + 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff +}; + +static struct fb_cmap default_2_colors = { + 0, 2, red2, green2, blue2, NULL +}; +static struct fb_cmap default_8_colors = { + 0, 8, red8, green8, blue8, NULL +}; +static struct fb_cmap default_4_colors = { + 0, 4, red4, green4, blue4, NULL +}; +static struct fb_cmap default_16_colors = { + 0, 16, red16, green16, blue16, NULL +}; + + + /* + * Allocate a colormap + */ + +int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + int size = len*sizeof(u_short); + + if (cmap->len != len) { + if (cmap->red) + kfree(cmap->red); + if (cmap->green) + kfree(cmap->green); + if (cmap->blue) + kfree(cmap->blue); + if (cmap->transp) + kfree(cmap->transp); + cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; + cmap->len = 0; + if (!len) + return 0; + if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) + return -1; + if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) + return -1; + if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) + return -1; + if (transp) { + if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) + return -1; + } else + cmap->transp = NULL; + } + cmap->start = 0; + cmap->len = len; + fb_copy_cmap(fb_default_cmap(len), cmap, 0); + return 0; +} + + + /* + * Copy a colormap + */ + +void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) +{ + int size; + int tooff = 0, fromoff = 0; + + if (to->start > from->start) + fromoff = to->start-from->start; + else + tooff = from->start-to->start; + size = to->len-tooff; + if (size > from->len-fromoff) + size = from->len-fromoff; + if (size < 0) + return; + size *= sizeof(u_short); + memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); + memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); + memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size); +} + + + /* + * Get the colormap for a screen + */ + +int fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, + int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *)) +{ + int i, start; + u_short *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + if (start < 0) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + if (getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) + return 0; + hred = CNVT_FROMHW(hred, var->red.length); + hgreen = CNVT_FROMHW(hgreen, var->green.length); + hblue = CNVT_FROMHW(hblue, var->blue.length); + htransp = CNVT_FROMHW(htransp, var->transp.length); + if (kspc) { + *red = hred; + *green = hgreen; + *blue = hblue; + if (transp) + *transp = htransp; + } else { + put_user(hred, red); + put_user(hgreen, green); + put_user(hblue, blue); + if (transp) + put_user(htransp, transp); + } + red++; + green++; + blue++; + if (transp) + transp++; + } + return 0; +} + + + /* + * Set the colormap for a screen + */ + +int fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, int kspc, + int (*setcolreg)(u_int, u_int, u_int, u_int, u_int)) +{ + int i, start; + u_short *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0) + return -EINVAL; + for (i = 0; i < cmap->len; i++) { + if (kspc) { + hred = *red; + hgreen = *green; + hblue = *blue; + htransp = transp ? *transp : 0; + } else { + get_user(hred, red); + get_user(hgreen, green); + get_user(hblue, blue); + if (transp) + get_user(htransp, transp); + else + htransp = 0; + } + hred = CNVT_TOHW(hred, var->red.length); + hgreen = CNVT_TOHW(hgreen, var->green.length); + hblue = CNVT_TOHW(hblue, var->blue.length); + htransp = CNVT_TOHW(htransp, var->transp.length); + red++; + green++; + blue++; + if (transp) + transp++; + if (setcolreg(start++, hred, hgreen, hblue, htransp)) + return 0; + } + return 0; +} + + + /* + * Get the default colormap for a specific screen depth + */ + +struct fb_cmap *fb_default_cmap(int bpp) +{ + switch (bpp) { + case 1: + return &default_2_colors; + break; + case 2: + return &default_4_colors; + break; + case 3: + return &default_8_colors; + break; + default: + return &default_16_colors; + break; + } +} + + + /* + * Invert all default colormaps + */ + +void fb_invert_cmaps(void) +{ + u_int i; + + for (i = 0; i < 2; i++) { + red2[i] = ~red2[i]; + green2[i] = ~green2[i]; + blue2[i] = ~blue2[i]; + } + for (i = 0; i < 4; i++) { + red4[i] = ~red4[i]; + green4[i] = ~green4[i]; + blue4[i] = ~blue4[i]; + } + for (i = 0; i < 8; i++) { + red8[i] = ~red8[i]; + green8[i] = ~green8[i]; + blue8[i] = ~blue8[i]; + } + for (i = 0; i < 16; i++) { + red16[i] = ~red16[i]; + green16[i] = ~green16[i]; + blue16[i] = ~blue16[i]; + } +} + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(fb_alloc_cmap); +EXPORT_SYMBOL(fb_copy_cmap); +EXPORT_SYMBOL(fb_get_cmap); +EXPORT_SYMBOL(fb_set_cmap); +EXPORT_SYMBOL(fb_default_cmap); +EXPORT_SYMBOL(fb_invert_cmaps); diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c --- v2.1.66/linux/drivers/video/fbcon-afb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-afb.c Tue Sep 16 02:29:29 1997 @@ -0,0 +1,304 @@ +/* + * linux/drivers/video/afb.c -- Low level frame buffer operations for + * bitplanes à la Amiga + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + + /* + * Prototypes + */ + +static int open_afb(struct display *p); +static void release_afb(void); +static void bmove_afb(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_afb(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_afb(struct vc_data *conp, struct display *p, int c, int yy, + int xx); +static void putcs_afb(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx); +static void rev_char_afb(struct display *p, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_afb = { + open_afb, release_afb, bmove_afb, clear_afb, putc_afb, putcs_afb, + rev_char_afb +}; + + /* + * Bitplanes à la Amiga + */ + +static int open_afb(struct display *p) +{ + if (p->type != FB_TYPE_PLANES) + return -EINVAL; + + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; + p->next_plane = p->var.yres_virtual*p->next_line; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_afb(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_afb(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + u_char *src, *dest, *src0, *dest0; + u_int i, rows; + + if (sx == 0 && dx == 0 && width == p->next_line) { + src = p->screen_base+sy*p->fontheight*width; + dest = p->screen_base+dy*p->fontheight*width; + for (i = p->var.bits_per_pixel; i--;) { + mymemmove(dest, src, height*p->fontheight*width); + src += p->next_plane; + dest += p->next_plane; + } + } else if (dy <= sy) { + src0 = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest0 = p->screen_base+dy*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel; i--;) { + src = src0; + dest = dest0; + for (rows = height*p->fontheight; rows--;) { + mymemmove(dest, src, width); + src += p->next_line; + dest += p->next_line; + } + src0 += p->next_plane; + dest0 += p->next_plane; + } + } else { + src0 = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx; + dest0 = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel; i--;) { + src = src0; + dest = dest0; + for (rows = height*p->fontheight; rows--;) { + src -= p->next_line; + dest -= p->next_line; + mymemmove(dest, src, width); + } + src0 += p->next_plane; + dest0 += p->next_plane; + } + } +} + +static void clear_afb(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest, *dest0; + u_int i, rows; + int bg; + + dest0 = p->screen_base+sy*p->fontheight*p->next_line+sx; + + bg = attr_bgcol_ec(p,conp); + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + dest = dest0; + for (rows = height*p->fontheight; rows--; dest += p->next_line) + if (bg & 1) + mymemset(dest, width); + else + mymemclear(dest, width); + bg >>= 1; + } +} + +static void putc_afb(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u_char *dest, *dest0, *cdat, *cdat0; + u_int rows, i; + u_char d; + int fg, bg; + + c &= 0xff; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + cdat0 = p->fontdata+c*p->fontheight; + fg = attr_fgcol(p,conp); + bg = attr_bgcol(p,conp); + + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + dest = dest0; + cdat = cdat0; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + } + bg >>= 1; + fg >>= 1; + } +} + + /* + * I've split the console character loop in two parts + * (cfr. fbcon_putcs_ilbm()) + */ + +static void putcs_afb(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx) +{ + u_char *dest, *dest0, *dest1; + u_char *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40; + u_int rows, i; + u_char c1, c2, c3, c4; + u_long d; + int fg0, bg0, fg, bg; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + fg0 = attr_fgcol(p,conp); + bg0 = attr_bgcol(p,conp); + + while (count--) + if (xx&3 || count < 3) { /* Slow version */ + c1 = *s++; + dest1 = dest0++; + xx++; + + cdat10 = p->fontdata+c1*p->fontheight; + fg = fg0; + bg = bg0; + + for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) { + dest = dest1; + cdat1 = cdat10; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat1++; + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + } + bg >>= 1; + fg >>= 1; + } + } else { /* Fast version */ + c1 = s[0]; + c2 = s[1]; + c3 = s[2]; + c4 = s[3]; + + dest1 = dest0; + cdat10 = p->fontdata+c1*p->fontheight; + cdat20 = p->fontdata+c2*p->fontheight; + cdat30 = p->fontdata+c3*p->fontheight; + cdat40 = p->fontdata+c4*p->fontheight; + fg = fg0; + bg = bg0; + + for (i = p->var.bits_per_pixel; i--; dest1 += p->next_plane) { + dest = dest1; + cdat1 = cdat10; + cdat2 = cdat20; + cdat3 = cdat30; + cdat4 = cdat40; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; + if (bg & 1) + if (fg & 1) + *(u_long *)dest = 0xffffffff; + else + *(u_long *)dest = ~d; + else + if (fg & 1) + *(u_long *)dest = d; + else + *(u_long *)dest = 0x00000000; + } + bg >>= 1; + fg >>= 1; + } + s += 4; + dest0 += 4; + xx += 4; + count -= 3; + } +} + +static void rev_char_afb(struct display *p, int xx, int yy) +{ + u_char *dest, *dest0; + u_int rows, i; + int mask; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + mask = p->fgcol ^ p->bgcol; + + /* + * This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + if (mask & 1) { + dest = dest0; + for (rows = p->fontheight; rows--; dest += p->next_line) + *dest = ~*dest; + } + mask >>= 1; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_afb(void) +#endif +{ + return(fbcon_register_driver(&dispsw_afb, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_afb); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c --- v2.1.66/linux/drivers/video/fbcon-cfb16.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-cfb16.c Tue Sep 16 02:29:31 1997 @@ -0,0 +1,233 @@ +/* + * linux/drivers/video/cfb16.c -- Low level frame buffer operations for 16 bpp + * packed pixels + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + + /* + * Prototypes + */ + +static int open_cfb16(struct display *p); +static void release_cfb16(void); +static void bmove_cfb16(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_cfb16(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_cfb16(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void putcs_cfb16(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx); +static void rev_char_cfb16(struct display *p, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_cfb16 = { + open_cfb16, release_cfb16, bmove_cfb16, clear_cfb16, putc_cfb16, + putcs_cfb16, rev_char_cfb16 +}; + + + /* + * 16 bpp packed pixels + */ + +u_short packed16_cmap[16]; + +static u_long tab_cfb16[] = { + 0x00000000,0x0000ffff,0xffff0000,0xffffffff +}; + +static int open_cfb16(struct display *p) +{ + if (p->type != FB_TYPE_PACKED_PIXELS || p->var.bits_per_pixel != 16) + return -EINVAL; + + p->next_line = p->var.xres_virtual<<1; + p->next_plane = 0; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_cfb16(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_cfb16(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + u_char *src,*dst; + + if (sx == 0 && dx == 0 && width * 16 == bytes) + mymemmove(p->screen_base + dy * linesize, + p->screen_base + sy * linesize, + height * linesize); + else if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx * 16; + dst = p->screen_base + dy * linesize + dx * 16; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 16); + src += bytes; + dst += bytes; + } + } else { + src = p->screen_base + (sy+height) * linesize + sx * 16 - bytes; + dst = p->screen_base + (dy+height) * linesize + dx * 16 - bytes; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 16); + src -= bytes; + dst -= bytes; + } + } +} + +static void clear_cfb16(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + u_char *dest0,*dest; + int bytes=p->next_line,lines=height * p->fontheight, rows, i; + u_long bgx; + + dest = p->screen_base + sy * p->fontheight * bytes + sx * 16; + + bgx = attr_bgcol_ec(p,conp); + bgx = packed16_cmap[bgx]; + bgx |= (bgx << 16); + + if (sx == 0 && width * 16 == bytes) + for (i = 0 ; i < lines * width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + ((u_long *)dest)[2]=bgx; + ((u_long *)dest)[3]=bgx; + dest+=16; + } + else { + dest0=dest; + for (rows = lines; rows-- ; dest0 += bytes) { + dest=dest0; + for (i = 0 ; i < width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + ((u_long *)dest)[2]=bgx; + ((u_long *)dest)[3]=bgx; + dest+=16; + } + } + } +} + +static void putc_cfb16(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u_char *dest,*cdat; + int bytes=p->next_line,rows; + ulong eorx,fgx,bgx; + + c &= 0xff; + + dest = p->screen_base + yy * p->fontheight * bytes + xx * 16; + cdat = p->fontdata + c * p->fontheight; + + fgx = attr_fgcol(p,conp); + fgx = packed16_cmap[fgx]; + bgx = attr_bgcol(p,conp); + bgx = packed16_cmap[bgx]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= (tab_cfb16[*cdat >> 6] & eorx) ^ bgx; + ((u_long *)dest)[1]= (tab_cfb16[*cdat >> 4 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[2]= (tab_cfb16[*cdat >> 2 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[3]= (tab_cfb16[*cdat++ & 0x3] & eorx) ^ bgx; + } +} + +static void putcs_cfb16(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx) +{ + u_char *cdat, c, *dest, *dest0; + int rows,bytes=p->next_line; + u_long eorx, fgx, bgx; + + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16; + fgx = attr_fgcol(p,conp); + fgx = packed16_cmap[fgx]; + bgx = attr_bgcol(p,conp); + bgx = packed16_cmap[bgx]; + fgx |= (fgx << 16); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + while (count--) { + c = *s++; + cdat = p->fontdata + c * p->fontheight; + + for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= (tab_cfb16[*cdat >> 6] & eorx) ^ bgx; + ((u_long *)dest)[1]= (tab_cfb16[*cdat >> 4 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[2]= (tab_cfb16[*cdat >> 2 & 0x3] & eorx) ^ bgx; + ((u_long *)dest)[3]= (tab_cfb16[*cdat++ & 0x3] & eorx) ^ bgx; + } + dest0+=16; + } +} + +static void rev_char_cfb16(struct display *p, int xx, int yy) +{ + u_char *dest; + int bytes=p->next_line, rows; + + dest = p->screen_base + yy * p->fontheight * bytes + xx * 16; + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0] ^= 0xffffffff; + ((u_long *)dest)[1] ^= 0xffffffff; + ((u_long *)dest)[2] ^= 0xffffffff; + ((u_long *)dest)[3] ^= 0xffffffff; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_cfb16(void) +#endif +{ + return(fbcon_register_driver(&dispsw_cfb16, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_cfb16); +} +#endif /* MODULE */ + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(packed16_cmap); diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c --- v2.1.66/linux/drivers/video/fbcon-cfb8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-cfb8.c Tue Sep 16 02:29:34 1997 @@ -0,0 +1,218 @@ +/* + * linux/drivers/video/cfb8.c -- Low level frame buffer operations for 8 bpp + * packed pixels + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + + /* + * Prototypes + */ + +static int open_cfb8(struct display *p); +static void release_cfb8(void); +static void bmove_cfb8(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_cfb8(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_cfb8(struct vc_data *conp, struct display *p, int c, int yy, + int xx); +static void putcs_cfb8(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx); +static void rev_char_cfb8(struct display *p, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_cfb8 = { + open_cfb8, release_cfb8, bmove_cfb8, clear_cfb8, putc_cfb8, putcs_cfb8, + rev_char_cfb8 +}; + + + /* + * 8 bpp packed pixels + */ + +static u_long nibbletab_cfb8[] = { + 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, + 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, + 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, + 0xffff0000,0xffff00ff,0xffffff00,0xffffffff +}; + +static int open_cfb8(struct display *p) +{ + if (p->type != FB_TYPE_PACKED_PIXELS || p->var.bits_per_pixel != 8) + return -EINVAL; + + p->next_line = p->var.xres_virtual; + p->next_plane = 0; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_cfb8(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_cfb8(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int bytes = p->next_line, linesize = bytes * p->fontheight, rows; + u_char *src,*dst; + + if (sx == 0 && dx == 0 && width * 8 == bytes) + mymemmove(p->screen_base + dy * linesize, + p->screen_base + sy * linesize, + height * linesize); + else if (dy < sy || (dy == sy && dx < sx)) { + src = p->screen_base + sy * linesize + sx * 8; + dst = p->screen_base + dy * linesize + dx * 8; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 8); + src += bytes; + dst += bytes; + } + } else { + src = p->screen_base + (sy+height) * linesize + sx * 8 - bytes; + dst = p->screen_base + (dy+height) * linesize + dx * 8 - bytes; + for (rows = height * p->fontheight ; rows-- ;) { + mymemmove(dst, src, width * 8); + src -= bytes; + dst -= bytes; + } + } +} + +static void clear_cfb8(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest0,*dest; + int bytes=p->next_line,lines=height * p->fontheight, rows, i; + u_long bgx; + + dest = p->screen_base + sy * p->fontheight * bytes + sx * 8; + + bgx=attr_bgcol_ec(p,conp); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + if (sx == 0 && width * 8 == bytes) + for (i = 0 ; i < lines * width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + dest+=8; + } + else { + dest0=dest; + for (rows = lines; rows-- ; dest0 += bytes) { + dest=dest0; + for (i = 0 ; i < width ; i++) { + ((u_long *)dest)[0]=bgx; + ((u_long *)dest)[1]=bgx; + dest+=8; + } + } + } +} + +static void putc_cfb8(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u_char *dest,*cdat; + int bytes=p->next_line,rows; + ulong eorx,fgx,bgx; + + c &= 0xff; + + dest = p->screen_base + yy * p->fontheight * bytes + xx * 8; + cdat = p->fontdata + c * p->fontheight; + + fgx=attr_fgcol(p,conp); + bgx=attr_bgcol(p,conp); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx; + ((u_long *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx; + } +} + +static void putcs_cfb8(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx) +{ + u_char *cdat, c, *dest, *dest0; + int rows,bytes=p->next_line; + u_long eorx, fgx, bgx; + + dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 8; + fgx=attr_fgcol(p,conp); + bgx=attr_bgcol(p,conp); + fgx |= (fgx << 8); + fgx |= (fgx << 16); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + eorx = fgx ^ bgx; + while (count--) { + c = *s++; + cdat = p->fontdata + c * p->fontheight; + + for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + ((u_long *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx; + ((u_long *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ + bgx; + } + dest0+=8; + } +} + +static void rev_char_cfb8(struct display *p, int xx, int yy) +{ + u_char *dest; + int bytes=p->next_line, rows; + + dest = p->screen_base + yy * p->fontheight * bytes + xx * 8; + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((u_long *)dest)[0] ^= 0x0f0f0f0f; + ((u_long *)dest)[1] ^= 0x0f0f0f0f; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_cfb8(void) +#endif +{ + return(fbcon_register_driver(&dispsw_cfb8, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_cfb8); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-cyber.c linux/drivers/video/fbcon-cyber.c --- v2.1.66/linux/drivers/video/fbcon-cyber.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-cyber.c Tue Sep 16 02:29:36 1997 @@ -0,0 +1,230 @@ +/* + * linux/drivers/video/cyber.c -- Low level frame buffer operations for the + * CyberVision64 (accelerated) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" +#include "s3blit.h" + + + /* + * Prototypes + */ + +static int open_cyber(struct display *p); +static void release_cyber(void); +static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_cyber(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy, + int xx); +static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx); +static void rev_char_cyber(struct display *p, int xx, int yy); + + + /* + * Acceleration functions in cyberfb.c + */ + +extern void Cyber_WaitQueue(unsigned short fifo); +extern void Cyber_WaitBlit(void); +extern void Cyber_BitBLT(unsigned short curx, unsigned short cury, + unsigned short destx, unsigned short desty, + unsigned short width, unsigned short height, + unsigned short mode); +extern void Cyber_RectFill(unsigned short xx, unsigned short yy, + unsigned short width, unsigned short height, + unsigned short mode, unsigned short fillcolor); +extern void Cyber_MoveCursor(unsigned short xx, unsigned short yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_cyber = { + open_cyber, release_cyber, bmove_cyber, clear_cyber, putc_cyber, + putcs_cyber, rev_char_cyber +}; + + + /* + * CyberVision64 (accelerated) + */ + +static int open_cyber(struct display *p) +{ + if (p->type != FB_TYPE_PACKED_PIXELS || + p->var.accel != FB_ACCEL_CYBERVISION) + return -EINVAL; + + p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3; + p->next_plane = 0; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_cyber(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_cyber(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + sx *= 8; dx *= 8; width *= 8; + Cyber_BitBLT((u_short)sx, (u_short)(sy*p->fontheight), (u_short)dx, + (u_short)(dy*p->fontheight), (u_short)width, + (u_short)(height*p->fontheight), (u_short)S3_NEW); +} + +static void clear_cyber(struct vc_data *conp, struct display *p, int + sy, int sx, int height, int width) +{ + unsigned char bg; + + sx *= 8; width *= 8; + bg = attr_bgcol_ec(p,conp); + Cyber_RectFill((u_short)sx, + (u_short)(sy*p->fontheight), + (u_short)width, + (u_short)(height*p->fontheight), + (u_short)S3_NEW, + (u_short)bg); +} + +static void putc_cyber(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u_char *dest, *cdat; + u_long tmp; + u_int rows, revs, underl; + u_char d; + u_char fg, bg; + + c &= 0xff; + + dest = p->screen_base+yy*p->fontheight*p->next_line+8*xx; + cdat = p->fontdata+(c*p->fontheight); + fg = p->fgcol; + bg = p->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; + + Cyber_WaitBlit(); + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + + if (underl && !rows) + d = 0xff; + if (revs) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((u_long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((u_long*) dest + 1) = tmp; + } +} + +static void putcs_cyber(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx) +{ + u_char *dest, *dest0, *cdat; + u_long tmp; + u_int rows, underl; + u_char c, d; + u_char fg, bg; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+8*xx; + fg = p->fgcol; + bg = p->bgcol; + underl = conp->vc_underline; + + Cyber_WaitBlit(); + while (count--) { + c = *s++; + dest = dest0; + dest0 += 8; + cdat = p->fontdata+(c*p->fontheight); + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + + if (underl && !rows) + d = 0xff; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((u_long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((u_long*) dest + 1) = tmp; + } + } +} + + +static void rev_char_cyber(struct display *p, int xx, int yy) +{ + unsigned char *dest; + unsigned int rows; + unsigned char fg, bg; + + fg = p->fgcol; + bg = p->bgcol; + + dest = p->screen_base+yy*p->fontheight*p->next_line+8*xx; + Cyber_WaitBlit(); + for (rows = p->fontheight; rows--; dest += p->next_line) { + *dest = (*dest == fg) ? bg : fg; + *(dest+1) = (*(dest + 1) == fg) ? bg : fg; + *(dest+2) = (*(dest + 2) == fg) ? bg : fg; + *(dest+3) = (*(dest + 3) == fg) ? bg : fg; + *(dest+4) = (*(dest + 4) == fg) ? bg : fg; + *(dest+5) = (*(dest + 5) == fg) ? bg : fg; + *(dest+6) = (*(dest + 6) == fg) ? bg : fg; + *(dest+7) = (*(dest + 7) == fg) ? bg : fg; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_cyber(void) +#endif +{ + return(fbcon_register_driver(&dispsw_cyber, 1)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_cyber); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c --- v2.1.66/linux/drivers/video/fbcon-ilbm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-ilbm.c Tue Sep 16 02:29:39 1997 @@ -0,0 +1,301 @@ +/* + * linux/drivers/video/ilbm.c -- Low level frame buffer operations for + * interleaved bitplanes à la Amiga + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + + /* + * Prototypes + */ + +static int open_ilbm(struct display *p); +static void release_ilbm(void); +static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy, + int xx); +static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx); +static void rev_char_ilbm(struct display *p, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_ilbm = { + open_ilbm, release_ilbm, bmove_ilbm, clear_ilbm, putc_ilbm, putcs_ilbm, + rev_char_ilbm +}; + + + /* + * Interleaved bitplanes à la Amiga + * + * This code heavily relies on the fact that + * + * next_line == interleave == next_plane*bits_per_pixel + * + * But maybe it can be merged with the code for normal bitplanes without + * much performance loss? + */ + +static int open_ilbm(struct display *p) +{ + if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux == 2) + return -EINVAL; + + if (p->line_length) { + p->next_line = p->line_length*p->var.bits_per_pixel; + p->next_plane = p->line_length; + } else { + p->next_line = p->type_aux; + p->next_plane = p->type_aux/p->var.bits_per_pixel; + } + MOD_INC_USE_COUNT; + return 0; +} + +static void release_ilbm(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_ilbm(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + if (sx == 0 && dx == 0 && width == p->next_plane) + mymemmove(p->screen_base+dy*p->fontheight*p->next_line, + p->screen_base+sy*p->fontheight*p->next_line, + height*p->fontheight*p->next_line); + else { + u_char *src, *dest; + u_int i; + + if (dy <= sy) { + src = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest = p->screen_base+dy*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) { + mymemmove(dest, src, width); + src += p->next_plane; + dest += p->next_plane; + } + } else { + src = p->screen_base+(sy+height)*p->fontheight*p->next_line+sx; + dest = p->screen_base+(dy+height)*p->fontheight*p->next_line+dx; + for (i = p->var.bits_per_pixel*height*p->fontheight; i--;) { + src -= p->next_plane; + dest -= p->next_plane; + mymemmove(dest, src, width); + } + } + } +} + +static void clear_ilbm(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest; + u_int i, rows; + int bg, bg0; + + dest = p->screen_base+sy*p->fontheight*p->next_line+sx; + + bg0 = attr_bgcol_ec(p,conp); + for (rows = height*p->fontheight; rows--;) { + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + mymemset(dest, width); + else + mymemclear(dest, width); + bg >>= 1; + } + } +} + +static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u_char *dest, *cdat; + u_int rows, i; + u_char d; + int fg0, bg0, fg, bg; + + c &= 0xff; + + dest = p->screen_base+yy*p->fontheight*p->next_line+xx; + cdat = p->fontdata+c*p->fontheight; + fg0 = attr_fgcol(p,conp); + bg0 = attr_bgcol(p,conp); + + for (rows = p->fontheight; rows--;) { + d = *cdat++; + fg = fg0; + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + bg >>= 1; + fg >>= 1; + } + } +} + + /* + * I've split the console character loop in two parts: + * + * - slow version: this blits one character at a time + * + * - fast version: this blits 4 characters at a time at a longword + * aligned address, to reduce the number of expensive + * Chip RAM accesses. + * + * Experiments on my A4000/040 revealed that this makes a console switch + * on a 640x400 screen with 256 colors about 3 times faster. + * + * -- Geert + */ + +static void putcs_ilbm(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx) +{ + u_char *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4; + u_int rows, i; + u_char c1, c2, c3, c4; + u_long d; + int fg0, bg0, fg, bg; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + fg0 = attr_fgcol(p,conp); + bg0 = attr_bgcol(p,conp); + + while (count--) + if (xx&3 || count < 3) { /* Slow version */ + c1 = *s++; + dest = dest0++; + xx++; + + cdat1 = p->fontdata+c1*p->fontheight; + for (rows = p->fontheight; rows--;) { + d = *cdat1++; + fg = fg0; + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + if (fg & 1) + *dest = 0xff; + else + *dest = ~d; + else + if (fg & 1) + *dest = d; + else + *dest = 0x00; + bg >>= 1; + fg >>= 1; + } + } + } else { /* Fast version */ + c1 = s[0]; + c2 = s[1]; + c3 = s[2]; + c4 = s[3]; + + dest = dest0; + cdat1 = p->fontdata+c1*p->fontheight; + cdat2 = p->fontdata+c2*p->fontheight; + cdat3 = p->fontdata+c3*p->fontheight; + cdat4 = p->fontdata+c4*p->fontheight; + for (rows = p->fontheight; rows--;) { + d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; + fg = fg0; + bg = bg0; + for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) { + if (bg & 1) + if (fg & 1) + *(u_long *)dest = 0xffffffff; + else + *(u_long *)dest = ~d; + else + if (fg & 1) + *(u_long *)dest = d; + else + *(u_long *)dest = 0x00000000; + bg >>= 1; + fg >>= 1; + } + } + s += 4; + dest0 += 4; + xx += 4; + count -= 3; + } +} + +static void rev_char_ilbm(struct display *p, int xx, int yy) +{ + u_char *dest, *dest0; + u_int rows, i; + int mask; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + mask = p->fgcol ^ p->bgcol; + + /* + * This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + + for (i = p->var.bits_per_pixel; i--; dest0 += p->next_plane) { + if (mask & 1) { + dest = dest0; + for (rows = p->fontheight; rows--; dest += p->next_line) + *dest = ~*dest; + } + mask >>= 1; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_ilbm(void) +#endif +{ + return(fbcon_register_driver(&dispsw_ilbm, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_ilbm); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c --- v2.1.66/linux/drivers/video/fbcon-iplan2p2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-iplan2p2.c Mon Nov 24 01:18:54 1997 @@ -0,0 +1,443 @@ +/* + * linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for + * interleaved bitplanes à la Atari (2 + * planes, 2 bytes interleave) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + +#ifndef __mc68000__ +#error No support for non-m68k yet +#endif + + + /* + * Prototypes + */ + +static int open_iplan2p2(struct display *p); +static void release_iplan2p2(void); +static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_iplan2p2(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_iplan2p2(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void putcs_iplan2p2(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx); +static void rev_char_iplan2p2(struct display *display, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_iplan2p2 = { + open_iplan2p2, release_iplan2p2, bmove_iplan2p2, clear_iplan2p2, + putc_iplan2p2, putcs_iplan2p2, rev_char_iplan2p2 +}; + + + /* + * Interleaved bitplanes à la Atari (2 planes, 2 bytes interleave) + */ + +/* Increment/decrement 2 plane addresses */ + +#define INC_2P(p) do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0) +#define DEC_2P(p) do { if ((long)(--(p)) & 1) (p) -= 2; } while(0) + + /* Convert a standard 4 bit color to our 2 bit color assignment: + * If at least two RGB channels are active, the low bit is turned on; + * The intensity bit (b3) is shifted into b1. + */ + +#define COLOR_2P(c) (((c & 7) >= 3 && (c & 7) != 4) | (c & 8) >> 2) + + +/* Sets the bytes in the visible column at d, height h, to the value + * val for a 2 plane screen. The the bis of the color in 'color' are + * moved (8 times) to the respective bytes. This means: + * + * for(h times; d += bpr) + * *d = (color & 1) ? 0xff : 0; + * *(d+2) = (color & 2) ? 0xff : 0; + */ + +static __inline__ void memclear_2p_col(void *d, size_t h, u_short val, int bpr) +{ +#ifdef __mc68000__ + __asm__ __volatile__ ("1: movepw %4,%0@(0)\n\t" + "addal %5,%0\n\t" + "dbra %1,1b" + : "=a" (d), "=d" (h) + : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)); +#else /* !m68k */ +#endif /* !m68k */ +} + +/* Sets a 2 plane region from 'd', length 'count' bytes, to the color + * in val1. 'd' has to be an even address and count must be divisible + * by 8, because only whole words and all planes are accessed. I.e.: + * + * for(count/4 times) + * *d = *(d+1) = (color & 1) ? 0xff : 0; + * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0; + */ + +static __inline__ void memset_even_2p(void *d, size_t count, u_long val) +{ + u_long *dd = d; + + count /= 4; + while (count--) + *dd++ = val; +} + +/* Copies a 2 plane column from 's', height 'h', to 'd'. */ + +static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr) +{ + u_char *dd = d, *ss = s; + + while (h--) { + dd[0] = ss[0]; + dd[2] = ss[2]; + dd += bpr; + ss += bpr; + } +} + + +/* This expands a 2 bit color into a short for movepw (2 plane) operations. */ + +static __inline__ u_short expand2w(u_char c) +{ + u_short rv; + +#ifdef __mc68000__ + __asm__ __volatile__ ("lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + : "=&d" (rv), "=d" (c) + : "1" (c)); +#endif /* !m68k */ + return(rv); +} + +/* This expands a 2 bit color into one long for a movel operation + * (2 planes). + */ + +static __inline__ u_long expand2l(u_char c) +{ + u_long rv; + +#ifdef __mc68000__ + __asm__ __volatile__ ("lsrb #1,%2\n\t" + "scs %0\n\t" + "extw %0\n\t" + "swap %0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + "extw %0\n\t" + : "=&d" (rv), "=d" (c) + : "1" (c)); +#endif /* !m68k */ + return rv; +} + + +/* This duplicates a byte 2 times into a short. */ + +static __inline__ u_short dup2w(u_char c) +{ + ushort rv; + +#ifdef __mc68000__ + __asm__ __volatile__ ("moveb %1,%0\n\t" + "lslw #8,%0\n\t" + "moveb %1,%0\n\t" + : "=&d" (rv) + : "d" (c)); +#endif /* !m68k */ + return( rv ); +} + + +static int open_iplan2p2(struct display *p) +{ + if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux != 2 || + p->var.bits_per_pixel != 2) + return -EINVAL; + + p->next_line = p->var.xres_virtual>>2; + p->next_plane = 2; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_iplan2p2(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_iplan2p2(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + if (sx == 0 && dx == 0 && width == p->next_line/2) { + /* Special (but often used) case: Moving whole lines can be + * done with memmove() + */ + mymemmove(p->screen_base + dy * p->next_line * p->fontheight, + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); + } else { + int rows, cols; + u_char *src; + u_char *dst; + int bytes = p->next_line; + int linesize = bytes * p->fontheight; + u_int colsize = height * p->fontheight; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + if ((sx & 1) == (dx & 1)) { + /* odd->odd or even->even */ + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + if (sx & 1) { + memmove_2p_col(dst, src, colsize, bytes); + src += 3; + dst += 3; + --width; + } + if (width > 1) { + for (rows = colsize; rows > 0; --rows) { + mymemmove(dst, src, (width>>1)*4); + src += bytes; + dst += bytes; + } + } + if (width & 1) { + src -= colsize * bytes; + dst -= colsize * bytes; + memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4, + colsize, bytes); + } + } else { + if (!((sx+width-1) & 1)) { + src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*4; + dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*4; + memmove_2p_col(dst, src, colsize, bytes); + --width; + } + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + if (width > 1) { + src += colsize * bytes + (sx & 1)*3; + dst += colsize * bytes + (sx & 1)*3; + for(rows = colsize; rows > 0; --rows) { + src -= bytes; + dst -= bytes; + mymemmove(dst, src, (width>>1)*4); + } + } + if (width & 1) + memmove_2p_col(dst-3, src-3, colsize, bytes); + } + } else { + /* odd->even or even->odd */ + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + for (cols = width; cols > 0; --cols) { + memmove_2p_col(dst, src, colsize, bytes); + INC_2P(src); + INC_2P(dst); + } + } else { + sx += width-1; + dx += width-1; + src = p->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_2p_col(dst, src, colsize, bytes); + DEC_2P(src); + DEC_2P(dst); + } + } + } + } +} + +static void clear_iplan2p2(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + ulong offset; + u_char *start; + int rows; + int bytes = p->next_line; + int lines = height * p->fontheight; + ulong size; + u_long cval; + u_short pcval; + + cval = expand2l (COLOR_2P (attr_bgcol_ec(p,conp))); + + if (sx == 0 && width == bytes/2) { + offset = sy * bytes * p->fontheight; + size = lines * bytes; + memset_even_2p(p->screen_base+offset, size, cval); + } else { + offset = (sy * bytes * p->fontheight) + (sx>>1)*4 + (sx & 1); + start = p->screen_base + offset; + pcval = expand2w(COLOR_2P(attr_bgcol_ec(p,conp))); + + /* Clears are split if the region starts at an odd column or + * end at an even column. These extra columns are spread + * across the interleaved planes. All in between can be + * cleared by normal mymemclear_small(), because both bytes of + * the single plane words are affected. + */ + + if (sx & 1) { + memclear_2p_col(start, lines, pcval, bytes); + start += 3; + width--; + } + if (width & 1) { + memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes); + width--; + } + if (width) { + for (rows = lines; rows-- ; start += bytes) + memset_even_2p(start, width*2, cval); + } + } +} + +static void putc_iplan2p2(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx, fgx, bgx, fdx; + + c &= 0xff; + + dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1); + cdat = p->fontdata + (c * p->fontheight); + + fgx = expand2w(COLOR_2P(attr_fgcol(p,conp))); + bgx = expand2w(COLOR_2P(attr_bgcol(p,conp))); + eorx = fgx ^ bgx; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + fdx = dup2w(*cdat++); +#ifdef __mc68000__ + __asm__ __volatile__ ("movepw %1,%0@(0)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); +#endif /* !m68k */ + } +} + +static void putcs_iplan2p2(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx) +{ + u_char *dest, *dest0; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx, fgx, bgx, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1); + fgx = expand2w(COLOR_2P(attr_fgcol(p,conp))); + bgx = expand2w(COLOR_2P(attr_bgcol(p,conp))); + eorx = fgx ^ bgx; + + while (count--) { + c = *s++; + cdat = p->fontdata + (c * p->fontheight); + + for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + fdx = dup2w(*cdat++); +#ifdef __mc68000__ + __asm__ __volatile__ ("movepw %1,%0@(0)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); +#endif /* !m68k */ + } + INC_2P(dest0); + } +} + +static void rev_char_iplan2p2(struct display *p, int xx, int yy) +{ + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + yy * p->fontheight * p->next_line + (xx>>1)*4 + + (xx & 1); + j = p->fontheight; + bytes = p->next_line; + while (j--) { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest += bytes; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_iplan2p2(void) +#endif +{ + return(fbcon_register_driver(&dispsw_iplan2p2, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_iplan2p2); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c --- v2.1.66/linux/drivers/video/fbcon-iplan2p4.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-iplan2p4.c Mon Nov 24 01:18:55 1997 @@ -0,0 +1,474 @@ +/* + * linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for + * interleaved bitplanes à la Atari (4 + * planes, 2 bytes interleave) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + +#ifndef __mc68000__ +#error No support for non-m68k yet +#endif + + + /* + * Prototypes + */ + +static int open_iplan2p4(struct display *p); +static void release_iplan2p4(void); +static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_iplan2p4(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_iplan2p4(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void putcs_iplan2p4(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx); +static void rev_char_iplan2p4(struct display *p, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_iplan2p4 = { + open_iplan2p4, release_iplan2p4, bmove_iplan2p4, clear_iplan2p4, + putc_iplan2p4, putcs_iplan2p4, rev_char_iplan2p4 +}; + + + /* + * Interleaved bitplanes à la Atari (4 planes, 2 bytes interleave) + */ + +/* Increment/decrement 4 plane addresses */ + +#define INC_4P(p) do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0) +#define DEC_4P(p) do { if ((long)(--(p)) & 1) (p) -= 6; } while(0) + + +/* Sets the bytes in the visible column at d, height h, to the value + * val for a 4 plane screen. The the bis of the color in 'color' are + * moved (8 times) to the respective bytes. This means: + * + * for(h times; d += bpr) + * *d = (color & 1) ? 0xff : 0; + * *(d+2) = (color & 2) ? 0xff : 0; + * *(d+4) = (color & 4) ? 0xff : 0; + * *(d+6) = (color & 8) ? 0xff : 0; + */ + +static __inline__ void memclear_4p_col(void *d, size_t h, u_long val, int bpr) +{ +#ifdef __mc68000__ + __asm__ __volatile__ ("1: movepl %4,%0@(0)\n\t" + "addal %5,%0\n\t" + "dbra %1,1b" + : "=a" (d), "=d" (h) + : "0" (d), "1" (h - 1), "d" (val), "r" (bpr)); +#endif /* !m68k */ +} + +/* Sets a 4 plane region from 'd', length 'count' bytes, to the color + * in val1/val2. 'd' has to be an even address and count must be divisible + * by 8, because only whole words and all planes are accessed. I.e.: + * + * for(count/8 times) + * *d = *(d+1) = (color & 1) ? 0xff : 0; + * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0; + * *(d+4) = *(d+5) = (color & 4) ? 0xff : 0; + * *(d+6) = *(d+7) = (color & 8) ? 0xff : 0; + */ + +static __inline__ void memset_even_4p(void *d, size_t count, u_long val1, + u_long val2) +{ + u_long *dd = d; + + count /= 8; + while (count--) { + *dd++ = val1; + *dd++ = val2; + } +} + +/* Copies a 4 plane column from 's', height 'h', to 'd'. */ + +static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr) +{ + u_char *dd = d, *ss = s; + + while (h--) { + dd[0] = ss[0]; + dd[2] = ss[2]; + dd[4] = ss[4]; + dd[6] = ss[6]; + dd += bpr; + ss += bpr; + } +} + + +/* This expands a 4 bit color into a long for movepl (4 plane) operations. */ + +static __inline__ u_long expand4l(u_char c) +{ + u_long rv; + +#ifdef __mc68000__ + __asm__ __volatile__ ("lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%2\n\t" + "scs %0\n\t" + : "=&d" (rv), "=d" (c) + : "1" (c)); +#endif /* !m68k */ + return(rv); +} + +/* This expands a 4 bit color into two longs for two movel operations + * (4 planes). + */ + +static __inline__ void expand4dl(u_char c, u_long *ret1, u_long *ret2) +{ + u_long rv1, rv2; + +#ifdef __mc68000__ + __asm__ __volatile__ ("lsrb #1,%3\n\t" + "scs %0\n\t" + "extw %0\n\t" + "swap %0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "extw %0\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "extw %1\n\t" + "swap %1\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "extw %1" + : "=&d" (rv1), "=&d" (rv2), "=d" (c) + : "2" (c)); +#endif /* !m68k */ + *ret1 = rv1; + *ret2 = rv2; +} + + +/* This duplicates a byte 4 times into a long. */ + +static __inline__ u_long dup4l(u_char c) +{ + ushort tmp; + ulong rv; + +#ifdef __mc68000__ + __asm__ __volatile__ ("moveb %2,%0\n\t" + "lslw #8,%0\n\t" + "moveb %2,%0\n\t" + "movew %0,%1\n\t" + "swap %0\n\t" + "movew %1,%0" + : "=&d" (rv), "=d" (tmp) + : "d" (c)); +#endif /* !m68k */ + return(rv); +} + + +static int open_iplan2p4(struct display *p) +{ + if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux != 2 || + p->var.bits_per_pixel != 4) + return -EINVAL; + + p->next_line = p->var.xres_virtual>>1; + p->next_plane = 2; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_iplan2p4(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_iplan2p4(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + if (sx == 0 && dx == 0 && width == p->next_line/4) { + /* Special (but often used) case: Moving whole lines can be + *done with memmove() + */ + mymemmove(p->screen_base + dy * p->next_line * p->fontheight, + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); + } else { + int rows, cols; + u_char *src; + u_char *dst; + int bytes = p->next_line; + int linesize = bytes * p->fontheight; + u_int colsize = height * p->fontheight; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + if ((sx & 1) == (dx & 1)) { + /* odd->odd or even->even */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + if (sx & 1) { + memmove_4p_col(dst, src, colsize, bytes); + src += 7; + dst += 7; + --width; + } + if (width > 1) { + for(rows = colsize; rows > 0; --rows) { + mymemmove(dst, src, (width>>1)*8); + src += bytes; + dst += bytes; + } + } + if (width & 1) { + src -= colsize * bytes; + dst -= colsize * bytes; + memmove_4p_col(dst + (width>>1)*8, src + (width>>1)*8, + colsize, bytes); + } + } else { + if (!((sx+width-1) & 1)) { + src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*8; + dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*8; + memmove_4p_col(dst, src, colsize, bytes); + --width; + } + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + if (width > 1) { + src += colsize * bytes + (sx & 1)*7; + dst += colsize * bytes + (sx & 1)*7; + for(rows = colsize; rows > 0; --rows) { + src -= bytes; + dst -= bytes; + mymemmove(dst, src, (width>>1)*8); + } + } + if (width & 1) { + memmove_4p_col(dst-7, src-7, colsize, bytes); + } + } + } else { + /* odd->even or even->odd */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_4p_col(dst, src, colsize, bytes); + INC_4P(src); + INC_4P(dst); + } + } else { + sx += width-1; + dx += width-1; + src = p->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_4p_col(dst, src, colsize, bytes); + DEC_4P(src); + DEC_4P(dst); + } + } + } + } +} + +static void clear_iplan2p4(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + ulong offset; + u_char *start; + int rows; + int bytes = p->next_line; + int lines = height * p->fontheight; + ulong size; + u_long cval1, cval2, pcval; + + expand4dl(attr_bgcol_ec(p,conp), &cval1, &cval2); + + if (sx == 0 && width == bytes/4) { + offset = sy * bytes * p->fontheight; + size = lines * bytes; + memset_even_4p(p->screen_base+offset, size, cval1, cval2); + } else { + offset = (sy * bytes * p->fontheight) + (sx>>1)*8 + (sx & 1); + start = p->screen_base + offset; + pcval = expand4l(attr_bgcol_ec(p,conp)); + + /* Clears are split if the region starts at an odd column or + * end at an even column. These extra columns are spread + * across the interleaved planes. All in between can be + * cleared by normal mymemclear_small(), because both bytes of + * the single plane words are affected. + */ + + if (sx & 1) { + memclear_4p_col(start, lines, pcval, bytes); + start += 7; + width--; + } + if (width & 1) { + memclear_4p_col(start + (width>>1)*8, lines, pcval, bytes); + width--; + } + if (width) { + for(rows = lines; rows-- ; start += bytes) + memset_even_4p(start, width*4, cval1, cval2); + } + } +} + +static void putc_iplan2p4(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx, fgx, bgx, fdx; + + c &= 0xff; + + dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1); + cdat = p->fontdata + (c * p->fontheight); + + fgx = expand4l(attr_fgcol(p,conp)); + bgx = expand4l(attr_bgcol(p,conp)); + eorx = fgx ^ bgx; + + for(rows = p->fontheight ; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); +#ifdef __mc68000__ + __asm__ __volatile__ ("movepl %1,%0@(0)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); +#endif /* !m68k */ + } +} + +static void putcs_iplan2p4(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx) +{ + u_char *dest, *dest0; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx, fgx, bgx, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1); + fgx = expand4l(attr_fgcol(p,conp)); + bgx = expand4l(attr_bgcol(p,conp)); + eorx = fgx ^ bgx; + + while (count--) { + /* I think, unrolling the loops like in the 1 plane case isn't + * practicable here, because the body is much longer for 4 + * planes (mostly the dup4l()). I guess, unrolling this would + * need more than 256 bytes and so exceed the instruction + * cache :-( + */ + + c = *s++; + cdat = p->fontdata + (c * p->fontheight); + + for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); +#ifdef __mc68000__ + __asm__ __volatile__ ("movepl %1,%0@(0)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx) ^ bgx)); +#endif /* !m68k */ + } + INC_4P(dest0); + } +} + +static void rev_char_iplan2p4(struct display *p, int xx, int yy) +{ + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + yy * p->fontheight * p->next_line + (xx>>1)*8 + + (xx & 1); + j = p->fontheight; + bytes = p->next_line; + + while (j--) { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest[4] = ~dest[4]; + dest[6] = ~dest[6]; + dest += bytes; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_iplan2p4(void) +#endif +{ + return(fbcon_register_driver(&dispsw_iplan2p4, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_iplan2p4); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c --- v2.1.66/linux/drivers/video/fbcon-iplan2p8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-iplan2p8.c Mon Nov 24 01:18:56 1997 @@ -0,0 +1,532 @@ +/* + * linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for + * interleaved bitplanes à la Atari (8 + * planes, 2 bytes interleave) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + +#ifndef __mc68000__ +#error No support for non-m68k yet +#endif + + + /* + * Prototypes + */ + +static int open_iplan2p8(struct display *p); +static void release_iplan2p8(void); +static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_iplan2p8(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +static void putc_iplan2p8(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +static void putcs_iplan2p8(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx); +static void rev_char_iplan2p8(struct display *display, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_iplan2p8 = { + open_iplan2p8, release_iplan2p8, bmove_iplan2p8, clear_iplan2p8, + putc_iplan2p8, putcs_iplan2p8, rev_char_iplan2p8 +}; + + + /* + * Interleaved bitplanes à la Atari (8 planes, 2 bytes interleave) + * + * In 8 plane mode, 256 colors would be possible, but only the first + * 16 are used by the console code (the upper 4 bits are + * background/unused). For that, the following functions mask off the + * higher 4 bits of each color. + */ + +/* Increment/decrement 8 plane addresses */ + +#define INC_8P(p) do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0) +#define DEC_8P(p) do { if ((long)(--(p)) & 1) (p) -= 14; } while(0) + + +/* Sets the bytes in the visible column at d, height h, to the value + * val1,val2 for a 8 plane screen. The the bis of the color in 'color' are + * moved (8 times) to the respective bytes. This means: + * + * for(h times; d += bpr) + * *d = (color & 1) ? 0xff : 0; + * *(d+2) = (color & 2) ? 0xff : 0; + * *(d+4) = (color & 4) ? 0xff : 0; + * *(d+6) = (color & 8) ? 0xff : 0; + * *(d+8) = (color & 16) ? 0xff : 0; + * *(d+10) = (color & 32) ? 0xff : 0; + * *(d+12) = (color & 64) ? 0xff : 0; + * *(d+14) = (color & 128) ? 0xff : 0; + */ + +static __inline__ void memclear_8p_col(void *d, size_t h, u_long val1, + u_long val2, int bpr) +{ +#ifdef __mc68000__ + __asm__ __volatile__ ("1: movepl %4,%0@(0)\n\t" + "movepl %5,%0@(8)\n\t" + "addal %6,%0\n\t" + "dbra %1,1b" + : "=a" (d), "=d" (h) + : "0" (d), "1" (h - 1), "d" (val1), "d" (val2), + "r" (bpr)); +#endif /* !m68k */ +} + +/* Sets a 8 plane region from 'd', length 'count' bytes, to the color + * val1..val4. 'd' has to be an even address and count must be divisible + * by 16, because only whole words and all planes are accessed. I.e.: + * + * for(count/16 times) + * *d = *(d+1) = (color & 1) ? 0xff : 0; + * *(d+2) = *(d+3) = (color & 2) ? 0xff : 0; + * *(d+4) = *(d+5) = (color & 4) ? 0xff : 0; + * *(d+6) = *(d+7) = (color & 8) ? 0xff : 0; + * *(d+8) = *(d+9) = (color & 16) ? 0xff : 0; + * *(d+10) = *(d+11) = (color & 32) ? 0xff : 0; + * *(d+12) = *(d+13) = (color & 64) ? 0xff : 0; + * *(d+14) = *(d+15) = (color & 128) ? 0xff : 0; + */ + +static __inline__ void memset_even_8p(void *d, size_t count, u_long val1, + u_long val2, u_long val3, u_long val4) +{ + u_long *dd = d; + + count /= 16; + while (count--) { + *dd++ = val1; + *dd++ = val2; + *dd++ = val3; + *dd++ = val4; + } +} + +/* Copies a 8 plane column from 's', height 'h', to 'd'. */ + +static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr) +{ + u_char *dd = d, *ss = s; + + while (h--) { + dd[0] = ss[0]; + dd[2] = ss[2]; + dd[4] = ss[4]; + dd[6] = ss[6]; + dd[8] = ss[8]; + dd[10] = ss[10]; + dd[12] = ss[12]; + dd[14] = ss[14]; + dd += bpr; + ss += bpr; + } +} + + +/* This expands a 8 bit color into two longs for two movepl (8 plane) + * operations. + */ + +static __inline__ void expand8dl(u_char c, u_long *ret1, u_long *ret2) +{ + u_long rv1, rv2; + +#ifdef __mc68000__ + __asm__ __volatile__ ("lsrb #1,%3\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "lsll #8,%0\n\t" + "lsrb #1,%3\n\t" + "scs %0\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "lsll #8,%1\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "lsll #8,%1\n\t" + "lsrb #1,%3\n\t" + "scs %1\n\t" + "lsll #8,%1\n\t" + "lsrb #1,%3\n\t" + "scs %1" + : "=&d" (rv1), "=&d" (rv2),"=d" (c) + : "2" (c)); +#endif /* !m68k */ + *ret1 = rv1; + *ret2 = rv2; +} + +/* This expands a 8 bit color into four longs for four movel operations + * (8 planes). + */ + +#ifdef __mc68000__ +/* ++andreas: use macro to avoid taking address of return values */ +#define expand8ql(c, rv1, rv2, rv3, rv4) \ + do { \ + u_char tmp = c; \ + __asm__ __volatile__ ("lsrb #1,%5\n\t" \ + "scs %0\n\t" \ + "extw %0\n\t" \ + "swap %0\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %0\n\t" \ + "extw %0\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %1\n\t" \ + "extw %1\n\t" \ + "swap %1\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %1\n\t" \ + "extw %1\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %2\n\t" \ + "extw %2\n\t" \ + "swap %2\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %2\n\t" \ + "extw %2\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %3\n\t" \ + "extw %3\n\t" \ + "swap %3\n\t" \ + "lsrb #1,%5\n\t" \ + "scs %3\n\t" \ + "extw %3" \ + : "=&d" (rv1), "=&d" (rv2), "=&d" (rv3), \ + "=&d" (rv4), "=d" (tmp) \ + : "4" (tmp)); \ + } while (0) +#endif /* !m68k */ + + +/* This duplicates a byte 4 times into a long. */ + +static __inline__ u_long dup4l(u_char c) +{ + ushort tmp; + ulong rv; + +#ifdef __mc68000__ + __asm__ __volatile__ ("moveb %2,%0\n\t" + "lslw #8,%0\n\t" + "moveb %2,%0\n\t" + "movew %0,%1\n\t" + "swap %0\n\t" + "movew %1,%0" + : "=&d" (rv), "=d" (tmp) + : "d" (c)); +#endif /* !m68k */ + return(rv); +} + + +static int open_iplan2p8(struct display *p) +{ + if (p->type != FB_TYPE_INTERLEAVED_PLANES || p->type_aux != 2 || + p->var.bits_per_pixel != 8) + return -EINVAL; + + p->next_line = p->var.xres_virtual; + p->next_plane = 2; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_iplan2p8(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_iplan2p8(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + if (sx == 0 && dx == 0 && width == p->next_line/8) { + /* Special (but often used) case: Moving whole lines can be + * done with memmove() + */ + fast_memmove(p->screen_base + dy * p->next_line * p->fontheight, + p->screen_base + sy * p->next_line * p->fontheight, + p->next_line * height * p->fontheight); + } else { + int rows, cols; + u_char *src; + u_char *dst; + int bytes = p->next_line; + int linesize = bytes * p->fontheight; + u_int colsize = height * p->fontheight; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + if ((sx & 1) == (dx & 1)) { + /* odd->odd or even->even */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + if (sx & 1) { + memmove_8p_col(dst, src, colsize, bytes); + src += 15; + dst += 15; + --width; + } + if (width > 1) { + for(rows = colsize; rows > 0; --rows) { + fast_memmove (dst, src, (width >> 1) * 16); + src += bytes; + dst += bytes; + } + } + + if (width & 1) { + src -= colsize * bytes; + dst -= colsize * bytes; + memmove_8p_col(dst + (width>>1)*16, src + (width>>1)*16, + colsize, bytes); + } + } else { + if (!((sx+width-1) & 1)) { + src = p->screen_base + sy * linesize + ((sx+width-1)>>1)*16; + dst = p->screen_base + dy * linesize + ((dx+width-1)>>1)*16; + memmove_8p_col(dst, src, colsize, bytes); + --width; + } + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + if (width > 1) { + src += colsize * bytes + (sx & 1)*15; + dst += colsize * bytes + (sx & 1)*15; + for(rows = colsize; rows > 0; --rows) { + src -= bytes; + dst -= bytes; + fast_memmove (dst, src, (width>>1)*16); + } + } + if (width & 1) + memmove_8p_col(dst-15, src-15, colsize, bytes); + } + } else { + /* odd->even or even->odd */ + + if (upwards) { + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_8p_col(dst, src, colsize, bytes); + INC_8P(src); + INC_8P(dst); + } + } else { + sx += width-1; + dx += width-1; + src = p->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1); + dst = p->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1); + for(cols = width; cols > 0; --cols) { + memmove_8p_col(dst, src, colsize, bytes); + DEC_8P(src); + DEC_8P(dst); + } + } + } + } +} + +static void clear_iplan2p8(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width) +{ + ulong offset; + u_char *start; + int rows; + int bytes = p->next_line; + int lines = height * p->fontheight; + ulong size; + u_long cval1, cval2, cval3, cval4, pcval1, pcval2; + + expand8ql(attr_bgcol_ec(p,conp), cval1, cval2, cval3, cval4); + + if (sx == 0 && width == bytes/8) { + offset = sy * bytes * p->fontheight; + size = lines * bytes; + memset_even_8p(p->screen_base+offset, size, cval1, cval2, cval3, cval4); + } else { + offset = (sy * bytes * p->fontheight) + (sx>>1)*16 + (sx & 1); + start = p->screen_base + offset; + expand8dl(attr_bgcol_ec(p,conp), &pcval1, &pcval2); + + /* Clears are split if the region starts at an odd column or + * end at an even column. These extra columns are spread + * across the interleaved planes. All in between can be + * cleared by normal mymemclear_small(), because both bytes of + * the single plane words are affected. + */ + + if (sx & 1) { + memclear_8p_col(start, lines, pcval1, pcval2, bytes); + start += 7; + width--; + } + if (width & 1) { + memclear_8p_col(start + (width>>1)*16, lines, pcval1, + pcval2, bytes); + width--; + } + if (width) + for(rows = lines; rows-- ; start += bytes) + memset_even_8p(start, width*8, cval1, cval2, cval3, cval4); + } +} + +static void putc_iplan2p8(struct vc_data *conp, struct display *p, int c, + int yy, int xx) +{ + u_char *dest; + u_char *cdat; + int rows; + int bytes = p->next_line; + ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; + + c &= 0xff; + + dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + (xx & 1); + cdat = p->fontdata + (c * p->fontheight); + + expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2); + expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2); + eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2; + + for(rows = p->fontheight ; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); +#ifdef __mc68000__ + __asm__ __volatile__ ("movepl %1,%0@(0)\n\t" + "movepl %2,%0@(8)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx1) ^ bgx1), + "d" ((fdx & eorx2) ^ bgx2) ); +#endif /* !m68k */ + } +} + +static void putcs_iplan2p8(struct vc_data *conp, struct display *p, + const char *s, int count, int yy, int xx) +{ + u_char *dest, *dest0; + u_char *cdat, c; + int rows; + int bytes; + ulong eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx; + + bytes = p->next_line; + dest0 = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + + (xx & 1); + + expand8dl(attr_fgcol(p,conp), &fgx1, &fgx2); + expand8dl(attr_bgcol(p,conp), &bgx1, &bgx2); + eorx1 = fgx1 ^ bgx1; eorx2 = fgx2 ^ bgx2; + + while (count--) { + + /* I think, unrolling the loops like in the 1 plane case isn't + * practicable here, because the body is much longer for 4 + * planes (mostly the dup4l()). I guess, unrolling this would + * need more than 256 bytes and so exceed the instruction + * cache :-( + */ + + c = *s++; + cdat = p->fontdata + (c * p->fontheight); + + for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) { + fdx = dup4l(*cdat++); +#ifdef __mc68000__ + __asm__ __volatile__ ("movepl %1,%0@(0)\n\t" + "movepl %2,%0@(8)" + : /* no outputs */ + : "a" (dest), "d" ((fdx & eorx1) ^ bgx1), + "d" ((fdx & eorx2) ^ bgx2)); +#endif /* !m68k */ + } + INC_8P(dest0); + } +} + +static void rev_char_iplan2p8(struct display *p, int xx, int yy) +{ + u_char *dest; + int j; + int bytes; + + dest = p->screen_base + yy * p->fontheight * p->next_line + (xx>>1)*16 + + (xx & 1); + j = p->fontheight; + bytes = p->next_line; + + while (j--) { + /* This should really obey the individual character's + * background and foreground colors instead of simply + * inverting. For 8 plane mode, only the lower 4 bits of the + * color are inverted, because only that color registers have + * been set up. + */ + dest[0] = ~dest[0]; + dest[2] = ~dest[2]; + dest[4] = ~dest[4]; + dest[6] = ~dest[6]; + dest += bytes; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_iplan2p8(void) +#endif +{ + return(fbcon_register_driver(&dispsw_iplan2p8, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_iplan2p8); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c --- v2.1.66/linux/drivers/video/fbcon-mfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-mfb.c Mon Nov 10 05:20:37 1997 @@ -0,0 +1,203 @@ +/* + * linux/drivers/video/mfb.c -- Low level frame buffer operations for + * monochrome + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + + /* + * Prototypes + */ + +static int open_mfb(struct display *p); +static void release_mfb(void); +static void bmove_mfb(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_mfb(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); +static void putc_mfb(struct vc_data *conp, struct display *p, int c, int yy, + int xx); +static void putcs_mfb(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx); +static void rev_char_mfb(struct display *p, int xx, int yy); + + + /* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_mfb = { + open_mfb, release_mfb, bmove_mfb, clear_mfb, putc_mfb, putcs_mfb, + rev_char_mfb +}; + + + /* + * Monochrome + */ + +static int open_mfb(struct display *p) +{ + if (p->var.bits_per_pixel != 1) + return -EINVAL; + + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; + p->next_plane = 0; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_mfb(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_mfb(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + u_char *src, *dest; + u_int rows; + + if (sx == 0 && dx == 0 && width == p->next_line) { + src = p->screen_base+sy*p->fontheight*width; + dest = p->screen_base+dy*p->fontheight*width; + mymemmove(dest, src, height*p->fontheight*width); + } else if (dy <= sy) { + src = p->screen_base+sy*p->fontheight*p->next_line+sx; + dest = p->screen_base+dy*p->fontheight*p->next_line+dx; + for (rows = height*p->fontheight; rows--;) { + mymemmove(dest, src, width); + src += p->next_line; + dest += p->next_line; + } + } else { + src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx; + dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx; + for (rows = height*p->fontheight; rows--;) { + mymemmove(dest, src, width); + src -= p->next_line; + dest -= p->next_line; + } + } +} + +static void clear_mfb(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + u_char *dest; + u_int rows; + + dest = p->screen_base+sy*p->fontheight*p->next_line+sx; + + if (sx == 0 && width == p->next_line) { + if (attr_reverse(p,conp)) + mymemset(dest, height*p->fontheight*width); + else + mymemclear(dest, height*p->fontheight*width); + } else + for (rows = height*p->fontheight; rows--; dest += p->next_line) + if (attr_reverse(p,conp)) + mymemset(dest, width); + else + mymemclear_small(dest, width); +} + +static void putc_mfb(struct vc_data *conp, struct display *p, int c, int yy, + int xx) +{ + u_char *dest, *cdat; + u_int rows, bold, revs, underl; + u_char d; + + c &= 0xff; + + dest = p->screen_base+yy*p->fontheight*p->next_line+xx; + cdat = p->fontdata+c*p->fontheight; + bold = attr_bold(p,conp); + revs = attr_reverse(p,conp); + underl = attr_underline(p,conp); + + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + if (underl && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (revs) + d = ~d; + *dest = d; + } +} + +static void putcs_mfb(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx) +{ + u_char *dest, *dest0, *cdat; + u_int rows, bold, revs, underl; + u_char c, d; + + dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx; + bold = attr_bold(p,conp); + revs = attr_reverse(p,conp); + underl = attr_underline(p,conp); + + while (count--) { + c = *s++; + dest = dest0++; + cdat = p->fontdata+c*p->fontheight; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + if (underl && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (revs) + d = ~d; + *dest = d; + } + } +} + +static void rev_char_mfb(struct display *p, int xx, int yy) +{ + u_char *dest; + u_int rows; + + dest = p->screen_base+yy*p->fontheight*p->next_line+xx; + for (rows = p->fontheight; rows--; dest += p->next_line) + *dest = ~*dest; +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_mfb(void) +#endif +{ + return(fbcon_register_driver(&dispsw_mfb, 0)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_mfb); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon-retz3.c linux/drivers/video/fbcon-retz3.c --- v2.1.66/linux/drivers/video/fbcon-retz3.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-retz3.c Tue Sep 16 02:29:50 1997 @@ -0,0 +1,261 @@ +/* + * linux/drivers/video/retz3.c -- Low level frame buffer operations for the + * RetinaZ3 (accelerated) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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 "fbcon.h" + + +/* + * Prototypes + */ + +static int open_retz3(struct display *p); +static void release_retz3(void); +static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +static void clear_retz3(struct vc_data *conp, struct display *p, int + sy, int sx, int height, int width); +static void putc_retz3(struct vc_data *conp, struct display *p, int c, + int ypos, int xpos); +static void putcs_retz3(struct vc_data *conp, struct display *p, const + char *s, int count, int ypos, int xpos); +static void rev_char_retz3(struct display *p, int xpos, int ypos); + + + /* + * Acceleration functions in retz3fb.c + */ + +extern void retz3_bitblt(struct fb_var_screeninfo *scr, + unsigned short srcx, unsigned short srcy, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask); + +#define Z3BLTcopy 0xc0 +#define Z3BLTset 0xf0 + + +/* + * `switch' for the low level operations + */ + +static struct display_switch dispsw_retz3 = { + open_retz3, release_retz3, bmove_retz3, clear_retz3, putc_retz3, + putcs_retz3, rev_char_retz3 +}; + + +/* + * RetinaZ3 (accelerated) + */ + +static int open_retz3(struct display *p) +{ + if (p->type != FB_TYPE_PACKED_PIXELS || + p->var.accel != FB_ACCEL_RETINAZ3) + return -EINVAL; + + p->next_line = p->var.xres_virtual*p->var.bits_per_pixel>>3; + p->next_plane = 0; + MOD_INC_USE_COUNT; + return 0; +} + +static void release_retz3(void) +{ + MOD_DEC_USE_COUNT; +} + +static void bmove_retz3(struct display *p, int sy, int sx, int dy, int dx, + int height, int width) +{ + int fontwidth = p->fontwidth; + + sx *= fontwidth; + dx *= fontwidth; + width *= fontwidth; + + retz3_bitblt(&p->var, + (unsigned short)sx, + (unsigned short)(sy*p->fontheight), + (unsigned short)dx, + (unsigned short)(dy*p->fontheight), + (unsigned short)width, + (unsigned short)(height*p->fontheight), + Z3BLTcopy, + 0xffff); +} + +static void clear_retz3(struct vc_data *conp, struct display *p, int + sy, int sx, int height, int width) +{ + unsigned short col; + int fontwidth = p->fontwidth; + + sx *= fontwidth; + width *= fontwidth; + + col = attr_bgcol_ec(p, conp); + col &= 0xff; + col |= (col << 8); + + retz3_bitblt(&p->var, + (unsigned short)sx, + (unsigned short)(sy*p->fontheight), + (unsigned short)sx, + (unsigned short)(sy*p->fontheight), + (unsigned short)width, + (unsigned short)(height*p->fontheight), + Z3BLTset, + col); +} + +static void putc_retz3(struct vc_data *conp, struct display *p, + int c, int ypos, int xpos) +{ + unsigned char *dest, *cdat; + unsigned long tmp; + unsigned int rows, revs, underl; + unsigned char d; + unsigned char fg, bg; + + c &= 0xff; + + dest = p->screen_base + ypos * p->fontheight * p->next_line + + xpos*p->fontwidth; + cdat = p->fontdata + c * p->fontheight; + + fg = p->fgcol; + bg = p->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; + + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + + if (underl && !rows) + d = 0xff; + if (revs) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((unsigned long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((unsigned long*) dest + 1) = tmp; + } +} + +static void putcs_retz3(struct vc_data *conp, struct display *p, + const char *s, int count, int ypos, int xpos) +{ + unsigned char *dest, *dest0, *cdat; + unsigned long tmp; + unsigned int rows, revs, underl; + unsigned char c, d; + unsigned char fg, bg; + + dest0 = p->screen_base + ypos * p->fontheight * p->next_line + + xpos * p->fontwidth; + + fg = p->fgcol; + bg = p->bgcol; + revs = conp->vc_reverse; + underl = conp->vc_underline; + + while (count--) { + c = *s++; + dest = dest0; + dest0 += 8; + + cdat = p->fontdata + c * p->fontheight; + for (rows = p->fontheight; rows--; dest += p->next_line) { + d = *cdat++; + + if (underl && !rows) + d = 0xff; + if (revs) + d = ~d; + + tmp = ((d & 0x80) ? fg : bg) << 24; + tmp |= ((d & 0x40) ? fg : bg) << 16; + tmp |= ((d & 0x20) ? fg : bg) << 8; + tmp |= ((d & 0x10) ? fg : bg); + *((unsigned long*) dest) = tmp; + tmp = ((d & 0x8) ? fg : bg) << 24; + tmp |= ((d & 0x4) ? fg : bg) << 16; + tmp |= ((d & 0x2) ? fg : bg) << 8; + tmp |= ((d & 0x1) ? fg : bg); + *((unsigned long*) dest + 1) = tmp; + } + } +} + +static void rev_char_retz3(struct display *p, int xpos, int ypos) +{ + unsigned char *dest; + int bytes=p->next_line, rows; + unsigned int bpp, mask; + + bpp = p->var.bits_per_pixel; + + switch (bpp){ + case 8: + mask = 0x0f0f0f0f; + break; + case 16: + mask = 0xffffffff; + break; + case 24: + mask = 0xffffffff; /* ??? */ + break; + default: + printk("illegal depth for rev_char_retz3(), bpp = %i\n", bpp); + return; + } + + dest = p->screen_base + ypos * p->fontheight * bytes + + xpos * p->fontwidth; + + for (rows = p->fontheight ; rows-- ; dest += bytes) { + ((unsigned long *)dest)[0] ^= mask; + ((unsigned long *)dest)[1] ^= mask; + } +} + + +#ifdef MODULE +int init_module(void) +#else +int fbcon_init_retz3(void) +#endif +{ + return(fbcon_register_driver(&dispsw_retz3, 1)); +} + +#ifdef MODULE +void cleanup_module(void) +{ + fbcon_unregister_driver(&dispsw_retz3); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c --- v2.1.66/linux/drivers/video/fbcon.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon.c Mon Nov 24 01:18:56 1997 @@ -0,0 +1,1475 @@ +/* + * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is based on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * + * and on the original Atari console driver (atacon.c): + * + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * + * + * The low level operations for the various display memory organizations are + * now in separate source files. + * + * Currently only the following organizations are supported: + * + * - non-accelerated: + * + * o mfb Monochrome + * o ilbm Interleaved bitplanes à la Amiga + * o afb Bitplanes à la Amiga + * o iplan2p[248] Interleaved bitplanes à la Atari (2, 4 and 8 planes) + * o cfb{8,16} Packed pixels (8 and 16 bpp) + * + * - accelerated: + * + * o cyber CyberVision64 packed pixels (accelerated) + * o retz3 Retina Z3 packed pixels (accelerated) + * o mach64 ATI Mach 64 packed pixels (accelerated) + * + * To do: + * + * - Implement 16 plane mode (iplan2p16) + * - Add support for 24/32 bit packed pixels (cfb{24,32}) + * - Hardware cursor + * + * + * 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. + */ + +#define SUPPORT_SCROLLBACK 0 +#define FLASHING_CURSOR 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KERNELD +#include +#endif + +#include +#include +#include +#ifdef CONFIG_AMIGA +#include +#include +#endif /* CONFIG_AMIGA */ +#ifdef CONFIG_ATARI +#include +#endif +#ifdef __mc68000__ +#include +#include +#endif +#include + +#include "fbcon.h" +#include "font.h" + + +struct display fb_display[MAX_NR_CONSOLES]; + + +/* ++Geert: Sorry, no hardware cursor support at the moment; + use Atari alike software cursor */ + +#if FLASHING_CURSOR +static int cursor_drawn = 0; + +#define CURSOR_DRAW_DELAY (2) + +/* # VBL ints between cursor state changes */ +#define AMIGA_CURSOR_BLINK_RATE (20) +#define ATARI_CURSOR_BLINK_RATE (42) +#define DEFAULT_CURSOR_BLINK_RATE (20) + +static int vbl_cursor_cnt = 0; +static int cursor_on = 0; +static int cursor_blink_rate; + +static __inline__ int CURSOR_UNDRAWN(void) +{ + int cursor_was_drawn; + vbl_cursor_cnt = 0; + cursor_was_drawn = cursor_drawn; + cursor_drawn = 0; + return(cursor_was_drawn); +} +#endif + +/* + * Scroll Method + */ + +#define SCROLL_YWRAP (0) +#define SCROLL_YPAN (1) +#define SCROLL_YMOVE (2) + +#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) + + +/* + * Interface used by the world + */ + +static unsigned long fbcon_startup(unsigned long kmem_start, + const char **display_desc); +static void fbcon_init(struct vc_data *conp); +static int fbcon_deinit(struct vc_data *conp); +static int fbcon_changevar(int con); +static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width); +static int fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos); +static int fbcon_putcs(struct vc_data *conp, const char *s, int count, + int ypos, int xpos); +static int fbcon_cursor(struct vc_data *conp, int mode); +static int fbcon_scroll(struct vc_data *conp, int t, int b, + int dir, int count); +static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width); +static int fbcon_switch(struct vc_data *conp); +static int fbcon_blank(int blank); +static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data); +static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data); +static int fbcon_set_palette(struct vc_data *conp, unsigned char *table); +static int fbcon_scrolldelta(int lines); +int fbcon_register_driver(struct display_switch *dispsw, int is_accel); +int fbcon_unregister_driver(struct display_switch *dispsw); + + +/* + * Internal routines + */ + +static void fbcon_setup(int con, int setcol, int init); +static __inline__ int real_y(struct display *p, int ypos); +#if FLASHING_CURSOR +static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp); +#endif +static __inline__ void updatescrollmode(struct display *p); +#if SUPPORT_SCROLLBACK +static __inline__ void ywrap_up(int unit, struct vc_data *conp, + struct display *p, int count); +static __inline__ void ywrap_down(int unit, struct vc_data *conp, + struct display *p, int count); +#else +static __inline__ void ywrap_up(int unit, struct display *p, int count); +static __inline__ void ywrap_down(int unit, struct display *p, int count); +#endif +static __inline__ void ypan_up(int unit, struct vc_data *conp, + struct display *p, int count); +static __inline__ void ypan_down(int unit, struct vc_data *conp, + struct display *p, int count); +static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, + int height, int width, u_int y_break); +static struct display_switch *probe_list(struct display_switch *dispsw, + struct display *disp); + +#ifdef CONFIG_KERNELD +static void request_driver(struct display *disp, int is_accel); +#endif +static struct display_switch *fbcon_get_driver(struct display *disp); +static int fbcon_show_logo(void); + +#if FLASHING_CURSOR +static void cursor_timer_handler(unsigned long dev_addr); + +static struct timer_list cursor_timer = { + NULL, NULL, 0, 0L, cursor_timer_handler +}; + +static void cursor_timer_handler(unsigned long dev_addr) +{ + fbcon_vbl_handler(0, NULL, NULL); + cursor_timer.expires = jiffies+2; + cursor_timer.data = 0; + cursor_timer.next = cursor_timer.next = NULL; + add_timer(&cursor_timer); +} +#endif + +/* + * Low Level Operations + */ + +static struct display_switch dispsw_dummy; + +#ifdef CONFIG_FBCON_MFB +extern int fbcon_init_mfb(void); +#endif +#ifdef CONFIG_FBCON_ILBM +extern int fbcon_init_ilbm(void); +#endif +#ifdef CONFIG_FBCON_AFB +extern int fbcon_init_afb(void); +#endif +#ifdef CONFIG_FBCON_IPLAN2P2 +extern int fbcon_init_iplan2p2(void); +#endif +#ifdef CONFIG_FBCON_IPLAN2P4 +extern int fbcon_init_iplan2p4(void); +#endif +#ifdef CONFIG_FBCON_IPLAN2P8 +extern int fbcon_init_iplan2p8(void); +#endif +#ifdef CONFIG_FBCON_CFB8 +extern int fbcon_init_cfb8(void); +#endif +#ifdef CONFIG_FBCON_CFB16 +extern int fbcon_init_cfb16(void); +#endif +#ifdef CONFIG_FBCON_CFB24 +extern int fbcon_init_cfb24(void); +#endif +#ifdef CONFIG_FBCON_CFB32 +extern int fbcon_init_cfb32(void); +#endif +#ifdef CONFIG_FBCON_CYBER +extern int fbcon_init_cyber(void); +#endif +#ifdef CONFIG_FBCON_RETINAZ3 +extern int fbcon_init_retz3(void); +#endif +#ifdef CONFIG_FBCON_MACH64 +extern int fbcon_init_mach64(void); +#endif + +extern int num_registered_fb; + +__initfunc(static unsigned long fbcon_startup(unsigned long kmem_start, + const char **display_desc)) +{ + int irqres = 1; + + /* Probe all frame buffer devices */ + kmem_start = probe_framebuffers(kmem_start); + + if (!num_registered_fb) + return kmem_start; + + /* Initialize all built-in low level drivers */ +#ifdef CONFIG_FBCON_RETINAZ3 + fbcon_init_retz3(); +#endif +#ifdef CONFIG_FBCON_MFB + fbcon_init_mfb(); +#endif +#ifdef CONFIG_FBCON_IPLAN2P2 + fbcon_init_iplan2p2(); +#endif +#ifdef CONFIG_FBCON_IPLAN2P4 + fbcon_init_iplan2p4(); +#endif +#ifdef CONFIG_FBCON_IPLAN2P8 + fbcon_init_iplan2p8(); +#endif +#ifdef CONFIG_FBCON_ILBM + fbcon_init_ilbm(); +#endif +#ifdef CONFIG_FBCON_AFB + fbcon_init_afb(); +#endif +#ifdef CONFIG_FBCON_CFB8 + fbcon_init_cfb8(); +#endif +#ifdef CONFIG_FBCON_CFB16 + fbcon_init_cfb16(); +#endif +#ifdef CONFIG_FBCON_CFB24 + fbcon_init_cfb24(); +#endif +#ifdef CONFIG_FBCON_CFB32 + fbcon_init_cfb32(); +#endif +#ifdef CONFIG_FBCON_CYBER + fbcon_init_cyber(); +#endif +#ifdef CONFIG_FBCON_MACH64 + fbcon_init_mach64(); +#endif + + *display_desc = "frame buffer device"; + +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA) { + cursor_blink_rate = AMIGA_CURSOR_BLINK_RATE; + irqres = request_irq(IRQ_AMIGA_VERTB, fbcon_vbl_handler, 0, + "console/cursor", fbcon_vbl_handler); + } +#endif /* CONFIG_AMIGA */ +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) { + cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; + irqres = request_irq(IRQ_AUTO_4, fbcon_vbl_handler, IRQ_TYPE_PRIO, + "console/cursor", fbcon_vbl_handler); + } +#endif /* CONFIG_ATARI */ + if (irqres) { + cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE; + cursor_timer.expires = jiffies+2; + cursor_timer.data = 0; + cursor_timer.next = cursor_timer.prev = NULL; + add_timer(&cursor_timer); + } + + if (!console_show_logo) + console_show_logo = fbcon_show_logo; + + return kmem_start; +} + + +static void fbcon_init(struct vc_data *conp) +{ + int unit = conp->vc_num; + struct fb_info *info; + + /* on which frame buffer will we open this console? */ + info = registered_fb[(int)con2fb_map[unit]]; + + info->changevar = &fbcon_changevar; + fb_display[unit] = *(info->disp); /* copy from default */ + fb_display[unit].conp = conp; + fb_display[unit].fb_info = info; + fbcon_setup(unit, 1, 1); +} + + +static int fbcon_deinit(struct vc_data *conp) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + + if (p->dispsw) + p->dispsw->release(); + p->dispsw = 0; + p->conp = 0; + return(0); +} + + +static int fbcon_changevar(int con) +{ + if (fb_display[con].conp) + fbcon_setup(con, 1, 0); + return(0); +} + + +static __inline__ void updatescrollmode(struct display *p) +{ + if (divides(p->ywrapstep, p->fontheight) && + divides(p->fontheight, p->var.yres_virtual)) + p->scrollmode = SCROLL_YWRAP; + else if (divides(p->ypanstep, p->fontheight) && + p->var.yres_virtual >= p->var.yres+p->fontheight) + p->scrollmode = SCROLL_YPAN; + else + p->scrollmode = SCROLL_YMOVE; +} + + +static void fbcon_setup(int con, int setcol, int init) +{ + struct display *p = &fb_display[con]; + struct vc_data *conp = p->conp; + int nr_rows, nr_cols; + struct display_switch *old_dispsw, *new_dispsw; + + p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + + if (!p->fb_info->fontname[0] || + !findsoftfont(p->fb_info->fontname, &p->fontwidth, &p->fontheight, + &p->fontdata) || p->fontwidth != 8) + getdefaultfont(p->var.xres, p->var.yres, NULL, &p->fontwidth, + &p->fontheight, &p->fontdata); + if (p->fontwidth != 8) { + /* ++Geert: changed from panic() to `correct and continue' */ + printk(KERN_ERR "fbcon_setup: No support for fontwidth != 8"); + p->fontwidth = 8; + } + updatescrollmode(p); + + nr_cols = p->var.xres/p->fontwidth; + nr_rows = p->var.yres/p->fontheight; + /* + * ++guenther: console.c:vc_allocate() relies on initializing + * vc_{cols,rows}, but we must not set those if we are only + * resizing the console. + */ + if (init) { + conp->vc_cols = nr_cols; + conp->vc_rows = nr_rows; + } + p->vrows = p->var.yres_virtual/p->fontheight; + conp->vc_can_do_color = p->var.bits_per_pixel != 1; + + new_dispsw = fbcon_get_driver(p); + if (!new_dispsw) { + printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not " + "supported\n", p->type, p->type_aux, p->var.bits_per_pixel); + dispsw_dummy.open(p); + new_dispsw = &dispsw_dummy; + } + /* Be careful when changing dispsw, it might be the current console. */ + old_dispsw = p->dispsw; + p->dispsw = new_dispsw; + if (old_dispsw) + old_dispsw->release(); + + if (setcol) { + p->fgcol = p->var.bits_per_pixel > 2 ? 7 : (1<var.bits_per_pixel)-1; + p->bgcol = 0; + } + + if (!init) + vc_resize_con(nr_rows, nr_cols, con); +} + + +/* ====================================================================== */ + +/* fbcon_XXX routines - interface used by the world + * + * This system is now divided into two levels because of complications + * caused by hardware scrolling. Top level functions: + * + * fbcon_bmove(), fbcon_clear(), fbcon_putc() + * + * handles y values in range [0, scr_height-1] that correspond to real + * screen positions. y_wrap shift means that first line of bitmap may be + * anywhere on this display. These functions convert lineoffsets to + * bitmap offsets and deal with the wrap-around case by splitting blits. + * + * fbcon_bmove_physical_8() -- These functions fast implementations + * fbcon_clear_physical_8() -- of original fbcon_XXX fns. + * fbcon_putc_physical_8() -- (fontwidth != 8) may be added later + * + * WARNING: + * + * At the moment fbcon_putc() cannot blit across vertical wrap boundary + * Implies should only really hardware scroll in rows. Only reason for + * restriction is simplicity & efficiency at the moment. + */ + +static __inline__ int real_y(struct display *p, int ypos) +{ + int rows = p->vrows; + + ypos += p->yscroll; + return(ypos < rows ? ypos : ypos-rows); +} + + +static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + u_int y_break; + + if (!p->can_soft_blank && console_blanked) + return(0); + + if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) && + (sx <= p->cursor_x) && (p->cursor_x < sx+width)) + CURSOR_UNDRAWN(); + + /* Split blits that cross physical y_wrap boundary */ + + y_break = p->vrows-p->yscroll; + if (sy < y_break && sy+height-1 >= y_break) { + u_int b = y_break-sy; + p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width); + p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width); + } else + p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width); + + return(0); +} + + +static int fbcon_putc(struct vc_data *conp, int c, int ypos, int xpos) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + + if (!p->can_soft_blank && console_blanked) + return 0; + + if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) + CURSOR_UNDRAWN(); + + p->dispsw->putc(conp, p, c, real_y(p, ypos), xpos); + + return 0; +} + + +static int fbcon_putcs(struct vc_data *conp, const char *s, int count, + int ypos, int xpos) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + + if (!p->can_soft_blank && console_blanked) + return 0; + + if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) && + (p->cursor_x < (xpos + count))) + CURSOR_UNDRAWN(); + p->dispsw->putcs(conp, p, s, count, real_y(p, ypos), xpos); + + return(0); +} + + +static int fbcon_cursor(struct vc_data *conp, int mode) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + + /* Avoid flickering if there's no real change. */ + if (p->cursor_x == conp->vc_x && p->cursor_y == conp->vc_y && + (mode == CM_ERASE) == !cursor_on) + return 0; + if (CURSOR_UNDRAWN ()) + p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); + p->cursor_x = conp->vc_x; + p->cursor_y = conp->vc_y; + + switch (mode) { + case CM_ERASE: + cursor_on = 0; + break; + + case CM_MOVE: + case CM_DRAW: + vbl_cursor_cnt = CURSOR_DRAW_DELAY; + cursor_on = 1; + break; + } + + return(0); +} + + +#if FLASHING_CURSOR +static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp) +{ + struct display *p; + + if (!cursor_on) + return; + + if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { + /* Here no check is possible for console changing. The console + * switching code should set vbl_cursor_cnt to an appropriate value. + */ + p = &fb_display[fg_console]; + p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); + cursor_drawn ^= 1; + vbl_cursor_cnt = cursor_blink_rate; + } +} +#endif + +#if SUPPORT_SCROLLBACK +static int scrollback_max = 0; +static int scrollback_current = 0; +#endif + +#if SUPPORT_SCROLLBACK +static __inline__ void ywrap_up(int unit, struct vc_data *conp, + struct display *p, int count) +#else +static __inline__ void ywrap_up(int unit, struct display *p, int count) +#endif +{ + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode |= FB_VMODE_YWRAP; + p->fb_info->updatevar(unit); +#if SUPPORT_SCROLLBACK + scrollback_max += count; + if (scrollback_max > p->vrows-conp->vc_rows) + scrollback_max = p->vrows-conp->vc_rows; + scrollback_current = 0; +#endif +} + + +#if SUPPORT_SCROLLBACK +static __inline__ void ywrap_down(int unit, struct vc_data *conp, + struct display *p, int count) +#else +static __inline__ void ywrap_down(int unit, struct display *p, int count) +#endif +{ + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode |= FB_VMODE_YWRAP; + p->fb_info->updatevar(unit); +#if SUPPORT_SCROLLBACK + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +#endif +} + + +static __inline__ void ypan_up(int unit, struct vc_data *conp, + struct display *p, int count) +{ + p->yscroll += count; + if (p->yscroll+conp->vc_rows > p->vrows) { + p->dispsw->bmove(p, p->yscroll, 0, 0, 0, conp->vc_rows-count, + conp->vc_cols); + p->yscroll = 0; + } + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode &= ~FB_VMODE_YWRAP; + p->fb_info->updatevar(unit); +} + + +static __inline__ void ypan_down(int unit, struct vc_data *conp, + struct display *p, int count) +{ + p->yscroll -= count; + if (p->yscroll < 0) { + p->yscroll = p->vrows-conp->vc_rows; + p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, conp->vc_rows-count, + conp->vc_cols); + } + p->var.xoffset = 0; + p->var.yoffset = p->yscroll*p->fontheight; + p->var.vmode &= ~FB_VMODE_YWRAP; + p->fb_info->updatevar(unit); +} + + +static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + + if (!p->can_soft_blank && console_blanked) + return(0); + + fbcon_cursor(conp, CM_ERASE); + + /* + * ++Geert: Only use ywrap/ypan if the console is in text mode + */ + + switch (dir) { + case SM_UP: + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + if (vt_cons[unit]->vc_mode == KD_TEXT) + switch (p->scrollmode) { + case SCROLL_YWRAP: + if (b-t-count > 3*conp->vc_rows>>2) { + if (t > 0) + fbcon_bmove(conp, 0, 0, count, 0, t, + conp->vc_cols); +#if SUPPORT_SCROLLBACK + ywrap_up(unit, conp, p, count); +#else + ywrap_up(unit, p, count); +#endif + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b-count, 0, b, 0, + conp->vc_rows-b, conp->vc_cols); + } else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case SCROLL_YPAN: + if (b-t-count > 3*conp->vc_rows>>2) { + if (t > 0) + fbcon_bmove(conp, 0, 0, count, 0, t, + conp->vc_cols); + ypan_up(unit, conp, p, count); + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b-count, 0, b, 0, + conp->vc_rows-b, conp->vc_cols); + } else + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case SCROLL_YMOVE: + p->dispsw->bmove(p, t+count, 0, t, 0, b-t-count, + conp->vc_cols); + p->dispsw->clear(conp, p, b-count, 0, count, + conp->vc_cols); + break; + } + else { + fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); + fbcon_clear(conp, b-count, 0, count, conp->vc_cols); + } + break; + + case SM_DOWN: + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + if (vt_cons[unit]->vc_mode == KD_TEXT) + switch (p->scrollmode) { + case SCROLL_YWRAP: + if (b-t-count > 3*conp->vc_rows>>2) { + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b, 0, b-count, 0, + conp->vc_rows-b, conp->vc_cols); +#if SUPPORT_SCROLLBACK + ywrap_down(unit, conp, p, count); +#else + ywrap_down(unit, p, count); +#endif + if (t > 0) + fbcon_bmove(conp, count, 0, 0, 0, t, + conp->vc_cols); + } else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + break; + + case SCROLL_YPAN: + if (b-t-count > 3*conp->vc_rows>>2) { + if (conp->vc_rows-b > 0) + fbcon_bmove(conp, b, 0, b-count, 0, + conp->vc_rows-b, conp->vc_cols); + ypan_down(unit, conp, p, count); + if (t > 0) + fbcon_bmove(conp, count, 0, 0, 0, t, + conp->vc_cols); + } else + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + break; + + case SCROLL_YMOVE: + p->dispsw->bmove(p, t, 0, t+count, 0, b-t-count, + conp->vc_cols); + p->dispsw->clear(conp, p, t, 0, count, conp->vc_cols); + break; + } + else { + /* + * Fixed bmove() should end Arno's frustration with copying? + * Confucius says: + * Man who copies in wrong direction, end up with trashed + * data + */ + fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); + fbcon_clear(conp, t, 0, count, conp->vc_cols); + } + break; + + case SM_LEFT: + fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count); + fbcon_clear(conp, 0, b-count, conp->vc_rows, count); + break; + + case SM_RIGHT: + fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count); + fbcon_clear(conp, 0, t, conp->vc_rows, count); + break; + } + + return(0); +} + + +static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + + if (!p->can_soft_blank && console_blanked) + return(0); + + if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && + (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || + ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && + (dx <= p->cursor_x) && (p->cursor_x < dx+width))) + fbcon_cursor(conp, CM_ERASE); + + /* Split blits that cross physical y_wrap case. + * Pathological case involves 4 blits, better to use recursive + * code rather than unrolled case + * + * Recursive invocations don't need to erase the cursor over and + * over again, so we use fbcon_bmove_rec() + */ + fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll); + + return(0); +} + + +static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, + int height, int width, u_int y_break) +{ + u_int b; + + if (sy < y_break && sy+height > y_break) { + b = y_break-sy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + } else { + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + } + return; + } + + if (dy < y_break && dy+height > y_break) { + b = y_break-dy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + } else { + fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); + fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); + } + return; + } + p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width); +} + + +static int fbcon_switch(struct vc_data *conp) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + struct fb_info *info = p->fb_info; + + if (info && info->switch_con) + (*info->switch_con)(conp->vc_num); +#if SUPPORT_SCROLLBACK + scrollback_max = 0; + scrollback_current = 0; +#endif + return(0); +} + + +static int fbcon_blank(int blank) +{ + struct display *p = &fb_display[fg_console]; + + fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW); + + if (!p->can_soft_blank) { + if (blank) { + if (p->visual == FB_VISUAL_MONO01) + mymemset(p->screen_base, + p->var.xres_virtual*p->var.yres_virtual* + p->var.bits_per_pixel>>3); + else + mymemclear(p->screen_base, + p->var.xres_virtual*p->var.yres_virtual* + p->var.bits_per_pixel>>3); + return(0); + } else { + /* Tell console.c that it has to restore the screen itself */ + return(1); + } + } + (*p->fb_info->blank)(blank); + return(0); +} + + +static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + int i, j, size, alloc; + + size = (p->fontwidth+7)/8 * p->fontheight * 256; + alloc = (*w+7)/8 * *h * 256; + *w = p->fontwidth; + *h = p->fontheight; + + if (alloc < size) + /* allocation length not sufficient */ + return( -ENAMETOOLONG ); + + for (i = 0; i < 256; i++) + for (j = 0; j < p->fontheight; j++) + data[i*32+j] = p->fontdata[i*p->fontheight+j]; + return( 0 ); +} + + +#define REFCOUNT(fd) (((int *)(fd))[-1]) + +static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + int i, j, size, userspace = 1, resize; + char *old_data = NULL, *new_data; + + if (w < 0) + w = p->fontwidth; + if (h < 0) + h = p->fontheight; + + if (w == 0) { + /* engage predefined font, name in 'data' */ + char name[MAX_FONT_NAME+1]; + + if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME ))) + return i; + copy_from_user( name, data, MAX_FONT_NAME ); + name[sizeof(name)-1] = 0; + + if (!findsoftfont( name, &w, &h, (u_char **)&data )) + return( -ENOENT ); + userspace = 0; + } else if (w == 1) { + /* copy font from some other console in 'h'*/ + struct display *op; + + if (h < 0 || !vc_cons_allocated( h )) + return( -ENOTTY ); + if (h == unit) + return( 0 ); /* nothing to do */ + op = &fb_display[h]; + if (op->fontdata == p->fontdata) + return( 0 ); /* already the same font... */ + + resize = (op->fontwidth != p->fontwidth) || + (op->fontheight != p->fontheight); + if (p->userfont) + old_data = p->fontdata; + p->fontdata = op->fontdata; + w = p->fontwidth = op->fontwidth; + h = p->fontheight = op->fontheight; + if ((p->userfont = op->userfont)) + REFCOUNT(p->fontdata)++; /* increment usage counter */ + goto activate; + } + + if (w != 8) + /* Currently only fontwidth == 8 supported */ + return( -ENXIO ); + + resize = (w != p->fontwidth) || (h != p->fontheight); + size = (w+7)/8 * h * 256; + + if (p->userfont) + old_data = p->fontdata; + + if (userspace) { + if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER ))) + return( -ENOMEM ); + new_data += sizeof(int); + REFCOUNT(new_data) = 1; /* usage counter */ + + for (i = 0; i < 256; i++) + for (j = 0; j < h; j++) + new_data[i*h+j] = data[i*32+j]; + + p->fontdata = new_data; + p->userfont = 1; + } else { + p->fontdata = data; + p->userfont = 0; + } + p->fontwidth = w; + p->fontheight = h; + +activate: + if (resize) { + /* reset wrap/pan */ + p->var.xoffset = p->var.yoffset = p->yscroll = 0; + /* Adjust the virtual screen-size to fontheight*rows */ + p->var.yres_virtual = (p->var.yres/h)*h; + p->vrows = p->var.yres_virtual/h; + updatescrollmode(p); + vc_resize_con( p->var.yres/h, p->var.xres/w, unit ); + } else if (unit == fg_console) + update_screen( unit ); + + if (old_data && (--REFCOUNT(old_data) == 0)) + kfree( old_data - sizeof(int) ); + + return( 0 ); +} + +static unsigned short palette_red[16]; +static unsigned short palette_green[16]; +static unsigned short palette_blue[16]; + +static struct fb_cmap palette_cmap = { + 0, 16, palette_red, palette_green, palette_blue, NULL +}; + +static int fbcon_set_palette(struct vc_data *conp, unsigned char *table) +{ + int unit = conp->vc_num; + struct display *p = &fb_display[unit]; + int i, j, k; + u_char val; + + if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked)) + return(-EINVAL); + for (i = j = 0; i < 16; i++) { + k = table[i]; + val = conp->vc_palette[j++]; + palette_red[k] = (val<<8)|val; + val = conp->vc_palette[j++]; + palette_green[k] = (val<<8)|val; + val = conp->vc_palette[j++]; + palette_blue[k] = (val<<8)|val; + } + palette_cmap.len = 1<var.bits_per_pixel; + if (palette_cmap.len > 16) + palette_cmap.len = 16; + return(p->fb_info->setcmap(&palette_cmap, unit)); +} + +static int fbcon_scrolldelta(int lines) +{ +#if SUPPORT_SCROLLBACK + int unit = fg_console; /* xxx */ + struct display *p = &fb_display[unit]; + int offset; + + if (!p->can_soft_blank && console_blanked || + vt_cons[unit]->vc_mode != KD_TEXT || !lines || + p->scrollmode != SCROLL_YWRAP) + return 0; + + fbcon_cursor(conp, CM_ERASE); + + scrollback_current -= lines; + if (scrollback_current < 0) + scrollback_current = 0; + else if (scrollback_current > scrollback_max) + scrollback_current = scrollback_max; + + offset = p->yscroll-scrollback_current; + if (offset < 0) + offset += p->vrows; + else if (offset > p->vrows) + offset -= p->vrows; + p->var.vmode |= FB_VMODE_YWRAP; + p->var.xoffset = 0; + p->var.yoffset = offset*p->fontheight; + p->fb_info->updatevar(unit); +#else + return -ENOSYS; +#endif +} + + +#define LOGO_H 80 +#define LOGO_W 80 +#define LOGO_LINE (LOGO_W/8) + +__initfunc(static int fbcon_show_logo( void )) +{ + struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ + int depth = p->var.bits_per_pixel; + int line = p->next_line; + unsigned char *fb = p->screen_base; + unsigned char *logo; + unsigned char *dst, *src; + int i, j, n, x1, y1; + int logo_depth, done = 0; + + /* Set colors if visual is PSEUDOCOLOR and we have enough colors */ + if (p->visual == FB_VISUAL_PSEUDOCOLOR && depth >= 4) { + int first_col = depth >= 8 ? 32 : depth > 4 ? 16 : 0; + int num_cols = depth >= 8 ? LINUX_LOGO_COLORS : 16; + unsigned char *red, *green, *blue; + int old_cmap_len; + + if (depth >= 8) { + red = linux_logo_red; + green = linux_logo_green; + blue = linux_logo_blue; + } + else { + red = linux_logo16_red; + green = linux_logo16_green; + blue = linux_logo16_blue; + } + + /* dirty trick to avoid setcmap calling kmalloc which isn't + * initialized yet... */ + old_cmap_len = fb_display[fg_console].cmap.len; + fb_display[fg_console].cmap.len = 1 << depth; + + for( i = 0; i < num_cols; i += n ) { + n = num_cols - i; + if (n > 16) + /* palette_cmap provides space for only 16 colors at once */ + n = 16; + palette_cmap.start = first_col + i; + palette_cmap.len = n; + for( j = 0; j < n; ++j ) { + palette_cmap.red[j] = (red[i+j] << 8) | red[i+j]; + palette_cmap.green[j] = (green[i+j] << 8) | green[i+j]; + palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j]; + } + p->fb_info->setcmap( &palette_cmap, fg_console ); + } + fb_display[fg_console].cmap.len = old_cmap_len; + } + + if (depth >= 8) { + logo = linux_logo; + logo_depth = 8; + } + else if (depth >= 4) { + logo = linux_logo16; + logo_depth = 4; + } + else { + logo = linux_logo_bw; + logo_depth = 1; + } + +#if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CYBER) || \ + defined(CONFIG_FBCON_RETINAZ3) + if ((depth % 8 == 0) && (p->visual == FB_VISUAL_TRUECOLOR || + p->visual == FB_VISUAL_DIRECTCOLOR)) { + /* Modes without color mapping, needs special data transformation... */ + unsigned long val; /* max. depth 32! */ + int bdepth = depth/8; + unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; + unsigned char redmask, greenmask, bluemask; + int redshift, greenshift, blueshift; + + /* Bug: Doesn't obey msb_right ... (who needs that?) */ + redmask = mask[p->var.red.length < 8 ? p->var.red.length : 8]; + greenmask = mask[p->var.green.length < 8 ? p->var.green.length : 8]; + bluemask = mask[p->var.blue.length < 8 ? p->var.blue.length : 8]; + redshift = p->var.red.offset - (8-p->var.red.length); + greenshift = p->var.green.offset - (8-p->var.green.length); + blueshift = p->var.blue.offset - (8-p->var.blue.length); + + src = logo; + for( y1 = 0; y1 < LOGO_H; y1++ ) { + dst = fb + y1*line; + for( x1 = 0; x1 < LOGO_W; x1++, src++ ) { + val = ((linux_logo_red[*src] & redmask) << redshift) | + ((linux_logo_green[*src] & greenmask) << greenshift) | + ((linux_logo_blue[*src] & bluemask) << blueshift); + for( i = 0; i < bdepth; ++i ) + *dst++ = val >> (i*8); + } + } + + done = 1; + } +#endif +#if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CYBER) || \ + defined(CONFIG_FBCON_RETINAZ3) + if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) { + /* depth 8 or more, packed, with color registers */ + + src = logo; + for( y1 = 0; y1 < LOGO_H; y1++ ) { + dst = fb + y1*line; + for( x1 = 0; x1 < LOGO_W; x1++ ) { + *dst++ = *src++; + } + } + + done = 1; + } +#endif +#if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \ + defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P4) || \ + defined(CONFIG_FBCON_IPLAN2P8) + if (depth >= 2 && (p->type == FB_TYPE_PLANES || + p->type == FB_TYPE_INTERLEAVED_PLANES)) { + /* planes (normal or interleaved), with color registers */ + int bit; + unsigned char val, mask; + int plane = p->next_plane; + + /* for support of Atari interleaved planes */ +#define MAP_X(x) (plane > line ? x : (x & ~1)*depth + (x & 1)) + /* extract a bit from the source image */ +#define BIT(p,pix,bit) (p[pix*logo_depth/8] & \ + (1 << ((8-((pix*logo_depth)&7)-logo_depth) + bit))) + + src = logo; + for( y1 = 0; y1 < LOGO_H; y1++ ) { + for( x1 = 0; x1 < LOGO_LINE; x1++, src += logo_depth ) { + dst = fb + y1*line + MAP_X(x1); + for( bit = 0; bit < logo_depth; bit++ ) { + val = 0; + for( mask = 0x80, i = 0; i < 8; mask >>= 1, i++ ) { + if (BIT( src, i, bit )) + val |= mask; + } + *dst = val; + dst += plane; + } + } + } + + /* fill remaining planes + * special case for logo_depth == 4: we used color registers 16..31, + * so fill plane 4 with 1 bits instead of 0 */ + if (depth > logo_depth) { + for( y1 = 0; y1 < LOGO_H; y1++ ) { + for( x1 = 0; x1 < LOGO_LINE; x1++ ) { + dst = fb + y1*line + MAP_X(x1) + logo_depth*plane; + for( i = logo_depth; i < depth; i++, dst += plane ) + *dst = (i == logo_depth && logo_depth == 4) + ? 0xff : 0x00; + } + } + } + + done = 1; + } +#endif +#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_AFB) || \ + defined(CONFIG_FBCON_ILBM) + if (depth == 1) { + /* monochrome */ + unsigned char inverse = p->inverse ? 0x00 : 0xff; + + /* can't use simply memcpy because need to apply inverse */ + for( y1 = 0; y1 < LOGO_H; y1++ ) { + src = logo + y1*LOGO_LINE; + dst = fb + y1*line; + for( x1 = 0; x1 < LOGO_LINE; ++x1 ) + *dst++ = *src++ ^ inverse; + } + + done = 1; + } +#endif + /* Modes not yet supported: packed pixels with depth != 8 (does such a + * thing exist in reality?) */ + + return( done ? LOGO_H/p->fontheight + 1 : 0 ); +} + + + +/* + * The console `switch' structure for the frame buffer based console + */ + +struct consw fb_con = { + fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc, + fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch, + fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette, + fbcon_scrolldelta +}; + + +/* + * Driver registration + */ + +static struct display_switch *drivers = NULL, *accel_drivers = NULL; + +int fbcon_register_driver(struct display_switch *dispsw, int is_accel) +{ + struct display_switch **list; + + list = is_accel ? &accel_drivers : &drivers; + dispsw->next = *list; + *list = dispsw; + return 0; +} + +int fbcon_unregister_driver(struct display_switch *dispsw) +{ + struct display_switch **list; + + for (list = &accel_drivers; *list; list = &(*list)->next) + if (*list == dispsw) { + *list = dispsw->next; + dispsw->next = NULL; + return 0; + } + for (list = &drivers; *list; list = &(*list)->next) + if (*list == dispsw) { + *list = dispsw->next; + dispsw->next = NULL; + return 0; + } + return -EINVAL; +} + + +static struct display_switch *probe_list(struct display_switch *dispsw, + struct display *disp) +{ + while (dispsw) { + if (!dispsw->open(disp)) + return(dispsw); + dispsw = dispsw->next; + } + return(NULL); +} + + +#ifdef CONFIG_KERNELD +static void request_driver(struct display *disp, int is_accel) +{ + char modname[30]; + int len; + const char *type; + + if (disp->var.bits_per_pixel == 1) + type = "mfb"; + else + switch (disp->type) { + case FB_TYPE_INTERLEAVED_PLANES: + if (disp->type_aux == 2) + type = "iplan2p%d"; + else + type = "ilbm"; + break; + case FB_TYPE_PLANES: + type = "afb"; + break; + case FB_TYPE_PACKED_PIXELS: + type = "cfb%d"; + break; + default: + return; + } + len = sprintf(modname, "fbcon-"); + len += sprintf(modname+len, type, disp->var.bits_per_pixel); + if (is_accel) + len += sprintf(modname+len, "-%d", disp->var.accel); + request_module(modname); +} +#endif /* CONFIG_KERNELD */ + + +static struct display_switch *fbcon_get_driver(struct display *disp) +{ + struct display_switch *dispsw; + + if (disp->var.accel != FB_ACCEL_NONE) { + /* First try an accelerated driver */ + dispsw = probe_list(accel_drivers, disp); +#ifdef CONFIG_KERNELD + if (!dispsw) { + request_driver(disp, 1); + dispsw = probe_list(accel_drivers, disp); + } +#endif + if (dispsw) + return(dispsw); + } + + /* Then try an unaccelerated driver */ + dispsw = probe_list(drivers, disp); +#ifdef CONFIG_KERNELD + if (!dispsw) { + request_driver(disp, 0); + dispsw = probe_list(drivers, disp); + } +#endif + return(dispsw); +} + + +/* + * Dummy Low Level Operations + */ + +static int open_dummy(struct display *p) +{ + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; + p->next_plane = 0; + p->var.bits_per_pixel = 1; + return 0; +} + +static void misc_dummy(void) {} + +static struct display_switch dispsw_dummy = { + open_dummy, + /* release_dummy */ + misc_dummy, + /* bmove_dummy */ + (void (*)(struct display *, int, int, int, int, int, int))misc_dummy, + /* clear_dummy */ + (void (*)(struct vc_data *, struct display *, int, int, int, int))misc_dummy, + /* putc_dummy */ + (void (*)(struct vc_data *, struct display *, int, int, int))misc_dummy, + /* putcs_dummy */ + (void (*)(struct vc_data *, struct display *, const char *, int, int, int))misc_dummy, + /* rev_char_dummy */ + (void (*)(struct display *, int, int))misc_dummy, +}; + + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(fb_display); +EXPORT_SYMBOL(fbcon_register_driver); +EXPORT_SYMBOL(fbcon_unregister_driver); diff -u --recursive --new-file v2.1.66/linux/drivers/video/fbcon.h linux/drivers/video/fbcon.h --- v2.1.66/linux/drivers/video/fbcon.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon.h Fri Oct 31 07:59:41 1997 @@ -0,0 +1,337 @@ +/* + * linux/drivers/video/fbcon.h -- Low level frame buffer based console driver + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * 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 + + + /* + * `switch' for the Low Level Operations + */ + +struct display_switch { + int (*open)(struct display *p); + void (*release)(void); + void (*bmove)(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); + void (*clear)(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width); + void (*putc)(struct vc_data *conp, struct display *p, int c, int yy, + int xx); + void (*putcs)(struct vc_data *conp, struct display *p, const char *s, + int count, int yy, int xx); + void (*rev_char)(struct display *p, int xx, int yy); + struct display_switch *next; +}; + + + /* + * Driver registration + */ + +extern int fbcon_register_driver(struct display_switch *dispsw, int is_accel); +int fbcon_unregister_driver(struct display_switch *dispsw); + + + /* + * Attribute Decoding + */ + +/* Color */ +#define attr_fgcol(p,conp) \ + (((conp)->vc_attr >> ((p)->inverse ? 4 : 0)) & 0x0f) +#define attr_bgcol(p,conp) \ + (((conp)->vc_attr >> ((p)->inverse ? 0 : 4)) & 0x0f) +#define attr_bgcol_ec(p,conp) \ + (((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f) + +/* Monochrome */ +#define attr_bold(p,conp) \ + (((conp)->vc_attr & 3) == 2) +#define attr_reverse(p,conp) \ + (((conp)->vc_attr & 8) ^ ((p)->inverse ? 8 : 0)) +#define attr_underline(p,conp) \ + (((conp)->vc_attr) & 4) + + +/* ================================================================= */ +/* Utility Assembler Functions */ +/* ================================================================= */ + + +#ifdef __mc68000__ + +/* ====================================================================== */ + +/* Those of a delicate disposition might like to skip the next couple of + * pages. + * + * These functions are drop in replacements for memmove and + * memset(_, 0, _). However their five instances add at least a kilobyte + * to the object file. You have been warned. + * + * Not a great fan of assembler for the sake of it, but I think + * that these routines are at least 10 times faster than their C + * equivalents for large blits, and that's important to the lowest level of + * a graphics driver. Question is whether some scheme with the blitter + * would be faster. I suspect not for simple text system - not much + * asynchrony. + * + * Code is very simple, just gruesome expansion. Basic strategy is to + * increase data moved/cleared at each step to 16 bytes to reduce + * instruction per data move overhead. movem might be faster still + * For more than 15 bytes, we try to align the write direction on a + * longword boundary to get maximum speed. This is even more gruesome. + * Unaligned read/write used requires 68020+ - think this is a problem? + * + * Sorry! + */ + + +/* ++roman: I've optimized Robert's original versions in some minor + * aspects, e.g. moveq instead of movel, let gcc choose the registers, + * use movem in some places... + * For other modes than 1 plane, lots of more such assembler functions + * were needed (e.g. the ones using movep or expanding color values). + */ + +/* ++andreas: more optimizations: + subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc + addal is faster than addaw + movep is rather expensive compared to ordinary move's + some functions rewritten in C for clarity, no speed loss */ + +static __inline__ void *mymemclear_small(void *s, size_t count) +{ + if (!count) + return(0); + + __asm__ __volatile__( + "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" + "1: subql #1,%1 ; jcs 3f\n\t" + "2: moveml %2/%3/%4/%5,%0@-\n\t" + "dbra %1,2b\n\t" + "3:" + : "=a" (s), "=d" (count) + : "d" (0), "d" (0), "d" (0), "d" (0), + "0" ((char *)s+count), "1" (count) + ); + + return(0); +} + + +static __inline__ void *mymemclear(void *s, size_t count) +{ + if (!count) + return(0); + + if (count < 16) { + __asm__ __volatile__( + "lsrl #1,%1 ; jcc 1f ; clrb %0@+\n\t" + "1: lsrl #1,%1 ; jcc 1f ; clrw %0@+\n\t" + "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+\n\t" + "1: lsrl #1,%1 ; jcc 1f ; clrl %0@+ ; clrl %0@+\n\t" + "1:" + : "=a" (s), "=d" (count) + : "0" (s), "1" (count) + ); + } else { + long tmp; + __asm__ __volatile__( + "movel %1,%2\n\t" + "lsrl #1,%2 ; jcc 1f ; clrb %0@+ ; subqw #1,%1\n\t" + "lsrl #1,%2 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ + "clrw %0@+ ; subqw #2,%1 ; jra 2f\n\t" + "1: lsrl #1,%2 ; jcc 2f\n\t" + "clrw %0@+ ; subqw #2,%1\n\t" + "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t" + "lsrl #1,%1 ; jcc 3f ; clrl %0@+\n\t" + "3: lsrl #1,%1 ; jcc 4f ; clrl %0@+ ; clrl %0@+\n\t" + "4: subql #1,%1 ; jcs 6f\n\t" + "5: clrl %0@+; clrl %0@+ ; clrl %0@+ ; clrl %0@+\n\t" + "dbra %1,5b ; clrw %1; subql #1,%1; jcc 5b\n\t" + "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0@+\n\t" + "7: ; btst #0,%1 ; jeq 8f ; clrb %0@+\n\t" + "8:" + : "=a" (s), "=d" (count), "=d" (tmp) + : "0" (s), "1" (count) + ); + } + + return(0); +} + + +static __inline__ void *mymemset(void *s, size_t count) +{ + if (!count) + return(0); + + __asm__ __volatile__( + "lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t" + "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t" + "1: subql #1,%1 ; jcs 3f\n\t" + "2: moveml %2/%3/%4/%5,%0@-\n\t" + "dbra %1,2b\n\t" + "3:" + : "=a" (s), "=d" (count) + : "d" (-1), "d" (-1), "d" (-1), "d" (-1), + "0" ((char *) s + count), "1" (count) + ); + + return(0); +} + + +static __inline__ void *mymemmove(void *d, const void *s, size_t count) +{ + if (d < s) { + if (count < 16) { + __asm__ __volatile__( + "lsrl #1,%2 ; jcc 1f ; moveb %1@+,%0@+\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movew %1@+,%0@+\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" + "1:" + : "=a" (d), "=a" (s), "=d" (count) + : "0" (d), "1" (s), "2" (count) + ); + } else { + long tmp; + __asm__ __volatile__( + "movel %0,%3\n\t" + "lsrl #1,%3 ; jcc 1f ; moveb %1@+,%0@+ ; subqw #1,%2\n\t" + "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ + "movew %1@+,%0@+ ; subqw #2,%2 ; jra 2f\n\t" + "1: lsrl #1,%3 ; jcc 2f\n\t" + "movew %1@+,%0@+ ; subqw #2,%2\n\t" + "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" + "lsrl #1,%2 ; jcc 3f ; movel %1@+,%0@+\n\t" + "3: lsrl #1,%2 ; jcc 4f ; movel %1@+,%0@+ ; movel %1@+,%0@+\n\t" + "4: subql #1,%2 ; jcs 6f\n\t" + "5: movel %1@+,%0@+;movel %1@+,%0@+\n\t" + "movel %1@+,%0@+;movel %1@+,%0@+\n\t" + "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" + "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@+,%0@+\n\t" + "7: ; btst #0,%2 ; jeq 8f ; moveb %1@+,%0@+\n\t" + "8:" + : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) + : "0" (d), "1" (s), "2" (count) + ); + } + } else { + if (count < 16) { + __asm__ __volatile__( + "lsrl #1,%2 ; jcc 1f ; moveb %1@-,%0@-\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movew %1@-,%0@-\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@-\n\t" + "1: lsrl #1,%2 ; jcc 1f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" + "1:" + : "=a" (d), "=a" (s), "=d" (count) + : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) + ); + } else { + long tmp; + __asm__ __volatile__( + "movel %0,%3\n\t" + "lsrl #1,%3 ; jcc 1f ; moveb %1@-,%0@- ; subqw #1,%2\n\t" + "lsrl #1,%3 ; jcs 2f\n\t" /* %0 increased=>bit 2 switched*/ + "movew %1@-,%0@- ; subqw #2,%2 ; jra 2f\n\t" + "1: lsrl #1,%3 ; jcc 2f\n\t" + "movew %1@-,%0@- ; subqw #2,%2\n\t" + "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t" + "lsrl #1,%2 ; jcc 3f ; movel %1@-,%0@-\n\t" + "3: lsrl #1,%2 ; jcc 4f ; movel %1@-,%0@- ; movel %1@-,%0@-\n\t" + "4: subql #1,%2 ; jcs 6f\n\t" + "5: movel %1@-,%0@-;movel %1@-,%0@-\n\t" + "movel %1@-,%0@-;movel %1@-,%0@-\n\t" + "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t" + "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1@-,%0@-\n\t" + "7: ; btst #0,%2 ; jeq 8f ; moveb %1@-,%0@-\n\t" + "8:" + : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) + : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count) + ); + } + } + + return(0); +} + + +/* ++andreas: Simple and fast version of memmove, assumes size is + divisible by 16, suitable for moving the whole screen bitplane */ +static __inline__ void fast_memmove(char *dst, const char *src, size_t size) +{ + if (!size) + return; + if (dst < src) + __asm__ __volatile__ + ("1:" + " moveml %0@+,%/d0/%/d1/%/a0/%/a1\n" + " moveml %/d0/%/d1/%/a0/%/a1,%1@\n" + " addql #8,%1; addql #8,%1\n" + " dbra %2,1b\n" + " clrw %2; subql #1,%2\n" + " jcc 1b" + : "=a" (src), "=a" (dst), "=d" (size) + : "0" (src), "1" (dst), "2" (size / 16 - 1) + : "d0", "d1", "a0", "a1", "memory"); + else + __asm__ __volatile__ + ("1:" + " subql #8,%0; subql #8,%0\n" + " moveml %0@,%/d0/%/d1/%/a0/%/a1\n" + " moveml %/d0/%/d1/%/a0/%/a1,%1@-\n" + " dbra %2,1b\n" + " clrw %2; subql #1,%2\n" + " jcc 1b" + : "=a" (src), "=a" (dst), "=d" (size) + : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1) + : "d0", "d1", "a0", "a1", "memory"); +} + +#else /* !m68k */ + + /* + * Anyone who'd like to write asm functions for other CPUs? + */ + +static __inline__ void *mymemclear_small(void *s, size_t count) +{ + return(memset(s, 0, count)); +} + +static __inline__ void *mymemclear(void *s, size_t count) +{ + return(memset(s, 0, count)); +} + +static __inline__ void *mymemset(void *s, size_t count) +{ + return(memset(s, 255, count)); +} + +static __inline__ void *mymemmove(void *d, const void *s, size_t count) +{ + return(memmove(d, s, count)); +} + +static __inline__ void fast_memmove(char *dst, const char *src, size_t size) +{ + memmove(dst, src, size); +} + +#endif /* !m68k */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/font.h linux/drivers/video/font.h --- v2.1.66/linux/drivers/video/font.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/font.h Mon Nov 24 01:18:57 1997 @@ -0,0 +1,35 @@ +/* + * font.h -- `Soft' font definitions + * + * Created 1995 by Geert Uytterhoeven + * + * 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. + */ + +#ifndef _FONT_H_ +#define _FONT_H_ + +#include + + + /* + * Find a font with a specific name + */ + +extern int findsoftfont(char *name, int *width, int *height, u_char *data[]); + + + /* + * Get the default font for a specific screen size + */ + +extern void getdefaultfont(int xres, int yres, char *name[], int *width, + int *height, u_char *data[]); + + +/* Max. length for the name of a predefined font */ +#define MAX_FONT_NAME 32 + +#endif /* _FONT_H_ */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/font_8x16.c linux/drivers/video/font_8x16.c --- v2.1.66/linux/drivers/video/font_8x16.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/font_8x16.c Tue Sep 16 02:29:59 1997 @@ -0,0 +1,4625 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#define FONTDATAMAX 4096 + +char fontname_8x16[] = "VGA8x16"; + +int fontheight_8x16 = 16; +int fontwidth_8x16 = 8; + +unsigned char fontdata_8x16[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 'ˆ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '™' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c 'œ' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e 'ž' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f 'Ÿ' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '¬' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '­' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 'é' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee 'î' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc 'ü' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + diff -u --recursive --new-file v2.1.66/linux/drivers/video/font_8x8.c linux/drivers/video/font_8x8.c --- v2.1.66/linux/drivers/video/font_8x8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/font_8x8.c Tue Sep 16 02:30:02 1997 @@ -0,0 +1,2577 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* */ +/**********************************************/ + +#define FONTDATAMAX 2048 + +char fontname_8x8[] = "VGA8x8"; + +int fontheight_8x8 = 8; +int fontwidth_8x8 = 8; + +unsigned char fontdata_8x8[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xce, /* 11001110 */ + 0x7c, /* 01111100 */ + 0x0e, /* 00001110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x8c, /* 10001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* 96 0x60 '`' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf8, /* 11111000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + + /* 104 0x68 'h' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + + /* 107 0x6b 'k' */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x4c, /* 01001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 'ˆ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '™' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f 'Ÿ' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '¬' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '­' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 'é' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee 'î' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc 'ü' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + diff -u --recursive --new-file v2.1.66/linux/drivers/video/fonts.c linux/drivers/video/fonts.c --- v2.1.66/linux/drivers/video/fonts.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fonts.c Mon Nov 24 01:18:58 1997 @@ -0,0 +1,113 @@ +/* + * linux/drivers/video/fonts.c -- `Soft' font definitions + * + * Created 1995 by Geert Uytterhoeven + * + * 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 +#ifdef __mc68000__ +#include +#endif +#include "font.h" + + + /* + * External Font Definitions + */ + +/* VGA8x8 */ +extern char fontname_8x8[]; +extern int fontwidth_8x8, fontheight_8x8; +extern u_char fontdata_8x8[]; + +/* VGA8x16 */ +extern char fontname_8x16[]; +extern int fontwidth_8x16, fontheight_8x16; +extern u_char fontdata_8x16[]; + +/* PEARL8x8 */ +extern char fontname_pearl8x8[]; +extern int fontwidth_pearl8x8, fontheight_pearl8x8; +extern u_char fontdata_pearl8x8[]; + + + /* + * Font Descriptor Array + */ + +struct softfontdesc { + char *name; + int *width; + int *height; + u_char *data; +}; + +#define VGA8x8_IDX 0 +#define VGA8x16_IDX 1 +#define PEARL8x8_IDX 2 + +static struct softfontdesc softfonts[] = { + { fontname_8x8, &fontwidth_8x8, &fontheight_8x8, fontdata_8x8 }, + { fontname_8x16, &fontwidth_8x16, &fontheight_8x16, fontdata_8x16 }, + { fontname_pearl8x8, &fontwidth_pearl8x8, &fontheight_pearl8x8, + fontdata_pearl8x8 }, +}; + +static unsigned int numsoftfonts = sizeof(softfonts)/sizeof(*softfonts); + + + /* + * Find a font with a specific name + */ + +int findsoftfont(char *name, int *width, int *height, u_char *data[]) +{ + unsigned int i; + + for (i = 0; i < numsoftfonts; i++) + if (!strcmp(softfonts[i].name, name)) { + if (width) + *width = *softfonts[i].width; + if (height) + *height = *softfonts[i].height; + if (data) + *data = softfonts[i].data; + return(1); + } + return(0); +} + + + /* + * Get the default font for a specific screen size + */ + +void getdefaultfont(int xres, int yres, char *name[], int *width, int *height, + u_char *data[]) +{ + int i; + + if (yres < 400) { + i = VGA8x8_IDX; +#ifdef CONFIG_AMIGA + if (MACH_IS_AMIGA) + i = PEARL8x8_IDX; +#endif + } else + i = VGA8x16_IDX; + + if (name) + *name = softfonts[i].name; + if (width) + *width = *softfonts[i].width; + if (height) + *height = *softfonts[i].height; + if (data) + *data = softfonts[i].data; +} diff -u --recursive --new-file v2.1.66/linux/drivers/video/offb.c linux/drivers/video/offb.c --- v2.1.66/linux/drivers/video/offb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/offb.c Mon Nov 24 01:18:58 1997 @@ -0,0 +1,454 @@ +/* + * linux/drivers/video/offb.c -- Open Firmware based frame buffer device + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This driver is partly based on the PowerMac console driver: + * + * Copyright (C) 1996 Paul Mackerras + * + * 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 +#include +#include +#include +#include +#include +#include + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +static int currcon = 0; +static struct display disp; +static struct fb_info fb_info; +static struct { u_char red, green, blue, pad; } palette[256]; +static char offb_name[16] = "OFfb "; + +static volatile unsigned char *unknown_cmap_adr = NULL; +static volatile unsigned char *unknown_cmap_data = NULL; + +static struct fb_fix_screeninfo fb_fix = { 0, }; +static struct fb_var_screeninfo fb_var = { 0, }; + + + /* + * Interface used by the world + */ + +void offb_video_setup(char *options, int *ints); + +static int offb_open(int fbidx); +static int offb_release(int fbidx); +static int offb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int offb_get_var(struct fb_var_screeninfo *var, int con); +static int offb_set_var(struct fb_var_screeninfo *var, int con); +static int offb_pan_display(struct fb_var_screeninfo *var, int con); +static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con); + + + /* + * Interface to the low level console driver + */ + +unsigned long offb_init(unsigned long mem_start); +static int offbcon_switch(int con); +static int offbcon_updatevar(int con); +static void offbcon_blank(int blank); +static int offbcon_setcmap(struct fb_cmap *cmap, int con); + + + /* + * Internal routines + */ + +static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); +static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); +static void do_install_cmap(int con); + + +static struct fb_ops offb_ops = { + offb_open, offb_release, offb_get_fix, offb_get_var, offb_set_var, + offb_get_cmap, offb_set_cmap, offb_pan_display, offb_ioctl +}; + + + /* + * Open/Release the frame buffer device + */ + +static int offb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int offb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + + + /* + * Get the Fixed Part of the Display + */ + +static int offb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + memcpy(fix, &fb_fix, sizeof(fb_fix)); + return 0; +} + + + /* + * Get the User Defined Part of the Display + */ + +static int offb_get_var(struct fb_var_screeninfo *var, int con) +{ + memcpy(var, &fb_var, sizeof(fb_var)); + return 0; +} + + + /* + * Set the User Defined Part of the Display + */ + +static int offb_set_var(struct fb_var_screeninfo *var, int con) +{ + struct display *display; + int oldbpp = -1, err; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + if (var->xres > fb_var.xres || var->yres > fb_var.yres || + var->xres_virtual > fb_var.xres_virtual || + var->yres_virtual > fb_var.yres_virtual || + var->bits_per_pixel > fb_var.bits_per_pixel || + var->nonstd || + (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + memcpy(var, &fb_var, sizeof(fb_var)); + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldbpp = display->var.bits_per_pixel; + display->var = *var; + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con); + } + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int offb_pan_display(struct fb_var_screeninfo *var, int con) +{ + if (var->xoffset || var->yoffset) + return -EINVAL; + else + return 0; +} + + /* + * Get the Colormap + */ + +static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, &fb_display[con].var, kspc, offb_getcolreg); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + /* + * Set the Colormap + */ + +static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!unknown_cmap_adr) + return -ENOSYS; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<name, sizeof(offb_name)); + offb_name[sizeof(offb_name)-1] = '\0'; + strcpy(fb_fix.id, offb_name); + + if ((pp = (int *)get_property(dp, "depth", &len)) != NULL + && len == sizeof(int) && *pp != 8) { + printk("%s: can't use depth = %d\n", dp->full_name, *pp); + return mem_start; + } + if ((pp = (int *)get_property(dp, "width", &len)) != NULL + && len == sizeof(int)) + fb_var.xres = fb_var.xres_virtual = *pp; + if ((pp = (int *)get_property(dp, "height", &len)) != NULL + && len == sizeof(int)) + fb_var.yres = fb_var.yres_virtual = *pp; + if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL + && len == sizeof(int)) + fb_fix.line_length = *pp; + else + fb_fix.line_length = fb_var.xres_virtual; + fb_fix.smem_len = fb_fix.line_length*fb_var.yres; + if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL + && len == sizeof(unsigned)) + address = (u_long)*up; + else { + for (i = 0; i < dp->n_addrs; ++i) + if (dp->addrs[i].size >= len) + break; + if (i >= dp->n_addrs) { + printk("no framebuffer address found for %s\n", dp->full_name); + return mem_start; + } + address = (u_long)dp->addrs[i].address; + } + fb_fix.smem_start = ioremap(address, fb_fix.smem_len); + fb_fix.type = FB_TYPE_PACKED_PIXELS; + fb_fix.type_aux = 0; + + /* XXX kludge for ati */ + if (strncmp(dp->name, "ATY,", 4) == 0) { + unknown_cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0; + unknown_cmap_data = unknown_cmap_adr + 1; + } + + fb_fix.visual = unknown_cmap_adr ? FB_VISUAL_PSEUDOCOLOR : + FB_VISUAL_STATIC_PSEUDOCOLOR; + + fb_var.xoffset = fb_var.yoffset = 0; + fb_var.bits_per_pixel = 8; + fb_var.grayscale = 0; + fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0; + fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8; + fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0; + fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0; + fb_var.nonstd = 0; + fb_var.activate = 0; + fb_var.height = fb_var.width = -1; + fb_var.accel = FB_ACCEL_NONE; + fb_var.pixclock = 10000; + fb_var.left_margin = fb_var.right_margin = 16; + fb_var.upper_margin = fb_var.lower_margin = 16; + fb_var.hsync_len = fb_var.vsync_len = 8; + fb_var.sync = 0; + fb_var.vmode = FB_VMODE_NONINTERLACED; + + disp.var = fb_var; + disp.cmap.start = 0; + disp.cmap.len = 0; + disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL; + disp.screen_base = fb_fix.smem_start; + disp.visual = fb_fix.visual; + disp.type = fb_fix.type; + disp.type_aux = fb_fix.type_aux; + disp.ypanstep = 0; + disp.ywrapstep = 0; + disp.line_length = fb_fix.line_length; + disp.can_soft_blank = 1; + disp.inverse = 0; + + strcpy(fb_info.modename, "OFfb "); + strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename)); + fb_info.node = -1; + fb_info.fbops = &offb_ops; + fb_info.fbvar_num = 1; + fb_info.fbvar = &fb_var; + fb_info.disp = &disp; + fb_info.fontname[0] = '\0'; + fb_info.changevar = NULL; + fb_info.switch_con = &offbcon_switch; + fb_info.updatevar = &offbcon_updatevar; + fb_info.blank = &offbcon_blank; + fb_info.setcmap = &offbcon_setcmap; + + err = register_framebuffer(&fb_info); + if (err < 0) + return mem_start; + + offb_set_var(&fb_var, -1); + + printk("Open Firmware frame buffer device on %s\n", dp->full_name); + return mem_start; +} + + +static int offbcon_switch(int con) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, + offb_getcolreg); + + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int offbcon_updatevar(int con) +{ + /* Nothing */ + return 0; +} + + /* + * Blank the display. + */ + +static void offbcon_blank(int blank) +{ + /* Nothing */ +} + + /* + * Set the colormap + */ + +static int offbcon_setcmap(struct fb_cmap *cmap, int con) +{ + return(offb_set_cmap(cmap, 1, con)); +} + + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp) +{ + if (!unknown_cmap_adr || regno > 255) + return 1; + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp) +{ + if (!unknown_cmap_adr || regno > 255) + return 1; + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + *unknown_cmap_adr = regno; +#ifdef __powerpc__ + eieio(); +#endif + *unknown_cmap_data = red; +#ifdef __powerpc__ + eieio(); +#endif + *unknown_cmap_data = green; +#ifdef __powerpc__ + eieio(); +#endif + *unknown_cmap_data = blue; +#ifdef __powerpc__ + eieio(); +#endif + return 0; +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + offb_setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &fb_display[con].var, 1, offb_setcolreg); +} diff -u --recursive --new-file v2.1.66/linux/drivers/video/pearl_8x8.c linux/drivers/video/pearl_8x8.c --- v2.1.66/linux/drivers/video/pearl_8x8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/pearl_8x8.c Tue Sep 16 02:30:10 1997 @@ -0,0 +1,2582 @@ +/**********************************************/ +/* */ +/* Font file generated by cpi2fnt */ +/* ------------------------------ */ +/* Combined with the alpha-numeric */ +/* portion of Greg Harp's old PEARL */ +/* font (from earlier versions of */ +/* linux-m86k) by John Shifflett */ +/* */ +/**********************************************/ + +#define FONTDATAMAX 2048 + +char fontname_pearl8x8[] = "PEARL8x8"; + +int fontheight_pearl8x8 = 8; +int fontwidth_pearl8x8 = 8; + +unsigned char fontdata_pearl8x8[FONTDATAMAX] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + + /* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + + /* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + + /* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + + /* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + + /* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + + /* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + + /* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + + /* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + + /* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x60, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x68, /* 01101000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xfe, /* 11111110 */ + 0xf6, /* 11110110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x1c, /* 00011100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + + /* 60 0x3c '<' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xf0, /* 11110000 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x82, /* 10000010 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + + /* 82 0x52 'R' */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc3, /* 11000011 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0xc0, /* 11000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x03, /* 00000011 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + + /* 96 0x60 '`' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x7c, /* 01111100 */ + + /* 104 0x68 'h' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + + /* 107 0x6b 'k' */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xf0, /* 11110000 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfc, /* 11111100 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc3, /* 11000011 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x72, /* 01110010 */ + 0x9c, /* 10011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + + /* 129 0x81 '' */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x0c, /* 00001100 */ + 0x38, /* 00111000 */ + + /* 136 0x88 'ˆ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xf8, /* 11111000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x7c, /* 01111100 */ + 0x82, /* 10000010 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0xfc, /* 11111100 */ + + /* 153 0x99 '™' */ + 0xc6, /* 11000110 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 156 0x9c 'œ' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 158 0x9e 'ž' */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfa, /* 11111010 */ + 0xc6, /* 11000110 */ + 0xcf, /* 11001111 */ + 0xc6, /* 11000110 */ + 0xc7, /* 11000111 */ + + /* 159 0x9f 'Ÿ' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x63, /* 01100011 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7e, /* 01111110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x0f, /* 00001111 */ + + /* 172 0xac '¬' */ + 0x63, /* 01100011 */ + 0xe6, /* 11100110 */ + 0x6c, /* 01101100 */ + 0x7a, /* 01111010 */ + 0x36, /* 00110110 */ + 0x6a, /* 01101010 */ + 0xdf, /* 11011111 */ + 0x06, /* 00000110 */ + + /* 173 0xad '­' */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x66, /* 01100110 */ + 0x33, /* 00110011 */ + 0x66, /* 01100110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xc8, /* 11001000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0xc0, /* 11000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + + /* 233 0xe9 'é' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + + /* 238 0xee 'î' */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + + /* 252 0xfc 'ü' */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; + diff -u --recursive --new-file v2.1.66/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c --- v2.1.66/linux/drivers/video/retz3fb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/retz3fb.c Mon Nov 24 01:18:59 1997 @@ -0,0 +1,1646 @@ +/* + * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * This file is based on the CyberVision64 frame buffer device and + * the generic Cirrus Logic driver. + * + * cyberfb.c: Copyright (C) 1996 Martin Apel, + * Geert Uytterhoeven + * clgen.c: Copyright (C) 1996 Frank Neumann + * + * History: + * - 22 Jan 97: Initial work + * - 14 Feb 97: Screen initialization works somewhat, still only + * 8-bit packed pixel is supported. + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "retz3fb.h" + +/* #define DEBUG if(1) */ +#define DEBUG if(0) + +/* + * Reserve space for one pattern line. + * + * For the time being we only support 4MB boards! + */ + +#define PAT_MEM_SIZE 16*3 +#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +struct retz3_fb_par { + int xres; + int yres; + int xres_vir; + int yres_vir; + int xoffset; + int yoffset; + int bpp; + + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + + int pixclock; + int left_margin; /* time from sync to picture */ + int right_margin; /* time from picture to sync */ + int upper_margin; /* time from sync to picture */ + int lower_margin; + int hsync_len; /* length of horizontal sync */ + int vsync_len; /* length of vertical sync */ + int vmode; +}; + +struct display_data { + long h_total; /* Horizontal Total */ + long h_sstart; /* Horizontal Sync Start */ + long h_sstop; /* Horizontal Sync Stop */ + long h_bstart; /* Horizontal Blank Start */ + long h_bstop; /* Horizontal Blank Stop */ + long h_dispend; /* Horizontal Display End */ + long v_total; /* Vertical Total */ + long v_sstart; /* Vertical Sync Start */ + long v_sstop; /* Vertical Sync Stop */ + long v_bstart; /* Vertical Blank Start */ + long v_bstop; /* Vertical Blank Stop */ + long v_dispend; /* Horizontal Display End */ +}; + +static struct retz3_fb_par current_par; + +static int current_par_valid = 0; +static int currcon = 0; + +static struct display disp; +static struct fb_info fb_info; + + +/* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialisation */ + + int (*init)(void); + + /* Display Control */ + + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); + int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned + int *green, unsigned int *blue, unsigned int *transp); + int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int + green, unsigned int blue, unsigned int transp); + void (*blank)(int blank); +} *fbhw; + + +/* + * Frame Buffer Name + */ + +static char retz3_fb_name[16] = "RetinaZ3"; + + +static unsigned char retz3_color_table [256][4]; +static unsigned long z3_mem; +static unsigned long z3_fbmem; +static unsigned long z3_size; +static volatile unsigned char *z3_regs; + + +/* + * Predefined Video Mode Names + */ + +static char *retz3_fb_modenames[] = { + + /* + * Autodetect (Default) Video Mode + */ + + "default", + + /* + * Predefined Video Modes + */ + + "640x480", /* RetinaZ3 8 bpp */ + "800x600", /* RetinaZ3 8 bpp */ + "1024x768i", + "640x480-16", /* RetinaZ3 16 bpp */ + "640x480-24", /* RetinaZ3 24 bpp */ + + /* + * Dummy Video Modes + */ + + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + + /* + * User Defined Video Modes + * + * This doesn't work yet!! + */ + + "user0", "user1", "user2", "user3", + "user4", "user5", "user6", "user7" +}; + +/* + * A small info on how to convert XFree86 timing values into fb + * timings - by Frank Neumann: + * +An XFree86 mode line consists of the following fields: + "800x600" 50 800 856 976 1040 600 637 643 666 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + +The fields in the fb_var_screeninfo structure are: + unsigned long pixclock; * pixel clock in ps (pico seconds) * + unsigned long left_margin; * time from sync to picture * + unsigned long right_margin; * time from picture to sync * + unsigned long upper_margin; * time from sync to picture * + unsigned long lower_margin; + unsigned long hsync_len; * length of horizontal sync * + unsigned long vsync_len; * length of vertical sync * + +1) Pixelclock: + xfree: in MHz + fb: In Picoseconds (ps) + + pixclock = 1000000 / DCF + +2) horizontal timings: + left_margin = HFL - SH2 + right_margin = SH1 - HR + hsync_len = SH2 - SH1 + +3) vertical timings: + upper_margin = VFL - SV2 + lower_margin = SV1 - VR + vsync_len = SV2 - SV1 + +Good examples for VESA timings can be found in the XFree86 source tree, +under "programs/Xserver/hw/xfree86/doc/modeDB.txt". +*/ + +/* + * Predefined Video Mode Definitions + */ + +static struct fb_var_screeninfo retz3_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { 0, }, + + /* + * Predefined Video Modes + */ + + /* + * NB: it is very important to adjust the pixel-clock to the color-depth. + */ + + { + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + /* 800 x 600, 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + /* + ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + */ + { + /* 1024 x 768, 8 bpp, interlaced */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED + }, + { + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + { + 640, 480, 640, 480, 0, 0, 24, 0, + {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, + + /* + * Dummy Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, + { 0, }, { 0, }, + + /* + * User Defined Video Modes + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + + +#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined) +#define NUM_PREDEF_MODES 5 + + +static int z3fb_inverse = 0; +static int z3fb_mode = 0; + + +/* + * Interface used by the world + */ + +void retz3_video_setup(char *options, int *ints); + +static int retz3_fb_open(int fbidx); +static int retz3_fb_release(int fbidx); +static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con); +static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con); +static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int retz3_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con); + + +/* + * Interface to the low level console driver + */ + +unsigned long retz3_fb_init(unsigned long mem_start); +static int z3fb_switch(int con); +static int z3fb_updatevar(int con); +static void z3fb_blank(int blank); +static int z3fb_setcmap(struct fb_cmap *cmap, int con); + + +/* + * Accelerated Functions used by the low level console driver + */ + +void retz3_bitblt(struct fb_var_screeninfo *scr, + unsigned short curx, unsigned short cury, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask); +void retz3_fill(unsigned short x, unsigned short y, unsigned short + width, unsigned short height, unsigned short mode, + unsigned short color); + +/* + * Hardware Specific Routines + */ + +static int retz3_init(void); +static int retz3_encode_fix(struct fb_fix_screeninfo *fix, + struct retz3_fb_par *par); +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par); +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par); +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp); +static int retz3_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp); +static void retz3_blank(int blank); + + +/* + * Internal routines + */ + +static void retz3_fb_get_par(struct retz3_fb_par *par); +static void retz3_fb_set_par(struct retz3_fb_par *par); +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static void do_install_cmap(int con); +/* +static void retz3_fb_set_disp(int con); +*/ +static int get_video_mode(const char *name); + + +/* -------------------- Hardware specific routines -------------------------- */ + +static unsigned short find_fq(unsigned int freq) +{ + unsigned long f; + long tmp; + long prev = 0x7fffffff; + long n2, n1 = 3; + unsigned long m; + unsigned short res = 0; + + if (freq <= 31250000) + n2 = 3; + else if (freq <= 62500000) + n2 = 2; + else if (freq <= 125000000) + n2 = 1; + else if (freq <= 250000000) + n2 = 0; + else + return(0); + + + do { + f = freq >> (10 - n2); + + m = (f * n1) / (14318180/1024); + + if (m > 129) + break; + + tmp = (((m * 14318180) >> n2) / n1) - freq; + if (tmp < 0) + tmp = -tmp; + + if (tmp < prev) { + prev = tmp; + res = (((n2 << 5) | (n1-2)) << 8) | (m-2); + } + + } while ( (++n1) <= 21); + + return res; +} + + +static int retz3_set_video(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + float freq_f; + long freq; + + int xres, hfront, hsync, hback; + int yres, vfront, vsync, vback; + unsigned char tmp; + unsigned short best_freq; + struct display_data data; + + short clocksel = 0; /* Apparantly this is always zero */ + + int bpp = var->bits_per_pixel; + + /* + * XXX + */ + if (bpp == 24) + return 0; + + if ((bpp != 8) && (bpp != 16) && (bpp != 24)) + return -EFAULT; + + par->xoffset = 0; + par->yoffset = 0; + + xres = var->xres * bpp / 4; + hfront = var->right_margin * bpp / 4; + hsync = var->hsync_len * bpp / 4; + hback = var->left_margin * bpp / 4; + + if (var->vmode & FB_VMODE_DOUBLE) + { + yres = var->yres * 2; + vfront = var->lower_margin * 2; + vsync = var->vsync_len * 2; + vback = var->upper_margin * 2; + } + else if (var->vmode & FB_VMODE_INTERLACED) + { + yres = (var->yres + 1) / 2; + vfront = (var->lower_margin + 1) / 2; + vsync = (var->vsync_len + 1) / 2; + vback = (var->upper_margin + 1) / 2; + } + else + { + yres = var->yres; /* -1 ? */ + vfront = var->lower_margin; + vsync = var->vsync_len; + vback = var->upper_margin; + } + + data.h_total = (hback / 8) + (xres / 8) + + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; + data.h_dispend = ((xres + bpp - 1)/ 8) - 1; + data.h_bstart = xres / 8 /* + 1 */; + + data.h_bstop = data.h_total+1 + 2 + 1; + data.h_sstart = (xres / 8) + (hfront / 8) + 1; + data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; + + data.v_total = yres + vfront + vsync + vback - 1; + + data.v_dispend = yres - 1; + data.v_bstart = yres; + + data.v_bstop = data.v_total; + data.v_sstart = yres + vfront - 1 - 2; + data.v_sstop = yres + vfront + vsync - 1; + +#if 0 /* testing */ + + printk("HBS: %i\n", data.h_bstart); + printk("HSS: %i\n", data.h_sstart); + printk("HSE: %i\n", data.h_sstop); + printk("HBE: %i\n", data.h_bstop); + printk("HT: %i\n", data.h_total); + + printk("hsync: %i\n", hsync); + printk("hfront: %i\n", hfront); + printk("hback: %i\n", hback); + + printk("VBS: %i\n", data.v_bstart); + printk("VSS: %i\n", data.v_sstart); + printk("VSE: %i\n", data.v_sstop); + printk("VBE: %i\n", data.v_bstop); + printk("VT: %i\n", data.v_total); + + printk("vsync: %i\n", vsync); + printk("vfront: %i\n", vfront); + printk("vback: %i\n", vback); +#endif + + if (data.v_total >= 1024) + printk("MAYDAY: v_total >= 1024; bailing out!\n"); + + reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); + reg_w(GREG_FEATURE_CONTROL_W, 0x00); + + seq_w(SEQ_RESET, 0x00); + seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */ + + /* + * CLOCKING_MODE bits: + * 2: This one is only set for certain text-modes, wonder if + * it may be for EGA-lines? (it was referred to as CLKDIV2) + * (The CL drivers sets it to 0x21 with the comment: + * FullBandwidth (video off) and 8/9 dot clock) + */ + seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); + + seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ + seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ + seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ + seq_w(SEQ_RESET, 0x01); + seq_w(SEQ_RESET, 0x03); + + seq_w(SEQ_EXTENDED_ENABLE, 0x05); + + seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ + seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); + seq_w(SEQ_LINEAR_0, 0x4a); + seq_w(SEQ_LINEAR_1, 0x00); + + seq_w(SEQ_SEC_HOST_OFF_HI, 0x00); + seq_w(SEQ_SEC_HOST_OFF_LO, 0x00); + seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); + + /* + * The lower 4 bits (0-3) are used to set the font-width for + * text-mode - DON'T try to set this for gfx-mode. + */ + seq_w(SEQ_EXT_CLOCK_MODE, 0x10); + seq_w(SEQ_EXT_VIDEO_ADDR, 0x03); + + /* + * Extended Pixel Control: + * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) + * bit 1: (Packed/Nibble Pixel Format ?) + * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp + */ + seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); + + seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04); + seq_w(SEQ_COLOR_EXP_WFG, 0x01); + seq_w(SEQ_COLOR_EXP_WBG, 0x00); + seq_w(SEQ_EXT_RW_CONTROL, 0x00); + seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); + seq_w(SEQ_COLOR_KEY_CNTL, 0x40); + seq_w(SEQ_COLOR_KEY_MATCH0, 0x00); + seq_w(SEQ_COLOR_KEY_MATCH1, 0x00); + seq_w(SEQ_COLOR_KEY_MATCH2, 0x00); + seq_w(SEQ_CRC_CONTROL, 0x00); + seq_w(SEQ_PERF_SELECT, 0x10); + seq_w(SEQ_ACM_APERTURE_1, 0x00); + seq_w(SEQ_ACM_APERTURE_2, 0x30); + seq_w(SEQ_ACM_APERTURE_3, 0x00); + seq_w(SEQ_MEMORY_MAP_CNTL, 0x03); + + + /* unlock register CRT0..CRT7 */ + crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); + + /* Zuerst zu schreibende Werte nur per printk ausgeben */ + DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); + crt_w(CRT_HOR_TOTAL, data.h_total & 0xff); + + DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); + crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); + + DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); + crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff); + + DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); + crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); + + DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); + crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff); + + tmp = (data.h_sstop & 0x1f); + if (data.h_bstop & 0x20) + tmp |= 0x80; + DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); + crt_w(CRT_END_HOR_RETR, tmp); + + DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); + crt_w(CRT_VER_TOTAL, (data.v_total & 0xff)); + + tmp = 0x10; /* LineCompare bit #9 */ + if (data.v_total & 256) + tmp |= 0x01; + if (data.v_dispend & 256) + tmp |= 0x02; + if (data.v_sstart & 256) + tmp |= 0x04; + if (data.v_bstart & 256) + tmp |= 0x08; + if (data.v_total & 512) + tmp |= 0x20; + if (data.v_dispend & 512) + tmp |= 0x40; + if (data.v_sstart & 512) + tmp |= 0x80; + DEBUG printk("CRT_OVERFLOW: %d\n", tmp); + crt_w(CRT_OVERFLOW, tmp); + + crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ + + tmp = 0x40; /* LineCompare bit #8 */ + if (data.v_bstart & 512) + tmp |= 0x20; + if (var->vmode & FB_VMODE_DOUBLE) + tmp |= 0x80; + DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); + crt_w(CRT_MAX_SCAN_LINE, tmp); + + crt_w(CRT_CURSOR_START, 0x00); + crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */ + + crt_w(CRT_START_ADDR_HIGH, 0x00); + crt_w(CRT_START_ADDR_LOW, 0x00); + + crt_w(CRT_CURSOR_LOC_HIGH, 0x00); + crt_w(CRT_CURSOR_LOC_LOW, 0x00); + + DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); + crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff)); + +#if 1 + /* 5 refresh cycles per scanline */ + DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); + crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); +#else + DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); + crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); +#endif + DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); + crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); + + DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); + crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff)); + + DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); + crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff)); + + DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); + crt_w(CRT_MODE_CONTROL, 0xe3); + + DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); + crt_w(CRT_LINE_COMPARE, 0xff); + + tmp = (var->xres_virtual / 8) * (bpp / 8); + crt_w(CRT_OFFSET, tmp); + + crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ + + tmp = 0x20; /* Enable extended end bits */ + if (data.h_total & 0x100) + tmp |= 0x01; + if ((data.h_dispend) & 0x100) + tmp |= 0x02; + if (data.h_bstart & 0x100) + tmp |= 0x04; + if (data.h_sstart & 0x100) + tmp |= 0x08; + if (var->vmode & FB_VMODE_INTERLACED) + tmp |= 0x10; + DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); + crt_w(CRT_EXT_HOR_TIMING1, tmp); + + tmp = 0x00; + if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) + tmp |= 0x10; + crt_w(CRT_EXT_START_ADDR, tmp); + + tmp = 0x00; + if (data.h_total & 0x200) + tmp |= 0x01; + if ((data.h_dispend) & 0x200) + tmp |= 0x02; + if (data.h_bstart & 0x200) + tmp |= 0x04; + if (data.h_sstart & 0x200) + tmp |= 0x08; + tmp |= ((data.h_bstop & 0xc0) >> 2); + tmp |= ((data.h_sstop & 0x60) << 1); + crt_w(CRT_EXT_HOR_TIMING2, tmp); + DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); + + tmp = 0x10; /* Line compare bit 10 */ + if (data.v_total & 0x400) + tmp |= 0x01; + if ((data.v_dispend) & 0x400) + tmp |= 0x02; + if (data.v_bstart & 0x400) + tmp |= 0x04; + if (data.v_sstart & 0x400) + tmp |= 0x08; + tmp |= ((data.v_bstop & 0x300) >> 3); + if (data.v_sstop & 0x10) + tmp |= 0x80; + crt_w(CRT_EXT_VER_TIMING, tmp); + DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); + + crt_w(CRT_MONITOR_POWER, 0x00); + + /* + * Convert from ps to Hz. + */ + freq_f = (1.0/(float)var->pixclock) * 1000000000; + freq = ((long)freq_f) * 1000; + + best_freq = find_fq(freq); + pll_w(0x02, best_freq); + best_freq = find_fq(61000000); + pll_w(0x0a, best_freq); + pll_w(0x0e, 0x22); + + gfx_w(GFX_SET_RESET, 0x00); + gfx_w(GFX_ENABLE_SET_RESET, 0x00); + gfx_w(GFX_COLOR_COMPARE, 0x00); + gfx_w(GFX_DATA_ROTATE, 0x00); + gfx_w(GFX_READ_MAP_SELECT, 0x00); + gfx_w(GFX_GRAPHICS_MODE, 0x00); + gfx_w(GFX_MISC, 0x05); + gfx_w(GFX_COLOR_XCARE, 0x0f); + gfx_w(GFX_BITMASK, 0xff); + + reg_r(ACT_ADDRESS_RESET); + attr_w(ACT_PALETTE0 , 0x00); + attr_w(ACT_PALETTE1 , 0x01); + attr_w(ACT_PALETTE2 , 0x02); + attr_w(ACT_PALETTE3 , 0x03); + attr_w(ACT_PALETTE4 , 0x04); + attr_w(ACT_PALETTE5 , 0x05); + attr_w(ACT_PALETTE6 , 0x06); + attr_w(ACT_PALETTE7 , 0x07); + attr_w(ACT_PALETTE8 , 0x08); + attr_w(ACT_PALETTE9 , 0x09); + attr_w(ACT_PALETTE10, 0x0a); + attr_w(ACT_PALETTE11, 0x0b); + attr_w(ACT_PALETTE12, 0x0c); + attr_w(ACT_PALETTE13, 0x0d); + attr_w(ACT_PALETTE14, 0x0e); + attr_w(ACT_PALETTE15, 0x0f); + reg_r(ACT_ADDRESS_RESET); + + attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ + + attr_w(ACT_OVERSCAN_COLOR, 0x00); + attr_w(ACT_COLOR_PLANE_ENA, 0x0f); + attr_w(ACT_HOR_PEL_PANNING, 0x00); + attr_w(ACT_COLOR_SELECT, 0x00); + + reg_r(ACT_ADDRESS_RESET); + reg_w(ACT_DATA, 0x20); + + reg_w(VDAC_MASK, 0xff); + + /* + * Extended palette adressing ??? + */ + switch (bpp){ + case 8: + reg_w(0x83c6, 0x00); + break; + case 16: + reg_w(0x83c6, 0x60); + break; + case 24: + reg_w(0x83c6, 0xe0); + break; + default: + printk("Illegal color-depth: %i\n", bpp); + } + + reg_w(VDAC_ADDRESS, 0x00); + + seq_w(SEQ_MAP_MASK, 0x0f ); + + return 0; +} + +/* + * Initialization + * + * Set the default video mode for this chipset. If a video mode was + * specified on the command line, it will override the default mode. + */ + +static int retz3_init(void) +{ + short i; +#if 0 + volatile unsigned long *CursorBase; +#endif + + for (i = 0; i < 256; i++){ + for (i = 0; i < 256; i++){ + retz3_color_table [i][0] = i; + retz3_color_table [i][1] = i; + retz3_color_table [i][2] = i; + retz3_color_table [i][3] = 0; + } + } + + /* Disable hardware cursor */ + + seq_w(SEQ_CURSOR_Y_INDEX, 0x00); + +#if 0 + /* Initialize hardware cursor */ + CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400); + for (i=0; i < 8; i++){ + *(CursorBase +(i*4)) = 0xffffff00; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } + for (i=8; i < 64; i++){ + *(CursorBase +(i*4)) = 0xffff0000; + *(CursorBase+1+(i*4)) = 0xffff0000; + *(CursorBase+2+(i*4)) = 0xffff0000; + *(CursorBase+3+(i*4)) = 0xffff0000; + } +#endif + + retz3_setcolreg (255, 56, 100, 160, 0); + retz3_setcolreg (254, 0, 0, 0, 0); + + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int retz3_encode_fix(struct fb_fix_screeninfo *fix, + struct retz3_fb_par *par) +{ + short i; + + strcpy(fix->id, retz3_fb_name); + fix->smem_start = (char *)z3_fbmem; + fix->smem_len = z3_size; + fix->mmio_start = (unsigned char *)z3_regs; + fix->mmio_len = 0x00c00000; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->bpp == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_DIRECTCOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = 0; + + for (i = 0; i < arraysize(fix->reserved); i++) + fix->reserved[i] = 0; + + return 0; +} + + +/* + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. + */ + +static int retz3_decode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + par->xres = var->xres; + par->yres = var->yres; + par->xres_vir = var->xres_virtual; + par->yres_vir = var->yres_virtual; + par->bpp = var->bits_per_pixel; + par->pixclock = var->pixclock; + par->vmode = var->vmode; + + par->red = var->red; + par->green = var->green; + par->blue = var->blue; + par->transp = var->transp; + + par->left_margin = var->left_margin; + par->right_margin = var->right_margin; + par->upper_margin = var->upper_margin; + par->lower_margin = var->lower_margin; + par->hsync_len = var->hsync_len; + par->vsync_len = var->vsync_len; + + return 0; +} + + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int retz3_encode_var(struct fb_var_screeninfo *var, + struct retz3_fb_par *par) +{ + short i; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->xres_vir; + var->yres_virtual = par->yres_vir; + var->xoffset = 0; + var->yoffset = 0; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red = par->red; + var->green = par->green; + var->blue = par->blue; + var->transp = par->transp; + + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->accel = FB_ACCEL_RETINAZ3; + + var->pixclock = par->pixclock; + + var->sync = 0; /* ??? */ + var->left_margin = par->left_margin; + var->right_margin = par->right_margin; + var->upper_margin = par->upper_margin; + var->lower_margin = par->lower_margin; + var->hsync_len = par->hsync_len; + var->vsync_len = par->vsync_len; + + for (i = 0; i < arraysize(var->reserved); i++) + var->reserved[i] = 0; + + var->vmode = par->vmode; + return 0; +} + + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int retz3_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp) +{ + /* We'll get to this */ + + if (regno > 255) + return 1; + + retz3_color_table [regno][0] = red & 0xff; + retz3_color_table [regno][1] = green & 0xff; + retz3_color_table [regno][2] = blue & 0xff; + retz3_color_table [regno][3] = transp; + + reg_w(VDAC_ADDRESS_W, regno); + reg_w(VDAC_DATA, (red & 0xff) >> 2); + reg_w(VDAC_DATA, (green & 0xff) >> 2); + reg_w(VDAC_DATA, (blue & 0xff) >> 2); + + return 0; +} + + +/* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int retz3_getcolreg(unsigned int regno, unsigned int *red, + unsigned int *green, unsigned int *blue, + unsigned int *transp) +{ + if (regno > 255) + return 1; + *red = retz3_color_table [regno][0]; + *green = retz3_color_table [regno][1]; + *blue = retz3_color_table [regno][2]; + *transp = retz3_color_table [regno][3]; + return 0; +} + + +/* + * (Un)Blank the screen + */ + +void retz3_blank(int blank) +{ + short i; + + if (blank) + for (i = 0; i < 256; i++){ + reg_w(VDAC_ADDRESS_W, i); + reg_w(VDAC_DATA, 0); + reg_w(VDAC_DATA, 0); + reg_w(VDAC_DATA, 0); + } + else + for (i = 0; i < 256; i++){ + reg_w(VDAC_ADDRESS_W, i); + reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2); + reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2); + reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2); + } +} + + +void retz3_bitblt (struct fb_var_screeninfo *var, + unsigned short srcx, unsigned short srcy, unsigned + short destx, unsigned short desty, unsigned short + width, unsigned short height, unsigned short cmd, + unsigned short mask) +{ + + volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET); + unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF); + + unsigned short mod; + unsigned long tmp; + unsigned long pat, src, dst; + unsigned char blt_status; + + int i, xres_virtual = var->xres_virtual; + short bpp = (var->bits_per_pixel & 0xff); + + if (bpp < 8) + bpp = 8; + + tmp = mask | (mask << 16); + +#if 0 + /* + * Check for blitter finished before we start messing with the + * pattern. + */ + do{ + blt_status = *(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)); + }while ((blt_status & 1) == 0); +#endif + + i = 0; + do{ + *pattern++ = tmp; + }while(i++ < bpp/4); + + tmp = cmd << 8; + *(acm + ACM_RASTEROP_ROTATION/4) = tmp; + + mod = 0xc0c2; + + pat = 8 * PAT_MEM_OFF; + dst = bpp * (destx + desty * xres_virtual); + + /* + * Source is not set for clear. + */ + if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { + src = bpp * (srcx + srcy * xres_virtual); + + if (destx > srcx) { + mod &= ~0x8000; + src += bpp * (width - 1); + dst += bpp * (width - 1); + pat += bpp * 2; + } + if (desty > srcy) { + mod &= ~0x4000; + src += bpp * (height - 1) * xres_virtual; + dst += bpp * (height - 1) * xres_virtual; + pat += bpp * 4; + } + + *(acm + ACM_SOURCE/4) = cpu_to_le32(src); + } + + *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); + + *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); + + tmp = mod << 16; + *(acm + ACM_CONTROL/4) = tmp; + + tmp = width | (height << 16); + + *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); + + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; + *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; + + /* + * No reason to wait for the blitter to finish, it is better + * just to check if it has finished before we use it again. + */ +#if 1 +#if 0 + while ((*(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)) & 1) == 0); +#else + do{ + blt_status = *(((volatile unsigned char *)acm) + + (ACM_START_STATUS + 2)); + } + while ((blt_status & 1) == 0); +#endif +#endif +} + +#if 0 +void retz3_fill (unsigned short x, unsigned short y, unsigned + short width, unsigned short height, + unsigned short mode, unsigned short color) +{ + +} +#endif + + +#if 0 +/* + * Move cursor to x, y + */ +void retz3_MoveCursor (unsigned short x, unsigned short y) +{ + /* Guess we gotta deal with the cursor at some point */ +} +#endif + +/* -------------------- Interfaces to hardware functions -------------------- */ + + +static struct fb_hwswitch retz3_switch = { + retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var, + retz3_getcolreg, retz3_setcolreg, retz3_blank +}; + + +/* -------------------- Generic routines ------------------------------------ */ + + +/* + * Fill the hardware's `par' structure. + */ + +static void retz3_fb_get_par(struct retz3_fb_par *par) +{ + if (current_par_valid) + *par = current_par; + else + fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par); +} + + +static void retz3_fb_set_par(struct retz3_fb_par *par) +{ + current_par = *par; + current_par_valid = 1; +} + + +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +{ + int err, activate; + struct retz3_fb_par par; + + if ((err = fbhw->decode_var(var, &par))) + return err; + activate = var->activate; + + /* XXX ... what to do about isactive ? */ + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) + retz3_fb_set_par(&par); + fbhw->encode_var(var, &par); + var->activate = activate; + + retz3_set_video(var, ¤t_par); + + return 0; +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + fbhw->setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &fb_display[con].var, 1, + fbhw->setcolreg); +} + + +/* + * Open/Release the frame buffer device + */ + +static int retz3_fb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return 0; +} + +static int retz3_fb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +/* + * Get the Fixed Part of the Display + */ + +static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct retz3_fb_par par; + int error = 0; + + if (con == -1) + retz3_fb_get_par(&par); + else + error = fbhw->decode_var(&fb_display[con].var, &par); + return(error ? error : fbhw->encode_fix(fix, &par)); +} + + +/* + * Get the User Defined Part of the Display + */ + +static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + struct retz3_fb_par par; + int error = 0; + + if (con == -1) { + retz3_fb_get_par(&par); + error = fbhw->encode_var(var, &par); + } else + *var = fb_display[con].var; + return error; +} + + +#if 1 +static void retz3_fb_set_disp(int con) +{ + struct fb_fix_screeninfo fix; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + retz3_fb_get_fix(&fix, con); + + if (con == -1) + con = 0; + + display->screen_base = (unsigned char *)fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->can_soft_blank = 1; + display->inverse = z3fb_inverse; +} +#endif + +/* + * Set the User Defined Part of the Display + */ + +static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; + struct display *display; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + +#if 0 + if (con == -1) + con = 0; +#endif + + if ((err = do_fb_set_var(var, con == currcon))) + return err; + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + display->var = *var; + + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || + oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + + struct fb_fix_screeninfo fix; + retz3_fb_get_fix(&fix, con); + + display->screen_base = fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = z3fb_inverse; +/* + retz3_fb_set_disp(con); +*/ + if (fb_info.changevar) + (*fb_info.changevar)(con); + } + + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con); + } + } + return 0; +} + + +/* + * Get the Colormap + */ + +static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return(fb_get_cmap(cmap, &fb_display[con].var, kspc, + fbhw->getcolreg)); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + +/* + * Set the Colormap + */ + +static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<setcolreg)); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + return 0; +} + + +/* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + return -EINVAL; +} + + +/* + * RetinaZ3 Frame Buffer Specific ioctls + */ + +static int retz3_fb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con) +{ + return -EINVAL; +} + + +static struct fb_ops retz3_fb_ops = { + retz3_fb_open, retz3_fb_release, retz3_fb_get_fix, retz3_fb_get_var, + retz3_fb_set_var, retz3_fb_get_cmap, retz3_fb_set_cmap, + retz3_fb_pan_display, retz3_fb_ioctl +}; + + +__initfunc(void retz3_video_setup(char *options, int *ints)) +{ + char *this_opt; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")){ + if (!strcmp(this_opt, "inverse")) { + z3fb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt+5); + else + z3fb_mode = get_video_mode(this_opt); + } +} + + +/* + * Initialization + */ + +__initfunc(unsigned long retz3_fb_init(unsigned long mem_start)) +{ + int err; + unsigned long board_addr, board_size; + unsigned int key; + const struct ConfigDev *cd; + + struct retz3_fb_par par; + + if (!(key = zorro_find(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, 0, 0))) + return mem_start; + + cd = zorro_get_board (key); + zorro_config_board (key, 0); + board_addr = (unsigned long)cd->cd_BoardAddr; + board_size = (unsigned long)cd->cd_BoardSize; + + z3_mem = kernel_map (board_addr, board_size, + KERNELMAP_NOCACHE_SER, &mem_start); + + z3_regs = (char*) z3_mem; + z3_fbmem = z3_mem + VIDEO_MEM_OFFSET; + + /* Get memory size - for now we asume its a 4MB board */ + + z3_size = 0x00400000; /* 4 MB */ + + memset ((char*)z3_fbmem, 0, z3_size); + + fbhw = &retz3_switch; + + fbhw->init(); + + strcpy(fb_info.modename, retz3_fb_name); + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &retz3_fb_ops; + fb_info.fbvar_num = NUM_TOTAL_MODES; + fb_info.fbvar = retz3_fb_predefined; + fb_info.disp = &disp; + fb_info.switch_con = &z3fb_switch; + fb_info.updatevar = &z3fb_updatevar; + fb_info.blank = &z3fb_blank; + fb_info.setcmap = &z3fb_setcmap; + + err = register_framebuffer(&fb_info); + if (err < 0) + return mem_start; + + if (z3fb_mode == -1) + z3fb_mode = 1; + + fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par); + fbhw->encode_var(&retz3_fb_predefined[0], &par); + + do_fb_set_var(&retz3_fb_predefined[0], 0); + retz3_fb_get_var(&disp.var, -1); + + retz3_fb_set_disp(-1); + + do_install_cmap(0); + + printk("%s frame buffer device, using %ldK of video memory\n", + fb_info.modename, z3_size>>10); + + /* TODO: This driver cannot be unloaded yet */ + MOD_INC_USE_COUNT; + + return mem_start; +} + + +static int z3fb_switch(int con) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, + &fb_display[currcon].var, 1, fbhw->getcolreg); + + do_fb_set_var(&fb_display[con].var, 1); + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + +/* + * Update the `var' structure (called by fbcon.c) + * + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. + * Since it's called by a kernel driver, no range checking is done. + */ + +static int z3fb_updatevar(int con) +{ + return 0; +} + + +/* + * Blank the display. + */ + +static void z3fb_blank(int blank) +{ + fbhw->blank(blank); +} + + +/* + * Set the colormap + */ + +static int z3fb_setcmap(struct fb_cmap *cmap, int con) +{ + return(retz3_fb_set_cmap(cmap, 1, con)); +} + + +/* + * Get a Video Mode + */ + +static int get_video_mode(const char *name) +{ + short i; + + for (i = 1; i <= NUM_PREDEF_MODES; i++) + if (!strcmp(name, retz3_fb_modenames[i])){ + retz3_fb_predefined[0] = retz3_fb_predefined[i]; + return i; + } + return -1; +} + + +#ifdef MODULE +int init_module(void) +{ + return(retz3_fb_init(NULL)); +} + +void cleanup_module(void) +{ + /* + * Not reached because the usecount will never + * be decremented to zero + */ + unregister_framebuffer(&fb_info); + /* TODO: clean up ... */ +} +#endif /* MODULE */ + + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(retz3_bitblt); diff -u --recursive --new-file v2.1.66/linux/drivers/video/retz3fb.h linux/drivers/video/retz3fb.h --- v2.1.66/linux/drivers/video/retz3fb.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/retz3fb.h Tue Sep 16 02:30:26 1997 @@ -0,0 +1,286 @@ +/* + * linux/drivers/video/retz3fb.h -- Defines and macros for the RetinaZ3 frame + * buffer device + * + * Copyright (C) 1997 Jes Sorensen + * + * History: + * - 22 Jan 97: Initial work + * + * + * 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. + */ + +/* + * Macros to read and write to registers. + */ +#define reg_w(reg,dat) (*(z3_regs + reg) = dat) +#define reg_r(reg) (*(z3_regs + reg)) + +/* + * Macro to access the sequencer. + */ +#define seq_w(sreg,sdat) \ + do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0) + +/* + * Macro to access the CRT controller. + */ +#define crt_w(creg,cdat) \ + do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0) + +/* + * Macro to access the graphics controller. + */ +#define gfx_w(greg,gdat) \ + do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0) + +/* + * Macro to access the attribute controller. + */ +#define attr_w(areg,adat) \ + do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0) + +/* + * Macro to access the pll. + */ +#define pll_w(preg,pdat) \ + do{ reg_w(PLL_IDX, preg); \ + reg_w(PLL_DATA, (pdat & 0xff)); \ + reg_w(PLL_DATA, (pdat >> 8));\ + } while(0) + +/* + * Offsets + */ +#define VIDEO_MEM_OFFSET 0x00c00000 +#define ACM_OFFSET 0x00b00000 + +/* + * Accelerator Control Menu + */ +#define ACM_PRIMARY_OFFSET 0x00 +#define ACM_SECONDARY_OFFSET 0x04 +#define ACM_MODE_CONTROL 0x08 +#define ACM_CURSOR_POSITION 0x0c +#define ACM_START_STATUS 0x30 +#define ACM_CONTROL 0x34 +#define ACM_RASTEROP_ROTATION 0x38 +#define ACM_BITMAP_DIMENSION 0x3c +#define ACM_DESTINATION 0x40 +#define ACM_SOURCE 0x44 +#define ACM_PATTERN 0x48 +#define ACM_FOREGROUND 0x4c +#define ACM_BACKGROUND 0x50 + +/* + * Video DAC addresses + */ +#define VDAC_ADDRESS 0x03c8 +#define VDAC_ADDRESS_W 0x03c8 +#define VDAC_ADDRESS_R 0x03c7 +#define VDAC_STATE 0x03c7 +#define VDAC_DATA 0x03c9 +#define VDAC_MASK 0x03c6 + +/* + * Sequencer + */ +#define SEQ_IDX 0x03c4 /* Sequencer Index */ +#define SEQ_DATA 0x03c5 +#define SEQ_RESET 0x00 +#define SEQ_CLOCKING_MODE 0x01 +#define SEQ_MAP_MASK 0x02 +#define SEQ_CHAR_MAP_SELECT 0x03 +#define SEQ_MEMORY_MODE 0x04 +#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */ +#define SEQ_UNKNOWN1 0x06 +#define SEQ_UNKNOWN2 0x07 +#define SEQ_CHIP_ID 0x08 +#define SEQ_UNKNOWN3 0x09 +#define SEQ_CURSOR_COLOR1 0x0a +#define SEQ_CURSOR_COLOR0 0x0b +#define SEQ_CURSOR_CONTROL 0x0c +#define SEQ_CURSOR_X_LOC_HI 0x0d +#define SEQ_CURSOR_X_LOC_LO 0x0e +#define SEQ_CURSOR_Y_LOC_HI 0x0f +#define SEQ_CURSOR_Y_LOC_LO 0x10 +#define SEQ_CURSOR_X_INDEX 0x11 +#define SEQ_CURSOR_Y_INDEX 0x12 +#define SEQ_CURSOR_STORE_HI 0x13 +#define SEQ_CURSOR_STORE_LO 0x14 +#define SEQ_CURSOR_ST_OFF_HI 0x15 +#define SEQ_CURSOR_ST_OFF_LO 0x16 +#define SEQ_CURSOR_PIXELMASK 0x17 +#define SEQ_PRIM_HOST_OFF_HI 0x18 +#define SEQ_PRIM_HOST_OFF_LO 0x19 +#define SEQ_LINEAR_0 0x1a +#define SEQ_LINEAR_1 0x1b +#define SEQ_SEC_HOST_OFF_HI 0x1c +#define SEQ_SEC_HOST_OFF_LO 0x1d +#define SEQ_EXTENDED_MEM_ENA 0x1e +#define SEQ_EXT_CLOCK_MODE 0x1f +#define SEQ_EXT_VIDEO_ADDR 0x20 +#define SEQ_EXT_PIXEL_CNTL 0x21 +#define SEQ_BUS_WIDTH_FEEDB 0x22 +#define SEQ_PERF_SELECT 0x23 +#define SEQ_COLOR_EXP_WFG 0x24 +#define SEQ_COLOR_EXP_WBG 0x25 +#define SEQ_EXT_RW_CONTROL 0x26 +#define SEQ_MISC_FEATURE_SEL 0x27 +#define SEQ_COLOR_KEY_CNTL 0x28 +#define SEQ_COLOR_KEY_MATCH0 0x29 +#define SEQ_COLOR_KEY_MATCH1 0x2a +#define SEQ_COLOR_KEY_MATCH2 0x2b +#define SEQ_UNKNOWN6 0x2c +#define SEQ_CRC_CONTROL 0x2d +#define SEQ_CRC_DATA_LOW 0x2e +#define SEQ_CRC_DATA_HIGH 0x2f +#define SEQ_MEMORY_MAP_CNTL 0x30 +#define SEQ_ACM_APERTURE_1 0x31 +#define SEQ_ACM_APERTURE_2 0x32 +#define SEQ_ACM_APERTURE_3 0x33 +#define SEQ_BIOS_UTILITY_0 0x3e +#define SEQ_BIOS_UTILITY_1 0x3f + +/* + * Graphics Controller + */ +#define GFX_IDX 0x03ce +#define GFX_DATA 0x03cf +#define GFX_SET_RESET 0x00 +#define GFX_ENABLE_SET_RESET 0x01 +#define GFX_COLOR_COMPARE 0x02 +#define GFX_DATA_ROTATE 0x03 +#define GFX_READ_MAP_SELECT 0x04 +#define GFX_GRAPHICS_MODE 0x05 +#define GFX_MISC 0x06 +#define GFX_COLOR_XCARE 0x07 +#define GFX_BITMASK 0x08 + +/* + * CRT Controller + */ +#define CRT_IDX 0x03d4 +#define CRT_DATA 0x03d5 +#define CRT_HOR_TOTAL 0x00 +#define CRT_HOR_DISP_ENA_END 0x01 +#define CRT_START_HOR_BLANK 0x02 +#define CRT_END_HOR_BLANK 0x03 +#define CRT_START_HOR_RETR 0x04 +#define CRT_END_HOR_RETR 0x05 +#define CRT_VER_TOTAL 0x06 +#define CRT_OVERFLOW 0x07 +#define CRT_PRESET_ROW_SCAN 0x08 +#define CRT_MAX_SCAN_LINE 0x09 +#define CRT_CURSOR_START 0x0a +#define CRT_CURSOR_END 0x0b +#define CRT_START_ADDR_HIGH 0x0c +#define CRT_START_ADDR_LOW 0x0d +#define CRT_CURSOR_LOC_HIGH 0x0e +#define CRT_CURSOR_LOC_LOW 0x0f +#define CRT_START_VER_RETR 0x10 +#define CRT_END_VER_RETR 0x11 +#define CRT_VER_DISP_ENA_END 0x12 +#define CRT_OFFSET 0x13 +#define CRT_UNDERLINE_LOC 0x14 +#define CRT_START_VER_BLANK 0x15 +#define CRT_END_VER_BLANK 0x16 +#define CRT_MODE_CONTROL 0x17 +#define CRT_LINE_COMPARE 0x18 +#define CRT_UNKNOWN1 0x19 +#define CRT_UNKNOWN2 0x1a +#define CRT_UNKNOWN3 0x1b +#define CRT_UNKNOWN4 0x1c +#define CRT_UNKNOWN5 0x1d +#define CRT_UNKNOWN6 0x1e +#define CRT_UNKNOWN7 0x1f +#define CRT_UNKNOWN8 0x20 +#define CRT_UNKNOWN9 0x21 +#define CRT_UNKNOWN10 0x22 +#define CRT_UNKNOWN11 0x23 +#define CRT_UNKNOWN12 0x24 +#define CRT_UNKNOWN13 0x25 +#define CRT_UNKNOWN14 0x26 +#define CRT_UNKNOWN15 0x27 +#define CRT_UNKNOWN16 0x28 +#define CRT_UNKNOWN17 0x29 +#define CRT_UNKNOWN18 0x2a +#define CRT_UNKNOWN19 0x2b +#define CRT_UNKNOWN20 0x2c +#define CRT_UNKNOWN21 0x2d +#define CRT_UNKNOWN22 0x2e +#define CRT_UNKNOWN23 0x2f +#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */ +#define CRT_EXT_START_ADDR 0x31 +#define CRT_EXT_HOR_TIMING2 0x32 +#define CRT_EXT_VER_TIMING 0x33 +#define CRT_MONITOR_POWER 0x34 + +/* + * General Registers + */ +#define GREG_STATUS0_R 0x03c2 +#define GREG_STATUS1_R 0x03da +#define GREG_MISC_OUTPUT_R 0x03cc +#define GREG_MISC_OUTPUT_W 0x03c2 +#define GREG_FEATURE_CONTROL_R 0x03ca +#define GREG_FEATURE_CONTROL_W 0x03da +#define GREG_POS 0x0102 + +/* + * Attribute Controller + */ +#define ACT_IDX 0x03C0 +#define ACT_ADDRESS_R 0x03C0 +#define ACT_DATA 0x03C0 +#define ACT_ADDRESS_RESET 0x03DA +#define ACT_PALETTE0 0x00 +#define ACT_PALETTE1 0x01 +#define ACT_PALETTE2 0x02 +#define ACT_PALETTE3 0x03 +#define ACT_PALETTE4 0x04 +#define ACT_PALETTE5 0x05 +#define ACT_PALETTE6 0x06 +#define ACT_PALETTE7 0x07 +#define ACT_PALETTE8 0x08 +#define ACT_PALETTE9 0x09 +#define ACT_PALETTE10 0x0A +#define ACT_PALETTE11 0x0B +#define ACT_PALETTE12 0x0C +#define ACT_PALETTE13 0x0D +#define ACT_PALETTE14 0x0E +#define ACT_PALETTE15 0x0F +#define ACT_ATTR_MODE_CNTL 0x10 +#define ACT_OVERSCAN_COLOR 0x11 +#define ACT_COLOR_PLANE_ENA 0x12 +#define ACT_HOR_PEL_PANNING 0x13 +#define ACT_COLOR_SELECT 0x14 + +/* + * PLL + */ +#define PLL_IDX 0x83c8 +#define PLL_DATA 0x83c9 + +/* + * Blitter operations + */ +#define Z3BLTclear 0x00 /* 0 */ +#define Z3BLTand 0x80 /* src AND dst */ +#define Z3BLTandReverse 0x40 /* src AND NOT dst */ +#define Z3BLTcopy 0xc0 /* src */ +#define Z3BLTandInverted 0x20 /* NOT src AND dst */ +#define Z3BLTnoop 0xa0 /* dst */ +#define Z3BLTxor 0x60 /* src XOR dst */ +#define Z3BLTor 0xe0 /* src OR dst */ +#define Z3BLTnor 0x10 /* NOT src AND NOT dst */ +#define Z3BLTequiv 0x90 /* NOT src XOR dst */ +#define Z3BLTinvert 0x50 /* NOT dst */ +#define Z3BLTorReverse 0xd0 /* src OR NOT dst */ +#define Z3BLTcopyInverted 0x30 /* NOT src */ +#define Z3BLTorInverted 0xb0 /* NOT src OR dst */ +#define Z3BLTnand 0x70 /* NOT src OR NOT dst */ +#define Z3BLTset 0xf0 /* 1 */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/s3blit.h linux/drivers/video/s3blit.h --- v2.1.66/linux/drivers/video/s3blit.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/s3blit.h Tue Sep 16 02:30:32 1997 @@ -0,0 +1,74 @@ +/* s3 commands */ +#define S3_BITBLT 0xc011 +#define S3_TWOPOINTLINE 0x2811 +#define S3_FILLEDRECT 0x40b1 + +#define S3_FIFO_EMPTY 0x0400 +#define S3_HDW_BUSY 0x0200 + +/* Enhanced register mapping (MMIO mode) */ + +#define S3_READ_SEL 0xbee8 /* offset f */ +#define S3_MULT_MISC 0xbee8 /* offset e */ +#define S3_ERR_TERM 0x92e8 +#define S3_FRGD_COLOR 0xa6e8 +#define S3_BKGD_COLOR 0xa2e8 +#define S3_PIXEL_CNTL 0xbee8 /* offset a */ +#define S3_FRGD_MIX 0xbae8 +#define S3_BKGD_MIX 0xb6e8 +#define S3_CUR_Y 0x82e8 +#define S3_CUR_X 0x86e8 +#define S3_DESTY_AXSTP 0x8ae8 +#define S3_DESTX_DIASTP 0x8ee8 +#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */ +#define S3_MAJ_AXIS_PCNT 0x96e8 +#define S3_CMD 0x9ae8 +#define S3_GP_STAT 0x9ae8 +#define S3_ADVFUNC_CNTL 0x4ae8 +#define S3_WRT_MASK 0xaae8 +#define S3_RD_MASK 0xaee8 + +/* Enhanced register mapping (Packed MMIO mode, write only) */ +#define S3_ALT_CURXY 0x8100 +#define S3_ALT_CURXY2 0x8104 +#define S3_ALT_STEP 0x8108 +#define S3_ALT_STEP2 0x810c +#define S3_ALT_ERR 0x8110 +#define S3_ALT_CMD 0x8118 +#define S3_ALT_MIX 0x8134 +#define S3_ALT_PCNT 0x8148 +#define S3_ALT_PAT 0x8168 + +/* Drawing modes */ +#define S3_NOTCUR 0x0000 +#define S3_LOGICALZERO 0x0001 +#define S3_LOGICALONE 0x0002 +#define S3_LEAVEASIS 0x0003 +#define S3_NOTNEW 0x0004 +#define S3_CURXORNEW 0x0005 +#define S3_NOT_CURXORNEW 0x0006 +#define S3_NEW 0x0007 +#define S3_NOTCURORNOTNEW 0x0008 +#define S3_CURORNOTNEW 0x0009 +#define S3_NOTCURORNEW 0x000a +#define S3_CURORNEW 0x000b +#define S3_CURANDNEW 0x000c +#define S3_NOTCURANDNEW 0x000d +#define S3_CURANDNOTNEW 0x000e +#define S3_NOTCURANDNOTNEW 0x000f + +#define S3_CRTC_ADR 0x03d4 +#define S3_CRTC_DATA 0x03d5 + +#define S3_REG_LOCK2 0x39 +#define S3_HGC_MODE 0x45 + +#define S3_HWGC_ORGX_H 0x46 +#define S3_HWGC_ORGX_L 0x47 +#define S3_HWGC_ORGY_H 0x48 +#define S3_HWGC_ORGY_L 0x49 +#define S3_HWGC_DX 0x4e +#define S3_HWGC_DY 0x4f + + +#define S3_LAW_CTL 0x58 diff -u --recursive --new-file v2.1.66/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c --- v2.1.66/linux/drivers/video/tgafb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/tgafb.c Mon Nov 24 01:18:59 1997 @@ -0,0 +1,938 @@ +/* + * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This driver is partly based on the original TGA console driver + * + * Copyright (C) 1995 Jay Estabrook + * + * 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. + */ + + +/* KNOWN PROBLEMS/TO DO ===================================================== * + * + * - How to set a single color register? + * + * - We don't have support for CFB32 yet (fbcon-cfb32.c) + * + * - Hardware cursor (useful for other graphics boards too) + * + * KNOWN PROBLEMS/TO DO ==================================================== */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* TGA hardware description (minimal) */ +/* + * Offsets within Memory Space + */ +#define TGA_ROM_OFFSET 0x0000000 +#define TGA_REGS_OFFSET 0x0100000 +#define TGA_8PLANE_FB_OFFSET 0x0200000 +#define TGA_24PLANE_FB_OFFSET 0x0804000 +#define TGA_24PLUSZ_FB_OFFSET 0x1004000 + +#define TGA_PLANEMASK_REG 0x0028 +#define TGA_MODE_REG 0x0030 +#define TGA_RASTEROP_REG 0x0034 +#define TGA_DEEP_REG 0x0050 +#define TGA_PIXELMASK_REG 0x005c +#define TGA_CURSOR_BASE_REG 0x0060 +#define TGA_HORIZ_REG 0x0064 +#define TGA_VERT_REG 0x0068 +#define TGA_BASE_ADDR_REG 0x006c +#define TGA_VALID_REG 0x0070 +#define TGA_CURSOR_XY_REG 0x0074 +#define TGA_INTR_STAT_REG 0x007c +#define TGA_RAMDAC_SETUP_REG 0x00c0 +#define TGA_BLOCK_COLOR0_REG 0x0140 +#define TGA_BLOCK_COLOR1_REG 0x0144 +#define TGA_CLOCK_REG 0x01e8 +#define TGA_RAMDAC_REG 0x01f0 +#define TGA_CMD_STAT_REG 0x01f8 + +/* + * useful defines for managing the BT485 on the 8-plane TGA + */ +#define BT485_READ_BIT 0x01 +#define BT485_WRITE_BIT 0x00 + +#define BT485_ADDR_PAL_WRITE 0x00 +#define BT485_DATA_PAL 0x02 +#define BT485_PIXEL_MASK 0x04 +#define BT485_ADDR_PAL_READ 0x06 +#define BT485_ADDR_CUR_WRITE 0x08 +#define BT485_DATA_CUR 0x0a +#define BT485_CMD_0 0x0c +#define BT485_ADDR_CUR_READ 0x0e +#define BT485_CMD_1 0x10 +#define BT485_CMD_2 0x12 +#define BT485_STATUS 0x14 +#define BT485_CMD_3 0x14 +#define BT485_CUR_RAM 0x16 +#define BT485_CUR_LOW_X 0x18 +#define BT485_CUR_HIGH_X 0x1a +#define BT485_CUR_LOW_Y 0x1c +#define BT485_CUR_HIGH_Y 0x1e + +/* + * useful defines for managing the BT463 on the 24-plane TGAs + */ +#define BT463_ADDR_LO 0x0 +#define BT463_ADDR_HI 0x1 +#define BT463_REG_ACC 0x2 +#define BT463_PALETTE 0x3 + +#define BT463_CUR_CLR_0 0x0100 +#define BT463_CUR_CLR_1 0x0101 + +#define BT463_CMD_REG_0 0x0201 +#define BT463_CMD_REG_1 0x0202 +#define BT463_CMD_REG_2 0x0203 + +#define BT463_READ_MASK_0 0x0205 +#define BT463_READ_MASK_1 0x0206 +#define BT463_READ_MASK_2 0x0207 +#define BT463_READ_MASK_3 0x0208 + +#define BT463_BLINK_MASK_0 0x0209 +#define BT463_BLINK_MASK_1 0x020a +#define BT463_BLINK_MASK_2 0x020b +#define BT463_BLINK_MASK_3 0x020c + +#define BT463_WINDOW_TYPE_BASE 0x0300 + + +int tga_type; +unsigned int tga_mem_base; +unsigned long tga_fb_base; +unsigned long tga_regs_base; + +static unsigned int fb_offset_presets[4] __initdata = { + TGA_8PLANE_FB_OFFSET, + TGA_24PLANE_FB_OFFSET, + 0xffffffff, + TGA_24PLUSZ_FB_OFFSET +}; + +static unsigned int deep_presets[4] __initdata = { + 0x00014000, + 0x0001440d, + 0xffffffff, + 0x0001441d +}; + +static unsigned int rasterop_presets[4] __initdata = { + 0x00000003, + 0x00000303, + 0xffffffff, + 0x00000303 +}; + +static unsigned int mode_presets[4] __initdata = { + 0x00002000, + 0x00002300, + 0xffffffff, + 0x00002300 +}; + +static unsigned int base_addr_presets[4] __initdata = { + 0x00000000, + 0x00000001, + 0xffffffff, + 0x00000001 +}; + +#define TGA_WRITE_REG(v,r) \ + { writel((v), tga_regs_base+(r)); mb(); } + +#define TGA_READ_REG(r) readl(tga_regs_base+(r)) + +#define BT485_WRITE(v,r) \ + TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG); \ + TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG); + +#define BT463_LOAD_ADDR(a) \ + TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \ + TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \ + TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \ + TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG); + +#define BT463_WRITE(m,a,v) \ + BT463_LOAD_ADDR((a)); \ + TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \ + TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG); + + +unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 }; + +const unsigned long bt485_cursor_source[64] __initdata = { + 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, + 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, + 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, + 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +const unsigned int bt463_cursor_source[256] __initdata = { + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0xffff0000, 0x00000000, 0x00000000, 0x00000000, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +static int currcon = 0; +static struct display disp; +static struct fb_info fb_info; +static struct { u_char red, green, blue, pad; } palette[256]; +static char tgafb_name[16] = "DEC TGA "; + +static struct fb_fix_screeninfo fb_fix; +static struct fb_var_screeninfo fb_var = { 0, }; + + + /* + * Interface used by the world + */ + +void tgafb_video_setup(char *options, int *ints); + +static int tgafb_open(int fbidx); +static int tgafb_release(int fbidx); +static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int tgafb_get_var(struct fb_var_screeninfo *var, int con); +static int tgafb_set_var(struct fb_var_screeninfo *var, int con); +static int tgafb_pan_display(struct fb_var_screeninfo *var, int con); +static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con); + + + /* + * Interface to the low level console driver + */ + +unsigned long tgafb_init(unsigned long mem_start); +static int tgafbcon_switch(int con); +static int tgafbcon_updatevar(int con); +static void tgafbcon_blank(int blank); +static int tgafbcon_setcmap(struct fb_cmap *cmap, int con); + + + /* + * Internal routines + */ + +static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); +static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); +#if 1 +static void tga_update_palette(void); +#endif +static void do_install_cmap(int con); + + +static struct fb_ops tgafb_ops = { + tgafb_open, tgafb_release, tgafb_get_fix, tgafb_get_var, tgafb_set_var, + tgafb_get_cmap, tgafb_set_cmap, tgafb_pan_display, tgafb_ioctl +}; + + + /* + * Open/Release the frame buffer device + */ + +static int tgafb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int tgafb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + + + /* + * Get the Fixed Part of the Display + */ + +static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + memcpy(fix, &fb_fix, sizeof(fb_fix)); + return 0; +} + + + /* + * Get the User Defined Part of the Display + */ + +static int tgafb_get_var(struct fb_var_screeninfo *var, int con) +{ + memcpy(var, &fb_var, sizeof(fb_var)); + return 0; +} + + + /* + * Set the User Defined Part of the Display + */ + +static int tgafb_set_var(struct fb_var_screeninfo *var, int con) +{ + struct display *display; + int oldbpp = -1, err; + + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + if (var->xres > fb_var.xres || var->yres > fb_var.yres || + var->xres_virtual > fb_var.xres_virtual || + var->yres_virtual > fb_var.yres_virtual || + var->bits_per_pixel > fb_var.bits_per_pixel || + var->nonstd || + (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + memcpy(var, &fb_var, sizeof(fb_var)); + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldbpp = display->var.bits_per_pixel; + display->var = *var; + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con); + } + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int tgafb_pan_display(struct fb_var_screeninfo *var, int con) +{ + if (var->xoffset || var->yoffset) + return -EINVAL; + else + return 0; +} + + /* + * Get the Colormap + */ + +static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, &fb_display[con].var, kspc, tgafb_getcolreg); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + /* + * Set the Colormap + */ + +static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<> 12) & 0x0f; + switch (tga_type) { + case 0: + strcat(tgafb_name, "8plane"); + break; + case 1: + strcat(tgafb_name, "24plane"); + break; + case 3: + strcat(tgafb_name, "24plusZ"); + break; + default: + printk("TGA type (0x%x) unrecognized!\n", tga_type); + return mem_start; + } + strcpy(fb_fix.id, tgafb_name); + + tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET); + tga_fb_base = ((unsigned long)tga_mem_base + fb_offset_presets[tga_type]); + + /* first, disable video timing */ + TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */ + + /* write the DEEP register */ + while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ + continue; + + mb(); + TGA_WRITE_REG(deep_presets[tga_type], TGA_DEEP_REG); + while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ + continue; + mb(); + + /* write some more registers */ + TGA_WRITE_REG(rasterop_presets[tga_type], TGA_RASTEROP_REG); + TGA_WRITE_REG(mode_presets[tga_type], TGA_MODE_REG); + TGA_WRITE_REG(base_addr_presets[tga_type], TGA_BASE_ADDR_REG); + + /* write the PLL for 640x480 @ 60Hz */ + for (i = 0; i <= 6; i++) { + for (j = 0; j <= 7; j++) { + temp = (PLLbits[i] >> (7-j)) & 1; + if (i == 6 && j == 7) + temp |= 2; + TGA_WRITE_REG(temp, TGA_CLOCK_REG); + } + } + + /* write some more registers */ + TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG); + TGA_WRITE_REG(0xffffffff, TGA_PIXELMASK_REG); + TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG); + TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG); + + /* init video timing regs for 640x480 @ 60 Hz */ + TGA_WRITE_REG(0x018608a0, TGA_HORIZ_REG); + TGA_WRITE_REG(0x084251e0, TGA_VERT_REG); + + if (tga_type == 0) { /* 8-plane */ + + fb_var.bits_per_pixel = 8; + fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; + + /* init BT485 RAMDAC registers */ + BT485_WRITE(0xa2, BT485_CMD_0); + BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE); + BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */ + BT485_WRITE(0x40, BT485_CMD_1); + BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */ + BT485_WRITE(0xff, BT485_PIXEL_MASK); + + /* fill palette registers */ + BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + } + for (i = 0; i < 240*3; i += 4) { + TGA_WRITE_REG(0x55|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); + } + + /* initialize RAMDAC cursor colors */ + BT485_WRITE(0, BT485_ADDR_CUR_WRITE); + + BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */ + BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */ + BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */ + + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */ + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */ + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */ + + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */ + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */ + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */ + + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */ + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */ + BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */ + + /* initialize RAMDAC cursor RAM */ + BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); + cbp = (unsigned char *)bt485_cursor_source; + for (i = 0; i < 512; i++) { + BT485_WRITE(*cbp++, BT485_CUR_RAM); + } + for (i = 0; i < 512; i++) { + BT485_WRITE(0xff, BT485_CUR_RAM); + } + + } else { /* 24-plane or 24plusZ */ + + fb_var.bits_per_pixel = 32; + fb_fix.visual = FB_VISUAL_TRUECOLOR; + + TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */ + + /* + * init some registers + */ + BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40); + BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08); + BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2, 0x40); + + BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff); + BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff); + BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_2, 0xff); + BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); + + BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); + BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); + BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); + BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); + + /* + * fill the palette + */ + BT463_LOAD_ADDR(0x0000); + TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + TGA_WRITE_REG(default_red[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(default_grn[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(default_blu[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + } + for (i = 0; i < 512*3; i += 4) { + TGA_WRITE_REG(0x55|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + } + + /* + * fill window type table after start of vertical retrace + */ + while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01)) + continue; + TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG); + mb(); + while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01)) + continue; + TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG); + + BT463_LOAD_ADDR(BT463_WINDOW_TYPE_BASE); + TGA_WRITE_REG((BT463_REG_ACC<<2), TGA_RAMDAC_SETUP_REG); + + for (i = 0; i < 16; i++) { + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x01|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + } + + /* + * init cursor colors + */ + BT463_LOAD_ADDR(BT463_CUR_CLR_0); + + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */ + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */ + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */ + + TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */ + TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */ + TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */ + + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + + /* + * finally, init the cursor shape + */ + temp = tga_fb_base - 1024; /* this assumes video starts at base + and base is beyond memory start*/ + + for (i = 0; i < 256; i++) { + writel(bt463_cursor_source[i], temp + i*4); + } + TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG); + } + + /* finally, enable video scan & cursor + (and pray for the monitor... :-) */ + TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */ + + fb_var.xres = fb_var.xres_virtual = 640; + fb_var.yres = fb_var.yres_virtual = 480; + fb_fix.line_length = 80*fb_var.bits_per_pixel; + fb_fix.smem_start = (char *)tga_fb_base; + fb_fix.smem_len = fb_fix.line_length*fb_var.yres; + fb_fix.type = FB_TYPE_PACKED_PIXELS; + fb_fix.type_aux = 0; + fb_fix.mmio_start = (unsigned char *)tga_regs_base; + fb_fix.mmio_len = 0x1000; /* Is this sufficient? */ + + fb_var.xoffset = fb_var.yoffset = 0; + fb_var.grayscale = 0; + fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0; + fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8; + fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0; + fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0; + fb_var.nonstd = 0; + fb_var.activate = 0; + fb_var.height = fb_var.width = -1; + fb_var.accel = FB_ACCEL_TGA; + fb_var.pixclock = 39722; + fb_var.left_margin = 40; + fb_var.right_margin = 24; + fb_var.upper_margin = 32; + fb_var.lower_margin = 11; + fb_var.hsync_len = 96; + fb_var.vsync_len = 2; + fb_var.sync = 0; + fb_var.vmode = FB_VMODE_NONINTERLACED; + + disp.var = fb_var; + disp.cmap.start = 0; + disp.cmap.len = 0; + disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL; + disp.screen_base = fb_fix.smem_start; + disp.visual = fb_fix.visual; + disp.type = fb_fix.type; + disp.type_aux = fb_fix.type_aux; + disp.ypanstep = 0; + disp.ywrapstep = 0; + disp.line_length = fb_fix.line_length; + disp.can_soft_blank = 1; + disp.inverse = 0; + + strcpy(fb_info.modename, tgafb_name); + fb_info.node = -1; + fb_info.fbops = &tgafb_ops; + fb_info.fbvar_num = 1; + fb_info.fbvar = &fb_var; + fb_info.disp = &disp; + fb_info.fontname[0] = '\0'; + fb_info.changevar = NULL; + fb_info.switch_con = &tgafbcon_switch; + fb_info.updatevar = &tgafbcon_updatevar; + fb_info.blank = &tgafbcon_blank; + fb_info.setcmap = &tgafbcon_setcmap; + + err = register_framebuffer(&fb_info); + if (err < 0) + return mem_start; + + tgafb_set_var(&fb_var, -1); + + printk("%s frame buffer device\n", tgafb_name); + return mem_start; +} + + +static int tgafbcon_switch(int con) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, + tgafb_getcolreg); + + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int tgafbcon_updatevar(int con) +{ + /* Nothing */ + return 0; +} + + /* + * Blank the display. + */ + +static void tgafbcon_blank(int blank) +{ + /* Nothing */ +} + + /* + * Set the colormap + */ + +static int tgafbcon_setcmap(struct fb_cmap *cmap, int con) +{ + return(tgafb_set_cmap(cmap, 1, con)); +} + + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp) +{ + if (regno > 255) + return 1; + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp) +{ + if (regno > 255) + return 1; + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + /* How to set a single color register?? */ + + return 0; +} + + +#if 1 + /* + * FIXME: since I don't know how to set a single arbitrary color register, + * all color palette registers have to be updated + */ + +static void tga_update_palette(void) +{ + int i; + + if (tga_type == 0) { /* 8-plane */ + BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + for (i = 0; i < 256; i++) { + TGA_WRITE_REG(palette[i].red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(palette[i].green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(palette[i].blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + } + } else { + BT463_LOAD_ADDR(0x0000); + TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); + + for (i = 0; i < 256; i++) { + TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + } + } +} +#endif + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + tgafb_setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &fb_display[con].var, 1, tgafb_setcolreg); +#if 1 + tga_update_palette(); +#endif +} + + +#if 0 /* No cursor stuff yet */ + +/* + * Hide the cursor from view, during blanking, usually... + */ +void +hide_cursor(void) +{ + unsigned long flags; + save_flags(flags); cli(); + + if (tga_type == 0) { + BT485_WRITE(0x20, BT485_CMD_2); + } else { + TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */ + } + + restore_flags(flags); +} + +void +set_cursor(int currcons) +{ + unsigned int idx, xt, yt, row, col; + unsigned long flags; + + if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) + return; + + if (__real_origin != __origin) + __set_origin(__real_origin); + + save_flags(flags); cli(); + + if (deccm) { + idx = (pos - video_mem_base) >> 1; + col = idx % 80; + row = (idx - col) / 80; + + if (tga_type == 0) { /* 8-plane */ + + xt = col * TGA_F_WIDTH + 64; + yt = row * TGA_F_HEIGHT_PADDED + 64; + + /* make sure it's enabled */ + BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */ + + BT485_WRITE(xt, BT485_CUR_LOW_X); + BT485_WRITE((xt >> 8), BT485_CUR_HIGH_X); + BT485_WRITE(yt, BT485_CUR_LOW_Y); + BT485_WRITE((yt >> 8), BT485_CUR_HIGH_Y); + + } else { + + xt = col * TGA_F_WIDTH + 144; + yt = row * TGA_F_HEIGHT_PADDED + 35; + + TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */ + TGA_WRITE_REG(xt | (yt << 12), TGA_CURSOR_XY_REG); + } + + } else + hide_cursor(); + restore_flags(flags); +} + +#endif diff -u --recursive --new-file v2.1.66/linux/drivers/video/txtcon.c linux/drivers/video/txtcon.c --- v2.1.66/linux/drivers/video/txtcon.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/txtcon.c Mon Nov 24 01:19:01 1997 @@ -0,0 +1,153 @@ +/* + * linux/drivers/video/txtcon.c -- Low level text mode based console driver + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is currently only a skeleton, since all Amigas and Ataris have + * bitmapped graphics. + * + * + * 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 + + + /* + * Interface used by the world + */ + +static int txtcon_startup(u_long *kmem_start, const char **display_desc); +static void txtcon_init(struct vc_data *conp); +static int txtcon_deinit(struct vc_data *conp); +static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width); +static int txtcon_putc(struct vc_data *conp, int c, int y, int x); +static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y, + int x); +static int txtcon_cursor(struct vc_data *conp, int mode); +static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count); +static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width); +static int txtcon_switch(struct vc_data *conp); +static int txtcon_blank(int blank); +static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data); +static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data); +static int txtcon_set_palette(struct vc_data *conp, unsigned char *table); +static int txtcon_scrolldelta(int lines); + + +static int txtcon_startup(u_long *kmem_start, const char **display_desc) +{ + return -ENODEV; +} + + +static void txtcon_init(struct vc_data *conp) +{ +} + + +static int txtcon_deinit(struct vc_data *conp) +{ + return 0; +} + + +/* ====================================================================== */ + +/* txtcon_XXX routines - interface used by the world */ + + +static int txtcon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + return -ENOSYS; +} + + +static int txtcon_putc(struct vc_data *conp, int c, int y, int x) +{ + return -ENOSYS; +} + + +static int txtcon_putcs(struct vc_data *conp, const char *s, int count, int y, + int x) +{ + return -ENOSYS; +} + + +static int txtcon_cursor(struct vc_data *conp, int mode) +{ + return -ENOSYS; +} + + +static int txtcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) +{ + return -ENOSYS; +} + + +static int txtcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + return -ENOSYS; +} + + +static int txtcon_switch(struct vc_data *conp) +{ + return -ENOSYS; +} + + +static int txtcon_blank(int blank) +{ + return -ENOSYS; +} + + +static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data) +{ + return -ENOSYS; +} + + +static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data) +{ + return -ENOSYS; +} + + +static int txtcon_set_palette(struct vc_data *conp, unsigned char *table) +{ + return -ENOSYS; +} + + +static int txtcon_scrolldelta(int lines) +{ + return -ENOSYS; +} + + +/* ====================================================================== */ + + /* + * The console `switch' structure for the text mode based console + */ + +struct consw txt_con = { + txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc, + txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch, + txtcon_blank, txtcon_get_font, txtcon_set_font, txtcon_set_palette, + txtcon_scrolldelta +}; diff -u --recursive --new-file v2.1.66/linux/drivers/video/vfb.c linux/drivers/video/vfb.c --- v2.1.66/linux/drivers/video/vfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/vfb.c Mon Nov 24 01:19:01 1997 @@ -0,0 +1,601 @@ +/* + * linux/drivers/video/vfb.c -- Virtual frame buffer device + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * 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 +#include +#include +#include +#include +#include + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + + + /* + * RAM we reserve for the frame buffer. This defines the maximum screen + * size + * + * The default can be overridden if the driver is compiled as a module + */ + +#define VIDEOMEMSIZE (1*1024*1024) /* 1 MB */ + +static u_long videomemory, videomemorysize = VIDEOMEMSIZE; +MODULE_PARM(videomemorysize, "l"); +static int currcon = 0; +static struct display disp; +static struct fb_info fb_info; +static struct { u_char red, green, blue, pad; } palette[256]; +static char virtual_fb_name[16] = "Virtual FB"; + +static struct fb_var_screeninfo virtual_fb_predefined[] = { + + /* + * Autodetect (Default) Video Mode + */ + + { + /* 640x480, 8 bpp */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCEL_NONE, 20000, 64, 64, 32, 32, 64, 2, + 0, FB_VMODE_NONINTERLACED + }, + + /* + * User Defined Video Modes (8) + */ + + { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } +}; + +#define NUM_USER_MODES (8) +#define NUM_TOTAL_MODES arraysize(virtual_fb_predefined) +#define NUM_PREDEF_MODES (1) + + + /* + * Interface used by the world + */ + +void vfb_video_setup(char *options, int *ints); + +static int virtual_fb_open(int fbidx); +static int virtual_fb_release(int fbidx); +static int virtual_fb_get_fix(struct fb_fix_screeninfo *fix, int con); +static int virtual_fb_get_var(struct fb_var_screeninfo *var, int con); +static int virtual_fb_set_var(struct fb_var_screeninfo *var, int con); +static int virtual_fb_pan_display(struct fb_var_screeninfo *var, int con); +static int virtual_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); +static int virtual_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); +static int virtual_fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con); + + + /* + * Interface to the low level console driver + */ + +unsigned long virtual_fb_init(unsigned long mem_start); +static int vfbcon_switch(int con); +static int vfbcon_updatevar(int con); +static void vfbcon_blank(int blank); +static int vfbcon_setcmap(struct fb_cmap *cmap, int con); + + + /* + * Internal routines + */ + +static u_long get_line_length(int xres_virtual, int bpp); +static void vfb_encode_fix(struct fb_fix_screeninfo *fix, + struct fb_var_screeninfo *var); +static void set_color_bitfields(struct fb_var_screeninfo *var); +static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp); +static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp); +static void do_install_cmap(int con); + + +static struct fb_ops virtual_fb_ops = { + virtual_fb_open, virtual_fb_release, virtual_fb_get_fix, + virtual_fb_get_var, virtual_fb_set_var, virtual_fb_get_cmap, + virtual_fb_set_cmap, virtual_fb_pan_display, virtual_fb_ioctl +}; + + + /* + * Open/Release the frame buffer device + */ + +static int virtual_fb_open(int fbidx) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int virtual_fb_release(int fbidx) +{ + MOD_DEC_USE_COUNT; + return(0); +} + + + /* + * Get the Fixed Part of the Display + */ + +static int virtual_fb_get_fix(struct fb_fix_screeninfo *fix, int con) +{ + struct fb_var_screeninfo *var; + + if (con == -1) + var = &virtual_fb_predefined[0]; + else + var = &fb_display[con].var; + vfb_encode_fix(fix, var); + return 0; +} + + + /* + * Get the User Defined Part of the Display + */ + +static int virtual_fb_get_var(struct fb_var_screeninfo *var, int con) +{ + if (con == -1) + *var = virtual_fb_predefined[0]; + else + *var = fb_display[con].var; + set_color_bitfields(var); + return 0; +} + + + /* + * Set the User Defined Part of the Display + */ + +static int virtual_fb_set_var(struct fb_var_screeninfo *var, int con) +{ + int err, activate = var->activate; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp; + u_long line_length; + + struct display *display; + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = display->var.xoffset; + var->yoffset = display->var.yoffset; + } + + /* + * Some very basic checks + */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + if (var->bits_per_pixel <= 1) + var->bits_per_pixel = 1; + else if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; +#if 0 + /* fbcon doesn't support this (yet) */ + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; +#endif + else + return -EINVAL; + + /* + * Memory limit + */ + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length*var->yres_virtual > videomemorysize) + return -ENOMEM; + + set_color_bitfields(var); + + if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + display->var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + struct fb_fix_screeninfo fix; + + vfb_encode_fix(&fix, var); + display->screen_base = (u_char *)fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = 0; + if (fb_info.changevar) + (*fb_info.changevar)(con); + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con); + } + } + return 0; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + */ + +static int virtual_fb_pan_display(struct fb_var_screeninfo *var, int con) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 || + var->yoffset >= fb_display[con].var.yres_virtual || + var->xoffset) + return -EINVAL; + } else { + if (var->xoffset+fb_display[con].var.xres > + fb_display[con].var.xres_virtual || + var->yoffset+fb_display[con].var.yres > + fb_display[con].var.yres_virtual) + return -EINVAL; + } + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + fb_display[con].var.vmode |= FB_VMODE_YWRAP; + else + fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + + /* + * Get the Colormap + */ + +static int virtual_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, &fb_display[con].var, kspc, vfb_getcolreg); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + + /* + * Set the Colormap + */ + +static int virtual_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<>10); + return mem_start; +} + + +static int vfbcon_switch(int con) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, + vfb_getcolreg); + + currcon = con; + /* Install new colormap */ + do_install_cmap(con); + return 0; +} + + /* + * Update the `var' structure (called by fbcon.c) + */ + +static int vfbcon_updatevar(int con) +{ + /* Nothing */ + return 0; +} + + /* + * Blank the display. + */ + +static void vfbcon_blank(int blank) +{ + /* Nothing */ +} + + /* + * Set the colormap + */ + +static int vfbcon_setcmap(struct fb_cmap *cmap, int con) +{ + return(virtual_fb_set_cmap(cmap, 1, con)); +} + + +static u_long get_line_length(int xres_virtual, int bpp) +{ + u_long length; + + length = (xres_virtual+bpp-1)/bpp; + length = (length+31)&-32; + length >>= 3; + return(length); +} + +static void vfb_encode_fix(struct fb_fix_screeninfo *fix, + struct fb_var_screeninfo *var) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, virtual_fb_name); + fix->smem_start = (caddr_t)videomemory; + fix->smem_len = videomemorysize; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + switch (var->bits_per_pixel) { + case 1: + fix->visual = FB_VISUAL_MONO01; + break; + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + case 24: + case 32: + fix->visual = FB_VISUAL_TRUECOLOR; + break; + } + fix->ywrapstep = 1; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); +} + +static void set_color_bitfields(struct fb_var_screeninfo *var) +{ + switch (var->bits_per_pixel) { + case 1: + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 24: /* RGB 888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: /* RGBA 8888 */ + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + } + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; +} + + + /* + * Read a single color register and split it into + * colors/transparent. Return != 0 for invalid regno. + */ + +static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp) +{ + if (regno > 255) + return 1; + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + return 0; +} + + + /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp) +{ + if (regno > 255) + return 1; + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + return 0; +} + + +static void do_install_cmap(int con) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, + vfb_setcolreg); + else + fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), + &fb_display[con].var, 1, vfb_setcolreg); +} + + +#ifdef MODULE +int init_module(void) +{ + return(virtual_fb_init(NULL)); +} + +void cleanup_module(void) +{ + unregister_framebuffer(&fb_info); + vfree(videomemory); +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c --- v2.1.66/linux/drivers/video/vgacon.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/vgacon.c Mon Nov 24 01:19:02 1997 @@ -0,0 +1,591 @@ +/* + * linux/drivers/video/vgacon.c -- Low level VGA based console driver + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * + * This file is based on the old console.c, vga.c and vesa_blank.c drivers. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * + * User definable mapping table and font loading by Eugene G. Crosser, + * + * + * Improved loadable font/UTF-8 support by H. Peter Anvin + * Feb-Sep 1995 + * + * Colour palette handling, by Simon Tatham + * 17-Jun-95 + * + * if 512 char mode is already enabled don't re-enable it, + * because it causes screen to flicker, by Mitja Horvat + * 5-May-96 + * + * Use 2 outw instead of 4 outb_p to reduce erroneous text + * flashing on RHS of screen during heavy console scrolling . + * Oct 1996, Paul Gortmaker. + * + * + * 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. + */ + + + + +/* KNOWN PROBLEMS/TO DO ===================================================== * + * + * - monochrome attribute encoding (convert abscon <-> VGA style) + * + * - speed up scrolling by changing the screen origin + * + * - add support for palette, loadable fonts and VESA blanking + * + * KNOWN PROBLEMS/TO DO ==================================================== */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define BLANK 0x0020 + +#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ +#define CAN_LOAD_PALETTE /* undefine if the user must not do this */ + +#define dac_reg (0x3c8) +#define dac_val (0x3c9) + +#ifdef __powerpc__ +#define VGA_OFFSET _ISA_MEM_BASE; +#else +#define VGA_OFFSET 0x0 +#endif + + +/* + * Interface used by the world + */ + +static unsigned long vgacon_startup(unsigned long kmem_start, + const char **display_desc); +static void vgacon_init(struct vc_data *conp); +static int vgacon_deinit(struct vc_data *conp); +static int vgacon_clear(struct vc_data *conp, int sy, int sx, int height, + int width); +static int vgacon_putc(struct vc_data *conp, int c, int ypos, int xpos); +static int vgacon_putcs(struct vc_data *conp, const char *s, int count, + int ypos, int xpos); +static int vgacon_cursor(struct vc_data *conp, int mode); +static int vgacon_scroll(struct vc_data *conp, int t, int b, + int dir, int count); +static int vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width); +static int vgacon_switch(struct vc_data *conp); +static int vgacon_blank(int blank); +static int vgacon_get_font(struct vc_data *conp, int *w, int *h, char *data); +static int vgacon_set_font(struct vc_data *conp, int w, int h, char *data); +static int vgacon_set_palette(struct vc_data *conp, unsigned char *table); +static int vgacon_scrolldelta(int lines); + + +/* + * Internal routines + */ + +static int vgacon_show_logo(void); + + +/* Description of the hardware situation */ +static unsigned long vga_video_mem_base; /* Base of video memory */ +static unsigned long vga_video_mem_term; /* End of video memory */ +static unsigned short vga_video_port_reg; /* Video register select port */ +static unsigned short vga_video_port_val; /* Video register value port */ +static unsigned long vga_video_num_columns; /* Number of text columns */ +static unsigned long vga_video_num_lines; /* Number of text lines */ +static unsigned long vga_video_size_row; +static unsigned long vga_video_screen_size; + +static int vga_can_do_color = 0; +static unsigned long vga_default_font_height; /* Height of default screen font */ + +static unsigned char vga_video_type; +static unsigned char vga_has_wrapped; /* all of videomem is data of fg_console */ +static unsigned char vga_hardscroll_enabled; +static unsigned char vga_hardscroll_disabled_by_init = 0; + + + + /* + * VGA screen access + */ + +static inline void vga_writew(unsigned short val, unsigned short * addr) +{ +#ifdef __powerpc__ + st_le16(addr, val); +#else + writew(val, (unsigned long) addr); +#endif /* !__powerpc__ */ +} + +static inline unsigned short vga_readw(unsigned short * addr) +{ +#ifdef __powerpc__ + return ld_le16(addr); +#else + return readw((unsigned long) addr); +#endif /* !__powerpc__ */ +} + +static inline void vga_memsetw(void * s, unsigned short c, unsigned int count) +{ + unsigned short * addr = (unsigned short *) s; + + while (count) { + count--; + vga_writew(c, addr++); + } +} + +static inline void vga_memmovew(unsigned short *to, unsigned short *from, + unsigned int count) +{ + if (to < from) { + while (count) { + count--; + vga_writew(vga_readw(from++), to++); + } + } else { + from += count; + to += count; + while (count) { + count--; + vga_writew(vga_readw(--from), --to); + } + } +} + + +/* + * By replacing the four outb_p with two back to back outw, we can reduce + * the window of opportunity to see text mislocated to the RHS of the + * console during heavy scrolling activity. However there is the remote + * possibility that some pre-dinosaur hardware won't like the back to back + * I/O. Since the Xservers get away with it, we should be able to as well. + */ +static inline void write_vga(unsigned char reg, unsigned int val) +{ +#ifndef SLOW_VGA + unsigned int v1, v2; + + v1 = reg + (val & 0xff00); + v2 = reg + 1 + ((val << 8) & 0xff00); + outw(v1, vga_video_port_reg); + outw(v2, vga_video_port_reg); +#else + outb_p(reg, vga_video_port_reg); + outb_p(val >> 8, vga_video_port_val); + outb_p(reg+1, vga_video_port_reg); + outb_p(val & 0xff, vga_video_port_val); +#endif +} + + +__initfunc(static unsigned long vgacon_startup(unsigned long kmem_start, + const char **display_desc)) +{ + unsigned short saved; + unsigned short *p; + + /* + * Find out if there is a graphics card present. + * Are there smarter methods around? + */ + p = (unsigned short *)(((ORIG_VIDEO_MODE == 7) ? 0xb0000 : 0xb8000) + + + VGA_OFFSET); + saved = vga_readw(p); + vga_writew(0xAA55, p); + if (vga_readw(p) != 0xAA55) { + vga_writew(saved, p); + return kmem_start; + } + vga_writew(0x55AA, p); + if (vga_readw(p) != 0x55AA) { + vga_writew(saved, p); + return kmem_start; + } + vga_writew(saved, p); + + vga_video_num_lines = ORIG_VIDEO_LINES; + vga_video_num_columns = ORIG_VIDEO_COLS; + vga_video_size_row = 2 * ORIG_VIDEO_COLS; + vga_video_screen_size = vga_video_num_lines * vga_video_size_row; + + if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ + { + vga_video_mem_base = 0xb0000 + VGA_OFFSET; + vga_video_port_reg = 0x3b4; + vga_video_port_val = 0x3b5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + vga_video_type = VIDEO_TYPE_EGAM; + vga_video_mem_term = 0xb8000 + VGA_OFFSET; + *display_desc = "EGA+"; + request_region(0x3b0,16,"ega"); + } + else + { + vga_video_type = VIDEO_TYPE_MDA; + vga_video_mem_term = 0xb2000 + VGA_OFFSET; + *display_desc = "*MDA"; + request_region(0x3b0,12,"mda"); + request_region(0x3bf, 1,"mda"); + } + } + else /* If not, it is color. */ + { + vga_can_do_color = 1; + vga_video_mem_base = 0xb8000 + VGA_OFFSET; + vga_video_port_reg = 0x3d4; + vga_video_port_val = 0x3d5; + if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) + { + int i ; + + vga_video_mem_term = 0xc0000 + VGA_OFFSET; + + if (!ORIG_VIDEO_ISVGA) { + vga_video_type = VIDEO_TYPE_EGAC; + *display_desc = "EGA"; + request_region(0x3c0,32,"ega"); + } else { + vga_video_type = VIDEO_TYPE_VGAC; + *display_desc = "VGA+"; + request_region(0x3c0,32,"vga+"); + +#ifdef VGA_CAN_DO_64KB + /* + * get 64K rather than 32K of video RAM. + * This doesn't actually work on all "VGA" + * controllers (it seems like setting MM=01 + * and COE=1 isn't necessarily a good idea) + */ + vga_video_mem_base = 0xa0000 + VGA_OFFSET; + vga_video_mem_term = 0xb0000 + VGA_OFFSET; + outb_p (6, 0x3ce) ; + outb_p (6, 0x3cf) ; +#endif + + /* + * Normalise the palette registers, to point + * the 16 screen colours to the first 16 + * DAC entries. + */ + + for (i=0; i<16; i++) { + inb_p (0x3da) ; + outb_p (i, 0x3c0) ; + outb_p (i, 0x3c0) ; + } + outb_p (0x20, 0x3c0) ; + + /* now set the DAC registers back to their + * default values */ + + for (i=0; i<16; i++) { + outb_p (color_table[i], 0x3c8) ; + outb_p (default_red[i], 0x3c9) ; + outb_p (default_grn[i], 0x3c9) ; + outb_p (default_blu[i], 0x3c9) ; + } + } + } + else + { + vga_video_type = VIDEO_TYPE_CGA; + vga_video_mem_term = 0xba000 + VGA_OFFSET; + *display_desc = "*CGA"; + request_region(0x3d4,2,"cga"); + } + } + + vga_hardscroll_enabled = (vga_hardscroll_disabled_by_init ? 0 : + (vga_video_type == VIDEO_TYPE_EGAC + || vga_video_type == VIDEO_TYPE_VGAC + || vga_video_type == VIDEO_TYPE_EGAM)); + vga_has_wrapped = 0; + + if (vga_video_type == VIDEO_TYPE_VGAC + || vga_video_type == VIDEO_TYPE_EGAC + || vga_video_type == VIDEO_TYPE_EGAM) + { + vga_default_font_height = ORIG_VIDEO_POINTS; + video_font_height = ORIG_VIDEO_POINTS; + /* This may be suboptimal but is a safe bet - go with it */ + video_scan_lines = + video_font_height * vga_video_num_lines; + } + + if (!console_show_logo) + console_show_logo = vgacon_show_logo; + + return kmem_start; +} + + +static void vgacon_init(struct vc_data *conp) +{ + conp->vc_cols = vga_video_num_columns; + conp->vc_rows = vga_video_num_lines; + conp->vc_can_do_color = vga_can_do_color; +} + +static int vgacon_deinit(struct vc_data *conp) +{ + return 0; +} + + +/* ====================================================================== */ + +static int vgacon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + int rows; + unsigned long dest; + + if (console_blanked) + return 0; + + dest = vga_video_mem_base + sy*vga_video_size_row + sx*2; + if (sx == 0 && width == vga_video_num_columns) + vga_memsetw((void *)dest, conp->vc_video_erase_char, height * width); + else + for (rows = height; rows-- ; dest += vga_video_size_row) + vga_memsetw((void *)dest, conp->vc_video_erase_char, width); + return 0; +} + + +static int vgacon_putc(struct vc_data *conp, int c, int ypos, int xpos) +{ + u_short *p; + + if (console_blanked) + return 0; + + p = (u_short *)(vga_video_mem_base+ypos*vga_video_size_row+xpos*2); + vga_writew(conp->vc_attr << 8 | c, p); + return 0; +} + + +static int vgacon_putcs(struct vc_data *conp, const char *s, int count, + int ypos, int xpos) +{ + u_short *p; + u_short sattr; + + if (console_blanked) + return 0; + + p = (u_short *)(vga_video_mem_base+ypos*vga_video_size_row+xpos*2); + sattr = conp->vc_attr << 8; + while (count--) + vga_writew(sattr | *s++, p++); + return 0; +} + + +static int vgacon_cursor(struct vc_data *conp, int mode) +{ + switch (mode) { + case CM_ERASE: + write_vga(14, (vga_video_mem_term - vga_video_mem_base - 1)>>1); + break; + + case CM_MOVE: + case CM_DRAW: + write_vga(14, conp->vc_y*vga_video_num_columns+conp->vc_x); + break; + } + return 0; +} + + +static int vgacon_scroll(struct vc_data *conp, int t, int b, int dir, int count) +{ + if (console_blanked) + return 0; + + vgacon_cursor(conp, CM_ERASE); + + switch (dir) { + case SM_UP: + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + vgacon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); + vgacon_clear(conp, b-count, 0, count, conp->vc_cols); + break; + + case SM_DOWN: + if (count > conp->vc_rows) /* Maximum realistic size */ + count = conp->vc_rows; + /* + * Fixed bmove() should end Arno's frustration with copying? + * Confucius says: + * Man who copies in wrong direction, end up with trashed + * data + */ + vgacon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); + vgacon_clear(conp, t, 0, count, conp->vc_cols); + break; + + case SM_LEFT: + vgacon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count); + vgacon_clear(conp, 0, b-count, conp->vc_rows, count); + break; + + case SM_RIGHT: + vgacon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count); + vgacon_clear(conp, 0, t, conp->vc_rows, count); + break; + } + + return 0; +} + + +static int vgacon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + unsigned long src, dst; + int rows; + + if (console_blanked) + return 0; + + if (sx == 0 && dx == 0 && width == vga_video_num_columns) { + src = vga_video_mem_base + sy * vga_video_size_row; + dst = vga_video_mem_base + dy * vga_video_size_row; + vga_memmovew((unsigned short *)dst, (unsigned short *)src, + height * width); + } else if (dy < sy || (dy == sy && dx < sx)) { + src = vga_video_mem_base + sy * vga_video_size_row + sx * 2; + dst = vga_video_mem_base + dy * vga_video_size_row + dx * 2; + for (rows = height; rows-- ;) { + vga_memmovew((unsigned short *)dst, (unsigned short *)src, width); + src += vga_video_size_row; + dst += vga_video_size_row; + } + } else { + src = vga_video_mem_base + (sy+height-1) * vga_video_size_row + sx * 2; + dst = vga_video_mem_base + (dy+height-1) * vga_video_size_row + dx * 2; + for (rows = height; rows-- ;) { + vga_memmovew((unsigned short *)dst, (unsigned short *)src, width); + src -= vga_video_size_row; + dst -= vga_video_size_row; + } + } + return 0; +} + + +static int vgacon_switch(struct vc_data *conp) +{ + return 0; +} + + +static int vgacon_blank(int blank) +{ + if (blank) { + vga_memsetw((void *)vga_video_mem_base, BLANK, vga_video_screen_size/2); + return 0; + } else { + /* Tell console.c that it has to restore the screen itself */ + return(1); + } + return 0; +} + + +static int vgacon_get_font(struct vc_data *conp, int *w, int *h, char *data) +{ + /* TODO */ + return -ENOSYS; +} + + +static int vgacon_set_font(struct vc_data *conp, int w, int h, char *data) +{ + /* TODO */ + return -ENOSYS; +} + +static int vgacon_set_palette(struct vc_data *conp, unsigned char *table) +{ + int i, j ; + + if (vga_video_type != VIDEO_TYPE_VGAC || console_blanked || + vt_cons[fg_console]->vc_mode == KD_GRAPHICS) + return -EINVAL; + + for (i=j=0; i<16; i++) { + outb_p (table[i], dac_reg) ; + outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ; + outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ; + outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ; + } + return 0; +} + +static int vgacon_scrolldelta(int lines) +{ + /* TODO */ + return -ENOSYS; +} + + +__initfunc(static int vgacon_show_logo( void )) +{ + int height = 0; + char *p; + + printk(linux_serial_image); + for (p = linux_serial_image; *p; p++) + if (*p == '\n') + height++; + return height; +} + + + +/* + * The console `switch' structure for the VGA based console + */ + +struct consw vga_con = { + vgacon_startup, vgacon_init, vgacon_deinit, vgacon_clear, vgacon_putc, + vgacon_putcs, vgacon_cursor, vgacon_scroll, vgacon_bmove, vgacon_switch, + vgacon_blank, vgacon_get_font, vgacon_set_font, vgacon_set_palette, + vgacon_scrolldelta +}; diff -u --recursive --new-file v2.1.66/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.1.66/linux/fs/ext2/namei.c Wed Nov 12 13:34:27 1997 +++ linux/fs/ext2/namei.c Wed Nov 26 15:13:56 1997 @@ -614,10 +614,9 @@ /* * Prune any child dentries so that this dentry becomes negative. */ - if (dentry->d_count > 1) { - printk("ext2_rmdir: d_count=%d, pruning\n", dentry->d_count); + if (dentry->d_count > 1) shrink_dcache_parent(dentry); - } + if (!empty_dir (inode)) retval = -ENOTEMPTY; else if (le32_to_cpu(de->inode) != inode->i_ino) diff -u --recursive --new-file v2.1.66/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.66/linux/fs/nfs/dir.c Mon Nov 17 18:47:22 1997 +++ linux/fs/nfs/dir.c Wed Nov 26 15:32:27 1997 @@ -478,15 +478,16 @@ int error; dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n", - dir->i_dev, dir->i_ino, len, dentry->d_name.name); + dir->i_dev, dir->i_ino, len, dentry->d_name.name); if (!dir || !S_ISDIR(dir->i_mode)) { printk("nfs_lookup: inode is NULL or not a directory\n"); return -ENOENT; } + error = -ENAMETOOLONG; if (len > NFS_MAXNAMLEN) - return -ENAMETOOLONG; + goto out; error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr); @@ -504,6 +505,7 @@ error = 0; } } +out: return error; } @@ -516,7 +518,6 @@ struct inode *inode; int error = -EACCES; - nfs_invalidate_dircache(dir); inode = nfs_fhget(dir->i_sb, fhandle, fattr); if (inode) { d_instantiate(dentry, inode); @@ -526,6 +527,12 @@ return error; } +/* + * Following a failed create operation, we drop the dentry rather + * than retain a negative dentry. This avoids a problem in the event + * that the operation succeeded on the server, but an error in the + * reply path made it appear to have failed. + */ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode) { struct nfs_sattr sattr; @@ -541,19 +548,36 @@ return -ENOENT; } + error = -ENAMETOOLONG; if (dentry->d_name.len > NFS_MAXNAMLEN) - return -ENAMETOOLONG; + goto out; sattr.mode = mode; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + + /* + * Invalidate the dir cache before the operation to avoid a race. + */ + nfs_invalidate_dircache(dir); error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) error = nfs_instantiate(dir, dentry, &fattr, &fhandle); + else { +#ifdef NFS_PARANOIA +printk("nfs_create: %s/%s failed, error=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, error); +#endif + d_drop(dentry); + } +out: return error; } +/* + * See comments for nfs_proc_create regarding failed operations. + */ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) { struct nfs_sattr sattr; @@ -576,15 +600,26 @@ sattr.uid = sattr.gid = sattr.size = (unsigned) -1; if (S_ISCHR(mode) || S_ISBLK(mode)) sattr.size = rdev; /* get out your barf bag */ - sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + + nfs_invalidate_dircache(dir); error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) error = nfs_instantiate(dir, dentry, &fattr, &fhandle); + else { +#ifdef NFS_PARANOIA +printk("nfs_mknod: %s/%s failed, error=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, error); +#endif + d_drop(dentry); + } return error; } +/* + * See comments for nfs_proc_create regarding failed operations. + */ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct nfs_sattr sattr; @@ -607,10 +642,18 @@ sattr.uid = sattr.gid = sattr.size = (unsigned) -1; sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + nfs_invalidate_dircache(dir); error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) error = nfs_instantiate(dir, dentry, &fattr, &fhandle); + else { +#ifdef NFS_PARANOIA +printk("nfs_mkdir: %s/%s failed, error=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, error); +#endif + d_drop(dentry); + } return error; } @@ -897,7 +940,7 @@ int error; dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n", - dir->i_dev, dir->i_ino, dentry->d_name.name, symname); + dir->i_dev, dir->i_ino, dentry->d_name.name, symname); if (!dir || !S_ISDIR(dir->i_mode)) { printk("nfs_symlink: inode is NULL or not a directory\n"); @@ -911,25 +954,35 @@ if (strlen(symname) > NFS_MAXPATHLEN) goto out; - sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */ +#ifdef NFS_PARANOIA +if (dentry->d_inode) +printk("nfs_proc_symlink: %s/%s not negative!\n", +dentry->d_parent->d_name.name, dentry->d_name.name); +#endif + /* + * Fill in the sattr for the call. + * Note: SunOS 4.1.2 crashes if the mode isn't initialized! + */ + sattr.mode = S_IFLNK | S_IRWXUGO; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + /* + * Drop the dentry in advance to force a new lookup. + * Since nfs_proc_symlink doesn't return a fattr, we + * can't instantiate the new inode. + */ + d_drop(dentry); error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, symname, &sattr); if (!error) { nfs_invalidate_dircache(dir); nfs_renew_times(dentry->d_parent); - /* this looks _funny_ doesn't it? But: nfs_proc_symlink() - * only fills in sattr, not fattr. Thus nfs_fhget() cannot be - * called, it would be pointless, without a valid fattr - * argument. Other possibility: call nfs_proc_lookup() - * HERE. But why? If somebody wants to reference this - * symlink, the cached_lookup() will fail, and - * nfs_proc_symlink() will be called anyway. - */ - d_drop(dentry); + } else if (error == -EEXIST) { + printk("nfs_proc_symlink: %s/%s already exists??\n", + dentry->d_parent->d_name.name, dentry->d_name.name); } + out: return error; } diff -u --recursive --new-file v2.1.66/linux/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.1.66/linux/fs/nfsd/export.c Tue Nov 18 17:22:08 1997 +++ linux/fs/nfsd/export.c Wed Nov 26 13:08:38 1997 @@ -26,6 +26,9 @@ #include #include +#define NFSDDBG_FACILITY NFSDDBG_EXPORT +#define NFSD_PARANOIA 1 + typedef struct svc_client svc_client; typedef struct svc_export svc_export; @@ -37,9 +40,7 @@ static void exp_freeclient(svc_client *clp); static void exp_unhashclient(svc_client *clp); static int exp_verify_string(char *cp, int max); -struct inode * exp_lnamei(char *pathname, int *errp); -#define NFSDDBG_FACILITY NFSDDBG_EXPORT #define CLIENT_HASHBITS 6 #define CLIENT_HASHMAX (1 << CLIENT_HASHBITS) #define CLIENT_HASHMASK (CLIENT_HASHMAX - 1) @@ -65,7 +66,7 @@ #define WRITELOCK 1 /* - * Find the export entry matching xdev/xino. + * Find a client's export for a device. */ static inline svc_export * exp_find(svc_client *clp, dev_t dev) @@ -78,6 +79,9 @@ return exp; } +/* + * Find the client's export entry matching xdev/xino. + */ svc_export * exp_get(svc_client *clp, dev_t dev, ino_t ino) { @@ -90,8 +94,22 @@ } /* - * Look up the root inode of the parent fs. - * We have to go through iget in order to allow for wait_on_inode. + * Check whether there are any exports for a device. + */ +static int +exp_device_in_use(dev_t dev) +{ + struct svc_client *clp; + + for (clp = clients; clp; clp = clp->cl_next) { + if (exp_find(clp, dev)) + return 1; + } + return 0; +} + +/* + * Look up the device of the parent fs. */ static inline int nfsd_parentdev(dev_t *devp) @@ -153,13 +171,12 @@ /* Try to lock the export table for update */ if ((err = exp_writelock()) < 0) - return err; + goto out; /* Look up client info */ - if (!(clp = exp_getclientbyname(nxp->ex_client))) { - err = -EINVAL; - goto finish; - } + err = -EINVAL; + if (!(clp = exp_getclientbyname(nxp->ex_client))) + goto out_unlock; /* * If there's already an export for this file, assume this @@ -167,22 +184,22 @@ */ if ((exp = exp_find(clp, dev)) != NULL) { /* Ensure there's only one export per FS. */ - if (exp->ex_ino != ino) { - err = -EPERM; - } else { + err = -EPERM; + if (exp->ex_ino == ino) { exp->ex_flags = nxp->ex_flags; exp->ex_anon_uid = nxp->ex_anon_uid; exp->ex_anon_gid = nxp->ex_anon_gid; err = 0; } - goto finish; + goto out_unlock; } /* Look up the dentry */ err = -EINVAL; dentry = lookup_dentry(nxp->ex_path, NULL, 0); if (IS_ERR(dentry)) - goto finish; + goto out_unlock; + err = -ENOENT; inode = dentry->d_inode; if(!inode) @@ -199,11 +216,15 @@ goto finish; /* If this is a sub-export, must be root of FS */ + err = -EINVAL; if ((parent = exp_parent(clp, dev)) != NULL) { struct super_block *sb = inode->i_sb; - if (sb && (inode != sb->s_root->d_inode)) { - err = -EINVAL; + if (inode != sb->s_root->d_inode) { +#ifdef NFSD_PARANOIA +printk("exp_export: sub-export %s not root of device %s\n", +nxp->ex_path, kdevname(sb->s_dev)); +#endif goto finish; } } @@ -242,14 +263,16 @@ err = 0; -finish: - /* Release dentry */ - if (err < 0 && !IS_ERR(dentry)) - dput(dentry); - /* Unlock hashtable */ +out_unlock: exp_unlock(); +out: return err; + + /* Release the dentry */ +finish: + dput(dentry); + goto out_unlock; } /* @@ -273,12 +296,21 @@ exp->ex_parent = unexp->ex_parent; } + /* + * Check whether this is the last export for this device, + * and if so flush any cached dentries. + */ + if (!exp_device_in_use(unexp->ex_dev)) { +printk("exp_do_unexport: %s last use, flushing cache\n", +kdevname(unexp->ex_dev)); + nfsd_fh_flush(unexp->ex_dev); + } + dentry = unexp->ex_dentry; inode = dentry->d_inode; if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino) printk(KERN_WARNING "nfsd: bad dentry in unexport!\n"); - else - dput(dentry); + dput(dentry); kfree(unexp); } @@ -321,15 +353,19 @@ return -EINVAL; if ((err = exp_writelock()) < 0) - return err; + goto out; err = -EINVAL; - if ((clp = exp_getclientbyname(nxp->ex_client)) != NULL) { + clp = exp_getclientbyname(nxp->ex_client); + if (clp) { +printk("exp_unexport: found client %s\n", nxp->ex_client); expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev); while ((exp = *expp) != NULL) { if (exp->ex_dev == nxp->ex_dev) { - if (exp->ex_ino != nxp->ex_ino) + if (exp->ex_ino != nxp->ex_ino) { +printk("exp_unexport: ino mismatch, %ld not %ld\n", exp->ex_ino, nxp->ex_ino); break; + } *expp = exp->ex_next; exp_do_unexport(exp); err = 0; @@ -340,6 +376,7 @@ } exp_unlock(); +out: return err; } @@ -477,27 +514,27 @@ int i, err, change = 0, ilen; /* First, consistency check. */ + err = -EINVAL; if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))) - return -EINVAL; + goto out; if (ncp->cl_naddr > NFSCLNT_ADDRMAX) - return -EINVAL; + goto out; /* Lock the hashtable */ if ((err = exp_writelock()) < 0) - return err; + goto out; /* First check if this is a change request for a client. */ for (clp = clients; clp; clp = clp->cl_next) if (!strcmp(clp->cl_ident, ncp->cl_ident)) break; + err = -ENOMEM; if (clp) { change = 1; } else { - if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) { - exp_unlock(); - return -ENOMEM; - } + if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) + goto out_unlock; memset(clp, 0, sizeof(*clp)); dprintk("created client %s (%p)\n", ncp->cl_ident, clp); @@ -508,13 +545,13 @@ /* Allocate hash buckets */ for (i = 0; i < ncp->cl_naddr; i++) { - if (!(ch[i] = kmalloc(GFP_KERNEL, sizeof(ch[0])))) { + ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL); + if (!ch[i]) { while (i--) kfree(ch[i]); if (!change) kfree(clp); - exp_unlock(); - return -ENOMEM; + goto out_unlock; } } @@ -544,9 +581,12 @@ clp->cl_next = clients; clients = clp; } + err = 0; +out_unlock: exp_unlock(); - return 0; +out: + return err; } /* diff -u --recursive --new-file v2.1.66/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.1.66/linux/fs/nfsd/nfsfh.c Wed Nov 26 16:24:03 1997 +++ linux/fs/nfsd/nfsfh.c Wed Nov 26 13:08:38 1997 @@ -388,6 +388,7 @@ struct inode *dir; char *name; unsigned long page; + ino_t root_ino; int error; struct nfsd_dirent dirent; @@ -404,24 +405,25 @@ if (!sb) goto out_page; root = dget(sb->s_root); + root_ino = root->d_inode->i_ino; /* usually 2 */ name = (char *) page + PAGE_SIZE; *(--name) = 0; /* - * Walk up the tree building the name string as we go. - * When we reach the root (ino == 2), get the dentry + * Walk up the tree to construct the name string. + * When we reach the root inode, look up the name * relative to the root dentry. */ while (1) { - if (ino == 2) { + if (ino == root_ino) { if (*name == '/') name++; /* * Note: this dput()s the root dentry. */ result = lookup_dentry(name, root, 0); - goto out_page; + break; } result = ERR_PTR(-ENOENT); @@ -444,30 +446,39 @@ /* * Prepend the name to the buffer. */ - name -= dirent.len; - memcpy(name, dirent.name, dirent.len); - *(--name) = '/'; + result = ERR_PTR(-ENAMETOOLONG); + name -= (dirent.len + 1); + if ((unsigned long) name <= page) + goto out_root; + memcpy(name + 1, dirent.name, dirent.len); + *name = '/'; /* * Make sure we can't get caught in a loop ... */ - result = ERR_PTR(-EINVAL); - if (dirino == dirent.ino && dirino != 2) { -printk("lookup_inode: loop detected, dirino=%ld, path=%s\n", dirino, name); + if (dirino == dirent.ino && dirino != root_ino) { + printk("lookup_inode: looping?? (ino=%ld, path=%s)\n", + dirino, name); goto out_root; } ino = dirino; dirino = dirent.ino; } -out_iput: - iput(dir); -out_root: - dput(root); out_page: free_page(page); out: return result; + + /* + * Error exits ... + */ +out_iput: + result = ERR_PTR(-ENOMEM); + iput(dir); +out_root: + dput(root); + goto out; } /* @@ -840,14 +851,23 @@ * and verify that it has the correct inode number. * * (2) Try to validate the dentry pointer in the filehandle, - * and verify that it has the correct inode number. + * and verify that it has the correct inode number. If this + * fails, check for a cached lookup in the fix-up list and + * repeat step (2) using the new dentry pointer. + * + * (3) Look up the dentry by using the inode and parent inode numbers + * to build the name string. This should succeed for any unix-like + * filesystem. * - * (3) Search for the parent dentry in the dir cache, and then + * (4) Search for the parent dentry in the dir cache, and then * look for the name matching the inode number. * - * (4) The most general case ... search the whole volume for the inode. + * (5) The most general case ... search the whole volume for the inode. * * If successful, we return a dentry with the use count incremented. + * + * Note: steps (4) and (5) above are probably unnecessary now that (3) + * is working. Remove the code once this is verified ... */ static struct dentry * find_fh_dentry(struct knfs_fh *fh) @@ -859,8 +879,10 @@ * Stage 1: Look for the dentry in the short-term fhcache. */ dentry = find_dentry_in_fhcache(fh); - if (dentry) + if (dentry) { + nfsdstats.fh_cached++; goto out; + } /* * Stage 2: Attempt to validate the dentry in the filehandle. @@ -881,9 +903,15 @@ #ifdef NFSD_DEBUG_VERBOSE printk("find_fh_dentry: validated %s/%s, ino=%ld\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino); -if (retry) +#endif + if (!retry) + nfsdstats.fh_valid++; + else { + nfsdstats.fh_fixup++; +#ifdef NFSD_DEBUG_VERBOSE printk("find_fh_dentry: retried validation successful\n"); #endif + } goto out; } } @@ -910,8 +938,10 @@ printk("find_fh_dentry: looked up %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); #endif - if (inode && inode->i_ino == fh->fh_ino) + if (inode && inode->i_ino == fh->fh_ino) { + nfsdstats.fh_lookup++; goto out; + } #ifdef NFSD_PARANOIA printk("find_fh_dentry: %s/%s lookup mismatch!\n", dentry->d_parent->d_name.name, dentry->d_name.name); @@ -941,6 +971,7 @@ kdevname(fh->fh_dev), fh->fh_dirino, fh->fh_ino); #endif dentry = NULL; + nfsdstats.fh_stale++; out: if (looked_up && dentry) { @@ -1038,6 +1069,10 @@ /* Finally, check access permissions. */ error = nfsd_permission(fhp->fh_export, dentry, access); +if (error) +printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, access, error); + out: return error; } @@ -1154,7 +1189,7 @@ */ len = dentry->d_name.len; if (len > NFS_MAXNAMLEN) - goto bad_length; + goto out; /* * Note: d_validate doesn't dereference the parent pointer ... * just combines it with the name hash to find the hash chain. @@ -1170,18 +1205,18 @@ bad_align: printk("nfsd_d_validate: unaligned address %lx\n", dent_addr); goto out; -bad_length: - printk("nfsd_d_validate: invalid length %d\n", len); - goto out; } /* - * Free the dentry and path caches. + * Flush any cached dentries for the specified device + * or for all devices. + * + * This is called when revoking the last export for a + * device, so that it can be unmounted cleanly. */ -void nfsd_fh_free(void) +void nfsd_fh_flush(dev_t dev) { struct fh_entry *fhe; - struct list_head *tmp; int i, pass = 2; fhe = &filetable[0]; @@ -1190,12 +1225,26 @@ struct dentry *dentry = fhe->dentry; if (!dentry) continue; + if (dev && dentry->d_inode->i_dev != dev) + continue; fhe->dentry = NULL; dput(dentry); nfsd_nr_put++; } fhe = &dirstable[0]; } +} + +/* + * Free the dentry and path caches. + */ +void nfsd_fh_free(void) +{ + struct list_head *tmp; + int i; + + /* Flush dentries for all devices */ + nfsd_fh_flush(0); /* * N.B. write a destructor for these lists ... @@ -1222,8 +1271,7 @@ nfsd_nr_verified, nfsd_nr_put); } -void -nfsd_fh_init(void) +void nfsd_fh_init(void) { memset(filetable, 0, NFSD_MAXFH*sizeof(struct fh_entry)); memset(dirstable, 0, NFSD_MAXFH*sizeof(struct fh_entry)); @@ -1232,4 +1280,3 @@ printk("nfsd_init: initialized fhcache, entries=%lu\n", NFSD_MAXFH); } - diff -u --recursive --new-file v2.1.66/linux/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c --- v2.1.66/linux/fs/nfsd/nfsxdr.c Tue Nov 18 17:22:08 1997 +++ linux/fs/nfsd/nfsxdr.c Wed Nov 26 13:08:38 1997 @@ -18,7 +18,7 @@ #define NFSDDBG_FACILITY NFSDDBG_XDR u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio, - nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir, + nfserr_inval, nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir, nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs, nfserr_nametoolong, nfserr_dquot, nfserr_stale; @@ -47,10 +47,11 @@ if (inited) return; - nfs_ok = htonl(NFS_OK); - nfserr_perm = htonl(NFSERR_PERM); - nfserr_noent = htonl(NFSERR_NOENT); - nfserr_io = htonl(NFSERR_IO); + nfs_ok = htonl(NFS_OK); + nfserr_perm = htonl(NFSERR_PERM); + nfserr_noent = htonl(NFSERR_NOENT); + nfserr_io = htonl(NFSERR_IO); + nfserr_inval = htonl(NFSERR_INVAL); nfserr_nxio = htonl(NFSERR_NXIO); nfserr_acces = htonl(NFSERR_ACCES); nfserr_exist = htonl(NFSERR_EXIST); diff -u --recursive --new-file v2.1.66/linux/fs/nfsd/stats.c linux/fs/nfsd/stats.c --- v2.1.66/linux/fs/nfsd/stats.c Sun Apr 13 10:18:22 1997 +++ linux/fs/nfsd/stats.c Wed Nov 26 13:08:38 1997 @@ -32,11 +32,15 @@ { int len; - len = sprintf(buffer, - "rc %d %d %d\n", + len = sprintf(buffer, "rc %d %d %d %d %d %d %d %d\n", nfsdstats.rchits, nfsdstats.rcmisses, - nfsdstats.rcnocache); + nfsdstats.rcnocache, + nfsdstats.fh_cached, + nfsdstats.fh_valid, + nfsdstats.fh_fixup, + nfsdstats.fh_lookup, + nfsdstats.fh_stale); /* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */ *eof = 0; diff -u --recursive --new-file v2.1.66/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.1.66/linux/fs/nfsd/vfs.c Tue Nov 18 17:22:08 1997 +++ linux/fs/nfsd/vfs.c Wed Nov 26 13:08:38 1997 @@ -672,13 +672,14 @@ int err; if ((err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ)) != 0) - return err; + goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; + err = nfserr_inval; if (!inode->i_op || !inode->i_op->readlink) - return nfserr_io; + goto out; UPDATE_ATIME(inode); oldfs = get_fs(); set_fs(KERNEL_DS); @@ -686,10 +687,14 @@ set_fs(oldfs); if (err < 0) - return nfserrno(-err); - *lenp = err; + err = nfserrno(-err); + else { + *lenp = err; + err = 0; + } - return 0; +out: + return err; } /* @@ -706,41 +711,43 @@ struct inode *dirp; int err; + err = nfserr_noent; if (!flen || !plen) - return nfserr_noent; + goto out; if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0) - return err; - + goto out; dentry = fhp->fh_dentry; - dirp = dentry->d_inode; - if (nfsd_iscovered(dentry, fhp->fh_export) || - !dirp->i_op || - !dirp->i_op->symlink) - return nfserr_perm; + err = nfserr_perm; + if (nfsd_iscovered(dentry, fhp->fh_export)) + goto out; + dirp = dentry->d_inode; + if (!dirp->i_op || !dirp->i_op->symlink) + goto out; dnew = lookup_dentry(fname, dget(dentry), 0); err = PTR_ERR(dnew); if (IS_ERR(dnew)) - goto out; + goto out_nfserr; err = -EEXIST; - if(dnew->d_inode) - goto compose_and_out; - - fh_lock(fhp); - err = dirp->i_op->symlink(dirp, dnew, path); - fh_unlock(fhp); - - if (!err) { - if (EX_ISSYNC(fhp->fh_export)) - write_inode_now(dirp); + if (!dnew->d_inode) { + fh_lock(fhp); + err = dirp->i_op->symlink(dirp, dnew, path); + fh_unlock(fhp); + if (!err) { + if (EX_ISSYNC(fhp->fh_export)) + write_inode_now(dirp); + } } -compose_and_out: fh_compose(resfhp, fhp->fh_export, dnew); + +out_nfserr: + if (err) + err = nfserrno(-err); out: - return (err ? nfserrno(-err) : 0); + return err; } /* diff -u --recursive --new-file v2.1.66/linux/include/asm-i386/delay.h linux/include/asm-i386/delay.h --- v2.1.66/linux/include/asm-i386/delay.h Tue May 13 22:41:17 1997 +++ linux/include/asm-i386/delay.h Sat Nov 29 10:33:21 1997 @@ -4,61 +4,15 @@ /* * Copyright (C) 1993 Linus Torvalds * - * Delay routines, using a pre-computed "loops_per_second" value. + * Delay routines calling functions in arch/i386/lib/delay.c */ -#ifdef __SMP__ -#include -#endif - -extern __inline__ void __delay(int loops) -{ - __asm__ __volatile__( - ".align 2,0x90\n1:\tdecl %0\n\tjns 1b" - :/* no outputs */ - :"a" (loops) - :"ax"); -} - -/* - * division by multiplication: you don't have to worry about - * loss of precision. - * - * Use only for very small delays ( < 1 msec). Should probably use a - * lookup table, really, as the multiplications take much too long with - * short delays. This is a "reasonable" implementation, though (and the - * first constant multiplications gets optimized away if the delay is - * a constant) - */ -extern __inline__ void __udelay(unsigned long usecs, unsigned long lps) -{ - usecs *= 0x000010c6; /* 2**32 / 1000000 */ - __asm__("mull %0" - :"=d" (usecs) - :"a" (usecs),"0" (lps) - :"ax"); - - __delay(usecs); -} - -#ifdef __SMP__ -#define __udelay_val cpu_data[smp_processor_id()].udelay_val -#else -#define __udelay_val loops_per_sec -#endif - -#define udelay(usecs) __udelay((usecs),__udelay_val) - - -extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) -{ - __asm__("mull %1 ; divl %2" - :"=a" (a) - :"d" (b), - "r" (c), - "0" (a) - :"dx"); - return a; -} +extern void __udelay(unsigned long usecs); +extern void __const_udelay(unsigned long usecs); +extern void __delay(unsigned long loops); + +#define udelay(n) (__builtin_constant_p(n) ? \ + __const_udelay((n) * 0x10c6) : \ + __udelay(n)) #endif /* defined(_I386_DELAY_H) */ diff -u --recursive --new-file v2.1.66/linux/include/asm-i386/locks.h linux/include/asm-i386/locks.h --- v2.1.66/linux/include/asm-i386/locks.h Mon May 6 02:26:15 1996 +++ linux/include/asm-i386/locks.h Sat Nov 29 10:33:21 1997 @@ -38,7 +38,7 @@ * Wait for any invalidates to go off */ - if(smp_invalidate_needed&(1<spins++; diff -u --recursive --new-file v2.1.66/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.1.66/linux/include/asm-i386/pgtable.h Sun Sep 7 13:10:43 1997 +++ linux/include/asm-i386/pgtable.h Sat Nov 29 11:07:26 1997 @@ -37,7 +37,7 @@ #define __flush_tlb() \ do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0) -#ifdef CONFIG_M386 +#if defined(CONFIG_M386) || defined(CONFIG_AMD_K5_INVBUG) #define __flush_tlb_one(addr) flush_tlb() #else #define __flush_tlb_one(addr) \ diff -u --recursive --new-file v2.1.66/linux/include/asm-i386/socket.h linux/include/asm-i386/socket.h --- v2.1.66/linux/include/asm-i386/socket.h Thu Mar 27 14:40:06 1997 +++ linux/include/asm-i386/socket.h Sat Nov 29 10:33:21 1997 @@ -33,4 +33,6 @@ #define SO_SECURITY_ENCRYPTION_TRANSPORT 23 #define SO_SECURITY_ENCRYPTION_NETWORK 24 +#define SO_BINDTODEVICE 25 + #endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v2.1.66/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.1.66/linux/include/asm-i386/unistd.h Wed Sep 24 20:05:48 1997 +++ linux/include/asm-i386/unistd.h Sat Nov 29 10:33:21 1997 @@ -278,6 +278,8 @@ static inline _syscall0(int,sync) static inline _syscall0(pid_t,setsid) static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) static inline _syscall1(int,dup,int,fd) static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) static inline _syscall3(int,open,const char *,file,int,flag,int,mode) diff -u --recursive --new-file v2.1.66/linux/include/linux/atalk.h linux/include/linux/atalk.h --- v2.1.66/linux/include/linux/atalk.h Tue Sep 23 16:48:49 1997 +++ linux/include/linux/atalk.h Sat Nov 29 11:08:27 1997 @@ -156,9 +156,9 @@ extern struct device *atrtr_get_dev(struct at_addr *sa); extern int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr); extern void aarp_send_probe(struct device *dev, struct at_addr *addr); +extern void aarp_device_down(struct device *dev); #ifdef MODULE -extern void aarp_device_down(struct device *dev); extern void aarp_cleanup_module(void); #endif /* MODULE */ diff -u --recursive --new-file v2.1.66/linux/include/linux/awe_voice.h linux/include/linux/awe_voice.h --- v2.1.66/linux/include/linux/awe_voice.h Wed Nov 12 13:34:27 1997 +++ linux/include/linux/awe_voice.h Sat Nov 29 10:33:21 1997 @@ -3,7 +3,7 @@ * * Voice information definitions for the low level driver for the * AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2; Sep. 1, 1997 + * version 0.4.2c; Oct. 7, 1997 * * Copyright (C) 1996,1997 Takashi Iwai * @@ -419,16 +419,17 @@ /* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */ /* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */ /* 2*/ AWE_MD_VERSION, /* read only */ -/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* 0/1: (default=1) */ +/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* ignored */ /* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */ -/* 5*/ AWE_MD_GUS_BANK, /* bank number (default=0) */ +/* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */ /* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */ /* 7*/ AWE_MD_ZERO_ATTEN, /* attenuation of max volume (default=32) */ /* 8*/ AWE_MD_CHN_PRIOR, /* 0/1: set MIDI channel priority mode (default=1) */ -/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity */ -/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number */ -/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number */ -/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number */ +/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity (def=18) */ +/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number (def=0) */ +/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */ +/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */ +/*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */ AWE_MD_END, }; diff -u --recursive --new-file v2.1.66/linux/include/linux/icmp.h linux/include/linux/icmp.h --- v2.1.66/linux/include/linux/icmp.h Fri Feb 7 05:54:54 1997 +++ linux/include/linux/icmp.h Sat Nov 29 10:33:21 1997 @@ -88,4 +88,15 @@ }; #endif +/* + * constants for (set|get)sockopt + */ + +#define ICMP_FILTER 1 + +struct icmp_filter { + __u32 data; +}; + + #endif /* _LINUX_ICMP_H */ diff -u --recursive --new-file v2.1.66/linux/include/linux/if.h linux/include/linux/if.h --- v2.1.66/linux/include/linux/if.h Thu Sep 4 17:07:31 1997 +++ linux/include/linux/if.h Sat Nov 29 10:51:43 1997 @@ -39,6 +39,8 @@ #define IFF_MULTICAST 0x1000 /* Supports multicast */ +#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ALLMULTI) + #define IFF_PORTSEL 0x2000 /* can set media type */ #define IFF_AUTOMEDIA 0x4000 /* auto media select active */ @@ -129,6 +131,7 @@ #define ifr_slave ifr_ifru.ifru_slave /* slave device */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ #define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ +#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ /* * Structure used in SIOCGIFCONF request. @@ -148,5 +151,6 @@ }; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + #endif /* _LINUX_IF_H */ diff -u --recursive --new-file v2.1.66/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.1.66/linux/include/linux/if_arp.h Mon Jul 7 16:02:46 1997 +++ linux/include/linux/if_arp.h Sat Nov 29 11:08:26 1997 @@ -60,6 +60,10 @@ #define ARPHRD_BIF 775 /* AP1000 BIF */ #define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ #define ARPHRD_IPDDP 777 /* IP over DDP tunneller */ +#define ARPHRD_IPGRE 778 /* GRE over IP */ +#define ARPHRD_PIMREG 779 /* PIMSM register interface */ +#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ +#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request */ diff -u --recursive --new-file v2.1.66/linux/include/linux/if_frad.h linux/include/linux/if_frad.h --- v2.1.66/linux/include/linux/if_frad.h Mon May 13 13:23:07 1996 +++ linux/include/linux/if_frad.h Sat Nov 29 10:33:21 1997 @@ -24,8 +24,11 @@ #ifndef _FRAD_H_ #define _FRAD_H_ +#include #include +#if defined(CONFIG_DLCI) || defined(CONFIG_DLCI_MODULE) + /* Structures and constants associated with the DLCI device driver */ struct dlci_add @@ -189,6 +192,10 @@ int register_frad(const char *name); int unregister_frad(const char *name); +int (*dlci_ioctl_hook)(unsigned int, void *); + #endif __KERNEL__ + +#endif /* CONFIG_DLCI || CONFIG_DLCI_MODULE */ #endif diff -u --recursive --new-file v2.1.66/linux/include/linux/if_packet.h linux/include/linux/if_packet.h --- v2.1.66/linux/include/linux/if_packet.h Sat Mar 16 03:52:11 1996 +++ linux/include/linux/if_packet.h Sat Nov 29 10:33:21 1997 @@ -8,4 +8,41 @@ unsigned short spkt_protocol; }; +struct sockaddr_ll +{ + unsigned short sll_family; + unsigned short sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; +}; + +/* Packet types */ + +#define PACKET_HOST 0 /* To us */ +#define PACKET_BROADCAST 1 /* To all */ +#define PACKET_MULTICAST 2 /* To group */ +#define PACKET_OTHERHOST 3 /* To someone else */ +#define PACKET_OUTGOING 4 /* Originated by us */ +#define PACKET_NDISC 17 /* Outgoing NDISC packet*/ + +/* Packet socket options */ + +#define PACKET_ADD_MEMBERSHIP 1 +#define PACKET_DROP_MEMBERSHIP 2 + +struct packet_mreq +{ + int mr_ifindex; + unsigned short mr_type; + unsigned short mr_alen; + unsigned char mr_address[8]; +}; + +#define PACKET_MR_MULTICAST 0 +#define PACKET_MR_PROMISC 1 +#define PACKET_MR_ALLMULTI 2 + #endif diff -u --recursive --new-file v2.1.66/linux/include/linux/if_tr.h linux/include/linux/if_tr.h --- v2.1.66/linux/include/linux/if_tr.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/if_tr.h Sat Nov 29 10:33:21 1997 @@ -34,12 +34,6 @@ #endif -/* These are some defined Ethernet Protocol ID's. */ -/* FIXME: should use the definitions in if_ether.h!!! */ -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ -#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ - /* LLC and SNAP constants */ #define EXTENDED_SAP 0xAA #define UI_CMD 0x03 diff -u --recursive --new-file v2.1.66/linux/include/linux/in6.h linux/include/linux/in6.h --- v2.1.66/linux/include/linux/in6.h Sat Oct 25 02:44:18 1997 +++ linux/include/linux/in6.h Sat Nov 29 10:33:21 1997 @@ -106,8 +106,10 @@ #define IPV6_ADDRFORM 1 #define IPV6_PKTINFO 2 -#define IPV6_RXHOPOPTS 3 -#define IPV6_RXDSTOPTS 4 +#define IPV6_RXHOPOPTS 3 /* obsolete name */ +#define IPV6_RXDSTOPTS 4 /* obsolete name */ +#define IPV6_HOPOPTS IPV6_RXHOPOPTS /* new name */ +#define IPV6_DSTOPTS IPV6_RXDSTOPTS /* new name */ #define IPV6_RXSRCRT 5 #define IPV6_PKTOPTIONS 6 #define IPV6_CHECKSUM 7 diff -u --recursive --new-file v2.1.66/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v2.1.66/linux/include/linux/interrupt.h Mon Jun 30 15:23:12 1997 +++ linux/include/linux/interrupt.h Sat Nov 29 10:33:21 1997 @@ -39,7 +39,8 @@ IMMEDIATE_BH, KEYBOARD_BH, CYCLADES_BH, - CM206_BH + CM206_BH, + JS_BH }; #include diff -u --recursive --new-file v2.1.66/linux/include/linux/ipv6_route.h linux/include/linux/ipv6_route.h --- v2.1.66/linux/include/linux/ipv6_route.h Thu Mar 27 14:40:10 1997 +++ linux/include/linux/ipv6_route.h Sat Nov 29 10:33:21 1997 @@ -25,6 +25,8 @@ #define RTF_FLOW 0x02000000 /* flow significant route */ #define RTF_POLICY 0x04000000 /* policy route */ +#define RTF_LOCAL 0x80000000 + struct in6_rtmsg { struct in6_addr rtmsg_dst; struct in6_addr rtmsg_src; @@ -37,5 +39,11 @@ __u32 rtmsg_flags; int rtmsg_ifindex; }; + +#define RTMSG_NEWDEVICE 0x11 +#define RTMSG_DELDEVICE 0x12 +#define RTMSG_NEWROUTE 0x21 +#define RTMSG_DELROUTE 0x22 +#define RTMSG_AR_FAILED 0x51 /* Address Resolution failed */ #endif diff -u --recursive --new-file v2.1.66/linux/include/linux/joystick.h linux/include/linux/joystick.h --- v2.1.66/linux/include/linux/joystick.h Thu Jul 17 10:06:08 1997 +++ linux/include/linux/joystick.h Sat Nov 29 10:33:21 1997 @@ -1,61 +1,81 @@ #ifndef _LINUX_JOYSTICK_H #define _LINUX_JOYSTICK_H -#define JS_RETURN sizeof(struct js_status) /*number of bytes returned by js_read*/ -#define JS_TRUE 1 -#define JS_FALSE 0 -#define JS_PORT 0x201 /*io port for joystick operations*/ -#define JS_DEF_TIMEOUT 0x1300 /*default timeout value for js_read()*/ -#define JS_DEF_CORR 0 /*default correction factor*/ -#define JS_DEF_TIMELIMIT 10L /*default data valid time =10 jiffies == 100ms*/ -#define JS_X_0 0x01 /*bit mask for x-axis js0*/ -#define JS_Y_0 0x02 /*bit mask for y-axis js0*/ -#define JS_X_1 0x04 /*bit mask for x-axis js1*/ -#define JS_Y_1 0x08 /*bit mask for y-axis js1*/ -#define JS_MAX 2 /*Max number of joysticks*/ -#define PIT_MODE 0x43 /*io port for timer 0*/ -#define PIT_COUNTER_0 0x40 /*io port for timer 0*/ -#define JSIOCSCAL 0x01 /*ioctl cmd to set joystick correction factor*/ -#define JSIOCGCAL 0x02 /*ioctl cmd to get joystick correction factor*/ -#define JSIOCSTIMEOUT 0x03 /*ioctl cmd to set maximum number of iterations - to wait for a timeout*/ -#define JSIOCGTIMEOUT 0x04 /*as above, to get*/ -#define JSIOCSTIMELIMIT 0x05 /*set data retention time*/ -#define JSIOCGTIMELIMIT 0x06 /*get data retention time*/ -#define JSIOCGCONFIG 0x07 /*get the whole js_data[minor] struct*/ -#define JSIOCSCONFIG 0x08 /*set the whole js_data[minor] struct - except js_busy!*/ - -/* - * This union is used for the ioctl to set the scaling factor and to - * return the current values for a joystick. 'buttons' is ignored on - * the ioctl call - */ - -struct js_status -{ - int buttons; - int x; - int y; +/* + * $Id: joystick.h,v 1.2 1997/10/31 19:11:57 mj Exp $ + * + * Copyright (C) 1997 Vojtech Pavlik + */ + +#include +#include + +/* + * Version + */ + +#define JS_VERSION 0x00010006L /* 1.0.6 BCD */ + +/* + * IOCTL commands for joystick driver + */ + +#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ + +#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ +#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ + +#define JSIOCSCORR _IOW('j', 0x21, struct js_corr[4]) /* set correction values */ +#define JSIOCGCORR _IOR('j', 0x22, struct js_corr[4]) /* get correction values */ + +/* + * Types and constants for get/set correction + */ + +#define JS_CORR_NONE 0x00 /* returns raw values */ +#define JS_CORR_BROKEN 0x01 /* broken line */ + +struct js_corr { + __s32 coef[8]; + __u16 prec; + __u16 type; +}; + +/* + * Types and constants for reading from /dev/js + */ + +#define JS_EVENT_BUTTON 0x01 /* button pressed/released */ +#define JS_EVENT_AXIS 0x02 /* joystick moved */ +#define JS_EVENT_INIT 0x80 /* initial state of device */ + +struct js_event { + __u32 time; /* time when event happened in miliseconds since open */ + __u16 value; /* new value */ + __u8 type; /* type of event, see above */ + __u8 number; /* axis/button number */ }; /* - * This struct is used for misc data about the joystick + * Backward (version 0.x) compatibility definitions */ -struct js_config -{ - int js_timeout; /*timeout*/ - int busy; /*joystick is in use*/ - long js_expiretime; /*Time when stick after which stick must be re-read*/ - long js_timelimit; /*Max time before data is invalid*/ - struct js_status js_save; /*last read data*/ - struct js_status js_corr; /*correction factor*/ +#define JS_RETURN sizeof(struct JS_DATA_TYPE) +#define JS_TRUE 1 +#define JS_FALSE 0 +#define JS_X_0 0x01 /* bit mask for x-axis js0 */ +#define JS_Y_0 0x02 /* bit mask for y-axis js0 */ +#define JS_X_1 0x04 /* bit mask for x-axis js1 */ +#define JS_Y_1 0x08 /* bit mask for y-axis js1 */ +#define JS_MAX 2 /* max number of joysticks */ + +struct JS_DATA_TYPE { + int buttons; /* immediate button state */ + int x; /* immediate x axis value */ + int y; /* immediate y axis value */ }; -#define LATCH (1193180L/HZ) /*initial timer 0 value*/ -#define DELTA_TIME(X,Y) ((X)-(Y)+(((X)>=(Y))?0:LATCH)) -extern int joystick_init(void); +extern int js_init(void); #endif /* _LINUX_JOYSTICK_H */ diff -u --recursive --new-file v2.1.66/linux/include/linux/kerneld.h linux/include/linux/kerneld.h --- v2.1.66/linux/include/linux/kerneld.h Sat May 11 00:35:04 1996 +++ linux/include/linux/kerneld.h Sat Nov 29 10:33:21 1997 @@ -8,6 +8,7 @@ #define KERNELD_CANCEL_RELEASE_MODULE 5 /* "rmmod" */ #define KERNELD_REQUEST_ROUTE 6 /* from net/ipv4/route.c */ #define KERNELD_BLANKER 7 /* from drivers/char/console.c */ +#define KERNELD_PNP 8 /* from drivers/pnp/kerneld.c */ #define KERNELD_ARP 256 /* from net/ipv4/arp.c */ /* diff -u --recursive --new-file v2.1.66/linux/include/linux/major.h linux/include/linux/major.h --- v2.1.66/linux/include/linux/major.h Tue May 13 22:41:19 1997 +++ linux/include/linux/major.h Sat Nov 29 10:33:21 1997 @@ -67,6 +67,7 @@ #define Z2RAM_MAJOR 37 #define APBLOCK_MAJOR 38 /* AP1000 Block device */ #define DDV_MAJOR 39 /* AP1000 DDV block device */ +#define NBD_MAJOR 43 /* Network block device */ #define RISCOM8_NORMAL_MAJOR 48 #define RISCOM8_CALLOUT_MAJOR 49 #define MKISS_MAJOR 55 diff -u --recursive --new-file v2.1.66/linux/include/linux/nbd.h linux/include/linux/nbd.h --- v2.1.66/linux/include/linux/nbd.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/nbd.h Sat Nov 29 10:33:21 1997 @@ -0,0 +1,74 @@ +#ifndef LINUX_NBD_H +#define LINUX_NBD_H + +#include +#include + +#define NBD_SET_SOCK _IO( 0xab, 0 ) +#define NBD_SET_BLKSIZE _IO( 0xab, 1 ) +#define NBD_SET_SIZE _IO( 0xab, 2 ) +#define NBD_DO_IT _IO( 0xab, 3 ) +#define NBD_CLEAR_SOCK _IO( 0xab, 4 ) +#define NBD_CLEAR_QUE _IO( 0xab, 5 ) +#define NBD_PRINT_DEBUG _IO( 0xab, 6 ) + +#ifdef MAJOR_NR + +#include + +#define LOCAL_END_REQUEST + +#include + +#ifdef PARANOIA +extern int requests_in; +extern int requests_out; +#endif + +static void +nbd_end_request(struct request *req) +{ +#ifdef PARANOIA + requests_out++; +#endif + if (end_that_request_first( req, !req->errors, "nbd" )) + return; + end_that_request_last( req ); +} + +#define MAX_NBD 128 +#endif + +struct nbd_device { + int refcnt; + int flags; + int harderror; /* Code of hard error */ +#define NBD_READ_ONLY 0x0001 +#define NBD_WRITE_NOCHK 0x0002 + struct socket * sock; + struct file * file; /* If == NULL, device is not ready, yet */ + int magic; /* FIXME: not if debugging is off */ + struct request *head; /* Requests are added here... */ + struct request *tail; +}; + +/* This now IS in some kind of include file... */ + +#define NBD_REQUEST_MAGIC 0x12560953 +#define NBD_REPLY_MAGIC 0x96744668 +#define LO_MAGIC 0x68797548 + +struct nbd_request { + __u32 magic; + __u32 from; + __u32 len; + char handle[8]; + __u32 type; /* == READ || == WRITE */ +}; + +struct nbd_reply { + __u32 magic; + char handle[8]; /* handle you got from request */ + __u32 error; /* 0 = ok, else error */ +}; +#endif diff -u --recursive --new-file v2.1.66/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h --- v2.1.66/linux/include/linux/nfsd/nfsfh.h Tue Nov 18 17:22:08 1997 +++ linux/include/linux/nfsd/nfsfh.h Sat Nov 29 11:09:33 1997 @@ -76,7 +76,9 @@ */ u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int); void fh_compose(struct svc_fh *, struct svc_export *, struct dentry *); +void fh_update(struct svc_fh *); void fh_put(struct svc_fh *); +void nfsd_fh_flush(dev_t); void nfsd_fh_init(void); void nfsd_fh_free(void); diff -u --recursive --new-file v2.1.66/linux/include/linux/nfsd/stats.h linux/include/linux/nfsd/stats.h --- v2.1.66/linux/include/linux/nfsd/stats.h Mon Apr 7 11:35:32 1997 +++ linux/include/linux/nfsd/stats.h Wed Nov 26 13:08:38 1997 @@ -13,6 +13,11 @@ unsigned int rchits; /* repcache hits */ unsigned int rcmisses; /* repcache hits */ unsigned int rcnocache; /* uncached reqs */ + unsigned int fh_cached; /* dentry cached */ + unsigned int fh_valid; /* dentry validated */ + unsigned int fh_fixup; /* dentry fixup validated */ + unsigned int fh_lookup; /* new lookup required */ + unsigned int fh_stale; /* FH stale error */ }; #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.66/linux/include/linux/ppp-comp.h linux/include/linux/ppp-comp.h --- v2.1.66/linux/include/linux/ppp-comp.h Tue Mar 5 00:01:27 1996 +++ linux/include/linux/ppp-comp.h Sat Nov 29 10:33:21 1997 @@ -28,7 +28,7 @@ */ /* - * ==FILEVERSION 960302== + * ==FILEVERSION 970501== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the above date. @@ -50,16 +50,16 @@ #ifndef DO_BSD_COMPRESS #define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */ #endif - +#ifndef DO_DEFLATE +#define DO_DEFLATE 1 /* by default, include Deflate */ +#endif #define DO_PREDICTOR_1 0 #define DO_PREDICTOR_2 0 -#define DO_DEFLATE 0 /* * Structure giving methods for compression/decompression. */ -#ifdef PACKETPTR struct compressor { int compress_proto; /* CCP compression protocol number */ @@ -107,18 +107,20 @@ /* Return decompression statistics */ void (*decomp_stat) (void *state, struct compstat *stats); }; -#endif /* PACKETPTR */ /* - * Return values for decompress routine. - * We need to make these distinctions so that we can disable certain + * The return value from decompress routine is the length of the + * decompressed packet if successful, otherwise DECOMP_ERROR + * or DECOMP_FATALERROR if an error occurred. + * + * We need to make this distinction so that we can disable certain * useful functionality, namely sending a CCP reset-request as a result * of an error detected after decompression. This is to avoid infringing * a patent held by Motorola. * Don't you just lurve software patents. */ -#define DECOMP_OK 0 /* everything went OK */ +#define DECOMP_OK 0 /* no error occured */ #define DECOMP_ERROR 1 /* error detected before decomp. */ #define DECOMP_FATALERROR 2 /* error detected after decomp. */ @@ -169,14 +171,9 @@ #define BSD_MAX_BITS 15 /* largest code size supported */ /* - * Definitions for other, as yet unsupported, compression methods. + * Definitions for Deflate. */ -#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ -#define CILEN_PREDICTOR_1 2 /* length of its config option */ -#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ -#define CILEN_PREDICTOR_2 2 /* length of its config option */ - #define CI_DEFLATE 24 /* config option for Deflate */ #define CILEN_DEFLATE 4 /* length of its config option */ @@ -188,5 +185,14 @@ #define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \ + DEFLATE_METHOD_VAL) #define DEFLATE_CHK_SEQUENCE 0 + +/* + * Definitions for other, as yet unsupported, compression methods. + */ + +#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */ +#define CILEN_PREDICTOR_1 2 /* length of its config option */ +#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */ +#define CILEN_PREDICTOR_2 2 /* length of its config option */ #endif /* _NET_PPP_COMP_H */ diff -u --recursive --new-file v2.1.66/linux/include/linux/ppp_defs.h linux/include/linux/ppp_defs.h --- v2.1.66/linux/include/linux/ppp_defs.h Sun Nov 3 01:04:42 1996 +++ linux/include/linux/ppp_defs.h Sat Nov 29 10:33:21 1997 @@ -28,7 +28,7 @@ */ /* - * ==FILEVERSION 960302== + * ==FILEVERSION 970607== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the above date. @@ -66,18 +66,21 @@ * Protocol field values. */ #define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ #define PPP_IPX 0x2b /* IPX protocol */ #define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ #define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ #define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ #define PPP_COMP 0xfd /* compressed packet */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ #define PPP_IPXCP 0x802b /* IPX Control Protocol */ #define PPP_CCP 0x80fd /* Compression Control Protocol */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ #define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ /* * Values for FCS calculations. diff -u --recursive --new-file v2.1.66/linux/include/linux/rose.h linux/include/linux/rose.h --- v2.1.66/linux/include/linux/rose.h Mon Jul 7 08:19:59 1997 +++ linux/include/linux/rose.h Sat Nov 29 10:33:21 1997 @@ -21,8 +21,10 @@ #define SIOCRSGCAUSE (SIOCPROTOPRIVATE+0) #define SIOCRSSCAUSE (SIOCPROTOPRIVATE+1) #define SIOCRSL2CALL (SIOCPROTOPRIVATE+2) +#define SIOCRSSL2CALL (SIOCPROTOPRIVATE+2) #define SIOCRSACCEPT (SIOCPROTOPRIVATE+3) #define SIOCRSCLRRT (SIOCPROTOPRIVATE+4) +#define SIOCRSGL2CALL (SIOCPROTOPRIVATE+5) #define ROSE_DTE_ORIGINATED 0x00 #define ROSE_NUMBER_BUSY 0x01 diff -u --recursive --new-file v2.1.66/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.1.66/linux/include/linux/videodev.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/videodev.h Sat Nov 29 10:33:21 1997 @@ -0,0 +1,171 @@ +#ifndef __LINUX_VIDEODEV_H +#define __LINUX_VIDEODEV_H + +#ifdef __KERNEL__ + +struct video_device +{ + char name[32]; + int type; + int hardware; + + int (*open)(struct video_device *, int mode); + void (*close)(struct video_device *); + long (*read)(struct video_device *, char *, unsigned long, int noblock); + /* Do we need a write method ? */ + long (*write)(struct video_device *, const char *, unsigned long, int noblock); + int (*ioctl)(struct video_device *, unsigned int , void *); + int (*mmap)(struct video_device *, const char *, unsigned long); + int (*initialize)(struct video_device *); + void *private; + int busy; + int minor; +}; + +extern int videodev_init(void); +#define VIDEO_MAJOR 81 +extern int video_register_device(struct video_device *); +extern void video_unregister_device(struct video_device *); +#endif + + +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ + + +struct video_capability +{ + char name[32]; + int type; + int channels; /* Num channels */ + int audios; /* Num audio devices */ + int maxwidth; /* Supported width */ + int maxheight; /* And height */ + int minwidth; /* Supported width */ + int minheight; /* And height */ +}; + + +struct video_channel +{ + int channel; + char name[32]; + int tuners; + __u32 flags; +#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ +#define VIDEO_VC_AUDIO 2 /* Channel has audio */ + __u16 type; +#define VIDEO_TYPE_TV 1 +#define VIDEO_TYPE_CAMERA 2 +}; + +struct video_tuner +{ + int tuner; + char name[32]; + ulong rangelow, rangehigh; /* Tuner range */ + __u32 flags; +#define VIDEO_TUNER_PAL 1 +#define VIDEO_TUNER_NTSC 2 +#define VIDEO_TUNER_SECAM 4 + __u16 mode; /* PAL/NTSC/SECAM/OTHER */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SECAM 2 +#define VIDEO_MODE_AUTO 3 +}; + +struct video_picture +{ + __u16 brightness; + __u16 hue; + __u16 colour; + __u16 contrast; + __u16 whiteness; /* Black and white only */ + __u16 depth; /* Capture depth */ + __u16 palette; /* Palette in use */ +#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ +#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ +#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ +#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ +}; + +struct video_audio +{ + int audio; /* Audio channel */ + __u16 volume; /* If settable */ + __u16 bass, treble; + __u32 flags; +#define VIDEO_AUDIO_MUTE 1 +#define VIDEO_AUDIO_MUTABLE 2 +#define VIDEO_AUDIO_VOLUME 4 +#define VIDEO_AUDIO_BASS 8 +#define VIDEO_AUDIO_TREBLE 16 +}; + +struct video_clip +{ + __s32 x,y; + __s32 width, height; + struct video_clip *next; /* For user use/driver use only */ +}; + +struct video_window +{ + __u32 x,y; + __u32 width,height; + __u32 chromakey; + __u32 flags; + struct video_clip *clips; /* Set only */ + int clipcount; +#define VIDEO_WINDOW_INTERLACE 1 +}; + +struct video_buffer +{ + void *base; + int height,width; + int depth; + int bytesperline; +}; + + +struct video_key +{ + __u8 key[8]; + __u32 flags; +}; + +#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ +#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ +#define VIDIOCSCHAN _IOW('v',3,int) /* Set channel */ +#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ +#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ +#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ +#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ +#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ +#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */ +#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ +#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ +#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ +#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ +#define VIDIOCGFREQ _IOR('v',15, unsigned long) /* Set tuner */ +#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ +#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ +#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ + + +#define VID_HARDWARE_BT848 1 +#define VID_HARDWARE_QCAM_BW 2 +#define VID_HARDWARE_PMS 3 + +#endif diff -u --recursive --new-file v2.1.66/linux/include/net/snmp.h linux/include/net/snmp.h --- v2.1.66/linux/include/net/snmp.h Sun Sep 7 13:10:43 1997 +++ linux/include/net/snmp.h Sat Nov 29 10:33:21 1997 @@ -113,6 +113,8 @@ unsigned long TcpInSegs; unsigned long TcpOutSegs; unsigned long TcpRetransSegs; + unsigned long TcpInErrs; + unsigned long TcpOutRsts; }; struct udp_mib diff -u --recursive --new-file v2.1.66/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.66/linux/kernel/ksyms.c Wed Nov 26 16:24:03 1997 +++ linux/kernel/ksyms.c Sat Nov 29 10:41:10 1997 @@ -90,6 +90,7 @@ }; #endif + #ifdef CONFIG_MODULES EXPORT_SYMBOL(get_module_symbol); #endif @@ -123,6 +124,7 @@ /* internal kernel memory management */ EXPORT_SYMBOL(__get_free_pages); EXPORT_SYMBOL(free_pages); +EXPORT_SYMBOL(__free_page); EXPORT_SYMBOL(kmem_find_general_cachep); EXPORT_SYMBOL(kmem_cache_create); EXPORT_SYMBOL(kmem_cache_shrink); @@ -142,6 +144,7 @@ EXPORT_SYMBOL(vmtruncate); /* filesystem internal functions */ +EXPORT_SYMBOL(get_super); EXPORT_SYMBOL(getname); EXPORT_SYMBOL(putname); EXPORT_SYMBOL(__fput); @@ -197,6 +200,7 @@ EXPORT_SYMBOL(dput); EXPORT_SYMBOL(get_cached_page); EXPORT_SYMBOL(put_cached_page); +EXPORT_SYMBOL(prune_dcache); EXPORT_SYMBOL(shrink_dcache_sb); EXPORT_SYMBOL(shrink_dcache_parent); @@ -364,7 +368,6 @@ EXPORT_SYMBOL(si_meminfo); /* Added to make file system as module */ -EXPORT_SYMBOL(get_super); EXPORT_SYMBOL(set_writetime); EXPORT_SYMBOL(sys_tz); EXPORT_SYMBOL(__wait_on_super); @@ -374,7 +377,6 @@ EXPORT_SYMBOL(nr_async_pages); EXPORT_SYMBOL(___strtok); EXPORT_SYMBOL(init_fifo); -EXPORT_SYMBOL(super_blocks); EXPORT_SYMBOL(fifo_inode_operations); EXPORT_SYMBOL(chrdev_inode_operations); EXPORT_SYMBOL(blkdev_inode_operations); diff -u --recursive --new-file v2.1.66/linux/kernel/printk.c linux/kernel/printk.c --- v2.1.66/linux/kernel/printk.c Wed Sep 24 20:05:48 1997 +++ linux/kernel/printk.c Sat Nov 29 10:41:10 1997 @@ -109,7 +109,7 @@ log_size--; log_start &= LOG_BUF_LEN-1; sti(); - put_user(c,buf); + __put_user(c,buf); buf++; i++; cli(); @@ -138,7 +138,7 @@ j = log_start + log_size - count; for (i = 0; i < count; i++) { c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1))); - put_user(c, buf++); + __put_user(c, buf++); } if (do_clear) logged_chars = 0; diff -u --recursive --new-file v2.1.66/linux/net/802/Makefile linux/net/802/Makefile --- v2.1.66/linux/net/802/Makefile Mon Apr 7 11:35:32 1997 +++ linux/net/802/Makefile Sat Nov 29 10:41:10 1997 @@ -17,7 +17,7 @@ ifeq ($(CONFIG_LLC),y) SUB_DIRS += transit O_OBJS += llc_sendpdu.o llc_utility.o cl2llc.o -OX_OBJS += llc_macinit.o +OX_OBJS += llc_macinit.o p8022.o psnap.o p8022tr.o endif ifdef CONFIG_TR diff -u --recursive --new-file v2.1.66/linux/net/802/cl2llc.c linux/net/802/cl2llc.c --- v2.1.66/linux/net/802/cl2llc.c Thu Feb 27 10:57:31 1997 +++ linux/net/802/cl2llc.c Sat Nov 29 10:41:10 1997 @@ -196,7 +196,7 @@ switch(pseudo_code[pc]) { case 9: - if ((type != I_CMD) || (fr->i_hdr.i_pflag =0)) + if ((type != I_CMD) || (fr->i_hdr.i_pflag == 0)) break; case 1: lp->remote_busy = 0; diff -u --recursive --new-file v2.1.66/linux/net/802/cl2llc.pre linux/net/802/cl2llc.pre --- v2.1.66/linux/net/802/cl2llc.pre Thu Feb 27 10:57:31 1997 +++ linux/net/802/cl2llc.pre Sat Nov 29 10:41:10 1997 @@ -196,7 +196,7 @@ switch(pseudo_code[pc]) { case IF_F=1_CLEAR_REMOTE_BUSY: - if ((type != I_CMD) || (fr->i_hdr.i_pflag =0)) + if ((type != I_CMD) || (fr->i_hdr.i_pflag == 0)) break; case CLEAR_REMOTE_BUSY: lp->remote_busy = 0; diff -u --recursive --new-file v2.1.66/linux/net/802/fddi.c linux/net/802/fddi.c --- v2.1.66/linux/net/802/fddi.c Fri Apr 4 08:52:26 1997 +++ linux/net/802/fddi.c Sat Nov 29 10:41:10 1997 @@ -56,11 +56,11 @@ int hl = FDDI_K_SNAP_HLEN; struct fddihdr *fddi; - if(type!=htons(ETH_P_IP)) + if(type != ETH_P_IP && type != ETH_P_ARP) hl=FDDI_K_8022_HLEN-3; fddi = (struct fddihdr *)skb_push(skb, hl); fddi->fc = FDDI_FC_K_ASYNC_LLC_DEF; - if(type==htons(ETH_P_IP)) + if(type == ETH_P_IP || type == ETH_P_ARP) { fddi->hdr.llc_snap.dsap = FDDI_EXTENDED_SAP; fddi->hdr.llc_snap.ssap = FDDI_EXTENDED_SAP; @@ -68,7 +68,7 @@ fddi->hdr.llc_snap.oui[0] = 0x00; fddi->hdr.llc_snap.oui[1] = 0x00; fddi->hdr.llc_snap.oui[2] = 0x00; - fddi->hdr.llc_snap.ethertype = htons(type); + fddi->hdr.llc_snap.ethertype = htons(type); } /* Set the source and destination hardware addresses */ @@ -83,6 +83,7 @@ memcpy(fddi->daddr, daddr, dev->addr_len); return(hl); } + return(-hl); } @@ -96,18 +97,29 @@ int fddi_rebuild_header(struct sk_buff *skb) { struct fddihdr *fddi = (struct fddihdr *)skb->data; +#if 0 + struct neighbour *neigh = NULL; - /* Only ARP/IP is currently supported */ - - if (fddi->hdr.llc_snap.ethertype != htons(ETH_P_IP)) + if (skb->dst) + neigh = skb->dst->neighbour; + + if (neigh) + return neigh->ops->resolve(fddi->daddr, skb); +#endif + /* + * Only ARP/IP is currently supported + */ + + if (fddi->hdr.llc_snap.ethertype != __constant_htons(ETH_P_IP)) { - printk("fddi_rebuild_header: Don't know how to resolve type %04X addresses?\n", (unsigned int)htons(fddi->hdr.llc_snap.ethertype)); + printk("%s: Don't know how to resolve type %02X addresses.\n", + skb->dev->name, htons(fddi->hdr.llc_snap.ethertype)); return(0); } /* Try to get ARP to resolve the header and fill destination address */ - return arp_find(fddi->daddr, skb) ? 1 : 0; + return arp_find(fddi->daddr, skb); } /* @@ -127,12 +139,12 @@ * to start of packet data. Assume 802.2 SNAP frames for now. */ - skb->mac.raw = skb->data; /* point to frame control (FC) */ + skb->mac.raw = skb->data; /* point to frame control (FC) */ if(fddi->hdr.llc_8022_1.dsap==0xe0) { skb_pull(skb, FDDI_K_8022_HLEN-3); - type=htons(ETH_P_802_2); + type = __constant_htons(ETH_P_802_2); } else { @@ -159,5 +171,4 @@ /* Assume 802.2 SNAP frames, for now */ return(type); - } diff -u --recursive --new-file v2.1.66/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c --- v2.1.66/linux/net/802/llc_macinit.c Tue May 13 22:41:20 1997 +++ linux/net/802/llc_macinit.c Sat Nov 29 10:41:10 1997 @@ -36,15 +36,14 @@ /* * All incoming frames pass thru mac_data_indicate(). - * Here an llc structure is associated with an skb depending on the source - * MAC address in the pdu. + * On entry the llc structure related to the frame is passed as parameter. * The received sk_buffs with pdus other than I_CMD and I_RSP * are freed by mac_data_indicate() after processing, * the I pdu buffers are freed by the cl2llc client when it no longer needs * the skb. */ -int llc_mac_data_indicate(llcptr lp, struct sk_buff *skb, struct device *dev, struct packet_type *pt) +int llc_mac_data_indicate(llcptr lp, struct sk_buff *skb) { int ll; /* logical length == 802.3 length field */ unsigned char p_flag; @@ -142,7 +141,7 @@ if(lp->llc_callbacks) { - lp->llc_event(lp); + if ( lp->llc_event != NULL ) lp->llc_event(lp); lp->llc_callbacks=0; } return 0; @@ -173,8 +172,7 @@ lp->timer_interval[BUSY_TIMER] = HZ*2; lp->local_sap = ssap; lp->llc_event = event; - lp->remote_mac_len = lp->dev->addr_len; - memcpy(lp->remote_mac, rmac, lp->remote_mac_len); + memcpy(lp->remote_mac, rmac, sizeof(lp->remote_mac)); lp->state = 0; lp->llc_mode = MODE_ADM; lp->remote_sap = dsap; @@ -199,7 +197,8 @@ EXPORT_SYMBOL(llc_unit_data_request); EXPORT_SYMBOL(llc_test_request); EXPORT_SYMBOL(llc_xid_request); - +EXPORT_SYMBOL(llc_mac_data_indicate); +EXPORT_SYMBOL(llc_cancel_timers); #define ALL_TYPES_8022 0 diff -u --recursive --new-file v2.1.66/linux/net/802/llc_sendpdu.c linux/net/802/llc_sendpdu.c --- v2.1.66/linux/net/802/llc_sendpdu.c Wed Dec 18 02:07:55 1996 +++ linux/net/802/llc_sendpdu.c Sat Nov 29 10:41:10 1997 @@ -162,7 +162,6 @@ lp->dev->hard_header(skb, lp->dev, ETH_P_802_3, lp->remote_mac, NULL, fl); skb->arp = 1; - skb->priority=SOPRI_NORMAL; skb->dev=lp->dev; dev_queue_xmit(skb); } @@ -220,7 +219,6 @@ if(tmp!=NULL) { tmp->dev=lp->dev; - tmp->priority=SOPRI_NORMAL; dev_queue_xmit(tmp); } } @@ -288,7 +286,6 @@ { tmp->arp = 1; tmp->dev = lp->dev; - tmp->priority = SOPRI_NORMAL; dev_queue_xmit(skb); } resend_count++; diff -u --recursive --new-file v2.1.66/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c --- v2.1.66/linux/net/appletalk/aarp.c Tue Sep 23 16:48:50 1997 +++ linux/net/appletalk/aarp.c Sat Nov 29 10:41:10 1997 @@ -157,7 +157,6 @@ * Send it. */ - skb->priority = SOPRI_NORMAL; dev_queue_xmit(skb); /* @@ -219,7 +218,6 @@ /* * Send it. */ - skb->priority = SOPRI_NORMAL; dev_queue_xmit(skb); } @@ -279,7 +277,6 @@ /* * Send it. */ - skb->priority = SOPRI_NORMAL; dev_queue_xmit(skb); } @@ -433,10 +430,13 @@ struct aarp_entry *a; unsigned long flags; + skb->nh.raw=skb->data; + /* * Check for localtalk first */ + if(dev->type==ARPHRD_LOCALTLK) { struct at_addr *at=atalk_find_dev_addr(dev); @@ -472,9 +472,7 @@ skb->data[1]=at->s_node; skb->data[2]=ft; - if(skb->sk==NULL) - skb->priority = SOPRI_NORMAL; - else + if(skb->sk) skb->priority = skb->sk->priority; skb->dev = dev; dev_queue_xmit(skb); @@ -487,9 +485,7 @@ if(dev->type==ARPHRD_PPP) { skb->protocol = htons(ETH_P_PPPTALK); - if(skb->sk==NULL) - skb->priority = SOPRI_NORMAL; - else + if(skb->sk) skb->priority = skb->sk->priority; skb->dev = dev; dev_queue_xmit(skb); @@ -519,9 +515,7 @@ if(sa->s_node==ATADDR_BCAST) { ddp_dl->datalink_header(ddp_dl, skb, ddp_eth_multicast); - if(skb->sk==NULL) - skb->priority = SOPRI_NORMAL; - else + if(skb->sk) skb->priority = skb->sk->priority; dev_queue_xmit(skb); restore_flags(flags); @@ -536,9 +530,7 @@ a->expires_at=jiffies+sysctl_aarp_expiry_time*10; ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr); - if(skb->sk==NULL) - skb->priority = SOPRI_NORMAL; - else + if(skb->sk) skb->priority = skb->sk->priority; dev_queue_xmit(skb); restore_flags(flags); @@ -644,9 +636,7 @@ { a->expires_at=jiffies+sysctl_aarp_expiry_time*10; ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr); - if(skb->sk==NULL) - skb->priority = SOPRI_NORMAL; - else + if(skb->sk) skb->priority = skb->sk->priority; dev_queue_xmit(skb); } @@ -828,11 +818,9 @@ } -#ifdef MODULE /* * Remove the AARP entries associated with a device. - * Called from cleanup_module() in ddp.c. */ void aarp_device_down(struct device *dev) { @@ -847,6 +835,7 @@ return; } +#ifdef MODULE /* * General module cleanup. Called from cleanup_module() in ddp.c. */ diff -u --recursive --new-file v2.1.66/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.66/linux/net/appletalk/ddp.c Tue Sep 23 16:48:50 1997 +++ linux/net/appletalk/ddp.c Sat Nov 29 10:41:10 1997 @@ -54,10 +54,11 @@ #include #include #include -#include -#include #include #include +/*#include -- coming soon */ +#include +#include #include #include #include @@ -268,12 +269,12 @@ *iface = tmp->next; kfree_s(tmp, sizeof(struct atalk_iface)); dev->atalk_ptr=NULL; + MOD_DEC_USE_COUNT; } else iface = &tmp->next; } - MOD_DEC_USE_COUNT; } static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa) @@ -301,49 +302,42 @@ } /* + * Probe a Phase 1 device or a device that requires its Net:Node to + * be set via an ioctl. + */ +void atif_send_probe_phase1(struct atalk_iface *iface) +{ + struct ifreq atreq; + struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr; + + sa->sat_addr.s_node = iface->address.s_node; + sa->sat_addr.s_net = ntohs(iface->address.s_net); + + /* We pass the Net:Node to the drivers/cards by a Device ioctl. */ + if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR))) + { + (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR); + if((iface->address.s_net != htons(sa->sat_addr.s_net)) + || (iface->address.s_node != sa->sat_addr.s_node)) + iface->status |= ATIF_PROBE_FAIL; + + iface->address.s_net = htons(sa->sat_addr.s_net); + iface->address.s_node = sa->sat_addr.s_node; + } + + return; +} + +/* * Perform phase 2 AARP probing on our tentative address. */ static int atif_probe_device(struct atalk_iface *atif) { - int ct; int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1; int probe_net=ntohs(atif->address.s_net); int probe_node=atif->address.s_node; - int netct; - int nodect; - - struct ifreq atreq; - struct sockaddr_at *sa; - int err; + int ct, netct, nodect; -/* - * THIS IS A HACK: Farallon cards want to do their own picking of - * addresses. This needs tidying up when someone does localtalk - * drivers - */ - - if((atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP) - && atif->dev->do_ioctl) - { - /* fake up the request and pass it down */ - sa = (struct sockaddr_at*)&atreq.ifr_addr; - sa->sat_addr.s_node = probe_node; - sa->sat_addr.s_net = probe_net; - if(!(err=atif->dev->do_ioctl(atif->dev,&atreq,SIOCSIFADDR))) - { - (void)atif->dev->do_ioctl(atif->dev,&atreq,SIOCGIFADDR); - atif->address.s_net=htons(sa->sat_addr.s_net); - atif->address.s_node=sa->sat_addr.s_node; - return (0); - } - /* - * If it didn't like our faked request then fail: - * This should check against -ENOIOCTLCMD and fall - * through. That needs us to fix all the devices up - * properly. We can then also dump the localtalk test. - */ - return (err); - } /* * Offset the network we start probing with. */ @@ -378,17 +372,23 @@ /* * Probe a proposed address. */ - for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++) - { - aarp_send_probe(atif->dev, &atif->address); - /* - * Defer 1/10th - */ - current->timeout = jiffies + (HZ/10); - current->state = TASK_INTERRUPTIBLE; - schedule(); - if(atif->status & ATIF_PROBE_FAIL) - break; + + if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP) + atif_send_probe_phase1(atif); + else + { + for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++) + { + aarp_send_probe(atif->dev, &atif->address); + /* + * Defer 1/10th + */ + current->timeout = jiffies + (HZ/10); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if(atif->status & ATIF_PROBE_FAIL) + break; + } } if(!(atif->status & ATIF_PROBE_FAIL)) return (0); @@ -664,6 +664,16 @@ } /* + * Actually down the interface. + */ +static inline void atalk_dev_down(struct device *dev) +{ + atrtr_device_down(dev); /* Remove all routes for the device */ + aarp_device_down(dev); /* Remove AARP entries for the device */ + atif_drop_device(dev); /* Remove the device */ +} + +/* * A device event has occurred. Watch for devices going down and * delete our use of them (iface and route). */ @@ -672,8 +682,7 @@ if(event == NETDEV_DOWN) { /* Discard any use of this */ - atrtr_device_down((struct device *)ptr); - atif_drop_device((struct device *)ptr); + atalk_dev_down((struct device *) ptr); } return (NOTIFY_DONE); @@ -820,14 +829,12 @@ break; case SIOCATALKDIFADDR: + case SIOCDIFADDR: if(!suser()) return (-EPERM); if(sa->sat_family != AF_APPLETALK) return (-EINVAL); - if(atif == NULL) - return (-EADDRNOTAVAIL); - atrtr_device_down(atif->dev); - atif_drop_device(atif->dev); + atalk_dev_down(dev); break; } @@ -1431,6 +1438,7 @@ skb_pull(skb, 13); skb->dev = dev; skb->h.raw = skb->data; + skb->nh.raw = skb->data; /* printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]); * printk("tot_len %d, skb->len %d\n", @@ -1821,6 +1829,7 @@ case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCATALKDIFADDR: + case SIOCDIFADDR: return (atif_ioctl(cmd,(void *)arg)); /* @@ -1834,10 +1843,12 @@ case SIOCGIFMTU: case SIOCGIFCONF: case SIOCADDMULTI: - case SIOCDELMULTI: + case SIOCDELMULTI: case SIOCGIFCOUNT: - case SIOGIFINDEX: - case SIOGIFNAME: +#if 0 /* Also coming in the IP merge */ + case SIOCGIFINDEX: +#endif + case SIOCGIFNAME: return ((dev_ioctl(cmd,(void *) arg))); case SIOCSIFMETRIC: @@ -1984,18 +1995,6 @@ } /* - * Actually down the interface. - */ -static void atalk_iface_down(struct atalk_iface *iface) -{ - atrtr_device_down(iface->dev); /* Remove all routes for the device */ - aarp_device_down(iface->dev); /* Remove AARP entries for the device */ - atif_drop_device(iface->dev); /* Remove the device */ - - return; -} - -/* * Note on MOD_{INC,DEC}_USE_COUNT: * * Use counts are incremented/decremented when @@ -2010,16 +2009,6 @@ void cleanup_module(void) { - struct atalk_iface *ifaces = atalk_iface_list, *tmp; - - while(ifaces != NULL) - { - tmp = ifaces->next; - ifaces->dev->atalk_ptr = NULL; - atalk_iface_down(ifaces); - ifaces = tmp; - } - #ifdef CONFIG_SYSCTL atalk_unregister_sysctl(); #endif /* CONFIG_SYSCTL */ diff -u --recursive --new-file v2.1.66/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.1.66/linux/net/sunrpc/clnt.c Wed Nov 26 16:24:03 1997 +++ linux/net/sunrpc/clnt.c Wed Nov 26 15:32:27 1997 @@ -325,16 +325,27 @@ { dprintk("RPC: %4d call_reserveresult (status %d)\n", task->tk_pid, task->tk_status); + /* + * After a call to xprt_reserve(), we must have either + * a request slot or else an error status. + */ + if ((task->tk_status >= 0 && !task->tk_rqstp) || + (task->tk_status < 0 && task->tk_rqstp)) + printk("call_reserveresult: status=%d, request=%p??\n", + task->tk_status, task->tk_rqstp); if (task->tk_status >= 0) { task->tk_action = call_allocate; + goto out; } else if (task->tk_status == -EAGAIN) { task->tk_timeout = task->tk_client->cl_timeout.to_resrvval; task->tk_status = 0; xprt_reserve(task); - return; + goto out; } else if (task->tk_status == -ETIMEDOUT) { + printk("RPC: task timed out\n"); task->tk_action = call_timeout; + goto out; } else { task->tk_action = NULL; } @@ -342,6 +353,8 @@ printk("RPC: task has no request, exit EIO\n"); rpc_exit(task, -EIO); } +out: + return; } /*