diff -u --recursive --new-file v2.4.0-test6/linux/CREDITS linux/CREDITS --- v2.4.0-test6/linux/CREDITS Wed Aug 9 19:19:48 2000 +++ linux/CREDITS Tue Aug 22 15:21:53 2000 @@ -12,7 +12,7 @@ N: Matti Aarnio E: mea@nic.funet.fi D: Alpha systems hacking, IPv6 and other network related stuff -D: One of assisting postmasters for vger.rutgers.edu's lists +D: One of assisting postmasters for vger.kernel.org's lists S: (ask for current address) S: Finland @@ -507,6 +507,13 @@ D: Assorted sched/mm titbits S: Oxfordshire, UK. +N: Mark Corner +E: mcorner@umich.edu +W: http://www.eecs.umich.edu/~mcorner/ +D: USB Bluetooth Driver +S: University of Michigan +S: Ann Arbor, MI + N: Alan Cox W: http://roadrunner.swansea.linux.org.uk/alan.shtml E: alan@lxorguk.ukuu.org.uk @@ -740,6 +747,14 @@ S: 23900 - LECCO (Lc) S: Italy +N: Nils Faerber +E: nils@kernelconcepts.de +D: i810 TCO watchdog driver author +D: Mitsumi LU005 tests and fixes +S: Dreisbachstrasse 24 +S: D-57250 Netphen +S: Germany + N: Rik Faith E: faith@cs.unc.edu E: faith@acm.org @@ -1448,6 +1463,12 @@ D: Author of the dialog utility, foundation D: for Menuconfig's lxdialog. +N: Christoph Lameter +E: christoph@lameter.com +D: Digiboard PC/Xe and PC/Xi, Digiboard EPCA +D: Early protocol filter for bridging code +D: Bug fixes + N: Paul Laufer E: pelaufer@csupomona.edu D: Soundblaster driver fixes, ISAPnP quirk @@ -1633,7 +1654,7 @@ S: USA N: Petko Manolov -E: petkan@spct.net +E: petkan@dce.bg D: USB ethernet (pegasus) driver D: optimizing i[45]86 string routines D: i386 task swithing hacks @@ -1671,6 +1692,16 @@ D: XF86_8514 D: cfdisk (curses based disk partitioning program) +N: Torben Mathiasen +E: torben.mathiasen@compaq.com +E: tmm@image.dk +W: http://tlan.kernel.dk +D: ThunderLAN maintainer +D: ThunderLAN updates and other kernel fixes. +S: Bremensgade 29, st.th +S: 2300 Copenhagen S +S: Denmark + N: Claudio S. Matsuoka E: claudio@conectiva.com E: claudio@helllabs.org @@ -2010,6 +2041,11 @@ W: http://www.speakeasy.org/~kirk/ D: implemented kmod D: modularized BSD Unix domain sockets + +N: Mikael Pettersson +E: mikpe@csd.uu.se +W: http://www.csd.uu.se/~mikpe/ +D: Miscellaneous fixes N: Reed H. Petty E: rhp@draper.net diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.0-test6/linux/Documentation/Changes Wed Aug 9 19:19:48 2000 +++ linux/Documentation/Changes Mon Aug 21 08:09:09 2000 @@ -16,14 +16,16 @@ 'net). The latest revision of this document, in various formats, can always -be found at http://cyberbuzz.gatech.edu/kaboom/linux/Changes-2.4/ -. +be found at . Feel free to translate this document. If you do so, please send me a URL to your translation for inclusion in future revisions of this document. -Last updated: June 11, 2000 +Smotrite file , yavlyaushisya +russkim perevodom dannogo documenta. + +Last updated: August 15, 2000 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -41,12 +43,13 @@ with pcmcia-cs. o Gnu C 2.7.2.3 # gcc --version +o Gnu make 3.77 # make --version o binutils 2.9.1.0.22 # ld -v -o util-linux 2.10g # chsh -v +o util-linux 2.10o # kbdrate -v o modutils 2.3.13 # insmod -V o e2fsprogs 1.18 # /sbin/tune2fs --version -o pcmcia-cs 3.1.13 # cardmgr -V -o PPP 2.4.0b1 # pppd --version +o pcmcia-cs 3.1.19 # cardmgr -V +o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1beta7 # isdnctrl 2>&1|grep version Kernel compilation @@ -59,7 +62,7 @@ have several options for gcc-derived compilers: gcc 2.7.2.3, various versions of egcs, the new gcc 2.95 and upcoming gcc 3.0, and experimental compilers like pgcc. For absolute stability, it is still recommended -that gcc 2.7.2.3 be used to compile your kernel. egcs 1.12 should also +that gcc 2.7.2.3 be used to compile your kernel. egcs 1.1.2 should also work. gcc 2.95 is known to have problems, and using pgcc for your kernel is just asking for trouble. @@ -68,6 +71,11 @@ or derivatives, be sure not to use -fstrict-aliasing (which, depending on your version of gcc 2.95, may necessitate using -fno-strict-aliasing). +Make +---- + +You will need Gnu make 3.77 or later to build the kernel. + Binutils -------- @@ -95,7 +103,7 @@ You do not have to mount it to use it as long as you can live with the default maxima for shared memory and segments. If you wish to change these variables, you have to mount it with the options nr_blocks -and/or nr_inodes. POSIX shared memory is also now implemented via a +and / or nr_inodes. POSIX shared memory is also now implemented via a virtual filesystem. If you want to use it, you'll need to mount the filesystem. The recommended mount location is /dev/shm, and adding the following line to /etc/fstab should take care of things: @@ -124,7 +132,8 @@ New versions of util-linux provide *fdisk support for larger disks, support new options to mount, recognize more supported partition -types, and similar goodies. You'll probably want to upgrade. +types, have a fdformat which works with 2.4 kernels, and similar goodies. +You'll probably want to upgrade. Ksymoops -------- @@ -138,7 +147,15 @@ Upgrade to recent modutils to fix various outstanding bugs which are seen more frequently under 2.3.x, and to enable auto-loading of USB -modules. +modules. In addition, the layout of modules under +/lib/modules/`uname -r`/ has been made more sane. This change also +requires that you upgrade to a recent modutils. + +Mkinitrd +-------- + +These changes to the /lib/modules file tree layout also require that +mkinitrd be upgraded. E2fsprogs --------- @@ -224,110 +241,90 @@ gcc 2.7.2.3 ----------- -o ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz - -o ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz - +o +o -egcs 1.12 +egcs 1.1.2 --------- -o ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2 - -o ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2 - -o ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.tar.bz2 - +o +o +o Binutils ******** 2.9.1 series ------------ -o ftp://ftp.valinux.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz - +o 2.9.5 series ------------ -o ftp://ftp.valinux.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.gz - +o System utilities **************** Util-linux ---------- -o ftp://ftp.cwi.nl/pub/aeb/util-linux/util-linux-2.10g.tar.gz - +o Ksymoops -------- -o ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.3 - +o Modutils -------- -o ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.13.tar.gz - +o + +Mkinitrd +-------- +o E2fsprogs --------- -o http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.tar.gz - -o http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.src.rpm - +o +o LVM toolset ----------- -o http://linux.msede.com/lvm/ +o Pcmcia-cs --------- -o ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.13.tar.gz - +o Jade ---- -o ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz - +o DocBook Stylesheets ------------------- -o http://nwalsh.com/docbook/dsssl/ - +o Intel P6 microcode ------------------ -o http://www.urbanmyth.org/microcode/ - +o Network ******* PPP --- -o ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz - +o Isdn4k-utils ------------ -o ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k- - utils.v3.1beta7.tar.gz - +o Netfilter --------- -o http://netfilter.filewatcher.org/iptables-1.1.1.tar.bz2 - -o http://www.samba.org/netfilter/iptables-1.1.1.tar.bz2 - -o http://netfilter.kernelnotes.org/iptables-1.1.1.tar.bz2 - +o +o +o Ip-route2 --------- -o ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz - +o Suggestions and corrections =========================== diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.0-test6/linux/Documentation/Configure.help Wed Aug 9 19:19:48 2000 +++ linux/Documentation/Configure.help Wed Aug 23 09:30:13 2000 @@ -2305,7 +2305,7 @@ Intel 440LX/BX/GX support CONFIG_AGP_INTEL This option gives you AGP support for the GLX component of the - "soon to be released" XFree86 4.x on Intel 440LX/BX/GX chipsets. + XFree86 4.x on Intel 440LX/BX/GX chipsets. For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from @@ -2320,7 +2320,7 @@ VIA chipset support CONFIG_AGP_VIA This option gives you AGP support for the GLX component of the - "soon to be released" XFree86 4.x on VIA MPV3/Apollo Pro chipsets. + XFree86 4.x on VIA MPV3/Apollo Pro chipsets. For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from @@ -2329,7 +2329,7 @@ AMD Irongate support CONFIG_AGP_AMD This option gives you AGP support for the GLX component of the - "soon to be released" XFree86 4.x on Intel AMD Irongate chipset. + XFree86 4.x on Intel AMD Irongate chipset. For the moment, you should probably say N, unless you want to test the GLX component for XFree86 3.3.6, which can be downloaded from @@ -2350,7 +2350,7 @@ ALI M1541 support CONFIG_AGP_ALI This option gives you AGP support for the GLX component of the - "soon to be released" XFree86 4.x on the ALi M1541 chipset. + XFree86 4.x on the ALi M1541 chipset. This chipset can do AGP 1x and 2x, but note that there is an acknowledged incompatibility with Matrox G200 cards. Due to @@ -2777,7 +2777,8 @@ SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S. - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - - "Pentium-Classic" for the Intel Pentium/Pentium MMX. + - "Pentium-Classic" for the Intel Pentium. + - "Pentium-MMX" for the Intel Pentium MMX. - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II. - "Pentium-III" for the Intel Pentium III. - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D). @@ -3672,27 +3673,6 @@ can be gotten from the document http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html -IP: optimize as router not host -CONFIG_IP_ROUTER - Some Linux network drivers use a technique called copy and checksum - to optimize host performance. For a machine which acts as a router - most of the time and is forwarding most packets to another host this - is however a loss. If you say Y here, copy and checksum will be - switched off. In the future, it may make other changes which - optimize for router operation. - - Note that your box can only act as a router if you enable IP - forwarding in your kernel; you can do that by saying Y to "/proc - file system support" and "Sysctl support" below and executing the - line - - echo "1" > /proc/sys/net/ipv4/ip_forward - - at boot time after the /proc file system has been mounted. You can - do that even if you say N here. - - If unsure, say N here. - IP: kernel level autoconfiguration CONFIG_IP_PNP This enables automatic configuration of IP addresses of devices and @@ -3762,26 +3742,6 @@ Network), but can be distributed all over the Internet. If you want to do that, say Y here and to "IP: multicast routing" below. -IP: aliasing support -CONFIG_IP_ALIAS - Sometimes it is useful to give several IP addresses to a single - physical network interface (serial port or Ethernet card). The most - common case is that you want to serve different WWW or FTP documents - to the outside depending on which of your host names was used to - connect to you. This is called "multihosting" or "virtual domains" - or "virtual hosting services" and is explained in the - Virtual-Services-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . - - Another scenario would be that there are two logical networks living - on your local Ethernet and you want to access them both with the - same Ethernet card. This can also be done if you say Y here. - - The configuration of these alias addresses is done with a special - name syntax explained in Documentation/networking/alias.txt and in - the IP-Alias mini-HOWTO. If you want this, say Y. Most people don't - need it and say N. - IP: multicast routing CONFIG_IP_MROUTE This is used if you want your machine to act as a router for IP @@ -7259,7 +7219,29 @@ module, say M here and read Documentation/modules.txt. If unsure, say N. -Ethertap network tap (EXPERIMENTAL) +Universal TUN/TAP device driver. +CONFIG_TUN + TUN/TAP provides packet reception and transmission for user space programs. + It can be viewed as a simple Point-to-Point or Ethernet device, which + instead of receiving packets from a physical media, receives them from + user space program and instead of sending packets via physical media + writes them to the user space program. + + When a program opens /dev/net/tun, driver creates and registers + corresponding net device tunX or tapX. After a program closed above + devices, driver will automatically delete tunXX or tapXX device and all + routes corresponding to it. + + Please read Documentation/networking/tuntap.txt for more information. + + 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 tun.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what to use this for, you don't need it. + +Ethertap network tap (OBSOLETE) CONFIG_ETHERTAP If you say Y here (and have said Y to "Kernel/User network link driver", above) and create a character special file /dev/tap0 with @@ -8736,6 +8718,13 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +National Semiconductor DP83810 series PCI Ethernet support +CONFIG_NATSEMI + This driver is for the National Semiconductor DP83810 series, + including the 83815 chip. + More specific information and updates are available from + http://www.scyld.com/network/natsemi.html + SK_G16 support CONFIG_SK_G16 If you have a network (Ethernet) card of this type, say Y and read @@ -10173,9 +10162,10 @@ USB Digi International AccelePort USB Serial Driver CONFIG_USB_SERIAL_DIGI_ACCELEPORT - Say Y here if you want to use a Digi AccelePort USB 4 device, - a 4 port USB serial converter. The Digi Acceleport USB 2 and - 8 are not yet supported by this driver. + Say Y here if you want to use Digi AccelePort USB 2 or 4 devices, + 2 port (plus parallel port) and 4 port USB serial converters. The + parallel port on the USB 2 appears as a third serial port on Linux. + The Digi Acceleport USB 8 is not yet supported by this driver. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -10236,16 +10226,19 @@ CONFIG_USB_PEGASUS Say Y if you want to use your USB ethernet device. Supported cards until now are: + ADMtek AN986 (eval. board) Accton 10/100 Billington USB-100 Corega FEter USB-TX MELCO/BUFFALO LUA-TX - D-Link DSB-650TX, DSB-650TX-PNA - Linksys USB100TX - SNC 202 + D-Link DSB-650TX, DSB-650TX-PNA, DSB-650, DU-E10, DU-E100 + Linksys USB100TX, USB10TX + LANEED Ethernet LD-USB/TX + SMC 202 + SOHOware NUB Ethernet If you have devices with vendor IDs other than noted above you should add them in the driver code and send a message - to me (petkan@spct.net) for update. + to me (petkan@dce.bg) for update. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -11297,6 +11290,21 @@ want), say M here and read Documentation/modules.txt. The module will be called smbfs.o. Most people say N, however. +nls support setting +CONFIG_SMB_NLS_REMOTE + This setting allows you to specify a default value for which + codepage the server uses. If this field is left blank no + translations will be done by default. The local codepage/charset + default to CONFIG_NLS_DEFAULT. + + The nls settings can be changed at mount time, if your smbmount + supports that, using the codepage and iocharset parameters. + + Currently no smbmount distributed with samba supports this, it is + assumed future versions will. In the meantime you can get an + unofficial patch for samba 2.0.7 from: + http://www.hojdpunkten.ac.se/054/samba/index.html + Coda file system support (advanced network fs) CONFIG_CODA_FS Coda is an advanced network file system, similar to NFS in that it @@ -14085,7 +14093,13 @@ Creative EMU10K1 based PCI sound cards CONFIG_SOUND_EMU10K1 Say Y or M if you have a PCI sound card using the EMU10K1 - chipset, such as the Creative SBLive! or SB PCI512. + chipset, such as the Creative SBLive!, SB PCI512 or Emu-APS. + +Crystal SoundFusion (CS4280/461x) +CONFIG_SOUND_FUSION + This module drives the Crystal SoundFusion devices (CS4280/46xx series) + when wired as native sound drivers with AC97 codecs. If this driver + does not work try the CS4232 driver. Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 @@ -14374,6 +14388,10 @@ before E-DSS1 was established. Nowadays, all new lines in Germany use E-DSS1. +HiSax Support for US NI1 +CONFIG_HISAX_NI1 + Enable this if you like to use ISDN in US on a NI1 basic rate interface. + Teles 16.0/8.0 CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 @@ -14502,6 +14520,13 @@ See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. +NETspider U card +CONFIG_HISAX_NETJET_U + This enables HiSax support for the Netspider U interface ISDN card from + Traverse Technologies. + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + Niccy PnP/PCI card CONFIG_HISAX_NICCY This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. @@ -14590,7 +14615,7 @@ called sc.o. See Documentation/isdn/README.sc and http://www.spellcast.com for more information. -Eicon.Diehl active card support +Eicon active card support CONFIG_ISDN_DRV_EICON Say Y here if you have an Eicon active ISDN card. In order to use this card, additional firmware is necessary, which has to be loaded @@ -14598,6 +14623,11 @@ latest isdn4k-utils package. Please read the file Documentation/isdn/README.eicon for more information. +Eicon Diva Server card support +CONFIG_ISDN_DRV_EICON_PCI + Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card. + Please read Documentation/isdn/README.eicon for more information. + Eicon old-type card support CONFIG_ISDN_DRV_EICON_ISA Say Y here if you have an old-type Eicon active ISDN card. In order @@ -14606,10 +14636,18 @@ the latest isdn4k-utils package. Please read the file Documentation/isdn/README.eicon for more information. -Support AT-Fax Class 2 commands +Eicon driver type standalone +CONFIG_ISDN_DRV_EICON_STANDALONE + Enable this option if you want the eicon driver as standalone + version with no interface to the ISDN4Linux isdn module. If you + say Y here, the eicon module only supports the Diva Server PCI + cards and will provide its own IDI interface. You should say N + here. + +Support AT-Fax Class 1 and 2 commands CONFIG_ISDN_TTY_FAX If you say Y here, the modem-emulator will support a subset of the - Fax Class 2 commands. Using a getty with fax-support + Fax Class 1 and 2 commands. Using a getty with fax-support (mgetty+sendfax, hylafax), you will be able to use your Linux box as an ISDN-fax-machine. This must be supported by the lowlevel driver also. See Documentation/isdn/README.fax for more information. @@ -14678,6 +14716,10 @@ Champ, Ergo and Metro. You will then get a module called hysdn.o. Please read the file Documentation/isdn/README.hysdn for more information. + +HYSDN CAPI 2.0 support +CONFIG_HYSDN_CAPI + Say Y here if you like to use Hypercope's CAPI 2.0 interface Support for Sun4 architecture CONFIG_SUN4 diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.0-test6/linux/Documentation/DocBook/Makefile Thu Jul 27 17:37:59 2000 +++ linux/Documentation/DocBook/Makefile Sat Aug 12 14:25:54 2000 @@ -81,6 +81,11 @@ $(TOPDIR)/scripts/docgen $(APISOURCES) \ kernel-api.sgml +kernel-api-man: $(APISOURCES) + @rm -rf $(TOPDIR)/Documentation/man + $(TOPDIR)/scripts/kernel-doc -man $^ | \ + $(PERL) $(TOPDIR)/scripts/split-man $(TOPDIR)/Documentation/man + parportbook: $(JPG-parportbook) parportbook.ps: $(EPS-parportbook) parportbook.sgml: parportbook.tmpl $(TOPDIR)/drivers/parport/init.c diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/README.DAC960 linux/Documentation/README.DAC960 --- v2.4.0-test6/linux/Documentation/README.DAC960 Wed Aug 9 19:19:48 2000 +++ linux/Documentation/README.DAC960 Mon Aug 21 09:23:54 2000 @@ -1,11 +1,11 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Version 2.2.7 for Linux 2.2.16 - Version 2.4.7 for Linux 2.4.0 + Version 2.2.8 for Linux 2.2.16 + Version 2.4.8 for Linux 2.4.0 PRODUCTION RELEASE - 1 August 2000 + 19 August 2000 Leonard N. Zubkoff Dandelion Digital @@ -28,9 +28,9 @@ well as the most recent release of this driver, will always be available from my Linux Home Page at URL "http://www.dandelion.com/Linux/". The Linux DAC960 driver supports all current Mylex PCI RAID controllers including the new -eXtremeRAID 2000/3000 and AcceleRAID 352/170 models which have an entirely new -firmware interface from the older eXtremeRAID 1100, AcceleRAID 150/200/250, and -DAC960PJ/PG/PU/PD/PL. See below for a complete controller list as well as +eXtremeRAID 2000/3000 and AcceleRAID 352/170/160 models which have an entirely +new firmware interface from the older eXtremeRAID 1100, AcceleRAID 150/200/250, +and DAC960PJ/PG/PU/PD/PL. See below for a complete controller list as well as minimum firmware version requirements. For simplicity, in most places this documentation refers to DAC960 generically rather than explicitly listing all the supported models. @@ -120,6 +120,12 @@ 100MHz Intel i960RM RISC Processor 16MB/32MB/64MB ECC SDRAM Memory +AcceleRAID 160 + 1 Wide Ultra-160 LVD SCSI channel + 100MHz Intel i960RS RISC Processor + Built in 16M ECC SDRAM Memory + PCI Low Profile Form Factor - fit for 2U height + eXtremeRAID 1100 (DAC1164P) 3 Wide Ultra-2/LVD SCSI channels 233MHz StrongARM SA 110 Processor @@ -164,8 +170,8 @@ Intel i960 RISC Processor 2MB/4MB/8MB/16MB/32MB DRAM Memory -For the eXtremeRAID 2000/3000 and AcceleRAID 352/170, firmware version 6.00-01 -or above is required. +For the eXtremeRAID 2000/3000 and AcceleRAID 352/170/160, firmware version +6.00-01 or above is required. For the eXtremeRAID 1100, firmware version 5.06-0-52 or above is required. @@ -203,10 +209,10 @@ replacing "/usr/src" with wherever you keep your Linux kernel source tree: cd /usr/src - tar -xvzf DAC960-2.2.7.tar.gz (or DAC960-2.4.7.tar.gz) + tar -xvzf DAC960-2.2.8.tar.gz (or DAC960-2.4.8.tar.gz) mv README.DAC960 linux/Documentation mv DAC960.[ch] linux/drivers/block - patch -p0 < DAC960.patch + patch -p0 < DAC960.patch (if DAC960.patch is included) cd linux make config make depend diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/arm/SA1100/CERF linux/Documentation/arm/SA1100/CERF --- v2.4.0-test6/linux/Documentation/arm/SA1100/CERF Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/CERF Sun Aug 13 09:58:24 2000 @@ -0,0 +1,34 @@ +The Intrinsyc CerfBoard is a StrongARM 1110-based computer on a board that measures +approximately 2" square. It includes an Ethernet controller, an RS232-compatible serial port, a +USB function port, and one CompactFlash+ slot on the back. Pictures can be found at the +Intrinsyc website, http://www.intrinsyc.com. + +This document describes the support in the Linux kernel for the Intrinsyc CerfBoard as of +version 2.4.0-test4-np1. + +Supported in this version: + - CompactFlash+ slot (select PCMCIA in General Setup and any options that may be required) + - Onboard Crystal CS8900 Ethernet controller (Cerf CS8900A support in Network Devices) + - Serial ports with a serial console (hardcoded to 38400 8N1) + +Not supported in this version (yet): + - LCD driver/touchscreen interface + - UDC (a driver exists right now, but is unstable and slow and only works with the Linux USB) + +In order to get this kernel onto your Cerf, you need a server that runs both BOOTP and +TFTP. Detailed instructions should have come with your evaluation kit on how to use the +bootloader. This series of commands will suffice: + + make cerf_config + make xconfig + make dep + make zImage + cp arch/arm/boot/zImage + +The default config uses a 4MB RAM disk located at 0xc0500000 as root. Setting the board to +mount root from a NFS partition works, too. + + +I-Gene Leong, Intrinsyc Software Inc. +ileong@intrinsyc.com + diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/arm/SA1100/nanoEngine linux/Documentation/arm/SA1100/nanoEngine --- v2.4.0-test6/linux/Documentation/arm/SA1100/nanoEngine Wed Dec 31 16:00:00 1969 +++ linux/Documentation/arm/SA1100/nanoEngine Sun Aug 13 09:58:24 2000 @@ -0,0 +1,9 @@ +nanoEngine +---------- + +"nanoEngine" is a SA1110 based single board computer from +Bright Star Engineering Inc. See www.brightstareng.com/arm +for more info. + +Ref: Stuart Adams + diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt --- v2.4.0-test6/linux/Documentation/digiboard.txt Sun Nov 7 16:37:33 1999 +++ linux/Documentation/digiboard.txt Tue Aug 22 15:21:53 2000 @@ -20,7 +20,7 @@ It is available from ftp.digi.com/ftp.digiboard.com. You can write me if you need an patch for this driver. - Bernhard Kaindl (bkaindl@netway.at) 6. April 1997. +Bernhard Kaindl (bkaindl@netway.at) 6. April 1997. Configuring the Driver ---------------------- @@ -153,20 +153,18 @@ Sources of Information ---------------------- -Web page: http://private.fuller.edu/clameter/digi.html +Please contact digi directly digilnux@dgii.com. Forward any information of +general interest to me. -Mailing list: digiboard@list.fuller.edu +Web page (mainly of historical interest): http://lameter.com/digi -(Write e-mail to that address to subscribe. Common ListServ commands work. -Archive of messages available) - -Christoph Lameter (clameter@fuller.edu) 16. April 1996. +Christoph Lameter (christoph@lameter.com) Aug 14, 2000. Supporting Tools ---------------- -Some tools and more detailed information can be found at -ftp://ftp.fuller.edu/Linux/digi +Some (old) tools and more detailed information can be found at +ftp://lameter.com/digi The "ditty" tool described in the Digiboard Manuals for other Unixes is also available. diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/digiepca.txt linux/Documentation/digiepca.txt --- v2.4.0-test6/linux/Documentation/digiepca.txt Thu Apr 29 11:53:41 1999 +++ linux/Documentation/digiepca.txt Tue Aug 22 15:21:53 2000 @@ -81,16 +81,12 @@ -> FTP: ftp://dgii.com -> Webpage: http://www.dgii.com --> Webpage: http://private.fuller.edu/clameter/digi.html --> Mailing List: digiboard@list.fuller.edu Note write e-mail to subscribe - common ListServ commands will not work. +-> Webpage: http://lameter.com/digi Acknowledgments: ---------------- Much of this work (And even text) was derived from a similar document supporting the original public domain DigiBoard driver Copyright (C) 1994,1995 Troy De Jongh. Many thanks to Christoph Lameter -(clameter@fuller.edu) and Mike McLagan (mike.mclagan@linux.org) who authored +(christoph@lameter.com) and Mike McLagan (mike.mclagan@linux.org) who authored and contributed to the original document. - - diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/fb/matroxfb.txt linux/Documentation/fb/matroxfb.txt --- v2.4.0-test6/linux/Documentation/fb/matroxfb.txt Wed Aug 9 19:19:48 2000 +++ linux/Documentation/fb/matroxfb.txt Thu Aug 10 12:34:31 2000 @@ -146,6 +146,27 @@ strange pattern on screen and so on. Devices not enabled by BIOS are still initialized. It is default. init - driver initializes every device it knows about. +memtype - specifies memory type, implies 'init'. This is valid only for G200 + and G400 and has following meaning: + G200: 0 -> 2x128Kx32 chips, 2MB onboard, probably sgram + 1 -> 2x128Kx32 chips, 4MB onboard, probably sgram + 2 -> 2x256Kx32 chips, 4MB onboard, probably sgram + 3 -> 2x256Kx32 chips, 8MB onboard, probably sgram + 4 -> 2x512Kx16 chips, 8/16MB onboard, probably sdram only + 5 -> same as above + 6 -> 4x128Kx32 chips, 4MB onboard, probably sgram + 7 -> 4x128Kx32 chips, 8MB onboard, probably sgram + G400: 0 -> 2x512Kx16 SDRAM, 16/32MB + 2x512Kx32 SGRAM, 16/32MB + 1 -> 2x256Kx32 SGRAM, 8/16MB + 2 -> 4x128Kx32 SGRAM, 8/16MB + 3 -> 4x512Kx32 SDRAM, 32MB + 4 -> 4x256Kx32 SGRAM, 16/32MB + 5 -> 2x1Mx32 SDRAM, 32MB + 6 -> reserved + 7 -> reserved + You should use sdram or sgram parameter in addition to memtype + parameter. nomtrr - disables write combining on frame buffer. This slows down driver but there is reported minor incompatibility between GUS DMA and XFree under high loads if write combining is enabled (sound dropouts). diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/i386/IO-APIC.txt linux/Documentation/i386/IO-APIC.txt --- v2.4.0-test6/linux/Documentation/i386/IO-APIC.txt Thu May 11 15:30:05 2000 +++ linux/Documentation/i386/IO-APIC.txt Mon Aug 21 08:57:35 2000 @@ -109,8 +109,8 @@ use smart try-and-err techniques to find out the correct pirq line ... -good luck and mail to linux-smp@vger.rutgers.edu or -linux-kernel@vger.rutgers.edu if you have any problems that are not covered +good luck and mail to linux-smp@vger.kernel.org or +linux-kernel@vger.kernel.org if you have any problems that are not covered by this document. -- mingo diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v2.4.0-test6/linux/Documentation/isdn/README Wed Aug 9 19:19:49 2000 +++ linux/Documentation/isdn/README Sun Aug 13 10:05:32 2000 @@ -242,7 +242,7 @@ 0 = transparent 1 = transparent with audio features (e.g. DSP) 2 = Fax G3 Class 2 commands (S14 has to be set to 11) - 2 = Fax G3 Class 1 commands (S14 has to be set to 11) + 3 = Fax G3 Class 1 commands (S14 has to be set to 11) 16 250 Send-Packet-size/16 17 8 Window-size (not yet implemented) 18 4 Bit coded register, Service-Octet-1 to accept, diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.4.0-test6/linux/Documentation/isdn/README.HiSax Wed Aug 9 19:19:49 2000 +++ linux/Documentation/isdn/README.HiSax Mon Aug 21 07:49:02 2000 @@ -53,7 +53,7 @@ Sedlbauer ISDN-Controller PC/104 USR Sportster internal TA (compatible Stollmann tina-pp V3) ith Kommunikationstechnik GmbH MIC 16 ISA card -Traverse Technologie NETjet PCI S0 card +Traverse Technologie NETjet PCI S0 card and NETspider U card Dr. Neuhaus Niccy PnP/PCI Siemens I-Surf 1.0 Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom) @@ -134,7 +134,12 @@ The parameter for the D-Channel protocol may be omitted if you selected the correct one during kernel config. Valid values are "1" for German 1TR6, -"2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel). +"2" for EDSS1 (Euro ISDN), "3" for leased lines (no D-Channel) and "4" +for US NI1. +With US NI1 you have to include your SPID into the MSN setting in the form +: for example (your phonenumber is 1234 your SPID 5678): +AT&E1234:5678 on ttyI interfaces +isdnctrl eaz ippp0 1234:5678 on network devices The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying the I/O addresses of the ISAC and HSCX chips, respectively. @@ -186,8 +191,8 @@ 34 Gazel ISDN cards (PCI) none 35 HFC 2BDS0 PCI none 36 W6692 based PCI cards none - 37 HFC 2BDS0 S+, SP/PCMCIA irq,io (pcmcia must be set with cardmgr) - + 37 HFC 2BDS0 S+, SP/PCMCIA irq,io (pcmcia must be set with cardmgr) + 38 NETspider U PCI card none At the moment IRQ sharing is only possible with PCI cards. Please make sure that your IRQ is free and enabled for ISA use. @@ -291,7 +296,9 @@ 34 Gazel ISDN cards (PCI) no parameter 35 HFC 2BDS0 PCI no parameter 36 W6692 based PCI cards none - 37 HFC 2BDS0 S+,SP/PCMCIA pa=irq, pb=io + 37 HFC 2BDS0 S+,SP/PCMCIA ONLY WORKS AS A MODULE ! + 38 NETspider U PCI card none + Running the driver ------------------ diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon --- v2.4.0-test6/linux/Documentation/isdn/README.eicon Mon Mar 27 08:08:20 2000 +++ linux/Documentation/isdn/README.eicon Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -$Id: README.eicon,v 1.7 2000/03/06 16:38:43 armin Exp $ +$Id: README.eicon,v 1.9 2000/06/08 08:50:25 armin Exp $ (c) 1999,2000 Armin Schindler (mac@melware.de) (c) 1999,2000 Cytronics & Melware (info@melware.de) @@ -40,6 +40,7 @@ ------------------ - DIVA Server BRI/PCI 2M - DIVA Server PRI/PCI 2M (9M 23M 30M) +- DIVA Server 4BRI/PCI supported functions of onboard DSPs: - analog modem - fax group 2/3 (Fax Class 2 commands) @@ -80,7 +81,7 @@ Example for a BRI card with E-DSS1 Protocol with PtP configuration. - eiconctrl [-d DriverId] load etsi -n -t0 -s1 + eiconctrl [-d DriverId] load etsi -n -t1 -s1 Example for loading and starting a PRI card with E-DSS1 Protocol. @@ -99,6 +100,18 @@ the necessary D-Channel traces for isdnlog. +FILECHECK: +A part of the eicon driver source code files are provided +by Eicon Technology. In order to get the best support from Eicon, +these files are tested with a checksum, just to know if the files +were modified. This does *not* mean, you are not allowed to modify the +driver. If you want to improve the driver or you fix a bug, please do +so and let me (or Eicon) know, about the necessary changes. So +every user knows, if the driver he uses is modified or checked with +Eicon files. When the driver has been loaded, in the syslog you will +find something like "verified" or "modified" right after the version. + + Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH for sponsoring and testing fax @@ -113,3 +126,4 @@ Armin Schindler mac@melware.de http://www.melware.de + diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/isdn/README.fax linux/Documentation/isdn/README.fax --- v2.4.0-test6/linux/Documentation/isdn/README.fax Thu Nov 11 20:11:31 1999 +++ linux/Documentation/isdn/README.fax Sun Aug 13 10:05:32 2000 @@ -24,6 +24,9 @@ Eicon DIVA Server BRI/PCI - full support with both B-channels. +Eicon DIVA Server 4BRI/PCI + - full support with all B-channels. + Eicon DIVA Server PRI/PCI - full support on amount of B-channels depending on DSPs on board. diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/isdn/README.hysdn linux/Documentation/isdn/README.hysdn --- v2.4.0-test6/linux/Documentation/isdn/README.hysdn Wed Aug 9 19:19:49 2000 +++ linux/Documentation/isdn/README.hysdn Mon Aug 21 07:49:02 2000 @@ -1,9 +1,13 @@ -$Id: README.hysdn,v 1.1 2000/02/10 19:46:15 werner Exp $ +$Id: README.hysdn,v 1.3 2000/08/06 09:22:51 armin Exp $ The hysdn driver has been written by by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver under the GNU Public License. +The CAPI 2.0-support was added by Ulrich Albrecht (ualbrecht@hypercope.de) +for Hypercope GmbH Aachen, Germany. + + 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 @@ -41,15 +45,19 @@ enable ISDN support in the kernel config and support for HYSDN cards in the active cards submenu. The driver may only be compiled and used if support for loadable modules and the process filesystem have been enabled. - No other ISDN options need to be enabled for these cards. - Up to now these cards do not use or require the standard isdn interface - module (isdn.o), but registers itself as an ethernet card. All necessary + These cards provide two different interfaces to the kernel. Without the + optional CAPI 2.0 support, they register as ethernet card. IP-routing + to a ISDN-destination is performed on the card itself. All necessary handlers for various protocols like ppp and others as well as config info and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de. - The driver has been included in the i4l tree as a CAPI compliant module - is under development and will be connected to the standard i4l modules - additionally. + + With CAPI 2.0 support enabled, the card can also be used as a CAPI 2.0 + compliant devices with either CAPI 2.0 applications + (check isdn4k-utils) or -using the capidrv module- as a regular + isdn4linux device. This is done via the same mechanism as with the + active AVM cards and in fact uses the same module. + 2. Loading/Unloading the driver @@ -58,7 +66,14 @@ If a loaded driver shall be unloaded all open files in the /proc/net/hysdn subdir need to be closed and all ethernet interfaces allocated by this driver must be shut down. Otherwise the module counter will avoid a module - unload. + unload. + + If you are using the CAPI 2.0-interface, make sure to load/modprobe the + kernelcapi-module first. + + If you plan to use the capidrv-link to isdn4linux, make sure to load + capidrv.o after all modules using this driver (i.e. after hysdn and + any avm-specific modules). 3. Entries in the /proc filesystem @@ -160,8 +175,11 @@ 6. Where to get additional info and help If you have any problems concerning the driver or configuration contact - the Hypercope support team (www.hypercope.de) and or the author - Werner Cornelius (werner@isdn4linux or cornelius@titro.de) + the Hypercope support team (support@hypercope.de) and or the authors + Werner Cornelius (werner@isdn4linux or cornelius@titro.de) or + Ulrich Albrecht (ualbrecht@hypercope.de). + + diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt --- v2.4.0-test6/linux/Documentation/kernel-docs.txt Mon Jul 10 16:47:18 2000 +++ linux/Documentation/kernel-docs.txt Wed Aug 23 09:33:09 2000 @@ -278,7 +278,7 @@ Author: Stephen C. Tweedie. URL: ftp://ftp.uk.linux.org:/pub/linux/sct/fs/jfs/journal-design.ps.gz - Keywords: ext3, journalist. + Keywords: ext3, journaling. Description: Excellent 8-pages paper explaining the journaling capabilities added to ext2 by the author, showing different problems faced and the alternatives chosen. @@ -476,6 +476,14 @@ URL: http://www.linux-mag.com/2000-03/gear_01.html Keywords: PCI, bus, bus-mastering. Description: The title says it all. + + * Title: "Linux 2.4 Kernel Internals" + Author: Tigran Aivazian. + URL: http://www.moses.uklinux.net/patches/lki.html + Keywords: Linux, kernel, VFS, SMP boot + Description: A little book used for a short training course + I gave on this subject at VERITAS. Covers building the kernel + image, booting (including SMP), process management, VFS and more. BOOKS: (Not on-line) diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt --- v2.4.0-test6/linux/Documentation/networking/arcnet-hardware.txt Sun Nov 7 16:37:33 1999 +++ linux/Documentation/networking/arcnet-hardware.txt Tue Aug 22 15:21:54 2000 @@ -3063,7 +3063,7 @@ ** Tiara ** (model unknown) ------------------------- - - from Christoph Lameter + - from Christoph Lameter Here is information about my card as far as I could figure it out: diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt --- v2.4.0-test6/linux/Documentation/networking/arcnet.txt Mon Jul 5 19:52:52 1999 +++ linux/Documentation/networking/arcnet.txt Mon Aug 21 08:57:35 2000 @@ -70,7 +70,7 @@ There are archives of the mailing list at: http://tichy.ch.uj.edu.pl/lists/linux-arcnet -The people on linux-net@vger.rutgers.edu have also been known to be very +The people on linux-net@vger.kernel.org have also been known to be very helpful, especially when we're talking about ALPHA Linux kernels that may or may not work right in the first place. diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/ax25.txt linux/Documentation/networking/ax25.txt --- v2.4.0-test6/linux/Documentation/networking/ax25.txt Mon Jul 7 08:19:59 1997 +++ linux/Documentation/networking/ax25.txt Mon Aug 21 08:57:35 2000 @@ -8,7 +8,7 @@ There is an active mailing list for discussing Linux amateur radio matters called linux-hams. To subscribe to it, send a message to -Majordomo@vger.rutgers.edu with the words "subscribe linux-hams" in the body +majordomo@vger.kernel.org with the words "subscribe linux-hams" in the body of the message, the subject field is ignored. Jonathan G4KLX diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/ethertap.txt linux/Documentation/networking/ethertap.txt --- v2.4.0-test6/linux/Documentation/networking/ethertap.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/networking/ethertap.txt Wed Aug 23 09:30:13 2000 @@ -1,3 +1,9 @@ +NOTE: Ethertap is now an obsolete facility, and is scheduled + to be removed in the 2.5.x kernel series. Those writing + applications using ethertap should convert their code to + use the TUN/TAP driver instead, see 'tuntap.txt' in this + directory for more details. -DaveM + Ethertap programming mini-HOWTO ------------------------------- diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.4.0-test6/linux/Documentation/networking/ip-sysctl.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/networking/ip-sysctl.txt Fri Aug 18 10:26:25 2000 @@ -194,13 +194,84 @@ Enable timestamps as defined in RFC1323. tcp_sack - BOOLEAN - Enable select acknowledgments. + Enable select acknowledgments (SACKS). + +tcp_fack - BOOLEAN + Enable FACK congestion avoidance and fast restransmission. + The value is not used, if tcp_sack is not enabled. + +tcp_dsack - BOOLEAN + Allows TCP to send "duplicate" SACKs. + +tcp_ecn - BOOLEN + Enable Explicit Congestion Notification in TCP. + +tcp_reordering - INTEGER + Maximal reordering of packets in a TCP stream. + Default: 3 tcp_retrans_collapse - BOOLEAN Bug-to-bug compatibility with some broken printers. On retransmit try to send bigger packets to work around bugs in certain TCP stacks. +tcp_wmem - vector of 3 INTEGERs: min, default, max + min: Amount of memory reserved for send buffers for TCP socket. + Each TCP socket has rights to use it due to fact of its birth. + Default: 4K + + default: Amount of memory allowed for send buffers for TCP socket + by default. This value overrides net.core.wmem_default used + by other protocols, it is usually lower than net.core.wmem_default. + Default: 16K + + max: Maximal amount of memory allowed for automatically selected + send buffers for TCP socket. This value does not override + net.core.wmem_max, "static" selection via SO_SNDBUF does not use this. + Default: 128K + +tcp_rmem - vector of 3 INTEGERs: min, default, max + min: Minimal size of receive buffer used by TCP sockets. + It is guaranteed to each TCP socket, even under moderate memory + pressure. + Default: 8K + + default: default size of receive buffer used by TCP sockets. + This value overrides net.core.rmem_default used by other protocols. + Default: 87380 bytes. This value results in window of 65535 with + default setting of tcp_adv_win_scale and tcp_app_win:0 and a bit + less for default tcp_app_win. See below about these variables. + + max: maximal size of receive buffer allowed for automatically + selected receiver buffers for TCP socket. This value does not override + net.core.rmem_max, "static" selection via SO_RCVBUF does not use this. + Default: 87380*2 bytes. + +tcp_mem - vector of 3 INTEGERs: min, pressure, max + low: below this number of pages TCP is not bothered about its + memory appetite. + + pressure: when amount of memory allocated by TCP exceeds this number + of pages, TCP moderates its memory consumption and enters memory + pressure mode, which is exited when memory consumtion falls + under "low". + + high: number of pages allowed for queueing by all TCP sockets. + + Defaults are calculated at boot time from amount of available + memory. + +tcp_app_win - INTEGER + Reserve max(window/2^tcp_app_win, mss) of window for application + buffer. Value 0 is special, it means that nothing is reserved. + Default: 31 + +tcp_adv_win_scale - INTEGER + Count buffering overhead as bytes/2^tcp_adv_win_scale + (if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale), + if it is <= 0. + Default: 2 + 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 @@ -305,4 +376,4 @@ Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.13 2000/01/18 08:24:09 davem Exp $ +$Id: ip-sysctl.txt,v 1.16 2000/08/13 18:24:11 davem Exp $ diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/tuntap.txt linux/Documentation/networking/tuntap.txt --- v2.4.0-test6/linux/Documentation/networking/tuntap.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/tuntap.txt Wed Aug 23 09:30:13 2000 @@ -0,0 +1,150 @@ +Universal TUN/TAP device driver. +Copyright (C) 1999-2000 Maxim Krasnyansky + + Linux, Solaris drivers + Copyright (C) 1999-2000 Maxim Krasnyansky + + FreeBSD TAP driver + Copyright (c) 1999-2000 Maksim Yevmenkin + +1. Description + TUN/TAP provides packet reception and transmission for user space programs. + It can be viewed as a simple Point-to-Point or Ethernet device, which + instead of receiving packets from a physical media, receives them from + user space program and instead of sending packets via physical media + writes them to the user space program. + + When a program opens /dev/net/tun, driver creates and registers corresponding + net device tunX or tapX. After a program closed above devices, driver will + automatically delete tunXX or tapXX device and all routes corresponding to it. + + This package(http://vtun.sourceforge.net/tun) contains two simple example + programs how to use tun and tap devices. Both programs works like + bridge between two network interfaces. + br_select.c - bridge based on select system call. + br_sigio.c - bridge based on async io and SIGIO signal. + However the best example is VTun http://vtun.sourceforge.net :)) + +2. Installation + Run './configure' to configure the driver. + + Run 'make install' to compile and install driver module and to create + /dev/net/tun device node. + +3. Loading driver module + Linux + To load TUN/TAP driver module run: + modprobe tun + To configure automatic loading of the 'tun' module you have to add: + alias char-major-195 tun + to the /etc/conf.modules, and run: + modprobe -a + TUN/TAP driver will be automatically loaded when application access + /dev/net/tun. + If "Kernel module loader" - module auto-loading support is not enabled + in your kernel then you can add + modprobe tun + to one of the startup rc files. + +4. Program interface + 4.1 Network device allocation: + + int tun_alloc(char *dev) + { + struct ifreq ifr; + int fd, err; + + if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) + return tun_alloc_old(dev); + + memset(&ifr, 0, sizeof(ifr)); + + /* Flags: IFF_TUN - TUN device (no Ethernet headers) + * IFF_TAP - TAP device + * + * IFF_NO_PI - Do not provide packet information + */ + ifr.ifr_flags = IFF_TUN; + if( *dev ) + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ + close(fd); + return err; + } + strcpy(dev, ifr.ifr_name); + return fd; + } + + 4.2 Frame format: + If flag IFF_NO_PI is not set each frame format is: + Flags [2 bytes] + Proto [2 bytes] + Raw protocol(IP, IPv6, etc) frame. + +Universal TUN/TAP device driver Frequently Asked Question. + +1. What is the TUN ? +The TUN is Virtual Point-to-Point network device. +TUN driver was designed as low level kernel support for +IP tunneling. It provides to userland application +two interfaces: + - /dev/tunX - character device; + - tunX - virtual Point-to-Point interface. + +Userland application can write IP frame to /dev/tunX +and kernel will receive this frame from tunX interface. +In the same time every frame that kernel writes to tunX +interface can be read by userland application from /dev/tunX +device. + +2. What is the TAP ? +The TAP is a Virtual Ethernet network device. +TAP driver was designed as low level kernel support for +Ethernet tunneling. It provides to userland application +two interfaces: + - /dev/tapX - character device; + - tapX - virtual Ethernet interface. + +Userland application can write Ethernet frame to /dev/tapX +and kernel will receive this frame from tapX interface. +In the same time every frame that kernel writes to tapX +interface can be read by userland application from /dev/tapX +device. + +3. What platforms are supported by TUN/TAP driver ? +Currently driver has been written for 3 Unices: + Linux kernels 2.2.x, 2.4.x + FreeBSD 3.x, 4.x, 5.x + Solaris 2.6, 7.0, 8.0 + +4. What is TUN/TAP driver used for? +As mentioned above, main purpose of TUN/TAP driver is tunneling. +It used by VTun (http://vtun.netpedia.net). + +5. How does Virtual network device actually work ? +Virtual network device can be viewed as a simple Point-to-Point or +Ethernet device, which instead of receiving packets from a physical +media, receives them from user space program and instead of sending +packets via physical media sends them to the user space program. + +Let's say that you configured IPX on the tap0, then whenever +kernel sends any IPX packet to tap0, it is passed to the application +(VTun for example). Application encrypts, compresses and sends it to +the other side over TCP or UDP. Application on other side decompress +and decrypts them and write packet to the TAP device, kernel handles +the packet like it came from real physical device. + +6. What is the difference between TUN driver and TAP driver? +TUN works with IP frames. TAP works with Ethernet frames. + +7. What is the difference between BPF and TUN/TAP driver? +BFP is a advanced packet filter. It can be attached to existing +network interface. It does not provide virtual network interface. +TUN/TAP driver does provide virtual network interface and it is possible +to attach BPF to this interface. + +8. Does TAP driver support kernel Ethernet bridging? +Yes. Linux and FreeBSD drivers support Ethernet bridging. + + diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt --- v2.4.0-test6/linux/Documentation/networking/vortex.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/networking/vortex.txt Mon Aug 21 08:57:35 2000 @@ -13,7 +13,7 @@ Andrew Morton Netdev mailing list - Linux kernel mailing list + Linux kernel mailing list Please note the 'Reporting and Diagnosing Problems' section at the end of this file. @@ -52,7 +52,6 @@ 3CCFE656 Cyclone CardBus 3CCFEM656 Cyclone CardBus 3c450 Cyclone/unknown - 3Com Boomerang (unknown version) Module parameters @@ -67,7 +66,7 @@ If you are using the PCMCIA tools (cardmgr) then the options may be placed in /etc/pcmcia/config.opts: -module "3c59x" opts "debug=3 extra_reset=1" +module "3c59x" opts "debug=3 rx_copybreak=300" The supported parameters are: @@ -104,8 +103,8 @@ When generating a value for the 'options' setting, the above media selection values may be OR'ed (or added to) the following: - 512 (0x200) Force full-duplex - 16 (0x10) Bus-master enable bit (Old Vortex cards only) + 512 (0x200) Force full duplex mode. + 16 (0x10) Bus-master enable bit (Old Vortex cards only) For example: @@ -119,6 +118,22 @@ Similar to bit 9 of 'options'. Forces the corresponding card into full-duplex mode. +flow_ctrl=N1,N2,N3... + + Use 802.3x MAC-layer flow control. The 3com cards only support the + PAUSE command, which means that they will stop sending packets for a + short period if they receive a PAUSE frame from the link partner. + + The driver only allows flow control on a link which is operating in + full duplex mode. + + This feature does not appear to work on the 3c905 - only 3c905B and + 3c905C have been tested. + + The 3com cards appear to only respond to PAUSE frames which are + sent to the reserved destination address of 01:80:c2:00:00:01. They + do not honour PAUSE frames which are sent to the station MAC address. + rx_copybreak=M The driver preallocates 32 full-sized (1536 byte) network buffers @@ -141,15 +156,6 @@ is exceeded the interrupt service routine gives up and generates a warning message "eth0: Too much work in interrupt". -extra_reset=N - - Where N is 0 or 1 (default 0). - - Some network cards (notably 3CCFE575CT Cardbus) do not initialise - correctly and need an extra transmitter reset. If you find that the - card comes up receiving but not transmitting, try giving the module - the 'extra_reset=1' option. - compaq_ioaddr=N compaq_irq=N compaq_device_id=N @@ -220,29 +226,102 @@ Reporting and diagnosing problems --------------------------------- -If the driver plays up, there are a number of things you can do analyse -the problem and to help others do this: +Maintainers find that accurate and complete problem reports are +invaluable in resolving driver problems. We are frequently not able to +reproduce problems and must rely on your patience and efforts to get to +the bottom of the problem. + +If you believe you have a driver problem here are some of the +steps you should take: + +- Is it really a driver problem? + + Eliminate some variables: try different cards, different + computers, different cables, different ports on the switch/hub, + different versions of the kernel or ofthe driver, etc. + +- OK, it's a driver problem. + + You need to generate a report. Typically this is an email to the + maintainer and/or linux-net@vger.kernel.org. The maintainer's + email address will be inthe driver source or in the MAINTAINERS file. + +- The contents of your report will vary a lot depending upon the + problem. If it's a kernel crash then you should refer to the + REPORTING-BUGS file. + + But for most problems it is useful to provide the following: + + o Kernel version, driver version + + o A copy of the banner message which the driver generates when + it is initialised. For example: + + eth0: 3Com PCI 3c905C Tornado at 0xa400, 00:50:da:6a:88:f0, IRQ 19 + 8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface. + MII transceiver found at address 24, status 782d. + Enabling bus-master transmits and whole-frame receives. + + o If it is a PCI device, the relevant output from 'lspci -vx', eg: + + 00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] (rev 74) + Subsystem: 3Com Corporation: Unknown device 9200 + Flags: bus master, medium devsel, latency 32, IRQ 19 + I/O ports at a400 [size=128] + Memory at db000000 (32-bit, non-prefetchable) [size=128] + Expansion ROM at [disabled] [size=128K] + Capabilities: [dc] Power Management version 2 + 00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00 + 10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00 + 20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10 + 30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a + + o A description of the environment: 10baseT? 100baseT? + full/half duplex? switched or hubbed? + + o Any additional module parameters which you may be providing to the driver. + + o Any kernel logs which are produced. The more the merrier. + If this is a large file and you are sending your report to a + mailing list, mention that you have the logfile, but don't send + it. If you're reporting direct to the maintainer then just send + it. + + To ensure that all kernel logs are available, add the + following line to /etc/syslog.conf: + + kern.* /var/log/messages + + Then restart syslogd with: + + /etc/rc.d/init.d/syslog restart -- Turn on debugging in the driver - Add 'debug=7' to /etc/modules.conf (/etc/conf.modules) - Change 'vortex_debug' to 7 in the source code. + (The above may vary, depending upon which Linux distribution you use). -- Send all kernel logs, starting with the first probe of the card. + o If your problem is reproducible then that's great. Try the + following: -- Run 'mii-diag -v' to show the state of the Media Independent - Interface. If the card sometimes works and sometimes doesn't, run - 'mii-diag -v' in both states. + 1) Increase the debug level. Usually this is done via: -- Please run 'vortex-diag -aaee' in both good and bad states. This - show the NIC's registers and EEPROM contents. + a) modprobe driver.o debug=7 + b) In /etc/conf.modules (or modules.conf): + options driver_name debug=7 -- Describe your setup: 10baseT, 100baseT, full/half duplex, etc. + 2) Recreate the problem with the higher debug level, + send all logs to the maintainer. -- Note any additional module insertion commands you're using. + 3) Download you card's diagnostic tool from Donald + Backer's website http://www.scyld.com/diag. Download + mii-diag.c as well. Build these. -- Try different media type settings (see above). + a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is + working correctly. Save the output. -- Try inserting the module with 'extra_reset=1' (or compile this into - the driver). + b) Run the above commands when the card is malfunctioning. Send + both sets of output. +Finally, please be patient and be prepared to do some work. You may end up working on +this problem for a week or more as the maintainer asks more questions, asks for more +tests, asks for patches to be applied, etc. At the end of it all, the problem may even +remain unresolved. diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/networking/x25.txt linux/Documentation/networking/x25.txt --- v2.4.0-test6/linux/Documentation/networking/x25.txt Tue Apr 28 14:22:04 1998 +++ linux/Documentation/networking/x25.txt Mon Aug 21 08:57:35 2000 @@ -29,10 +29,10 @@ format and behaviour of the protocol. If time permits this option will also be actively considered. -A linux-x25 mailing list has been created at vger.rutgers.edu to support the +A linux-x25 mailing list has been created at vger.kernel.org to support the development and use of Linux X.25. It is early days yet, but interested parties are welcome to subscribe to it. Just send a message to -Majordomo@vger.rutgers.edu with the following in the message body: +majordomo@vger.kernel.org with the following in the message body: subscribe linux-x25 end diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/nmi_watchdog.txt linux/Documentation/nmi_watchdog.txt --- v2.4.0-test6/linux/Documentation/nmi_watchdog.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/nmi_watchdog.txt Mon Aug 21 08:57:35 2000 @@ -29,5 +29,5 @@ [ feel free to send bug reports, suggestions and patches to Ingo Molnar or the Linux SMP mailing - list at ] + list at ] diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt --- v2.4.0-test6/linux/Documentation/oops-tracing.txt Thu Nov 11 20:11:31 1999 +++ linux/Documentation/oops-tracing.txt Mon Aug 21 08:57:35 2000 @@ -13,7 +13,7 @@ worth even more than the oops If you are totally stumped as to whom to send the report, send it to -linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as +linux-kernel@vger.kernel.org. Thanks for your help in making Linux as stable as humanly possible. Where is the_oops.txt? diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt --- v2.4.0-test6/linux/Documentation/scsi-generic.txt Sun Mar 19 18:35:30 2000 +++ linux/Documentation/scsi-generic.txt Mon Aug 21 08:57:35 2000 @@ -756,7 +756,7 @@ the SCSI "sr" driver. http://www.torque.net/sg My site with sg related information. -newsgroup:linux-scsi@vger.rutgers.edu +newsgroup:linux-scsi@vger.kernel.org Newsgroup for Linux related SCSI matters /usr/src/linux/MAINTAINERS This is a file in the Linux kernel source that diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/sound/Soundblaster linux/Documentation/sound/Soundblaster --- v2.4.0-test6/linux/Documentation/sound/Soundblaster Wed Apr 26 16:34:06 2000 +++ linux/Documentation/sound/Soundblaster Fri Aug 11 14:42:16 2000 @@ -9,8 +9,8 @@ io I/O address of the Sound Blaster chip (0x220,0x240,0x260,0x280) irq IRQ of the Sound Blaster chip (5,7,9,10) -dma 8-bit DMA channel for the Sound Blaster (0,1,3) -dma16 16-bit DMA channel for SB16 and equivalent cards (5,6,7) +dma 8-bit DMA channel for the Sound Blaster (0,1,3) +dma16 16-bit DMA channel for SB16 and equivalent cards (5,6,7) mpu_io I/O for MPU chip if present (0x300,0x330) sm_games=1 Set if you have a Logitech soundman games @@ -21,11 +21,13 @@ The following arguments are taken if ISAPnP support is compiled in isapnp=0 Set this to disable ISAPnP detection (use io=0xXXX etc. above) -multiple=1 Set to enable detection of multiple Soundblaster cards. +multiple=0 Set to disable detection of multiple Soundblaster cards. + Consider it a bug if this option is needed, and send in a + report. reverse=1 Reverses the order of the search in the PnP table. uart401=1 Set to enable detection of mpu devices on some clones. -isapnpjump Jumps to a specific slot in the driver's PnP table. Use the - source, Luke. +isapnpjump=n Jumps to slot n in the driver's PnP table. Use the source, + Luke. You may well want to load the opl3 driver for synth music on most SB and clone SB devices diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/sparc/sbus_drivers.txt linux/Documentation/sparc/sbus_drivers.txt --- v2.4.0-test6/linux/Documentation/sparc/sbus_drivers.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sparc/sbus_drivers.txt Fri Aug 18 10:26:25 2000 @@ -0,0 +1,272 @@ + + Writing SBUS Drivers + + David S. Miller (davem@redhat.com) + + The SBUS driver interfaces of the Linux kernel have been +revamped completely for 2.4.x for several reasons. Foremost were +performance and complexity concerns. This document details these +new interfaces and how they are used to write an SBUS device driver. + + SBUS drivers need to include to get access +to functions and structures described here. + + Probing and Detection + + Each SBUS device inside the machine is described by a +structure called "struct sbus_dev". Likewise, each SBUS bus +found in the system is described by a "struct sbus_bus". For +each SBUS bus, the devices underneath are hung in a tree-like +fashion off of the bus structure. + + The SBUS device structure contains enough information +for you to implement your device probing algorithm and obtain +the bits necessary to run your device. The most commonly +used members of this structure, and their typical usage, +will be detailed below. + + Here is how probing is performed by an SBUS driver +under Linux: + + static void init_one_mydevice(struct sbus_dev *sdev) + { + ... + } + + static int mydevice_match(struct sbus_dev *sdev) + { + if (some_criteria(sdev)) + return 1; + return 0; + } + + static void mydevice_probe(void) + { + struct sbus_bus *sbus; + struct sbus_dev *sdev; + + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if (mydevice_match(sdev)) + init_one_mydevice(sdev); + } + } + } + + All this does is walk through all SBUS devices in the +system, checks each to see if it is of the type which +your driver is written for, and if so it calls the init +routine to attach the device and prepare to drive it. + + "init_one_mydevice" might do things like allocate software +state structures, map in I/O registers, place the hardware +into an initialized state, etc. + + Mapping and Accessing I/O Registers + + Each SBUS device structure contains an array of descriptors +which describe each register set. We abuse struct resource for that. +They each correspond to the "reg" properties provided by the OBP firmware. + + Before you can access your device's registers you must map +them. And later if you wish to shutdown your driver (for module +unload or similar) you must unmap them. You must treat them as +a resource, which you allocate (map) before using and free up +(unmap) when you are done with it. + + The mapping information is stored in an opaque value +typed as an "unsigned long". This is the type of the return value +of the mapping interface, and the arguments to the unmapping +interface. Let's say you want to map the first set of registers. +Perhaps part of your driver software state structure looks like: + + struct mydevice { + unsigned long control_regs; + ... + struct sbus_dev *sdev; + ... + }; + + At initialization time you then use the sbus_ioremap +interface to map in your registers, like so: + + static void init_one_mydevice(struct sbus_dev *sdev) + { + struct mydevice *mp; + ... + + mp->control_regs = sbus_ioremap(&sdev->resource[0], 0, + CONTROL_REGS_SIZE, "mydevice regs"); + if (!mp->control_regs) { + /* Failure, cleanup and return. */ + } + } + + Second argument to sbus_ioremap is an offset for +cranky devices with broken OBP PROM. The sbus_ioremap uses only +a start address and flags from the resource structure. +Therefore it is possible to use the same resource to map +several sets of registers or even to fabricate a resource +structure if driver gets physical address from some private place. +This practice is discouraged though. Use whatever OBP PROM +provided to you. + + And here is how you might unmap these registers later at +driver shutdown or module unload time, using the sbus_iounmap +interface: + + static void mydevice_unmap_regs(struct mydevice *mp) + { + sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE); + } + + Finally, to actually access your registers there are 6 +interface routines at your disposal. Accesses are byte (8 bit), +word (16 bit), or longword (32 bit) sized. Here they are: + + u8 sbus_readb(unsigned long reg) /* read byte */ + u16 sbus_readw(unsigned long reg) /* read word */ + u32 sbus_readl(unsigned long reg) /* read longword */ + void sbus_writeb(u8 value, unsigned long reg) /* write byte */ + void sbus_writew(u16 value, unsigned long reg) /* write word */ + void sbus_writel(u32 value, unsigned long reg) /* write longword */ + + So, let's say your device has a control register of some sort +at offset zero. The following might implement resetting your device: + + #define CONTROL 0x00UL + + #define CONTROL_RESET 0x00000001 /* Reset hardware */ + + static void mydevice_reset(struct mydevice *mp) + { + sbus_writel(CONTROL_RESET, mp->regs + CONTROL); + } + + Or perhaps there is a data port register at an offset of +16 bytes which allows you to read bytes from a fifo in the device: + + #define DATA 0x10UL + + static u8 mydevice_get_byte(struct mydevice *mp) + { + return sbus_readb(mp->regs + DATA); + } + + It's pretty straightforward, and clueful readers may have +noticed that these interfaces mimick the PCI interfaces of the +Linux kernel. This was not by accident. + + WARNING: + + DO NOT try to treat these opaque register mapping + values as a memory mapped pointer to some structure + which you can dereference. + + It may be memory mapped, it may not be. In fact it + could be a physical address, or it could be the time + of day xor'd with 0xdeadbeef. :-) + + Whatever it is, it's an implementation detail. The + interface was done this way to shield the driver + author from such complexities. + + Doing DVMA + + SBUS devices can perform DMA transactions in a way similar +to PCI but dissimilar to ISA, e.g. DMA masters supply address. +In contrast to PCI, however, that address (a bus address) is +translated by IOMMU before a memory access is performed and therefore +it is virtual. Sun calls this procedure DVMA. + + Linux supports two styles of using SBUS DVMA: "consistent memory" +and "streaming DVMA". CPU view of consistent memory chunk is, well, +consistent with a view of a device. Think of it as an uncached memory. +Typically this way of doing DVMA is not very fast and drivers use it +mostly for control blocks or queues. On some CPUs we cannot flush or +invalidate individual pages or cache lines and doing explicit flushing +over ever little byte in every control block would be wasteful. + +Streaming DVMA is a preferred way to transfer large amounts of data. +This process works in the following way: +1. a CPU stops accessing a certain part of memory, + flushes its caches covering that memory; +2. a device does DVMA accesses, then posts an interrupt; +3. CPU invalidates its caches and starts to access the memory. + +A single streaming DVMA operation can touch several discontiguous +regions of a virtual bus address space. This is called a scatter-gather +DVMA. + +[TBD: Why do not we neither Solaris attempt to map disjoint pages +into a single virtual chunk with the help of IOMMU, so that non SG +DVMA masters would do SG? It'd be very helpful for RAID.] + + In order to perform a consistent DVMA a driver does something +like the following: + + char *mem; /* Address in the CPU space */ + u32 busa; /* Address in the SBus space */ + + mem = (char *) sbus_alloc_consistant(sdev, MYMEMSIZE, &busa); + + Then mem is used when CPU accesses this memory and u32 +is fed to the device so that it can do DVMA. This is typically +done with an sbus_writel() into some device register. + + Do not forget to free the DVMA resources once you are done: + + sbus_free_consistant(sdev, MYMEMSIZE, mem, busa); + + Streaming DVMA is more interesting. First you allocate some +memory suitable for it or pin down some user pages. Then it all works +like this: + + char *mem = argumen1; + unsigned int size = argument2; + u32 busa; /* Address in the SBus space */ + + *mem = 1; /* CPU can access */ + busa = sbus_map_single(sdev, mem, size); + if (busa == 0) ....... + + /* Tell the device to use busa here */ + /* CPU cannot access the memory without sbus_dma_sync_single() */ + + sbus_unmap_single(sdev, busa, size); + if (*mem == 0) .... /* CPU can access again */ + + It is possible to retain mappings and ask the device to +access data again and again without calling sbus_unmap_single. +However, CPU caches must be invalidated with sbus_dma_sync_single +before such access. + +[TBD but what about writeback caches here... do we have any?] + + There is an equivalent set of functions doing the same thing +only with several memory segments at once for devices capable of +scatter-gather transfers. Use the Source, Luke. + + Examples + + drivers/net/sunhme.c + This is a complicated driver which illustrates many concepts +discussed above and plus it handles both PCI and SBUS boards. + + drivers/scsi/esp.c + Check it out for scatter-gather DVMA. + + drivers/sbus/char/bpp.c + A non-DVMA device. + + drivers/net/sunlance.c + Lance driver abuses consistent mappings for data transfer. +It is a nifty trick which we do not particularly recommend... +Just check it out and know that it's legal. + + Bad examples, do NOT use + + drivers/video/cgsix.c + This one uses result of sbus_ioremap as if it is an address. +This does NOT work on sparc64 and therefore is broken. We will +convert it at a later date. diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/usb/proc_usb_info.txt linux/Documentation/usb/proc_usb_info.txt --- v2.4.0-test6/linux/Documentation/usb/proc_usb_info.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/usb/proc_usb_info.txt Tue Aug 22 09:06:31 2000 @@ -1,6 +1,6 @@ /proc/bus/usb filesystem output =============================== -(version 2000.03.24) +(version 2000.08.15) The /proc filesystem for USB devices generates @@ -9,6 +9,23 @@ /proc/bus/usb/drivers lists the registered drivers, one per line, with each driver's USB minor dev node number range if applicable. + +**NOTE**: If /proc/bus/usb appears empty, you need + to mount the filesystem, issue the command (as root): + + mount -t usbdevfs none /proc/bus/usb + + An alternative and more permanent method would be to add + + none /proc/bus/usb usbdevfs defaults 0 0 + + to /etc/fstab. This will mount usbdevfs at each reboot. + You can then issue `cat /proc/bus/usb/devices` to extract + USB device information. + +For more information on mounting the usbdevfs file system, see the +"USB Device Filesystem" section of the USB Guide. The latest copy +of the USB Guide can be found at http://www.linux-usb.org/ In /proc/bus/usb/devices, each device's output has multiple lines of ASCII output. diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt --- v2.4.0-test6/linux/Documentation/usb/usb-serial.txt Wed Aug 9 19:19:49 2000 +++ linux/Documentation/usb/usb-serial.txt Sun Aug 13 19:23:19 2000 @@ -135,16 +135,16 @@ Digi AccelePort Driver - This driver supports the Digi AccelePort USB 4 device, a 4 port - USB serial converter. The driver does NOT yet support the Digi - AccelePort USB 2 or 8. + This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port + (plus a parallel port) and 4 port USB serial converters. The driver + does NOT yet support the Digi AccelePort USB 8. - The driver supports open, close, read, write, termios settings (baud - rate, word size, parity, stop bits, hardware/software flow control, - CREAD), DTR/RTS, and TIOCMGET/SET/BIS/BIC ioctls. It has not been - thoroughly tested, but it seems to be working reasonable well. There - is more work to do, including flow control, ioctls, and support for - the Digi AccelePort USB 2 and 8. + The driver is generally working, though we still have a few more ioctls + to implement and final testing and debugging to do. The paralled port + on the USB 2 is supported as a serial to parallel converter; in other + words, it appears as another USB serial port on Linux, even though + physically it is really a parallel port. The Digi Acceleport USB 8 + is not yet supported. Please contact Peter Berger (pberger@brimson.com) or Al Borchers (alborchers@steinerpoint.com) for questions or problems with this diff -u --recursive --new-file v2.4.0-test6/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt --- v2.4.0-test6/linux/Documentation/watchdog.txt Fri Jun 23 21:55:07 2000 +++ linux/Documentation/watchdog.txt Fri Aug 11 15:57:57 2000 @@ -14,7 +14,7 @@ Berkshire Products PC Watchdog Revision A & C (by Ken Hollis) -All five interfaces provide /dev/watchdog, which when open must be written +All six interfaces provide /dev/watchdog, which when open must be written to within a timeout or the machine will reboot. Each write delays the reboot time another timeout. In the case of the software watchdog the ability to reboot will depend on the state of the machines and interrupts. The hardware @@ -35,17 +35,27 @@ The wdt card cannot be safely probed for. Instead you need to pass wdt=ioaddr,irq as a boot parameter - eg "wdt=0x240,11". +The i810 TCO watchdog modules can be configured with the "i810_margin" +commandline argument which specifies the counter initial value. The counter +is decremented every 0.6 seconds and default to 50 (30 seconds). Values can +range between 3 and 63. + +The i810 TCO watchdog driver also implements the WDIOC_GETSTATUS and +WDIOC_GETBOOTSTATUS ioctl()s. WDIOC_GETSTATUS returns the actual counter value +and WDIOC_GETBOOTSTATUS returns the value of TCO2 Status Register (see Intel's +documentation for the 82801AA and 82801AB datasheet). + Features -------- - WDT501P WDT500P Software Berkshire -Reboot Timer X X X X -External Reboot X X o o -I/O Port Monitor o o o X -Temperature X o o X -Fan Speed X o o o -Power Under X o o o -Power Over X o o o -Overheat X o o o + WDT501P WDT500P Software Berkshire i810 TCO +Reboot Timer X X X X X +External Reboot X X o o o +I/O Port Monitor o o o X o +Temperature X o o X o +Fan Speed X o o o o +Power Under X o o o o +Power Over X o o o o +Overheat X o o o o The external event interfaces on the WDT boards are not currently supported. Minor numbers are however allocated for it. @@ -69,6 +79,7 @@ while(1) { write(fd,"\0",1); + fsync(fd); sleep(10); } } diff -u --recursive --new-file v2.4.0-test6/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.0-test6/linux/MAINTAINERS Wed Aug 9 19:19:49 2000 +++ linux/MAINTAINERS Tue Aug 22 15:21:54 2000 @@ -72,25 +72,32 @@ 3C501 NETWORK DRIVER P: Alan Cox M: alan@the.3c501.cabal.tm -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained for 2.2 only 3C505 NETWORK DRIVER P: Philip Blundell M: Philip.Blundell@pobox.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained 6PACK NETWORK DRIVER FOR AX.25 P: Andreas Koensgen M: ajk@iehk.rwth-aachen.de -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org +S: Maintained + +8250/16?50 (AND CLONE UARTS) SERIAL DRIVER +P: Theodore Ts'o +M: tytso@mit.edu +L: linux-serial@vger.kernel.org +W: http://serial.sourceforge.net S: Maintained 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] P: Paul Gortmaker M: p_gortmaker@yahoo.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained ACPI @@ -112,7 +119,7 @@ P: Bob Frey M: linux@advansys.com W: http://www.advansys.com/linux.html -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Maintained AEDSP16 DRIVER @@ -123,13 +130,13 @@ AHA152X SCSI DRIVER P: Juergen E. Fischer M: Juergen Fischer -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Maintained APM DRIVER P: Stephen Rothwell M: apm@linuxcare.com.au -L: linux-laptop@vger.rutgers.edu +L: linux-laptop@vger.kernel.org W: http://linuxcare.com.au/apm/ S: Supported @@ -154,19 +161,19 @@ ARPD SUPPORT P: Jonathan Layes M: layes@loran.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained AX.25 NETWORK LAYER P: Matthias Welwarsky M: dg2fef@afthd.tu-darmstadt.de -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org S: Maintained BAYCOM/HDLCDRV/SOUNDMODEM DRIVERS FOR AX.25 P: Thomas Sailer M: sailer@ife.ee.ethz.ch -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org W: http://www.ife.ee.ethz.ch/~sailer/ham/ham.html S: Maintained @@ -179,7 +186,7 @@ BFS FILE SYSTEM P: Tigran A. Aivazian M: tigran@veritas.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.ocston.org/~tigran/patches/bfs S: Maintained @@ -193,7 +200,7 @@ BUSLOGIC SCSI DRIVER P: Leonard N. Zubkoff M: Leonard N. Zubkoff -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org W: http://www.dandelion.com/Linux/ S: Maintained @@ -276,7 +283,7 @@ M: jreuter@poboxes.com W: http://poboxes.com/jreuter/ W: http://qsl.net/dl1bke/ -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org S: Maintained DC390/AM53C974 SCSI driver @@ -295,13 +302,13 @@ DEVICE NUMBER REGISTRY P: H. Peter Anvin M: hpa@zytor.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained DEVICE FILESYSTEM P: Richard Gooch M: rgooch@atnf.csiro.au -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained DIGI INTL. EPCA DRIVER @@ -314,10 +321,17 @@ DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson M: rick@remotepoint.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org W: http://www.dgii.com/linux/ S: Maintained +DIGIBOARD PC/XE AND PC/XI DRIVER +P: Christoph Lameter +M: christoph@lameter.com +W: http://www.dgii.com/linux,http://lameter.com/digi +L: digilnux@dgii.com +S: Maintained + DISK GEOMETRY AND PARTITION HANDLING P: Andries Brouwer M: aeb@veritas.com @@ -329,7 +343,7 @@ DISKQUOTA: P: Marco van Wieringen M: mvw@planets.elm.net -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained DOUBLETALK DRIVER @@ -341,19 +355,19 @@ EATA-DMA SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net -L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu +L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org S: Maintained EATA ISA/EISA/PCI SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Maintained EATA-PIO SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net -L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu +L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org S: Maintained EEPRO100 NETWORK DRIVER @@ -371,7 +385,7 @@ ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell M: Philip.Blundell@pobox.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained ETHERNET BRIDGE @@ -389,13 +403,13 @@ EXT2 FILE SYSTEM P: Remy Card M: Remy.Card@linux.org -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained FILE LOCKING (flock() and fcntl()/lockf()) P: Matthew Wilcox M: willy@thepuffingroup.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained FPU EMULATOR @@ -407,46 +421,53 @@ FRAME RELAY DLCI/FRAD (Sangoma drivers too) P: Mike McLagan M: mike.mclagan@linux.org -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained FTAPE/QIC-117 P: Claus-Justus Heine M: claus@momo.math.rwth-aachen.de -L: linux-tape@vger.rutgers.edu +L: linux-tape@vger.kernel.org W: http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ S: Maintained FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit) P: Rik Faith M: faith@cs.unc.edu -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Odd fixes (e.g., new signatures) GDT SCSI DISK ARRAY CONTROLLER DRIVER P: Achim Leubner M: achim@vortex.de -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org W: http://www.icp-vortex.com/ S: Supported HAYES ESP SERIAL DRIVER P: Andrew J. Robinson M: arobinso@nyx.net -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.nyx.net/~arobinso S: Maintained HFS FILESYSTEM P: Adrian Sun M: asun@cobaltnet.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained +HGA FRAMEBUFFER DRIVER +P: Ferenc Bakonyi +M: fero@drama.obuda.kando.hu +L: linux-nvidia@lists.surfsouth.com +W: http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml +S: Maintained + HIGH-SPEED SCC DRIVER FOR AX.25 P: Klaus Kudielka M: klaus.kudielka@ieee.org -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org W: http://www.nt.tuwien.ac.at/~kkudielk/Linux/ S: Maintained @@ -486,7 +507,13 @@ i386 BOOT CODE P: Riley H. Williams M: rhw@memalpha.cx -L: Linux-Kernel@vger.rutgers.edu +L: Linux-Kernel@vger.kernel.org +S: Maintained + +i810 TCO TIMER WATCHDOG +P: Nils Faerber +M: nils@kernelconcepts.de +W: http://www.kernelconcepts.de/ S: Maintained IBM MCA SCSI SUBSYSTEM DRIVER @@ -506,7 +533,7 @@ M: andre@linux-ide.org M: ahedrick@atipa.com M: andre@suse.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.kernel.org/pub/linux/kernel/people/hedrick/ W: http://www.linux-ide.org/ S: Supported @@ -514,14 +541,14 @@ IDE/ATAPI CDROM DRIVER P: Jens Axboe M: axboe@image.dk -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.kernel.dk S: Maintained IDE/ATAPI TAPE/FLOPPY DRIVERS P: Gadi Oxman M: Gadi Oxman -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained IEEE 1394 SUBSYSTEM @@ -571,7 +598,7 @@ IPX/SPX NETWORK LAYER P: Jay Schulist M: jschlst@turbolinux.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained IRDA SUBSYSTEM @@ -643,7 +670,7 @@ LAPB module P: Henner Eisen M: eis@baty.hanse.de -L: linux-x25@vger.rutgers.edu +L: linux-x25@vger.kernel.org S: Maintained LINUX FOR POWERPC @@ -704,25 +731,25 @@ M: David Weinehall W: http://www.acc.umu.se/~tao/ W: http://www.acc.umu.se/~mcalinux/ -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained MODULE SUPPORT [GENERAL], KMOD P: Keith Owens M: kaos@ocs.com.au -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained MOUSE AND MISC DEVICES [GENERAL] P: Alessandro Rubini M: rubini@ipvvis.unipv.it -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained MTRR AND SIMILAR SUPPORT [i386] P: Richard Gooch M: rgooch@atnf.csiro.au -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html S: Maintained @@ -753,7 +780,7 @@ NETROM NETWORK LAYER P: Tomi Manninen M: Tomi.Manninen@hut.fi -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org S: Maintained NETWORK BLOCK DEVICE @@ -764,7 +791,7 @@ NETWORKING [GENERAL] P: Networking Team M: netdev@oss.sgi.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org W: http://www.uk.linux.org/NetNews.html (2.0 only) S: Maintained @@ -781,26 +808,26 @@ NFS CLIENT P: Trond Myklebust M: trond.myklebust@fys.uio.no -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained NI5010 NETWORK DRIVER P: Jan-Pascal van Best and Andreas Mohr M: Jan-Pascal van Best M: Andreas Mohr <100.30936@germany.net> -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility) P: Eberhard Moenkeberg M: emoenke@gwdg.de -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained NTFS FILESYSTEM P: Anton Altaparmakov M: aia21@cus.cam.ac.uk -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Odd Fixes NVIDIA (RIVA) FRAMEBUFFER DRIVER @@ -814,7 +841,7 @@ M: p2@ace.ulyssis.sutdent.kuleuven.ac.be P: Mike Phillips M: phillim@amtrak.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org L: linux-tr@emissary.aus-etc.com W: http://www.linuxtr.net S: Maintained @@ -822,7 +849,7 @@ OPL3-SA2, SA3, and SAx DRIVER P: Scott Murray M: scott@spiteful.org -L: linux-sound@vger.rutgers.edu +L: linux-sound@vger.kernel.org S: Maintained PARALLEL PORT SUPPORT @@ -853,27 +880,27 @@ PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES) P: Thomas Sailer M: sailer@ife.ee.ethz.ch -L: linux-sound@vger.rutgers.edu +L: linux-sound@vger.kernel.org W: http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html S: Maintained PCI SUBSYSTEM P: Martin Mares M: mj@suse.cz -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Supported PCMCIA SUBSYSTEM P: David Hinds M: dhinds@zen.stanford.edu -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://pcmcia.sourceforge.org S: Maintained PCNET32 NETWORK DRIVER P: Thomas Bogendörfer M: tsbogend@alpha.franken.de -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained PNP SUPPORT @@ -887,7 +914,7 @@ PPP PROTOCOL DRIVERS AND COMPRESSORS P: Paul Mackerras M: paulus@linuxcare.com -L: linux-ppp@vger.rutgers.edu +L: linux-ppp@vger.kernel.org S: Maintained PPP OVER ETHERNET @@ -904,7 +931,7 @@ QNX4 FILESYSTEM P: Anders Larsen M: al@alarsen.net -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.alarsen.net/linux/qnx4fs/ S: Maintained @@ -917,25 +944,25 @@ RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER P: Corey Thomas M: corey@world.std.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained REAL TIME CLOCK DRIVER P: Paul Gortmaker M: p_gortmaker@yahoo.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained ROSE NETWORK LAYER P: Jean-Paul Roubelat M: jpr@f6fbb.org -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org S: Maintained RISCOM8 DRIVER P: Dmitry Gorodchanin M: pgmdsg@ibi.com -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained RTLINUX REALTIME LINUX @@ -954,31 +981,31 @@ SBPCD CDROM DRIVER P: Eberhard Moenkeberg M: emoenke@gwdg.de -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Maintained SCSI CDROM DRIVER P: Jens Axboe M: axboe@image.dk -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org W: http://www.kernel.dk S: Maintained SCSI SG DRIVER P: Doug Gilbert M: dgilbert@interlog.com -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org W: http://www.torque.net/sg S: Maintained SCSI SUBSYSTEM -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Unmaintained SCSI TAPE DRIVER P: Kai Mdkisara M: Kai.Makisara@metla.fi -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Maintained SGI VISUAL WORKSTATION 320 AND 540 @@ -991,7 +1018,7 @@ SIS 900/7016 FAST ETHERNET DRIVER P: Ollie Lho M: ollie@sis.com.tw -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Supported SMB FILESYSTEM @@ -1004,7 +1031,7 @@ SMP: (except SPARC) P: Linus Torvalds M: torvalds@transmeta.com -L: linux-smp@vger.rutgers.edu +L: linux-smp@vger.kernel.org S: Maintained SOFTWARE RAID (Multiple Disks) SUPPORT @@ -1015,7 +1042,7 @@ SONIC NETWORK DRIVER P: Thomas Bogendoerfer M: tsbogend@alpha.franken.de -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Maintained SOUND @@ -1032,8 +1059,8 @@ M: jj@sunsite.ms.mff.cuni.cz P: Anton Blanchard M: anton@linuxcare.com -L: sparclinux@vger.rutgers.edu -L: ultralinux@vger.rutgers.edu +L: sparclinux@vger.kernel.org +L: ultralinux@vger.kernel.org W: http://ultra.linux.cz W: http://www.geog.ubc.ca/s_linux.html S: Maintained @@ -1042,13 +1069,13 @@ P: Roger Wolff M: R.E.Wolff@BitWizard.nl M: io8-linux@specialix.co.uk -L: linux-kernel@vger.rutgers.edu ? +L: linux-kernel@vger.kernel.org ? S: Supported SPX NETWORK LAYER P: Jay Schulist M: jschlst@turbolinux.com -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org S: Supported SNA NETWORK LAYER @@ -1093,21 +1120,21 @@ M: torben.mathiasen@compaq.com M: tmm@image.dk L: tlan@vuser.vu.union.edu -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org W: http://tlan.kernel.dk S: Maintained TOKEN-RING NETWORK DRIVER P: Paul Norton M: pnorton@ieee.org -L: linux-net@vger.rutgers.edu +L: linux-net@vger.kernel.org L: linux-tr@linuxtr.net S: Maintained TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE P: Ollie Lho M: ollie@sis.com.tw -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org S: Supported TMS380 TOKEN-RING NETWORK DRIVER @@ -1126,7 +1153,7 @@ U14-34F SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Maintained UDF FILESYSTEM @@ -1141,14 +1168,14 @@ UMSDOS FILESYSTEM P: Matija Nalis M: Matija Nalis -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://linux.voyager.hr/umsdos/ S: Maintained UNIFORM CDROM DRIVER P: Jens Axboe M: axboe@image.dk -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://www.kernel.dk S: Maintained @@ -1207,7 +1234,7 @@ USB PEGASUS DRIVER P: Petko Manolov -M: petkan@spct.net +M: petkan@dce.bg L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained @@ -1262,7 +1289,7 @@ VFAT FILESYSTEM: P: Gordon Chaffee M: chaffee@cs.berkeley.edu -L: linux-kernel@vger.rutgers.edu +L: linux-kernel@vger.kernel.org W: http://bmrc.berkeley.edu/people/chaffee S: Maintained @@ -1301,13 +1328,13 @@ WD7000 SCSI DRIVER P: Miroslav Zagorac M: zaga@fly.cc.fer.hr -L: linux-scsi@vger.rutgers.edu +L: linux-scsi@vger.kernel.org S: Maintained X.25 NETWORK LAYER P: Henner Eisen M: eis@baty.hanse.de -L: linux-x25@vger.rutgers.edu +L: linux-x25@vger.kernel.org S: Maintained Z85230 SYNCHRONOUS DRIVER @@ -1321,7 +1348,7 @@ M: jreuter@poboxes.com W: http://poboxes.com/jreuter/ W: http://qsl.net/dl1bke/ -L: linux-hams@vger.rutgers.edu +L: linux-hams@vger.kernel.org S: Maintained ZR36120 VIDEO FOR LINUX DRIVER diff -u --recursive --new-file v2.4.0-test6/linux/Makefile linux/Makefile --- v2.4.0-test6/linux/Makefile Wed Aug 9 19:19:49 2000 +++ linux/Makefile Tue Aug 22 11:41:14 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test6 +EXTRAVERSION = -test7 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -123,6 +123,7 @@ drivers/char/char.o \ drivers/misc/misc.o \ drivers/net/net.o \ + drivers/media/media.o \ drivers/parport/parport.a LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib @@ -136,10 +137,10 @@ DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a DRIVERS-$(CONFIG_ISDN) += drivers/isdn/isdn.a -DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.a +DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.a DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.a -DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.a +DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o @@ -169,8 +170,9 @@ DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o +DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o -DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda_drivers.a +DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.a DRIVERS-$(CONFIG_ACPI_INTERPRETER) += drivers/acpi/acpi.o @@ -428,6 +430,9 @@ scripts/mkdep init/*.c > .depend scripts/mkdep `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" +ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile +endif ifdef CONFIG_MODVERSIONS MODVERFILE := $(TOPDIR)/include/linux/modversions.h @@ -436,7 +441,7 @@ endif export MODVERFILE -depend dep: dep-files $(MODVERFILE) +depend dep: dep-files # make checkconfig: Prune 'scripts' directory to avoid "false positives". checkconfig: diff -u --recursive --new-file v2.4.0-test6/linux/README linux/README --- v2.4.0-test6/linux/README Thu Jul 27 17:37:59 2000 +++ linux/README Mon Aug 21 08:57:35 2000 @@ -14,7 +14,7 @@ contained in 2.4.xx when the code base has stabilized again. If you decide to use 2.3, it is recommended that you join the kernel mailing -list. To do this, e-mail majordomo@vger.rutgers.edu, and put in the body +list. To do this, e-mail majordomo@vger.kernel.org, and put in the body of the message "subscribe linux-kernel" or "subscribe linux-kernel-digest" for a daily digest of the mailing list (it is a high-traffic list.) diff -u --recursive --new-file v2.4.0-test6/linux/REPORTING-BUGS linux/REPORTING-BUGS --- v2.4.0-test6/linux/REPORTING-BUGS Wed Apr 26 16:34:06 2000 +++ linux/REPORTING-BUGS Mon Aug 21 08:57:35 2000 @@ -17,7 +17,7 @@ The list of maintainers is in the MAINTAINERS file in this directory. If you are totally stumped as to whom to send the report, send it to -linux-kernel@vger.rutgers.edu. (For more information on the linux-kernel +linux-kernel@vger.kernel.org. (For more information on the linux-kernel mailing list see http://www.tux.org/lkml/). This is a suggested format for a bug report sent to the Linux kernel mailing diff -u --recursive --new-file v2.4.0-test6/linux/Rules.make linux/Rules.make --- v2.4.0-test6/linux/Rules.make Wed Aug 9 19:19:49 2000 +++ linux/Rules.make Sun Aug 13 09:55:51 2000 @@ -10,7 +10,7 @@ # # Special variables which should not be exported # -unexport EXTRA_ASFLAGS +unexport EXTRA_AFLAGS unexport EXTRA_CFLAGS unexport EXTRA_LDFLAGS unexport EXTRA_ARFLAGS @@ -57,7 +57,21 @@ ) > $(dir $@)/.$(notdir $@).flags %.o: %.s - $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $< + $(AS) $(AFLAGS) $(EXTRA_CFLAGS) -o $@ $< + +# Old makefiles define their own rules for compiling .S files, +# but these standard rules are available for any Makefile that +# wants to use them. Our plan is to incrementally convert all +# the Makefiles to these standard rules. -- rmk, mec +ifdef USE_STANDARD_AS_RULE + +%.s: %.S + $(CPP) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) $< > $@ + +%.o: %.S + $(CC) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) -c -o $@ $< + +endif # # @@ -208,8 +222,16 @@ $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h -$(TOPDIR)/include/linux/modversions.h: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)) - @echo updating $(TOPDIR)/include/linux/modversions.h +# updates .ver files but not modversions.h +fastdep: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)) + +# updates .ver files and modversions.h like before (is this needed?) +dep: fastdep update-modverfile + +endif # SYMTAB_OBJS + +# update modversions.h, but only if it would change +update-modverfile: @(echo "#ifndef _LINUX_MODVERSIONS_H";\ echo "#define _LINUX_MODVERSIONS_H"; \ echo "#include "; \ @@ -218,11 +240,14 @@ if [ -f $$f ]; then echo "#include "; fi; \ done; \ echo "#endif"; \ - ) > $@ - -dep fastdep: $(TOPDIR)/include/linux/modversions.h - -endif # SYMTAB_OBJS + ) > $(TOPDIR)/include/linux/modversions.h.tmp + @if [ -r $(TOPDIR)/include/linux/modversions.h ] && cmp -s $(TOPDIR)/include/linux/modversions.h $(TOPDIR)/include/linux/modversions.h.tmp; then \ + echo $(TOPDIR)/include/linux/modversions.h was not updated; \ + rm -f $(TOPDIR)/include/linux/modversions.h.tmp; \ + else \ + echo $(TOPDIR)/include/linux/modversions.h was updated; \ + mv -f $(TOPDIR)/include/linux/modversions.h.tmp $(TOPDIR)/include/linux/modversions.h; \ + fi $(M_OBJS): $(TOPDIR)/include/linux/modversions.h ifdef MAKING_MODULES diff -u --recursive --new-file v2.4.0-test6/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.0-test6/linux/arch/alpha/config.in Thu Jul 27 17:37:59 2000 +++ linux/arch/alpha/config.in Tue Aug 22 11:41:14 2000 @@ -302,9 +302,10 @@ source drivers/char/Config.in - #source drivers/misc/Config.in +source drivers/media/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then @@ -334,6 +335,7 @@ endmenu source drivers/usb/Config.in +source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.0-test6/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.0-test6/linux/arch/alpha/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/alpha/kernel/entry.S Fri Aug 11 14:29:04 2000 @@ -1160,3 +1160,4 @@ .quad sys_pivot_root .quad sys_mincore /* 375 */ .quad sys_pciconfig_iobase + .quad sys_getdents64 diff -u --recursive --new-file v2.4.0-test6/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.4.0-test6/linux/arch/alpha/kernel/osf_sys.c Thu Jul 27 17:37:59 2000 +++ linux/arch/alpha/kernel/osf_sys.c Fri Aug 11 14:29:04 2000 @@ -104,7 +104,8 @@ int error; }; -static int osf_filldir(void *__buf, const char *name, int namlen, off_t offset, ino_t ino) +static int osf_filldir(void *__buf, const char *name, int namlen, off_t offset, + ino_t ino, unsigned int d_type) { struct osf_dirent *dirent; struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; diff -u --recursive --new-file v2.4.0-test6/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.4.0-test6/linux/arch/alpha/kernel/time.c Fri Jul 14 12:12:04 2000 +++ linux/arch/alpha/kernel/time.c Mon Aug 21 07:52:34 2000 @@ -1,7 +1,7 @@ /* * linux/arch/alpha/kernel/time.c * - * Copyright (C) 1991, 1992, 1995, 1999 Linus Torvalds + * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds * * This file contains the PC-specific time handling details: * reading the RTC at bootup, etc.. @@ -21,6 +21,9 @@ * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) * fixed algorithm in do_gettimeofday() for calculating the precise time * from processor cycle counter (now taking lost_ticks into account) + * 2000-08-13 Jan-Benedict Glaw + * Fixed time_init to be aware of epoches != 1900. This prevents + * booting up in 2048 for me;) Code is stolen from rtc.c. */ #include #include @@ -200,7 +203,7 @@ void time_init(void) { - unsigned int year, mon, day, hour, min, sec, cc1, cc2; + unsigned int year, mon, day, hour, min, sec, cc1, cc2, epoch; unsigned long cycle_freq, one_percent; long diff; @@ -263,16 +266,24 @@ BCD_TO_BIN(mon); BCD_TO_BIN(year); } -#ifdef ALPHA_PRE_V1_2_SRM_CONSOLE - /* - * The meaning of life, the universe, and everything. Plus - * this makes the year come out right on SRM consoles earlier - * than v1.2. - */ - year -= 42; -#endif - if ((year += 1900) < 1970) + + /* PC-like is standard; used for year <= 20 || year >= 100 */ + epoch = 1900; + if (year > 20 && year < 48) + /* ARC console, used on some not so old boards */ + epoch = 1980; + else if (year >= 48 && year < 70) + /* Digital UNIX, used on older boards (eg. AXPpxi33) */ + epoch = 1952; + else if (year >= 70 && year < 100) + /* Digital DECstations, very old... */ + epoch = 1928; + + printk(KERN_INFO "Using epoch = %d\n", epoch); + + if ((year += epoch) < 1970) year += 100; + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_usec = 0; diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.0-test6/linux/arch/arm/Makefile Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/Makefile Sun Aug 13 09:54:15 2000 @@ -48,7 +48,7 @@ # ifeq ($(NEW_GCC),y) CFLAGS += -mshort-load-bytes -CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os +CFLAGS_PROC_CPU_26 := -mcpu=arm3 -mapcs-26 -Os CFLAGS_PROC_CPU_32v3 := -march=armv3 CFLAGS_PROC_CPU_32v4 := -march=armv4 CFLAGS_ARM6 := -mtune=arm6 @@ -166,10 +166,9 @@ HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ arch/arm/kernel/init_task.o SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \ - arch/arm/special arch/arm/nwfpe + arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC) -DRIVERS += arch/arm/special/special.a ifeq ($(CONFIG_NWFPE),y) LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) @@ -193,7 +192,14 @@ # The following is a hack to get 'constants.h' up # to date before starting compilation -$(patsubst %, _dir_%, $(SUBDIRS)) : constants +$(patsubst %, _dir_%, $(SUBDIRS)) init/main.o init/version.o : \ + constants \ + include/asm-arm/mach-types.h + +include/asm-arm/mach-types.h: \ + arch/arm/tools/mach-types \ + arch/arm/tools/gen-mach-types + @awk -f arch/arm/tools/gen-mach-types arch/arm/tools/mach-types > $@ constants: $(TOPDIR)/include/asm-arm/proc-fns.h dummy @$(MAKE) -C arch/arm/lib constants.h @@ -218,16 +224,16 @@ arch/arm/lib: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/arm/lib -zImage zinstall Image install: vmlinux +bzImage zImage zinstall Image bootpImage install: vmlinux @$(MAKEBOOT) $@ archmrproper: - @$(MAKE) -C arch/$(ARCH)/special mrproper $(RM) include/asm-arm/arch include/asm-arm/proc archclean: @$(MAKEBOOT) clean $(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds + $(RM) include/asm-arm/mach-types.h archdep: symlinks @$(MAKEBOOT) dep @@ -241,46 +247,25 @@ # # Configuration targets. Use these to select a # configuration for your architecture -# -a5k_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/a5k arch/arm/defconfig - -ebsa110_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/ebsa110 arch/arm/defconfig - -footbridge_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/footbridge arch/arm/defconfig - -rpc_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/rpc arch/arm/defconfig - -brutus_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/brutus arch/arm/defconfig - -victor_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/victor arch/arm/defconfig - -empeg_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/empeg arch/arm/defconfig - -thinclient_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/thinclient arch/arm/defconfig - -assabet_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/assabet arch/arm/defconfig - -lart_config: - $(RM) arch/arm/defconfig - cp arch/arm/def-configs/lart arch/arm/defconfig +CFGS= a5k_config ebsa110_config \ + footbridge_config rpc_config \ + brutus_config victor_config \ + empeg_config thinclient_config \ + assabet_config lart_config \ + cerf_config + +$(CFGS): + @( \ + CFG=$(@:_config=); \ + if [ -f arch/arm/def-configs/$$CFG ]; then \ + $(RM) arch/arm/defconfig; \ + cp arch/arm/def-configs/$$CFG arch/arm/defconfig; \ + echo "*** Default configuration for $$CFG installed"; \ + echo "*** Next, you may run 'make oldconfig'"; \ + else \ + echo "$$CFG does not exist"; \ + fi; \ + ) l7200_config: $(RM) arch/arm/defconfig diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.4.0-test6/linux/arch/arm/boot/Makefile Sun Apr 12 11:42:15 1998 +++ linux/arch/arm/boot/Makefile Sun Aug 13 09:54:15 2000 @@ -5,20 +5,105 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1995, 1996 Russell King +# Copyright (C) 1995-2000 Russell King # SYSTEM =$(TOPDIR)/vmlinux +ifeq ($(CONFIG_CPU_26),y) +ZTEXTADDR = 0x02080000 +PARAMS_PHYS = 0x0207c000 +INITRD_PHYS = 0x02180000 +INITRD_VIRT = 0x02180000 +endif + +ifeq ($(CONFIG_ARCH_RPC),y) +ZTEXTADDR = 0x10008000 +PARAMS_PHYS = 0x10000100 +INITRD_PHYS = 0x18000000 +INITRD_VIRT = 0xc8000000 +endif + +ifeq ($(CONFIG_ARCH_CLPS7500),y) +ZTEXTADDR = 0x10008000 +endif + +ifeq ($(CONFIG_ARCH_EBSA110),y) +ZTEXTADDR = 0x00008000 +PARAMS_PHYS = 0x00000400 +INITRD_PHYS = 0x00800000 +INITRD_VIRT = 0xc0800000 +endif + +ifeq ($(CONFIG_FOOTBRIDGE),y) +ZTEXTADDR = 0x00008000 +PARAMS = 0x00000100 +INITRD_PHYS = 0x00800000 +INITRD_VIRT = 0xc0800000 +endif + +ifeq ($(CONFIG_ARCH_NEXUSPCI),y) +ZTEXTADDR = 0x40200000 +ZRELADDR = 0x40008000 +endif + +ifeq ($(CONFIG_ARCH_L7200),y) +# RAM based kernel +#ZTEXTADDR = 0xf0400000 +#ZRELADDR = 0xf0008000 + +# FLASH based kernel +ZTEXTADDR = 0x00010000 +ZRELADDR = 0xf0008000 +ZBSSADDR = 0xf03e0000 +endif + +ifeq ($(CONFIG_ARCH_SA1100),y) +ZTEXTADDR = 0xc0008000 +ZRELADDR = 0xc0008000 +ifeq ($(CONFIG_SA1100_VICTOR),y) + ZTEXTADDR = 0x00002000 + ZBSSADDR = 0xc0100000 +endif +ifeq ($(CONFIG_SA1100_THINCLIENT),y) + ZTEXTADDR = 0xC0200000 +endif +ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y) + ZTEXTADDR = 0xC0200000 +endif +endif + +# +# If you don't define ZRELADDR above, +# then it defaults to ZTEXTADDR +# +ifeq ($(ZRELADDR),) +ZRELADDR = $(ZTEXTADDR) +endif + +export SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS INITRD_VIRT PARAMS_PHYS + Image: $(CONFIGURE) $(SYSTEM) $(OBJCOPY) $(SYSTEM) $@ +bzImage: zImage + zImage: $(CONFIGURE) compressed/vmlinux $(OBJCOPY) compressed/vmlinux $@ +bootpImage: bootp/bootp + $(OBJCOPY) bootp/bootp $@ + compressed/vmlinux: $(TOPDIR)/vmlinux dep @$(MAKE) -C compressed vmlinux +bootp/bootp: zImage initrd + @$(MAKE) -C bootp bootp + +initrd: + @test "$(INITRD_VIRT)" != "" || (echo This architecture does not support INITRD; exit -1) + @test "$(INITRD)" != "" || (echo You must specify INITRD; exit -1) + install: $(CONFIGURE) Image sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" @@ -26,7 +111,8 @@ sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" clean: - rm -f Image zImage + $(RM) Image zImage bootpImage @$(MAKE) -C compressed clean + @$(MAKE) -C bootp clean dep: diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/bootp/Makefile linux/arch/arm/boot/bootp/Makefile --- v2.4.0-test6/linux/arch/arm/boot/bootp/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/bootp/Makefile Sun Aug 13 09:54:15 2000 @@ -0,0 +1,26 @@ +# +# linux/arch/arm/boot/bootp/Makefile +# + +ZSYSTEM =$(TOPDIR)/arch/arm/boot/zImage +INITRD =$(ZSYSTEM) +ZLDFLAGS =-p -X -T bootp.lds \ + --defsym initrd_addr=$(INITRD_PHYS) \ + --defsym initrd_virt=$(INITRD_VIRT) \ + --defsym params=$(PARAMS_PHYS) + +all: bootp + +# Note that bootp.lds picks up kernel.o and initrd.o +bootp: init.o kernel.o initrd.o bootp.lds + $(LD) $(ZLDFLAGS) -o $@ init.o + +kernel.o: $(ZSYSTEM) + $(LD) -r -s -o $@ -b binary $(ZSYSTEM) + +initrd.o: $(INITRD) + $(LD) -r -s -o $@ -b binary $(INITRD) + +.PHONY: $(INITRD) $(ZSYSTEM) + +clean:; $(RM) bootp bootp.lds diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/bootp/init.S linux/arch/arm/boot/bootp/init.S --- v2.4.0-test6/linux/arch/arm/boot/bootp/init.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/bootp/init.S Sun Aug 13 09:54:15 2000 @@ -0,0 +1,57 @@ +/* + * Header file for splitting kernel + initrd. Note that we pass + * r0 through to r3 straight through. + */ + .section .start,#alloc,#execinstr + .type _entry, #function +_entry: +kernel_addr: adr r10, initdata + ldmia r10, {r11, r12} + sub r11, r10, r11 @ work out exec offset + add r12, r12, r11 @ correct "splitify" + mov pc, r12 @ jump to splitify + .size _entry,. - _entry + + .type initdata, #object +initdata: .word initdata @ compiled address of this + .word splitify + .size initdata,. - initdata + + .text +splitify: adr r13, data + ldmia r13!, {r4-r6} @ move the kernel + add r4, r4, r11 @ correction + mov r12, r5 + bl move + + ldmia r13!, {r4-r6} @ then the initrd + add r4, r4, r11 @ correction + bl move + + ldmib r13, {r5,r6,r7} @ get size and addr of initrd + add r7, r7, #16*4 @ offset of initrd_start in param_struct + stmia r7, {r5,r6} @ save in param_struct + mov pc, r12 @ call kernel + +move: ldmia r4!, {r7 - r10} @ move 32-bytes at a time + stmia r5!, {r7 - r10} + ldmia r4!, {r7 - r10} + stmia r5!, {r7 - r10} + subs r6, r6, #8 * 4 + bcs move + mov pc, lr + +data: .word kernel_start + .word kernel_addr + .word kernel_len + + .word initrd_start + .word initrd_addr + .word initrd_len + + .word initrd_virt + .word initrd_len + .word params + + .type kernel_start,#object + .type initrd_start,#object diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.4.0-test6/linux/arch/arm/boot/compressed/Makefile Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/boot/compressed/Makefile Sun Aug 13 09:54:15 2000 @@ -2,10 +2,13 @@ # linux/arch/arm/boot/compressed/Makefile # # create a compressed vmlinuz image from the original vmlinux +# +# Note! SYSTEM, ZTEXTADDR, ZBSSADDR and ZRELADDR are now exported +# from arch/arm/boot/Makefile +# HEAD = head.o OBJS = misc.o -SYSTEM = $(TOPDIR)/vmlinux CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c ZLDFLAGS = -p -X -T vmlinux.lds @@ -17,60 +20,25 @@ OBJS += ll_char_wr.o font.o endif -ifeq ($(CONFIG_CPU_26),y) -ZTEXTADDR = 0x02080000 -endif - -ifeq ($(CONFIG_ARCH_RPC),y) -ZTEXTADDR = 0x10008000 -endif - -ifeq ($(CONFIG_ARCH_CLPS7500),y) -ZTEXTADDR = 0x10008000 -endif - -ifeq ($(CONFIG_ARCH_EBSA110),y) -ZTEXTADDR = 0x00008000 -endif - -ifeq ($(CONFIG_FOOTBRIDGE),y) -ZTEXTADDR = 0x00008000 -endif - ifeq ($(CONFIG_ARCH_NETWINDER),y) OBJS += head-netwinder.o endif ifeq ($(CONFIG_ARCH_NEXUSPCI),y) HEAD = head-nexuspci.o -ZTEXTADDR = 0x40200000 -ZRELADDR = 0x40008000 +endif + +ifeq ($(CONFIG_ARCH_L7200),y) +OBJS += head-l7200.o endif ifeq ($(CONFIG_ARCH_SA1100),y) OBJS += head-sa1100.o setup-sa1100.o -ZTEXTADDR = 0xc0008000 -ZRELADDR = 0xc0008000 -ifeq ($(CONFIG_SA1100_VICTOR),y) - ZTEXTADDR = 0x00002000 - ZBSSADDR = 0xc0100000 -endif -ifeq ($(CONFIG_SA1100_THINCLIENT),y) - ZTEXTADDR = 0xC0200000 -endif -ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y) - ZTEXTADDR = 0xC0200000 +ifeq ($(CONFIG_SA1100_NANOENGINE),y) + OBJS += hw-bse.o endif endif -# -# If you don't define ZRELADDR above, -# then it defaults to ZTEXTADDR -# -ifeq ($(ZRELADDR),) -ZRELADDR = $(ZTEXTADDR) -endif - SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/; ifneq ($(ZBSSADDR),) @@ -104,3 +72,6 @@ .PHONY: vmlinux.lds clean misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c + +%.o: %.S + $(CC) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) -c -o $@ $< diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/head-l7200.S linux/arch/arm/boot/compressed/head-l7200.S --- v2.4.0-test6/linux/arch/arm/boot/compressed/head-l7200.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/head-l7200.S Sun Aug 13 09:54:15 2000 @@ -0,0 +1,30 @@ +/* + * linux/arch/arm/boot/compressed/head-l7200.S + * + * Copyright (C) 2000 Steve Hill + * + * Some code borrowed from Nicola Pitre's 'head-sa1100.S' file. This + * is merged with head.S by the linker. + */ + +#include + +#ifndef CONFIG_ARCH_L7200 +#error What am I doing here... +#endif + + .section ".start", #alloc, #execinstr + +__L7200_start: + + mov r0, #0x00100000 @ FLASH address of initrd + mov r2, #0xf1000000 @ RAM address of initrd + add r1, r2, #0x00700000 @ Size of initrd +1: + ldmia r0!, {r3, r4, r5, r6} + stmia r2!, {r3, r4, r5, r6} + cmp r2, r1 + ble 1b + + mov r8, #0 @ Zero it out + mov r7, #19 @ Set architecture ID diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/head-netwinder.S linux/arch/arm/boot/compressed/head-netwinder.S --- v2.4.0-test6/linux/arch/arm/boot/compressed/head-netwinder.S Tue Nov 23 22:42:20 1999 +++ linux/arch/arm/boot/compressed/head-netwinder.S Sun Aug 13 09:54:15 2000 @@ -1,15 +1,24 @@ +#define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) + .section ".start", #alloc, #execinstr + /* + * check to see if we are running from the correct address. + * If not, we move ourselves in a two stage process. Firstly, + * we copy the start of the kernel (which includes this code) + * to 0x8000, and then jump to this code to continue with the + * rest (since this code will get overwritten). + */ adr r2, 1f - ldmdb r2, {r7, r8} + ldmdb r2, {r9, r10} and r3, r2, #0xc000 - teq r3, #0x8000 - beq 2f + teq r3, #0x8000 @ correctly located? + beq 2f @ skip this code bic r3, r2, #0xc000 orr r3, r3, #0x8000 - mov r0, r3 - mov r4, #64 - sub r5, r8, r7 + mov r0, r3 @ new address if '1' + mov r4, #64 @ number of bytes to copy + sub r5, r10, r9 @ total number of bytes to copy b 1f .word _start @@ -17,15 +26,16 @@ 1: .rept 4 - ldmia r2!, {r6, r7, r8, r9} - stmia r3!, {r6, r7, r8, r9} + ldmia r2!, {r6, r9, r10, r11} + stmia r3!, {r6, r9, r10, r11} .endr subs r4, r4, #64 bcs 1b - movs r4, r5 - mov r5, #0 - mov r1, #5 @ only here to fix NeTTroms which dont set r1 - movne pc, r0 - - mov r0, #0 + movs r4, r5 @ remaining length + mov r5, #0 @ no more to copy + movne pc, r0 @ jump back to 1 (in the newly copied + @ code) + mov r7, #5 @ only here to fix NeTTroms which dont + mov r8, #2 << 24 @ scheduled for removal in 2.5.xx + orr r8, r8, #5 << 12 2: diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/head-sa1100.S linux/arch/arm/boot/compressed/head-sa1100.S --- v2.4.0-test6/linux/arch/arm/boot/compressed/head-sa1100.S Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/boot/compressed/head-sa1100.S Sun Aug 13 09:54:15 2000 @@ -9,6 +9,7 @@ #include #include +#include #ifndef CONFIG_ARCH_SA1100 #error What am I doing here... @@ -18,27 +19,10 @@ __SA1100_start: - @ Preserve r0/r1 i.e. kernel entry values - mov r8, r0 - mov r9, r1 - -#if defined( CONFIG_SA1100_ASSABET ) || \ - defined( CONFIG_SA1100_BRUTUS ) || \ - defined( CONFIG_SA1100_THINCLIENT ) -@ Booting from Angel -- need to enter SVC mode -#define angel_SWIreason_EnterSVC 0x17 /* from arm.h, in angel source */ -#define angel_SWI_ARM (0x123456) - mov r0, #angel_SWIreason_EnterSVC - swi #angel_SWI_ARM - - @ turn off interrupts to prevent the angel from running - mrs r0, cpsr - orr r0, r0, #0xc0 - msr cpsr_c, r0 -#endif + @ Preserve r8/r7 i.e. kernel entry values #ifdef CONFIG_SA1100_VICTOR - teq r9, #26 @ MACH_TYPE_VICTOR + teq r7, #MACH_TYPE_VICTOR bne 10f @ Copy cmdline to 0xc0000000 @@ -74,10 +58,6 @@ * Pause for a short time so that we give enough time * for the host to start a terminal up. */ - mov r0, #0x02000000 + mov r0, #0x00200000 1: subs r0, r0, #1 bne 1b - - @ Restore initial r0/r1 - mov r0, r8 - mov r1, r9 diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.4.0-test6/linux/arch/arm/boot/compressed/head.S Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/boot/compressed/head.S Sun Aug 13 09:54:15 2000 @@ -3,9 +3,9 @@ * * Copyright (C) 1996-1999 Russell King */ +#include #include - /* * Debugging stuff */ @@ -84,18 +84,31 @@ b 1f .word 0x016f2818 @ Magic numbers to help the loader .word start -1: +1: mov r7, r1 @ save architecture ID + mov r8, r0 @ save r0 +#ifdef CONFIG_ANGELBOOT + /* + * Booting from Angel - need to enter SVC mode and disable + * FIQs/IRQs (numeric definitions from angel arm.h source) + */ + mov r0, #0x17 @ angel_SWIreason_EnterSVC + swi 0x123456 @ angel_SWI_ARM + mrs r0, cpsr @ turn off interrupts to + orr r0, r0, #0xc0 @ prevent angel from running + msr cpsr_c, r0 + + /* + * Note that some cache flushing and other stuff may + * be needed here - is there an Angel SWI call for this? + */ +#endif /* * some architecture specific code can be inserted - * by the linker here, but it should preserve r0, r1 - * and r8. + * by the linker here, but it should preserve r7 and r8. */ .text -1: teq r0, #0 - bne 1b - mov r7, r1 @ save architecture ID - mrc p15, 0, r6, c0, c0 @ get processor ID +1: mrc p15, 0, r6, c0, c0 @ get processor ID adr r2, LC0 ldmia r2, {r2, r3, r4, r5, sp} diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/hw-bse.c linux/arch/arm/boot/compressed/hw-bse.c --- v2.4.0-test6/linux/arch/arm/boot/compressed/hw-bse.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/hw-bse.c Sun Aug 13 09:54:15 2000 @@ -0,0 +1,74 @@ +/* + * Bright Star Engineering Inc. + * + * code for readng parameters from the + * parameter blocks of the boot block + * flash memory + * + */ + +static int strcmp(const char *s1, const char *s2) +{ + while (*s1 != '\0' && *s1 == *s2) + { + s1++; + s2++; + } + + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +} + +struct pblk_t { + char type; + unsigned short size; +}; + +static char *bse_getflashparam(char *name) { + unsigned int esize; + char *q,*r; + unsigned char *p,*e; + struct pblk_t *thepb = (struct pblk_t *) 0x00004000; + struct pblk_t *altpb = (struct pblk_t *) 0x00006000; + if (thepb->type&1) { + if (altpb->type&1) { + /* no valid param block */ + return (char*)0; + } else { + /* altpb is valid */ + struct pblk_t *tmp; + tmp = thepb; + thepb = altpb; + altpb = tmp; + } + } + p = (char*)thepb + sizeof(struct pblk_t); + e = p + thepb->size; + while (p < e) { + q = p; + esize = *p; + if (esize == 0xFF) break; + if (esize == 0) break; + if (esize > 127) { + esize = (esize&0x7F)<<8 | p[1]; + q++; + } + q++; + r=q; + if (*r && ((name == 0) || (!strcmp(name,r)))) { + while (*q++) ; + return q; + } + p+=esize; + } + return (char*)0; +} + +void bse_setup(void) { + /* extract the linux cmdline from flash */ + char *name=bse_getflashparam("linuxboot"); + char *x = (char *)0xc0000100; + if (name) { + while (*name) *x++=*name++; + } + *x=0; +} diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S --- v2.4.0-test6/linux/arch/arm/boot/compressed/setup-sa1100.S Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/boot/compressed/setup-sa1100.S Sun Aug 13 09:54:15 2000 @@ -9,8 +9,9 @@ * Runtime test for Neponset added. */ -#define __ASSEMBLY__ #include +#include +#include .text @@ -44,6 +45,12 @@ #define GPIO_2_9 0x3fc +/* + * void sa1100_setup( int arch_id ); + * + * This is called from decompress_kernel() with the arch_decomp_setup() macro. + */ + ENTRY(sa1100_setup) mov r3, r0 @ keep machine type in r3 @@ -51,7 +58,7 @@ @ (taken from "Intel StrongARM SA-1110 Microprocessor Development Board @ User's Guide," p.4-9) - teq r3, #25 @ MACH_TYPE_ASSABET + teq r3, #MACH_TYPE_ASSABET bne skip_SCR ldr r0, GPIO_BASE @@ -80,8 +87,8 @@ skip_SCR: @ Initialize UART (if bootloader has not done it yet)... - teq r3, #16 @ MACH_TYPE_BRUTUS - teqne r3, #25 @ MACH_TYPE_ASSABET + teq r3, #MACH_TYPE_BRUTUS + teqne r3, #MACH_TYPE_ASSABET bne skip_uart @ UART3 if Assabet is used with Neponset @@ -92,7 +99,7 @@ @ At least for Brutus, the UART1 is used through @ the alternate GPIO function... - teq r3, #16 @ MACH_TYPE_BRUTUS + teq r3, #MACH_TYPE_BRUTUS bne uart1 alt_GPIO_uart: ldr r0, GPIO_BASE @@ -126,5 +133,14 @@ mov r1, #0xff @ flush status reg str r1, [r0, #UTSR0] skip_uart: + + @ Extra specific setup calls + @ The machine type is passed in r0 + mov r0, r3 +#ifdef CONFIG_SA1100_NANOENGINE + teq r0, #32 @ MACH_TYPE_NANOENGINE + beq SYMBOL_NAME(bse_setup) +#endif + out: mov pc, lr diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.4.0-test6/linux/arch/arm/config.in Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/config.in Tue Aug 22 11:41:14 2000 @@ -29,6 +29,7 @@ choice 'ARM system type' \ "Archimedes/A5000 CONFIG_ARCH_ARCA5K \ + Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ Co-EBSA285 CONFIG_ARCH_CO285 \ EBSA-110 CONFIG_ARCH_EBSA110 \ FootBridge CONFIG_ARCH_FOOTBRIDGE \ @@ -62,6 +63,7 @@ bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET fi bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS + bool ' Include support for CerfBoard' CONFIG_SA1100_CERF bool ' Include support for Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY # bool ' Include support for Empeg' CONFIG_SA1100_EMPEG # bool ' Include support for Itsy' CONFIG_SA1100_ITSY @@ -69,9 +71,52 @@ # bool ' Include support for PLEB' CONFIG_SA1100_PLEB bool ' Include support for ThinClient' CONFIG_SA1100_THINCLIENT bool ' Include support for GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT + bool ' Include support for nanoEngine' CONFIG_SA1100_NANOENGINE bool ' Include support for Victor' CONFIG_SA1100_VICTOR # bool ' Include support for Tifon' CONFIG_SA1100_TIFON -# bool ' Include support for XP860' CONFIG_SA1100_XP860 + bool ' Include support for XP860' CONFIG_SA1100_XP860 + + bool ' Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT + + # Determine if SA1111 support is required + if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ + "$CONFIG_SA1100_XP860" = "y" ]; then + define_bool CONFIG_SA1111 y + fi +fi + +# Definitions to make life easier +if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ + "$CONFIG_ARCH_RPC" = "y" ]; then + define_bool CONFIG_ARCH_ACORN y +else + define_bool CONFIG_ARCH_ACORN n +fi + +# see Documentation/arm/ConfigVars for a description of these +if [ "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then + define_bool CONFIG_FOOTBRIDGE y +else + define_bool CONFIG_FOOTBRIDGE n +fi +if [ "$CONFIG_ARCH_CATS" = "y" -o \ + "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \ + "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_PERSONAL_SERVER" = "y" ]; then + define_bool CONFIG_FOOTBRIDGE_HOST y +else + define_bool CONFIG_FOOTBRIDGE_HOST n +fi +if [ "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then + define_bool CONFIG_FOOTBRIDGE_ADDIN y +else + define_bool CONFIG_FOOTBRIDGE_ADDIN n +fi +if [ "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \ + "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then + define_bool CONFIG_ARCH_EBSA285 y fi # Figure out whether this system uses 26-bit or 32-bit CPUs. @@ -113,38 +158,6 @@ fi # Select various configuration options depending on the machine type -if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ - "$CONFIG_ARCH_RPC" = "y" ]; then - define_bool CONFIG_ARCH_ACORN y -else - define_bool CONFIG_ARCH_ACORN n -fi - -if [ "$CONFIG_ARCH_CO285" = "y" -o \ - "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then - define_bool CONFIG_FOOTBRIDGE y -else - define_bool CONFIG_FOOTBRIDGE n -fi -if [ "$CONFIG_ARCH_CATS" = "y" -o \ - "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \ - "$CONFIG_ARCH_NETWINDER" = "y" -o \ - "$CONFIG_ARCH_PERSONAL_SERVER" = "y" ]; then - define_bool CONFIG_FOOTBRIDGE_HOST y -else - define_bool CONFIG_FOOTBRIDGE_HOST n -fi -if [ "$CONFIG_ARCH_CO285" = "y" -o \ - "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then - define_bool CONFIG_FOOTBRIDGE_ADDIN y -else - define_bool CONFIG_FOOTBRIDGE_ADDIN n -fi -if [ "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \ - "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then - define_bool CONFIG_ARCH_EBSA285 y -fi - if [ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_DISCONTIGMEM y else @@ -167,6 +180,15 @@ define_bool CONFIG_ISA n define_bool CONFIG_ISA_DMA n fi + +# Do we have a PC-type keyboard in this architecture? +if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then + define_bool CONFIG_PC_KEYB y + define_bool CONFIG_PC_KEYMAP y +fi +if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then + define_bool CONFIG_PC_KEYMAP y +fi endmenu mainmenu_option next_comment @@ -199,6 +221,7 @@ fi if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \ "$CONFIG_ARCH_CATS" = "y" ]; then string 'Default kernel command string' CONFIG_CMDLINE "" @@ -301,6 +324,8 @@ #source drivers/misc/Config.in +source drivers/media/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then @@ -329,6 +354,7 @@ fi source drivers/usb/Config.in +source drivers/input/Config.in mainmenu_option next_comment diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.4.0-test6/linux/arch/arm/kernel/Makefile Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/Makefile Sun Aug 13 09:54:15 2000 @@ -5,9 +5,14 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). +USE_STANDARD_AS_RULE := true + HEAD_OBJ = head-$(PROCESSOR).o ENTRY_OBJ = entry-$(PROCESSOR).o +AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional +AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional + O_OBJS_arc = dma-arc.o oldlatches.o O_OBJS_rpc = dma-rpc.o O_OBJS_footbridge = dma-footbridge.o hw-footbridge.o isa.o @@ -54,13 +59,7 @@ all: kernel.o $(HEAD_OBJ) init_task.o -$(HEAD_OBJ): $(HEAD_OBJ:.o=.S) - $(CC) $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ - include $(TOPDIR)/Rules.make - -.S.o: - $(CC) $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $< # Spell out some dependencies that `make dep' doesn't spot entry-armv.o: calls.S ../lib/constants.h diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c --- v2.4.0-test6/linux/arch/arm/kernel/arch.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/arch.c Sun Aug 13 09:54:15 2000 @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "arch.h" @@ -219,6 +219,17 @@ while (1); } + +static void xp860_power_off(void) +{ + GPDR |= GPIO_GPIO20; + GPSR = GPIO_GPIO20; + mdelay(1000); + GPCR = GPIO_GPIO20; + while(1); +} + + extern void select_sa1100_io_desc(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ @@ -273,6 +284,18 @@ setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); } + else if (machine_is_cerf()) { + // 16Meg Ram. + SET_BANK( 0, 0xc0000000, 8*1024*1024 ); + SET_BANK( 1, 0xc8000000, 8*1024*1024 ); // comment this out for 8MB Cerfs + mi->nr_banks = 2; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, 8192); + // Save 2Meg for RAMDisk + setup_initrd(0xc0500000, 3*1024*1024); + } + else if (machine_is_empeg()) { SET_BANK( 0, 0xc0000000, 4*1024*1024 ); SET_BANK( 1, 0xc8000000, 4*1024*1024 ); @@ -309,6 +332,18 @@ setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } + else if (machine_is_nanoengine()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); + + /* Get command line parameters passed from the loader (if any) */ + if( *((char*)0xc0000100) ) + *cmdline = ((char *)0xc0000100); + } else if (machine_is_tifon()) { SET_BANK( 0, 0xc0000000, 16*1024*1024 ); SET_BANK( 1, 0xc8000000, 16*1024*1024 ); @@ -335,6 +370,12 @@ pm_power_off = victor_power_off; } + else if (machine_is_xp860()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + mi->nr_banks = 1; + + pm_power_off = xp860_power_off; + } } #ifdef CONFIG_SA1100_ASSABET @@ -356,6 +397,13 @@ FIXUP(fixup_sa1100) MACHINE_END #endif +#ifdef CONFIG_SA1100_CERF +MACHINE_START(CERF, "Intrinsyc CerfBoard") + MAINTAINER("Pieter Truter") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif #ifdef CONFIG_SA1100_EMPEG MACHINE_START(EMPEG, "empeg MP3 Car Audio Player") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) @@ -377,6 +425,12 @@ #endif #ifdef CONFIG_SA1100_LART MACHINE_START(LART, "LART") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_NANOENGINE +MACHINE_START(NANOENGINE, "BSE nanoEngine") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) FIXUP(fixup_sa1100) MACHINE_END diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.4.0-test6/linux/arch/arm/kernel/armksyms.c Wed Aug 9 19:19:49 2000 +++ linux/arch/arm/kernel/armksyms.c Sun Aug 13 09:54:15 2000 @@ -23,6 +23,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, struct user_fp_struct *); @@ -187,16 +188,17 @@ EXPORT_SYMBOL(__arch_copy_to_user); EXPORT_SYMBOL(__arch_clear_user); EXPORT_SYMBOL(__arch_strnlen_user); -#elif defined(CONFIG_CPU_26) -EXPORT_SYMBOL(uaccess_kernel); -EXPORT_SYMBOL(uaccess_user); -#endif /* consistent area handling */ EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(consistent_alloc); EXPORT_SYMBOL(consistent_free); EXPORT_SYMBOL(consistent_sync); + +#elif defined(CONFIG_CPU_26) +EXPORT_SYMBOL(uaccess_kernel); +EXPORT_SYMBOL(uaccess_user); +#endif /* gcc lib functions */ EXPORT_SYMBOL_NOVERS(__gcc_bcmp); diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.0-test6/linux/arch/arm/kernel/bios32.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/bios32.c Sun Aug 13 09:54:15 2000 @@ -11,7 +11,7 @@ #include #include -#include +#include #include "bios32.h" @@ -198,20 +198,35 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { - unsigned long where, size; - u32 reg; + u32 val, check; + int reg; if (debug_pci) printk("PCI: Assigning %3s %08lx to %s\n", res->flags & IORESOURCE_IO ? "IO" : "MEM", res->start, dev->name); - where = PCI_BASE_ADDRESS_0 + resource * 4; - size = res->end - res->start; - - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); + val = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + val |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a + * non-standard resource. + */ + return; + } + pci_write_config_dword(dev, reg, val); + pci_read_config_dword(dev, reg, &check); + if ((val ^ check) & ((val & PCI_BASE_ADDRESS_SPACE_IO) ? + PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, + resource, val, check); + } } void __init pcibios_update_irq(struct pci_dev *dev, int irq) diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S --- v2.4.0-test6/linux/arch/arm/kernel/calls.S Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/kernel/calls.S Fri Aug 11 14:29:05 2000 @@ -226,8 +226,9 @@ .long SYMBOL_NAME(sys_setgid) /* 215 */ .long SYMBOL_NAME(sys_setfsuid) .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_getdents64) - .rept NR_syscalls-216 + .rept NR_syscalls-217 .long SYMBOL_NAME(sys_ni_syscall) .endr #endif diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S --- v2.4.0-test6/linux/arch/arm/kernel/debug-armv.S Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/kernel/debug-armv.S Sun Aug 13 09:54:15 2000 @@ -162,12 +162,14 @@ #elif defined(CONFIG_ARCH_L7200) - .macro addruart,rx + .equ io_virt, IO_BASE + .equ io_phys, IO_START + .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? - moveq \rx, #0x80000000 @ physical base address - movne \rx, #0xd0000000 @ virtual address + moveq \rx, #io_phys @ physical base address + movne \rx, #io_virt @ virtual address add \rx, \rx, #0x00044000 @ Ser1 @ add \rx, \rx, #0x00045000 @ Ser2 .endm diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.4.0-test6/linux/arch/arm/kernel/dec21285.c Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/kernel/dec21285.c Sun Aug 13 09:54:15 2000 @@ -274,7 +274,7 @@ cfn_mode = __footbridge_cfn_mode(); - printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX in " + printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in " "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? "central function" : "addin"); diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.4.0-test6/linux/arch/arm/kernel/dma-arc.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/dma-arc.c Sun Aug 13 09:54:15 2000 @@ -13,6 +13,7 @@ #include #include #include +#include #include "dma.h" diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.4.0-test6/linux/arch/arm/kernel/dma-rpc.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/dma-rpc.c Sun Aug 13 09:54:15 2000 @@ -315,7 +315,7 @@ /* * This is virtual DMA - we don't need anything here. */ -static int sound_enable_disable_dma(dmach_t channel, dma_t *dma) +static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) { } diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c --- v2.4.0-test6/linux/arch/arm/kernel/dma.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/dma.c Sun Aug 13 09:54:15 2000 @@ -248,24 +248,23 @@ return -EINVAL; } -static int no_dma(void) +int get_dma_residue(dmach_t channel) { return 0; } #define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a) -GLOBAL_ALIAS(disable_dma, no_dma); -GLOBAL_ALIAS(enable_dma, no_dma); -GLOBAL_ALIAS(free_dma, no_dma); -GLOBAL_ALIAS(get_dma_residue, no_dma); -GLOBAL_ALIAS(get_dma_list, no_dma); -GLOBAL_ALIAS(set_dma_mode, no_dma); -GLOBAL_ALIAS(set_dma_page, no_dma); -GLOBAL_ALIAS(set_dma_count, no_dma); -GLOBAL_ALIAS(set_dma_addr, no_dma); -GLOBAL_ALIAS(set_dma_sg, no_dma); -GLOBAL_ALIAS(set_dma_speed, no_dma); -GLOBAL_ALIAS(init_dma, no_dma); +GLOBAL_ALIAS(disable_dma, get_dma_residue); +GLOBAL_ALIAS(enable_dma, get_dma_residue); +GLOBAL_ALIAS(free_dma, get_dma_residue); +GLOBAL_ALIAS(get_dma_list, get_dma_residue); +GLOBAL_ALIAS(set_dma_mode, get_dma_residue); +GLOBAL_ALIAS(set_dma_page, get_dma_residue); +GLOBAL_ALIAS(set_dma_count, get_dma_residue); +GLOBAL_ALIAS(set_dma_addr, get_dma_residue); +GLOBAL_ALIAS(set_dma_sg, get_dma_residue); +GLOBAL_ALIAS(set_dma_speed, get_dma_residue); +GLOBAL_ALIAS(init_dma, get_dma_residue); #endif diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.4.0-test6/linux/arch/arm/kernel/ecard.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/ecard.c Sun Aug 13 09:54:15 2000 @@ -265,8 +265,7 @@ * Set up the expansion card * daemon's environment. */ -static void -ecard_init_task(void) +static void ecard_init_task(int force) { /* We want to set up the page tables for the following mapping: * Virtual Physical @@ -282,7 +281,8 @@ pgd_t *src_pgd, *dst_pgd; unsigned int dst_addr = IO_START; - exec_mmap(); + if (!force) + exec_mmap(); src_pgd = pgd_offset(current->mm, IO_BASE); dst_pgd = pgd_offset(current->mm, dst_addr); @@ -309,21 +309,24 @@ static int ecard_task(void * unused) { - current->session = 1; - current->pgrp = 1; + struct task_struct *tsk = current; + + tsk->session = 1; + tsk->pgrp = 1; /* * We don't want /any/ signals, not even SIGKILL */ - sigfillset(¤t->blocked); - sigemptyset(¤t->signal); + sigfillset(&tsk->blocked); + sigemptyset(&tsk->signal); + recalc_sigpending(tsk); - strcpy(current->comm, "kecardd"); + strcpy(tsk->comm, "kecardd"); /* * Set up the environment */ - ecard_init_task(); + ecard_init_task(0); while (1) { struct ecard_request *req; @@ -332,7 +335,7 @@ req = xchg(&ecard_req, NULL); if (req == NULL) { - sigemptyset(¤t->signal); + sigemptyset(&tsk->signal); interruptible_sleep_on(&ecard_wait); } } while (req == NULL); @@ -368,7 +371,7 @@ */ if ((current == &init_task || in_interrupt()) && req->req == req_reset && req->ec == NULL) { - ecard_init_task(); + ecard_init_task(1); ecard_task_reset(req); } else { if (ecard_pid <= 0) diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S --- v2.4.0-test6/linux/arch/arm/kernel/entry-armo.S Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/kernel/entry-armo.S Sun Aug 13 09:54:15 2000 @@ -38,17 +38,6 @@ .text -@ Offsets into task structure -@ --------------------------- -@ -#define STATE 0 -#define COUNTER 4 -#define PRIORITY 8 -#define FLAGS 12 -#define SIGPENDING 16 - -#define PF_TRACESYS 0x20 - @ Bad Abort numbers @ ----------------- @ @@ -58,12 +47,6 @@ #define BAD_IRQ 3 #define BAD_UNDEFINSTR 4 -@ OS version number used in SWIs -@ RISC OS is 0 -@ RISC iX is 8 -@ -#define OS_NUMBER 9 - @ @ Stack format (ensured by USER_* and SVC_*) @ @@ -456,6 +439,7 @@ orr lr, lr, #0x08000003 @ Force SVC bne do_IRQ mov r4, #0 + get_current_task r5 b ret_with_reschedule irq_prio_table diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.4.0-test6/linux/arch/arm/kernel/entry-armv.S Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/kernel/entry-armv.S Sun Aug 13 09:54:15 2000 @@ -32,8 +32,6 @@ .text -#define PT_TRACESYS 0x00000002 - @ Bad Abort numbers @ ----------------- @ @@ -43,12 +41,6 @@ #define BAD_IRQ 3 #define BAD_UNDEFINSTR 4 -@ OS version number used in SWIs -@ RISC OS is 0 -@ RISC iX is 8 -@ -#define OS_NUMBER 9 - @ @ Stack format (ensured by USER_* and SVC_*) @ @@ -426,12 +418,15 @@ .endm #elif defined(CONFIG_ARCH_L7200) -/* Don't use fast interrupts */ + + .equ irq_base_addr, IO_BASE_2 + .macro disable_fiq .endm .macro get_irqnr_and_base, irqnr, irqstat, base - ldr r4, =0xe0001000 @ Virt addr status reg + mov r4, #irq_base_addr @ Virt addr IRQ regs + add r4, r4, #0x00001000 @ Status reg ldr \irqstat, [r4] @ get interrupts mov \irqnr, #0 1001: tst \irqstat, #1 @@ -727,6 +722,7 @@ @ bne do_IRQ mov r4, #0 + get_current_task r5 b ret_with_reschedule .align 5 diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.4.0-test6/linux/arch/arm/kernel/entry-common.S Wed Aug 9 19:19:49 2000 +++ linux/arch/arm/kernel/entry-common.S Sun Aug 13 09:54:15 2000 @@ -1,4 +1,13 @@ #include + +#define PT_TRACESYS 0x00000002 + +@ OS version number used in SWIs +@ RISC OS is 0 +@ RISC iX is 8 +@ +#define OS_NUMBER 9 + /*============================================================================ * All exits to user mode from the kernel go through this code. */ @@ -22,25 +31,23 @@ add sp, sp, #S_OFF ret_from_sys_call: @ external entry get_softirq r0 + get_current_task r5 ldmia r0, {r0, r1} @ softirq_active, softirq_mask mov r4, #1 @ flag this as being syscall return tst r0, r1 blne SYMBOL_NAME(do_softirq) -ret_with_reschedule: @ external entry (__irq_usr) - get_current_task r5 +ret_with_reschedule: @ external entry (r5 must be set) (__irq_usr) ldr r0, [r5, #TSK_NEED_RESCHED] ldr r1, [r5, #TSK_SIGPENDING] teq r0, #0 bne ret_reschedule teq r1, #0 @ check for signals - bne ret_signal - + blne ret_signal ret_from_all: restore_user_regs @ internal ret_signal: mov r1, sp @ internal - adrsvc al, lr, ret_from_all mov r2, r4 - b SYMBOL_NAME(do_signal) + b SYMBOL_NAME(do_signal) @ note the bl above sets lr ret_reschedule: adrsvc al, lr, ret_with_reschedule @ internal b SYMBOL_NAME(schedule) @@ -48,12 +55,13 @@ .globl ret_from_exception ret_from_exception: @ external entry get_softirq r0 + get_current_task r5 ldmia r0, {r0, r1} @ softirq_active, softirq_mask mov r4, #0 tst r0, r1 + ldr r6, [sp, #S_PSR] blne SYMBOL_NAME(do_softirq) - ldr r0, [sp, #S_PSR] - tst r0, #3 @ returning to user mode? + tst r6, #3 @ returning to user mode? beq ret_with_reschedule b ret_from_all diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c --- v2.4.0-test6/linux/arch/arm/kernel/fiq.c Tue Dec 7 09:32:40 1999 +++ linux/arch/arm/kernel/fiq.c Sun Aug 13 09:54:15 2000 @@ -83,8 +83,11 @@ return 0; } -static struct fiq_handler default_owner = - { NULL, "default", fiq_def_op, NULL }; +static struct fiq_handler default_owner = { + name: "default", + fiq_op: fiq_def_op, +}; + static struct fiq_handler *current_fiq = &default_owner; int get_fiq_list(char *buf) diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.4.0-test6/linux/arch/arm/kernel/head-armo.S Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/kernel/head-armo.S Sun Aug 13 09:54:15 2000 @@ -1,11 +1,13 @@ /* * linux/arch/arm/kernel/head-armo.S * - * Copyright (C) 1994, 1995, 1996, 1997 Russell King + * Copyright (C) 1994-2000 Russell King * * 26-bit kernel startup code */ +#include #include +#include .globl SYMBOL_NAME(swapper_pg_dir) .equ SYMBOL_NAME(swapper_pg_dir), 0x0207d000 @@ -17,46 +19,69 @@ ENTRY(stext) ENTRY(_stext) __entry: cmp pc, #0x02000000 - ldrlt pc, LC1 @ if 0x01800000, call at 0x02080000 + ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000 teq r0, #0 @ Check for old calling method - blne Loldparams @ Move page if old - adr r5, LC0 - ldmia r5, {r5, r6, sl, sp} @ Setup stack - mov r4, #0 -1: cmp r5, sl @ Clear BSS - strcc r4, [r5], #4 + blne oldparams @ Move page if old + adr r0, LC0 + ldmib r0, {r2-r5, sp} @ Setup stack + mov r0, #0 +1: cmp r2, r3 @ Clear BSS + strcc r0, [r2], #4 bcc 1b - mov r0, #0xea000000 @ Point undef instr to continuation - adr r5, Lcontinue - 12 - orr r5, r0, r5, lsr #2 - str r5, [r4, #4] - mov r2, r4 - ldr r5, Larm2_id - swp r0, r0, [r2] @ check for swp (ARM2 can't) - ldr r5, Larm250_id - mrc 15, 0, r0, c0, c0 @ check for CP#15 (ARM250 can't) - mov r5, r0 @ Use processor ID if we do have CP#15 -Lcontinue: str r5, [r6] - mov r5, #0xeb000000 @ Point undef instr vector to itself - sub r5, r5, #2 - str r5, [r4, #4] + + bl detect_proc_type + str r0, [r4] + bl detect_arch_type + str r0, [r5] + mov fp, #0 b SYMBOL_NAME(start_kernel) -LC1: .word SYMBOL_NAME(_stext) -LC0: .word SYMBOL_NAME(__bss_start) - .word SYMBOL_NAME(processor_id) - .word SYMBOL_NAME(_end) - .word SYMBOL_NAME(init_task_union)+8192 -Larm2_id: .long 0x41560200 -Larm250_id: .long 0x41560250 +LC0: .word SYMBOL_NAME(_stext) + .word SYMBOL_NAME(__bss_start) @ r2 + .word SYMBOL_NAME(_end) @ r3 + .word SYMBOL_NAME(processor_id) @ r4 + .word SYMBOL_NAME(__machine_arch_type) @ r5 + .word SYMBOL_NAME(init_task_union)+8192 @ sp +arm2_id: .long 0x41560200 +arm250_id: .long 0x41560250 .align -Loldparams: mov r4, #0x02000000 +oldparams: mov r4, #0x02000000 add r3, r4, #0x00080000 add r4, r4, #0x0007c000 1: ldmia r0!, {r5 - r12} stmia r4!, {r5 - r12} cmp r4, r3 blt 1b - movs pc, lr + mov pc, lr + +/* + * We need some way to automatically detect the difference between + * these two machines. Unfortunately, it is not possible to detect + * the presence of the SuperIO chip, because that will hang the old + * Archimedes machines solid. + */ +/* DAG: Outdated, these have been combined !!!!!!! */ +detect_arch_type: +#if defined(CONFIG_ARCH_ARC) + mov r0, #MACH_TYPE_ARCHIMEDES +#elif defined(CONFIG_ARCH_A5K) + mov r0, #MACH_TYPE_A5K +#endif + mov pc, lr + +detect_proc_type: + mov r2, #0xea000000 @ Point undef instr to continuation + adr r0, continue - 12 + orr r0, r2, r0, lsr #2 + mov r1, #0 + str r0, [r1, #4] + ldr r0, arm2_id + swp r2, r2, [r1] @ check for swp (ARM2 can't) + ldr r0, arm250_id + mrc 15, 0, r0, c0, c0 @ check for CP#15 (ARM250 can't) +continue: mov r2, #0xeb000000 @ Make undef vector loop + sub r2, r2, #2 + str r2, [r1, #4] + mov pc, lr diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.4.0-test6/linux/arch/arm/kernel/head-armv.S Fri May 12 14:18:55 2000 +++ linux/arch/arm/kernel/head-armv.S Sun Aug 13 09:54:15 2000 @@ -19,6 +19,7 @@ #endif #define SWAPPER_PGDIR_OFFSET 0x4000 +#define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) .globl SYMBOL_NAME(swapper_pg_dir) .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET @@ -27,7 +28,28 @@ .type stext, #function ENTRY(stext) ENTRY(_stext) - +/* + * Entry point. The general rules are: + * should be called with r0 == 0 + * r1 contains the unique architecture number + * with MMU is off, I-cache may be on or off, D-cache should be off. + * See linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h + * for the complete list of numbers for r1. If you require a new number, + * please follow the instructions given towards the end of + * linux/Documentation/arm/README. + */ + mov r12, r0 +/* + * NOTE! Any code which is placed here should be done for one of + * the following reasons: + * + * 1. Compatability with old production boot firmware (ie, users + * actually have and are booting the kernel with the old firmware) + * and therefore will be eventually removed. + * 2. Cover the case when there is no boot firmware. This is not + * ideal, but in this case, it should ONLY set r0 and r1 to the + * appropriate value. + */ #ifdef CONFIG_ARCH_NETWINDER /* * Compatability cruft for old NetWinder NeTTroms. This @@ -63,28 +85,18 @@ mov r5, #0 movne pc, r0 - mov r0, #0 @ catch old NeTTroms mov r1, #5 @ (will go in 2.5) + mov r12, #2 << 24 @ scheduled for removal in 2.5.xx + orr r12, r12, #5 << 12 #endif #ifdef CONFIG_ARCH_L7200 /* * FIXME - No bootloader, so manually set 'r1' with our architecture number. */ - mov r0, #0 mov r1, #19 #endif -/* - * Entry point. Entry *must* be called with r0 == 0, with the MMU off. - * r1 contains the unique architecture number. See - * linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h for - * the complete list. If you require a new number, please follow the - * instructions given towards the end of Documentation/arm/README. - */ -__entry: teq r0, #0 @ wrong register vals? - movne r0, #'i' @ yes, error 'i' - bne __error - bl __lookup_processor_type +__entry: bl __lookup_processor_type teq r10, #0 @ invalid processor? moveq r0, #'p' @ yes, error 'p' beq __error @@ -98,6 +110,7 @@ @ (return control reg) __switch_data: .long __mmap_switched + .long SYMBOL_NAME(compat) .long SYMBOL_NAME(__bss_start) .long SYMBOL_NAME(_end) .long SYMBOL_NAME(processor_id) @@ -123,8 +136,9 @@ .align 5 __mmap_switched: adr r3, __switch_data + 4 - ldmia r3, {r4, r5, r6, r7, r8, sp} @ r4 = __bss_start + ldmia r3, {r2, r4, r5, r6, r7, r8, sp}@ r2 = compat @ sp = stack pointer + str r12, [r2] mov fp, #0 @ Clear BSS 1: cmp r4, r5 diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.4.0-test6/linux/arch/arm/kernel/hw-footbridge.c Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/kernel/hw-footbridge.c Sun Aug 13 09:54:15 2000 @@ -15,7 +15,7 @@ #include #include -#include +#include #define IRDA_IO_BASE 0x180 #define GP1_IO_BASE 0x338 diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/hw-sa1100.c linux/arch/arm/kernel/hw-sa1100.c --- v2.4.0-test6/linux/arch/arm/kernel/hw-sa1100.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/hw-sa1100.c Sun Aug 13 09:54:15 2000 @@ -17,7 +17,7 @@ #include #include - +#include /* * SA1100 GPIO edge detection for IRQs: @@ -130,12 +130,40 @@ * any other SA-1111 functional blocks must be enabled separately * using the SKPCR. */ + + { + /* + * SA1111 DMA bus master setup + */ + int cas; + + /* SA1111 side */ + switch ( (MDCNFG>>12) & 0x03 ) { + case 0x02: + cas = 0; break; + case 0x03: + cas = 1; break; + default: + cas = 1; break; + } + SMCR = 1 /* 1: memory is SDRAM */ + | ( 1 << 1 ) /* 1:MBGNT is enable */ + | ( ((MDCNFG >> 4) & 0x07) << 2 ) /* row address lines */ + | ( cas << 5 ); /* CAS latency */ + + /* SA1110 side */ + GPDR |= 1<<21; + GPDR &= ~(1<<22); + GAFR |= ( (1<<21) | (1<<22) ); + + TUCR |= (1<<10); + } } #endif -static void __init hw_sa1100_init(void) +static int __init hw_sa1100_init(void) { if( machine_is_assabet() ){ if(machine_has_neponset()){ @@ -147,7 +175,10 @@ "hasn't been configured in the kernel\n" ); #endif } + } else if (machine_is_xp860()) { + sa1111_init(); } + return 0; } module_init(hw_sa1100_init); diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.4.0-test6/linux/arch/arm/kernel/irq.c Wed Aug 9 19:19:49 2000 +++ linux/arch/arm/kernel/irq.c Sun Aug 13 09:54:15 2000 @@ -31,18 +31,12 @@ #include #include -#ifndef cliIF -#define cliIF() -#endif - /* - * Maximum IRQ count. Currently, this is arbitary. - * However, it should not be set too low to prevent - * false triggering. Conversely, if it is set too - * high, then you could miss a stuck IRQ. + * Maximum IRQ count. Currently, this is arbitary. However, it should + * not be set too low to prevent false triggering. Conversely, if it + * is set too high, then you could miss a stuck IRQ. * - * Maybe we ought to set a timer and re-enable the - * IRQ at a later time? + * Maybe we ought to set a timer and re-enable the IRQ at a later time? */ #define MAX_IRQ_CNT 100000 @@ -94,7 +88,6 @@ unsigned long flags; spin_lock_irqsave(&irq_controller_lock, flags); - cliIF(); irq_desc[irq].enabled = 0; irq_desc[irq].mask(irq); spin_unlock_irqrestore(&irq_controller_lock, flags); @@ -105,7 +98,6 @@ unsigned long flags; spin_lock_irqsave(&irq_controller_lock, flags); - cliIF(); irq_desc[irq].probing = 0; irq_desc[irq].triggered = 0; irq_desc[irq].enabled = 1; diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c --- v2.4.0-test6/linux/arch/arm/kernel/leds-footbridge.c Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/kernel/leds-footbridge.c Sun Aug 13 09:54:15 2000 @@ -25,6 +25,7 @@ #include #include +#include #include #define LED_STATE_ENABLED 1 @@ -35,7 +36,7 @@ static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; extern spinlock_t gpio_lock; -#ifdef CONFIG_FOOTBRIDGE +#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_CO285) static void ebsa285_leds_event(led_event_t evt) { @@ -76,15 +77,20 @@ #ifdef CONFIG_LEDS_CPU case led_idle_start: if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= XBUS_LED_RED; + hw_led_state |= XBUS_LED_AMBER; break; case led_idle_end: if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_RED; + hw_led_state &= ~XBUS_LED_AMBER; break; #endif + case led_halted: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~XBUS_LED_RED; + break; + case led_green_on: if (led_state & LED_STATE_CLAIMED) hw_led_state &= ~XBUS_LED_GREEN; @@ -174,6 +180,11 @@ break; #endif + case led_halted: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= GPIO_RED_LED; + break; + case led_green_on: if (led_state & LED_STATE_CLAIMED) hw_led_state |= GPIO_GREEN_LED; @@ -229,7 +240,7 @@ static int __init leds_init(void) { -#ifdef CONFIG_FOOTBRIDGE +#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_CO285) if (machine_is_ebsa285() || machine_is_co285()) leds_event = ebsa285_leds_event; #endif diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/leds-sa1100.c linux/arch/arm/kernel/leds-sa1100.c --- v2.4.0-test6/linux/arch/arm/kernel/leds-sa1100.c Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/kernel/leds-sa1100.c Sun Aug 13 09:54:15 2000 @@ -36,6 +36,7 @@ #include #include +#include #include @@ -95,6 +96,9 @@ break; #endif + case led_halted: + break; + case led_green_on: if (led_state & LED_STATE_CLAIMED) hw_led_state &= ~BCR_LED_GREEN; @@ -302,6 +306,100 @@ #endif /* CONFIG_SA1100_LART */ +#ifdef CONFIG_SA1100_CERF +#define LED_D0 GPIO_GPIO(0) +#define LED_D1 GPIO_GPIO(1) +#define LED_D2 GPIO_GPIO(2) +#define LED_D3 GPIO_GPIO(3) +#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3) + +static void cerf_leds_event(led_event_t evt) +{ + unsigned long flags; + + save_flags_cli(flags); + + switch (evt) { + case led_start: + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_D0; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D1; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D1; + break; +#endif + case led_green_on: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D2; + break; + + case led_green_off: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D2; + break; + + case led_amber_on: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D3; + break; + + case led_amber_off: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D3; + break; + + case led_red_on: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D1; + break; + + case led_red_off: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D1; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + restore_flags(flags); +} + +#endif /* CONFIG_SA1100_CERF */ + static void dummy_leds_event(led_event_t evt) { } @@ -325,7 +423,13 @@ if (machine_is_lart()) leds_event = lart_leds_event; #endif - +#ifdef CONFIG_SA1100_CERF + if (machine_is_cerf()) + { + //GPDR |= 0x0000000F; + leds_event = cerf_leds_event; + } +#endif leds_event(led_start); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c --- v2.4.0-test6/linux/arch/arm/kernel/oldlatches.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/oldlatches.c Sun Aug 13 09:54:15 2000 @@ -1,14 +1,17 @@ /* Support for the latches on the old Archimedes which control the floppy, * hard disc and printer * - * (c) David Alan Gilbert 1995/1996 + * (c) David Alan Gilbert 1995/1996,2000 */ #include #include #include +#include #include #include +#include +#include static unsigned char latch_a_copy; static unsigned char latch_b_copy; diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.4.0-test6/linux/arch/arm/kernel/process.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/process.c Sun Aug 13 09:54:15 2000 @@ -22,6 +22,7 @@ #include #include +#include #include /* @@ -32,7 +33,7 @@ #define IDLE_CLOCK_SLOW 2 #define IDLE_CLOCK_FAST 3 -extern char *processor_modes[]; +extern const char *processor_modes[]; extern void setup_mm_for_reboot(char mode); asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); @@ -109,10 +110,12 @@ void machine_halt(void) { + leds_event(led_halted); } void machine_power_off(void) { + leds_event(led_halted); if (pm_power_off) pm_power_off(); } diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.4.0-test6/linux/arch/arm/kernel/semaphore.c Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/kernel/semaphore.c Mon Aug 14 13:09:07 2000 @@ -7,6 +7,7 @@ * * Modified for ARM by Russell King */ +#include #include #include @@ -53,8 +54,8 @@ { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&sem->wait, &wait); + tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; + add_wait_queue_exclusive(&sem->wait, &wait); spin_lock_irq(&semaphore_lock); sem->sleepers++; @@ -67,28 +68,28 @@ */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { sem->sleepers = 0; - wake_up(&sem->wait); break; } sem->sleepers = 1; /* us - see -1 above */ spin_unlock_irq(&semaphore_lock); schedule(); - tsk->state = TASK_UNINTERRUPTIBLE; + tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; spin_lock_irq(&semaphore_lock); } spin_unlock_irq(&semaphore_lock); remove_wait_queue(&sem->wait, &wait); tsk->state = TASK_RUNNING; + wake_up(&sem->wait); } int __down_interruptible(struct semaphore * sem) { - int retval; + int retval = 0; struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue(&sem->wait, &wait); + tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE; + add_wait_queue_exclusive(&sem->wait, &wait); spin_lock_irq(&semaphore_lock); sem->sleepers ++; @@ -102,12 +103,10 @@ * it has contention. Just correct the count * and exit. */ - retval = -EINTR; if (signal_pending(current)) { + retval = -EINTR; sem->sleepers = 0; - if (atomic_add_negative(sleepers, &sem->count)) - break; - wake_up(&sem->wait); + atomic_add(sleepers, &sem->count); break; } @@ -118,8 +117,6 @@ * the lock. */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { - wake_up(&sem->wait); - retval = 0; sem->sleepers = 0; break; } @@ -127,12 +124,13 @@ spin_unlock_irq(&semaphore_lock); schedule(); - tsk->state = TASK_INTERRUPTIBLE; + tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE; spin_lock_irq(&semaphore_lock); } spin_unlock_irq(&semaphore_lock); tsk->state = TASK_RUNNING; remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); return retval; } @@ -147,8 +145,9 @@ int __down_trylock(struct semaphore * sem) { int sleepers; + unsigned long flags; - spin_lock_irq(&semaphore_lock); + spin_lock_irqsave(&semaphore_lock, flags); sleepers = sem->sleepers + 1; sem->sleepers = 0; @@ -159,7 +158,7 @@ if (!atomic_add_negative(sleepers, &sem->count)) wake_up(&sem->wait); - spin_unlock_irq(&semaphore_lock); + spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } @@ -254,7 +253,8 @@ while (atomic_read(&sem->count) < 0) { set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); if (atomic_read(&sem->count) >= 0) - break; /* we must attempt to aquire or bias the lock */ schedule(); + break; /* we must attempt to aquire or bias the lock */ + schedule(); } remove_wait_queue(&sem->wait, &wait); @@ -293,6 +293,102 @@ * registers (r0 to r3 and lr), but not ip, as we use it as a return * value in some cases.. */ +#ifdef CONFIG_CPU_26 +asm(" .section .text.lock, \"ax\" + .align 5 + .globl __down_failed +__down_failed: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + bl __down + ldmfd sp!, {r0 - r3, pc}^ + + .align 5 + .globl __down_interruptible_failed +__down_interruptible_failed: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + bl __down_interruptible + mov ip, r0 + ldmfd sp!, {r0 - r3, pc}^ + + .align 5 + .globl __down_trylock_failed +__down_trylock_failed: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + bl __down_trylock + mov ip, r0 + ldmfd sp!, {r0 - r3, pc}^ + + .align 5 + .globl __up_wakeup +__up_wakeup: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + bl __up + ldmfd sp!, {r0 - r3, pc}^ + + .align 5 + .globl __down_read_failed +__down_read_failed: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + bcc 1f +1: bl down_read_failed_biased + ldmfd sp!, {r0 - r3, pc}^ +2: bl down_read_failed + mov r1, pc + orr r2, r1, # + teqp r2, #0 + + ldr r3, [r0] + subs r3, r3, #1 + str r3, [r0] + ldmplfd sp!, {r0 - r3, pc}^ + orrcs r1, r1, #0x20000000 @ Set carry + teqp r1, #0 + bcc 2b + b 1b + + .align 5 + .globl __down_write_failed +__down_write_failed: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + bcc 1f +1: bl down_write_failed_biased + ldmfd sp!, {r0 - r3, pc}^ +2: bl down_write_failed + mov r1, pc + orr r2, r1, #128 + teqp r2, #0 + + ldr r3, [r0] + subs r3, r3, #"RW_LOCK_BIAS_STR" + str r3, [r0] + ldmeqfd sp!, {r0 - r3, pc}^ + orrcs r1, r1, #0x20000000 @ Set carry + teqp r1, #0 + bcc 2b + b 1b + + .align 5 + .globl __rwsem_wake +__rwsem_wake: + stmfd sp!, {r0 - r3, lr} + mov r0, ip + beq 1f + bl rwsem_wake_readers + ldmfd sp!, {r0 - r3, pc}^ +1: bl rwsem_wake_writer + ldmfd sp!, {r0 - r3, pc}^ + + .previous + "); + +#else +/* 32 bit version */ asm(" .section .text.lock, \"ax\" .align 5 .globl __down_failed @@ -382,3 +478,4 @@ .previous "); +#endif diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.4.0-test6/linux/arch/arm/kernel/setup.c Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/kernel/setup.c Sun Aug 13 09:54:15 2000 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include "arch.h" @@ -40,6 +40,7 @@ extern int _stext, _text, _etext, _edata, _end; unsigned int processor_id; +unsigned int compat; unsigned int __machine_arch_type; unsigned int system_rev; unsigned int system_serial_low; @@ -161,6 +162,11 @@ } printk("Architecture: %s\n", list->name); + if (compat) + printk(KERN_WARNING "Using compatability code " + "scheduled for removal in v%d.%d.%d\n", + compat >> 24, (compat >> 12) & 0x3ff, + compat & 0x3ff); return list; } @@ -304,12 +310,6 @@ char *from = default_command_line; memset(&meminfo, 0, sizeof(meminfo)); - -#if defined(CONFIG_ARCH_ARC) - __machine_arch_type = MACH_TYPE_ARCHIMEDES; -#elif defined(CONFIG_ARCH_A5K) - __machine_arch_type = MACH_TYPE_A5K; -#endif setup_processor(); diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.4.0-test6/linux/arch/arm/kernel/signal.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/signal.c Sun Aug 13 09:54:15 2000 @@ -35,37 +35,38 @@ int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) { + int err = -EFAULT;; + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; + goto out; + if (from->si_code < 0) return __copy_to_user(to, from, sizeof(siginfo_t)); - else { - int err; - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - /* First 32bits of unions are always present. */ - err |= __put_user(from->si_pid, &to->si_pid); - switch (from->si_code >> 16) { - case __SI_FAULT >> 16: - break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - err |= __put_user(from->si_uid, &to->si_uid); - break; - /* case __SI_RT: This is not generated by the kernel as of now. */ - } - return err; + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ } +out: + return err; } /* @@ -175,24 +176,24 @@ { int err = 0; - err |= __get_user(regs->ARM_r0, &sc->arm_r0); - err |= __get_user(regs->ARM_r1, &sc->arm_r1); - err |= __get_user(regs->ARM_r2, &sc->arm_r2); - err |= __get_user(regs->ARM_r3, &sc->arm_r3); - err |= __get_user(regs->ARM_r4, &sc->arm_r4); - err |= __get_user(regs->ARM_r5, &sc->arm_r5); - err |= __get_user(regs->ARM_r6, &sc->arm_r6); - err |= __get_user(regs->ARM_r7, &sc->arm_r7); - err |= __get_user(regs->ARM_r8, &sc->arm_r8); - err |= __get_user(regs->ARM_r9, &sc->arm_r9); - err |= __get_user(regs->ARM_r10, &sc->arm_r10); - err |= __get_user(regs->ARM_fp, &sc->arm_fp); - err |= __get_user(regs->ARM_ip, &sc->arm_ip); - err |= __get_user(regs->ARM_sp, &sc->arm_sp); - err |= __get_user(regs->ARM_lr, &sc->arm_lr); - err |= __get_user(regs->ARM_pc, &sc->arm_pc); + __get_user_error(regs->ARM_r0, &sc->arm_r0, err); + __get_user_error(regs->ARM_r1, &sc->arm_r1, err); + __get_user_error(regs->ARM_r2, &sc->arm_r2, err); + __get_user_error(regs->ARM_r3, &sc->arm_r3, err); + __get_user_error(regs->ARM_r4, &sc->arm_r4, err); + __get_user_error(regs->ARM_r5, &sc->arm_r5, err); + __get_user_error(regs->ARM_r6, &sc->arm_r6, err); + __get_user_error(regs->ARM_r7, &sc->arm_r7, err); + __get_user_error(regs->ARM_r8, &sc->arm_r8, err); + __get_user_error(regs->ARM_r9, &sc->arm_r9, err); + __get_user_error(regs->ARM_r10, &sc->arm_r10, err); + __get_user_error(regs->ARM_fp, &sc->arm_fp, err); + __get_user_error(regs->ARM_ip, &sc->arm_ip, err); + __get_user_error(regs->ARM_sp, &sc->arm_sp, err); + __get_user_error(regs->ARM_lr, &sc->arm_lr, err); + __get_user_error(regs->ARM_pc, &sc->arm_pc, err); #ifdef CONFIG_CPU_32 - err |= __get_user(regs->ARM_cpsr, &sc->arm_cpsr); + __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); #endif err |= !valid_user_regs(regs); @@ -289,30 +290,30 @@ { int err = 0; - err |= __put_user (regs->ARM_r0, &sc->arm_r0); - err |= __put_user (regs->ARM_r1, &sc->arm_r1); - err |= __put_user (regs->ARM_r2, &sc->arm_r2); - err |= __put_user (regs->ARM_r3, &sc->arm_r3); - err |= __put_user (regs->ARM_r4, &sc->arm_r4); - err |= __put_user (regs->ARM_r5, &sc->arm_r5); - err |= __put_user (regs->ARM_r6, &sc->arm_r6); - err |= __put_user (regs->ARM_r7, &sc->arm_r7); - err |= __put_user (regs->ARM_r8, &sc->arm_r8); - err |= __put_user (regs->ARM_r9, &sc->arm_r9); - err |= __put_user (regs->ARM_r10, &sc->arm_r10); - err |= __put_user (regs->ARM_fp, &sc->arm_fp); - err |= __put_user (regs->ARM_ip, &sc->arm_ip); - err |= __put_user (regs->ARM_sp, &sc->arm_sp); - err |= __put_user (regs->ARM_lr, &sc->arm_lr); - err |= __put_user (regs->ARM_pc, &sc->arm_pc); + __put_user_error(regs->ARM_r0, &sc->arm_r0, err); + __put_user_error(regs->ARM_r1, &sc->arm_r1, err); + __put_user_error(regs->ARM_r2, &sc->arm_r2, err); + __put_user_error(regs->ARM_r3, &sc->arm_r3, err); + __put_user_error(regs->ARM_r4, &sc->arm_r4, err); + __put_user_error(regs->ARM_r5, &sc->arm_r5, err); + __put_user_error(regs->ARM_r6, &sc->arm_r6, err); + __put_user_error(regs->ARM_r7, &sc->arm_r7, err); + __put_user_error(regs->ARM_r8, &sc->arm_r8, err); + __put_user_error(regs->ARM_r9, &sc->arm_r9, err); + __put_user_error(regs->ARM_r10, &sc->arm_r10, err); + __put_user_error(regs->ARM_fp, &sc->arm_fp, err); + __put_user_error(regs->ARM_ip, &sc->arm_ip, err); + __put_user_error(regs->ARM_sp, &sc->arm_sp, err); + __put_user_error(regs->ARM_lr, &sc->arm_lr, err); + __put_user_error(regs->ARM_pc, &sc->arm_pc, err); #ifdef CONFIG_CPU_32 - err |= __put_user (regs->ARM_cpsr, &sc->arm_cpsr); + __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); #endif - err |= __put_user (current->thread.trap_no, &sc->trap_no); - err |= __put_user (current->thread.error_code, &sc->error_code); - err |= __put_user (current->thread.address, &sc->fault_address); - err |= __put_user (mask, &sc->oldmask); + __put_user_error(current->thread.trap_no, &sc->trap_no, err); + __put_user_error(current->thread.error_code, &sc->error_code, err); + __put_user_error(current->thread.address, &sc->fault_address, err); + __put_user_error(mask, &sc->oldmask, err); return err; } diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.4.0-test6/linux/arch/arm/kernel/traps.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/kernel/traps.c Sun Aug 13 09:54:15 2000 @@ -30,7 +30,7 @@ extern void c_backtrace (unsigned long fp, int pmode); -char *processor_modes[]= +const char *processor_modes[]= { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , @@ -414,7 +414,7 @@ if (data) printk(KERN_CRIT" - extra data = %p", data); printk("\n"); - BUG(); + *(int *)0 = 0; } void __readwrite_bug(const char *fn) diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.0-test6/linux/arch/arm/lib/Makefile Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/lib/Makefile Sun Aug 13 09:54:15 2000 @@ -4,6 +4,8 @@ # Copyright (C) 1995-1999 Russell King # +USE_STANDARD_AS_RULE := true + L_TARGET := lib.a L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \ csumpartialcopyuser.o clearbit.o copy_page.o findbit.o \ @@ -35,9 +37,6 @@ L_OBJS += $(L_OBJS_$(MACHINE)) include $(TOPDIR)/Rules.make - -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< constants.h: getconsdata.o extractconstants.pl $(PERL) extractconstants.pl $(OBJDUMP) > $@ diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.4.0-test6/linux/arch/arm/lib/uaccess.S Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/lib/uaccess.S Sun Aug 13 09:54:15 2000 @@ -76,20 +76,20 @@ blt .c2u_0rem8lp .c2u_0cpy8lp: ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} @ Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldnt fault ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} @ Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #32 bpl .c2u_0cpy8lp .c2u_0rem8lp: cmn ip, #16 ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} @ Shouldn't fault + stmgeia r0!, {r3 - r6} @ Shouldnt fault tst ip, #8 ldmneia r1!, {r3 - r4} - stmneia r0!, {r3 - r4} @ Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 ldrne r3, [r1], #4 - strnet r3, [r0], #4 @ Shouldn't fault + strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_0fupi .c2u_0nowords: teq ip, #0 @@ -141,7 +141,7 @@ orr r5, r5, r6, lsl #24 mov r6, r6, lsr #8 orr r6, r6, r7, lsl #24 - stmia r0!, {r3 - r6} @ Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_1cpy8lp .c2u_1rem8lp: tst ip, #8 @@ -150,12 +150,12 @@ orrne r3, r3, r4, lsl #24 movne r4, r4, lsr #8 orrne r4, r4, r7, lsl #24 - stmneia r0!, {r3 - r4} @ Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 movne r3, r7, lsr #8 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #24 - strnet r3, [r0], #4 @ Shouldn't fault + strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_1fupi .c2u_1nowords: mov r3, r7, lsr #8 @@ -195,7 +195,7 @@ orr r5, r5, r6, lsl #16 mov r6, r6, lsr #16 orr r6, r6, r7, lsl #16 - stmia r0!, {r3 - r6} @ Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_2cpy8lp .c2u_2rem8lp: tst ip, #8 @@ -204,12 +204,12 @@ orrne r3, r3, r4, lsl #16 movne r4, r4, lsr #16 orrne r4, r4, r7, lsl #16 - stmneia r0!, {r3 - r4} @ Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 movne r3, r7, lsr #16 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #16 - strnet r3, [r0], #4 @ Shouldn't fault + strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_2fupi .c2u_2nowords: mov r3, r7, lsr #16 @@ -249,7 +249,7 @@ orr r5, r5, r6, lsl #8 mov r6, r6, lsr #24 orr r6, r6, r7, lsl #8 - stmia r0!, {r3 - r6} @ Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_3cpy8lp .c2u_3rem8lp: tst ip, #8 @@ -258,12 +258,12 @@ orrne r3, r3, r4, lsl #8 movne r4, r4, lsr #24 orrne r4, r4, r7, lsl #8 - stmneia r0!, {r3 - r4} @ Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 movne r3, r7, lsr #24 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #8 - strnet r3, [r0], #4 @ Shouldn't fault + strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_3fupi .c2u_3nowords: mov r3, r7, lsr #24 @@ -333,20 +333,20 @@ subs ip, ip, #32 blt .cfu_0rem8lp -.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldn't fault +.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault stmia r0!, {r3 - r6} - ldmia r1!, {r3 - r6} @ Shouldn't fault + ldmia r1!, {r3 - r6} @ Shouldnt fault stmia r0!, {r3 - r6} subs ip, ip, #32 bpl .cfu_0cpy8lp .cfu_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} @ Shouldn't fault + ldmgeia r1!, {r3 - r6} @ Shouldnt fault stmgeia r0!, {r3 - r6} tst ip, #8 - ldmneia r1!, {r3 - r4} @ Shouldn't fault + ldmneia r1!, {r3 - r4} @ Shouldnt fault stmneia r0!, {r3 - r4} tst ip, #4 - ldrnet r3, [r1], #4 @ Shouldn't fault + ldrnet r3, [r1], #4 @ Shouldnt fault strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_0fupi @@ -392,7 +392,7 @@ blt .cfu_1rem8lp .cfu_1cpy8lp: mov r3, r7, lsr #8 - ldmia r1!, {r4 - r7} @ Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldnt fault orr r3, r3, r4, lsl #24 mov r4, r4, lsr #8 orr r4, r4, r5, lsl #24 @@ -405,7 +405,7 @@ bpl .cfu_1cpy8lp .cfu_1rem8lp: tst ip, #8 movne r3, r7, lsr #8 - ldmneia r1!, {r4, r7} @ Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldnt fault orrne r3, r3, r4, lsl #24 movne r4, r4, lsr #8 orrne r4, r4, r7, lsl #24 @@ -446,7 +446,7 @@ blt .cfu_2rem8lp .cfu_2cpy8lp: mov r3, r7, lsr #16 - ldmia r1!, {r4 - r7} @ Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldnt fault orr r3, r3, r4, lsl #16 mov r4, r4, lsr #16 orr r4, r4, r5, lsl #16 @@ -459,7 +459,7 @@ bpl .cfu_2cpy8lp .cfu_2rem8lp: tst ip, #8 movne r3, r7, lsr #16 - ldmneia r1!, {r4, r7} @ Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldnt fault orrne r3, r3, r4, lsl #16 movne r4, r4, lsr #16 orrne r4, r4, r7, lsl #16 @@ -500,7 +500,7 @@ blt .cfu_3rem8lp .cfu_3cpy8lp: mov r3, r7, lsr #24 - ldmia r1!, {r4 - r7} @ Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldnt fault orr r3, r3, r4, lsl #8 mov r4, r4, lsr #24 orr r4, r4, r5, lsl #8 @@ -513,7 +513,7 @@ bpl .cfu_3cpy8lp .cfu_3rem8lp: tst ip, #8 movne r3, r7, lsr #24 - ldmneia r1!, {r4, r7} @ Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldnt fault orrne r3, r3, r4, lsl #8 movne r4, r4, lsr #24 orrne r4, r4, r7, lsl #8 @@ -597,7 +597,7 @@ * or zero on exception, or n + 1 if too long */ ENTRY(__arch_strnlen_user) - stmfd sp!, {lr} + str lr, [sp, #-4]! mov r2, r0 1: USER( ldrbt r3, [r0], #1) @@ -623,7 +623,7 @@ * Returns : number of characters copied */ ENTRY(__arch_strncpy_from_user) - stmfd sp!, {lr} + str lr, [sp, #-4]! add ip, r1, #1 1: subs r2, r2, #1 bmi 2f diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.4.0-test6/linux/arch/arm/mm/Makefile Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/mm/Makefile Sun Aug 13 09:54:15 2000 @@ -7,8 +7,10 @@ # # Note 2! The CFLAGS definition is now in the main makefile... +USE_STANDARD_AS_RULE := true + O_TARGET := mm.o -O_OBJS := consistent.o extable.o fault-$(PROCESSOR).o init.o \ +O_OBJS := extable.o fault-$(PROCESSOR).o init.o \ mm-$(PROCESSOR).o small_page.o ifeq ($(CONFIG_CPU_26),y) @@ -31,13 +33,10 @@ ifeq ($(CONFIG_CPU_SA1100),y) P_OBJS += proc-sa110.o endif - O_OBJS += mm-$(MACHINE).o ioremap.o $(sort $(P_OBJS)) + O_OBJS += mm-$(MACHINE).o consistent.o ioremap.o $(sort $(P_OBJS)) endif include $(TOPDIR)/Rules.make - -.S.o: - $(CC) $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $< # Special dependencies fault-armv.o: fault-common.c diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.4.0-test6/linux/arch/arm/mm/init.c Wed Aug 9 19:19:49 2000 +++ linux/arch/arm/mm/init.c Sun Aug 13 09:54:15 2000 @@ -18,12 +18,10 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_INITRD #include -#endif -#include #include +#include #include #include #include @@ -151,11 +149,18 @@ end = page + NODE_DATA(node)->node_size; do { - if (PageSkip(page)) { - page = page->next_hash; - if (page == NULL) - break; - } +/* This is currently broken + * PG_skip is used on sparc/sparc64 architectures to "skip" certain + * parts of the address space. + * + * #define PG_skip 10 + * #define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags)) + * if (PageSkip(page)) { + * page = page->next_hash; + * if (page == NULL) + * break; + * } + */ total++; if (PageReserved(page)) reserved++; @@ -554,7 +559,7 @@ initpages = &__init_end - &__init_begin; high_memory = (void *)__va(meminfo.end); - max_mapnr = MAP_NR(high_memory); + max_mapnr = virt_to_page(high_memory) - mem_map; /* * We may have non-contiguous memory. @@ -598,9 +603,9 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s) { unsigned int size = (end - addr) >> 10; - struct page *page = virt_to_page(addr); - for (; addr < end; addr += PAGE_SIZE, page ++) { + for (; addr < end; addr += PAGE_SIZE) { + struct page *page = virt_to_page(addr); ClearPageReserved(page); set_page_count(page, 1); free_page(addr); @@ -608,18 +613,14 @@ } if (size) - printk(" %dk %s", size, s); + printk("Freeing %s memory: %dK\n", s, size); } void free_initmem(void) { - printk("Freeing unused kernel memory:"); - free_area((unsigned long)(&__init_begin), (unsigned long)(&__init_end), "init"); - - printk("\n"); } #ifdef CONFIG_BLK_DEV_INITRD @@ -628,17 +629,8 @@ void free_initrd_mem(unsigned long start, unsigned long end) { - unsigned long addr; - - if (!keep_initrd) { - for (addr = start; addr < end; addr += PAGE_SIZE) { - ClearPageReserved(virt_to_page(addr)); - set_page_count(virt_to_page(addr), 1); - free_page(addr); - totalram_pages++; - } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); - } + if (!keep_initrd) + free_area(start, end, "initrd"); } static int __init keepinitrd_setup(char *__unused) diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c --- v2.4.0-test6/linux/arch/arm/mm/mm-footbridge.c Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/mm/mm-footbridge.c Sun Aug 13 09:54:15 2000 @@ -48,6 +48,28 @@ #else /* + * The mapping when the footbridge is in add-in mode. + */ +#define MAPPING \ + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 } + +#endif + +struct map_desc io_desc[] __initdata = { + MAPPING +}; + +unsigned int __initdata io_desc_size = SIZE(io_desc); + + +#ifdef CONFIG_FOOTBRIDGE_ADDIN + +/* * These two functions convert virtual addresses to PCI addresses * and PCI addresses to virtual addresses. Note that it is only * legal to use these on memory obtained via get_free_page or @@ -78,22 +100,4 @@ return res; } -/* - * The mapping when the footbridge is in add-in mode. - */ -#define MAPPING \ - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 } - #endif - -struct map_desc io_desc[] __initdata = { - MAPPING -}; - -unsigned int __initdata io_desc_size = SIZE(io_desc); - diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/mm-l7200.c linux/arch/arm/mm/mm-l7200.c --- v2.4.0-test6/linux/arch/arm/mm/mm-l7200.c Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/mm/mm-l7200.c Sun Aug 13 09:54:15 2000 @@ -1,9 +1,9 @@ /* * arch/arm/mm/mm-lusl7200.c * - * Extra MM routines for LUSL7200 architecture + * Extra MM routines for L7200 architecture * - * Copyright (C) 2000 Steven J. Hill + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) */ #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.4.0-test6/linux/arch/arm/mm/mm-sa1100.c Thu Jul 27 17:37:59 2000 +++ linux/arch/arm/mm/mm-sa1100.c Sun Aug 13 09:54:15 2000 @@ -23,6 +23,7 @@ #include #include #include +#include #include "map.h" @@ -53,6 +54,15 @@ #endif }; +static struct map_desc nanoengine_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_NANOENGINE + { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xd4000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ + { 0xdc000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */ + SA1100_STD_IO_MAPPING +#endif +}; + static struct map_desc bitsy_io_desc[] __initdata = { #ifdef CONFIG_SA1100_BITSY { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ @@ -61,6 +71,14 @@ #endif }; +static struct map_desc cerf_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_CERF + { 0xd8000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Chip */ + { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + SA1100_STD_IO_MAPPING +#endif +}; + static struct map_desc empeg_io_desc[] __initdata = { #ifdef CONFIG_SA1100_EMPEG { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ @@ -77,6 +95,14 @@ #endif }; +static struct map_desc lart_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_LART + { 0xd0000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */ + { 0xd8000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */ + SA1100_STD_IO_MAPPING +#endif +}; + static struct map_desc thinclient_io_desc[] __initdata = { #ifdef CONFIG_SA1100_THINCLIENT #if 0 @@ -104,6 +130,14 @@ #endif }; +static struct map_desc xp860_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_XP860 + { 0xd8000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xda000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ + { 0xdc000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ + SA1100_STD_IO_MAPPING +#endif +}; static struct map_desc default_io_desc[] __initdata = { SA1100_STD_IO_MAPPING @@ -122,15 +156,24 @@ if( machine_is_assabet() ) { memcpy( io_desc, assabet_io_desc, sizeof(assabet_io_desc) ); io_desc_size = SIZE(assabet_io_desc); + } else if( machine_is_nanoengine() ) { + memcpy( io_desc, nanoengine_io_desc, sizeof(nanoengine_io_desc) ); + io_desc_size = SIZE(nanoengine_io_desc); } else if( machine_is_bitsy() ) { memcpy( io_desc, bitsy_io_desc, sizeof(bitsy_io_desc) ); io_desc_size = SIZE(bitsy_io_desc); + } else if( machine_is_cerf() ) { + memcpy( io_desc, cerf_io_desc, sizeof(cerf_io_desc) ); + io_desc_size = SIZE(cerf_io_desc); } else if( machine_is_empeg() ) { memcpy( io_desc, empeg_io_desc, sizeof(empeg_io_desc) ); io_desc_size = SIZE(empeg_io_desc); } else if( machine_is_graphicsclient() ) { memcpy( io_desc, graphicsclient_io_desc, sizeof(graphicsclient_io_desc) ); io_desc_size = SIZE(graphicsclient_io_desc); + } else if( machine_is_lart() ) { + memcpy( io_desc, lart_io_desc, sizeof(lart_io_desc) ); + io_desc_size = SIZE(lart_io_desc); } else if( machine_is_thinclient() ) { memcpy( io_desc, thinclient_io_desc, sizeof(thinclient_io_desc) ); io_desc_size = SIZE(thinclient_io_desc); @@ -140,6 +183,9 @@ } else if( machine_is_victor() ) { memcpy( io_desc, victor_io_desc, sizeof(victor_io_desc) ); io_desc_size = SIZE(victor_io_desc); + } else if( machine_is_xp860() ) { + memcpy( io_desc, xp860_io_desc, sizeof(xp860_io_desc) ); + io_desc_size = SIZE(xp860_io_desc); } else { memcpy( io_desc, default_io_desc, sizeof(default_io_desc) ); io_desc_size = SIZE(default_io_desc); diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S --- v2.4.0-test6/linux/arch/arm/mm/proc-arm720.S Mon Jul 10 16:47:19 2000 +++ linux/arch/arm/mm/proc-arm720.S Sun Aug 13 09:54:15 2000 @@ -10,11 +10,13 @@ * Changelog: * 05-09-2000 SJH Created by moving 720 specific functions * out of 'proc-arm6,7.S' per RSK discussion + * 07-25-2000 SJH Added idle function. */ #include #include #include #include +#include #include "../lib/constants.h" /* @@ -127,8 +129,8 @@ add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine movs pc, lr - b Ldata_unknown - b Ldata_unknown + b Ldata_lateldrhpost @ ldrh rd, [rn], #m/rm + b Ldata_lateldrhpre @ ldrh rd, [rn, #m/rm] b Ldata_unknown b Ldata_unknown b Ldata_lateldrpostconst @ ldr rd, [rn], #m @@ -142,6 +144,7 @@ b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m b Ldata_simple @ ldc rd, [rn, #m] b Ldata_unknown + Ldata_unknown: @ Part of jumptable mov r0, r2 mov r1, r4 @@ -149,6 +152,33 @@ bl baddataabort b ret_from_sys_call +Ldata_lateldrhpre: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple +Ldata_lateldrhpost: + tst r4, #1 << 22 @ check if register or immediate offset + beq Ldata_lateldrhpostreg +Ldata_lateldrhpostconst: + and r2, r4, #0xf @ load and clear low nibble of const offset + and r5, r4, #0xf00 @ load and clear high nibble of const offset + orrs r2, r2, r5, lsr #4 @ create offset + beq Ldata_simple @ don't have to do anything if zero + and r5, r4, #0xf << 16 @ get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r7, r0, r2, lsr #20 + addeq r7, r0, r2, lsr #20 + b Ldata_saver7 +Ldata_lateldrhpostreg: + and r5, r4, #0xf + ldr r2, [sp, r5, lsl #2] @ get Rm + and r5, r4, #0xf << 16 + ldr r0, [sp, r5, lsr #14] @ get Rn + tst r4, #1 << 23 + subne r7, r0, r2 + addeq r7, r0, r2 + b Ldata_saver7 + Ldata_lateldrpreconst: tst r4, #1 << 21 @ check writeback bit beq Ldata_simple @@ -219,7 +249,6 @@ * Function: arm720_check_bugs (void) * : arm720_proc_init (void) * : arm720_proc_fin (void) - * : arm720_proc_do_idle (void) * * Notes : This processor does not require these */ @@ -240,8 +269,22 @@ mcr p15, 0, r0, c1, c0, 0 @ disable caches mov pc, lr +/* + * Function: arm720_proc_do_idle (void) + * + * Params : r0 = call type: + * 0 = slow idle + * 1 = fast idle + * 2 = switch to slow processor clock + * 3 = switch to fast processor clock + * + * Purpose : put the processer in proper idle mode + */ ENTRY(cpu_arm720_do_idle) - mov r0, #-EINVAL + ldr r2, =IO_BASE @ Virt addr of IO + add r2, r2, #0x00050000 @ Start of PMU regs + mov r1, #0x01 @ Idle mode + str r1, [r2, #4] mov pc, lr /* diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.4.0-test6/linux/arch/arm/mm/proc-sa110.S Fri Jun 23 21:55:07 2000 +++ linux/arch/arm/mm/proc-sa110.S Sun Aug 13 09:54:15 2000 @@ -313,8 +313,8 @@ ldr r1, [r0] @ read instruction causing problem mrc p15, 0, r0, c6, c0, 0 @ get FAR mov r1, r1, lsr #19 @ b1 = L - and r1, r1, #2 mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r1, r1, #2 and r3, r3, #255 mov pc, lr diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile --- v2.4.0-test6/linux/arch/arm/nwfpe/Makefile Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/nwfpe/Makefile Sun Aug 13 09:54:15 2000 @@ -4,6 +4,8 @@ # Copyright (C) 1998, 1999 Philip Blundell # +USE_STANDARD_AS_RULE := true + NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ fpmodule.o fpopcode.o softfloat.o \ single_cpdo.o double_cpdo.o extended_cpdo.o diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/tools/gen-mach-types linux/arch/arm/tools/gen-mach-types --- v2.4.0-test6/linux/arch/arm/tools/gen-mach-types Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/tools/gen-mach-types Sun Aug 13 09:54:15 2000 @@ -0,0 +1,73 @@ +#!/bin/awk +# +# Awk script to generate include/asm-arm/mach-types.h +# +BEGIN { nr = 0 } +/^#/ { next } +/^[ ]*$/ { next } + +NF == 4 { + machine_is[nr] = "machine_is_"$1; + config[nr] = "CONFIG_"$2; + mach_type[nr] = "MACH_TYPE_"$3; + num[nr] = $4; nr++ + } + +NF == 3 { + machine_is[nr] = "machine_is_"$1; + config[nr] = "CONFIG_"$2; + mach_type[nr] = "MACH_TYPE_"$3; + num[nr] = ""; nr++ + } + + +END { + printf("/*\n"); + printf(" * This was automagically generated from %s!\n", FILENAME); + printf(" * Do NOT edit\n"); + printf(" */\n\n"); + printf("#ifndef __ASM_ARM_MACH_TYPE_H\n"); + printf("#define __ASM_ARM_MACH_TYPE_H\n\n"); + printf("#include \n\n"); + printf("#ifndef __ASSEMBLY__\n"); + printf("/* The type of machine we're running on */\n"); + printf("extern unsigned int __machine_arch_type;\n"); + printf("#endif\n\n"); + + printf("/* see arch/arm/kernel/arch.c for a description of these */\n"); + for (i = 0; i < nr; i++) + if (num[i] ~ /..*/) + printf("#define %-30s %d\n", mach_type[i], num[i]); + + printf("\n"); + + for (i = 0; i < nr; i++) + if (num[i] ~ /..*/) { + printf("#ifdef %s\n", config[i]); + printf("# ifdef machine_arch_type\n"); + printf("# undef machine_arch_type\n"); + printf("# define machine_arch_type\t__machine_arch_type\n"); + printf("# else\n"); + printf("# define machine_arch_type\t%s\n", mach_type[i]); + printf("# endif\n"); + printf("# define %s()\t(machine_arch_type == %s)\n", machine_is[i], mach_type[i]); + printf("#else\n"); + printf("# define %s()\t(0)\n", machine_is[i]); + printf("#endif\n\n"); + } + + printf("/*\n * These have not yet been registered\n */\n"); + for (i = 0; i < nr; i++) + if (num[i] !~ /..*/) + printf("/* #define %-30s <> */\n", mach_type[i]); + + for (i = 0; i < nr; i++) + if (num[i] !~ /..*/) { + printf("#define %s()\t(0)\n", machine_is[i]); + } + + printf("\n#ifndef machine_arch_type\n"); + printf("#define machine_arch_type\t__machine_arch_type\n"); + printf("#endif\n\n"); + printf("#endif\n"); + } diff -u --recursive --new-file v2.4.0-test6/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types --- v2.4.0-test6/linux/arch/arm/tools/mach-types Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/tools/mach-types Sun Aug 13 09:54:15 2000 @@ -0,0 +1,44 @@ +# Database of machine macros and numbers +# +# To add an entry into this database, please see +# Documentation/arm/README +# +# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number +# +ebsa110 ARCH_EBSA110 EBSA110 0 +riscpc ARCH_RPC RISCPC 1 +nexuspci ARCH_NEXUSPCI NEXUSPCI 3 +ebsa285 ARCH_EBSA285 EBSA285 4 +netwinder ARCH_NETWINDER NETWINDER 5 +cats ARCH_CATS CATS 6 +tbox ARCH_TBOX TBOX 7 +co285 ARCH_CO285 CO285 8 +clps7110 ARCH_CLPS7110 CLPS7110 9 +arc ARCH_ARC ARCHIMEDES 10 +a5k ARCH_A5K A5K 11 +etoile ARCH_ETOILE ETOILE 12 +lacie_nas ARCH_LACIE_NAS LACIE_NAS 13 +clps7500 ARCH_CLPS7500 CLPS7500 14 +shark ARCH_SHARK SHARK 15 +brutus SA1100_BRUTUS BRUTUS 16 +personal_server ARCH_PERSONAL_SERVER PERSONAL_SERVER 17 +itsy SA1100_ITSY ITSY 18 +l7200 ARCH_L7200 L7200 19 +pleb SA1100_PLEB PLEB 20 +integrator ARCH_INTEGRATOR INTEGRATOR 21 +bitsy SA1100_BITSY BITSY 22 +ixp1200 ARCH_IXP1200 IXP1200 23 +thinclient SA1100_THINCLIENT THINCLIENT 24 +assabet SA1100_ASSABET ASSABET 25 +victor SA1100_VICTOR VICTOR 26 +lart SA1100_LART LART 27 +ranger ARCH_RANGER RANGER 28 +graphicsclient SA1100_GRAPHICSCLIENT GRAPHICSCLIENT 29 +xp860 SA1100_XP860 XP860 30 +cerf SA1100_CERF CERF 31 +nanoengine SA1100_NANOENGINE NANOENGINE 32 + +# The following are unallocated +empeg SA1100_EMPEG EMPEG +tifon SA1100_TIFON TIFON +penny SA1100_PENNY PENNY diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.4.0-test6/linux/arch/i386/Makefile Wed Aug 9 19:19:49 2000 +++ linux/arch/i386/Makefile Fri Aug 18 09:30:51 2000 @@ -45,6 +45,10 @@ CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi) endif +ifdef CONFIG_M586MMX +CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi) +endif + ifdef CONFIG_M686 CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) endif diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.0-test6/linux/arch/i386/config.in Fri Jul 14 12:12:05 2000 +++ linux/arch/i386/config.in Tue Aug 22 11:57:15 2000 @@ -30,7 +30,8 @@ "386 CONFIG_M386 \ 486 CONFIG_M486 \ 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ - Pentium-Classic/Pentium-MMX CONFIG_M586TSC \ + Pentium-Classic CONFIG_M586TSC \ + Pentium-MMX CONFIG_M586MMX \ Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \ Pentium-III CONFIG_M686FXSR \ K6/K6-II/K6-III CONFIG_MK6 \ @@ -68,6 +69,13 @@ define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y fi +if [ "$CONFIG_M586MMX" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_GOOD_APIC y +fi if [ "$CONFIG_M686" = "y" ]; then define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_TSC y @@ -310,10 +318,15 @@ fi endmenu +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in source drivers/char/Config.in - #source drivers/misc/Config.in + +source drivers/media/Config.in source fs/Config.in diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.0-test6/linux/arch/i386/defconfig Wed Aug 9 19:19:49 2000 +++ linux/arch/i386/defconfig Wed Aug 23 11:34:08 2000 @@ -25,6 +25,7 @@ # CONFIG_M486 is not set # CONFIG_M586 is not set # CONFIG_M586TSC is not set +# CONFIG_M586MMX is not set CONFIG_M686=y # CONFIG_M686FXSR is not set # CONFIG_MK6 is not set @@ -136,10 +137,8 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set @@ -332,6 +331,7 @@ CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -353,6 +353,7 @@ # CONFIG_TULIP is not set # CONFIG_DGRS is not set CONFIG_EEPRO100=y +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -427,6 +428,11 @@ # CONFIG_CD_NO_IDESCSI is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# # Character devices # CONFIG_VT=y @@ -456,6 +462,10 @@ # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -465,11 +475,6 @@ # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -492,6 +497,15 @@ # # CONFIG_PCMCIA_SERIAL_CS is not set # CONFIG_PCMCIA_SERIAL_CB is not set + +# +# Multimedia devices +# + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set # # File systems diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.4.0-test6/linux/arch/i386/kernel/apic.c Thu Jul 27 17:37:59 2000 +++ linux/arch/i386/kernel/apic.c Fri Aug 18 10:16:54 2000 @@ -7,7 +7,8 @@ * Maciej W. Rozycki : Bits for genuine 82489DX APICs; * thanks to Eric Gilmore * and Rolf G. Tews - * for testing these extensively + * for testing these extensively. + * Maciej W. Rozycki : Various updates and fixes. */ #include @@ -127,6 +128,67 @@ apic_write_around(APIC_SPIV, value); } +/* + * This is to verify that we're looking at a real local APIC. + * Check these against your board if the CPUs aren't getting + * started for no apparent reason. + */ +int __init verify_local_APIC(void) +{ + unsigned int reg0, reg1; + + /* + * The version register is read-only in a real APIC. + */ + reg0 = apic_read(APIC_LVR); + Dprintk("Getting VERSION: %x\n", reg0); + apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK); + reg1 = apic_read(APIC_LVR); + Dprintk("Getting VERSION: %x\n", reg1); + + /* + * The two version reads above should print the same + * numbers. If the second one is different, then we + * poke at a non-APIC. + */ + if (reg1 != reg0) + return 0; + + /* + * Check if the version looks reasonably. + */ + reg1 = GET_APIC_VERSION(reg0); + if (reg1 == 0x00 || reg1 == 0xff) + return 0; + reg1 = get_maxlvt(); + if (reg1 < 0x02 || reg1 == 0xff) + return 0; + + /* + * The ID register is read/write in a real APIC. + */ + reg0 = apic_read(APIC_ID); + Dprintk("Getting ID: %x\n", reg0); + apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); + reg1 = apic_read(APIC_ID); + Dprintk("Getting ID: %x\n", reg1); + apic_write(APIC_ID, reg0); + if (reg1 != (reg0 ^ APIC_ID_MASK)) + return 0; + + /* + * The next two are just to see if we have sane values. + * They're only really relevant if we're in Virtual Wire + * compatibility mode, but most boxes are anymore. + */ + reg0 = apic_read(APIC_LVT0); + Dprintk("Getting LVT0: %x\n", reg0); + reg1 = apic_read(APIC_LVT1); + Dprintk("Getting LVT1: %x\n", reg1); + + return 1; +} + void __init sync_Arb_IDs(void) { /* @@ -682,46 +744,28 @@ * This interrupt should never happen with our APIC/SMP architecture */ -static spinlock_t err_lock = SPIN_LOCK_UNLOCKED; - asmlinkage void smp_error_interrupt(void) { - unsigned long v; - - spin_lock(&err_lock); + unsigned long v, v1; + /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); - printk(KERN_INFO "APIC error interrupt on CPU#%d, should never happen.\n", - smp_processor_id()); - printk(KERN_INFO "... APIC ESR0: %08lx\n", v); - apic_write(APIC_ESR, 0); - v |= apic_read(APIC_ESR); - printk(KERN_INFO "... APIC ESR1: %08lx\n", v); - /* - * Be a bit more verbose. (multiple bits can be set) - */ - if (v & 0x01) - printk(KERN_INFO "... bit 0: APIC Send CS Error (hw problem).\n"); - if (v & 0x02) - printk(KERN_INFO "... bit 1: APIC Receive CS Error (hw problem).\n"); - if (v & 0x04) - printk(KERN_INFO "... bit 2: APIC Send Accept Error.\n"); - if (v & 0x08) - printk(KERN_INFO "... bit 3: APIC Receive Accept Error.\n"); - if (v & 0x10) - printk(KERN_INFO "... bit 4: Reserved!.\n"); - if (v & 0x20) - printk(KERN_INFO "... bit 5: Send Illegal Vector (kernel bug).\n"); - if (v & 0x40) - printk(KERN_INFO "... bit 6: Received Illegal Vector.\n"); - if (v & 0x80) - printk(KERN_INFO "... bit 7: Illegal Register Address.\n"); - + v1 = apic_read(APIC_ESR); ack_APIC_irq(); - irq_err_count++; - spin_unlock(&err_lock); + /* Here is what the APIC error bits mean: + 0: Send CS error + 1: Receive CS error + 2: Send accept error + 3: Receive accept error + 4: Reserved + 5: Send illegal vector + 6: Received illegal vector + 7: Illegal register address + */ + printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n", + smp_processor_id(), v , v1); } diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.4.0-test6/linux/arch/i386/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/i386/kernel/entry.S Fri Aug 11 14:38:31 2000 @@ -641,7 +641,8 @@ .long SYMBOL_NAME(sys_pivot_root) .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) - + .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_fcntl64) /* * NOTE!! This doesn't have to be exact - we just have @@ -649,6 +650,6 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-219 + .rept NR_syscalls-221 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.4.0-test6/linux/arch/i386/kernel/io_apic.c Wed Aug 9 19:19:49 2000 +++ linux/arch/i386/kernel/io_apic.c Mon Aug 21 08:57:35 2000 @@ -688,7 +688,7 @@ void __init UNEXPECTED_IO_APIC(void) { printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n"); - printk(KERN_WARNING " to linux-smp@vger.rutgers.edu\n"); + printk(KERN_WARNING " to linux-smp@vger.kernel.org\n"); } void __init print_IO_APIC(void) diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c --- v2.4.0-test6/linux/arch/i386/kernel/mca.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/mca.c Wed Aug 23 12:21:00 2000 @@ -15,7 +15,7 @@ * * Chris Beauregard August 9th, 1996 * - Rewrote /proc/mca - * + * * Chris Beauregard January 7th, 1997 * - Added basic NMI-processing * - Added more information to mca_info structure @@ -30,8 +30,11 @@ * - Fixed the output of 'Driver Installed' in /proc/mca/pos * - Made the Integrated Video & SCSI show up even if they have id 0000 * - * AV November 9th, 1999 - * - switched to regular procfs methods. + * Alexander Viro November 9th, 1999 + * - Switched to regular procfs methods + * + * Alfred Arnold & David Weinehall August 23rd, 2000 + * - Added support for Planar POS-registers */ #include @@ -50,9 +53,10 @@ #include #include -/* This structure holds MCA information. Each (plug-in) adapter has +/* This structure holds MCA information. Each (plug-in) adapter has * eight POS registers. Then the machine may have integrated video and * SCSI subsystems, which also have eight POS registers. + * Finally, the motherboard (planar) has got POS-registers. * Other miscellaneous information follows. */ @@ -92,7 +96,7 @@ /* The mca_info structure pointer. If MCA bus is present, the function * mca_probe() is invoked. The function puts motherboard, then all * adapters into setup mode, allocates and fills an MCA_info structure, - * and points this pointer to the structure. Otherwise the pointer + * and points this pointer to the structure. Otherwise the pointer * is set to zero. */ @@ -194,7 +198,7 @@ */ /* Make sure the MCA bus is present */ - + if(!MCA_bus) return; printk("Micro Channel bus detected.\n"); @@ -216,7 +220,16 @@ outb_p(0, MCA_ADAPTER_SETUP_REG); - /* Put motherboard into video setup mode, read integrated video + /* Read motherboard POS registers */ + + outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG); + mca_info->slot[MCA_MOTHERBOARD].name[0] = 0; + for(j=0; j<8; j++) { + mca_info->slot[MCA_MOTHERBOARD].pos[j] = inb_p(MCA_POS_REG(j)); + } + mca_configure_adapter_status(MCA_MOTHERBOARD); + + /* Put motherboard into video setup mode, read integrated video * POS registers, and turn motherboard setup off. */ @@ -242,7 +255,7 @@ outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG); mca_info->slot[MCA_INTEGSCSI].name[0] = 0; for(j=0; j<8; j++) { - if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff) + if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff) { /* 0xff all across means no device. 0x00 means * something's broken, but a device is probably there. @@ -256,17 +269,17 @@ mca_info->which_scsi = 0xf7; } } - if(!mca_info->which_scsi) { + if(!mca_info->which_scsi) { /* Didn't find it at 0xf7, try somewhere else... */ mca_info->which_scsi = 0xfd; outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG); - for(j=0; j<8; j++) + for(j=0; j<8; j++) mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j)); } mca_configure_adapter_status(MCA_INTEGSCSI); - + /* Turn off motherboard setup */ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); @@ -311,6 +324,9 @@ } else if(slot == MCA_INTEGVIDEO) { printk("NMI: caused by MCA integrated video adapter (%s)\n", mca_info->slot[slot].name); + } else if(slot == MCA_MOTHERBOARD) { + printk("NMI: caused by motherboard (%s)\n", + mca_info->slot[slot].name); } /* More info available in POS 6 and 7? */ @@ -375,7 +391,7 @@ * * Disabled adapters are not reported. */ - + int mca_find_adapter(int id, int start) { if(mca_info == NULL || id == 0xffff) { @@ -423,7 +439,7 @@ * to scan for further cards when some may already be driven. */ -int mca_find_unused_adapter(int id, int start) +int mca_find_unused_adapter(int id, int start) { if(mca_info == NULL || id == 0xffff) { return MCA_NOTFOUND; @@ -450,7 +466,7 @@ } return MCA_NOTFOUND; -} /* mca_find_unused_adapter() */ +} /* mca_find_unused_adapter() */ EXPORT_SYMBOL(mca_find_unused_adapter); @@ -465,8 +481,8 @@ * when it scanned the MCA space. The register value is returned. * Missing or invalid registers report 0. */ - -unsigned char mca_read_stored_pos(int slot, int reg) + +unsigned char mca_read_stored_pos(int slot, int reg) { if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0; if(reg < 0 || reg >= 8) return 0; @@ -487,9 +503,8 @@ * may not be invoked from interrupt context. It handles the * deep magic required for onboard devices transparently. */ - -unsigned char mca_read_pos(int slot, int reg) +unsigned char mca_read_pos(int slot, int reg) { unsigned int byte = 0; unsigned long flags; @@ -524,6 +539,14 @@ byte = inb_p(MCA_POS_REG(reg)); outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); + } else if(slot == MCA_MOTHERBOARD) { + + /* Disable adapter setup, enable motherboard setup */ + outb_p(0, MCA_ADAPTER_SETUP_REG); + outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG); + + byte = inb_p(MCA_POS_REG(reg)); + outp_b(0xff, MCA_MOTHERBOARD_SETUP_REG); } else if(slot < MCA_MAX_SLOT_NR) { /* Make sure motherboard setup is off */ @@ -556,7 +579,7 @@ * @reg: register to read from * @byte: byte to write to the POS registers * - * Store a POS value directly from the hardware. You should not + * Store a POS value directly from the hardware. You should not * normally need to use this function and should have a very good * knowledge of MCA bus before you do so. Doing this wrongly can * damage the hardware. @@ -574,7 +597,7 @@ * screws up. */ -void mca_write_pos(int slot, int reg, unsigned char byte) +void mca_write_pos(int slot, int reg, unsigned char byte) { unsigned long flags; @@ -615,11 +638,11 @@ * @name: text string for the namen * * This function sets the name reported via /proc for this - * adapter slot. This is for user information only. Setting a + * adapter slot. This is for user information only. Setting a * name deletes any previous name. */ - -void mca_set_adapter_name(int slot, char* name) + +void mca_set_adapter_name(int slot, char* name) { if(mca_info == NULL) return; @@ -640,7 +663,7 @@ /** * mca_set_adapter_procfn - Set the /proc callback * @slot: slot to configure - * @procfn: callback function to call for /proc + * @procfn: callback function to call for /proc * @dev: device information passed to the callback * * This sets up an information callback for /proc/mca/slot?. The @@ -648,7 +671,7 @@ * some equally informative context information, or nothing, if you * prefer), and is expected to put useful information into the * buffer. The adapter name, ID, and POS registers get printed - * before this is called though, so don't do it again. + * before this is called though, so don't do it again. * * This should be called with a %NULL @procfn when a module * unregisters, thus preventing kernel crashes and other such @@ -722,8 +745,8 @@ * Return the adapter description if set. If it has not been * set or the slot is out range then return NULL. */ - -char *mca_get_adapter_name(int slot) + +char *mca_get_adapter_name(int slot) { if(mca_info == NULL) return 0; @@ -789,14 +812,12 @@ { int i, j, len = 0; - if(MCA_bus && mca_info != NULL) - { + if(MCA_bus && mca_info != NULL) { /* Format POS registers of eight MCA slots */ - for(i=0; islot[i].pos[j]); len += sprintf(page+len, " %s\n", mca_info->slot[i].name); } @@ -804,19 +825,26 @@ /* Format POS registers of integrated video subsystem */ len += sprintf(page+len, "Video : "); - for(j=0; j<8; j++) + for(j=0; j<8; j++) len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]); len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name); /* Format POS registers of integrated SCSI subsystem */ - + len += sprintf(page+len, "SCSI : "); for(j=0; j<8; j++) len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]); len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name); + + /* Format POS registers of motherboard */ + + len += sprintf(page+len, "Planar: "); + for(j=0; j<8; j++) + len += sprintf(page+len, "%02x ", mca_info->slot[MCA_MOTHERBOARD].pos[j]); + len += sprintf(page+len, " %s\n", mca_info->slot[MCA_MOTHERBOARD].name); } else { /* Leave it empty if MCA not detected - this should *never* - * happen! + * happen! */ } @@ -843,6 +871,8 @@ len += sprintf(buf+len, "Integrated SCSI Adapter\n"); } else if(slot == MCA_INTEGVIDEO) { len += sprintf(buf+len, "Integrated Video Adapter\n"); + } else if(slot == MCA_MOTHERBOARD) { + len += sprintf(buf+len, "Motherboard\n"); } if(p->name[0]) { @@ -932,6 +962,7 @@ if(i < MCA_MAX_SLOT_NR) sprintf(p->procname,"slot%d", i+1); else if(i == MCA_INTEGVIDEO) sprintf(p->procname,"video"); else if(i == MCA_INTEGSCSI) sprintf(p->procname,"scsi"); + else if(i == MCA_MOTHERBOARD) sprintf(p->procname,"planar"); if(!mca_isadapter(i)) continue; diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.4.0-test6/linux/arch/i386/kernel/microcode.c Wed Aug 9 19:19:49 2000 +++ linux/arch/i386/kernel/microcode.c Tue Aug 22 11:45:12 2000 @@ -67,7 +67,7 @@ static void do_update_one(void *); /* read()/write()/ioctl() are serialized on this */ -DECLARE_RWSEM(microcode_rwsem); +static DECLARE_RWSEM(microcode_rwsem); static struct microcode *microcode; /* array of 2048byte microcode blocks */ static unsigned int microcode_num; /* number of chunks in microcode */ diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c --- v2.4.0-test6/linux/arch/i386/kernel/mpparse.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/mpparse.c Mon Aug 21 08:57:35 2000 @@ -170,7 +170,7 @@ mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; } else { printk("Unknown bustype %s\n", str); - panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu"); + panic("cannot handle bus - mail to linux-smp@vger.kernel.org"); } } @@ -565,7 +565,7 @@ address <<= 4; smp_scan_config(address, 0x1000); if (smp_found_config) - printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n"); + printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); } #else diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.0-test6/linux/arch/i386/kernel/setup.c Thu Jul 27 17:37:59 2000 +++ linux/arch/i386/kernel/setup.c Wed Aug 23 09:51:45 2000 @@ -16,7 +16,7 @@ * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. * * IDT Winchip tweaks, misc clean ups. - * Dave Jones , August 1999 + * Dave Jones , August 1999 * * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * @@ -27,7 +27,7 @@ * David Parsons , July-August 1999 * * Cleaned up cache-detection code - * Dave Jones , October 1999 + * Dave Jones , October 1999 * * Added proper L2 cache detection for Coppermine * Dragan Stancevic , October 1999 @@ -38,7 +38,7 @@ * * Detection for Celeron coppermine, identify_cpu() overhauled, * and a few other clean ups. - * Dave Jones , April 2000 + * Dave Jones , April 2000 * * Pentium III FXSR, SSE support * General FPU state handling cleanups @@ -48,6 +48,9 @@ * and 8-way type cache happy bunch from Intel:^) * Dragan Stancevic , May 2000 * + * Forward port AMD Duron errata T13 from 2.2.17pre + * Dave Jones , August 2000 + * */ /* @@ -380,8 +383,8 @@ } } -void __init add_memory_region(unsigned long start, - unsigned long size, int type) +void __init add_memory_region(unsigned long long start, + unsigned long long size, int type) { int x = e820.nr_map; @@ -398,12 +401,12 @@ #define E820_DEBUG 1 -static void __init print_e820_map(void) +static void __init print_memory_map(char *who) { int i; for (i = 0; i < e820.nr_map; i++) { - printk(" e820: %016Lx @ %016Lx ", + printk(" %s: %016Lx @ %016Lx ", who, e820.map[i].size, e820.map[i].addr); switch (e820.map[i].type) { case E820_RAM: printk("(usable)\n"); @@ -449,7 +452,7 @@ unsigned long long start = biosmap->addr; unsigned long long size = biosmap->size; unsigned long long end = start + size; - long type = biosmap->type; + unsigned long type = biosmap->type; /* Overflow in 64 bits? Ignore the memory map. */ if (start > end) @@ -460,12 +463,12 @@ * Not right. Fix it up. */ if (type == E820_RAM) { - if (start < 0x100000 && end > 0xA0000) { - if (start < 0xA0000) - add_memory_region(start, 0xA0000-start, type); - if (end < 0x100000) + if (start < 0x100000ULL && end > 0xA0000ULL) { + if (start < 0xA0000ULL) + add_memory_region(start, 0xA0000ULL-start, type); + if (end < 0x100000ULL) continue; - start = 0x100000; + start = 0x100000ULL; size = end - start; } } @@ -482,6 +485,8 @@ void __init setup_memory_region(void) { + char *who = "BIOS-e820"; + /* * Try to copy the BIOS-supplied E820-map. * @@ -491,14 +496,21 @@ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { unsigned long mem_size; - mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K; + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } e820.nr_map = 0; add_memory_region(0, LOWMEMSIZE(), E820_RAM); add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); } printk("BIOS-provided physical RAM map:\n"); - print_e820_map(); + print_memory_map(who); } /* setup_memory_region */ @@ -568,7 +580,7 @@ *cmdline_p = command_line; if (usermem) { printk("user-defined physical RAM map:\n"); - print_e820_map(); + print_memory_map("user"); } } @@ -925,7 +937,7 @@ break; } break; - case 6: /* An Athlon. We can trust the BIOS probably */ + case 6: /* An Athlon/Duron. We can trust the BIOS probably */ break; } @@ -936,10 +948,19 @@ edx>>24, ecx>>24, edx&0xFF); c->x86_cache_size=(ecx>>24)+(edx>>24); } - if (n >= 0x80000006) { - cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); - printk("CPU: L2 Cache: %dK\n", ecx>>16); - c->x86_cache_size=(ecx>>16); + + /* AMD errata T13 (order #21922) */ + if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 3 && + boot_cpu_data.x86_mask == 0) + { + c->x86_cache_size = 64; + printk("CPU: L2 Cache: 64K\n"); + } else { + if (n >= 0x80000006) { + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + printk("CPU: L2 Cache: %dK\n", ecx>>16); + c->x86_cache_size=(ecx>>16); + } } return r; @@ -1538,7 +1559,7 @@ if(c->x86_vendor == X86_VENDOR_NEXGEN) c->x86_cache_size = 256; /* A few had 1Mb.. */ - + for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) { if (cpu_models[i].vendor == c->x86_vendor && cpu_models[i].x86 == c->x86) { @@ -1570,8 +1591,8 @@ cyrix_model(&boot_cpu_data); } - - + + static char *cpu_vendor_names[] __initdata = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; diff -u --recursive --new-file v2.4.0-test6/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.4.0-test6/linux/arch/i386/kernel/smpboot.c Fri Jun 23 21:55:07 2000 +++ linux/arch/i386/kernel/smpboot.c Fri Aug 18 09:30:51 2000 @@ -883,39 +883,18 @@ phys_cpu_present_map |= (1 << hard_smp_processor_id()); } - { - int reg; - - /* - * This is to verify that we're looking at - * a real local APIC. Check these against - * your board if the CPUs aren't getting - * started for no apparent reason. - */ - - reg = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg); - - apic_write(APIC_LVR, 0); - reg = apic_read(APIC_LVR); - Dprintk("Getting VERSION: %x\n", reg); - - /* - * The two version reads above should print the same - * NON-ZERO!!! numbers. If the second one is zero, - * there is a problem with the APIC write/read - * definitions. - * - * The next two are just to see if we have sane values. - * They're only really relevant if we're in Virtual Wire - * compatibility mode, but most boxes are anymore. - */ - - reg = apic_read(APIC_LVT0); - Dprintk("Getting LVT0: %x\n", reg); - - reg = apic_read(APIC_LVT1); - Dprintk("Getting LVT1: %x\n", reg); + /* + * If we couldn't find a local APIC, then get out of here now! + */ + if (!verify_local_APIC()) { + printk(KERN_ERR "BIOS bug, local APIC at 0x%lX not detected!...\n", mp_lapic_addr); + printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); +#ifndef CONFIG_VISWS + io_apic_irqs = 0; +#endif + cpu_online_map = phys_cpu_present_map = 1; + smp_num_cpus = 1; + goto smp_done; } /* diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.0-test6/linux/arch/ia64/config.in Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/config.in Tue Aug 22 11:41:14 2000 @@ -18,15 +18,16 @@ comment 'General setup' define_bool CONFIG_IA64 y +define_bool CONFIG_SWIOTLB y # for now... define_bool CONFIG_ISA n define_bool CONFIG_SBUS n choice 'IA-64 system type' \ - "Generic CONFIG_IA64_GENERIC \ + "generic CONFIG_IA64_GENERIC \ + DIG-compliant CONFIG_IA64_DIG \ HP-simulator CONFIG_IA64_HP_SIM \ - SN1-simulator CONFIG_IA64_SGI_SN1_SIM \ - DIG-compliant CONFIG_IA64_DIG" Generic + SN1-simulator CONFIG_IA64_SGI_SN1_SIM" generic choice 'Kernel page size' \ "4KB CONFIG_IA64_PAGE_SIZE_4KB \ @@ -38,16 +39,18 @@ define_bool CONFIG_ITANIUM y define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC - bool ' Enable Itanium A1-step specific code' CONFIG_ITANIUM_A1_SPECIFIC + if [ "$CONFIG_ITANIUM_ASTEP_SPECIFIC" = "y" ]; then + bool ' Enable Itanium A1-step specific code' CONFIG_ITANIUM_A1_SPECIFIC + fi + bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC + if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then + bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC + fi + bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS - bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU - bool ' Enable IA64 Machine Check Abort' CONFIG_IA64_MCA -fi - -if [ "$CONFIG_IA64_GENERIC" = "y" ]; then - define_bool CONFIG_IA64_SOFTSDV_HACKS y + bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA fi if [ "$CONFIG_IA64_SGI_SN1_SIM" = "y" ]; then @@ -59,7 +62,7 @@ bool 'SMP support' CONFIG_SMP bool 'Performance monitor support' CONFIG_PERFMON -bool '/proc/palinfo support' CONFIG_IA64_PALINFO +bool '/proc/pal support' CONFIG_IA64_PALINFO bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -161,9 +164,9 @@ #source drivers/misc/Config.in -source fs/Config.in +source drivers/media/Config.in -source fs/nls/Config.in +source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment @@ -188,6 +191,7 @@ endmenu source drivers/usb/Config.in +source drivers/input/Config.in fi # !HP_SIM diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/dig/iosapic.c linux/arch/ia64/dig/iosapic.c --- v2.4.0-test6/linux/arch/ia64/dig/iosapic.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/dig/iosapic.c Fri Aug 11 19:09:06 2000 @@ -22,12 +22,14 @@ #include #include +#include +#include #include #include +#include +#include #include #include -#include -#include #undef DEBUG_IRQ_ROUTING @@ -315,10 +317,6 @@ */ outb(0xff, 0xA1); outb(0xff, 0x21); - -#ifndef CONFIG_IA64_DIG - iosapic_init(IO_SAPIC_DEFAULT_ADDR); -#endif } void @@ -337,15 +335,23 @@ if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ struct pci_dev * bridge = dev->bus->self; - /* do the bridge swizzle... */ - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - irq = iosapic_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin); + /* allow for multiple bridges on an adapter */ + do { + /* do the bridge swizzle... */ + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = iosapic_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + } while (irq < 0 && (bridge = bridge->bus->self)); if (irq >= 0) printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %02x\n", bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); + else + printk(KERN_WARNING + "PCI: Couldn't map irq for B%d,I%d,P%d\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), + pin); } if (irq >= 0) { printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %02x\n", @@ -360,4 +366,35 @@ if (dev->irq >= NR_IRQS) dev->irq = 15; /* Spurious interrupts */ } +} + +/* + * Register an IOSAPIC discovered via ACPI. + */ +void __init +dig_register_iosapic (acpi_entry_iosapic_t *iosapic) +{ + unsigned int ver, v; + int l, max_pin; + + ver = iosapic_version(iosapic->address); + max_pin = (ver >> 16) & 0xff; + + printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", + (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, + iosapic->irq_base, iosapic->irq_base + max_pin); + + for (l = 0; l <= max_pin; l++) { + v = iosapic->irq_base + l; + if (v < 16) + v = isa_irq_to_vector(v); + if (v > IA64_MAX_VECTORED_IRQ) { + printk(" !!! bad IOSAPIC interrupt vector: %u\n", v); + continue; + } + /* XXX Check for IOSAPIC collisions */ + iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); + iosapic_baseirq(v) = iosapic->irq_base; + } + iosapic_init(iosapic->address, iosapic->irq_base); } diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/dig/machvec.c linux/arch/ia64/dig/machvec.c --- v2.4.0-test6/linux/arch/ia64/dig/machvec.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/dig/machvec.c Fri Aug 11 19:09:06 2000 @@ -1,4 +1,2 @@ +#define MACHVEC_PLATFORM_NAME dig #include -#include - -MACHVEC_DEFINE(dig) diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c --- v2.4.0-test6/linux/arch/ia64/dig/setup.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/dig/setup.c Fri Aug 11 19:09:06 2000 @@ -24,10 +24,6 @@ #include #include -#ifdef CONFIG_IA64_FW_EMU -# include "../../kernel/fw-emu.c" -#endif - /* * This is here so we can use the CMOS detection in ide-probe.c to * determine what drives are present. In theory, we don't need this diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/hp/hpsim_machvec.c linux/arch/ia64/hp/hpsim_machvec.c --- v2.4.0-test6/linux/arch/ia64/hp/hpsim_machvec.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/hp/hpsim_machvec.c Fri Aug 11 19:09:06 2000 @@ -1,4 +1,2 @@ +#define MACHVEC_PLATFORM_NAME hpsim #include -#include - -MACHVEC_DEFINE(hpsim) diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.4.0-test6/linux/arch/ia64/ia32/ia32_entry.S Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/ia32/ia32_entry.S Fri Aug 11 19:09:06 2000 @@ -73,7 +73,7 @@ END(ia32_trace_syscall) GLOBAL_ENTRY(sys32_vfork) - alloc r16=ar.pfs,2,2,3,0;; + alloc r16=ar.pfs,2,2,4,0;; mov out0=IA64_CLONE_VFORK|IA64_CLONE_VM|SIGCHLD // out0 = clone_flags br.cond.sptk.few .fork1 // do the work END(sys32_vfork) @@ -105,7 +105,7 @@ .align 8 .globl ia32_syscall_table ia32_syscall_table: - data8 sys_ni_syscall /* 0 - old "setup(" system call*/ + data8 sys32_ni_syscall /* 0 - old "setup(" system call*/ data8 sys_exit data8 sys32_fork data8 sys_read @@ -122,25 +122,25 @@ data8 sys_mknod data8 sys_chmod /* 15 */ data8 sys_lchown - data8 sys_ni_syscall /* old break syscall holder */ - data8 sys_ni_syscall + data8 sys32_ni_syscall /* old break syscall holder */ + data8 sys32_ni_syscall data8 sys_lseek data8 sys_getpid /* 20 */ data8 sys_mount data8 sys_oldumount data8 sys_setuid data8 sys_getuid - data8 sys_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ + data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm - data8 sys_ni_syscall - data8 sys_ni_syscall + data8 sys32_ni_syscall + data8 sys32_ni_syscall data8 ia32_utime /* 30 */ - data8 sys_ni_syscall /* old stty syscall holder */ - data8 sys_ni_syscall /* old gtty syscall holder */ + data8 sys32_ni_syscall /* old stty syscall holder */ + data8 sys32_ni_syscall /* old gtty syscall holder */ data8 sys_access data8 sys_nice - data8 sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + data8 sys32_ni_syscall /* 35 */ /* old ftime syscall holder */ data8 sys_sync data8 sys_kill data8 sys_rename @@ -149,22 +149,22 @@ data8 sys_dup data8 sys32_pipe data8 sys32_times - data8 sys_ni_syscall /* old prof syscall holder */ + data8 sys32_ni_syscall /* old prof syscall holder */ data8 sys_brk /* 45 */ data8 sys_setgid data8 sys_getgid - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_geteuid data8 sys_getegid /* 50 */ data8 sys_acct data8 sys_umount /* recycled never used phys( */ - data8 sys_ni_syscall /* old lock syscall holder */ + data8 sys32_ni_syscall /* old lock syscall holder */ data8 ia32_ioctl - data8 sys_fcntl /* 55 */ - data8 sys_ni_syscall /* old mpx syscall holder */ + data8 sys32_fcntl /* 55 */ + data8 sys32_ni_syscall /* old mpx syscall holder */ data8 sys_setpgid - data8 sys_ni_syscall /* old ulimit syscall holder */ - data8 sys_ni_syscall + data8 sys32_ni_syscall /* old ulimit syscall holder */ + data8 sys32_ni_syscall data8 sys_umask /* 60 */ data8 sys_chroot data8 sys_ustat @@ -172,12 +172,12 @@ data8 sys_getppid data8 sys_getpgrp /* 65 */ data8 sys_setsid - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall + data8 sys32_sigaction + data8 sys32_ni_syscall + data8 sys32_ni_syscall data8 sys_setreuid /* 70 */ data8 sys_setregid - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_sigpending data8 sys_sethostname data8 sys32_setrlimit /* 75 */ @@ -189,7 +189,7 @@ data8 sys_setgroups data8 old_select data8 sys_symlink - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_readlink /* 85 */ data8 sys_uselib data8 sys_swapon @@ -203,7 +203,7 @@ data8 sys_fchown /* 95 */ data8 sys_getpriority data8 sys_setpriority - data8 sys_ni_syscall /* old profil syscall holder */ + data8 sys32_ni_syscall /* old profil syscall holder */ data8 sys32_statfs data8 sys32_fstatfs /* 100 */ data8 sys_ioperm @@ -214,11 +214,11 @@ data8 sys32_newstat data8 sys32_newlstat data8 sys32_newfstat - data8 sys_ni_syscall + data8 sys32_ni_syscall data8 sys_iopl /* 110 */ data8 sys_vhangup - data8 sys_ni_syscall // used to be sys_idle - data8 sys_ni_syscall + data8 sys32_ni_syscall // used to be sys_idle + data8 sys32_ni_syscall data8 sys32_wait4 data8 sys_swapoff /* 115 */ data8 sys_sysinfo @@ -242,7 +242,7 @@ data8 sys_bdflush data8 sys_sysfs /* 135 */ data8 sys_personality - data8 sys_ni_syscall /* for afs_syscall */ + data8 sys32_ni_syscall /* for afs_syscall */ data8 sys_setfsuid data8 sys_setfsgid data8 sys_llseek /* 140 */ @@ -293,8 +293,8 @@ data8 sys_capset /* 185 */ data8 sys_sigaltstack data8 sys_sendfile - data8 sys_ni_syscall /* streams1 */ - data8 sys_ni_syscall /* streams2 */ + data8 sys32_ni_syscall /* streams1 */ + data8 sys32_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ /* * CAUTION: If any system calls are added beyond this point diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.0-test6/linux/arch/ia64/ia32/sys_ia32.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/ia32/sys_ia32.c Fri Aug 11 19:09:06 2000 @@ -74,10 +74,14 @@ n = 0; do { - if ((err = get_user(addr, (int *)A(arg))) != 0) - return(err); - if (ap) - *ap++ = (char *)A(addr); + err = get_user(addr, (int *)A(arg)); + if (IS_ERR(err)) + return err; + if (ap) { /* no access_ok needed, we allocated */ + err = __put_user((char *)A(addr), ap++); + if (IS_ERR(err)) + return err; + } arg += sizeof(unsigned int); n++; } while (addr); @@ -101,7 +105,11 @@ int na, ne, r, len; na = nargs(argv, NULL); + if (IS_ERR(na)) + return(na); ne = nargs(envp, NULL); + if (IS_ERR(ne)) + return(ne); len = (na + ne + 2) * sizeof(*av); /* * kmalloc won't work because the `sys_exec' code will attempt @@ -121,12 +129,21 @@ if (IS_ERR(av)) return (long)av; ae = av + na + 1; - av[na] = (char *)0; - ae[ne] = (char *)0; - (void)nargs(argv, av); - (void)nargs(envp, ae); + r = __put_user(0, (av + na)); + if (IS_ERR(r)) + goto out; + r = __put_user(0, (ae + ne)); + if (IS_ERR(r)) + goto out; + r = nargs(argv, av); + if (IS_ERR(r)) + goto out; + r = nargs(envp, ae); + if (IS_ERR(r)) + goto out; r = sys_execve(filename, av, ae, regs); if (IS_ERR(r)) +out: sys_munmap((unsigned long) av, len); return(r); } @@ -711,7 +728,8 @@ }; static int -filldir32 (void *__buf, const char *name, int namlen, off_t offset, ino_t ino) +filldir32 (void *__buf, const char *name, int namlen, off_t offset, ino_t ino, + unsigned int d_type) { struct linux32_dirent * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; @@ -959,150 +977,85 @@ } struct iovec32 { unsigned int iov_base; int iov_len; }; +asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long); +asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long); -typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *); - -static long -do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, - u32 count) +static struct iovec * +get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) { - unsigned long tot_len; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov=iovstack, *ivp; - struct inode *inode; - long retval, i; - IO_fn_t fn; + int i; + u32 buf, len; + struct iovec *ivp, *iov; + + /* Get the "struct iovec" from user memory */ - /* First get the "struct iovec" from user memory and - * verify all the pointers - */ if (!count) return 0; - if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) - return -EFAULT; + if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) + return(struct iovec *)0; if (count > UIO_MAXIOV) - return -EINVAL; + return(struct iovec *)0; if (count > UIO_FASTIOV) { iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) - return -ENOMEM; - } + return((struct iovec *)0); + } else + iov = iov_buf; - tot_len = 0; - i = count; ivp = iov; - while(i > 0) { - u32 len; - u32 buf; - - __get_user(len, &vector->iov_len); - __get_user(buf, &vector->iov_base); - tot_len += len; + for (i = 0; i < count; i++) { + if (__get_user(len, &iov32->iov_len) || + __get_user(buf, &iov32->iov_base)) { + if (iov != iov_buf) + kfree(iov); + return((struct iovec *)0); + } + if (verify_area(type, (void *)A(buf), len)) { + if (iov != iov_buf) + kfree(iov); + return((struct iovec *)0); + } ivp->iov_base = (void *)A(buf); - ivp->iov_len = (__kernel_size_t) len; - vector++; - ivp++; - i--; - } - - inode = file->f_dentry->d_inode; - /* VERIFY_WRITE actually means a read, as we write to user space */ - retval = locks_verify_area((type == VERIFY_WRITE - ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), - inode, file, file->f_pos, tot_len); - if (retval) { - if (iov != iovstack) - kfree(iov); - return retval; - } - - /* Then do the actual IO. Note that sockets need to be handled - * specially as they have atomicity guarantees and can handle - * iovec's natively - */ - if (inode->i_sock) { - int err; - err = sock_readv_writev(type, inode, file, iov, count, tot_len); - if (iov != iovstack) - kfree(iov); - return err; - } - - if (!file->f_op) { - if (iov != iovstack) - kfree(iov); - return -EINVAL; - } - /* VERIFY_WRITE actually means a read, as we write to user space */ - fn = file->f_op->read; - if (type == VERIFY_READ) - fn = (IO_fn_t) file->f_op->write; - ivp = iov; - while (count > 0) { - void * base; - int len, nr; - - base = ivp->iov_base; - len = ivp->iov_len; + ivp->iov_len = (__kernel_size_t)len; + iov32++; ivp++; - count--; - nr = fn(file, base, len, &file->f_pos); - if (nr < 0) { - if (retval) - break; - retval = nr; - break; - } - retval += nr; - if (nr != len) - break; } - if (iov != iovstack) - kfree(iov); - return retval; + return(iov); } asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count) { - struct file *file; - long ret = -EBADF; - - file = fget(fd); - if(!file) - goto bad_file; - - if(!(file->f_mode & 1)) - goto out; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov; + int ret; + mm_segment_t old_fs = get_fs(); - ret = do_readv_writev32(VERIFY_WRITE, file, - vector, count); -out: - fput(file); -bad_file: + if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_readv(fd, iov, count); + set_fs(old_fs); + if (iov != iovstack) + kfree(iov); return ret; } asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count) { - struct file *file; - int ret = -EBADF; - - file = fget(fd); - if(!file) - goto bad_file; - - if(!(file->f_mode & 2)) - goto out; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov; + int ret; + mm_segment_t old_fs = get_fs(); - down(&file->f_dentry->d_inode->i_sem); - ret = do_readv_writev32(VERIFY_READ, file, - vector, count); - up(&file->f_dentry->d_inode->i_sem); -out: - fput(file); -bad_file: + if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_writev(fd, iov, count); + set_fs(old_fs); + if (iov != iovstack) + kfree(iov); return ret; } @@ -1173,21 +1126,22 @@ static inline int shape_msg(struct msghdr *mp, struct msghdr32 *mp32) { + int ret; unsigned int i; if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) return(-EFAULT); - __get_user(i, &mp32->msg_name); + ret = __get_user(i, &mp32->msg_name); mp->msg_name = (void *)A(i); - __get_user(mp->msg_namelen, &mp32->msg_namelen); - __get_user(i, &mp32->msg_iov); + ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); + ret |= __get_user(i, &mp32->msg_iov); mp->msg_iov = (struct iovec *)A(i); - __get_user(mp->msg_iovlen, &mp32->msg_iovlen); - __get_user(i, &mp32->msg_control); + ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen); + ret |= __get_user(i, &mp32->msg_control); mp->msg_control = (void *)A(i); - __get_user(mp->msg_controllen, &mp32->msg_controllen); - __get_user(mp->msg_flags, &mp32->msg_flags); - return(0); + ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen); + ret |= __get_user(mp->msg_flags, &mp32->msg_flags); + return(ret ? -EFAULT : 0); } /* @@ -2341,17 +2295,17 @@ { struct switch_stack *swp; struct pt_regs *ptp; - int i, tos; + int i, tos, ret; int fsrlo, fsrhi; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EIO); - __get_user(tsk->thread.fcr, (unsigned int *)&save->cw); - __get_user(fsrlo, (unsigned int *)&save->sw); - __get_user(fsrhi, (unsigned int *)&save->tag); + ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw); + ret |= __get_user(fsrlo, (unsigned int *)&save->sw); + ret |= __get_user(fsrhi, (unsigned int *)&save->tag); tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo; - __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff); - __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff); + ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff); + ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff); /* * Stack frames start with 16-bytes of temp space */ @@ -2360,7 +2314,7 @@ tos = (tsk->thread.fsr >> 11) & 3; for (i = 0; i < 8; i++) get_fpreg(i, &save->_st[i], ptp, swp, tos); - return(0); + return(ret ? -EFAULT : 0); } asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long); @@ -2492,6 +2446,105 @@ return ret; } +static inline int +get_flock32(struct flock *kfl, struct flock32 *ufl) +{ + int err; + + err = get_user(kfl->l_type, &ufl->l_type); + err |= __get_user(kfl->l_whence, &ufl->l_whence); + err |= __get_user(kfl->l_start, &ufl->l_start); + err |= __get_user(kfl->l_len, &ufl->l_len); + err |= __get_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +static inline int +put_flock32(struct flock *kfl, struct flock32 *ufl) +{ + int err; + + err = __put_user(kfl->l_type, &ufl->l_type); + err |= __put_user(kfl->l_whence, &ufl->l_whence); + err |= __put_user(kfl->l_start, &ufl->l_start); + err |= __put_user(kfl->l_len, &ufl->l_len); + err |= __put_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, + unsigned long arg); + +asmlinkage long +sys32_fcntl(unsigned int fd, unsigned int cmd, int arg) +{ + struct flock f; + mm_segment_t old_fs; + long ret; + + switch (cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + if(cmd != F_GETLK && get_flock32(&f, (struct flock32 *)((long)arg))) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long)&f); + set_fs(old_fs); + if(cmd == F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg))) + return -EFAULT; + return ret; + default: + /* + * `sys_fcntl' lies about arg, for the F_SETOWN + * sub-function arg can have a negative value. + */ + return sys_fcntl(fd, cmd, (unsigned long)((long)arg)); + } +} + +asmlinkage long +sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset32_t mask; + + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= __get_user(mask, &act->sa_mask); + if (ret) + return ret; + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage long sys_ni_syscall(void); + +asmlinkage long +sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, + int dummy4, int dummy5, int dummy6, int dummy7, int stack) +{ + struct pt_regs *regs = (struct pt_regs *)&stack; + + printk("IA32 syscall #%d issued, maybe we should implement it\n", + (int)regs->r1); + return(sys_ni_syscall()); +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional @@ -2545,61 +2598,6 @@ return sys_ioperm((unsigned long)from, (unsigned long)num, on); } -static inline int -get_flock(struct flock *kfl, struct flock32 *ufl) -{ - int err; - - err = get_user(kfl->l_type, &ufl->l_type); - err |= __get_user(kfl->l_whence, &ufl->l_whence); - err |= __get_user(kfl->l_start, &ufl->l_start); - err |= __get_user(kfl->l_len, &ufl->l_len); - err |= __get_user(kfl->l_pid, &ufl->l_pid); - return err; -} - -static inline int -put_flock(struct flock *kfl, struct flock32 *ufl) -{ - int err; - - err = __put_user(kfl->l_type, &ufl->l_type); - err |= __put_user(kfl->l_whence, &ufl->l_whence); - err |= __put_user(kfl->l_start, &ufl->l_start); - err |= __put_user(kfl->l_len, &ufl->l_len); - err |= __put_user(kfl->l_pid, &ufl->l_pid); - return err; -} - -extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, - unsigned long arg); - -asmlinkage long -sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - { - struct flock f; - mm_segment_t old_fs; - long ret; - - if(get_flock(&f, (struct flock32 *)arg)) - return -EFAULT; - old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_fcntl(fd, cmd, (unsigned long)&f); - set_fs (old_fs); - if(put_flock(&f, (struct flock32 *)arg)) - return -EFAULT; - return ret; - } - default: - return sys_fcntl(fd, cmd, (unsigned long)arg); - } -} - struct dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; @@ -3861,40 +3859,6 @@ } extern void check_pending(int signum); - -asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 *act, - struct old_sigaction32 *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if(sig < 0) { - current->tss.new_signal = 1; - sig = -sig; - } - - if (act) { - old_sigset_t32 mask; - - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - ret |= __get_user(mask, &act->sa_mask); - if (ret) - return ret; - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} #ifdef CONFIG_MODULES diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.4.0-test6/linux/arch/ia64/kernel/Makefile Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/Makefile Fri Aug 11 19:09:06 2000 @@ -9,8 +9,8 @@ all: kernel.o head.o init_task.o -obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ - pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ +obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt.o \ + machvec.o pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o obj-$(CONFIG_IA64_GENERIC) += machvec.o diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.4.0-test6/linux/arch/ia64/kernel/acpi.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/kernel/acpi.c Fri Aug 11 19:09:06 2000 @@ -19,10 +19,11 @@ #include #include -#include #include #include #include +#include +#include #undef ACPI_DEBUG /* Guess what this does? */ @@ -75,47 +76,6 @@ } /* - * Find all IOSAPICs and tag the iosapic_vector structure with the appropriate - * base addresses. - */ -static void __init -acpi_iosapic(char *p) -{ - /* - * This is not good. ACPI is not necessarily limited to CONFIG_IA64_SV, yet - * ACPI does not necessarily imply IOSAPIC either. Perhaps there should be - * a means for platform_setup() to register ACPI handlers? - */ -#ifdef CONFIG_IA64_DIG - acpi_entry_iosapic_t *iosapic = (acpi_entry_iosapic_t *) p; - unsigned int ver, v; - int l, max_pin; - - ver = iosapic_version(iosapic->address); - max_pin = (ver >> 16) & 0xff; - - printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", - (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, - iosapic->irq_base, iosapic->irq_base + max_pin); - - for (l = 0; l <= max_pin; l++) { - v = iosapic->irq_base + l; - if (v < 16) - v = isa_irq_to_vector(v); - if (v > IA64_MAX_VECTORED_IRQ) { - printk(" !!! bad IOSAPIC interrupt vector: %u\n", v); - continue; - } - /* XXX Check for IOSAPIC collisions */ - iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); - iosapic_baseirq(v) = iosapic->irq_base; - } - iosapic_init(iosapic->address, iosapic->irq_base); -#endif -} - - -/* * Configure legacy IRQ information in iosapic_vector */ static void __init @@ -227,7 +187,7 @@ break; case ACPI_ENTRY_IO_SAPIC: - acpi_iosapic(p); + platform_register_iosapic((acpi_entry_iosapic_t *) p); break; case ACPI_ENTRY_INT_SRC_OVERRIDE: diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.4.0-test6/linux/arch/ia64/kernel/efi.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/kernel/efi.c Fri Aug 11 19:09:06 2000 @@ -33,9 +33,10 @@ extern efi_status_t efi_call_phys (void *, ...); struct efi efi; - static efi_runtime_services_t *runtime; +static unsigned long mem_limit = ~0UL; + static efi_status_t phys_get_time (efi_time_t *tm, efi_time_cap_t *tc) { @@ -169,15 +170,13 @@ case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: - if (md->phys_addr > 1024*1024*1024UL) { - printk("Warning: ignoring %luMB of memory above 1GB!\n", - md->num_pages >> 8); - md->type = EFI_UNUSABLE_MEMORY; - continue; - } - if (!(md->attribute & EFI_MEMORY_WB)) continue; + if (md->phys_addr + (md->num_pages << 12) > mem_limit) { + if (md->phys_addr > mem_limit) + continue; + md->num_pages = (mem_limit - md->phys_addr) >> 12; + } if (md->num_pages == 0) { printk("efi_memmap_walk: ignoring empty region at 0x%lx", md->phys_addr); @@ -224,8 +223,8 @@ * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor * Abstraction Layer chapter 11 in ADAG */ -static void -map_pal_code (void) +void +efi_map_pal_code (void) { void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; @@ -240,13 +239,14 @@ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - if (md->type != EFI_PAL_CODE) continue; + if (md->type != EFI_PAL_CODE) + continue; if (++pal_code_count > 1) { printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n", md->phys_addr); continue; - } + } mask = ~((1 << _PAGE_SIZE_4M)-1); /* XXX should be dynamic? */ vaddr = PAGE_OFFSET + md->phys_addr; @@ -281,9 +281,28 @@ efi_config_table_t *config_tables; efi_char16_t *c16; u64 efi_desc_size; - char vendor[100] = "unknown"; + char *cp, *end, vendor[100] = "unknown"; + extern char saved_command_line[]; int i; + /* it's too early to be able to use the standard kernel command line support... */ + for (cp = saved_command_line; *cp; ) { + if (memcmp(cp, "mem=", 4) == 0) { + cp += 4; + mem_limit = memparse(cp, &end) - 1; + if (end != cp) + break; + cp = end; + } else { + while (*cp != ' ' && *cp) + ++cp; + while (*cp == ' ') + ++cp; + } + } + if (mem_limit != ~0UL) + printk("Ignoring memory above %luMB\n", mem_limit >> 20); + efi.systab = __va(ia64_boot_param.efi_systab); /* @@ -359,7 +378,7 @@ } #endif - map_pal_code(); + efi_map_pal_code(); } void diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.0-test6/linux/arch/ia64/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/ia64/kernel/entry.S Fri Aug 11 19:09:06 2000 @@ -106,29 +106,19 @@ alloc r16=ar.pfs,1,0,0,0 DO_SAVE_SWITCH_STACK UNW(.body) - // disable interrupts to ensure atomicity for next few instructions: - mov r17=psr // M-unit - ;; - rsm psr.i // M-unit - dep r18=-1,r0,0,61 // build mask 0x1fffffffffffffff - ;; - srlz.d - ;; + adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 + dep r18=-1,r0,0,61 // build mask 0x1fffffffffffffff adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; st8 [r22]=sp // save kernel stack pointer of old task ld8 sp=[r21] // load kernel stack pointer of new task and r20=in0,r18 // physical address of "current" ;; + mov ar.k6=r20 // copy "current" into ar.k6 mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer - mov ar.k6=r20 // copy "current" into ar.k6 ;; - // restore interrupts - mov psr.l=r17 - ;; - srlz.d DO_LOAD_SWITCH_STACK( ) br.ret.sptk.few rp END(ia64_switch_to) @@ -1207,7 +1197,7 @@ data8 sys_newlstat data8 sys_newfstat data8 sys_clone2 - data8 ia64_ni_syscall + data8 sys_getdents64 data8 ia64_ni_syscall // 1215 data8 ia64_ni_syscall data8 ia64_ni_syscall diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.4.0-test6/linux/arch/ia64/kernel/head.S Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/head.S Fri Aug 11 19:09:06 2000 @@ -181,7 +181,9 @@ GLOBAL_ENTRY(ia64_load_debug_regs) alloc r16=ar.pfs,1,0,0,0 +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) lfetch.nta [in0] +#endif mov r20=ar.lc // preserve ar.lc add r19=IA64_NUM_DBG_REGS*8,in0 mov ar.lc=IA64_NUM_DBG_REGS-1 @@ -702,3 +704,74 @@ SET_REG(b5); #endif /* CONFIG_IA64_BRL_EMU */ + +#ifdef CONFIG_SMP + + /* + * This routine handles spinlock contention. It uses a simple exponential backoff + * algorithm to reduce unnecessary bus traffic. The initial delay is selected from + * the low-order bits of the cycle counter (a cheap "randomizer"). I'm sure this + * could use additional tuning, especially on systems with a large number of CPUs. + * Also, I think the maximum delay should be made a function of the number of CPUs in + * the system. --davidm 00/08/05 + * + * WARNING: This is not a normal procedure. It gets called from C code without + * the compiler knowing about it. Thus, we must not use any scratch registers + * beyond those that were declared "clobbered" at the call-site (see spin_lock() + * macro). We may not even use the stacked registers, because that could overwrite + * output registers. Similarly, we can't use the scratch stack area as it may be + * in use, too. + * + * Inputs: + * ar.ccv = 0 (and available for use) + * r28 = available for use + * r29 = available for use + * r30 = non-zero (and available for use) + * r31 = address of lock we're trying to acquire + * p15 = available for use + */ + +# define delay r28 +# define timeout r29 +# define tmp r30 + +GLOBAL_ENTRY(ia64_spinlock_contention) + mov tmp=ar.itc + ;; + and delay=0x3f,tmp + ;; + +.retry: add timeout=tmp,delay + shl delay=delay,1 + ;; + dep delay=delay,r0,0,13 // limit delay to 8192 cycles + ;; + // delay a little... +.wait: sub tmp=tmp,timeout + or delay=0xf,delay // make sure delay is non-zero (otherwise we get stuck with 0) + ;; + cmp.lt p15,p0=tmp,r0 + mov tmp=ar.itc +(p15) br.cond.sptk .wait + ;; + ld1 tmp=[r31] + ;; + cmp.ne p15,p0=tmp,r0 + mov tmp=ar.itc +(p15) br.cond.sptk.few .retry // lock is still busy + ;; + // try acquiring lock (we know ar.ccv is still zero!): + mov tmp=1 + ;; + IA64_SEMFIX_INSN + cmpxchg1.acq tmp=[r31],tmp,ar.ccv + ;; + cmp.eq p15,p0=tmp,r0 + + mov tmp=ar.itc +(p15) br.ret.sptk.many b7 // got lock -> return + br .retry // still no luck, retry + +END(ia64_spinlock_contention) + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c --- v2.4.0-test6/linux/arch/ia64/kernel/ia64_ksyms.c Wed Aug 9 19:19:49 2000 +++ linux/arch/ia64/kernel/ia64_ksyms.c Fri Aug 11 19:09:06 2000 @@ -18,6 +18,7 @@ EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); #include @@ -37,6 +38,7 @@ EXPORT_SYMBOL(kernel_thread); #ifdef CONFIG_SMP +#include EXPORT_SYMBOL(synchronize_irq); #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.4.0-test6/linux/arch/ia64/kernel/irq_ia64.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/kernel/irq_ia64.c Fri Aug 11 19:09:06 2000 @@ -117,6 +117,13 @@ { unsigned long bsp, sp; + /* + * Note: if the interrupt happened while executing in + * the context switch routine (ia64_switch_to), we may + * get a spurious stack overflow here. This is + * because the register and the memory stack are not + * switched atomically. + */ asm ("mov %0=ar.bsp" : "=r"(bsp)); asm ("mov %0=sp" : "=r"(sp)); diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.4.0-test6/linux/arch/ia64/kernel/ivt.S Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/ivt.S Fri Aug 11 19:09:06 2000 @@ -170,33 +170,27 @@ * The ITLB basically does the same as the VHPT handler except * that we always insert exactly one instruction TLB entry. */ -#if 1 /* * Attempt to lookup PTE through virtual linear page table. * The speculative access will fail if there is no TLB entry * for the L3 page table page we're trying to access. */ - mov r31=pr // save predicates - ;; - thash r17=r16 // compute virtual address of L3 PTE + mov r16=cr.iha // get virtual address of L3 PTE ;; - ld8.s r18=[r17] // try to read L3 PTE + ld8.s r16=[r16] // try to read L3 PTE + mov r31=pr // save predicates ;; - tnat.nz p6,p0=r18 // did read succeed? + tnat.nz p6,p0=r16 // did read succeed? (p6) br.cond.spnt.many 1f ;; - itc.i r18 + itc.i r16 ;; mov pr=r31,-1 rfi -1: rsm psr.dt // use physical addressing for data -#else - mov r16=cr.ifa // get address that caused the TLB miss +1: mov r16=cr.ifa // get address that caused the TLB miss ;; rsm psr.dt // use physical addressing for data -#endif - mov r31=pr // save the predicate registers mov r19=ar.k7 // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 @@ -244,33 +238,27 @@ * The DTLB basically does the same as the VHPT handler except * that we always insert exactly one data TLB entry. */ - mov r16=cr.ifa // get address that caused the TLB miss -#if 1 /* * Attempt to lookup PTE through virtual linear page table. * The speculative access will fail if there is no TLB entry * for the L3 page table page we're trying to access. */ - mov r31=pr // save predicates - ;; - thash r17=r16 // compute virtual address of L3 PTE + mov r16=cr.iha // get virtual address of L3 PTE ;; - ld8.s r18=[r17] // try to read L3 PTE + ld8.s r16=[r16] // try to read L3 PTE + mov r31=pr // save predicates ;; - tnat.nz p6,p0=r18 // did read succeed? + tnat.nz p6,p0=r16 // did read succeed? (p6) br.cond.spnt.many 1f ;; - itc.d r18 + itc.d r16 ;; mov pr=r31,-1 rfi -1: rsm psr.dt // use physical addressing for data -#else - rsm psr.dt // use physical addressing for data - mov r31=pr // save the predicate registers +1: mov r16=cr.ifa // get address that caused the TLB miss ;; -#endif + rsm psr.dt // use physical addressing for data mov r19=ar.k7 // get page table base address shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 @@ -504,7 +492,24 @@ mov r29=b0 // save b0 in case of nested fault) ;; 1: ld8 r18=[r17] - ;; // avoid raw on r18 +#if defined(CONFIG_IA32_SUPPORT) && \ + (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) + // + // Erratum 85 (Access bit fault could be reported before page not present fault) + // If the PTE is indicates the page is not present, then just turn this into a + // page fault. + // + mov r31=pr // save predicates + ;; + tbit.nz p6,p0=r18,0 // page present bit set? +(p6) br.cond.sptk 1f + ;; // avoid WAW on p6 + mov pr=r31,-1 + br.cond.sptk page_fault // page wasn't present +1: mov pr=r31,-1 +#else + ;; // avoid RAW on r18 +#endif or r18=_PAGE_A,r18 // set the accessed bit mov b0=r29 // restore b0 ;; @@ -541,14 +546,6 @@ ;; srlz.d // ensure everyone knows psr.dt is off... cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) -#if 1 - // Allow syscalls via the old system call number for the time being. This is - // so we can transition to the new syscall number in a relatively smooth - // fashion. - mov r17=0x80000 - ;; -(p7) cmp.eq.or.andcm p0,p7=r16,r17 // is this the old syscall number? -#endif (p7) br.cond.spnt.many non_syscall SAVE_MIN // uses r31; defines r2: diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/machvec.c linux/arch/ia64/kernel/machvec.c --- v2.4.0-test6/linux/arch/ia64/kernel/machvec.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/machvec.c Sun Aug 13 10:17:16 2000 @@ -1,14 +1,12 @@ +#include #include #include #include -struct ia64_machine_vector ia64_mv; +#ifdef CONFIG_IA64_GENERIC -void -machvec_noop (void) -{ -} +struct ia64_machine_vector ia64_mv; /* * Most platforms use this routine for mapping page frame addresses @@ -45,4 +43,11 @@ } ia64_mv = *mv; printk("booting generic kernel on platform %s\n", name); +} + +#endif /* CONFIG_IA64_GENERIC */ + +void +machvec_noop (void) +{ } diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/pal.S linux/arch/ia64/kernel/pal.S --- v2.4.0-test6/linux/arch/ia64/kernel/pal.S Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/pal.S Fri Aug 11 19:09:06 2000 @@ -191,3 +191,57 @@ srlz.d // seralize restoration of psr.l br.ret.sptk.few b0 END(ia64_pal_call_phys_static) + +/* + * Make a PAL call using the stacked registers in physical mode. + * + * Inputs: + * in0 Index of PAL service + * in2 - in3 Remaning PAL arguments + */ +GLOBAL_ENTRY(ia64_pal_call_phys_stacked) + UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)) + alloc loc1 = ar.pfs,5,5,86,0 + movl loc2 = pal_entry_point +1: { + mov r28 = in0 // copy procedure index + mov loc0 = rp // save rp + } + .body + ;; + ld8 loc2 = [loc2] // loc2 <- entry point + mov out0 = in0 // first argument + mov out1 = in1 // copy arg2 + mov out2 = in2 // copy arg3 + mov out3 = in3 // copy arg3 + ;; + mov loc3 = psr // save psr + ;; + mov loc4=ar.rsc // save RSE configuration + dep.z loc2=loc2,0,61 // convert pal entry point to physical + ;; + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + movl r16=PAL_PSR_BITS_TO_CLEAR + movl r17=PAL_PSR_BITS_TO_SET + ;; + or loc3=loc3,r17 // add in psr the bits to set + mov b7 = loc2 // install target to branch reg + ;; + andcm r16=loc3,r16 // removes bits to clear from psr + br.call.sptk.few rp=ia64_switch_mode +.ret6: + br.call.sptk.many rp=b7 // now make the call +.ret7: + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov r16=loc3 // r16= original psr + br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + +.ret8: mov psr.l = loc3 // restore init PSR + mov ar.pfs = loc1 + mov rp = loc0 + ;; + mov ar.rsc=loc4 // restore RSE configuration + srlz.d // seralize restoration of psr.l + br.ret.sptk.few b0 +END(ia64_pal_call_phys_stacked) + diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c --- v2.4.0-test6/linux/arch/ia64/kernel/palinfo.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/kernel/palinfo.c Sun Aug 13 10:17:16 2000 @@ -16,24 +16,41 @@ * are empty for now. * - remove hack to avoid problem with <= 256M RAM for itr. */ +#include #include #include #include #include #include +#include +#if defined(MODVERSIONS) +#include +#endif #include #include #include #include #include +#ifdef CONFIG_SMP +#include +#endif + +MODULE_AUTHOR("Stephane Eranian "); +MODULE_DESCRIPTION("/proc interface to IA-64 PAL"); /* - * Hope to get rid of these in a near future + * Hope to get rid of this one in a near future */ #define IA64_PAL_VERSION_BUG 1 -#define PALINFO_VERSION "0.1" +#define PALINFO_VERSION "0.3" + +#ifdef CONFIG_SMP +#define cpu_is_online(i) (cpu_online_map & (1UL << i)) +#else +#define cpu_is_online(i) 1 +#endif typedef int (*palinfo_func_t)(char*); @@ -43,7 +60,6 @@ struct proc_dir_entry *entry; /* registered entry (removal) */ } palinfo_entry_t; -static struct proc_dir_entry *palinfo_dir; /* * A bunch of string array to get pretty printing @@ -95,7 +111,7 @@ #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *)) /* - * The current resvision of the Volume 2 of + * The current revision of the Volume 2 of * IA-64 Architecture Software Developer's Manual is wrong. * Table 4-10 has invalid information concerning the ma field: * Correct table is: @@ -121,64 +137,31 @@ /* * Allocate a buffer suitable for calling PAL code in Virtual mode * - * The documentation (PAL2.6) requires thius buffer to have a pinned - * translation to avoid any DTLB faults. For this reason we allocate - * a page (large enough to hold any possible reply) and use a DTC - * to hold the translation during the call. A call the free_palbuffer() - * is required to release ALL resources (page + translation). - * - * The size of the page allocated is based on the PAGE_SIZE defined - * at compile time for the kernel, i.e. >= 4Kb. + * The documentation (PAL2.6) allows DTLB misses on the buffer. So + * using the TC is enough, no need to pin the entry. * - * Return: a pointer to the newly allocated page (virtual address) + * We allocate a kernel-sized page (at least 4KB). This is enough to + * hold any possible reply. */ -static void * +static inline void * get_palcall_buffer(void) { void *tmp; tmp = (void *)__get_free_page(GFP_KERNEL); if (tmp == 0) { - printk(KERN_ERR "%s: can't get a buffer page\n", __FUNCTION__); - } else if ( ((u64)tmp - PAGE_OFFSET) > (1<<_PAGE_SIZE_256M) ) { /* XXX: temporary hack */ - unsigned long flags; - - /* PSR.ic must be zero to insert new DTR */ - ia64_clear_ic(flags); - - /* - * we only insert of DTR - * - * XXX: we need to figure out a way to "allocate" TR(s) to avoid - * conflicts. Maybe something in an include file like pgtable.h - * page.h or processor.h - * - * ITR0/DTR0: used for kernel code/data - * ITR1/DTR1: used by HP simulator - * ITR2/DTR2: used to map PAL code - */ - ia64_itr(0x2, 3, (u64)tmp, - pte_val(mk_pte_phys(__pa(tmp), __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), PAGE_SHIFT); - - ia64_srlz_d (); - - __restore_flags(flags); - } - + printk(KERN_ERR __FUNCTION__" : can't get a buffer page\n"); + } return tmp; } /* * Free a palcall buffer allocated with the previous call - * - * The translation is also purged. */ -static void +static inline void free_palcall_buffer(void *addr) { __free_page(addr); - ia64_ptr(0x2, (u64)addr, PAGE_SHIFT); - ia64_srlz_d (); } /* @@ -564,7 +547,6 @@ int i; s64 ret; - /* must be in physical mode */ if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0; for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) { @@ -577,6 +559,57 @@ return p - page; } +static const char *bus_features[]={ + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, + NULL,NULL, + "Request Bus Parking", + "Bus Lock Mask", + "Enable Half Transfer", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + "Disable Transaction Queuing", + "Disable Reponse Error Checking", + "Disable Bus Error Checking", + "Disable Bus Requester Internal Error Signalling", + "Disable Bus Requester Error Signalling", + "Disable Bus Initialization Event Checking", + "Disable Bus Initialization Event Signalling", + "Disable Bus Address Error Checking", + "Disable Bus Address Error Signalling", + "Disable Bus Data Error Checking" +}; + + +static int +bus_info(char *page) +{ + char *p = page; + const char **v = bus_features; + pal_bus_features_u_t av, st, ct; + u64 avail, status, control; + int i; + s64 ret; + + if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0; + + avail = av.pal_bus_features_val; + status = st.pal_bus_features_val; + control = ct.pal_bus_features_val; + + for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) { + if ( ! *v ) continue; + p += sprintf(p, "%-48s : %s%s %s\n", *v, + avail & 0x1 ? "" : "NotImpl", + avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", + avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); + } + return p - page; +} + + /* * physical mode call for PAL_VERSION is working fine. * This function is meant to go away once PAL get fixed. @@ -613,21 +646,25 @@ #endif if (status != 0) return 0; - p += sprintf(p, "PAL_vendor : 0x%x (min=0x%x)\n" \ - "PAL_A revision : 0x%x (min=0x%x)\n" \ - "PAL_A model : 0x%x (min=0x%x)\n" \ - "PAL_B mode : 0x%x (min=0x%x)\n" \ - "PAL_B revision : 0x%x (min=0x%x)\n", + p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \ + "PAL_A : %x.%x.%x (min=%x.%x.%x)\n" \ + "PAL_B : %x.%x.%x (min=%x.%x.%x)\n", cur_ver.pal_version_s.pv_pal_vendor, min_ver.pal_version_s.pv_pal_vendor, + + cur_ver.pal_version_s.pv_pal_a_model>>4, + cur_ver.pal_version_s.pv_pal_a_model&0xf, cur_ver.pal_version_s.pv_pal_a_rev, - cur_ver.pal_version_s.pv_pal_a_rev, - cur_ver.pal_version_s.pv_pal_a_model, - min_ver.pal_version_s.pv_pal_a_model, + min_ver.pal_version_s.pv_pal_a_model>>4, + min_ver.pal_version_s.pv_pal_a_model&0xf, + min_ver.pal_version_s.pv_pal_a_rev, + + cur_ver.pal_version_s.pv_pal_b_model>>4, + cur_ver.pal_version_s.pv_pal_b_model&0xf, cur_ver.pal_version_s.pv_pal_b_rev, - min_ver.pal_version_s.pv_pal_b_rev, - cur_ver.pal_version_s.pv_pal_b_model, - min_ver.pal_version_s.pv_pal_b_model); + min_ver.pal_version_s.pv_pal_b_model>>4, + min_ver.pal_version_s.pv_pal_b_model&0xf, + min_ver.pal_version_s.pv_pal_b_rev); return p - page; } @@ -648,6 +685,9 @@ } #ifdef IA64_PAL_PERF_MON_INFO_BUG + /* + * This bug has been fixed in PAL 2.2.9 and higher + */ pm_buffer[5]=0x3; pm_info.pal_perf_mon_info_s.cycles = 0x12; pm_info.pal_perf_mon_info_s.retired = 0x08; @@ -708,30 +748,111 @@ return p - page; } - -/* - * Entry point routine: all calls go trhough this function - */ static int -palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +tr_info(char *page) { - palinfo_func_t info = (palinfo_func_t)data; - int len = info(page); + char *p = page; + s64 status; + pal_tr_valid_u_t tr_valid; + u64 tr_buffer[4]; + pal_vm_info_1_u_t vm_info_1; + pal_vm_info_2_u_t vm_info_2; + int i, j; + u64 max[3], pgm; + struct ifa_reg { + u64 valid:1; + u64 ig:11; + u64 vpn:52; + } *ifa_reg; + struct itir_reg { + u64 rv1:2; + u64 ps:6; + u64 key:24; + u64 rv2:32; + } *itir_reg; + struct gr_reg { + u64 p:1; + u64 rv1:1; + u64 ma:3; + u64 a:1; + u64 d:1; + u64 pl:2; + u64 ar:3; + u64 ppn:38; + u64 rv2:2; + u64 ed:1; + u64 ig:11; + } *gr_reg; + struct rid_reg { + u64 ig1:1; + u64 rv1:1; + u64 ig2:6; + u64 rid:24; + u64 rv2:32; + } *rid_reg; - if (len <= off+count) *eof = 1; + if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) { + printk("ia64_pal_vm_summary=%ld\n", status); + return 0; + } + max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1; + max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1; - *start = page + off; - len -= off; + for (i=0; i < 2; i++ ) { + for (j=0; j < max[i]; j++) { - if (len>count) len = count; - if (len<0) len = 0; + status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid); + if (status != 0) { + printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status); + continue; + } - return len; + ifa_reg = (struct ifa_reg *)&tr_buffer[2]; + + if (ifa_reg->valid == 0) continue; + + gr_reg = (struct gr_reg *)tr_buffer; + itir_reg = (struct itir_reg *)&tr_buffer[1]; + rid_reg = (struct rid_reg *)&tr_buffer[3]; + + pgm = -1 << (itir_reg->ps - 12); + p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" \ + "\tppn : 0x%lx\n" \ + "\tvpn : 0x%lx\n" \ + "\tps : ", + + "ID"[i], + j, + tr_valid.pal_tr_valid_s.access_rights_valid, + tr_valid.pal_tr_valid_s.priv_level_valid, + tr_valid.pal_tr_valid_s.dirty_bit_valid, + tr_valid.pal_tr_valid_s.mem_attr_valid, + (gr_reg->ppn & pgm)<< 12, + (ifa_reg->vpn & pgm)<< 12); + + p = bitvector_process(p, 1<< itir_reg->ps); + + p += sprintf(p, "\n\tpl : %d\n" \ + "\tar : %d\n" \ + "\trid : %x\n" \ + "\tp : %d\n" \ + "\tma : %d\n" \ + "\td : %d\n", + gr_reg->pl, + gr_reg->ar, + rid_reg->rid, + gr_reg->p, + gr_reg->ma, + gr_reg->d); + } + } + return p - page; } + + /* - * List names,function pairs for every entry in /proc/palinfo - * Must be terminated with the NULL,NULL entry. + * List {name,function} pairs for every entry in /proc/palinfo/cpu* */ static palinfo_entry_t palinfo_entries[]={ { "version_info", version_info, }, @@ -742,38 +863,190 @@ { "processor_info", processor_info, }, { "perfmon_info", perfmon_info, }, { "frequency_info", frequency_info, }, - { NULL, NULL,} + { "bus_info", bus_info }, + { "tr_info", tr_info, } }; +#define NR_PALINFO_ENTRIES (sizeof(palinfo_entries)/sizeof(palinfo_entry_t)) + +/* + * this array is used to keep track of the proc entries we create. This is + * required in the module mode when we need to remove all entries. The procfs code + * does not do recursion of deletion + * + * Notes: + * - first +1 accounts for the cpuN entry + * - second +1 account for toplevel palinfo + * + */ +#define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1) + +static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES]; + +/* + * This data structure is used to pass which cpu,function is being requested + * It must fit in a 64bit quantity to be passed to the proc callback routine + * + * In SMP mode, when we get a request for another CPU, we must call that + * other CPU using IPI and wait for the result before returning. + */ +typedef union { + u64 value; + struct { + unsigned req_cpu: 32; /* for which CPU this info is */ + unsigned func_id: 32; /* which function is requested */ + } pal_func_cpu; +} pal_func_cpu_u_t; + +#define req_cpu pal_func_cpu.req_cpu +#define func_id pal_func_cpu.func_id + +#ifdef CONFIG_SMP + +/* + * used to hold information about final function to call + */ +typedef struct { + palinfo_func_t func; /* pointer to function to call */ + char *page; /* buffer to store results */ + int ret; /* return value from call */ +} palinfo_smp_data_t; + + +/* + * this function does the actual final call and he called + * from the smp code, i.e., this is the palinfo callback routine + */ +static void +palinfo_smp_call(void *info) +{ + palinfo_smp_data_t *data = (palinfo_smp_data_t *)info; + /* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/ + if (data == NULL) { + printk(KERN_ERR __FUNCTION__" data pointer is NULL\n"); + data->ret = 0; /* no output */ + return; + } + /* does this actual call */ + data->ret = (*data->func)(data->page); +} + +/* + * function called to trigger the IPI, we need to access a remote CPU + * Return: + * 0 : error or nothing to output + * otherwise how many bytes in the "page" buffer were written + */ +static +int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) +{ + palinfo_smp_data_t ptr; + int ret; + + ptr.func = palinfo_entries[f->func_id].proc_read; + ptr.page = page; + ptr.ret = 0; /* just in case */ + + /*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/ + + /* will send IPI to other CPU and wait for completion of remote call */ + if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) { + printk(__FUNCTION__" remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret); + return 0; + } + return ptr.ret; +} +#else /* ! CONFIG_SMP */ +static +int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) +{ + printk(__FUNCTION__" should not be called with non SMP kernel\n"); + return 0; +} +#endif /* CONFIG_SMP */ + +/* + * Entry point routine: all calls go through this function + */ +static int +palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len=0; + pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data; + + MOD_INC_USE_COUNT; + /* + * in SMP mode, we may need to call another CPU to get correct + * information. PAL, by definition, is processor specific + */ + if (f->req_cpu == smp_processor_id()) + len = (*palinfo_entries[f->func_id].proc_read)(page); + else + len = palinfo_handle_smp(f, page); + + if (len <= off+count) *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) len = count; + if (len<0) len = 0; + + MOD_DEC_USE_COUNT; + + return len; +} static int __init palinfo_init(void) { - palinfo_entry_t *p; +# define CPUSTR "cpu%d" + + pal_func_cpu_u_t f; + struct proc_dir_entry **pdir = palinfo_proc_entries; + struct proc_dir_entry *palinfo_dir, *cpu_dir; + int i, j; + char cpustr[sizeof(CPUSTR)]; printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); - palinfo_dir = create_proc_entry("palinfo", S_IFDIR | S_IRUGO | S_IXUGO, NULL); + palinfo_dir = proc_mkdir("pal", NULL); + + /* + * we keep track of created entries in a depth-first order for + * cleanup purposes. Each entry is stored into palinfo_proc_entries + */ + for (i=0; i < NR_CPUS; i++) { + + if (!cpu_is_online(i)) continue; + + sprintf(cpustr,CPUSTR, i); + + cpu_dir = proc_mkdir(cpustr, palinfo_dir); - for (p = palinfo_entries; p->name ; p++){ - p->entry = create_proc_read_entry (p->name, 0, palinfo_dir, - palinfo_read_entry, p->proc_read); + f.req_cpu = i; + + for (j=0; j < NR_PALINFO_ENTRIES; j++) { + f.func_id = j; + *pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir, + palinfo_read_entry, (void *)f.value); + } + *pdir++ = cpu_dir; } + *pdir = palinfo_dir; return 0; } -static int __exit +static void __exit palinfo_exit(void) { - palinfo_entry_t *p; + int i = 0; - for (p = palinfo_entries; p->name ; p++){ - remove_proc_entry (p->name, palinfo_dir); + /* remove all nodes: depth first pass */ + for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) { + remove_proc_entry (palinfo_proc_entries[i]->name, NULL); } - remove_proc_entry ("palinfo", 0); - - return 0; } module_init(palinfo_init); diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/pci-dma.c linux/arch/ia64/kernel/pci-dma.c --- v2.4.0-test6/linux/arch/ia64/kernel/pci-dma.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/kernel/pci-dma.c Fri Aug 11 19:09:06 2000 @@ -3,34 +3,509 @@ * * This implementation is for IA-64 platforms that do not support * I/O TLBs (aka DMA address translation hardware). - * - * XXX This doesn't do the right thing yet. It appears we would have - * to add additional zones so we can implement the various address - * mask constraints that we might encounter. A zone for memory < 32 - * bits is obviously necessary... + * Copyright (C) 2000 Asit Mallick + * Copyright (C) 2000 Goutham Rao */ -#include +#include + #include -#include #include +#include +#include +#include #include +#include +#include + +#ifdef CONFIG_SWIOTLB + +#include +#include + +#define ALIGN(val, align) ((unsigned long) (((unsigned long) (val) + ((align) - 1)) & ~((align) - 1))) + +/* + * log of the size of each IO TLB slab. The number of slabs is command line + * controllable. + */ +#define IO_TLB_SHIFT 11 + +/* + * Used to do a quick range check in pci_unmap_single and pci_sync_single, to see if the + * memory was in fact allocated by this API. + */ +static char *io_tlb_start, *io_tlb_end; + +/* + * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and io_tlb_end. + * This is command line adjustable via setup_io_tlb_npages. + */ +unsigned long io_tlb_nslabs = 1024; + +/* + * This is a free list describing the number of free entries available from each index + */ +static unsigned int *io_tlb_list; +static unsigned int io_tlb_index; + +/* + * We need to save away the original address corresponding to a mapped entry for the sync + * operations. + */ +static unsigned char **io_tlb_orig_addr; + +/* + * Protect the above data structures in the map and unmap calls + */ +spinlock_t io_tlb_lock = SPIN_LOCK_UNLOCKED; + +static int __init +setup_io_tlb_npages (char *str) +{ + io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); + return 1; +} +__setup("swiotlb=", setup_io_tlb_npages); + +/* + * Statically reserve bounce buffer space and initialize bounce buffer + * data structures for the software IO TLB used to implement the PCI DMA API + */ +void +setup_swiotlb (void) +{ + int i; + + /* + * Get IO TLB memory from the low pages + */ + io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); + if (!io_tlb_start) + BUG(); + io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); + + /* + * Allocate and initialize the free list array. This array is used + * to find contiguous free memory regions of size 2^IO_TLB_SHIFT between + * io_tlb_start and io_tlb_end. + */ + io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int)); + for (i = 0; i < io_tlb_nslabs; i++) + io_tlb_list[i] = io_tlb_nslabs - i; + io_tlb_index = 0; + io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); + + printk("Placing software IO TLB between 0x%p - 0x%p\n", io_tlb_start, io_tlb_end); +} + +/* + * Allocates bounce buffer and returns its kernel virtual address. + */ +static void * +__pci_map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction) +{ + unsigned long flags; + char *dma_addr; + unsigned int i, nslots, stride, index, wrap; + + /* + * For mappings greater than a page size, we limit the stride (and hence alignment) + * to a page size. + */ + nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; + if (size > (1 << PAGE_SHIFT)) + stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT)); + else + stride = nslots; + + if (!nslots) + BUG(); + + /* + * Find suitable number of IO TLB entries size that will fit this request and allocate a buffer + * from that IO TLB pool. + */ + spin_lock_irqsave(&io_tlb_lock, flags); + { + wrap = index = ALIGN(io_tlb_index, stride); + do { + /* + * If we find a slot that indicates we have 'nslots' number of + * contiguous buffers, we allocate the buffers from that slot and mark the + * entries as '0' indicating unavailable. + */ + if (io_tlb_list[index] >= nslots) { + for (i = index; i < index + nslots; i++) + io_tlb_list[i] = 0; + dma_addr = io_tlb_start + (index << IO_TLB_SHIFT); + + /* + * Update the indices to avoid searching in the next round. + */ + io_tlb_index = (index + nslots) < io_tlb_nslabs ? (index + nslots) : 0; + + goto found; + } + index += stride; + if (index >= io_tlb_nslabs) + index = 0; + } while (index != wrap); + + /* + * XXX What is a suitable recovery mechanism here? We cannot + * sleep because we are called from with in interrupts! + */ + panic("__pci_map_single: could not allocate software IO TLB (%ld bytes)", size); +found: + } + spin_unlock_irqrestore(&io_tlb_lock, flags); + + /* + * Save away the mapping from the original address to the DMA address. This is needed + * when we sync the memory. Then we sync the buffer if needed. + */ + io_tlb_orig_addr[index] = buffer; + if (direction == PCI_DMA_TODEVICE || direction == PCI_DMA_BIDIRECTIONAL) + memcpy(dma_addr, buffer, size); + + return dma_addr; +} + +/* + * dma_addr is the kernel virtual address of the bounce buffer to unmap. + */ +static void +__pci_unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) +{ + unsigned long flags; + int i, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; + int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; + char *buffer = io_tlb_orig_addr[index]; + + /* + * First, sync the memory before unmapping the entry + */ + if ((direction == PCI_DMA_FROMDEVICE) || (direction == PCI_DMA_BIDIRECTIONAL)) + /* + * bounce... copy the data back into the original buffer + * and delete the bounce buffer. + */ + memcpy(buffer, dma_addr, size); + + /* + * Return the buffer to the free list by setting the corresponding entries to indicate + * the number of contigous entries available. + * While returning the entries to the free list, we merge the entries with slots below + * and above the pool being returned. + */ + spin_lock_irqsave(&io_tlb_lock, flags); + { + int count = ((index + nslots) < io_tlb_nslabs ? io_tlb_list[index + nslots] : 0); + /* + * Step 1: return the slots to the free list, merging the slots with superceeding slots + */ + for (i = index + nslots - 1; i >= index; i--) + io_tlb_list[i] = ++count; + /* + * Step 2: merge the returned slots with the preceeding slots, if available (non zero) + */ + for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--) + io_tlb_list[i] += io_tlb_list[index]; + } + spin_unlock_irqrestore(&io_tlb_lock, flags); +} + +static void +__pci_sync_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) +{ + int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; + char *buffer = io_tlb_orig_addr[index]; + + /* + * bounce... copy the data back into/from the original buffer + * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ? + */ + if (direction == PCI_DMA_FROMDEVICE) + memcpy(buffer, dma_addr, size); + else if (direction == PCI_DMA_TODEVICE) + memcpy(dma_addr, buffer, size); + else + BUG(); +} + +/* + * Map a single buffer of the indicated size for DMA in streaming mode. + * The PCI address to use is returned. + * + * Once the device is given the dma address, the device owns this memory + * until either pci_unmap_single or pci_dma_sync_single is performed. + */ +dma_addr_t +pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) +{ + unsigned long pci_addr = virt_to_phys(ptr); + + if (direction == PCI_DMA_NONE) + BUG(); + /* + * Check if the PCI device can DMA to ptr... if so, just return ptr + */ + if ((pci_addr & ~hwdev->dma_mask) == 0) + /* + * Device is bit capable of DMA'ing to the + * buffer... just return the PCI address of ptr + */ + return pci_addr; + + /* + * get a bounce buffer: + */ + pci_addr = virt_to_phys(__pci_map_single(hwdev, ptr, size, direction)); + + /* + * Ensure that the address returned is DMA'ble: + */ + if ((pci_addr & ~hwdev->dma_mask) != 0) + panic("__pci_map_single: bounce buffer is not DMA'ble"); + + return pci_addr; +} + +/* + * Unmap a single streaming mode DMA translation. The dma_addr and size + * must match what was provided for in a previous pci_map_single call. All + * other usages are undefined. + * + * After this call, reads by the cpu to the buffer are guarenteed to see + * whatever the device wrote there. + */ +void +pci_unmap_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction) +{ + char *dma_addr = phys_to_virt(pci_addr); + + if (direction == PCI_DMA_NONE) + BUG(); + if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) + __pci_unmap_single(hwdev, dma_addr, size, direction); +} + +/* + * Make physical memory consistent for a single + * streaming mode DMA translation after a transfer. + * + * If you perform a pci_map_single() but wish to interrogate the + * buffer using the cpu, yet do not wish to teardown the PCI dma + * mapping, you must call this function before doing so. At the + * next point you give the PCI dma address back to the card, the + * device again owns the buffer. + */ +void +pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction) +{ + char *dma_addr = phys_to_virt(pci_addr); + + if (direction == PCI_DMA_NONE) + BUG(); + if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) + __pci_sync_single(hwdev, dma_addr, size, direction); +} + +/* + * Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scather-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +int +pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) { + sg->orig_address = sg->address; + if ((virt_to_phys(sg->address) & ~hwdev->dma_mask) != 0) { + sg->address = __pci_map_single(hwdev, sg->address, sg->length, direction); + } + } + return nelems; +} + +/* + * Unmap a set of streaming mode DMA translations. + * Again, cpu read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +void +pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) + if (sg->orig_address != sg->address) { + __pci_unmap_single(hwdev, sg->address, sg->length, direction); + sg->address = sg->orig_address; + } +} + +/* + * Make physical memory consistent for a set of streaming mode DMA + * translations after a transfer. + * + * The same as pci_dma_sync_single but for a scatter-gather list, + * same rules and usage. + */ +void +pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) + if (sg->orig_address != sg->address) + __pci_sync_single(hwdev, sg->address, sg->length, direction); +} + +#else +/* + * Map a single buffer of the indicated size for DMA in streaming mode. + * The 32-bit bus address to use is returned. + * + * Once the device is given the dma address, the device owns this memory + * until either pci_unmap_single or pci_dma_sync_single is performed. + */ +extern inline dma_addr_t +pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + return virt_to_bus(ptr); +} + +/* + * Unmap a single streaming mode DMA translation. The dma_addr and size + * must match what was provided for in a previous pci_map_single call. All + * other usages are undefined. + * + * After this call, reads by the cpu to the buffer are guarenteed to see + * whatever the device wrote there. + */ +extern inline void +pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + /* Nothing to do */ +} +/* + * Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scather-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +extern inline int +pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + return nents; +} + +/* + * Unmap a set of streaming mode DMA translations. + * Again, cpu read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +extern inline void +pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + /* Nothing to do */ +} +/* + * Make physical memory consistent for a single + * streaming mode DMA translation after a transfer. + * + * If you perform a pci_map_single() but wish to interrogate the + * buffer using the cpu, yet do not wish to teardown the PCI dma + * mapping, you must call this function before doing so. At the + * next point you give the PCI dma address back to the card, the + * device again owns the buffer. + */ +extern inline void +pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + /* Nothing to do */ +} + +/* + * Make physical memory consistent for a set of streaming mode DMA + * translations after a transfer. + * + * The same as pci_dma_sync_single but for a scatter-gather list, + * same rules and usage. + */ +extern inline void +pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + /* Nothing to do */ +} + +#endif /* CONFIG_SWIOTLB */ void * pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { - void *ret; + unsigned long pci_addr; int gfp = GFP_ATOMIC; + void *ret; - if (!hwdev || hwdev->dma_mask == 0xffffffff) - gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ + if (!hwdev || hwdev->dma_mask <= 0xffffffff) + gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ ret = (void *)__get_free_pages(gfp, get_order(size)); + if (!ret) + return NULL; - if (ret) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - } + memset(ret, 0, size); + pci_addr = virt_to_phys(ret); + if ((pci_addr & ~hwdev->dma_mask) != 0) + panic("pci_alloc_consistent: allocated memory is out of range for PCI device"); + *dma_handle = pci_addr; return ret; } diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c --- v2.4.0-test6/linux/arch/ia64/kernel/perfmon.c Fri Mar 10 16:40:39 2000 +++ linux/arch/ia64/kernel/perfmon.c Fri Aug 11 19:09:06 2000 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -55,24 +56,23 @@ #define WRITE_PMCS 0xa1 #define READ_PMDS 0xa2 #define STOP_PMCS 0xa3 -#define IA64_COUNTER_MASK 0xffffffffffffff6f -#define PERF_OVFL_VAL 0xffffffff +#define IA64_COUNTER_MASK 0xffffffffffffff6fL +#define PERF_OVFL_VAL 0xffffffffL + +volatile int used_by_system; struct perfmon_counter { unsigned long data; unsigned long counter_num; }; -unsigned long pmds[MAX_PERF_COUNTER]; -struct task_struct *perf_owner=NULL; +unsigned long pmds[NR_CPUS][MAX_PERF_COUNTER]; asmlinkage unsigned long sys_perfmonctl (int cmd1, int cmd2, void *ptr) { struct perfmon_counter tmp, *cptr = ptr; - unsigned long pmd, cnum, dcr, flags; - struct task_struct *p; - struct pt_regs *regs; + unsigned long cnum, dcr, flags; struct perf_counter; int i; @@ -80,22 +80,24 @@ case WRITE_PMCS: /* Writes to PMC's and clears PMDs */ case WRITE_PMCS_AND_START: /* Also starts counting */ - if (!access_ok(VERIFY_READ, cptr, sizeof(struct perf_counter)*cmd2)) - return -EFAULT; + if (cmd2 <= 0 || cmd2 > MAX_PERF_COUNTER - used_by_system) + return -EINVAL; - if (cmd2 > MAX_PERF_COUNTER) + if (!access_ok(VERIFY_READ, cptr, sizeof(struct perf_counter)*cmd2)) return -EFAULT; - if (perf_owner && perf_owner != current) - return -EBUSY; - perf_owner = current; + current->thread.flags |= IA64_THREAD_PM_VALID; for (i = 0; i < cmd2; i++, cptr++) { copy_from_user(&tmp, cptr, sizeof(tmp)); /* XXX need to check validity of counter_num and perhaps data!! */ + if (tmp.counter_num < 4 + || tmp.counter_num >= 4 + MAX_PERF_COUNTER - used_by_system) + return -EFAULT; + ia64_set_pmc(tmp.counter_num, tmp.data); ia64_set_pmd(tmp.counter_num, 0); - pmds[tmp.counter_num - 4] = 0; + pmds[smp_processor_id()][tmp.counter_num - 4] = 0; } if (cmd1 == WRITE_PMCS_AND_START) { @@ -104,26 +106,13 @@ dcr |= IA64_DCR_PP; ia64_set_dcr(dcr); local_irq_restore(flags); - - /* - * This is a no can do. It obviously wouldn't - * work on SMP where another process may not - * be blocked at all. We need to put in a perfmon - * IPI to take care of MP systems. See blurb above. - */ - lock_kernel(); - for_each_task(p) { - regs = (struct pt_regs *) (((char *)p) + IA64_STK_OFFSET) -1 ; - ia64_psr(regs)->pp = 1; - } - unlock_kernel(); ia64_set_pmc(0, 0); } break; case READ_PMDS: - if (cmd2 > MAX_PERF_COUNTER) - return -EFAULT; + if (cmd2 <= 0 || cmd2 > MAX_PERF_COUNTER - used_by_system) + return -EINVAL; if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perf_counter)*cmd2)) return -EFAULT; @@ -153,9 +142,13 @@ * when we re-enabled interrupts. When I muck with dcr, * is the irq_save/restore needed? */ - for (i = 0, cnum = 4;i < MAX_PERF_COUNTER; i++, cnum++, cptr++){ - pmd = pmds[i] + (ia64_get_pmd(cnum) & PERF_OVFL_VAL); - put_user(pmd, &cptr->data); + for (i = 0, cnum = 4;i < cmd2; i++, cnum++, cptr++) { + tmp.data = (pmds[smp_processor_id()][i] + + (ia64_get_pmd(cnum) & PERF_OVFL_VAL)); + tmp.counter_num = cnum; + if (copy_to_user(cptr, &tmp, sizeof(tmp))) + return -EFAULT; + //put_user(pmd, &cptr->data); } local_irq_save(flags); __asm__ __volatile__("ssm psr.pp"); @@ -167,30 +160,22 @@ case STOP_PMCS: ia64_set_pmc(0, 1); - for (i = 0; i < MAX_PERF_COUNTER; ++i) - ia64_set_pmc(i, 0); + ia64_srlz_d(); + for (i = 0; i < MAX_PERF_COUNTER - used_by_system; ++i) + ia64_set_pmc(4+i, 0); - local_irq_save(flags); - dcr = ia64_get_dcr(); - dcr &= ~IA64_DCR_PP; - ia64_set_dcr(dcr); - local_irq_restore(flags); - /* - * This is a no can do. It obviously wouldn't - * work on SMP where another process may not - * be blocked at all. We need to put in a perfmon - * IPI to take care of MP systems. See blurb above. - */ - lock_kernel(); - for_each_task(p) { - regs = (struct pt_regs *) (((char *)p) + IA64_STK_OFFSET) - 1; - ia64_psr(regs)->pp = 0; + if (!used_by_system) { + local_irq_save(flags); + dcr = ia64_get_dcr(); + dcr &= ~IA64_DCR_PP; + ia64_set_dcr(dcr); + local_irq_restore(flags); } - unlock_kernel(); - perf_owner = NULL; + current->thread.flags &= ~(IA64_THREAD_PM_VALID); break; default: + return -EINVAL; break; } return 0; @@ -202,13 +187,13 @@ unsigned long mask, i, cnum, val; mask = ia64_get_pmc(0) >> 4; - for (i = 0, cnum = 4; i < MAX_PERF_COUNTER; cnum++, i++, mask >>= 1) { + for (i = 0, cnum = 4; i < MAX_PERF_COUNTER - used_by_system; cnum++, i++, mask >>= 1) { + val = 0; if (mask & 0x1) - val = PERF_OVFL_VAL; - else + val += PERF_OVFL_VAL + 1; /* since we got an interrupt, might as well clear every pmd. */ - val = ia64_get_pmd(cnum) & PERF_OVFL_VAL; - pmds[i] += val; + val += ia64_get_pmd(cnum) & PERF_OVFL_VAL; + pmds[smp_processor_id()][i] += val; ia64_set_pmd(cnum, 0); } } @@ -221,20 +206,61 @@ ia64_srlz_d(); } +static struct irqaction perfmon_irqaction = { + handler: perfmon_interrupt, + flags: SA_INTERRUPT, + name: "perfmon" +}; + void perfmon_init (void) { - if (request_irq(PERFMON_IRQ, perfmon_interrupt, 0, "perfmon", NULL)) { - printk("perfmon_init: could not allocate performance monitor vector %u\n", - PERFMON_IRQ); - return; - } + irq_desc[PERFMON_IRQ].status |= IRQ_PER_CPU; + irq_desc[PERFMON_IRQ].handler = &irq_type_ia64_sapic; + setup_irq(PERFMON_IRQ, &perfmon_irqaction); + ia64_set_pmv(PERFMON_IRQ); ia64_srlz_d(); printk("Initialized perfmon vector to %u\n",PERFMON_IRQ); } +void +perfmon_init_percpu (void) +{ + ia64_set_pmv(PERFMON_IRQ); + ia64_srlz_d(); +} + +void +ia64_save_pm_regs (struct thread_struct *t) +{ + int i; + + ia64_set_pmc(0, 1); + ia64_srlz_d(); + for (i=0; i< IA64_NUM_PM_REGS - used_by_system ; i++) { + t->pmd[i] = ia64_get_pmd(4+i); + t->pmod[i] = pmds[smp_processor_id()][i]; + t->pmc[i] = ia64_get_pmc(4+i); + } +} + +void +ia64_load_pm_regs (struct thread_struct *t) +{ + int i; + + for (i=0; i< IA64_NUM_PM_REGS - used_by_system ; i++) { + ia64_set_pmd(4+i, t->pmd[i]); + pmds[smp_processor_id()][i] = t->pmod[i]; + ia64_set_pmc(4+i, t->pmc[i]); + } + ia64_set_pmc(0, 0); + ia64_srlz_d(); +} + #else /* !CONFIG_PERFMON */ + asmlinkage unsigned long sys_perfmonctl (int cmd1, int cmd2, void *ptr) { diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.4.0-test6/linux/arch/ia64/kernel/process.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/process.c Fri Aug 11 19:09:06 2000 @@ -27,6 +27,8 @@ #include #include +#ifdef CONFIG_IA64_NEW_UNWIND + static void do_show_stack (struct unw_frame_info *info, void *arg) { @@ -44,6 +46,8 @@ } while (unw_unwind(info) >= 0); } +#endif + void show_stack (struct task_struct *task) { @@ -118,15 +122,14 @@ current->nice = 20; current->counter = -100; -#ifdef CONFIG_SMP - if (!current->need_resched) - min_xtp(); -#endif while (1) { - while (!current->need_resched) { +#ifdef CONFIG_SMP + if (!current->need_resched) + min_xtp(); +#endif + while (!current->need_resched) continue; - } #ifdef CONFIG_SMP normal_xtp(); #endif @@ -157,11 +160,12 @@ void ia64_save_extra (struct task_struct *task) { - extern void ia64_save_debug_regs (unsigned long *save_area); - extern void ia32_save_state (struct thread_struct *thread); - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) ia64_save_debug_regs(&task->thread.dbr[0]); +#ifdef CONFIG_PERFMON + if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) + ia64_save_pm_regs(&task->thread); +#endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_save_state(&task->thread); } @@ -169,11 +173,12 @@ void ia64_load_extra (struct task_struct *task) { - extern void ia64_load_debug_regs (unsigned long *save_area); - extern void ia32_load_state (struct thread_struct *thread); - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) ia64_load_debug_regs(&task->thread.dbr[0]); +#ifdef CONFIG_PERFMON + if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) + ia64_load_pm_regs(&task->thread); +#endif if (IS_IA32_PROCESS(ia64_task_regs(task))) ia32_load_state(&task->thread); } @@ -530,17 +535,6 @@ if (ia64_get_fpu_owner() == current) { ia64_set_fpu_owner(0); } -} - -/* - * Free remaining state associated with DEAD_TASK. This is called - * after the parent of DEAD_TASK has collected the exist status of the - * task via wait(). - */ -void -release_thread (struct task_struct *dead_task) -{ - /* nothing to do */ } unsigned long diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.0-test6/linux/arch/ia64/kernel/ptrace.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/ptrace.c Fri Aug 11 19:09:06 2000 @@ -549,6 +549,7 @@ ia64_sync_fph (struct task_struct *child) { if (ia64_psr(ia64_task_regs(child))->mfh && ia64_get_fpu_owner() == child) { + ia64_psr(ia64_task_regs(child))->mfh = 0; ia64_set_fpu_owner(0); ia64_save_fpu(&child->thread.fph[0]); child->thread.flags |= IA64_THREAD_FPH_VALID; diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/sal.c linux/arch/ia64/kernel/sal.c --- v2.4.0-test6/linux/arch/ia64/kernel/sal.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/sal.c Fri Aug 11 19:09:06 2000 @@ -156,6 +156,14 @@ struct ia64_sal_desc_platform_feature *pf = (void *) p; printk("SAL: Platform features "); +#ifdef CONFIG_IA64_HAVE_IRQREDIR + /* + * Early versions of SAL say we don't have + * IRQ redirection, even though we do... + */ + pf->feature_mask |= (1 << 1); +#endif + if (pf->feature_mask & (1 << 0)) printk("BusLock "); diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/semaphore.c linux/arch/ia64/kernel/semaphore.c --- v2.4.0-test6/linux/arch/ia64/kernel/semaphore.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/semaphore.c Fri Aug 11 19:09:06 2000 @@ -222,9 +222,6 @@ void __down_read_failed (struct rw_semaphore *sem, long count) { - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - while (1) { if (count == -1) { down_read_failed_biased(sem); diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.4.0-test6/linux/arch/ia64/kernel/setup.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/setup.c Fri Aug 11 19:09:06 2000 @@ -122,6 +122,10 @@ */ memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param)); + *cmdline_p = __va(ia64_boot_param.command_line); + strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ + efi_init(); max_pfn = 0; @@ -133,19 +137,65 @@ */ bootmap_start = PAGE_ALIGN(__pa(&_end)); if (ia64_boot_param.initrd_size) - bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param.initrd_size); + bootmap_start = PAGE_ALIGN(bootmap_start + + ia64_boot_param.initrd_size); bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); efi_memmap_walk(free_available_memory, 0); reserve_bootmem(bootmap_start, bootmap_size); + #ifdef CONFIG_BLK_DEV_INITRD initrd_start = ia64_boot_param.initrd_start; + if (initrd_start) { + u64 start, size; +# define is_same_page(a,b) (((a)&PAGE_MASK) == ((b)&PAGE_MASK)) + +#if 1 + /* XXX for now some backwards compatibility... */ + if (initrd_start >= PAGE_OFFSET) + printk("Warning: boot loader passed virtual address " + "for initrd, please upgrade the loader\n"); + } else +#endif + /* + * The loader ONLY passes physical addresses + */ + initrd_start = (unsigned long)__va(initrd_start); initrd_end = initrd_start+ia64_boot_param.initrd_size; + start = initrd_start; + size = ia64_boot_param.initrd_size; + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", (void *) initrd_start, ia64_boot_param.initrd_size); - reserve_bootmem(virt_to_phys(initrd_start), ia64_boot_param.initrd_size); + + /* + * The kernel end and the beginning of initrd can be + * on the same page. This would cause the page to be + * reserved twice. While not harmful, it does lead to + * a warning message which can cause confusion. Thus, + * we make sure that in this case we only reserve new + * pages, i.e., initrd only pages. We need to: + * + * - align up start + * - adjust size of reserved section accordingly + * + * It should be noted that this operation is only + * valid for the reserve_bootmem() call and does not + * affect the integrety of the initrd itself. + * + * reserve_bootmem() considers partial pages as reserved. + */ + if (is_same_page(initrd_start, (unsigned long)&_end)) { + start = PAGE_ALIGN(start); + size -= start-initrd_start; + + printk("Initial ramdisk & kernel on the same page: " + "reserving start=%lx size=%ld bytes\n", + start, size); + } + reserve_bootmem(__pa(start), size); } #endif #if 0 @@ -164,27 +214,21 @@ /* process SAL system table: */ ia64_sal_init(efi.sal_systab); - *cmdline_p = __va(ia64_boot_param.command_line); - strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ - - printk("args to kernel: %s\n", *cmdline_p); - #ifdef CONFIG_SMP bootstrap_processor = hard_smp_processor_id(); current->processor = bootstrap_processor; #endif cpu_init(); /* initialize the bootstrap CPU */ +#ifdef CONFIG_IA64_GENERIC + machvec_init(acpi_get_sysname()); +#endif + if (efi.acpi) { /* Parse the ACPI tables */ acpi_parse(efi.acpi); } -#ifdef CONFIG_IA64_GENERIC - machvec_init(acpi_get_sysname()); -#endif - #ifdef CONFIG_VT # if defined(CONFIG_VGA_CONSOLE) conswitchp = &vga_con; @@ -197,8 +241,16 @@ /* enable IA-64 Machine Check Abort Handling */ ia64_mca_init(); #endif + paging_init(); platform_setup(cmdline_p); + +#ifdef CONFIG_SWIOTLB + { + extern void setup_swiotlb (void); + setup_swiotlb(); + } +#endif } /* diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.4.0-test6/linux/arch/ia64/kernel/smp.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/smp.c Fri Aug 11 19:09:06 2000 @@ -320,6 +320,58 @@ #endif /* !CONFIG_ITANIUM_PTCG */ /* + * Run a function on another CPU + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until the remote CPU is nearly ready to execute + * or is or has executed. + */ + +int +smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait) +{ + struct smp_call_struct data; + long timeout; + int cpus = 1; + + if (cpuid == smp_processor_id()) { + printk(__FUNCTION__" trying to call self\n"); + return -EBUSY; + } + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, cpus); + atomic_set(&data.unfinished_count, cpus); + + if (pointer_lock(&smp_call_function_data, &data, retry)) + return -EBUSY; + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_single(cpuid, IPI_CALL_FUNC); + + /* Wait for response */ + timeout = jiffies + HZ; + while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) + barrier(); + if (atomic_read(&data.unstarted_count) > 0) { + smp_call_function_data = NULL; + return -ETIMEDOUT; + } + if (wait) + while (atomic_read(&data.unfinished_count) > 0) + barrier(); + /* unlock pointer */ + smp_call_function_data = NULL; + return 0; +} + +/* * Run a function on all other CPUs. * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. @@ -396,13 +448,19 @@ smp_do_timer(struct pt_regs *regs) { int cpu = smp_processor_id(); + int user = user_mode(regs); struct cpuinfo_ia64 *data = &cpu_data[cpu]; - if (!--data->prof_counter) { - irq_enter(cpu, TIMER_IRQ); - update_process_times(user_mode(regs)); + if (--data->prof_counter <= 0) { data->prof_counter = data->prof_multiplier; - irq_exit(cpu, TIMER_IRQ); + /* + * update_process_times() expects us to have done irq_enter(). + * Besides, if we don't timer interrupts ignore the global + * interrupt lock, which is the WrongThing (tm) to do. + */ + irq_enter(cpu, 0); + update_process_times(user); + irq_exit(cpu, 0); } } @@ -473,6 +531,11 @@ extern void ia64_rid_init(void); extern void ia64_init_itm(void); extern void ia64_cpu_local_tick(void); +#ifdef CONFIG_PERFMON + extern void perfmon_init_percpu(void); +#endif + + efi_map_pal_code(); cpu_init(); @@ -480,6 +543,10 @@ /* setup the CPU local timer tick */ ia64_init_itm(); + +#ifdef CONFIG_PERFMON + perfmon_init_percpu(); +#endif /* Disable all local interrupts */ ia64_set_lrr0(0, 1); diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.4.0-test6/linux/arch/ia64/kernel/time.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/time.c Fri Aug 11 19:09:06 2000 @@ -150,11 +150,13 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - static unsigned long last_time; - static unsigned char count; int cpu = smp_processor_id(); unsigned long new_itm; +#if 0 + static unsigned long last_time; + static unsigned char count; int printed = 0; +#endif /* * Here we are in the timer irq handler. We have irqs locally @@ -192,7 +194,7 @@ if (time_after(new_itm, ia64_get_itc())) break; -#if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP)) +#if 0 /* * SoftSDV in SMP mode is _slow_, so we do "lose" ticks, * but it's really OK... diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.4.0-test6/linux/arch/ia64/kernel/traps.c Fri Jun 23 21:55:07 2000 +++ linux/arch/ia64/kernel/traps.c Fri Aug 11 19:09:06 2000 @@ -204,11 +204,13 @@ { struct task_struct *fpu_owner = ia64_get_fpu_owner(); + /* first, clear psr.dfh and psr.mfh: */ regs->cr_ipsr &= ~(IA64_PSR_DFH | IA64_PSR_MFH); if (fpu_owner != current) { ia64_set_fpu_owner(current); if (fpu_owner && ia64_psr(ia64_task_regs(fpu_owner))->mfh) { + ia64_psr(ia64_task_regs(fpu_owner))->mfh = 0; fpu_owner->thread.flags |= IA64_THREAD_FPH_VALID; __ia64_save_fpu(fpu_owner->thread.fph); } @@ -216,6 +218,11 @@ __ia64_load_fpu(current->thread.fph); } else { __ia64_init_fpu(); + /* + * Set mfh because the state in thread.fph does not match + * the state in the fph partition. + */ + ia64_psr(regs)->mfh = 1; } } } diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.4.0-test6/linux/arch/ia64/kernel/unwind.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/kernel/unwind.c Fri Aug 11 19:09:06 2000 @@ -62,7 +62,7 @@ #define UNW_LOG_HASH_SIZE (UNW_LOG_CACHE_SIZE + 1) #define UNW_HASH_SIZE (1 << UNW_LOG_HASH_SIZE) -#define UNW_DEBUG 1 +#define UNW_DEBUG 0 #define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */ #if UNW_DEBUG diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/lib/memcpy.S linux/arch/ia64/lib/memcpy.S --- v2.4.0-test6/linux/arch/ia64/lib/memcpy.S Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/lib/memcpy.S Fri Aug 11 19:09:06 2000 @@ -1,3 +1,20 @@ +/* + * + * Optimized version of the standard memcpy() function + * + * Inputs: + * in0: destination address + * in1: source address + * in2: number of bytes to copy + * Output: + * no return value + * + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 Stephane Eranian + * Copyright (C) 2000 David Mosberger-Tang + */ +#include + #include GLOBAL_ENTRY(bcopy) @@ -10,77 +27,254 @@ // FALL THROUGH GLOBAL_ENTRY(memcpy) -# define MEM_LAT 4 - -# define N MEM_LAT-1 -# define Nrot ((MEM_LAT + 7) & ~7) +# define MEM_LAT 2 /* latency to L1 cache */ # define dst r2 # define src r3 -# define len r9 -# define saved_pfs r10 -# define saved_lc r11 -# define saved_pr r16 -# define t0 r17 -# define cnt r18 - +# define retval r8 +# define saved_pfs r9 +# define saved_lc r10 +# define saved_pr r11 +# define cnt r16 +# define src2 r17 +# define t0 r18 +# define t1 r19 +# define t2 r20 +# define t3 r21 +# define t4 r22 +# define src_end r23 + +# define N (MEM_LAT + 4) +# define Nrot ((N + 7) & ~7) + + /* + * First, check if everything (src, dst, len) is a multiple of eight. If + * so, we handle everything with no taken branches (other than the loop + * itself) and a small icache footprint. Otherwise, we jump off to + * the more general copy routine handling arbitrary + * sizes/alignment etc. + */ UNW(.prologue) UNW(.save ar.pfs, saved_pfs) alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot +#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) lfetch [in1] +#else + nop.m 0 +#endif + or t0=in0,in1 + ;; - .rotr val[MEM_LAT] - .rotp p[MEM_LAT] - + or t0=t0,in2 UNW(.save ar.lc, saved_lc) mov saved_lc=ar.lc - - or t0=in0,in1 UNW(.save pr, saved_pr) mov saved_pr=pr - UNW(.body) - - mov ar.ec=MEM_LAT + cmp.eq p6,p0=in2,r0 // zero length? + mov retval=in0 // return dst +(p6) br.ret.spnt.many rp // zero length, return immediately + ;; - mov r8=in0 // return dst - shr cnt=in2,3 // number of 8-byte words to copy + mov dst=in0 // copy because of rotation + shr.u cnt=in2,3 // number of 8-byte words to copy mov pr.rot=1<<16 ;; - cmp.eq p6,p0=in2,r0 // zero length? - or t0=t0,in2 -(p6) br.ret.spnt.many rp // yes, return immediately - mov dst=in0 // copy because of rotation - mov src=in1 // copy because of rotation adds cnt=-1,cnt // br.ctop is repeat/until + cmp.gtu p7,p0=16,in2 // copying less than 16 bytes? + UNW(.body) + mov ar.ec=N ;; + and t0=0x7,t0 mov ar.lc=cnt ;; cmp.ne p6,p0=t0,r0 -(p6) br.cond.spnt.few slow_memcpy + mov src=in1 // copy because of rotation +(p7) br.cond.spnt.few memcpy_short +(p6) br.cond.spnt.few memcpy_long + ;; + .rotr val[N] + .rotp p[N] 1: (p[0]) ld8 val[0]=[src],8 -(p[N]) st8 [dst]=val[N],8 - br.ctop.sptk.few 1b +(p[N-1])st8 [dst]=val[N-1],8 + br.ctop.dptk.few 1b ;; -.exit: mov ar.lc=saved_lc - mov pr=saved_pr,0xffffffffffff0000 + mov pr=saved_pr,-1 mov ar.pfs=saved_pfs br.ret.sptk.many rp -slow_memcpy: - adds cnt=-1,in2 + /* + * Small (<16 bytes) unaligned copying is done via a simple byte-at-the-time + * copy loop. This performs relatively poorly on Itanium, but it doesn't + * get used very often (gcc inlines small copies) and due to atomicity + * issues, we want to avoid read-modify-write of entire words. + */ + .align 32 +memcpy_short: + adds cnt=-1,in2 // br.ctop is repeat/until + mov ar.ec=MEM_LAT ;; mov ar.lc=cnt ;; + /* + * It is faster to put a stop bit in the loop here because it makes + * the pipeline shorter (and latency is what matters on short copies). + */ 1: (p[0]) ld1 val[0]=[src],1 -(p[N]) st1 [dst]=val[N],1 - br.ctop.sptk.few 1b - br.sptk.few .exit + ;; +(p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1 + br.ctop.dptk.few 1b + ;; + mov ar.lc=saved_lc + mov pr=saved_pr,-1 + mov ar.pfs=saved_pfs + br.ret.sptk.many rp + + /* + * Large (>= 16 bytes) copying is done in a fancy way. Latency isn't + * an overriding concern here, but throughput is. We first do + * sub-word copying until the destination is aligned, then we check + * if the source is also aligned. If so, we do a simple load/store-loop + * until there are less than 8 bytes left over and then we do the tail, + * by storing the last few bytes using sub-word copying. If the source + * is not aligned, we branch off to the non-congruent loop. + * + * stage: op: + * 0 ld + * : + * MEM_LAT+3 shrp + * MEM_LAT+4 st + * + * On Itanium, the pipeline itself runs without stalls. However, br.ctop + * seems to introduce an unavoidable bubble in the pipeline so the overall + * latency is 2 cycles/iteration. This gives us a _copy_ throughput + * of 4 byte/cycle. Still not bad. + */ +# undef N +# undef Nrot +# define N (MEM_LAT + 5) /* number of stages */ +# define Nrot ((N+1 + 2 + 7) & ~7) /* number of rotating regs */ + +#define LOG_LOOP_SIZE 6 + +memcpy_long: + alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame + and t0=-8,src // t0 = src & ~7 + and t2=7,src // t2 = src & 7 + ;; + ld8 t0=[t0] // t0 = 1st source word + adds src2=7,src // src2 = (src + 7) + sub t4=r0,dst // t4 = -dst + ;; + and src2=-8,src2 // src2 = (src + 7) & ~7 + shl t2=t2,3 // t2 = 8*(src & 7) + shl t4=t4,3 // t4 = 8*(dst & 7) + ;; + ld8 t1=[src2] // t1 = 1st source word if src is 8-byte aligned, 2nd otherwise + sub t3=64,t2 // t3 = 64-8*(src & 7) + shr.u t0=t0,t2 + ;; + add src_end=src,in2 + shl t1=t1,t3 + mov pr=t4,0x38 // (p5,p4,p3)=(dst & 7) + ;; + or t0=t0,t1 + mov cnt=r0 + adds src_end=-1,src_end + ;; +(p3) st1 [dst]=t0,1 +(p3) shr.u t0=t0,8 +(p3) adds cnt=1,cnt + ;; +(p4) st2 [dst]=t0,2 +(p4) shr.u t0=t0,16 +(p4) adds cnt=2,cnt + ;; +(p5) st4 [dst]=t0,4 +(p5) adds cnt=4,cnt + and src_end=-8,src_end // src_end = last word of source buffer + ;; + + // At this point, dst is aligned to 8 bytes and there at least 16-7=9 bytes left to copy: + +1:{ add src=cnt,src // make src point to remainder of source buffer + sub cnt=in2,cnt // cnt = number of bytes left to copy + mov t4=ip + } ;; + and src2=-8,src // align source pointer + adds t4=memcpy_loops-1b,t4 + mov ar.ec=N + + and t0=7,src // t0 = src & 7 + shr.u t2=cnt,3 // t2 = number of 8-byte words left to copy + shl cnt=cnt,3 // move bits 0-2 to 3-5 + ;; + + .rotr val[N+1], w[2] + .rotp p[N] + + cmp.ne p6,p0=t0,r0 // is src aligned, too? + shl t0=t0,LOG_LOOP_SIZE // t0 = 8*(src & 7) + adds t2=-1,t2 // br.ctop is repeat/until + ;; + add t4=t0,t4 + mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy + mov ar.lc=t2 + ;; +(p6) ld8 val[1]=[src2],8 // prime the pump... + mov b6=t4 + br.sptk.few b6 + ;; + +memcpy_tail: + // At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is + // less than 8) and t0 contains the last few bytes of the src buffer: +(p5) st4 [dst]=t0,4 +(p5) shr.u t0=t0,32 + mov ar.lc=saved_lc + ;; +(p4) st2 [dst]=t0,2 +(p4) shr.u t0=t0,16 + mov ar.pfs=saved_pfs + ;; +(p3) st1 [dst]=t0 + mov pr=saved_pr,-1 + br.ret.sptk.many rp + +/////////////////////////////////////////////////////// + .align 64 + +#define COPY(shift,index) \ + 1: \ + { .mfi \ + (p[0]) ld8 val[0]=[src2],8; \ + nop.f 0; \ + (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \ + }; \ + { .mbb \ + (p[MEM_LAT+4]) st8 [dst]=w[1],8; \ + nop.b 0; \ + br.ctop.dptk.few 1b; \ + }; \ + ;; \ + ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \ + ;; \ + shrp t0=val[N-1],val[N-index],shift; \ + br memcpy_tail +memcpy_loops: + COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */ + COPY(8, 0) + COPY(16, 0) + COPY(24, 0) + COPY(32, 0) + COPY(40, 0) + COPY(48, 0) + COPY(56, 0) END(memcpy) diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.4.0-test6/linux/arch/ia64/mm/init.c Wed Aug 9 19:19:49 2000 +++ linux/arch/ia64/mm/init.c Fri Aug 11 19:09:06 2000 @@ -185,8 +185,42 @@ void free_initrd_mem(unsigned long start, unsigned long end) { + /* + * EFI uses 4KB pages while the kernel can use 4KB or bigger. + * Thus EFI and the kernel may have different page sizes. It is + * therefore possible to have the initrd share the same page as + * the end of the kernel (given current setup). + * + * To avoid freeing/using the wrong page (kernel sized) we: + * - align up the beginning of initrd + * - keep the end untouched + * + * | | + * |=============| a000 + * | | + * | | + * | | 9000 + * |/////////////| + * |/////////////| + * |=============| 8000 + * |///INITRD////| + * |/////////////| + * |/////////////| 7000 + * | | + * |KKKKKKKKKKKKK| + * |=============| 6000 + * |KKKKKKKKKKKKK| + * |KKKKKKKKKKKKK| + * K=kernel using 8KB pages + * + * In this example, we must free page 8000 ONLY. So we must align up + * initrd_start and keep initrd_end as is. + */ + start = PAGE_ALIGN(start); + if (start < end) printk ("Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { clear_bit(PG_reserved, &virt_to_page(start)->flags); set_page_count(virt_to_page(start), 1); @@ -423,5 +457,4 @@ #ifdef CONFIG_IA32_SUPPORT ia32_gdt_init(); #endif - return; } diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.4.0-test6/linux/arch/ia64/mm/tlb.c Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/mm/tlb.c Fri Aug 11 19:09:06 2000 @@ -1,8 +1,11 @@ /* * TLB support routines. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * + * 08/02/00 A. Mallick + * Modified RID allocation for SMP */ #include #include @@ -27,9 +30,11 @@ 1 << _PAGE_SIZE_8K | \ 1 << _PAGE_SIZE_4K ) -static void wrap_context (struct mm_struct *mm); - -unsigned long ia64_next_context = (1UL << IA64_HW_CONTEXT_BITS) + 1; +struct ia64_ctx ia64_ctx = { + lock: SPIN_LOCK_UNLOCKED, + next: 1, + limit: (1UL << IA64_HW_CONTEXT_BITS) +}; /* * Put everything in a struct so we avoid the global offset table whenever @@ -106,49 +111,43 @@ #endif /* CONFIG_SMP && !CONFIG_ITANIUM_PTCG */ -void -get_new_mmu_context (struct mm_struct *mm) -{ - if ((ia64_next_context & IA64_HW_CONTEXT_MASK) == 0) { - wrap_context(mm); - } - mm->context = ia64_next_context++; -} - /* - * This is where we handle the case where (ia64_next_context & - * IA64_HW_CONTEXT_MASK) == 0. Whenever this happens, we need to - * flush the entire TLB and skip over region id number 0, which is - * used by the kernel. + * Acquire the ia64_ctx.lock before calling this function! */ -static void -wrap_context (struct mm_struct *mm) +void +wrap_mmu_context (struct mm_struct *mm) { - struct task_struct *task; + struct task_struct *tsk; + unsigned long tsk_context; + + if (ia64_ctx.next >= (1UL << IA64_HW_CONTEXT_BITS)) + ia64_ctx.next = 300; /* skip daemons */ + ia64_ctx.limit = (1UL << IA64_HW_CONTEXT_BITS); /* - * We wrapped back to the first region id so we nuke the TLB - * so we can switch to the next generation of region ids. + * Scan all the task's mm->context and set proper safe range */ - __flush_tlb_all(); - if (ia64_next_context++ == 0) { - /* - * Oops, we've used up all 64 bits of the context - * space---walk through task table to ensure we don't - * get tricked into using an old context. If this - * happens, the machine has been running for a long, - * long time! - */ - ia64_next_context = (1UL << IA64_HW_CONTEXT_BITS) + 1; - - read_lock(&tasklist_lock); - for_each_task (task) { - if (task->mm == mm) - continue; - flush_tlb_mm(mm); + + read_lock(&tasklist_lock); + repeat: + for_each_task(tsk) { + if (!tsk->mm) + continue; + tsk_context = tsk->mm->context; + if (tsk_context == ia64_ctx.next) { + if (++ia64_ctx.next >= ia64_ctx.limit) { + /* empty range: reset the range limit and start over */ + if (ia64_ctx.next >= (1UL << IA64_HW_CONTEXT_BITS)) + ia64_ctx.next = 300; + ia64_ctx.limit = (1UL << IA64_HW_CONTEXT_BITS); + goto repeat; + } } - read_unlock(&tasklist_lock); + if ((tsk_context > ia64_ctx.next) && (tsk_context < ia64_ctx.limit)) + ia64_ctx.limit = tsk_context; } + read_unlock(&tasklist_lock); + flush_tlb_all(); } void diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/sn/sn1/irq.c linux/arch/ia64/sn/sn1/irq.c --- v2.4.0-test6/linux/arch/ia64/sn/sn1/irq.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/sn/sn1/irq.c Fri Aug 11 19:09:06 2000 @@ -1,9 +1,10 @@ #include +#include +#include -#include #include -static int +static unsigned int sn1_startup_irq(unsigned int irq) { return(0); @@ -24,23 +25,16 @@ { } -static int -sn1_handle_irq(unsigned int irq, struct pt_regs *regs) -{ - return(0); -} - struct hw_interrupt_type irq_type_sn1 = { "sn1_irq", sn1_startup_irq, sn1_shutdown_irq, - sn1_handle_irq, sn1_enable_irq, sn1_disable_irq }; void -sn1_irq_init (struct irq_desc desc[NR_IRQS]) +sn1_irq_init (void) { int i; diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/sn/sn1/machvec.c linux/arch/ia64/sn/sn1/machvec.c --- v2.4.0-test6/linux/arch/ia64/sn/sn1/machvec.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/sn/sn1/machvec.c Fri Aug 11 19:09:06 2000 @@ -1,4 +1,2 @@ +#define MACHVEC_PLATFORM_NAME sn1 #include -#include - -MACHVEC_DEFINE(sn1) diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/sn/sn1/setup.c linux/arch/ia64/sn/sn1/setup.c --- v2.4.0-test6/linux/arch/ia64/sn/sn1/setup.c Thu May 11 15:30:06 2000 +++ linux/arch/ia64/sn/sn1/setup.c Fri Aug 11 19:09:06 2000 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S --- v2.4.0-test6/linux/arch/ia64/vmlinux.lds.S Thu Jul 27 17:37:59 2000 +++ linux/arch/ia64/vmlinux.lds.S Fri Aug 11 19:09:06 2000 @@ -46,6 +46,15 @@ { *(__ex_table) } __stop___ex_table = .; +#if defined(CONFIG_IA64_GENERIC) + /* Machine Vector */ + . = ALIGN(16); + machvec_start = .; + .machvec : AT(ADDR(.machvec) - PAGE_OFFSET) + { *(.machvec) } + machvec_end = .; +#endif + __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : AT(ADDR(__ksymtab) - PAGE_OFFSET) { *(__ksymtab) } diff -u --recursive --new-file v2.4.0-test6/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.4.0-test6/linux/arch/m68k/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/m68k/kernel/entry.S Fri Aug 11 14:29:04 2000 @@ -629,6 +629,10 @@ .long SYMBOL_NAME(sys_setgid) .long SYMBOL_NAME(sys_setfsuid) /* 215 */ .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_getdents64) /* 220 */ .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) diff -u --recursive --new-file v2.4.0-test6/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.4.0-test6/linux/arch/mips/config.in Wed Aug 9 19:19:49 2000 +++ linux/arch/mips/config.in Tue Aug 22 11:41:14 2000 @@ -296,6 +296,8 @@ if [ "$CONFIG_DECSTATION" != "y" -a \ "$CONFIG_SGI_IP22" != "y" ]; then source drivers/char/Config.in + + source drivers/media/Config.in fi if [ "$CONFIG_DECSTATION" = "y" ]; then @@ -376,6 +378,7 @@ fi source drivers/usb/Config.in +source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.0-test6/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h --- v2.4.0-test6/linux/arch/mips/kernel/syscalls.h Tue May 23 15:31:33 2000 +++ linux/arch/mips/kernel/syscalls.h Fri Aug 11 14:29:04 2000 @@ -234,3 +234,4 @@ SYS(sys_pivot_root, 2) SYS(sys_mincore, 3) SYS(sys_madvise, 3) +SYS(sys_getdents64, 3) diff -u --recursive --new-file v2.4.0-test6/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.4.0-test6/linux/arch/mips/kernel/sysirix.c Mon Jul 10 16:47:19 2000 +++ linux/arch/mips/kernel/sysirix.c Sat Aug 12 19:48:04 2000 @@ -1622,7 +1622,7 @@ pgoff = (off1 << (32 - PAGE_SHIFT)) | (off2 >> PAGE_SHIFT); if (!(flags & MAP_ANONYMOUS)) { - if (!(file = fcheck(fd))) { + if (!(file = fget(fd))) { error = -EBADF; goto out; } @@ -1847,7 +1847,7 @@ #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) static int irix_filldir32(void *__buf, const char *name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct irix_dirent32 *dirent; struct irix_dirent32_callback *buf = @@ -1943,7 +1943,7 @@ #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) static int irix_filldir64(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct irix_dirent64 *dirent; struct irix_dirent64_callback * buf = diff -u --recursive --new-file v2.4.0-test6/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.4.0-test6/linux/arch/mips64/config.in Wed Aug 9 19:19:49 2000 +++ linux/arch/mips64/config.in Tue Aug 22 11:41:14 2000 @@ -210,9 +210,10 @@ source drivers/char/Config.in - #source drivers/misc/Config.in +source drivers/media/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then @@ -247,6 +248,7 @@ fi source drivers/usb/Config.in +source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.0-test6/linux/arch/mips64/kernel/scall_64.S linux/arch/mips64/kernel/scall_64.S --- v2.4.0-test6/linux/arch/mips64/kernel/scall_64.S Wed Aug 9 19:19:49 2000 +++ linux/arch/mips64/kernel/scall_64.S Fri Aug 11 14:29:05 2000 @@ -344,3 +344,4 @@ PTR sys_pivot_root /* 4210 */ PTR sys_mincore PTR sys_madvise + PTR sys_getdents64 diff -u --recursive --new-file v2.4.0-test6/linux/arch/mips64/kernel/scall_o32.S linux/arch/mips64/kernel/scall_o32.S --- v2.4.0-test6/linux/arch/mips64/kernel/scall_o32.S Wed Aug 9 19:19:49 2000 +++ linux/arch/mips64/kernel/scall_o32.S Fri Aug 11 14:29:05 2000 @@ -420,6 +420,7 @@ sys sys_pivot_root 2 sys sys_mincore 3 sys sys_madvise 3 + sys sys_getdents64 3 .endm .macro sys function, nargs diff -u --recursive --new-file v2.4.0-test6/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.4.0-test6/linux/arch/ppc/config.in Fri Jul 14 12:12:06 2000 +++ linux/arch/ppc/config.in Tue Aug 22 11:41:14 2000 @@ -263,6 +263,9 @@ endmenu source drivers/char/Config.in + +source drivers/media/Config.in + source fs/Config.in mainmenu_option next_comment @@ -284,6 +287,7 @@ fi source drivers/usb/Config.in +source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.0-test6/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.4.0-test6/linux/arch/ppc/kernel/misc.S Fri Jul 14 12:12:06 2000 +++ linux/arch/ppc/kernel/misc.S Fri Aug 11 14:29:04 2000 @@ -1216,6 +1216,7 @@ .long sys_pciconfig_write /* 199 */ .long sys_pciconfig_iobase /* 200 */ .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ + .long sys_getdents64 /* 202 */ .rept NR_syscalls-201 .long sys_ni_syscall .endr diff -u --recursive --new-file v2.4.0-test6/linux/arch/s390/config.in linux/arch/s390/config.in --- v2.4.0-test6/linux/arch/s390/config.in Fri Jul 14 12:12:07 2000 +++ linux/arch/s390/config.in Tue Aug 22 11:29:02 2000 @@ -59,6 +59,8 @@ # source drivers/char/Config.in +# source drivers/media/Config.in + mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.0-test6/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.0-test6/linux/arch/s390/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/s390/kernel/entry.S Fri Aug 11 14:29:05 2000 @@ -603,7 +603,8 @@ .long sys_pivot_root .long sys_mincore .long sys_madvise - .rept 255-219 + .long sys_getdents64 /* 220 */ + .rept 255-220 .long sys_ni_syscall .endr diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/cf-enabler.c linux/arch/sh/kernel/cf-enabler.c --- v2.4.0-test6/linux/arch/sh/kernel/cf-enabler.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/cf-enabler.c Thu Aug 10 13:03:25 2000 @@ -8,7 +8,6 @@ * Enable the CF configuration. */ -#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.4.0-test6/linux/arch/sh/kernel/entry.S Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/entry.S Fri Aug 11 14:29:05 2000 @@ -1106,6 +1106,7 @@ .long SYMBOL_NAME(sys_pivot_root) .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) + .long SYMBOL_NAME(sys_getdents64) /* 220 */ /* * NOTE!! This doesn't have to be exact - we just have @@ -1113,7 +1114,7 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-219 + .rept NR_syscalls-220 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/io.c linux/arch/sh/kernel/io.c --- v2.4.0-test6/linux/arch/sh/kernel/io.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/io.c Thu Aug 10 13:03:25 2000 @@ -7,7 +7,6 @@ * Also definitions of machine independant IO functions. */ -#include #include unsigned int _inb(unsigned long port) diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/io_generic.c linux/arch/sh/kernel/io_generic.c --- v2.4.0-test6/linux/arch/sh/kernel/io_generic.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/io_generic.c Thu Aug 10 13:03:25 2000 @@ -13,7 +13,6 @@ * */ -#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/mach_se.c linux/arch/sh/kernel/mach_se.c --- v2.4.0-test6/linux/arch/sh/kernel/mach_se.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/mach_se.c Thu Aug 10 13:03:25 2000 @@ -9,6 +9,7 @@ * Machine vector for the Hitachi SolutionEngine */ +#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/mach_unknown.c linux/arch/sh/kernel/mach_unknown.c --- v2.4.0-test6/linux/arch/sh/kernel/mach_unknown.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/mach_unknown.c Thu Aug 10 13:03:25 2000 @@ -9,6 +9,7 @@ * Machine specific code for an unknown machine (internal peripherials only) */ +#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/sh/kernel/setup_cqreek.c linux/arch/sh/kernel/setup_cqreek.c --- v2.4.0-test6/linux/arch/sh/kernel/setup_cqreek.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sh/kernel/setup_cqreek.c Thu Aug 10 13:03:25 2000 @@ -8,6 +8,7 @@ * */ +#include #include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.4.0-test6/linux/arch/sparc/config.in Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/config.in Wed Aug 23 09:30:13 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.100 2000/08/07 18:06:54 anton Exp $ +# $Id: config.in,v 1.102 2000/08/23 05:59:28 davem Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -98,7 +98,7 @@ dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +#dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD #if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then # bool ' Boot support' CONFIG_MD_BOOT # bool ' Auto Detect support' CONFIG_AUTODETECT_RAID @@ -202,9 +202,10 @@ if [ "$CONFIG_NETDEVICES" = "y" ]; then tristate ' Dummy net driver support' CONFIG_DUMMY tristate ' Bonding driver support' CONFIG_BONDING + tristate ' Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then - tristate ' Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + tristate ' Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP fi fi tristate ' PPP (point-to-point) support' CONFIG_PPP diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.4.0-test6/linux/arch/sparc/defconfig Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/defconfig Thu Aug 10 12:43:12 2000 @@ -115,7 +115,6 @@ CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m -CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.4.0-test6/linux/arch/sparc/kernel/Makefile Thu Jul 27 17:37:59 2000 +++ linux/arch/sparc/kernel/Makefile Sat Aug 12 12:08:49 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.59 2000/07/16 18:21:24 ecd Exp $ +# $Id: Makefile,v 1.60 2000/08/12 08:35:53 ecd Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -6,6 +6,8 @@ # unless it's something special (ie not a .c file). # # Note 2! The CFLAGS definitions are now in the main makefile... + +SH = $(CONFIG_SHELL) .S.s: $(CPP) $(AFLAGS) -ansi $< -o $*.s diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/kernel/check_asm.sh linux/arch/sparc/kernel/check_asm.sh --- v2.4.0-test6/linux/arch/sparc/kernel/check_asm.sh Thu Jul 27 17:37:59 2000 +++ linux/arch/sparc/kernel/check_asm.sh Wed Aug 23 09:30:13 2000 @@ -1,12 +1,12 @@ #!/bin/sh case $1 in -printf) - sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ + sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ /g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0 0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0 0x%08x\\n", check_asm_data[i++]);/' >> $4 echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4 ;; -data) - sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ + sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ /g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/ ((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)), sizeof(((struct '$2'_struct *)0)->\0),/' >> $4 echo " sizeof(struct $2_struct)," >> $4 ;; diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.4.0-test6/linux/arch/sparc/kernel/sys_sunos.c Fri Jul 14 12:12:07 2000 +++ linux/arch/sparc/kernel/sys_sunos.c Sat Aug 12 12:08:49 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.129 2000/07/10 20:57:35 davem Exp $ +/* $Id: sys_sunos.c,v 1.130 2000/08/12 13:25:41 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -322,7 +322,7 @@ #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) static int sunos_filldir(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct sunos_dirent * dirent; struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; @@ -403,7 +403,7 @@ }; static int sunos_filldirentry(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct sunos_direntry * dirent; struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf; diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.4.0-test6/linux/arch/sparc/kernel/systbls.S Wed Apr 26 16:34:07 2000 +++ linux/arch/sparc/kernel/systbls.S Sun Aug 13 12:01:54 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.97 2000/04/13 00:55:49 davem Exp $ +/* $Id: systbls.S,v 1.99 2000/08/12 20:49:49 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -48,8 +48,8 @@ /*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64 /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit /*145*/ .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write -/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall -/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount +/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64 +/*155*/ .long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall /*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.4.0-test6/linux/arch/sparc/mm/init.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/mm/init.c Thu Aug 10 12:43:12 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.90 2000/08/09 00:00:15 davem Exp $ +/* $Id: init.c,v 1.91 2000/08/09 23:10:19 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -456,8 +456,6 @@ #endif highmem_start_page = mem_map + highstart_pfn; - /* cache the highmem_mapnr */ - highmem_mapnr = highstart_pfn; /* Saves us work later. */ memset((void *)&empty_zero_page, 0, PAGE_SIZE); diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.4.0-test6/linux/arch/sparc/mm/srmmu.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/mm/srmmu.c Mon Aug 14 13:09:07 2000 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.220 2000/08/09 00:00:15 davem Exp $ +/* $Id: srmmu.c,v 1.221 2000/08/14 00:46:13 anton Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -137,8 +137,8 @@ static inline unsigned long srmmu_pmd_page(pmd_t pmd) { return srmmu_device_memory(pmd_val(pmd))?~0:(unsigned long)__nocache_va((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); } -static inline unsigned long srmmu_pte_pagenr(pte_t pte) -{ return srmmu_device_memory(pte_val(pte))?~0:(((pte_val(pte) & SRMMU_PTE_PMASK) << 4) >> PAGE_SHIFT); } +static inline struct page *srmmu_pte_page(pte_t pte) +{ return (mem_map + (unsigned long)(srmmu_device_memory(pte_val(pte))?~0:(((pte_val(pte) & SRMMU_PTE_PMASK) << 4) >> PAGE_SHIFT))); } static inline int srmmu_pte_none(pte_t pte) { return !(pte_val(pte) & 0xFFFFFFF); } @@ -2153,7 +2153,7 @@ BTFIXUPSET_CALL(set_pte, srmmu_set_pte, BTFIXUPCALL_SWAPO0O1); BTFIXUPSET_CALL(switch_mm, srmmu_switch_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(sparc_pte_pagenr, srmmu_pte_pagenr, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_page, srmmu_pte_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pgd_page, srmmu_pgd_page, BTFIXUPCALL_NORM); diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.4.0-test6/linux/arch/sparc/mm/sun4c.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc/mm/sun4c.c Mon Aug 14 13:09:07 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.197 2000/08/09 00:00:15 davem Exp $ +/* $Id: sun4c.c,v 1.198 2000/08/14 00:46:13 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2156,9 +2156,9 @@ return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); } -static unsigned long sun4c_pte_pagenr(pte_t pte) +static struct page *sun4c_pte_page(pte_t pte) { - return (pte_val(pte) & SUN4C_PFN_MASK); + return (mem_map + (unsigned long)(pte_val(pte) & SUN4C_PFN_MASK)); } static inline unsigned long sun4c_pmd_page(pmd_t pmd) @@ -2650,7 +2650,7 @@ BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0); - BTFIXUPSET_CALL(sparc_pte_pagenr, sun4c_pte_pagenr, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_page, sun4c_pte_page, BTFIXUPCALL_NORM); #if PAGE_SHIFT <= 12 BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1)); #else diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.0-test6/linux/arch/sparc64/config.in Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/config.in Wed Aug 23 09:30:13 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.119 2000/08/02 10:45:03 davem Exp $ +# $Id: config.in,v 1.121 2000/08/23 05:59:28 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -86,24 +86,29 @@ bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD -bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD -if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then - tristate ' Linear (append) mode' CONFIG_MD_LINEAR - tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED -# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING -# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 -fi +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET + +#tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N +#if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then +# bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y +#fi + +tristate 'Multiple devices driver support' CONFIG_BLK_DEV_MD +dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD +#dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then +# bool ' Boot support' CONFIG_MD_BOOT +# bool ' Auto Detect support' CONFIG_AUTODETECT_RAID +#fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 fi -if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then - bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD -fi - -tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP -tristate 'Network block device support' CONFIG_BLK_DEV_NBD +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM endmenu @@ -231,9 +236,10 @@ if [ "$CONFIG_NETDEVICES" = "y" ]; then tristate ' Dummy net driver support' CONFIG_DUMMY tristate ' Bonding driver support' CONFIG_BONDING + tristate ' Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then - tristate ' Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + tristate ' Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP fi fi tristate ' PPP (point-to-point) support' CONFIG_PPP diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.0-test6/linux/arch/sparc64/defconfig Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/defconfig Wed Aug 23 09:30:13 2000 @@ -83,6 +83,7 @@ CONFIG_FB_PM2=y # CONFIG_FB_PM2_FIFO_DISCONNECT is not set CONFIG_FB_PM2_PCI=y +# CONFIG_FB_CYBER2000 is not set # CONFIG_FB_MATROX is not set CONFIG_FB_ATY=y # CONFIG_FB_ATY128 is not set @@ -135,10 +136,14 @@ # Block devices # CONFIG_BLK_DEV_FD=y -# CONFIG_BLK_DEV_MD is not set -# CONFIG_BLK_DEV_RAM is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set # # Networking options @@ -449,6 +454,7 @@ CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_SMB_FS=m +CONFIG_SMB_NLS_REMOTE="" # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.4.0-test6/linux/arch/sparc64/kernel/Makefile Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/Makefile Sat Aug 12 12:08:49 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.61 2000/08/09 08:25:19 jj Exp $ +# $Id: Makefile,v 1.62 2000/08/12 08:35:53 ecd Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -6,6 +6,8 @@ # unless it's something special (ie not a .c file). # # Note 2! The CFLAGS definitions are now in the main makefile... + +SH = $(CONFIG_SHELL) .S.s: $(CPP) $(AFLAGS) -ansi $< -o $*.s diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/check_asm.sh linux/arch/sparc64/kernel/check_asm.sh --- v2.4.0-test6/linux/arch/sparc64/kernel/check_asm.sh Thu Jul 27 17:37:59 2000 +++ linux/arch/sparc64/kernel/check_asm.sh Wed Aug 23 09:30:13 2000 @@ -1,12 +1,12 @@ #!/bin/sh case $1 in -printf) - sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ + sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ /g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0 0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0 0x%08x\\n", check_asm_data[i++]);/' >> $4 echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4 ;; -data) - sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ + sed -n -e '/struct[ ]*'$2'_struct[ ]*{/,/};/p' < $3 | sed '/struct[ ]*'$2'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/(\*//;s/)(.*)//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ /g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/ ((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)), sizeof(((struct '$2'_struct *)0)->\0),/' >> $4 echo " sizeof(struct $2_struct)," >> $4 ;; diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.4.0-test6/linux/arch/sparc64/kernel/ioctl32.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Fri Aug 18 10:26:25 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.96 2000/08/02 06:22:35 davem Exp $ +/* $Id: ioctl32.c,v 1.98 2000/08/16 12:33:00 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -18,11 +18,11 @@ #include #include #include -#if 0 /* New RAID code is half-merged... -DaveM */ -#include -#endif +#include #include #include +#include +#include #include #include #include @@ -648,31 +648,69 @@ }; +struct in6_rtmsg32 { + struct in6_addr rtmsg_dst; + struct in6_addr rtmsg_src; + struct in6_addr rtmsg_gateway; + u32 rtmsg_type; + u16 rtmsg_dst_len; + u16 rtmsg_src_len; + u32 rtmsg_metric; + u32 rtmsg_info; + u32 rtmsg_flags; + s32 rtmsg_ifindex; +}; + +extern struct socket *sockfd_lookup(int fd, int *err); + static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct rtentry r; + int ret; + void *r = NULL; + struct in6_rtmsg r6; + struct rtentry r4; char devname[16]; u32 rtdev; - int ret; mm_segment_t old_fs = get_fs(); - ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); - ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); - ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); - ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); - ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window)); - ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); - ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); - if (rtdev) { - ret |= copy_from_user (devname, (char *)A(rtdev), 15); - r.rt_dev = devname; devname[15] = 0; - } else - r.rt_dev = 0; + struct socket *mysock = sockfd_lookup(fd, &ret); + + if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */ + ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), + 3 * sizeof(struct in6_addr)); + ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); + ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len)); + ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len)); + ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric)); + ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info)); + ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags)); + ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex)); + + r = (void *) &r6; + } else { /* ipv4 */ + ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); + ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); + ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); + ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); + ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window)); + ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); + ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); + if (rtdev) { + ret |= copy_from_user (devname, (char *)A(rtdev), 15); + r4.rt_dev = devname; devname[15] = 0; + } else + r4.rt_dev = 0; + + r = (void *) &r4; + } + if (ret) return -EFAULT; + set_fs (KERNEL_DS); - ret = sys_ioctl (fd, cmd, (long)&r); + ret = sys_ioctl (fd, cmd, (long) r); set_fs (old_fs); + return ret; } @@ -3067,17 +3105,27 @@ COMPATIBLE_IOCTL(BLKSECTSET) COMPATIBLE_IOCTL(BLKSSZGET) +/* RAID */ +COMPATIBLE_IOCTL(RAID_VERSION) +COMPATIBLE_IOCTL(GET_ARRAY_INFO) +COMPATIBLE_IOCTL(GET_DISK_INFO) +COMPATIBLE_IOCTL(PRINT_RAID_DEBUG) +COMPATIBLE_IOCTL(CLEAR_ARRAY) +COMPATIBLE_IOCTL(ADD_NEW_DISK) +COMPATIBLE_IOCTL(HOT_REMOVE_DISK) +COMPATIBLE_IOCTL(SET_ARRAY_INFO) +COMPATIBLE_IOCTL(SET_DISK_INFO) +COMPATIBLE_IOCTL(WRITE_RAID_INFO) +COMPATIBLE_IOCTL(UNPROTECT_ARRAY) +COMPATIBLE_IOCTL(PROTECT_ARRAY) +COMPATIBLE_IOCTL(HOT_ADD_DISK) +COMPATIBLE_IOCTL(SET_DISK_FAULTY) +COMPATIBLE_IOCTL(RUN_ARRAY) +COMPATIBLE_IOCTL(START_ARRAY) +COMPATIBLE_IOCTL(STOP_ARRAY) +COMPATIBLE_IOCTL(STOP_ARRAY_RO) +COMPATIBLE_IOCTL(RESTART_ARRAY_RW) -#if 0 /* New RAID code is being merged, fix up to handle - * new RAID ioctls when fully merged in 2.3.x -DaveM - */ -/* 0x09 */ -COMPATIBLE_IOCTL(REGISTER_DEV) -COMPATIBLE_IOCTL(REGISTER_DEV_NEW) -COMPATIBLE_IOCTL(START_MD) -COMPATIBLE_IOCTL(STOP_MD) -#endif - /* Big K */ COMPATIBLE_IOCTL(PIO_FONT) COMPATIBLE_IOCTL(GIO_FONT) diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.4.0-test6/linux/arch/sparc64/kernel/process.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/process.c Fri Aug 18 10:26:25 2000 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.110 2000/07/28 09:43:39 davem Exp $ +/* $Id: process.c,v 1.111 2000/08/16 11:13:12 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -65,6 +65,9 @@ * But this requires writing back the contents of the * L2 cache etc. so implement this later. -DaveM */ + while (!current->need_resched) + barrier(); + schedule(); check_pgt_cache(); } diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.4.0-test6/linux/arch/sparc64/kernel/sparc64_ksyms.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Thu Aug 10 12:43:12 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.91 2000/08/05 13:30:33 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.92 2000/08/09 08:45:40 anton Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -334,3 +334,7 @@ EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); + +void VISenter(void); +/* RAID code needs this */ +EXPORT_SYMBOL(VISenter); diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.4.0-test6/linux/arch/sparc64/kernel/sys_sparc32.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Wed Aug 23 09:30:13 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.159 2000/08/08 02:47:50 davem Exp $ +/* $Id: sys_sparc32.c,v 1.163 2000/08/22 10:09:10 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -45,6 +45,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -866,15 +870,27 @@ old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs (old_fs); + if (ret) return ret; + if (f.l_start >= 0x7fffffffUL || + f.l_len >= 0x7fffffffUL || + f.l_start + f.l_len >= 0x7fffffffUL) + return -EOVERFLOW; if(put_flock(&f, (struct flock32 *)arg)) return -EFAULT; - return ret; + return 0; } default: return sys_fcntl(fd, cmd, (unsigned long)arg); } } +asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + if (cmd >= F_GETLK64 && cmd <= F_SETLKW64) + return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg); + return sys32_fcntl(fd, cmd, arg); +} + struct dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; @@ -1180,7 +1196,7 @@ }; static int fillonedir(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; struct old_linux_dirent32 * dirent; @@ -1235,7 +1251,8 @@ int error; }; -static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino, + unsigned int d_type) { struct linux_dirent32 * dirent; struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf; @@ -2699,42 +2716,86 @@ extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen); -asmlinkage int sys32_setsockopt(int fd, int level, int optname, +static int do_set_attach_filter(int fd, int level, int optname, char *optval, int optlen) { - if (optname == SO_ATTACH_FILTER) { - struct sock_fprog32 { - __u16 len; - __u32 filter; - } *fprog32 = (struct sock_fprog32 *)optval; - struct sock_fprog kfprog; - struct sock_filter *kfilter; - unsigned int fsize; - mm_segment_t old_fs; - __u32 uptr; - int ret; + struct sock_fprog32 { + __u16 len; + __u32 filter; + } *fprog32 = (struct sock_fprog32 *)optval; + struct sock_fprog kfprog; + struct sock_filter *kfilter; + unsigned int fsize; + mm_segment_t old_fs; + __u32 uptr; + int ret; - if (get_user(kfprog.len, &fprog32->len) || - __get_user(uptr, &fprog32->filter)) - return -EFAULT; - kfprog.filter = (struct sock_filter *)A(uptr); - fsize = kfprog.len * sizeof(struct sock_filter); - kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); - if (kfilter == NULL) - return -ENOMEM; - if (copy_from_user(kfilter, kfprog.filter, fsize)) { - kfree(kfilter); - return -EFAULT; - } - kfprog.filter = kfilter; - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_setsockopt(fd, level, optname, - (char *)&kfprog, sizeof(kfprog)); - set_fs(old_fs); + if (get_user(kfprog.len, &fprog32->len) || + __get_user(uptr, &fprog32->filter)) + return -EFAULT; + + kfprog.filter = (struct sock_filter *)A(uptr); + fsize = kfprog.len * sizeof(struct sock_filter); + + kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); + if (kfilter == NULL) + return -ENOMEM; + + if (copy_from_user(kfilter, kfprog.filter, fsize)) { kfree(kfilter); - return ret; + return -EFAULT; + } + + kfprog.filter = kfilter; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, + (char *)&kfprog, sizeof(kfprog)); + set_fs(old_fs); + + kfree(kfilter); + + return ret; +} + +static int do_set_icmpv6_filter(int fd, int level, int optname, + char *optval, int optlen) +{ + struct icmp6_filter kfilter; + mm_segment_t old_fs; + int ret, i; + + if (copy_from_user(&kfilter, optval, sizeof(kfilter))) + return -EFAULT; + + + for (i = 0; i < 8; i += 2) { + u32 tmp = kfilter.data[i]; + + kfilter.data[i] = kfilter.data[i + 1]; + kfilter.data[i + 1] = tmp; } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, + (char *) &kfilter, sizeof(kfilter)); + set_fs(old_fs); + + return ret; +} + +asmlinkage int sys32_setsockopt(int fd, int level, int optname, + char *optval, int optlen) +{ + if (optname == SO_ATTACH_FILTER) + return do_set_attach_filter(fd, level, optname, + optval, optlen); + if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) + return do_set_icmpv6_filter(fd, level, optname, + optval, optlen); + return sys_setsockopt(fd, level, optname, optval, optlen); } @@ -4100,4 +4161,52 @@ return sys_setpriority((int) which, (int) who, (int) niceval); +} + +struct __sysctl_args32 { + u32 name; + int nlen; + u32 oldval; + u32 oldlenp; + u32 newval; + u32 newlen; + u32 __unused[4]; +}; + +extern asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) +{ + struct __sysctl_args32 tmp; + int error; + size_t oldlen, *oldlenp = NULL; + unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7; + + if (copy_from_user(&tmp, args, sizeof(tmp))) + return -EFAULT; + + if (tmp.oldval && tmp.oldlenp) { + /* Duh, this is ugly and might not work if sysctl_args + is in read-only memory, but do_sysctl does indirectly + a lot of uaccess in both directions and we'd have to + basically copy the whole sysctl.c here, and + glibc's __sysctl uses rw memory for the structure + anyway. */ + if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) || + put_user(oldlen, (size_t *)addr)) + return -EFAULT; + oldlenp = (size_t *)addr; + } + + lock_kernel(); + error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval), + oldlenp, (void *)A(tmp.newval), tmp.newlen); + unlock_kernel(); + if (oldlenp) { + if (!error) { + if (get_user(oldlen, (size_t *)addr) || + put_user(oldlen, (u32 *)A(tmp.oldlenp))) + error = -EFAULT; + } + copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); + } + return error; } diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.4.0-test6/linux/arch/sparc64/kernel/sys_sunos32.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/kernel/sys_sunos32.c Sat Aug 12 12:08:49 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.53 2000/07/30 23:12:24 davem Exp $ +/* $Id: sys_sunos32.c,v 1.54 2000/08/12 13:25:41 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -277,7 +277,7 @@ #define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1)) static int sunos_filldir(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct sunos_dirent * dirent; struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; @@ -359,7 +359,7 @@ }; static int sunos_filldirentry(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino) + off_t offset, ino_t ino, unsigned int d_type) { struct sunos_direntry * dirent; struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf; diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.4.0-test6/linux/arch/sparc64/kernel/systbls.S Thu Jul 27 17:38:00 2000 +++ linux/arch/sparc64/kernel/systbls.S Wed Aug 23 09:30:13 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.74 2000/07/13 10:59:13 davem Exp $ +/* $Id: systbls.S,v 1.77 2000/08/22 10:09:10 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -49,8 +49,8 @@ .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64 /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit .word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write -/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall - .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount +/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64 + .word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall /*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents @@ -69,7 +69,7 @@ .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/ .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl .word sys_aplib /* Now the 64-bit native Linux syscall table. */ @@ -108,7 +108,7 @@ .word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit .word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write -/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall +/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64 .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/lib/dec_and_lock.S linux/arch/sparc64/lib/dec_and_lock.S --- v2.4.0-test6/linux/arch/sparc64/lib/dec_and_lock.S Fri Jul 14 12:12:08 2000 +++ linux/arch/sparc64/lib/dec_and_lock.S Sun Aug 13 12:01:54 2000 @@ -1,4 +1,4 @@ -/* $Id: dec_and_lock.S,v 1.1 2000/07/10 20:57:34 davem Exp $ +/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $ * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()" * using cas and ldstub instructions. * @@ -17,12 +17,10 @@ * TMP = *(MEM); * *(MEM) = REG2; * REG2 = TMP; - * } + * } else + * REG2 = *(MEM); * END_ATOMIC(); * } - * - * All non-contention cases are handled in 2 I-cache - * lines which is 1 L2 cache line. */ .globl atomic_dec_and_lock @@ -42,20 +40,24 @@ brnz,pn %g3, spin_on_lock membar #StoreLoad | #StoreStore loop2: cas [%o0], %g5, %g7 /* ASSERT(g7 == 0) */ - brnz,pt %g7, out - mov 1, %g1 + nop + cmp %g5, %g7 + be,pt %icc, out + mov 1, %g1 lduw [%o0], %g5 subcc %g5, 1, %g7 be,pn %icc, loop2 nop membar #StoreStore | #LoadStore stb %g0, [%o1] + b,pt %xcc, nzero nop - spin_on_lock: ldub [%o1], %g3 brnz,pt %g3, spin_on_lock membar #LoadLoad - b,a,pt %xcc, to_zero + ba,pt %xcc, to_zero + nop + nop diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.4.0-test6/linux/arch/sparc64/mm/fault.c Wed Aug 9 19:19:49 2000 +++ linux/arch/sparc64/mm/fault.c Sat Aug 12 12:08:50 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.49 2000/08/09 00:00:15 davem Exp $ +/* $Id: fault.c,v 1.50 2000/08/11 03:00:13 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -42,7 +42,7 @@ sp_banks[0].base_addr = base_paddr; sp_banks[0].num_bytes = bytes; - while (mlist->theres_more != (void *) 0){ + while (mlist->theres_more != (void *) 0) { i++; mlist = mlist->theres_more; bytes = mlist->num_bytes; @@ -68,7 +68,7 @@ /* Now mask all bank sizes on a page boundary, it is all we can * use anyways. */ - for(i=0; sp_banks[i].num_bytes != 0; i++) + for (i = 0; sp_banks[i].num_bytes != 0; i++) sp_banks[i].num_bytes &= PAGE_MASK; return tally; @@ -77,7 +77,7 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk, struct pt_regs *regs) { - if((unsigned long) address < PAGE_SIZE) { + if ((unsigned long) address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL " "pointer dereference\n"); } else { @@ -100,17 +100,17 @@ unsigned long pa; u32 insn = 0; - if(pgd_none(*pgdp)) + if (pgd_none(*pgdp)) goto out; pmdp = pmd_offset(pgdp, tpc); - if(pmd_none(*pmdp)) + if (pmd_none(*pmdp)) goto out; ptep = pte_offset(pmdp, tpc); pte = *ptep; - if(!pte_present(pte)) + if (!pte_present(pte)) goto out; - pa = phys_base + (sparc64_pte_pagenr(pte) << PAGE_SHIFT); + pa = (pte_val(pte) & _PAGE_PADDR); pa += (tpc & ~PAGE_MASK); /* Use phys bypass so we don't pollute dtlb/dcache. */ diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.4.0-test6/linux/arch/sparc64/solaris/misc.c Mon Jul 10 16:47:21 2000 +++ linux/arch/sparc64/solaris/misc.c Fri Aug 18 10:26:25 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.28 2000/07/06 01:41:30 davem Exp $ +/* $Id: misc.c,v 1.29 2000/08/14 23:50:31 anton Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -20,7 +20,6 @@ #include #include #include -#include #include "conv.h" @@ -179,26 +178,7 @@ static char *platform(char *buffer) { - int i, len; - struct { - char *platform; - int id_machtype; - } platforms [] = { - { "sun4", (SM_SUN4 | SM_4_110) }, - { "sun4", (SM_SUN4 | SM_4_260) }, - { "sun4", (SM_SUN4 | SM_4_330) }, - { "sun4", (SM_SUN4 | SM_4_470) }, - { "SUNW,Sun_4_60", (SM_SUN4C | SM_4C_SS1) }, - { "SUNW,Sun_4_40", (SM_SUN4C | SM_4C_IPC) }, - { "SUNW,Sun_4_65", (SM_SUN4C | SM_4C_SS1PLUS) }, - { "SUNW,Sun_4_20", (SM_SUN4C | SM_4C_SLC) }, - { "SUNW,Sun_4_75", (SM_SUN4C | SM_4C_SS2) }, - { "SUNW,Sun_4_25", (SM_SUN4C | SM_4C_ELC) }, - { "SUNW,Sun_4_50", (SM_SUN4C | SM_4C_IPX) }, - { "SUNW,Sun_4_600", (SM_SUN4M | SM_4M_SS60) }, - { "SUNW,SPARCstation-5", (SM_SUN4M | SM_4M_SS50) }, - { "SUNW,SPARCstation-20", (SM_SUN4M | SM_4M_SS40) } - }; + int len; *buffer = 0; len = prom_getproperty(prom_root_node, "name", buffer, 256); @@ -211,10 +191,8 @@ if (*p == '/' || *p == ' ') *p = '_'; return buffer; } - for (i = 0; i < sizeof (platforms)/sizeof (platforms[0]); i++) - if (platforms[i].id_machtype == idprom->id_machtype) - return platforms[i].platform; - return "sun4c"; + + return "sun4u"; } static char *serial(char *buffer) diff -u --recursive --new-file v2.4.0-test6/linux/arch/sparc64/solaris/socket.c linux/arch/sparc64/solaris/socket.c --- v2.4.0-test6/linux/arch/sparc64/solaris/socket.c Wed Dec 29 13:13:15 1999 +++ linux/arch/sparc64/solaris/socket.c Fri Aug 18 10:26:25 2000 @@ -1,4 +1,4 @@ -/* $Id: socket.c,v 1.2 1999/09/22 09:28:50 davem Exp $ +/* $Id: socket.c,v 1.3 2000/08/14 23:50:31 anton Exp $ * socket.c: Socket syscall emulation for Solaris 2.6+ * * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -18,7 +18,6 @@ #include #include #include -#include #include "conv.h" diff -u --recursive --new-file v2.4.0-test6/linux/drivers/Makefile linux/drivers/Makefile --- v2.4.0-test6/linux/drivers/Makefile Wed Aug 9 19:19:49 2000 +++ linux/drivers/Makefile Tue Aug 22 11:41:14 2000 @@ -7,12 +7,12 @@ # # Note 2! The CFLAGS definitions are now in the main makefile. -SUB_DIRS := block char net parport sound misc +SUB_DIRS := block char net parport sound misc media MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci sgi ide scsi sbus cdrom isdn pnp i2o \ ieee1394 macintosh video dio zorro fc4 \ usb nubus tc atm pcmcia i2c telephony \ - acpi mtd + acpi mtd input ifdef CONFIG_DIO SUB_DIRS += dio @@ -74,6 +74,15 @@ else ifeq ($(CONFIG_USB),m) MOD_SUB_DIRS += usb + endif +endif + +ifeq ($(CONFIG_INPUT),y) +SUB_DIRS += input +MOD_SUB_DIRS += input +else + ifeq ($(CONFIG_INPUT),m) + MOD_SUB_DIRS += input endif endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/acorn/block/Makefile linux/drivers/acorn/block/Makefile --- v2.4.0-test6/linux/drivers/acorn/block/Makefile Wed Aug 9 19:19:49 2000 +++ linux/drivers/acorn/block/Makefile Sun Aug 13 09:54:15 2000 @@ -9,6 +9,8 @@ # parent makefile. # +USE_STANDARD_AS_RULE := true + L_TARGET := acorn-block.a obj-y := diff -u --recursive --new-file v2.4.0-test6/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.4.0-test6/linux/drivers/acorn/block/fd1772.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/acorn/block/fd1772.c Sun Aug 13 09:54:15 2000 @@ -142,6 +142,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/drivers/acorn/char/Makefile linux/drivers/acorn/char/Makefile --- v2.4.0-test6/linux/drivers/acorn/char/Makefile Thu Jul 27 17:38:00 2000 +++ linux/drivers/acorn/char/Makefile Sun Aug 13 09:54:15 2000 @@ -35,7 +35,12 @@ obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o # Do the i2c and rtc last -obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o +obj-y += $(obj-$(MACHINE)) + +# CL-PS7500 does not have these devices. +ifneq ($(CONFIG_ARCH_CLPS7500),y) +obj-y += i2c.o pcf8583.o +endif O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/acorn/scsi/Makefile linux/drivers/acorn/scsi/Makefile --- v2.4.0-test6/linux/drivers/acorn/scsi/Makefile Wed Aug 9 19:19:49 2000 +++ linux/drivers/acorn/scsi/Makefile Sun Aug 13 09:54:15 2000 @@ -2,6 +2,8 @@ # Makefile for drivers/acorn/scsi # +USE_STANDARD_AS_RULE := true + L_TARGET := acorn-scsi.a obj-y := diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.4.0-test6/linux/drivers/block/DAC960.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/DAC960.c Mon Aug 21 09:23:54 2000 @@ -19,8 +19,8 @@ */ -#define DAC960_DriverVersion "2.4.7" -#define DAC960_DriverDate "1 August 2000" +#define DAC960_DriverVersion "2.4.8" +#define DAC960_DriverDate "19 August 2000" #include @@ -2206,7 +2206,6 @@ Controller->Bus = Bus; Controller->Device = Device; Controller->Function = Function; - sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); /* Map the Controller Register Window. */ @@ -3756,15 +3755,15 @@ { 0x008D, "M Rebuild Failed for Unknown Reasons" }, { 0x008E, "M Rebuild Failed due to New Physical Device" }, { 0x008F, "M Rebuild Failed due to Logical Drive Failure" }, - { 0x0090, "L Initialization Started" }, - { 0x0091, "L Initialization Completed" }, - { 0x0092, "L Initialization Cancelled" }, - { 0x0093, "L Initialization Failed" }, + { 0x0090, "M Initialization Started" }, + { 0x0091, "M Initialization Completed" }, + { 0x0092, "M Initialization Cancelled" }, + { 0x0093, "M Initialization Failed" }, { 0x0094, "L Found" }, { 0x0095, "L Gone" }, - { 0x0096, "L Expand Capacity Started" }, - { 0x0097, "L Expand Capacity Completed" }, - { 0x0098, "L Expand Capacity Failed" }, + { 0x0096, "M Expand Capacity Started" }, + { 0x0097, "M Expand Capacity Completed" }, + { 0x0098, "M Expand Capacity Failed" }, { 0x0099, "L Bad Block Found" }, { 0x009A, "L Size Changed" }, { 0x009B, "L Type Changed" }, @@ -3799,6 +3798,12 @@ { 0, "" } }; int EventListIndex = 0, EventCode; unsigned char EventType, *EventMessage; + if (Event->EventCode == 0x1C && + RequestSense->SenseKey == DAC960_SenseKey_VendorSpecific && + (RequestSense->AdditionalSenseCode == 0x80 || + RequestSense->AdditionalSenseCode == 0x81)) + Event->EventCode = ((RequestSense->AdditionalSenseCode - 0x80) << 8) | + RequestSense->AdditionalSenseCodeQualifier; while (true) { EventCode = EventList[EventListIndex].EventCode; @@ -3862,6 +3867,7 @@ RequestSense->CommandSpecificInformation[3]); break; case 'E': + if (Controller->SuppressEnclosureMessages) break; sprintf(MessageBuffer, EventMessage, Event->LogicalUnit); DAC960_Critical("Enclosure %d %s\n", Controller, Event->TargetID, MessageBuffer); @@ -4274,7 +4280,7 @@ LogicalDeviceSize); else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress) DAC960_V2_ReportProgress(Controller, - "BackgroundInitialization", + "Background Initialization", LogicalDeviceNumber, NewLogicalDeviceInfo ->BackgroundInitializationBlockNumber, @@ -4900,6 +4906,7 @@ DiskGeometry_T Geometry, *UserGeometry; DAC960_Controller_T *Controller; int PartitionNumber; + if (File == NULL) return -EINVAL; if (File->f_flags & O_NONBLOCK) return DAC960_UserIOCTL(Inode, File, Request, Argument); if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) @@ -5106,6 +5113,7 @@ ErrorCode = copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T)); if (ErrorCode != 0) goto Failure1; + if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB.Direction == DAC960_V1_DCDB_NoDataTransfer) || @@ -5434,6 +5442,7 @@ if (CommandOpcode == DAC960_V1_DCDB) { DCDB = KernelCommand->DCDB; + if (DCDB->Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB->Direction == DAC960_V1_DCDB_NoDataTransfer) || (DataTransferLength > 0 && @@ -6246,6 +6255,8 @@ == DAC960_V2_NormalCompletion ? "Cancelled" : "Not Cancelled")); } + else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0) + Controller->SuppressEnclosureMessages = true; else DAC960_UserCritical("Illegal User Command: '%s'\n", Controller, UserCommand); DAC960_AcquireControllerLock(Controller, &ProcessorFlags); @@ -6425,6 +6436,7 @@ PROC_DirectoryEntry_T *ControllerProcEntry; PROC_DirectoryEntry_T *UserCommandProcEntry; if (Controller == NULL) continue; + sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); ControllerProcEntry = proc_mkdir(Controller->ControllerName, DAC960_ProcDirectoryEntry); create_proc_read_entry("initial_status", 0, ControllerProcEntry, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/DAC960.h linux/drivers/block/DAC960.h --- v2.4.0-test6/linux/drivers/block/DAC960.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/DAC960.h Mon Aug 21 09:23:54 2000 @@ -1911,26 +1911,6 @@ /* - Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. -*/ - -static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress) -{ - return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress); -} - - -/* - Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. -*/ - -static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress) -{ - return (void *) bus_to_virt(BusAddress); -} - - -/* DAC960_DriverVersion protects the private portion of this file. */ @@ -2317,6 +2297,7 @@ boolean EphemeralProgressMessage; boolean DriveSpinUpMessageDisplayed; boolean MonitoringAlertMode; + boolean SuppressEnclosureMessages; Timer_T MonitoringTimer; GenericDiskInfo_T GenericDiskInfo; DAC960_Command_T *FreeCommands; @@ -2518,6 +2499,26 @@ ProcessorFlags_T *ProcessorFlags) { spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. +*/ + +static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress) +{ + return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress); +} + + +/* + Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. +*/ + +static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress) +{ + return (void *) bus_to_virt(BusAddress); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/elevator.c linux/drivers/block/elevator.c --- v2.4.0-test6/linux/drivers/block/elevator.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/block/elevator.c Tue Aug 22 22:33:46 2000 @@ -14,6 +14,10 @@ * an existing request * - elevator_dequeue_fn, called when a request is taken off the active list * + * 20082000 Dave Jones : + * Removed tests for max-bomb-segments, which was breaking elvtune + * when run without -bN + * */ #include @@ -147,7 +151,7 @@ output.queue_ID = elevator->queue_ID; output.read_latency = elevator->read_latency; output.write_latency = elevator->write_latency; - output.max_bomb_segments = elevator->max_bomb_segments; + output.max_bomb_segments = 0; if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t))) return -EFAULT; @@ -166,13 +170,9 @@ return -EINVAL; if (input.write_latency < 0) return -EINVAL; - if (input.max_bomb_segments <= 0) - return -EINVAL; elevator->read_latency = input.read_latency; elevator->write_latency = input.write_latency; - elevator->max_bomb_segments = input.max_bomb_segments; - return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v2.4.0-test6/linux/drivers/block/linear.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/block/linear.c Thu Aug 10 12:35:50 2000 @@ -144,7 +144,7 @@ if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) { - printk ("linear_make_request: Block %ld out of bounds on dev %s size %d offset %d\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); + printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); return -1; } bh->b_rdev = tmp_dev->dev; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.4.0-test6/linux/drivers/block/ll_rw_blk.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/ll_rw_blk.c Mon Aug 14 08:26:34 2000 @@ -182,8 +182,8 @@ * Currently, its primary task it to free all the &struct request structures * that were allocated to the queue. * Caveat: - * Hopefully the low level driver will have finished any outstanding requests - * first... + * Hopefully the low level driver will have finished any outstanding + * requests first... **/ void blk_cleanup_queue(request_queue_t * q) { @@ -204,21 +204,23 @@ * @active: A flag indication where the head of the queue is active. * * Description: - * The driver for a block device may choose to leave the currently active request - * on the request queue, removing it only when it has completed. The queue - * handling routines assume this by default and will not involved the head of the - * request queue in any merging or reordering of requests. - * - * If a driver removes requests from the queue before processing them, then it may - * indicate that it does so, there by allowing the head of the queue to be involved - * in merging and reordering. This is done be calling blk_queue_headactive() with an - * @active flag of %1. + * The driver for a block device may choose to leave the currently active + * request on the request queue, removing it only when it has completed. + * The queue handling routines assume this by default for safety reasons + * and will not involve the head of the request queue in any merging or + * reordering of requests when the queue is unplugged (and thus may be + * working on this particular request). + * + * If a driver removes requests from the queue before processing them, then + * it may indicate that it does so, there by allowing the head of the queue + * to be involved in merging and reordering. This is done be calling + * blk_queue_headactive() with an @active flag of %0. * - * If a driver processes several requests at once, it must remove them (or at least all - * but one of them) from the request queue. + * If a driver processes several requests at once, it must remove them (or + * at least all but one of them) from the request queue. * - * When a queue is plugged (see blk_queue_pluggable()) the head will be assumed to - * be inactive. + * When a queue is plugged (see blk_queue_pluggable()) the head will be + * assumed to be inactive. **/ void blk_queue_headactive(request_queue_t * q, int active) @@ -236,9 +238,9 @@ * is empty. This allows a number of requests to be added before any are * processed, thus providing an opportunity for these requests to be merged * or re-ordered. - * The default plugging function (generic_plug_device()) sets the "plugged" flag - * for the queue and adds a task the the $tq_disk task queue to unplug the - * queue and call the request function at a later time. + * The default plugging function (generic_plug_device()) sets the "plugged" + * flag for the queue and adds a task to the $tq_disk task queue to unplug + * the queue and call the request function at a later time. * * A device driver may provide an alternate plugging function by passing it to * blk_queue_pluggable(). This function should set the "plugged" flag if it @@ -259,15 +261,14 @@ * @mfn: the alternate make_request function * * Description: - * The normal way for &struct buffer_heads to be passes to a device driver it to - * collect into requests on a request queue, and allow the device driver to select - * requests off that queue when it is ready. This works well for many block devices. - * However some block devices (typically virtual devices such as md or lvm) do not benefit - * from the processes on the request queue, and are served best by having the requests passed - * directly to them. This can be achived by providing a function to blk_queue_make_request(). - * If this is done, then the rest of the &request_queue_t structure is unused (unless the alternate - * make_request function explicitly uses it). In particular, there is no need to call - * blk_init_queue() if blk_queue_make_request() has been called. + * The normal way for &struct buffer_heads to be passed to a device driver + * it to collect into requests on a request queue, and allow the device + * driver to select requests off that queue when it is ready. This works + * well for many block devices. However some block devices (typically + * virtual devices such as md or lvm) do not benefit from the processes on + * the request queue, and are served best by having the requests passed + * directly to them. This can be achieved by providing a function to + * blk_queue_make_request(). **/ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) @@ -390,32 +391,30 @@ * placed on the queue. * * Description: - * If a block device wishes to use the stand request handling procedures, - * which sorts requests and coalesces adjactent requests, then it must + * If a block device wishes to use the standard request handling procedures, + * which sorts requests and coalesces adjacent requests, then it must * call blk_init_queue(). The function @rfn will be called when there * are requests on the queue that need to be processed. If the device - * supports plugging, then @rfn may not be called immediately that requests + * supports plugging, then @rfn may not be called immediately when requests * are available on the queue, but may be called at some time later instead. + * Plugged queues are generally unplugged when a buffer belonging to one + * of the requests on the queue is needed, or due to memory pressure. * - * @rfn is not required, or even expected, to remove all requests off the queue, but - * only as many as it can handle at a time. If it does leave requests on the queue, - * it is responsible for arranging that the requests get dealt with eventually. - * - * A global spin lock $io_spin_lock must held while manipulating the requests - * on the request queue. - * - * The request on the head of the queue is by default assumed to be potentially active, - * and it is not considered for re-ordering or merging. This behaviour can - * be changed with blk_queue_headactive(). + * @rfn is not required, or even expected, to remove all requests off the + * queue, but only as many as it can handle at a time. If it does leave + * requests on the queue, it is responsible for arranging that the requests + * get dealt with eventually. + * + * A global spin lock $io_request_lock must be held while manipulating the + * requests on the request queue. + * + * The request on the head of the queue is by default assumed to be + * potentially active, and it is not considered for re-ordering or merging + * whenever the given queue is unplugged. This behaviour can be changed with + * blk_queue_headactive(). * * Note: - * blk_init_queue() does not need to be called if - * blk_queue_make_request() has been called to register an alternate - * request handler. Ofcourse, it may be called if the handler wants - * to still use the fields on &request_queue_t, but in a non-standard - * way. - * - * blk_init_queue() should be paired with a blk_cleanup-queue() call + * blk_init_queue() must be paired with a blk_cleanup-queue() call * when the block device is deactivated (such as at module unload). **/ static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); @@ -697,19 +696,7 @@ rw_ahead = 1; rw = READ; /* drop into READ */ case READ: - if (buffer_uptodate(bh)) /* Hmmph! Already have it */ - goto end_io; - kstat.pgpgin++; - break; - case WRITERAW: - rw = WRITE; - goto do_write; /* Skip the buffer refile */ case WRITE: - if (!test_and_clear_bit(BH_Dirty, &bh->b_state)) - goto end_io; /* Hmmph! Nothing to write */ - refile_buffer(bh); - do_write: - kstat.pgpgout++; break; default: BUG(); @@ -942,6 +929,30 @@ set_bit(BH_Req, &bh->b_state); + switch(rw) { + case WRITE: + if (!atomic_set_buffer_clean(bh)) + /* Hmmph! Nothing to write */ + goto end_io; + __mark_buffer_clean(bh); + kstat.pgpgout++; + break; + + case READA: + case READ: + if (buffer_uptodate(bh)) + /* Hmmph! Already have it */ + goto end_io; + kstat.pgpgin++; + break; + default: + BUG(); + end_io: + bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); + continue; + + } + /* * First step, 'identity mapping' - RAID or LVM might * further remap this. @@ -1022,6 +1033,9 @@ request_cachep = kmem_cache_create("blkdev_requests", sizeof(struct request), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + + if (!request_cachep) + panic("Can't create request pool slab cache\n"); for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) dev->queue = NULL; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.4.0-test6/linux/drivers/block/md.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/md.c Tue Aug 22 09:10:46 2000 @@ -1520,22 +1520,22 @@ md_size[mdidx(mddev)] = sb->size * data_disks; readahead = MD_READAHEAD; - if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) - readahead = mddev->sb->chunk_size * 4 * data_disks; - if (readahead < data_disks * MAX_SECTORS*512*2) - readahead = data_disks * MAX_SECTORS*512*2; - else { + if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) { + readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; + if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2) + readahead = data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2; + } else { if (sb->level == -3) readahead = 0; } md_maxreadahead[mdidx(mddev)] = readahead; - printk(KERN_INFO "md%d: max total readahead window set to %dk\n", - mdidx(mddev), readahead/1024); + printk(KERN_INFO "md%d: max total readahead window set to %ldk\n", + mdidx(mddev), readahead*(PAGE_SIZE/1024)); printk(KERN_INFO - "md%d: %d data-disks, max readahead per data-disk: %dk\n", - mdidx(mddev), data_disks, readahead/data_disks/1024); + "md%d: %d data-disks, max readahead per data-disk: %ldk\n", + mdidx(mddev), data_disks, readahead/data_disks*(PAGE_SIZE/1024)); return 0; abort: return 1; @@ -3318,7 +3318,7 @@ /* * Tune reconstruction: */ - window = md_maxreadahead[mdidx(mddev)]/1024; + window = MAX_READAHEAD*(PAGE_SIZE/1024); printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window,max_blocks); atomic_set(&mddev->recovery_active, 0); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/raid0.c linux/drivers/block/raid0.c --- v2.4.0-test6/linux/drivers/block/raid0.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/raid0.c Thu Aug 10 12:35:50 2000 @@ -103,7 +103,7 @@ zone->nb_dev = c; zone->size = (smallest->size - current_offset) * c; - printk(" zone->nb_dev: %d, size: %d\n",zone->nb_dev,zone->size); + printk(" zone->nb_dev: %d, size: %ld\n",zone->nb_dev,zone->size); if (!conf->smallest || (zone->size < conf->smallest->size)) conf->smallest = zone; @@ -112,7 +112,7 @@ curr_zone_offset += zone->size; current_offset = smallest->size; - printk("current zone offset: %d\n", current_offset); + printk("current zone offset: %ld\n", current_offset); } printk("done.\n"); return 0; @@ -139,7 +139,7 @@ goto out_free_conf; printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); - printk("raid0 : conf->smallest->size is %d blocks.\n", conf->smallest->size); + printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size); nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); printk("raid0 : nb_zone is %ld.\n", nb_zone); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/raid1.c linux/drivers/block/raid1.c --- v2.4.0-test6/linux/drivers/block/raid1.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/raid1.c Mon Aug 14 08:26:34 2000 @@ -564,28 +564,6 @@ if (rw == READA) rw = READ; - if (rw == WRITE) { - rw = WRITERAW; - /* - * we first clean the bh, then we start the IO, then - * when the IO has finished, we end_io the bh and - * mark it uptodate. This way we do not miss the - * case when the bh got dirty again during the IO. - * - * We do an important optimization here - if the - * buffer was not dirty and we are during resync or - * reconstruction, then we can skip writing it back - * to the master disk! (we still have to write it - * back to the other disks, because we are not sync - * yet.) - */ - if (atomic_set_buffer_clean(bh)) - __mark_buffer_clean(bh); - else { - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - return 0; - } - } r1_bh = raid1_alloc_r1bh (conf); spin_lock_irq(&conf->segment_lock); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/raid5.c linux/drivers/block/raid5.c --- v2.4.0-test6/linux/drivers/block/raid5.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/block/raid5.c Mon Aug 14 08:26:34 2000 @@ -863,8 +863,7 @@ if (!sh->bh_copy[i]) sh->bh_copy[i] = raid5_alloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_copy[i], i); - if (atomic_set_buffer_clean(sh->bh_new[i])) - atomic_set_buffer_dirty(sh->bh_copy[i]); + atomic_set_buffer_dirty(sh->bh_copy[i]); memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size); } if (sh->bh_copy[pd_idx] == NULL) { @@ -995,28 +994,12 @@ } -static int is_stripe_allclean(struct stripe_head *sh, int disks) -{ - int i; - - return 0; - for (i = 0; i < disks; i++) { - if (sh->bh_new[i]) - if (test_bit(BH_Dirty, &sh->bh_new[i])) - return 0; - if (sh->bh_old[i]) - if (test_bit(BH_Dirty, &sh->bh_old[i])) - return 0; - } - return 1; -} - static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, struct stripe_head *sh, int nr_write, int * operational, int disks, int parity, int parity_failed, int nr_cache, int nr_cache_other, int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) { - int i, allclean; + int i; unsigned int block; struct buffer_head *bh; int method1 = INT_MAX, method2 = INT_MAX; @@ -1068,7 +1051,6 @@ PRINTK("handle_stripe(), sector %lu, nr_write %d, method1 %d, method2 %d\n", sh->sector, nr_write, method1, method2); if (!method1 || !method2) { - allclean = is_stripe_allclean(sh, disks); sh->phase = PHASE_WRITE; compute_parity(sh, method1 <= method2 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); @@ -1087,24 +1069,11 @@ PRINTK("writing spare %d\n", i); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->spare->dev; - generic_make_request(WRITERAW, bh); + generic_make_request(WRITE, bh); } else { -#if 0 atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[i].dev; - generic_make_request(WRITERAW, bh); -#else - if (!allclean || (i==sh->pd_idx)) { - PRINTK("writing dirty %d\n", i); - atomic_inc(&sh->nr_pending); - bh->b_dev = bh->b_rdev = conf->disks[i].dev; - generic_make_request(WRITERAW, bh); - } else { - PRINTK("not writing clean %d\n", i); - raid5_end_request(bh, 1); - sh->new[i] = 0; - } -#endif + generic_make_request(WRITE, bh); } atomic_dec(&bh->b_count); } @@ -1282,7 +1251,7 @@ atomic_inc(&sh->nr_pending); lock_get_bh(bh); bh->b_dev = bh->b_rdev = conf->spare->dev; - generic_make_request(WRITERAW, bh); + generic_make_request(WRITE, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu, phase WRITE, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); @@ -1308,7 +1277,7 @@ lock_get_bh(bh); atomic_inc(&sh->nr_pending); bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev; - generic_make_request(WRITERAW, bh); + generic_make_request(WRITE, bh); md_sync_acct(bh->b_rdev, bh->b_size/512); atomic_dec(&bh->b_count); PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n", diff -u --recursive --new-file v2.4.0-test6/linux/drivers/block/xor.c linux/drivers/block/xor.c --- v2.4.0-test6/linux/drivers/block/xor.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/block/xor.c Sat Aug 12 12:08:50 2000 @@ -1175,7 +1175,7 @@ wr %%g0, 0, %%fprs " : : "i" (&((struct buffer_head *)0)->b_data), - "i" (&((struct buffer_head *)0)->b_data), + "i" (&((struct buffer_head *)0)->b_size), "i" (FPRS_FEF|FPRS_DU), "i" (ASI_BLK_P), "i" (FPRS_FEF), "i" (VISenter)); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.4.0-test6/linux/drivers/char/Config.in Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/Config.in Tue Aug 22 11:29:02 2000 @@ -8,7 +8,7 @@ if [ "$CONFIG_VT" = "y" ]; then bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE fi -tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL +tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE if [ "$CONFIG_ARCH_ACORN" = "y" ]; then @@ -60,6 +60,15 @@ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi fi +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'DC21285 serial port support' CONFIG_SERIAL_21285 + if [ "$CONFIG_SERIAL_21285" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD + fi + bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE + fi +fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 @@ -124,8 +133,9 @@ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT - tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD + tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then @@ -154,98 +164,7 @@ bool 'Tadpole ANA H8 Support' CONFIG_H8 fi -mainmenu_option next_comment -comment 'Video For Linux' - -tristate 'Video For Linux' CONFIG_VIDEO_DEV -if [ "$CONFIG_VIDEO_DEV" != "n" ]; then - bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS Y - dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C - comment 'Radio Adapters' - dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV - dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then - hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f - fi - dep_tristate ' AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then - hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c - fi - dep_tristate ' Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then - hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 - fi - dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then - hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c - fi - dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV - dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then - hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 - fi - dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then - hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 - fi - dep_tristate ' Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_TRUST" = "y" ]; then - hex ' Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350 - fi - dep_tristate ' Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV - if [ "$CONFIG_PROC_FS" = "y" ]; then - if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then - bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS - fi - fi - if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then - hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316 - int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500 - fi - dep_tristate ' Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then - hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c - fi - comment 'Video Adapters' - if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT - fi - dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV - if [ "$CONFIG_ALL_PPC" = "y" ]; then - dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV - fi - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - fi - fi - dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV - if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then - if [ "CONFIG_PARPORT_1284" != "n" ]; then - dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT - fi - if [ "$CONFIG_USB" != "n" ]; then - dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB - fi - fi - dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C - dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_SGI" = "y" ]; then - dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI - fi - dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI - fi - dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI - dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN - dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C -fi - -endmenu - tristate 'Double Talk PC internal speech card support' CONFIG_DTLK - tristate 'Siemens R3964 line discipline' CONFIG_R3964 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.0-test6/linux/drivers/char/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/Makefile Tue Aug 22 11:41:14 2000 @@ -36,12 +36,11 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \ - misc.o pty.o random.o selection.o serial.o videodev.o \ - tty_io.o bttv-if.o cpia.o +export-objs := busmouse.o console.o keyboard.o sysrq.o \ + misc.o pty.o random.o selection.o serial.o \ + tty_io.o -list-multi := bttv.o -bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o +list-multi := KEYMAP =defkeymap.o KEYBD =pc_keyb.o @@ -65,11 +64,12 @@ endif ifeq ($(ARCH),arm) -# we actually need to be able to select various different keymaps -# and keyboards dependent on which actual machine we're going to -# run on. - KEYMAP = - KEYBD = + ifneq ($(CONFIG_PC_KEYMAP),y) + KEYMAP = + endif + ifneq ($(CONFIG_PC_KEYB),y) + KEYBD = + endif endif ifeq ($(ARCH),sh) @@ -142,12 +142,12 @@ obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o -ifeq ($(CONFIG_JOYSTICK),y) +ifeq ($(CONFIG_INPUT),y) obj-y += joystick/js.o SUB_DIRS += joystick MOD_SUB_DIRS += joystick else - ifeq ($(CONFIG_JOYSTICK),m) + ifeq ($(CONFIG_INPUT),m) MOD_SUB_DIRS += joystick endif endif @@ -175,44 +175,12 @@ obj-$(CONFIG_NVRAM) += nvram.o endif -obj-$(CONFIG_VIDEO_DEV) += videodev.o - obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_I810_TCO) += i810-tco.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o -obj-$(CONFIG_BUS_I2C) += i2c-old.o -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \ - tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o -obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o - -obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o -obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o -obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o -obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o -obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o -obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o -obj-$(CONFIG_VIDEO_PMS) += pms.o -obj-$(CONFIG_VIDEO_PLANB) += planb.o -obj-$(CONFIG_VIDEO_VINO) += vino.o -obj-$(CONFIG_VIDEO_STRADIS) += stradis.o -obj-$(CONFIG_VIDEO_CPIA) += cpia.o -obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o -obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o -obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o -obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o -obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o -obj-$(CONFIG_RADIO_CADET) += radio-cadet.o -obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o -obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o -obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o -obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o -obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o -obj-$(CONFIG_RADIO_TRUST) += radio-trust.o -obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o ifeq ($(CONFIG_FTAPE),y) @@ -300,10 +268,3 @@ defkeymap.c: defkeymap.map loadkeys --mktable defkeymap.map > defkeymap.c - -zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o - $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o - -bttv.o: $(bttv-objs) - $(LD) $(LD_RFLAG) -r -o $@ $(bttv-objs) - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h --- v2.4.0-test6/linux/drivers/char/agp/agp.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/agp/agp.h Sun Aug 13 19:37:15 2000 @@ -154,8 +154,11 @@ #ifndef PCI_DEVICE_ID_VIA_82C691_0 #define PCI_DEVICE_ID_VIA_82C691_0 0x0691 #endif -#ifndef PCI_DEVICE_ID_VIA_82C691_1 -#define PCI_DEVICE_ID_VIA_82C691_1 0x8691 +#ifndef PCI_DEVICE_ID_VIA_8371_0 +#define PCI_DEVICE_ID_VIA_8371_0 0x0391 +#endif +#ifndef PCI_DEVICE_ID_VIA_8363_0 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 #endif #ifndef PCI_DEVICE_ID_INTEL_810_0 #define PCI_DEVICE_ID_INTEL_810_0 0x7120 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.4.0-test6/linux/drivers/char/agp/agpgart_be.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/agp/agpgart_be.c Mon Aug 21 08:08:12 2000 @@ -67,14 +67,16 @@ { #if defined(__i386__) asm volatile ("wbinvd":::"memory"); -#elif defined(__alpha__) +#elif defined(__alpha__) || defined(__ia64__) /* ??? I wonder if we'll really need to flush caches, or if the core logic can manage to keep the system coherent. The ARM speaks only of using `cflush' to get things in memory in preparation for power failure. If we do need to call `cflush', we'll need a target page, - as we can only flush one page at a time. */ + as we can only flush one page at a time. + + Ditto for IA-64. --davidm 00/08/07 */ mb(); #else #error "Please define flush_cache." @@ -412,10 +414,9 @@ /* * Driver routines - start - * Currently this module supports the - * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, - * amd irongate, ALi M1541 and generic support for the - * SiS chipsets. + * Currently this module supports the following chipsets: + * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, via kx133, via kt133, + * amd irongate, ALi M1541, and generic support for the SiS chipsets. */ /* Generic Agp routines - Start */ @@ -637,7 +638,7 @@ } table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); - for (page = virt_to_page(table); page < virt_to_page(table_end); page++) + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) set_bit(PG_reserved, &page->flags); agp_bridge.gatt_table_real = (unsigned long *) table; @@ -647,7 +648,7 @@ CACHE_FLUSH(); if (agp_bridge.gatt_table == NULL) { - for (page = virt_to_page(table); page < virt_to_page(table_end); page++) + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) clear_bit(PG_reserved, &page->flags); free_pages((unsigned long) table, page_order); @@ -704,7 +705,7 @@ table = (char *) agp_bridge.gatt_table_real; table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); - for (page = virt_to_page(table); page < virt_to_page(table_end); page++) + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) clear_bit(PG_reserved, &page->flags); free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); @@ -976,6 +977,7 @@ agp_bridge.scratch_page); } + CACHE_FLUSH(); agp_bridge.tlb_flush(mem); return 0; } @@ -2127,12 +2129,6 @@ #endif /* CONFIG_AGP_SIS */ #ifdef CONFIG_AGP_VIA - { PCI_DEVICE_ID_VIA_8371_0, - PCI_VENDOR_ID_VIA, - VIA_APOLLO_SUPER, - "Via", - "Apollo Super", - via_generic_setup }, { PCI_DEVICE_ID_VIA_8501_0, PCI_VENDOR_ID_VIA, VIA_MVP4, @@ -2156,6 +2152,18 @@ VIA_APOLLO_PRO, "Via", "Apollo Pro", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_8371_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_KX133, + "Via", + "Apollo Pro KX133", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_8363_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_KT133, + "Via", + "Apollo Pro KT133", via_generic_setup }, { 0, PCI_VENDOR_ID_VIA, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/audiochip.h linux/drivers/char/audiochip.h --- v2.4.0-test6/linux/drivers/char/audiochip.h Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/audiochip.h Wed Dec 31 16:00:00 1969 @@ -1,60 +0,0 @@ -#ifndef AUDIOCHIP_H -#define AUDIOCHIP_H - -/* ---------------------------------------------------------------------- */ - -#define MIN(a,b) (((a)>(b))?(b):(a)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - -/* v4l device was opened in Radio mode */ -#define AUDC_SET_RADIO _IO('m',2) -/* select from TV,radio,extern,MUTE */ -#define AUDC_SET_INPUT _IOW('m',17,int) - -/* all the stuff below is obsolete and just here for reference. I'll - * remove it once the driver is tested and works fine. - * - * Instead creating alot of tiny API's for all kinds of different - * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not - * yet...). It is a bit less flexible, but most/all used i2c chips - * make sense in v4l context only. So I think that's acceptable... - */ - -#if 0 - -/* TODO (if it is ever [to be] accessible in the V4L[2] spec): - * maybe fade? (back/front) - * notes: - * NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special - * routine to go through when it tunes in to a new channel before turning - * back on the sound. - * Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be - * implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for - * channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV, - * radio, external, or MUTE]). If both methods are implemented, you get a - * cookie for doing such a good job! :) - */ - -#define AUDC_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ -#define AUDC_NEWCHANNEL _IO('m',3) /* indicate new chan - off mute */ - -#define AUDC_GET_VOLUME_LEFT _IOR('m',4,__u16) -#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16) -#define AUDC_SET_VOLUME_LEFT _IOW('m',6,__u16) -#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16) - -#define AUDC_GET_STEREO _IOR('m',8,__u16) -#define AUDC_SET_STEREO _IOW('m',9,__u16) - -#define AUDC_GET_DC _IOR('m',10,__u16)/* ??? */ - -#define AUDC_GET_BASS _IOR('m',11,__u16) -#define AUDC_SET_BASS _IOW('m',12,__u16) -#define AUDC_GET_TREBLE _IOR('m',13,__u16) -#define AUDC_SET_TREBLE _IOW('m',14,__u16) - -#define AUDC_GET_UNIT _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */ -#define AUDC_SWITCH_MUTE _IO('m',16) /* turn on mute */ -#endif - -#endif /* AUDIOCHIP_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/bt848.h linux/drivers/char/bt848.h --- v2.4.0-test6/linux/drivers/char/bt848.h Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/bt848.h Wed Dec 31 16:00:00 1969 @@ -1,355 +0,0 @@ -/* - bt848.h - Bt848 register offsets - - Copyright (C) 1996,97,98 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 -#ifndef PCI_DEVICE_ID_BT849 -#define PCI_DEVICE_ID_BT849 0x351 -#endif -#ifndef PCI_DEVICE_ID_BT878 -#define PCI_DEVICE_ID_BT878 0x36e -#endif -#ifndef PCI_DEVICE_ID_BT879 -#define PCI_DEVICE_ID_BT879 0x36f -#endif - - -/* 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_PLOCK (1<<2) -#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_NTSC_J 2 -#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_PAL_NC 7 -#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_SCLOOP_PEAK (1<<7) -#define BT848_SCLOOP_HFILT_MINP (1<<3) -#define BT848_SCLOOP_HFILT_MEDP (2<<3) -#define BT848_SCLOOP_HFILT_MAXP (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) - - - -/* Bt848A and higher only !! */ -#define BT848_TGLB 0x080 -#define BT848_TGCTRL 0x084 -#define BT848_FCAP 0x0E8 -#define BT848_PLL_F_LO 0x0F0 -#define BT848_PLL_F_HI 0x0F4 - -#define BT848_PLL_XCI 0x0F8 -#define BT848_PLL_X (1<<7) -#define BT848_PLL_C (1<<6) - -/* Bt878 register */ - -#define BT878_DEVCTRL 0x40 -#define BT878_EN_TBFX 0x02 - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/bttv-cards.c linux/drivers/char/bttv-cards.c --- v2.4.0-test6/linux/drivers/char/bttv-cards.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/bttv-cards.c Wed Dec 31 16:00:00 1969 @@ -1,835 +0,0 @@ -/* - bttv-cards.c -- this file has card-specific stuff - - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999,2000 Gerd Knorr - - 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. - -*/ - -#define __NO_VERSION__ 1 - -#include -#include -#include -#include -#include - -#include - -#include "bttv.h" -#include "tuner.h" - -/* fwd decl */ -static void hauppauge_eeprom(struct bttv *btv); -static void hauppauge_boot_msp34xx(struct bttv *btv); -static void init_PXC200(struct bttv *btv); -static void init_tea5757(struct bttv *btv); - -MODULE_PARM(card,"1-4i"); -MODULE_PARM(pll,"1-4i"); -MODULE_PARM(autoload,"i"); - -static unsigned int card[4] = { -1, -1, -1, -1 }; -static unsigned int pll[4] = { -1, -1, -1, -1 }; -#ifdef MODULE -static unsigned int autoload = 1; -#else -static unsigned int autoload = 0; -#endif - -/* ----------------------------------------------------------------------- */ -/* list of card IDs for bt878+ cards */ - -static struct CARD { - unsigned id; - int cardnr; - char *name; -} cards[] __devinitdata = { - { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, - { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00021461, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, - { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00041461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, - { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" }, - { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV/Radio+" }, - { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, - { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, - { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, - { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, - { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, - { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" }, - { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, - { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, - { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, - { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" }, -#if 0 /* probably wrong */ - { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, - { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, -#endif - { 0, -1, NULL } -}; - -/* ----------------------------------------------------------------------- */ -/* array with description for bt848 / bt878 tv/grabber cards */ - -struct tvcard bttv_tvcards[] = -{ - /* 0x00 */ - { " *** UNKNOWN *** ", - 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "MIRO PCTV", - 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Hauppauge old", - 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,0,1,0,0,0,1, PLL_NONE, -1 }, - { "STB", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, - 0,1,1,1,1,0,0,1, PLL_NONE, -1 }, - - { "Intel", - 3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Diamond DTV2000", - 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "AVerMedia TVPhone", - 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "MATRIX-Vision MV-Delta", - 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x08 */ - { "Fly Video II", - 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, - { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "TurboTV", - 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Hauppauge new (bt878)", - 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,0,1,0,0,0,1, PLL_28, -1 }, - { "MIRO PCTV pro", - 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, - /* 3, 1, 0, 2, 0x3004F, { 2, 3, 1, 1}, {1, 0x10011, 5, 0,10}, 0x3004F, */ - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - { "ADS Technologies Channel Surfer TV", - 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "AVerMedia TVCapture 98", - 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Aimslab VHX", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Zoltrix TV-Max", - 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x10 */ - { "Pixelview PlayTV (bt878)", - 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1}, - { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Leadtek WinView 601", - 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, - { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "AVEC Intercapture", - 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "LifeView FlyKit w/o Tuner", - 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, - 0,0,0,0,0,0,0,1, PLL_NONE, -1 }, - - { "CEI Raffles Card", - 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Lucky Star Image World ConferenceTV", - 3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_28, TUNER_PHILIPS_PAL_I }, - { "Phoebe Tv Master + FM", - 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Modular Technology MM205 PCTV, bt878", - 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x18 */ - { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)", - 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Terratec/Vobis TV-Boostar", - 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Newer Hauppauge WinCam (bt878)", - 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "MAXI TV Video PCI2", - 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, - 1,1,1,1,0,0,0,1, PLL_NONE, TUNER_PHILIPS_SECAM }, - - { "Terratec TerraTV+", - 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, - { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Imagenation PXC200", - 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "FlyVideo 98", - 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, - { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "iProTV", - 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x20 */ - { "Intel Create and Share PCI", - 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Terratec TerraTValue", - 3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1}, - { 0x500, 0, 0x300, 0x900, 0x900},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Leadtek WinFast 2000", - 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, - { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},0, - 1,1,1,1,1,0,0,1, PLL_28, -1 }, - { "Chronos Video Shuttle II", - 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - - { "Typhoon TView TV/FM Tuner", - 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "PixelView PlayTV pro", - 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, - { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0, - 0,0,0,0,0,0,0,1, PLL_28, -1 }, - { "TView99 CPH063", - 3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1}, - { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Pinnacle PCTV Rave", - 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - - /* 0x28 */ - { "STB2", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, - 0,1,1,1,0,1,1,1, PLL_NONE, -1 }, - { "AVerMedia TVPhone 98", - 3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, 5 }, - { "ProVideo PV951", /* pic16c54 */ - 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, - 0,0,0,0,0,0,0,0, PLL_28, 1 }, - { "Little OnAir TV", - 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1}, - {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0, - 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, - - { "Sigma TVII-FM", - 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0, - 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, - { "MATRIX-Vision MV-Delta 2", - 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, - 0,0,0,0,0,0,0,0, PLL_28, -1 }, - { "Zoltrix Genie TV", - 3, 1, 0, 2, 0xbcf03f, { 2, 3, 1, 1}, - { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f}, 0, - 0,0,0,0,0,0,0,0, PLL_28, 5 }, - { "Terratec TV/Radio+", /* Radio ?? */ - 3, 1, 0, 2, 0x1f0000, { 2, 3, 1, 1}, - { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },0, - 0,0,0,0,0,0,0,0, PLL_35, 1 }, - - /* 0x30 */ - { "Dynalink Magic TView ", - 3, 1, 0, 2, 15, { 2, 3, 1, 1}, {2,0,0,0,1},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, -}; -const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); - -/* ----------------------------------------------------------------------- */ - -static unsigned char eeprom_data[256]; - -static void __devinit bttv_dump_eeprom(struct bttv *btv,int addr) -{ - int i; - - if (bttv_verbose < 2) - return; - /* for debugging: dump eeprom to syslog */ - printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); - for (i = 0; i < 256;) { - printk(KERN_DEBUG " %02x:",i); - do { - printk(" %02x",eeprom_data[i++]); - } while (i % 16); - printk("\n"); - } -} - -static int __devinit bttv_idcard_eeprom(struct bttv *btv) -{ - unsigned id; - int i,n; - - id = (eeprom_data[252] << 24) | - (eeprom_data[253] << 16) | - (eeprom_data[254] << 8) | - (eeprom_data[255]); - if (id == 0 || id == 0xffffffff) - return -1; - - /* look for the card */ - btv->cardid = id; - for (n = -1, i = 0; cards[i].id != 0; i++) - if (cards[i].id == id) - n = i; - - if (n != -1) { - /* found it */ - printk(KERN_INFO "bttv%d: card id: %s (0x%08x) => card=%d\n", - btv->nr,cards[n].name,id,cards[n].cardnr); - return cards[n].cardnr; - } else { - /* 404 */ - printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n", - btv->nr, id); - printk(KERN_INFO "please mail id, board name and " - "the correct card= insmod option to " - "kraxel@goldbach.in-berlin.de\n"); - return -1; - } -} - -#ifndef HAVE_TVAUDIO -/* can tda9855.c handle this too maybe? */ -static void __devinit init_tda9840(struct bttv *btv) -{ - /* Horrible Hack */ - bttv_I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ - /* 00 - mute - 10 - mono / averaged stereo - 2a - stereo - 12 - dual A - 1a - dual AB - 16 - dual BA - 1e - dual B - 7a - external */ -} -#endif - -void __devinit bttv_idcard(struct bttv *btv) -{ - int type,eeprom = 0; - - btwrite(0, BT848_GPIO_OUT_EN); - - /* try to autodetect the card */ - /* many bt878 cards have a eeprom @ 0xa0 => read ID - and try to identify it */ - if (bttv_I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { - eeprom = 0xa0; - bttv_readee(btv,eeprom_data,0xa0); - bttv_dump_eeprom(btv,0xa0); /* DEBUG */ - type = bttv_idcard_eeprom(btv); - if (-1 != type) { - btv->type = type; - } else if (btv->id <= 849) { - /* for unknown bt848, assume old Hauppauge */ - btv->type=BTTV_HAUPPAUGE; - } - - /* STB cards have a eeprom @ 0xae (old bt848) */ - } else if (bttv_I2CRead(btv, I2C_STBEE, "eeprom")>=0) { - btv->type=BTTV_STB; - } - - /* let the user override the autodetected type */ - if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) - btv->type=card[btv->nr]; - - /* print which card config we are using */ - sprintf(btv->video_dev.name,"BT%d%s(%.23s)", - btv->id, - (btv->id==848 && btv->revision==0x12) ? "A" : "", - bttv_tvcards[btv->type].name); - printk(KERN_INFO "bttv%d: model: %s [%s]\n",btv->nr,btv->video_dev.name, - (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ? - "insmod option" : "autodetected"); - - /* board specific initialisations */ - if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { - /* auto detect tuner for MIRO cards */ - btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; -#if 0 - if (btv->type == BTTV_MIROPRO) { - if (bttv_verbose) - printk(KERN_INFO "Initializing TEA5757...\n"); - init_tea5757(btv); - } -#endif - } - if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { - /* pick up some config infos from the eeprom */ - if (0xa0 != eeprom) { - eeprom = 0xa0; - bttv_readee(btv,eeprom_data,0xa0); - } - hauppauge_eeprom(btv); - hauppauge_boot_msp34xx(btv); - } - if (btv->type == BTTV_PXC200) - init_PXC200(btv); - - /* pll configuration */ - if (!(btv->id==848 && btv->revision==0x11)) { - /* defaults from card list */ - if (PLL_28 == bttv_tvcards[btv->type].pll) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - /* insmod options can override */ - switch (pll[btv->nr]) { - case 0: /* none */ - btv->pll.pll_crystal = 0; - btv->pll.pll_ifreq = 0; - btv->pll.pll_ofreq = 0; - break; - case 1: /* 28 MHz */ - btv->pll.pll_ifreq = 28636363; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal=BT848_IFORM_XT0; - break; - case 2: /* 35 MHz */ - btv->pll.pll_ifreq = 35468950; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal=BT848_IFORM_XT1; - break; - } - } - - - /* tuner configuration */ - if (-1 != bttv_tvcards[btv->type].tuner_type) - btv->tuner_type = bttv_tvcards[btv->type].tuner_type; - if (btv->tuner_type != -1) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - - /* try to detect audio/fader chips */ - if (bttv_tvcards[btv->type].msp34xx && - bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { - if (autoload) - request_module("msp3400"); - } - -#ifndef HAVE_TVAUDIO - if (bttv_tvcards[btv->type].tda8425 && - bttv_I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) { - if (autoload) - request_module("tda8425"); - } - - if (bttv_tvcards[btv->type].tda9840 && - bttv_I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) { - init_tda9840(btv); - btv->audio_chip = TDA9840; - /* move this to a module too? */ - init_tda9840(btv); - } - - if (bttv_tvcards[btv->type].tda985x && - bttv_I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { - if (autoload) - request_module("tda985x"); - } - if (bttv_tvcards[btv->type].tea63xx) { - if (autoload) - request_module("tea6300"); - } -#else - if (bttv_tvcards[btv->type].tda8425 || - bttv_tvcards[btv->type].tda9840 || - bttv_tvcards[btv->type].tda985x || - bttv_tvcards[btv->type].tea63xx) { - if (autoload) - request_module("tvaudio"); - } -#endif - - if (bttv_tvcards[btv->type].tda9875 && - bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { - if (autoload) - request_module("tda9875"); - } - - if (bttv_tvcards[btv->type].tda7432 && - bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { - if (autoload) - request_module("tda7432"); - } - - - if (bttv_tvcards[btv->type].tea64xx) { - if (autoload) - request_module("tea6420"); - } - - if (bttv_tvcards[btv->type].tuner != -1) { - if (autoload) - request_module("tuner"); - } -} - - -/* ----------------------------------------------------------------------- */ -/* some hauppauge specific stuff */ - -static struct HAUPPAUGE_TUNER -{ - int id; - char *name; -} -hauppauge_tuner[] __devinitdata = -{ - { TUNER_ABSENT, "" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_ABSENT, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_ABSENT, "Philips FI1246" }, - { TUNER_ABSENT, "Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_ABSENT, "Philips FI1256 MK2" }, - { TUNER_ABSENT, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_ABSENT, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, - { TUNER_ABSENT, "Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_ABSENT, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_ABSENT, "Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_PAL, "Temic 4006FH5" }, - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_ABSENT, "Temic 4039FR5" }, - { TUNER_ABSENT, "Philips FQ1216 ME" }, - { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, - { TUNER_ABSENT, "Philips TD1536" }, - { TUNER_ABSENT, "Philips TD1536D" }, - { TUNER_ABSENT, "Philips FMR1236" }, - { TUNER_ABSENT, "Philips FI1256MP" }, - { TUNER_ABSENT, "Samsung TCPQ9091P" }, - { TUNER_ABSENT, "Temic 4006FN5" }, - { TUNER_ABSENT, "Temic 4009FR5" }, - { TUNER_ABSENT, "Temic 4046FM5" }, -}; - -static void __devinit hauppauge_eeprom(struct bttv *btv) -{ - if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) - { - btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; - if (bttv_verbose) - printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, - hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); - } -} - -static void __devinit hauppauge_boot_msp34xx(struct bttv *btv) -{ - int i; - - /* reset/enable the MSP on some Hauppauge cards */ - /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ - btaor(32, ~32, BT848_GPIO_OUT_EN); - btaor(0, ~32, BT848_GPIO_DATA); - udelay(2500); - btaor(32, ~32, BT848_GPIO_DATA); - - if (bttv_verbose) - printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); - - /* look if the msp3400 driver is already registered */ - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (btv->i2c_clients[i] != NULL && - btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { - return; - } - } - - /* if not: look for the chip ... */ - if (bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx")) { - /* ... if found re-register to trigger a i2c bus rescan, */ - /* this time with the msp34xx chip activated */ - i2c_bit_del_bus(&btv->i2c_adap); - i2c_bit_add_bus(&btv->i2c_adap); - } -} - - -/* ----------------------------------------------------------------------- */ -/* Imagenation L-Model PXC200 Framegrabber */ -/* This is basically the same procedure as - * used by Alessandro Rubini in his pxc200 - * driver, but using BTTV functions */ - -static void __devinit init_PXC200(struct bttv *btv) -{ - static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x00 }; - int i,tmp; - - /* Initialise GPIO-connevted stuff */ - btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ - btwrite(0,BT848_GPIO_DATA); - udelay(3); - btwrite(1<<13,BT848_GPIO_DATA); - /* GPIO inputs are pulled up, so no need to drive - * reset pin any longer */ - btwrite(0,BT848_GPIO_OUT_EN); - - /* we could/should try and reset/control the AD pots? but - right now we simply turned off the crushing. Without - this the AGC drifts drifts - remember the EN is reverse logic --> - setting BT848_ADC_AGC_EN disable the AGC - tboult@eecs.lehigh.edu - */ - btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); - - /* Initialise MAX517 DAC */ - printk(KERN_INFO "Setting DAC reference voltage level ...\n"); - bttv_I2CWrite(btv,0x5E,0,0x80,1); - - /* Initialise 12C508 PIC */ - /* The I2CWrite and I2CRead commmands are actually to the - * same chips - but the R/W bit is included in the address - * argument so the numbers are different */ - - printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); - - for (i = 0; i < sizeof(vals)/sizeof(int); i++) { - tmp=bttv_I2CWrite(btv,0x1E,vals[i],0,1); - printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n", - tmp,bttv_I2CRead(btv,0x1F,NULL)); - } - printk(KERN_INFO "PXC200 Initialised.\n"); -} - -/* ----------------------------------------------------------------------- */ -/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */ -/* - * Copyright (c) 1999 Csaba Halasz - * This code is placed under the terms of the GNU General Public License - * - * Brutally hacked by Dan Sheridan djs52 8/3/00 - */ - -/* bus bits on the GPIO port */ -#define TEA_WE 6 -#define TEA_DATA 9 -#define TEA_CLK 8 -#define TEA_MOST 7 - -#define BUS_LOW(bit) btand(~(1<> TEA_##bit) & 1) - -/* TEA5757 register bits */ -#define TEA_FREQ 0:14 -#define TEA_BUFFER 15:15 - -#define TEA_SIGNAL_STRENGTH 16:17 - -#define TEA_PORT1 18:18 -#define TEA_PORT0 19:19 - -#define TEA_BAND 20:21 -#define TEA_BAND_FM 0 -#define TEA_BAND_MW 1 -#define TEA_BAND_LW 2 -#define TEA_BAND_SW 3 - -#define TEA_MONO 22:22 -#define TEA_ALLOW_STEREO 0 -#define TEA_FORCE_MONO 1 - -#define TEA_SEARCH_DIRECTION 23:23 -#define TEA_SEARCH_DOWN 0 -#define TEA_SEARCH_UP 1 - -#define TEA_STATUS 24:24 -#define TEA_STATUS_TUNED 0 -#define TEA_STATUS_SEARCHING 1 - -/* Low-level stuff */ -static int tea_read(struct bttv *btv) -{ - int value = 0; - long timeout; - int i; - - /* better safe than sorry */ - btaor((1<volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; - data = btread(BT848_GPIO_DATA); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1< - - 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. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HACKING -# include -#endif - -#include "bttv.h" -#include "tuner.h" - -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ -#define MIN(a,b) (((a)>(b))?(b):(a)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - - -static void bt848_set_risc_jmps(struct bttv *btv, int state); - -int bttv_num; /* number of Bt848s in use */ -struct bttv bttvs[BTTV_MAX]; - - -/* insmod args */ -MODULE_PARM(triton1,"i"); -MODULE_PARM(radio,"1-4i"); -MODULE_PARM(bigendian,"i"); -MODULE_PARM(fieldnr,"i"); -MODULE_PARM(bttv_verbose,"i"); -MODULE_PARM(bttv_debug,"i"); -MODULE_PARM(gbuffers,"i"); -MODULE_PARM(gbufsize,"i"); - -MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); -MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); - -#if defined(__sparc__) || defined(__powerpc__) -static unsigned int bigendian=1; -#else -static unsigned int bigendian=0; -#endif -static int triton1=0; -static unsigned int radio[BTTV_MAX]; -static unsigned int fieldnr = 0; -static unsigned int gbuffers = 2; -static unsigned int gbufsize = BTTV_MAX_FBUF; -unsigned int bttv_debug = 0; -unsigned int bttv_verbose = 1; - -#define I2C_TIMING (0x7<<4) -#define I2C_DELAY 10 - -#define I2C_SET(CTRL,DATA) \ - { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } -#define I2C_GET() (btread(BT848_I2C)&1) - -#define BURSTOFFSET 76 -#define BTTV_ERRORS 5 - - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); - return ret; -} - -static void * rvmalloc(signed long size) -{ - void * mem; - unsigned long adr, page; - - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, signed long size) -{ - unsigned long adr, page; - - if (mem) - { - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} - - - -/* - * Create the giant waste of buffer space we need for now - * until we get DMA to user space sorted out (probably 2.3.x) - * - * We only create this as and when someone uses mmap - */ - -static int fbuffer_alloc(struct bttv *btv) -{ - if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); - else - printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", - btv->nr); - if(!btv->fbuffer) - return -ENOBUFS; - return 0; -} - - -static int __devinit init_bttv_i2c(struct bttv *btv) -{ - /* i2c bit_adapter */ - memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter)); - memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); - memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client)); - - sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), - " #%d", btv->nr); - btv->i2c_algo.data = btv; - btv->i2c_adap.data = btv; - btv->i2c_adap.algo_data = &btv->i2c_algo; - btv->i2c_client.adapter = &btv->i2c_adap; - - bttv_bit_setscl(btv,1); - bttv_bit_setsda(btv,1); - - btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap); - return btv->i2c_ok; -} - - -/* ----------------------------------------------------------------------- */ - -static void audio(struct bttv *btv, int mode, int no_irq_context) -{ - btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask, - BT848_GPIO_OUT_EN); - - switch (mode) - { - case AUDIO_MUTE: - btv->audio|=AUDIO_MUTE; - break; - 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 audio mute or not in H-lock, turn audio off */ - if ((btv->audio&AUDIO_MUTE)) - mode=AUDIO_OFF; - if ((mode == AUDIO_TUNER) && (btv->radio)) - mode = AUDIO_RADIO; - btaor(bttv_tvcards[btv->type].audiomux[mode], - ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); - if (no_irq_context) - bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); -} - - -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); -} - - -/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/ - -/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C - PLL_X = Reference pre-divider (0=1, 1=2) - PLL_C = Post divider (0=6, 1=4) - PLL_I = Integer input - PLL_F = Fractional input - - F_input = 28.636363 MHz: - PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0 -*/ - -static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout) -{ - unsigned char fl, fh, fi; - - /* prevent overflows */ - fin/=4; - fout/=4; - - fout*=12; - fi=fout/fin; - - fout=(fout%fin)*256; - fh=fout/fin; - - fout=(fout%fin)*256; - fl=fout/fin; - - /*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/ - btwrite(fl, BT848_PLL_F_LO); - btwrite(fh, BT848_PLL_F_HI); - btwrite(fi|BT848_PLL_X, BT848_PLL_XCI); -} - -static int set_pll(struct bttv *btv) -{ - int i; - unsigned long tv; - - if (!btv->pll.pll_crystal) - return 0; - - if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { - /* no PLL needed */ - if (btv->pll.pll_current == 0) { - /* printk ("bttv%d: PLL: is off\n",btv->nr); */ - return 0; - } - printk ("bttv%d: PLL: switching off\n",btv->nr); - btwrite(0x00,BT848_TGCTRL); - btwrite(0x00,BT848_PLL_XCI); - btv->pll.pll_current = 0; - return 0; - } - - if (btv->pll.pll_ofreq == btv->pll.pll_current) { - /* printk("bttv%d: PLL: no change required\n",btv->nr); */ - return 1; - } - - if (bttv_verbose) - printk("bttv%d: PLL: %d => %d ... ",btv->nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); - - set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); - - /* Let other people run while the PLL stabilizes */ - tv=jiffies+HZ/10; /* .1 seconds */ - do - { - schedule(); - } - while(time_before(jiffies,tv)); - - for (i=0; i<100; i++) - { - if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK)) - btwrite(0,BT848_DSTATUS); - else - { - btwrite(0x08,BT848_TGCTRL); - btv->pll.pll_current = btv->pll.pll_ofreq; - if (bttv_verbose) - printk("ok\n"); - return 1; - } - mdelay(10); - } - btv->pll.pll_current = 0; - if (bttv_verbose) - printk("oops\n"); - return -1; -} - -static void bt848_muxsel(struct bttv *btv, unsigned int input) -{ - btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2, - BT848_GPIO_OUT_EN); - - /* This seems to get rid of some synchronization problems */ - btand(~(3<<5), BT848_IFORM); - mdelay(10); - - - input %= bttv_tvcards[btv->type].video_inputs; - if (input==bttv_tvcards[btv->type].svhs) - { - 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); - } - btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); - audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? - AUDIO_EXTERN : AUDIO_TUNER, 1); - btaor(bttv_tvcards[btv->type].muxsel[input]>>4, - ~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); -} - - -struct tvnorm -{ - u32 Fsc; - u16 swidth, sheight; /* scaled standard width, height */ - u16 totalwidth; - u8 adelay, bdelay, iform; - u32 scaledtwidth; - u16 hdelayx1, hactivex1; - u16 vdelay; - u8 vbipack; -}; - -static struct tvnorm tvnorms[] = { - /* PAL-BDGHI */ - /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ - /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ - { 35468950, - 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 1135, 186, 924, 0x20, 255}, - - /* NTSC */ - { 28636363, - 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), - 910, 128, 910, 0x1a, 144}, -#if 0 - /* SECAM EAST */ - { 35468950, - 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), - 944, 186, 922, 0x20, 255}, -#else - /* SECAM L */ - { 35468950, - 924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), - 1135, 186, 922, 0x20, 255}, -#endif - /* PAL-NC */ - { 28636363, - 640, 576, 910, 0x68, 0x5d, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), - 780, 130, 734, 0x1a, 144}, - /* PAL-M */ - { 28636363, - 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0), - 780, 135, 754, 0x1a, 144}, - /* PAL-N */ - { 35468950, - 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1), - 944, 186, 922, 0x20, 144}, - /* NTSC-Japan */ - { 28636363, - 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), - 780, 135, 754, 0x16, 144}, -}; -#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) -#define VBI_SPL 2044 - -/* RISC command to write one VBI data line */ -#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL - -static void make_vbitab(struct bttv *btv) -{ - int i; - unsigned int *po=(unsigned int *) btv->vbi_odd; - unsigned int *pe=(unsigned int *) btv->vbi_even; - - if (bttv_debug > 1) - printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", - btv->nr,virt_to_bus(po), virt_to_bus(pe)); - - *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; - for (i=0; i<16; i++) - { - *(po++)=cpu_to_le32(VBI_RISC); - *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); - } - *(po++)=cpu_to_le32(BT848_RISC_JUMP); - *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); - - *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0; - for (i=16; i<32; i++) - { - *(pe++)=cpu_to_le32(VBI_RISC); - *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); - } - *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); - *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); - - if (bttv_debug > 1) - printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", - btv->nr,virt_to_bus(po), virt_to_bus(pe)); -} - -static int fmtbppx2[16] = { - 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 -}; - -static int palette2fmt[] = { - 0, - BT848_COLOR_FMT_Y8, - BT848_COLOR_FMT_RGB8, - BT848_COLOR_FMT_RGB16, - BT848_COLOR_FMT_RGB24, - BT848_COLOR_FMT_RGB32, - BT848_COLOR_FMT_RGB15, - BT848_COLOR_FMT_YUY2, - BT848_COLOR_FMT_BtYUV, - -1, - -1, - -1, - BT848_COLOR_FMT_RAW, - BT848_COLOR_FMT_YCrCb422, - BT848_COLOR_FMT_YCrCb411, - BT848_COLOR_FMT_YCrCb422, - BT848_COLOR_FMT_YCrCb411, -}; -#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int)) - -static int make_rawrisctab(struct bttv *btv, unsigned int *ro, - unsigned int *re, unsigned int *vbuf) -{ - unsigned long line; - unsigned long bpl=1024; /* bytes per line */ - unsigned long vadr=(unsigned long) vbuf; - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(0); - - /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY - is 2 and without separate VBI grabbing. - We'll have to handle this inside the IRQ handler ... */ - - for (line=0; line < 640; line++) - { - *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); - *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); - vadr+=bpl; - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - return 0; -} - -static int make_prisctab(struct bttv *btv, unsigned int *ro, - unsigned int *re, - unsigned int *vbuf, unsigned short width, - unsigned short height, unsigned short fmt) -{ - unsigned long line, lmask; - unsigned long bl, blcr, blcb, rcmd; - unsigned long todo; - unsigned int **rp; - int inter; - unsigned long cbadr, cradr; - unsigned long vadr=(unsigned long) vbuf; - int shift, csize; - - if (bttv_debug > 1) - printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - switch(fmt) - { - case VIDEO_PALETTE_YUV422P: - csize=(width*height)>>1; - shift=1; - lmask=0; - break; - - case VIDEO_PALETTE_YUV411P: - csize=(width*height)>>2; - shift=2; - lmask=0; - break; - - case VIDEO_PALETTE_YUV420P: - csize=(width*height)>>2; - shift=1; - lmask=1; - break; - - case VIDEO_PALETTE_YUV410P: - csize=(width*height)>>4; - shift=2; - lmask=3; - break; - - default: - return -1; - } - cbadr=vadr+(width*height); - cradr=cbadr+csize; - inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); - *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); - *(re++)=0; - - for (line=0; line < (height<<(1^inter)); line++) - { - if(line==height) - { - vadr+=csize<<1; - cbadr=vadr+(width*height); - cradr=cbadr+csize; - } - if (inter) - rp= (line&1) ? &re : &ro; - else - rp= (line>=height) ? &ro : &re; - - - if(line&lmask) - rcmd=BT848_RISC_WRITE1S23|BT848_RISC_SOL; - else - rcmd=BT848_RISC_WRITE123|BT848_RISC_SOL; - - todo=width; - while(todo) - { - bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); - blcr=(PAGE_SIZE-((PAGE_SIZE-1)&cradr))<todo) ? todo : bl; - blcr=bl>>shift; - blcb=blcr; - /* bl now containts the longest row that can be written */ - todo-=bl; - if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */ - - *((*rp)++)=cpu_to_le32(rcmd|bl); - *((*rp)++)=cpu_to_le32(blcb|(blcr<<16)); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=bl; - if((rcmd&(15<<28))==BT848_RISC_WRITE123) - { - *((*rp)++)=(kvirt_to_bus(cbadr)); - cbadr+=blcb; - *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); - cradr+=blcr; - } - - rcmd&=~BT848_RISC_SOL; /* only the first has SOL */ - } - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - if (bttv_debug > 1) - printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - return 0; -} - -static int make_vrisctab(struct bttv *btv, unsigned int *ro, - unsigned int *re, - unsigned int *vbuf, unsigned short width, - unsigned short height, unsigned short palette) -{ - unsigned long line; - unsigned long bpl; /* bytes per line */ - unsigned long bl; - unsigned long todo; - unsigned int **rp; - int inter; - unsigned long vadr=(unsigned long) vbuf; - - if (palette==VIDEO_PALETTE_RAW) - return make_rawrisctab(btv, ro, re, vbuf); - if (palette>=VIDEO_PALETTE_PLANAR) - return make_prisctab(btv, ro, re, vbuf, width, height, palette); - - if (bttv_debug > 1) - printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; - bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(0); - - for (line=0; line < (height<<(1^inter)); line++) - { - if (inter) - rp= (line&1) ? &re : &ro; - else - rp= (line>=height) ? &ro : &re; - - bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); - if (bpl<=bl) - { - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=bpl; - } - else - { - todo=bpl; - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=bl; - todo-=bl; - while (todo>PAGE_SIZE) - { - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=PAGE_SIZE; - todo-=PAGE_SIZE; - } - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=todo; - } - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - if (bttv_debug > 1) - printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - return 0; -} - -static unsigned char lmaskt[8] = -{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; -static unsigned char rmaskt[8] = -{ 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; - -static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h) -{ - unsigned char lmask, rmask, *p; - int W, l, r; - int i; - - if (bttv_debug > 1) - printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); - - /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ - if (x<0) - { - w+=x; - x=0; - } - if (y<0) - { - h+=y; - y=0; - } - if (w < 0 || h < 0) /* catch bad clips */ - return; - /* out of range data should just fall through */ - if (y+h>=625) - h=625-y; - if (x+w>=1024) - w=1024-x; - - l=x>>3; - r=(x+w-1)>>3; - W=r-l-1; - lmask=lmaskt[x&7]; - rmask=rmaskt[(x+w-1)&7]; - p=clipmap+128*y+l; - - if (W>0) - { - for (i=0; iwin.bpp is allowed here */ - bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; - bpl=btv->win.bpl; - adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; - inter=(btv->win.interlace&1)^1; - width=btv->win.width; - height=btv->win.height; - if (bttv_debug > 1) - printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", - btv->nr,btv->picture.palette,width,height,bpl,bpp); - if(width > 1023) - width = 1023; /* sanity check */ - if(height > 625) - height = 625; /* sanity check */ - ro=btv->risc_scr_odd; - re=btv->risc_scr_even; - - if (bttv_debug) - printk("bttv%d: clip: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { - /* can't clip, don't generate any risc code */ - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - } - if (ncr < 0) { /* bitmap was pased */ - memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); - } else { /* convert rectangular clips to a bitmap */ - memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ - for (i=0; iwin.x * btv->win.bpp) / bpp; - clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, - 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(0); - - /* translate bitmap to risc code */ - for (line=outofmem=0; line < (height<>inter; - rp= (line&1) ? &re : &ro; - clipline = clipmap + (y<<7); /* running pointers ... */ - lastbit = *clipline & 1; - for(x=dx=0,sx=0; x<=width && !outofmem;) { - if (0 == (x&7)) { - /* check bytes not bits if we can ... */ - if (lastbit) { - while (0xff==*clipline && xrisc_scr_odd>RISCMEM_LEN/2 - 16) - outofmem++; - if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) - outofmem++; - } - x++; - if (0 == (x&7)) - clipline++; - } - if ((!inter)||(line&1)) - adr+=bpl; - } - - vfree(clipmap); - /* outofmem flag relies on the following code to discard extra data */ - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - if (bttv_debug > 1) - printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", - btv->nr,btv->picture.palette,width,height,bpl,bpp); -} - -/* - * 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 inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn, - int odd, int width, int height) -{ - u16 vscale, hscale; - u32 xsf, sr; - u16 hdelay; - u8 crop, vtc; - int inter = (height>tvn->sheight/2) ? 0 : 1; - int off = odd ? 0x80 : 0x00; - - xsf = (width*tvn->scaledtwidth)/tvn->swidth; - hscale = ((tvn->totalwidth*4096UL)/xsf-4096); - hdelay = tvn->hdelayx1; - hdelay = (hdelay*width)/tvn->swidth; - hdelay &= 0x3fe; - sr=((tvn->sheight>>inter)*512)/height-512; - vscale=(0x10000UL-sr)&0x1fff; - crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)| - ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); - vscale |= inter ? (BT848_VSCALE_INT<<8) : 0; - -#if 0 - /* Some people say interpolation looks bad ... */ - vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); - if (width < 767) - btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); - else - btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); -#else - vtc = 0; - btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); -#endif - - btwrite(vtc, BT848_E_VTC+off); - btwrite(hscale>>8, BT848_E_HSCALE_HI+off); - btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); - btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); - btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); - btwrite(width&0xff, BT848_E_HACTIVE_LO+off); - btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); - btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off); - btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off); - btwrite(crop, BT848_E_CROP+off); -} - - -static void bt848_set_geo(struct bttv *btv, - int no_irq_context) -{ - u16 ewidth, eheight, owidth, oheight; - u16 format, bswap; - struct tvnorm *tvn; - - tvn=&tvnorms[btv->win.norm]; - - btwrite(tvn->adelay, BT848_ADELAY); - btwrite(tvn->bdelay, BT848_BDELAY); - btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); - btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE); - btwrite(1, BT848_VBI_PACK_DEL); - - btv->pll.pll_ofreq = tvn->Fsc; - if (no_irq_context) - set_pll(btv); - - btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; - - if (0 == btv->risc_cap_odd && - 0 == btv->risc_cap_even) { - /* overlay only */ - owidth = btv->win.width; - oheight = btv->win.height; - ewidth = btv->win.width; - eheight = btv->win.height; - format = btv->win.color_fmt; - bswap = btv->fb_color_ctl; - } else if (-1 != btv->gq_grab && - 0 == btv->risc_cap_odd && - !btv->win.interlace && - btv->scr_on) { - /* odd field -> overlay, even field -> capture */ - owidth = btv->win.width; - oheight = btv->win.height; - ewidth = btv->gbuf[btv->gq_grab].width; - eheight = btv->gbuf[btv->gq_grab].height; - format = (btv->win.color_fmt & 0xf0) | - (btv->gbuf[btv->gq_grab].fmt & 0x0f); - bswap = btv->fb_color_ctl & 0x0a; - } else { - /* capture only */ - owidth = btv->gbuf[btv->gq_grab].width; - oheight = btv->gbuf[btv->gq_grab].height; - ewidth = btv->gbuf[btv->gq_grab].width; - eheight = btv->gbuf[btv->gq_grab].height; - format = btv->gbuf[btv->gq_grab].fmt; - bswap = 0; - } - - /* program odd + even fields */ - bt848_set_eogeo(btv, tvn, 1, owidth, oheight); - bt848_set_eogeo(btv, tvn, 0, ewidth, eheight); - - btwrite(format, BT848_COLOR_FMT); - btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); -} - - -static int bpp2fmt[4] = { - BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, - BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 -}; - -static void bt848_set_winsize(struct bttv *btv) -{ - unsigned short format; - - if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { - /* format set by VIDIOCSPICT */ - format = palette2fmt[btv->picture.palette]; - } else { - /* use default for the given color depth */ - format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : - bpp2fmt[(btv->win.bpp-1)&3]; - } - btv->win.color_fmt = format; - if (bigendian && - format == BT848_COLOR_FMT_RGB32) { - btv->fb_color_ctl = - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN; - } else if (bigendian && - (format == BT848_COLOR_FMT_RGB16 || - format == BT848_COLOR_FMT_RGB15)) { - btv->fb_color_ctl = - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN; - } else { - btv->fb_color_ctl = 0; - } - - /* RGB8 seems to be a 9x5x5 GRB color cube starting at - * color 16. Why the h... can't they even mention this in the - * data sheet? [AC - because it's a standard format so I guess - * it never occurred to them] - * Enable dithering in this mode. - */ - - if (format==BT848_COLOR_FMT_RGB8) - btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - else - btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - - bt848_set_geo(btv,1); -} - -#ifdef HACKING -/* playing with kiobufs and dma-to-userspace. 2.4.x only - Yes, I know: cut+paste programming is ugly. - will fix later, this is proof-of-concept right now. */ -static int make_vrisctab_kiobuf(struct bttv *btv, unsigned int *ro, - unsigned int *re, struct kiobuf *iobuf, - unsigned short width, unsigned short height, - unsigned short palette) -{ - unsigned long bpl; /* bytes per line */ - unsigned long bl; - unsigned long todo; - unsigned long pageaddr; - unsigned int **rp; - unsigned long line,inter,offset,page; - - inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; - bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(0); - - offset = iobuf->offset; - page = 0; - pageaddr = virt_to_bus(page_address(iobuf->maplist[page])); - for (line=0; line < (height<<(1^inter)); line++) - { - if (inter) - rp= (line&1) ? &re : &ro; - else - rp= (line>=height) ? &ro : &re; - - bl = PAGE_SIZE - offset; - if (bpl <= bl) { - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); - *((*rp)++)=cpu_to_le32(pageaddr+offset); - offset+=bpl; - } else { - todo = bpl; - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); - *((*rp)++)=cpu_to_le32(pageaddr+offset); - todo -= bl; - offset = 0; - page++; - pageaddr = virt_to_bus(page_address(iobuf->maplist[page])); - while (todo>PAGE_SIZE) - { - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); - *((*rp)++)=cpu_to_le32(pageaddr); - page++; - pageaddr = virt_to_bus(page_address(iobuf->maplist[page])); - } - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); - *((*rp)++)=cpu_to_le32(pageaddr); - offset += todo; - } - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - return 0; -} - -static int vgrab_kiobuf(struct bttv *btv, struct bttv_just_hacking *mp, - struct kiobuf *iobuf) -{ - unsigned int *ro, *re; - unsigned long flags; - - if(btv->gbuf[0].stat != GBUFFER_UNUSED) - return -EBUSY; - - if(mp->height < 32 || mp->width < 32) - return -EINVAL; - if (mp->format >= 12 /* more is'nt yet ... PALETTEFMT_MAX */) - return -EINVAL; - - if(-1 == palette2fmt[mp->format]) - return -EINVAL; - - /* - * Ok load up the BT848 - */ - - ro=btv->gbuf[0].risc; - re=ro+2048; - make_vrisctab_kiobuf(btv, ro, re, iobuf, mp->width, mp->height, mp->format); - - if (bttv_debug) - printk("bttv%d: cap vgrab_kiobuf: queue %d (%d:%dx%d)\n", - btv->nr,0,mp->format,mp->width,mp->height); - spin_lock_irqsave(&btv->s_lock, flags); - btv->gbuf[0].stat = GBUFFER_GRABBING; - btv->gbuf[0].fmt = palette2fmt[mp->format]; - btv->gbuf[0].width = mp->width; - btv->gbuf[0].height = mp->height; - btv->gbuf[0].ro = virt_to_bus(ro); - btv->gbuf[0].re = virt_to_bus(re); - -#if 1 - if (mp->height <= tvnorms[btv->win.norm].sheight/2 && - mp->format != VIDEO_PALETTE_RAW) - btv->gbuf[0].ro = 0; -#endif - - if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { - btv->gq_start = 1; - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); - } - btv->gqueue[btv->gq_in++] = 0; - btv->gq_in = btv->gq_in % MAX_GBUFFERS; - - btor(3, BT848_CAP_CTL); - btor(3, BT848_GPIO_DMA_CTL); - spin_unlock_irqrestore(&btv->s_lock, flags); - return 0; -} -#endif - -/* - * Grab into virtual memory. - */ - -static int vgrab(struct bttv *btv, struct video_mmap *mp) -{ - unsigned int *ro, *re; - unsigned int *vbuf; - unsigned long flags; - - if(btv->fbuffer==NULL) - { - if(fbuffer_alloc(btv)) - return -ENOBUFS; - } - - if(mp->frame >= gbuffers || mp->frame < 0) - return -EINVAL; - if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) - return -EBUSY; - - if(mp->height < 32 || mp->width < 32) - return -EINVAL; - if (mp->format >= PALETTEFMT_MAX) - return -EINVAL; - - if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 - > gbufsize) - return -EINVAL; - if(-1 == palette2fmt[mp->format]) - return -EINVAL; - - /* - * Ok load up the BT848 - */ - - vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); - ro=btv->gbuf[mp->frame].risc; - re=ro+2048; - make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); - - if (bttv_debug) - printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n", - btv->nr,mp->frame,mp->format,mp->width,mp->height); - spin_lock_irqsave(&btv->s_lock, flags); - btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; - btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; - btv->gbuf[mp->frame].width = mp->width; - btv->gbuf[mp->frame].height = mp->height; - btv->gbuf[mp->frame].ro = virt_to_bus(ro); - btv->gbuf[mp->frame].re = virt_to_bus(re); - -#if 1 - if (mp->height <= tvnorms[btv->win.norm].sheight/2 && - mp->format != VIDEO_PALETTE_RAW) - btv->gbuf[mp->frame].ro = 0; -#endif - - if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { - btv->gq_start = 1; - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); - } - btv->gqueue[btv->gq_in++] = mp->frame; - btv->gq_in = btv->gq_in % MAX_GBUFFERS; - - btor(3, BT848_CAP_CTL); - btor(3, BT848_GPIO_DMA_CTL); - spin_unlock_irqrestore(&btv->s_lock, flags); - return 0; -} - -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; - DECLARE_WAITQUEUE(wait, current); - - /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ - 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; - - add_wait_queue(&btv->vbiq, &wait); - current->state = TASK_INTERRUPTIBLE; - if (todo && q==VBIBUF_SIZE-btv->vbip) - { - if(nonblock) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - if(count==todo) - return -EWOULDBLOCK; - return count-todo; - } - schedule(); - if(signal_pending(current)) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - - if(todo==count) - return -EINTR; - else - return count-todo; - } - } - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - } - if (todo) - { - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) - return -EFAULT; - btv->vbip+=todo; - } - return count; -} - -static inline void burst(int on) -{ - tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); - tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); - tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); - tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0); -} - -static void bt848_restart(struct bttv *btv) -{ - unsigned long irq_flags; - - if (bttv_verbose) - printk("bttv%d: resetting chip\n",btv->nr); - btwrite(0xfffffUL, BT848_INT_STAT); - btand(~15, BT848_GPIO_DMA_CTL); - btwrite(0, BT848_SRESET); - btwrite(virt_to_bus(btv->risc_jmp+2), - BT848_RISC_STRT_ADD); - - /* enforce pll reprogramming */ - btv->pll.pll_current = 0; - set_pll(btv); - - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->errors = 0; - btv->needs_restart = 0; - bt848_set_geo(btv,0); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); -} - -/* - * 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 i,ret; - - ret = -EBUSY; - - MOD_INC_USE_COUNT; - down(&btv->lock); - if (btv->user) - goto out_unlock; - - btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); - ret = -ENOMEM; - if (!btv->fbuffer) - goto out_unlock; - - btv->gq_in = 0; - btv->gq_out = 0; - btv->gq_grab = -1; - for (i = 0; i < gbuffers; i++) - btv->gbuf[i].stat = GBUFFER_UNUSED; - - if (btv->needs_restart) - bt848_restart(btv); - burst(0); - set_pll(btv); - btv->user++; - up(&btv->lock); - return 0; - - out_unlock: - up(&btv->lock); - MOD_DEC_USE_COUNT; - return ret; -} - -static void bttv_close(struct video_device *dev) -{ - struct bttv *btv=(struct bttv *)dev; - unsigned long irq_flags; - - down(&btv->lock); - btv->user--; - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->scr_on = 0; - btv->risc_cap_odd = 0; - btv->risc_cap_even = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - /* - * A word of warning. At this point the chip - * is still capturing because its FIFO hasn't emptied - * and the DMA control operations are posted PCI - * operations. - */ - - btread(BT848_I2C); /* This fixes the PCI posting delay */ - - if (-1 != btv->gq_grab) { - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); /* Wait 1/10th of a second */ - } - - /* - * We have allowed it to drain. - */ - - if(btv->fbuffer) - rvfree((void *) btv->fbuffer, gbuffers*gbufsize); - btv->fbuffer=0; - up(&btv->lock); - 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, unsigned long 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, unsigned long 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); -} - -/* - * ioctl routine - */ - - -static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct bttv *btv=(struct bttv *)dev; - unsigned long irq_flags; - int i,ret = 0; - - if (bttv_debug > 1) - printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name,btv->video_dev.name); - b.type = VID_TYPE_CAPTURE| - ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | - VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING| - VID_TYPE_FRAMERAM| - VID_TYPE_SCALES; - b.channels = bttv_tvcards[btv->type].video_inputs; - b.audios = bttv_tvcards[btv->type].audio_inputs; - b.maxwidth = tvnorms[btv->win.norm].swidth; - b.maxheight = tvnorms[btv->win.norm].sheight; - 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; - v.norm = btv->win.norm; - if (v.channel>=bttv_tvcards[btv->type].video_inputs) - return -EINVAL; - if(v.channel==bttv_tvcards[btv->type].tuner) - { - strcpy(v.name,"Television"); - v.flags|=VIDEO_VC_TUNER; - v.type=VIDEO_TYPE_TV; - v.tuners=1; - } - else if(v.channel==bttv_tvcards[btv->type].svhs) - strcpy(v.name,"S-Video"); - else - sprintf(v.name,"Composite%d",v.channel); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* - * Each channel has 1 tuner - */ - case VIDIOCSCHAN: - { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - - if (v.channel>bttv_tvcards[btv->type].video_inputs) - return -EINVAL; - if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) - return -EOPNOTSUPP; - - bttv_call_i2c_clients(btv,cmd,&v); - down(&btv->lock); - bt848_muxsel(btv, v.channel); - btv->channel=v.channel; - if (btv->win.norm != v.norm) { - btv->win.norm = v.norm; - make_vbitab(btv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - } - up(&btv->lock); - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v,arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner||btv->channel) /* Only tuner 0 */ - return -EINVAL; - strcpy(v.name, "Television"); - v.rangelow=0; - v.rangehigh=0xFFFFFFFF; - v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v.mode = btv->win.norm; - v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - bttv_call_i2c_clients(btv,cmd,&v); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* We have but one tuner */ - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - /* Only one channel has a tuner */ - if(v.tuner!=bttv_tvcards[btv->type].tuner) - return -EINVAL; - - if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC - &&v.mode!=VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - bttv_call_i2c_clients(btv,cmd,&v); - if (btv->win.norm != v.mode) { - btv->win.norm = v.mode; - down(&btv->lock); - set_pll(btv); - make_vbitab(btv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - } - return 0; - } - case VIDIOCGPICT: - { - struct video_picture p=btv->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 > PALETTEFMT_MAX) - return -EINVAL; - down(&btv->lock); - /* 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; - up(&btv->lock); - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp = NULL; - - if(copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - - down(&btv->lock); - if(vw.flags || vw.width < 16 || vw.height < 16) - { - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->scr_on = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - return -EINVAL; - } - if (btv->win.bpp < 4) - { /* adjust and align writes */ - vw.x = (vw.x + 3) & ~3; - vw.width &= ~3; - } - if (btv->needs_restart) - bt848_restart(btv); - btv->win.x=vw.x; - btv->win.y=vw.y; - btv->win.width=vw.width; - btv->win.height=vw.height; - - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_risc_jmps(btv,0); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - /* - * Do any clips. - */ - if(vw.clipcount<0) { - if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) - return -ENOMEM; - if(copy_from_user(vcp, vw.clips, - VIDEO_CLIPMAP_SIZE)) { - vfree(vcp); - return -EFAULT; - } - } else if (vw.clipcount) { - if((vcp=vmalloc(sizeof(struct video_clip)* - (vw.clipcount))) == NULL) - return -ENOMEM; - if(copy_from_user(vcp,vw.clips, - sizeof(struct video_clip)* - vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - } - make_clip_tab(btv, vcp, vw.clipcount); - if (vw.clipcount != 0) - vfree(vcp); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - 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) - return -EINVAL; - if (btv->win.width==0 || btv->win.height==0) - return -EINVAL; - spin_lock_irqsave(&btv->s_lock, irq_flags); - if (v == 1 && btv->win.vidadr != 0) - btv->scr_on = 1; - if (v == 0) - btv->scr_on = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - 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.depth; - v.bytesperline=btv->win.bpl; - if(copy_to_user(arg, &v,sizeof(v))) - return -EFAULT; - return 0; - - } - case VIDIOCSFBUF: - { - struct video_buffer v; - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if(v.depth!=8 && v.depth!=15 && v.depth!=16 && - v.depth!=24 && v.depth!=32 && v.width > 16 && - v.height > 16 && v.bytesperline > 16) - return -EINVAL; - down(&btv->lock); - if (v.base) - btv->win.vidadr=(unsigned long)v.base; - btv->win.sheight=v.height; - btv->win.swidth=v.width; - btv->win.bpp=((v.depth+7)&0x38)/8; - btv->win.depth=v.depth; - btv->win.bpl=v.bytesperline; - - /* set sefault color format */ - switch (btv->win.bpp) { - case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; - case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; - case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; - case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; - case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; - } - - if (bttv_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); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - 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; - bttv_call_i2c_clients(btv,cmd,&v); -#if 0 - if (btv->type == BTTV_MIROPRO && btv->radio) - tea5757_set_freq(btv,v); -#endif - return 0; - } - - case VIDIOCGAUDIO: - { - struct video_audio v; - - v=btv->audio_dev; - v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); - v.flags|=VIDEO_AUDIO_MUTABLE; - strcpy(v.name,"TV"); - - v.mode = VIDEO_SOUND_MONO; - bttv_call_i2c_clients(btv,cmd,&v); - - if (btv->type == BTTV_TERRATV) { - v.mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -#ifndef HAVE_TVAUDIO - else if (btv->audio_chip == TDA9840) { - /* begin of Horrible Hack */ - v.flags|=VIDEO_AUDIO_VOLUME; - v.mode = VIDEO_SOUND_MONO; - v.mode |= VIDEO_SOUND_STEREO; - v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; - v.volume = 32768; /* fixme */ - v.step = 4096; - } -#endif - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - - if(copy_from_user(&v,arg, sizeof(v))) - return -EFAULT; - down(&btv->lock); - if(v.flags&VIDEO_AUDIO_MUTE) - audio(btv, AUDIO_MUTE, 1); - /* One audio source per tuner -- huh? */ - if(v.audio<0 || v.audio >= bttv_tvcards[btv->type].audio_inputs) { - up(&btv->lock); - return -EINVAL; - } - /* bt848_muxsel(btv,v.audio); */ - if(!(v.flags&VIDEO_AUDIO_MUTE)) - audio(btv, AUDIO_UNMUTE, 1); - - bttv_call_i2c_clients(btv,cmd,&v); - - if (btv->type == BTTV_TERRATV) { - unsigned int con = 0; - btor(0x180000, BT848_GPIO_OUT_EN); - if (v.mode & VIDEO_SOUND_LANG2) - con = 0x080000; - if (v.mode & VIDEO_SOUND_STEREO) - con = 0x180000; - btaor(con, ~0x180000, BT848_GPIO_DATA); - - } else if (btv->type == BTTV_WINVIEW_601) - winview_setvol(btv,&v); - - btv->audio_dev=v; - up(&btv->lock); - return 0; - } - - case VIDIOCSYNC: - { - DECLARE_WAITQUEUE(wait, current); - - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - if (i < 0 || i >= gbuffers) - return -EINVAL; - switch (btv->gbuf[i].stat) { - case GBUFFER_UNUSED: - ret = -EINVAL; - break; - case GBUFFER_GRABBING: - add_wait_queue(&btv->capq, &wait); - current->state = TASK_INTERRUPTIBLE; - while(btv->gbuf[i].stat==GBUFFER_GRABBING) { - if (bttv_debug) - printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); - schedule(); - if(signal_pending(current)) { - remove_wait_queue(&btv->capq, &wait); - current->state = TASK_RUNNING; - return -EINTR; - } - } - remove_wait_queue(&btv->capq, &wait); - current->state = TASK_RUNNING; - /* fall throuth */ - case GBUFFER_DONE: - case GBUFFER_ERROR: - ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; - if (bttv_debug) - printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); - btv->gbuf[i].stat = GBUFFER_UNUSED; - } - if (btv->needs_restart) { - down(&btv->lock); - bt848_restart(btv); - up(&btv->lock); - } - return ret; - } - - case BTTV_FIELDNR: - if(copy_to_user((void *) arg, (void *) &btv->last_field, - sizeof(btv->last_field))) - return -EFAULT; - break; - - case BTTV_PLLSET: { - struct bttv_pll_info p; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) - return -EFAULT; - down(&btv->lock); - btv->pll.pll_ifreq = p.pll_ifreq; - btv->pll.pll_ofreq = p.pll_ofreq; - btv->pll.pll_crystal = p.pll_crystal; - up(&btv->lock); - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - int ret; - if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) - return -EFAULT; - down(&btv->lock); - ret = vgrab(btv, &vm); - up(&btv->lock); - return ret; - } - - case VIDIOCGMBUF: - { - struct video_mbuf vm; - memset(&vm, 0 , sizeof(vm)); - vm.size=gbufsize*gbuffers; - vm.frames=gbuffers; - for (i = 0; i < gbuffers; i++) - vm.offsets[i]=i*gbufsize; - if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - return 0; - } - - case VIDIOCGUNIT: - { - struct video_unit vu; - vu.video=btv->video_dev.minor; - vu.vbi=btv->vbi_dev.minor; - if(btv->radio_dev.minor!=-1) - vu.radio=btv->radio_dev.minor; - else - vu.radio=VIDEO_NO_UNIT; - vu.audio=VIDEO_NO_UNIT; - vu.teletext=VIDEO_NO_UNIT; - if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) - return -EFAULT; - return 0; - } - - case BTTV_BURST_ON: - { - burst(1); - return 0; - } - - case BTTV_BURST_OFF: - { - burst(0); - return 0; - } - - case BTTV_VERSION: - { - return BTTV_VERSION_CODE; - } - - case BTTV_PICNR: - { - /* return picture;*/ - return 0; - } - -#ifdef HACKING - /* playing with kiobufs and dma-to-userspace */ - case BTTV_JUST_HACKING: - { - DECLARE_WAITQUEUE(wait, current); - struct bttv_just_hacking hack; - struct kiobuf *iobuf; - int err; - - if(copy_from_user((void *) &hack, (void *) arg, sizeof(hack))) - return -EFAULT; - printk("bttv%d: hack: userland args: %dx%d, fmt=%d, buf=%lx, len=%d\n", - btv->nr,hack.width,hack.height,hack.format, - hack.buf,hack.len); - - /* pin down */ - err = alloc_kiovec(1,&iobuf); - if (err) - goto hack_oops; - err = map_user_kiobuf(READ, iobuf, hack.buf, hack.len); - if (err) - goto hack_oops; - err = lock_kiovec(1,&iobuf,1); - if (err) - goto hack_oops; - - /* have a look */ - printk("bttv%d: hack: kiobuf: nr_pages=%d, offset=%d, length=%d, locked=%d\n", - btv->nr,iobuf->nr_pages,iobuf->offset,iobuf->length, - iobuf->locked); - printk("bttv%d: hack: pages (bus addr):",btv->nr); - for (i = 0; i < iobuf->nr_pages; i++) { - printk(" %lx", virt_to_bus(page_address(iobuf->maplist[i]))); - } - printk("\n"); - - /* start capture */ - err = -EINVAL; - if (hack.height * hack.width * 2 * /* fixme: *2 */ - fmtbppx2[palette2fmt[hack.format]&0x0f]/2 > hack.len) - goto hack_oops; - err = vgrab_kiobuf(btv,&hack,iobuf); - if (err) - goto hack_oops; - printk("bttv%d: hack: capture started\n",btv->nr); - - /* wait */ - add_wait_queue(&btv->capq, &wait); - current->state = TASK_INTERRUPTIBLE; - while(btv->gbuf[0].stat==GBUFFER_GRABBING) { - if (bttv_debug) - printk("bttv%d: hack: cap sync: sleep on %d\n",btv->nr,0); - schedule(); -#if 0 - if(signal_pending(current)) { - remove_wait_queue(&btv->capq, &wait); - current->state = TASK_RUNNING; - return -EINTR; - } -#endif - } - remove_wait_queue(&btv->capq, &wait); - current->state = TASK_RUNNING; - printk("bttv%d: hack: capture done\n",btv->nr); - - /* release */ - err = 0; - hack_oops: - free_kiovec(1,&iobuf); - return 0; - } -#endif - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int bttv_init_done(struct video_device *dev) -{ - return 0; -} - -/* - * This maps the vmalloced and reserved fbuffer to user space. - * - * FIXME: - * - PAGE_READONLY should suffice!? - * - remap_page_range is kind of inefficient for page by page remapping. - * But e.g. pte_alloc() does not work in modules ... :-( - */ - -static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) -{ - unsigned long start=(unsigned long) adr; - unsigned long page,pos; - - if (size>gbuffers*gbufsize) - return -EINVAL; - if (!btv->fbuffer) { - if(fbuffer_alloc(btv)) - return -EINVAL; - } - pos=(unsigned long) btv->fbuffer; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; - } - return 0; -} - -static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - struct bttv *btv=(struct bttv *)dev; - int r; - - down(&btv->lock); - r=do_bttv_mmap(btv, adr, size); - up(&btv->lock); - return r; -} - - -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, - NULL, - bttv_ioctl, - bttv_mmap, - bttv_init_done, - NULL, - 0, - -1 -}; - - -static long vbi_read(struct video_device *v, char *buf, unsigned long count, - int nonblock) -{ - struct bttv *btv=(struct bttv *)(v-2); - int q,todo; - DECLARE_WAITQUEUE(wait, current); - - todo=count; - while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) - { - if (btv->needs_restart) { - down(&btv->lock); - bt848_restart(btv); - up(&btv->lock); - } - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) - return -EFAULT; - todo-=q; - buf+=q; - - add_wait_queue(&btv->vbiq, &wait); - current->state = TASK_INTERRUPTIBLE; - if (todo && q==VBIBUF_SIZE-btv->vbip) - { - if(nonblock) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - if(count==todo) - return -EWOULDBLOCK; - return count-todo; - } - schedule(); - if(signal_pending(current)) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - if(todo==count) - return -EINTR; - else - return count-todo; - } - } - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - } - if (todo) - { - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) - return -EFAULT; - btv->vbip+=todo; - } - return count; -} - -static unsigned int vbi_poll(struct video_device *dev, struct file *file, - poll_table *wait) -{ - struct bttv *btv=(struct bttv *)(dev-2); - unsigned int mask = 0; - - poll_wait(file, &btv->vbiq, wait); - - if (btv->vbip < VBIBUF_SIZE) - mask |= (POLLIN | POLLRDNORM); - - return mask; -} - -static int vbi_open(struct video_device *dev, int flags) -{ - struct bttv *btv=(struct bttv *)(dev-2); - unsigned long irq_flags; - - MOD_INC_USE_COUNT; - down(&btv->lock); - if (btv->needs_restart) - bt848_restart(btv); - set_pll(btv); - btv->vbip=VBIBUF_SIZE; - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->vbi_on = 1; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - - return 0; -} - -static void vbi_close(struct video_device *dev) -{ - struct bttv *btv=(struct bttv *)(dev-2); - unsigned long irq_flags; - - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->vbi_on = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - MOD_DEC_USE_COUNT; -} - -static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct bttv *btv=(struct bttv *)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name,btv->vbi_dev.name); - b.type = ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | - VID_TYPE_TELETEXT; - b.channels = 0; - b.audios = 0; - b.maxwidth = 0; - b.maxheight = 0; - b.minwidth = 0; - b.minheight = 0; - if(copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - return bttv_ioctl((struct video_device *)btv,cmd,arg); - case BTTV_VBISIZE: - /* make alevt happy :-) */ - return VBIBUF_SIZE; - default: - return -EINVAL; - } -} - -static struct video_device vbi_template= -{ - "bttv vbi", - VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, - VID_HARDWARE_BT848, - vbi_open, - vbi_close, - vbi_read, - bttv_write, - vbi_poll, - vbi_ioctl, - NULL, /* no mmap yet */ - bttv_init_done, - NULL, - 0, - -1 -}; - - -static int radio_open(struct video_device *dev, int flags) -{ - struct bttv *btv = (struct bttv *)(dev-1); - unsigned long v; - - MOD_INC_USE_COUNT; - down(&btv->lock); - if (btv->user) - goto busy_unlock; - btv->user++; - - btv->radio = 1; - v = 400*16; - bttv_call_i2c_clients(btv,VIDIOCSFREQ,&v); - bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); - bt848_muxsel(btv,0); - up(&btv->lock); - - return 0; - - busy_unlock: - up(&btv->lock); - MOD_DEC_USE_COUNT; - return -EBUSY; -} - -static void radio_close(struct video_device *dev) -{ - struct bttv *btv=(struct bttv *)(dev-1); - - down(&btv->lock); - btv->user--; - btv->radio = 0; - up(&btv->lock); - MOD_DEC_USE_COUNT; -} - -static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct bttv *btv=(struct bttv *)(dev-1); - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability v; - strcpy(v.name,btv->video_dev.name); - v.type = VID_TYPE_TUNER; - v.channels = 1; - v.audios = 1; - /* No we don't do pictures */ - v.maxwidth = 0; - v.maxheight = 0; - v.minwidth = 0; - v.minheight = 0; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - break; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v,arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner||btv->channel) /* Only tuner 0 */ - return -EINVAL; - strcpy(v.name, "Radio"); - v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */ - v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */ - v.flags= 0; /* XXX */ - v.mode = 0; /* XXX */ - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 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 || btv->channel) - return -EINVAL; - /* XXX anything to do ??? */ - return 0; - } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - bttv_ioctl((struct video_device *)btv,cmd,arg); - break; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static struct video_device radio_template= -{ - "bttv radio", - VID_TYPE_TUNER, - VID_HARDWARE_BT848, - radio_open, - radio_close, - radio_read, /* just returns -EINVAL */ - bttv_write, /* just returns -EINVAL */ - NULL, /* no poll */ - radio_ioctl, - NULL, /* no mmap */ - bttv_init_done, /* just returns 0 */ - NULL, - 0, - -1 -}; - - -#define TRITON_PCON 0x50 -#define TRITON_BUS_CONCURRENCY (1<<0) -#define TRITON_STREAMING (1<<1) -#define TRITON_WRITE_BURST (1<<2) -#define TRITON_PEER_CONCURRENCY (1<<3) - - -static void __devinit handle_chipset(void) -{ - struct pci_dev *dev = NULL; - - /* Just in case some nut set this to something dangerous */ - if (triton1) - triton1=BT848_INT_ETBF; - - while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) - { - /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ - printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82441, dev))) - { - unsigned char b; - pci_read_config_byte(dev, 0x53, &b); - DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); - DEBUG(printk("bufcon=0x%02x\n",b)); - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) - { - printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); - triton1=BT848_INT_ETBF; - } -} - - -static void bt848_set_risc_jmps(struct bttv *btv, int flags) -{ - if (-1 == flags) { - /* defaults */ - flags = 0; - if (btv->scr_on) - flags |= 0x03; - if (btv->vbi_on) - flags |= 0x0c; - } - - if (bttv_debug > 1) - printk("bttv%d: set_risc_jmp %08lx:", - btv->nr,virt_to_bus(btv->risc_jmp)); - - /* Sync to start of odd field */ - btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC - |BT848_FIFO_STATUS_VRE); - btv->risc_jmp[1]=cpu_to_le32(0); - - /* Jump to odd vbi sub */ - btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); - if (flags&8) { - if (bttv_debug > 1) - printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); - btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); - } else { - if (bttv_debug > 1) - printk(" -----------"); - btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); - } - - /* Jump to odd sub */ - btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); - if (0 != btv->risc_cap_odd) { - if (bttv_debug > 1) - printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); - flags |= 3; - btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); - } else if (flags&2) { - if (bttv_debug > 1) - printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); - } else { - if (bttv_debug > 1) - printk(" -----------"); - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); - } - - - /* Sync to start of even field */ - btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC - |BT848_FIFO_STATUS_VRO); - btv->risc_jmp[7]=cpu_to_le32(0); - - /* Jump to even vbi sub */ - btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); - if (flags&4) { - if (bttv_debug > 1) - printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); - btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); - } else { - if (bttv_debug > 1) - printk(" -----------"); - btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); - } - - /* Jump to even sub */ - btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); - if (0 != btv->risc_cap_even) { - if (bttv_debug > 1) - printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); - flags |= 3; - btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); - } else if (flags&1) { - if (bttv_debug > 1) - printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); - } else { - if (bttv_debug > 1) - printk(" -----------"); - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); - } - - if (btv->gq_start) { - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); - } else { - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); - } - btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); - - /* enable cpaturing and DMA */ - if (bttv_debug > 1) - printk(" flags=0x%x dma=%s\n", - flags,(flags&0x0f) ? "on" : "off"); - btaor(flags, ~0x0f, BT848_CAP_CTL); - if (flags&0x0f) - bt848_dma(btv, 3); - else - bt848_dma(btv, 0); -} - -static int __devinit init_video_dev(struct bttv *btv) -{ - memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); - memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); - memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); - - bttv_idcard(btv); - audio(btv, AUDIO_MUTE, 1); - - if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) - return -1; - if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) - { - video_unregister_device(&btv->video_dev); - return -1; - } - if (radio[btv->nr]) - { - if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) - { - video_unregister_device(&btv->vbi_dev); - video_unregister_device(&btv->video_dev); - return -1; - } - } - return 1; -} - -static int __devinit init_bt848(struct bttv *btv) -{ - int j; - unsigned long irq_flags; - - btv->user=0; - init_MUTEX(&btv->lock); - - /* dump current state of the gpio registers before changing them, - * might help to make a new card work */ - if (bttv_verbose >= 2) - printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", - btv->nr, - btread(BT848_GPIO_OUT_EN), - btread(BT848_GPIO_DATA), - btread(BT848_GPIO_REG_INP)); - - /* reset the bt848 */ - btwrite(0, BT848_SRESET); - DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem)); - - /* not registered yet */ - btv->video_dev.minor = -1; - btv->radio_dev.minor = -1; - btv->vbi_dev.minor = -1; - - /* 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.bpp=2; - btv->win.depth=16; - btv->win.color_fmt=BT848_COLOR_FMT_RGB16; - btv->win.bpl=1024*btv->win.bpp; - btv->win.swidth=1024; - btv->win.sheight=768; - btv->win.vidadr=0; - btv->vbi_on=0; - btv->scr_on=0; - - btv->risc_scr_odd=0; - btv->risc_scr_even=0; - btv->risc_cap_odd=0; - btv->risc_cap_even=0; - btv->risc_jmp=0; - btv->vbibuf=0; - btv->field=btv->last_field=0; - - btv->errors=0; - btv->needs_restart=0; - - /* i2c */ - btv->tuner_type=-1; - init_bttv_i2c(btv); - - if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) - return -1; - if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) - return -1; - if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) - return -1; - btv->vbi_odd=btv->risc_jmp+16; - btv->vbi_even=btv->vbi_odd+256; - btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); - 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=(unsigned char *) vmalloc_32(VBIBUF_SIZE); - if (!btv->vbibuf) - return -1; - if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) - return -1; - for (j = 0; j < gbuffers; j++) { - if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) - return -1; - } - - memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random - memory to the user */ - - btv->fbuffer=NULL; - - bt848_muxsel(btv, 1); - bt848_set_winsize(btv); - -/* btwrite(0, BT848_TDEC); */ - btwrite(0x10, BT848_COLOR_CTL); - btwrite(0x00, BT848_CAP_CTL); - /* set planar and packed mode trigger points and */ - /* set rising edge of inverted GPINTR pin as irq trigger */ - btwrite(BT848_GPIO_DMA_CTL_PKTP_32| - BT848_GPIO_DMA_CTL_PLTP1_16| - BT848_GPIO_DMA_CTL_PLTP23_16| - BT848_GPIO_DMA_CTL_GPINTC| - BT848_GPIO_DMA_CTL_GPINTI, - BT848_GPIO_DMA_CTL); - - /* select direct input */ - btwrite(0x00, BT848_GPIO_REG_INP); - - btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, - BT848_IFORM); - - btwrite(0xd8, BT848_CONTRAST_LO); - bt848_bright(btv, 0x10); - - btwrite(0x20, BT848_E_VSCALE_HI); - btwrite(0x20, 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); - - btv->picture.colour=254<<7; - btv->picture.brightness=128<<8; - btv->picture.hue=128<<8; - btv->picture.contrast=0xd8<<7; - - btwrite(0x00, BT848_E_SCLOOP); - btwrite(0x00, BT848_O_SCLOOP); - - /* clear interrupt status */ - btwrite(0xfffffUL, BT848_INT_STAT); - - /* set interrupt mask */ - btwrite(btv->triton1| - /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| - BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ - (fieldnr ? BT848_INT_VSYNC : 0)| - BT848_INT_GPINT| - BT848_INT_SCERR| - BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| - BT848_INT_FMTCHG|BT848_INT_HLOCK, - BT848_INT_MASK); - - make_vbitab(btv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - /* - * Now add the template and register the device unit. - */ - init_video_dev(btv); - - return 0; -} - -static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) -{ - u32 stat,astat; - u32 dstat; - int count,i; - 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%d: astat=%08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); - - /* get device status bits */ - dstat=btread(BT848_DSTATUS); - - if (astat&BT848_INT_GPINT) { - IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); - wake_up_interruptible(&btv->gpioq); - } - - if (astat&BT848_INT_FMTCHG) - { - IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); - /*btv->win.norm&= - (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ - } - if (astat&BT848_INT_VPRES) - { - IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr)); - } - if (astat&BT848_INT_VSYNC) - { - IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); - btv->field++; - } - if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { - if (bttv_verbose) - printk("bttv%d: irq:%s%s risc_count=%08x\n", - btv->nr, - (astat&BT848_INT_SCERR) ? " SCERR" : "", - (astat&BT848_INT_OCERR) ? " OCERR" : "", - btread(BT848_RISC_COUNT)); - btv->errors++; - if (btv->errors < BTTV_ERRORS) { - spin_lock(&btv->s_lock); - btand(~15, BT848_GPIO_DMA_CTL); - btwrite(virt_to_bus(btv->risc_jmp+2), - BT848_RISC_STRT_ADD); - bt848_set_geo(btv,0); - bt848_set_risc_jmps(btv,-1); - spin_unlock(&btv->s_lock); - } else { - if (bttv_verbose) - printk("bttv%d: aiee: error loops\n",btv->nr); - /* cancel all outstanding grab requests */ - spin_lock(&btv->s_lock); - btv->gq_in = 0; - btv->gq_out = 0; - btv->gq_grab = -1; - for (i = 0; i < gbuffers; i++) - if (btv->gbuf[i].stat == GBUFFER_GRABBING) - btv->gbuf[i].stat = GBUFFER_ERROR; - /* disable DMA */ - btv->risc_cap_odd = 0; - btv->risc_cap_even = 0; - bt848_set_risc_jmps(btv,0); - btv->needs_restart = 1; - spin_unlock(&btv->s_lock); - - wake_up_interruptible(&btv->vbiq); - wake_up_interruptible(&btv->capq); - } - } - if (astat&BT848_INT_RISCI) - { - if (bttv_debug > 1) - printk("bttv%d: IRQ_RISCI\n",btv->nr); - - /* captured VBI frame */ - if (stat&(1<<28)) - { - btv->vbip=0; - /* inc vbi frame count for detecting drops */ - (*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++; - wake_up_interruptible(&btv->vbiq); - } - - /* captured full frame */ - if (stat&(2<<28) && btv->gq_grab != -1) - { - btv->last_field=btv->field; - if (bttv_debug) - printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); - do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); - spin_lock(&btv->s_lock); - btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; - btv->gq_grab = -1; - if (btv->gq_in != btv->gq_out) - { - btv->gq_grab = btv->gqueue[btv->gq_out++]; - btv->gq_out = btv->gq_out % MAX_GBUFFERS; - if (bttv_debug) - printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); - btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; - btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; - bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); - btwrite(BT848_COLOR_CTL_GAMMA, - BT848_COLOR_CTL); - } else { - btv->risc_cap_odd = 0; - btv->risc_cap_even = 0; - bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); - btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, - BT848_COLOR_CTL); - } - spin_unlock(&btv->s_lock); - wake_up_interruptible(&btv->capq); - break; - } - if (stat&(8<<28)) - { - spin_lock(&btv->s_lock); - btv->gq_start = 0; - btv->gq_grab = btv->gqueue[btv->gq_out++]; - btv->gq_out = btv->gq_out % MAX_GBUFFERS; - if (bttv_debug) - printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab); - btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; - btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; - bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); - btwrite(BT848_COLOR_CTL_GAMMA, - BT848_COLOR_CTL); - spin_unlock(&btv->s_lock); - } - } - if (astat&BT848_INT_OCERR) - { - IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr)); - } - if (astat&BT848_INT_PABORT) - { - IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr)); - } - if (astat&BT848_INT_RIPERR) - { - IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr)); - } - if (astat&BT848_INT_PPERR) - { - IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr)); - } - if (astat&BT848_INT_FDSR) - { - IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr)); - } - if (astat&BT848_INT_FTRGT) - { - IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr)); - } - if (astat&BT848_INT_FBUS) - { - IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr)); - } - if (astat&BT848_INT_HLOCK) - { - if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) - audio(btv, AUDIO_ON,0); - else - audio(btv, AUDIO_OFF,0); - } - - if (astat&BT848_INT_I2CDONE) - { - IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); - } - count++; - if (count > 10) - printk (KERN_WARNING "bttv%d: irq loop %d\n", - btv->nr,count); - if (count > 20) - { - btwrite(0, BT848_INT_MASK); - printk(KERN_ERR - "bttv%d: IRQ lockup, cleared int mask\n", btv->nr); - } - } -} - - - -/* - * Scan for a Bt848 card, request the irq and map the io memory - */ - -static void __devinit bttv_remove(struct pci_dev *pci_dev) -{ - u8 command; - int j; - struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); - - /* unregister i2c_bus */ - if (0 == btv->i2c_ok) - i2c_bit_del_bus(&btv->i2c_adap); - - /* turn off all capturing, DMA and IRQs */ - btand(~15, BT848_GPIO_DMA_CTL); - - /* first disable interrupts before unmapping the memory! */ - btwrite(0, BT848_INT_MASK); - btwrite(~0x0UL,BT848_INT_STAT); - btwrite(0x0, BT848_GPIO_OUT_EN); - - /* disable PCI bus-mastering */ - pci_read_config_byte(btv->dev, PCI_COMMAND, &command); - /* Should this be &=~ ?? */ - command&=~PCI_COMMAND_MASTER; - pci_write_config_byte(btv->dev, PCI_COMMAND, command); - - /* unmap and free memory */ - for (j = 0; j < gbuffers; j++) - if (btv->gbuf[j].risc) - kfree(btv->gbuf[j].risc); - if (btv->gbuf) - kfree((void *) btv->gbuf); - - if (btv->risc_scr_odd) - kfree((void *) btv->risc_scr_odd); - - if (btv->risc_scr_even) - kfree((void *) btv->risc_scr_even); - - DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); - if (btv->risc_jmp) - kfree((void *) btv->risc_jmp); - - DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf)); - if (btv->vbibuf) - vfree((void *) btv->vbibuf); - - free_irq(btv->irq,btv); - DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); - if (btv->bt848_mem) - iounmap(btv->bt848_mem); - - if(btv->video_dev.minor!=-1) - video_unregister_device(&btv->video_dev); - if(btv->vbi_dev.minor!=-1) - video_unregister_device(&btv->vbi_dev); - if (radio[btv->nr] && btv->radio_dev.minor != -1) - video_unregister_device(&btv->radio_dev); - - release_mem_region(btv->bt848_adr, - pci_resource_len(btv->dev,0)); - /* wake up any waiting processes - because shutdown flag is set, no new processes (in this queue) - are expected - */ - btv->shutdown=1; - wake_up(&btv->gpioq); - - return; -} - - -static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) -{ - int result; - unsigned char command; - struct bttv *btv; -#if defined(__powerpc__) - unsigned int cmd; -#endif - - printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); - - btv=&bttvs[bttv_num]; - btv->dev=dev; - btv->nr = bttv_num; - btv->bt848_mem=NULL; - btv->vbibuf=NULL; - btv->risc_jmp=NULL; - btv->vbi_odd=NULL; - btv->vbi_even=NULL; - init_waitqueue_head(&btv->vbiq); - init_waitqueue_head(&btv->capq); - btv->vbip=VBIBUF_SIZE; - btv->s_lock = SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&btv->gpioq); - btv->shutdown=0; - - btv->id=dev->device; - btv->irq=dev->irq; - btv->bt848_adr=pci_resource_start(dev,0); - if (pci_enable_device(dev)) - return -EIO; - if (!request_mem_region(pci_resource_start(dev,0), - pci_resource_len(dev,0), - "bttv")) { - return -EBUSY; - } - if (btv->id >= 878) - btv->i2c_command = 0x83; - else - btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); - printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", - bttv_num,btv->id, btv->revision); - printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn); - printk("irq: %d, ",btv->irq); - printk("memory: 0x%lx.\n", btv->bt848_adr); - -#if defined(__powerpc__) - /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ - /* response on cards with no firmware is not enabled by OF */ - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY ); - pci_write_config_dword(dev, PCI_COMMAND, cmd); -#endif - -#ifdef __sparc__ - btv->bt848_mem=(unsigned char *)btv->bt848_adr; -#else - btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); -#endif - - /* clear interrupt mask */ - btwrite(0, BT848_INT_MASK); - - result = request_irq(btv->irq, bttv_irq, - SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); - if (result==-EINVAL) - { - printk(KERN_ERR "bttv%d: Bad irq number or handler\n", - bttv_num); - goto fail; - } - if (result==-EBUSY) - { - printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq); - goto fail; - } - if (result < 0) - goto fail; - - pci_set_master(dev); - - btv->triton1=triton1 ? BT848_INT_ETBF : 0; - if (triton1 && btv->id >= 878) - { - btv->triton1 = 0; - printk("bttv: Enabling 430FX compatibilty for bt878\n"); - pci_read_config_byte(dev, BT878_DEVCTRL, &command); - command|=BT878_EN_TBFX; - pci_write_config_byte(dev, BT878_DEVCTRL, command); - pci_read_config_byte(dev, BT878_DEVCTRL, &command); - if (!(command&BT878_EN_TBFX)) - { - printk("bttv: 430FX compatibility could not be enabled\n"); - free_irq(btv->irq,btv); - result = -1; - goto fail; - } - } - - PCI_SET_DRIVER_DATA(dev,btv); - - if(init_bt848(btv) < 0) { - bttv_remove(dev); - return -EIO; - } - bttv_num++; - - return 0; - - fail: - release_mem_region(pci_resource_start(btv->dev,0), - pci_resource_len(btv->dev,0)); - return result; -} - -static struct pci_device_id bttv_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); - -static struct pci_driver bttv_pci_driver = { - name: "bttv", - id_table: bttv_pci_tbl, - probe: bttv_probe, - remove: bttv_remove, -}; - -int bttv_init_module(void) -{ - bttv_num = 0; - - printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", - (BTTV_VERSION_CODE >> 16) & 0xff, - (BTTV_VERSION_CODE >> 8) & 0xff, - BTTV_VERSION_CODE & 0xff); - if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) - gbuffers = 2; - if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) - gbufsize = BTTV_MAX_FBUF; - if (bttv_verbose) - printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", - gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); - - handle_chipset(); - - return pci_module_init(&bttv_pci_driver); -} - -void bttv_cleanup_module(void) -{ - pci_unregister_driver(&bttv_pci_driver); - return; -} - -module_init(bttv_init_module); -module_exit(bttv_cleanup_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/bttv-if.c linux/drivers/char/bttv-if.c --- v2.4.0-test6/linux/drivers/char/bttv-if.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/bttv-if.c Wed Dec 31 16:00:00 1969 @@ -1,337 +0,0 @@ -/* - bttv-if.c -- interfaces to other kernel modules - all the i2c code is here - also the gpio interface exported by bttv (used by lirc) - - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999,2000 Gerd Knorr - - 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. - -*/ - -#define __NO_VERSION__ 1 - -#include -#include -#include - -#include - -#include "bttv.h" -#include "tuner.h" - - -EXPORT_SYMBOL(bttv_get_cardinfo); -EXPORT_SYMBOL(bttv_get_id); -EXPORT_SYMBOL(bttv_gpio_enable); -EXPORT_SYMBOL(bttv_read_gpio); -EXPORT_SYMBOL(bttv_write_gpio); -EXPORT_SYMBOL(bttv_get_gpio_queue); - -/* ----------------------------------------------------------------------- */ -/* Exported functions - for other modules which want to access the */ -/* gpio ports (IR for example) */ -/* see bttv.h for comments */ - -int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) -{ - if (card >= bttv_num) { - return -1; - } - *type = bttvs[card].type; - *cardid = bttvs[card].cardid; - return 0; -} - -int bttv_get_id(unsigned int card) -{ - printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); - if (card >= bttv_num) { - return -1; - } - return bttvs[card].type; -} - -int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = &bttvs[card]; - btaor(data, ~mask, BT848_GPIO_OUT_EN); - return 0; -} - -int bttv_read_gpio(unsigned int card, unsigned long *data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = &bttvs[card]; - - if(btv->shutdown) { - return -ENODEV; - } - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because we set direct input on init */ - *data = btread(BT848_GPIO_DATA); - return 0; -} - -int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = &bttvs[card]; - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because direct input is set on init */ - btaor(data & mask, ~mask, BT848_GPIO_DATA); - return 0; -} - -wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return NULL; - } - - btv = &bttvs[card]; - if (bttvs[card].shutdown) { - return NULL; - } - return &btv->gpioq; -} - - -/* ----------------------------------------------------------------------- */ -/* I2C functions */ - -void bttv_bit_setscl(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x02; - else - btv->i2c_state &= ~0x02; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -void bttv_bit_setsda(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x01; - else - btv->i2c_state &= ~0x01; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -static int bttv_bit_getscl(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x02 ? 1 : 0; - return state; -} - -static int bttv_bit_getsda(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x01; - return state; -} - -static void bttv_inc_use(struct i2c_adapter *adap) -{ - MOD_INC_USE_COUNT; -} - -static void bttv_dec_use(struct i2c_adapter *adap) -{ - MOD_DEC_USE_COUNT; -} - -static int attach_inform(struct i2c_client *client) -{ - struct bttv *btv = (struct bttv*)client->adapter->data; - int i; - - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (btv->i2c_clients[i] == NULL || - btv->i2c_clients[i]->driver->id == client->driver->id) { - btv->i2c_clients[i] = client; - break; - } - } - if (btv->tuner_type != -1) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - if (bttv_verbose) - printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); - return 0; -} - -static int detach_inform(struct i2c_client *client) -{ - struct bttv *btv = (struct bttv*)client->adapter->data; - int i; - - if (bttv_verbose) - printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (NULL != btv->i2c_clients[i] && - btv->i2c_clients[i]->driver->id == client->driver->id) { - btv->i2c_clients[i] = NULL; - break; - } - } - return 0; -} - -void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) -{ - int i; - - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (NULL == btv->i2c_clients[i]) - continue; - if (NULL == btv->i2c_clients[i]->driver->command) - continue; - btv->i2c_clients[i]->driver->command( - btv->i2c_clients[i],cmd,arg); - } -} - -struct i2c_algo_bit_data bttv_i2c_algo_template = { - NULL, - bttv_bit_setsda, - bttv_bit_setscl, - bttv_bit_getsda, - bttv_bit_getscl, - 10, 10, 100, -}; - -struct i2c_adapter bttv_i2c_adap_template = { - "bt848", - I2C_HW_B_BT848, - NULL, - NULL, - bttv_inc_use, - bttv_dec_use, - attach_inform, - detach_inform, - NULL, -}; - -struct i2c_client bttv_i2c_client_template = { - "bttv internal", - -1, - 0, - 0, - NULL, - NULL -}; - - -/* read I2C */ -int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) -{ - unsigned char buffer = 0; - - if (0 != btv->i2c_ok) - return -1; - if (bttv_verbose && NULL != probe_for) - printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", - btv->nr,probe_for,addr); - btv->i2c_client.addr = addr >> 1; - if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { - if (NULL != probe_for) { - if (bttv_verbose) - printk("not found\n"); - } else - printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", - btv->nr,addr); - return -1; - } - if (bttv_verbose && NULL != probe_for) - printk("found\n"); - return buffer; -} - -/* write I2C */ -int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both) -{ - unsigned char buffer[2]; - int bytes = both ? 2 : 1; - - if (0 != btv->i2c_ok) - return -1; - btv->i2c_client.addr = addr >> 1; - buffer[0] = b1; - buffer[1] = b2; - if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) - return -1; - return 0; -} - -/* read EEPROM content */ -void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) -{ - int i; - - if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) { - printk(KERN_WARNING "bttv: readee error\n"); - return; - } - btv->i2c_client.addr = addr >> 1; - for (i=0; i<256; i+=16) { - if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { - printk(KERN_WARNING "bttv: readee error\n"); - break; - } - } -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.4.0-test6/linux/drivers/char/bttv.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/bttv.h Wed Dec 31 16:00:00 1969 @@ -1,425 +0,0 @@ -/* - 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. -*/ - -#ifndef _BTTV_H_ -#define _BTTV_H_ - -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,38) - -#ifndef PCI_GET_DRIVER_DATA -# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) -# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - -#include -#include -#include -#include -#include - -#include "audiochip.h" -#include "bt848.h" - -#ifdef __KERNEL__ - -/* fwd decl */ -struct bttv; - - -/* ---------------------------------------------------------- */ -/* exported by bttv-cards.c */ - -#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 BTTV_AVERMEDIA 0x06 -#define BTTV_MATRIX_VISION 0x07 -#define BTTV_FLYVIDEO 0x08 -#define BTTV_TURBOTV 0x09 -#define BTTV_HAUPPAUGE878 0x0a -#define BTTV_MIROPRO 0x0b -#define BTTV_ADSTECH_TV 0x0c -#define BTTV_AVERMEDIA98 0x0d -#define BTTV_VHX 0x0e -#define BTTV_ZOLTRIX 0x0f -#define BTTV_PIXVIEWPLAYTV 0x10 -#define BTTV_WINVIEW_601 0x11 -#define BTTV_AVEC_INTERCAP 0x12 -#define BTTV_LIFE_FLYKIT 0x13 -#define BTTV_CEI_RAFFLES 0x14 -#define BTTV_CONFERENCETV 0x15 -#define BTTV_PHOEBE_TVMAS 0x16 -#define BTTV_MODTEC_205 0x17 -#define BTTV_MAGICTVIEW061 0x18 -#define BTTV_VOBIS_BOOSTAR 0x19 -#define BTTV_HAUPPAUG_WCAM 0x1a -#define BTTV_MAXI 0x1b -#define BTTV_TERRATV 0x1c -#define BTTV_PXC200 0x1d -#define BTTV_FLYVIDEO_98 0x1e -#define BTTV_IPROTV 0x1f -#define BTTV_INTEL_C_S_PCI 0x20 -#define BTTV_TERRATVALUE 0x21 -#define BTTV_WINFAST2000 0x22 -#define BTTV_CHRONOS_VS2 0x23 -#define BTTV_TYPHOON_TVIEW 0x24 -#define BTTV_PXELVWPLTVPRO 0x25 -#define BTTV_MAGICTVIEW063 0x26 -#define BTTV_PINNACLERAVE 0x27 -#define BTTV_STB2 0x28 -#define BTTV_AVPHONE98 0x29 -#define BTTV_PV951 0x2a -#define BTTV_ONAIR_TV 0x2b -#define BTTV_SIGMA_TVII_FM 0x2c -#define BTTV_MATRIX_VISION2 0x2d -#define BTTV_ZOLTRIX_GENIE 0x2e -#define BTTV_TERRATVRADIO 0x2f -#define BTTV_DYNALINK 0x30 - -struct tvcard -{ - char *name; - int video_inputs; - int audio_inputs; - int tuner; - int svhs; - u32 gpiomask; - u32 muxsel[8]; - u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ - u32 gpiomask2; /* GPIO MUX mask */ - - /* look for these i2c audio chips */ - int msp34xx:1; - int tda8425:1; - int tda9840:1; - int tda985x:1; - int tea63xx:1; - int tea64xx:1; - int tda7432:1; - int tda9875:1; - - /* other settings */ - int pll; -#define PLL_NONE 0 -#define PLL_28 1 -#define PLL_35 2 - - int tuner_type; -}; - -extern struct tvcard bttv_tvcards[]; -extern const int bttv_num_tvcards; - -/* identification / initialization of the card */ -extern void bttv_idcard(struct bttv *btv); - -/* card-specific funtions */ -extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); -extern void winview_setvol(struct bttv *btv, struct video_audio *v); - -/* ---------------------------------------------------------- */ -/* exported by bttv-if.c */ -/* interface for gpio access by other modules */ - -/* returns card type + card ID (for bt878-based ones) - for possible values see lines below beginning with #define BTTV_UNKNOWN - returns negative value if error ocurred -*/ -extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid); - -/* obsolete, use bttv_get_cardinfo instead */ -extern int bttv_get_id(unsigned int card); - -/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: - data | (current_GPOE_value & ~mask) - returns negative value if error ocurred -*/ -extern int bttv_gpio_enable(unsigned int card, - unsigned long mask, unsigned long data); - -/* fills data with GPDATA register contents - returns negative value if error ocurred -*/ -extern int bttv_read_gpio(unsigned int card, unsigned long *data); - -/* sets GPDATA register to new value: - (data & mask) | (current_GPDATA_value & ~mask) - returns negative value if error ocurred -*/ -extern int bttv_write_gpio(unsigned int card, - unsigned long mask, unsigned long data); - -/* returns pointer to task queue which can be used as parameter to - interruptible_sleep_on - in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated - (wake_up_interruptible) and following call to the function bttv_read_gpio - should return new value of GPDATA, - returns NULL value if error ocurred or queue is not available - WARNING: because there is no buffer for GPIO data, one MUST - process data ASAP -*/ -extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); - -/* i2c */ -struct i2c_algo_bit_data bttv_i2c_algo_template; -struct i2c_adapter bttv_i2c_adap_template; -struct i2c_client bttv_i2c_client_template; -void bttv_bit_setscl(void *data, int state); -void bttv_bit_setsda(void *data, int state); -void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); -int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); -int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both); -void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); - - -/* ---------------------------------------------------------- */ -/* bttv-driver.c */ - -/* insmod options */ -extern unsigned int bttv_verbose; -extern unsigned int bttv_debug; - -/* Anybody who uses more than four? */ -#define BTTV_MAX 4 -extern int bttv_num; /* number of Bt848s in use */ -extern struct bttv bttvs[BTTV_MAX]; - - -#ifndef O_NONCAP -#define O_NONCAP O_TRUNC -#endif - -#define MAX_GBUFFERS 64 -#define RISCMEM_LEN (32744*2) -#define VBI_MAXLINES 16 -#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) - -#define BTTV_MAX_FBUF 0x208000 -#define I2C_CLIENTS_MAX 8 - -struct bttv_window -{ - int x, y; - ushort width, height; - ushort bpp, bpl; - ushort swidth, sheight; - unsigned long vidadr; - ushort freq; - int norm; - int interlace; - int color_fmt; - ushort depth; -}; - -struct bttv_pll_info { - unsigned int pll_ifreq; /* PLL input frequency */ - unsigned int pll_ofreq; /* PLL output frequency */ - unsigned int pll_crystal; /* Crystal used for input */ - unsigned int pll_current; /* Currently programmed ofreq */ -}; - -struct bttv_gbuf { - int stat; -#define GBUFFER_UNUSED 0 -#define GBUFFER_GRABBING 1 -#define GBUFFER_DONE 2 -#define GBUFFER_ERROR 3 - struct timeval tv; - - u16 width; - u16 height; - u16 fmt; - - u32 *risc; - unsigned long ro; - unsigned long re; -}; - -struct bttv { - struct video_device video_dev; - struct video_device radio_dev; - struct video_device vbi_dev; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ - - spinlock_t s_lock; - struct semaphore lock; - int user; - int capuser; - - /* i2c */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - int i2c_state, i2c_ok; - struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; - - int tuner_type; - int channel; - - unsigned int nr; - unsigned short id; - struct pci_dev *dev; - unsigned int irq; /* IRQ used by Bt848 card */ - unsigned char revision; - unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ - unsigned char *bt848_mem; /* pointer to mapped IO memory */ - unsigned long busriscmem; - u32 *riscmem; - - unsigned char *vbibuf; - struct bttv_window win; - int fb_color_ctl; - int type; /* card type */ - int cardid; - int audio; /* audio mode */ - int audio_chip; /* set to one of the chips supported by bttv.c */ - int radio; - - u32 *risc_jmp; - u32 *vbi_odd; - u32 *vbi_even; - u32 bus_vbi_even; - u32 bus_vbi_odd; - wait_queue_head_t vbiq; - wait_queue_head_t capq; - int vbip; - - u32 *risc_scr_odd; - u32 *risc_scr_even; - u32 risc_cap_odd; - u32 risc_cap_even; - int scr_on; - int vbi_on; - struct video_clip *cliprecs; - - struct bttv_gbuf *gbuf; - int gqueue[MAX_GBUFFERS]; - int gq_in,gq_out,gq_grab,gq_start; - char *fbuffer; - - struct bttv_pll_info pll; - unsigned int Fsc; - unsigned int field; - unsigned int last_field; /* number of last grabbed field */ - int i2c_command; - int triton1; - - int errors; - int needs_restart; - - wait_queue_head_t gpioq; - int shutdown; -}; -#endif - -#if defined(__powerpc__) /* big-endian */ -extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) -{ - __asm__ __volatile__ ("stwbrx %1,0,%2" : \ - "=m" (*addr) : "r" (val), "r" (addr)); - __asm__ __volatile__ ("eieio" : : : "memory"); -} - -#define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) -#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(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_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]) -#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]) -#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int) -#define BTTV_PLLSET _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info) -#define BTTV_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int) -#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int) -#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) -#define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int) -#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) - -#define AUDIO_TUNER 0x00 -#define AUDIO_RADIO 0x01 -#define AUDIO_EXTERN 0x02 -#define AUDIO_INTERN 0x03 -#define AUDIO_OFF 0x04 -#define AUDIO_ON 0x05 -#define AUDIO_MUTE 0x80 -#define AUDIO_UNMUTE 0x81 - -#define TDA9850 0x01 -#define TDA9840 0x02 -#define TDA8425 0x03 -#define TEA6300 0x04 - -#define I2C_TSA5522 0xc2 -#define I2C_TDA7432 0x8a -#define I2C_TDA8425 0x82 -#define I2C_TDA9840 0x84 -#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ -#define I2C_TDA9875 0xb0 -#define I2C_HAUPEE 0xa0 -#define I2C_STBEE 0xae -#define I2C_VHX 0xc0 -#define I2C_MSP3400 0x80 -#define I2C_TEA6300 0x80 -#define I2C_DPL3518 0x84 - -#ifndef HAVE_TVAUDIO -#define TDA9840_SW 0x00 -#define TDA9840_LVADJ 0x02 -#define TDA9840_STADJ 0x03 -#define TDA9840_TEST 0x04 -#endif - -#define PT2254_L_CHANEL 0x10 -#define PT2254_R_CHANEL 0x08 -#define PT2254_DBS_IN_2 0x400 -#define PT2254_DBS_IN_10 0x20000 -#define WINVIEW_PT2254_CLK 0x40 -#define WINVIEW_PT2254_DATA 0x20 -#define WINVIEW_PT2254_STROBE 0x80 - -struct bttv_just_hacking { - int height,width; /* size */ - unsigned int format; /* should be VIDEO_PALETTE_* */ - long buf; - int len; -}; - -#define BTTV_JUST_HACKING _IOR('v' , BASE_VIDIOCPRIVATE+31,struct bttv_just_hacking) - -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/buz.c linux/drivers/char/buz.c --- v2.4.0-test6/linux/drivers/char/buz.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/buz.c Wed Dec 31 16:00:00 1969 @@ -1,3479 +0,0 @@ -#define MAX_KMALLOC_MEM (512*1024) -/* - buz - Iomega Buz driver version 1.0 - - Copyright (C) 1999 Rainer Johanni - - based on - - buz.0.0.3 Copyright (C) 1998 Dave Perks - - and - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include "buz.h" -#include -#include - -#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) -#define GPIO_MASK 0xdf - -/* - - BUZ - - GPIO0 = 1, take board out of reset - GPIO1 = 1, take JPEG codec out of sleep mode - GPIO3 = 1, deassert FRAME# to 36060 - - - GIRQ0 signals a vertical sync of the video signal - GIRQ1 signals that ZR36060's DATERR# line is asserted. - - SAA7111A - - In their infinite wisdom, the Iomega engineers decided to - use the same input line for composite and S-Video Color, - although there are two entries not connected at all! - Through this ingenious strike, it is not possible to - keep two running video sources connected at the same time - to Composite and S-VHS input! - - mode 0 - N/C - mode 1 - S-Video Y - mode 2 - noise or something I don't know - mode 3 - Composite and S-Video C - mode 4 - N/C - mode 5 - S-Video (gain C independently selectable of gain Y) - mode 6 - N/C - mode 7 - S-Video (gain C adapted to gain Y) - */ - -#define MAJOR_VERSION 1 /* driver major version */ -#define MINOR_VERSION 0 /* driver minor version */ - -#define BUZ_NAME "Iomega BUZ V-1.0" /* name of the driver */ - -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ -#define IOCTL_DEBUG(x) - - -/* The parameters for this driver */ - -/* - The video mem address of the video card. - The driver has a little database for some videocards - to determine it from there. If your video card is not in there - you have either to give it to the driver as a parameter - or set in in a VIDIOCSFBUF ioctl - */ - -static unsigned long vidmem = 0; /* Video memory base address */ - -/* Special purposes only: */ - -static int triton = 0; /* 0=no, 1=yes */ -static int natoma = 0; /* 0=no, 1=yes */ - -/* - Number and size of grab buffers for Video 4 Linux - The vast majority of applications should not need more than 2, - the very popular BTTV driver actually does ONLY have 2. - Time sensitive applications might need more, the maximum - is VIDEO_MAX_FRAME (defined in ). - - The size is set so that the maximum possible request - can be satisfied. Decrease it, if bigphys_area alloc'd - memory is low. If you don't have the bigphys_area patch, - set it to 128 KB. Will you allow only to grab small - images with V4L, but that's better than nothing. - - v4l_bufsize has to be given in KB ! - - */ - -static int v4l_nbufs = 2; -static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ - -/* - Default input and video norm at startup of the driver. - */ - -static int default_input = 0; /* 0=Composite, 1=S-VHS */ -static int default_norm = 0; /* 0=PAL, 1=NTSC */ - -MODULE_PARM(vidmem, "i"); -MODULE_PARM(triton, "i"); -MODULE_PARM(natoma, "i"); -MODULE_PARM(v4l_nbufs, "i"); -MODULE_PARM(v4l_bufsize, "i"); -MODULE_PARM(default_input, "i"); -MODULE_PARM(default_norm, "i"); - -/* Anybody who uses more than four? */ -#define BUZ_MAX 4 - -static int zoran_num; /* number of Buzs in use */ -static struct zoran zoran[BUZ_MAX]; - -/* forward references */ - -static void v4l_fbuffer_free(struct zoran *zr); -static void jpg_fbuffer_free(struct zoran *zr); -static void zoran_feed_stat_com(struct zoran *zr); - - - -/* - * Allocate the V4L grab buffers - * - * These have to be pysically contiguous. - * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc - */ - -static int v4l_fbuffer_alloc(struct zoran *zr) -{ - int i, off; - unsigned char *mem; - - for (i = 0; i < v4l_nbufs; i++) { - if (zr->v4l_gbuf[i].fbuffer) - printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); - - if (v4l_bufsize <= MAX_KMALLOC_MEM) { - /* Use kmalloc */ - - mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); - if (mem == 0) { - printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name); - v4l_fbuffer_free(zr); - return -ENOBUFS; - } - zr->v4l_gbuf[i].fbuffer = mem; - zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); - zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); - for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) - mem_map_reserve(virt_to_page(mem + off)); - DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); - } else { - return -ENOBUFS; - } - } - - return 0; -} - -/* free the V4L grab buffers */ -static void v4l_fbuffer_free(struct zoran *zr) -{ - int i, off; - unsigned char *mem; - - for (i = 0; i < v4l_nbufs; i++) { - if (!zr->v4l_gbuf[i].fbuffer) - continue; - - mem = zr->v4l_gbuf[i].fbuffer; - for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) - mem_map_unreserve(virt_to_page(mem + off)); - kfree((void *) zr->v4l_gbuf[i].fbuffer); - zr->v4l_gbuf[i].fbuffer = NULL; - } -} - -/* - * Allocate the MJPEG grab buffers. - * - * If the requested buffer size is smaller than MAX_KMALLOC_MEM, - * kmalloc is used to request a physically contiguous area, - * else we allocate the memory in framgents with get_free_page. - * - * If a Natoma chipset is present and this is a revision 1 zr36057, - * each MJPEG buffer needs to be physically contiguous. - * (RJ: This statement is from Dave Perks' original driver, - * I could never check it because I have a zr36067) - * The driver cares about this because it reduces the buffer - * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). - * - * RJ: The contents grab buffers needs never be accessed in the driver. - * Therefore there is no need to allocate them with vmalloc in order - * to get a contiguous virtual memory space. - * I don't understand why many other drivers first allocate them with - * vmalloc (which uses internally also get_free_page, but delivers you - * virtual addresses) and then again have to make a lot of efforts - * to get the physical address. - * - */ - -static int jpg_fbuffer_alloc(struct zoran *zr) -{ - int i, j, off, alloc_contig; - unsigned long mem; - - /* Decide if we should alloc contiguous or fragmented memory */ - /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - - alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); - - for (i = 0; i < zr->jpg_nbufs; i++) { - if (zr->jpg_gbuf[i].frag_tab) - printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i); - - /* Allocate fragment table for this buffer */ - - mem = get_free_page(GFP_KERNEL); - if (mem == 0) { - printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i); - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - memset((void *) mem, 0, PAGE_SIZE); - zr->jpg_gbuf[i].frag_tab = (u32 *) mem; - zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); - - if (alloc_contig) { - mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); - if (mem == 0) { - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); - zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1; - for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) - mem_map_reserve(virt_to_page(mem + off)); - } else { - /* jpg_bufsize is alreay page aligned */ - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - mem = get_free_page(GFP_KERNEL); - if (mem == 0) { - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem); - zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1; - mem_map_reserve(virt_to_page(mem)); - } - - zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; - } - } - - DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n", - (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); - zr->jpg_buffers_allocated = 1; - return 0; -} - -/* free the MJPEG grab buffers */ -static void jpg_fbuffer_free(struct zoran *zr) -{ - int i, j, off, alloc_contig; - unsigned char *mem; - - /* Decide if we should alloc contiguous or fragmented memory */ - /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - - alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); - - for (i = 0; i < zr->jpg_nbufs; i++) { - if (!zr->jpg_gbuf[i].frag_tab) - continue; - - if (alloc_contig) { - if (zr->jpg_gbuf[i].frag_tab[0]) { - mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]); - for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) - mem_map_unreserve(virt_to_page(mem + off)); - kfree((void *) mem); - zr->jpg_gbuf[i].frag_tab[0] = 0; - zr->jpg_gbuf[i].frag_tab[1] = 0; - } - } else { - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - if (!zr->jpg_gbuf[i].frag_tab[2 * j]) - break; - mem_map_unreserve(virt_to_page(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]))); - free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])); - zr->jpg_gbuf[i].frag_tab[2 * j] = 0; - zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; - } - } - - free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); - zr->jpg_gbuf[i].frag_tab = NULL; - } - zr->jpg_buffers_allocated = 0; -} - - -/* ----------------------------------------------------------------------- */ - -/* I2C functions */ - -#define I2C_DELAY 10 - - -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) -{ - struct zoran *zr = (struct zoran *) bus->data; - btwrite((data << 1) | ctrl, ZR36057_I2CBR); - btread(ZR36057_I2CBR); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct zoran *zr = (struct zoran *) bus->data; - return (btread(ZR36057_I2CBR) >> 1) & 1; -} - -static void attach_inform(struct i2c_bus *bus, int id) -{ - DEBUG(struct zoran *zr = (struct zoran *) bus->data); - DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id)); -} - -static void detach_inform(struct i2c_bus *bus, int id) -{ - DEBUG(struct zoran *zr = (struct zoran *) bus->data); - DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); -} - -static struct i2c_bus zoran_i2c_bus_template = -{ - "zr36057", - I2C_BUSID_BT848, - NULL, - - SPIN_LOCK_UNLOCKED, - - attach_inform, - detach_inform, - - i2c_setlines, - i2c_getdataline, - NULL, - NULL, -}; - - -/* ----------------------------------------------------------------------- */ - -static void GPIO(struct zoran *zr, unsigned bit, unsigned value) -{ - u32 reg; - u32 mask; - - mask = 1 << (24 + bit); - reg = btread(ZR36057_GPPGCR1) & ~mask; - if (value) { - reg |= mask; - } - btwrite(reg, ZR36057_GPPGCR1); - /* Stop any PCI posting on the GPIO bus */ - btread(ZR36057_I2CBR); -} - - -/* - * Set the registers for the size we have specified. Don't bother - * trying to understand this without the ZR36057 manual in front of - * you [AC]. - * - * PS: The manual is free for download in .pdf format from - * www.zoran.com - nicely done those folks. - */ - -struct tvnorm { - u16 Wt, Wa, Ht, Ha, HStart, VStart; -}; - -static struct tvnorm tvnorms[] = -{ - /* PAL-BDGHI */ - {864, 720, 625, 576, 31, 16}, - /* NTSC */ - {858, 720, 525, 480, 21, 8}, -}; -#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm)) - -static int format2bpp(int format) -{ - int bpp; - - /* Determine the number of bytes per pixel for the video format requested */ - - switch (format) { - - case VIDEO_PALETTE_YUV422: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB555: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB565: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB24: - bpp = 3; - break; - - case VIDEO_PALETTE_RGB32: - bpp = 4; - break; - - default: - bpp = 0; - } - - return bpp; -} - -/* - * set geometry - */ -static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, - unsigned int video_format) -{ - struct tvnorm *tvn; - unsigned HStart, HEnd, VStart, VEnd; - unsigned DispMode; - unsigned VidWinWid, VidWinHt; - unsigned hcrop1, hcrop2, vcrop1, vcrop2; - unsigned Wa, We, Ha, He; - unsigned X, Y, HorDcm, VerDcm; - u32 reg; - unsigned mask_line_size; - - if (zr->params.norm < 0 || zr->params.norm > 1) { - printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name, zr->params.norm); - return; - } - if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) { - printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height); - return; - } - tvn = &tvnorms[zr->params.norm]; - - Wa = tvn->Wa; - Ha = tvn->Ha; - - /* if window has more than half of active height, - switch on interlacing - we want the full information */ - - zr->video_interlace = (video_height > Ha / 2); - -/**** zr36057 ****/ - - /* horizontal */ - VidWinWid = video_width; - X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; - We = (VidWinWid * 64) / X; - HorDcm = 64 - X; - hcrop1 = 2 * ((tvn->Wa - We) / 4); - hcrop2 = tvn->Wa - We - hcrop1; - HStart = tvn->HStart | 1; - HEnd = HStart + tvn->Wa - 1; - HStart += hcrop1; - HEnd -= hcrop2; - reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) - | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); - reg |= ZR36057_VFEHCR_HSPol; - btwrite(reg, ZR36057_VFEHCR); - - /* Vertical */ - DispMode = !zr->video_interlace; - VidWinHt = DispMode ? video_height : video_height / 2; - Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; - He = (VidWinHt * 64) / Y; - VerDcm = 64 - Y; - vcrop1 = (tvn->Ha / 2 - He) / 2; - vcrop2 = tvn->Ha / 2 - He - vcrop1; - VStart = tvn->VStart; - VEnd = VStart + tvn->Ha / 2 - 1; - VStart += vcrop1; - VEnd -= vcrop2; - reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) - | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); - reg |= ZR36057_VFEVCR_VSPol; - btwrite(reg, ZR36057_VFEVCR); - - /* scaler and pixel format */ - reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ - | (HorDcm << ZR36057_VFESPFR_HorDcm) - | (VerDcm << ZR36057_VFESPFR_VerDcm) - | (DispMode << ZR36057_VFESPFR_DispMode) - | ZR36057_VFESPFR_LittleEndian; - /* RJ: I don't know, why the following has to be the opposite - of the corresponding ZR36060 setting, but only this way - we get the correct colors when uncompressing to the screen */ - reg |= ZR36057_VFESPFR_VCLKPol; - /* RJ: Don't know if that is needed for NTSC also */ - reg |= ZR36057_VFESPFR_TopField; - switch (video_format) { - - case VIDEO_PALETTE_YUV422: - reg |= ZR36057_VFESPFR_YUV422; - break; - - case VIDEO_PALETTE_RGB555: - reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; - break; - - case VIDEO_PALETTE_RGB565: - reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; - break; - - case VIDEO_PALETTE_RGB24: - reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; - break; - - case VIDEO_PALETTE_RGB32: - reg |= ZR36057_VFESPFR_RGB888; - break; - - default: - printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); - return; - - } - if (HorDcm >= 48) { - reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ - } else if (HorDcm >= 32) { - reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ - } else if (HorDcm >= 16) { - reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ - } - btwrite(reg, ZR36057_VFESPFR); - - /* display configuration */ - - reg = (16 << ZR36057_VDCR_MinPix) - | (VidWinHt << ZR36057_VDCR_VidWinHt) - | (VidWinWid << ZR36057_VDCR_VidWinWid); - if (triton) - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); - - /* Write overlay clipping mask data, but don't enable overlay clipping */ - /* RJ: since this makes only sense on the screen, we use - zr->window.width instead of video_width */ - - mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - reg = virt_to_bus(zr->overlay_mask); - btwrite(reg, ZR36057_MMTR); - reg = virt_to_bus(zr->overlay_mask + mask_line_size); - btwrite(reg, ZR36057_MMBR); - reg = mask_line_size - (zr->window.width + 31) / 32; - if (DispMode == 0) - reg += mask_line_size; - reg <<= ZR36057_OCR_MaskStride; - btwrite(reg, ZR36057_OCR); - -} - -/* - * Switch overlay on or off - */ - -static void zr36057_overlay(struct zoran *zr, int on) -{ - int fmt, bpp; - u32 reg; - - if (on) { - /* do the necessary settings ... */ - - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ - - switch (zr->buffer.depth) { - case 15: - fmt = VIDEO_PALETTE_RGB555; - bpp = 2; - break; - case 16: - fmt = VIDEO_PALETTE_RGB565; - bpp = 2; - break; - case 24: - fmt = VIDEO_PALETTE_RGB24; - bpp = 3; - break; - case 32: - fmt = VIDEO_PALETTE_RGB32; - bpp = 4; - break; - default: - fmt = 0; - bpp = 0; - } - - zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); - - /* Start and length of each line MUST be 4-byte aligned. - This should be allready checked before the call to this routine. - All error messages are internal driver checking only! */ - - /* video display top and bottom registers */ - - reg = (u32) zr->buffer.base - + zr->window.x * bpp - + zr->window.y * zr->buffer.bytesperline; - btwrite(reg, ZR36057_VDTR); - if (reg & 3) - printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); - if (zr->video_interlace) - reg += zr->buffer.bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - - reg = zr->buffer.bytesperline - zr->window.width * bpp; - if (zr->video_interlace) - reg += zr->buffer.bytesperline; - if (reg & 3) - printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ - btwrite(reg, ZR36057_VSSFGR); - - /* Set overlay clipping */ - - if (zr->window.clipcount) - btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); - - /* ... and switch it on */ - - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } else { - /* Switch it off */ - - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - } -} - -/* - * The overlay mask has one bit for each pixel on a scan line, - * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. - */ -static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count) -{ - unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - u32 *mask; - int x, y, width, height; - unsigned i, j, k; - u32 reg; - - /* fill mask with one bits */ - memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); - reg = 0; - - for (i = 0; i < count; ++i) { - /* pick up local copy of clip */ - x = vp[i].x; - y = vp[i].y; - width = vp[i].width; - height = vp[i].height; - - /* trim clips that extend beyond the window */ - if (x < 0) { - width += x; - x = 0; - } - if (y < 0) { - height += y; - y = 0; - } - if (x + width > zr->window.width) { - width = zr->window.width - x; - } - if (y + height > zr->window.height) { - height = zr->window.height - y; - } - /* ignore degenerate clips */ - if (height <= 0) { - continue; - } - if (width <= 0) { - continue; - } - /* apply clip for each scan line */ - for (j = 0; j < height; ++j) { - /* reset bit for each pixel */ - /* this can be optimized later if need be */ - mask = zr->overlay_mask + (y + j) * mask_line_size; - for (k = 0; k < width; ++k) { - mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); - } - } - } -} - -/* Enable/Disable uncompressed memory grabbing of the 36057 */ - -static void zr36057_set_memgrab(struct zoran *zr, int mode) -{ - if (mode) { - if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) - printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); - - /* switch on VSync interrupts */ - - btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts - - btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); - - /* enable SnapShot */ - - btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - - /* Set zr36057 video front end and enable video */ - -#ifdef XAWTV_HACK - zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat); -#else - zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); -#endif - - zr->v4l_memgrab_active = 1; - } else { - zr->v4l_memgrab_active = 0; - - /* switch off VSync interrupts */ - - btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); - - /* reenable grabbing to screen if it was running */ - - if (zr->v4l_overlay_active) { - zr36057_overlay(zr, 1); - } else { - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - } - } -} - -static int wait_grab_pending(struct zoran *zr) -{ - unsigned long flags; - - /* wait until all pending grabs are finished */ - - if (!zr->v4l_memgrab_active) - return 0; - - while (zr->v4l_pend_tail != zr->v4l_pend_head) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&zr->lock, flags); - zr36057_set_memgrab(zr, 0); - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} - -/* - * V4L Buffer grabbing - */ - -static int v4l_grab(struct zoran *zr, struct video_mmap *mp) -{ - unsigned long flags; - int res, bpp; - - /* - * There is a long list of limitations to what is allowed to be grabbed - * We don't output error messages her, since some programs (e.g. xawtv) - * just try several settings to find out what is valid or not. - */ - - /* No grabbing outside the buffer range! */ - - if (mp->frame >= v4l_nbufs || mp->frame < 0) - return -EINVAL; - - /* Check size and format of the grab wanted */ - - if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) - return -EINVAL; - if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) - return -EINVAL; - - bpp = format2bpp(mp->format); - if (bpp == 0) - return -EINVAL; - - /* Check against available buffer size */ - - if (mp->height * mp->width * bpp > v4l_bufsize) - return -EINVAL; - - /* The video front end needs 4-byte alinged line sizes */ - - if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) - return -EINVAL; - - /* - * To minimize the time spent in the IRQ routine, we avoid setting up - * the video front end there. - * If this grab has different parameters from a running streaming capture - * we stop the streaming capture and start it over again. - */ - - if (zr->v4l_memgrab_active && - (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { - res = wait_grab_pending(zr); - if (res) - return res; - } - zr->gwidth = mp->width; - zr->gheight = mp->height; - zr->gformat = mp->format; - zr->gbpl = bpp * zr->gwidth; - - - spin_lock_irqsave(&zr->lock, flags); - - /* make sure a grab isn't going on currently with this buffer */ - - switch (zr->v4l_gbuf[mp->frame].state) { - - default: - case BUZ_STATE_PEND: - res = -EBUSY; /* what are you doing? */ - break; - - case BUZ_STATE_USER: - case BUZ_STATE_DONE: - /* since there is at least one unused buffer there's room for at least one more pend[] entry */ - zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; - zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; - res = 0; - break; - - } - - /* put the 36057 into frame grabbing mode */ - - if (!res && !zr->v4l_memgrab_active) - zr36057_set_memgrab(zr, 1); - - spin_unlock_irqrestore(&zr->lock, flags); - - return res; -} - -/* - * Sync on a V4L buffer - */ - -static int v4l_sync(struct zoran *zr, int frame) -{ - unsigned long flags; - - - /* check passed-in frame number */ - if (frame >= v4l_nbufs || frame < 0) { - printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); - return -EINVAL; - } - /* Check if is buffer was queued at all */ - - if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { -// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); - return -EINVAL; - } - /* wait on this buffer to get ready */ - - while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - /* buffer should now be in BUZ_STATE_DONE */ - - if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) - printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); - - /* Check if streaming capture has finished */ - - spin_lock_irqsave(&zr->lock, flags); - - if (zr->v4l_pend_tail == zr->v4l_pend_head) - zr36057_set_memgrab(zr, 0); - - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} -/***************************************************************************** - * * - * Set up the Buz-specific MJPEG part * - * * - *****************************************************************************/ - -/* - * Wait til post office is no longer busy - */ - -static int post_office_wait(struct zoran *zr) -{ - u32 por; - u32 ct=0; - - while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { - ct++; - if(ct>100000) - { - printk(KERN_ERR "%s: timeout on post office.\n", zr->name); - return -1; - } - /* wait for something to happen */ - } - if ((por & ZR36057_POR_POPen) != 0) { - printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); - return -1; - } - if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { - printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); - return -1; - } - return 0; -} - -static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value) -{ - u32 por; - - post_office_wait(zr); - por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); - btwrite(por, ZR36057_POR); - return post_office_wait(zr); -} - -static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) -{ - u32 por; - - post_office_wait(zr); - por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); - btwrite(por, ZR36057_POR); - if (post_office_wait(zr) < 0) { - return -1; - } - return btread(ZR36057_POR) & 0xFF; -} - -static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) -{ - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg)) { - return -1; - } - return post_office_write(zr, 0, 3, val); -} - -static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_8(zr, reg + 0, val >> 8)) { - return -1; - } - return zr36060_write_8(zr, reg + 1, val >> 0); -} - -static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_8(zr, reg + 0, val >> 16)) { - return -1; - } - return zr36060_write_16(zr, reg + 1, val >> 0); -} - -static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_16(zr, reg + 0, val >> 16)) { - return -1; - } - return zr36060_write_16(zr, reg + 2, val >> 0); -} - -static u32 zr36060_read_8(struct zoran *zr, unsigned reg) -{ - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg)) { - return -1; - } - return post_office_read(zr, 0, 3) & 0xFF; -} - -static int zr36060_reset(struct zoran *zr) -{ - return post_office_write(zr, 3, 0, 0); -} - -static void zr36060_sleep(struct zoran *zr, int sleep) -{ - GPIO(zr, 1, !sleep); -} - - -static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - int size; - - reg = (1 << 0) /* CodeMstr */ - |(0 << 2) /* CFIS=0 */ - |(0 << 6) /* Endian=0 */ - |(0 << 7); /* Code16=0 */ - zr36060_write_8(zr, 0x002, reg); - - switch (mode) { - - case BUZ_MODE_MOTION_DECOMPRESS: - case BUZ_MODE_STILL_DECOMPRESS: - reg = 0x00; /* Codec mode = decompression */ - break; - - case BUZ_MODE_MOTION_COMPRESS: - case BUZ_MODE_STILL_COMPRESS: - default: - reg = 0xa4; /* Codec mode = compression with variable scale factor */ - break; - - } - zr36060_write_8(zr, 0x003, reg); - - reg = 0x00; /* reserved, mbz */ - zr36060_write_8(zr, 0x004, reg); - - reg = 0xff; /* 510 bits/block */ - zr36060_write_8(zr, 0x005, reg); - - /* JPEG markers */ - reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ - if (zr->params.COM_len) - reg |= JPEG_MARKER_COM; - if (zr->params.APP_len) - reg |= JPEG_MARKER_APP; - zr36060_write_8(zr, 0x006, reg); - - reg = (0 << 3) /* DATERR=0 */ - |(0 << 2) /* END=0 */ - |(0 << 1) /* EOI=0 */ - |(0 << 0); /* EOAV=0 */ - zr36060_write_8(zr, 0x007, reg); - - /* code volume */ - - /* Target field size in pixels: */ - tvn = &tvnorms[zr->params.norm]; - size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm); - - /* Target compressed field size in bits: */ - size = size * 16; /* uncompressed size in bits */ - size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ - - /* Lower limit (arbitrary, 1 KB) */ - if (size < 8192) - size = 8192; - - /* Upper limit: 7/8 of the code buffers */ - if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7) - size = zr->jpg_bufsize * 7 / zr->params.field_per_buff; - - reg = size; - zr36060_write_32(zr, 0x009, reg); - - /* how do we set initial SF as a function of quality parameter? */ - reg = 0x0100; /* SF=1.0 */ - zr36060_write_16(zr, 0x011, reg); - - reg = 0x00ffffff; /* AF=max */ - zr36060_write_24(zr, 0x013, reg); - - reg = 0x0000; /* test */ - zr36060_write_16(zr, 0x024, reg); -} - -static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - - reg = (0 << 7) /* Video8=0 */ - |(0 << 6) /* Range=0 */ - |(0 << 3) /* FlDet=0 */ - |(1 << 2) /* FlVedge=1 */ - |(0 << 1) /* FlExt=0 */ - |(0 << 0); /* SyncMstr=0 */ - - /* According to ZR36067 documentation, FlDet should correspond - to the odd_even flag of the ZR36067 */ - if (zr->params.odd_even) - reg |= (1 << 3); - - if (mode != BUZ_MODE_STILL_DECOMPRESS) { - /* limit pixels to range 16..235 as per CCIR-601 */ - reg |= (1 << 6); /* Range=1 */ - } - zr36060_write_8(zr, 0x030, reg); - - reg = (0 << 7) /* VCLKPol=0 */ - |(0 << 6) /* PValPol=0 */ - |(1 << 5) /* PoePol=1 */ - |(0 << 4) /* SImgPol=0 */ - |(0 << 3) /* BLPol=0 */ - |(0 << 2) /* FlPol=0 */ - |(0 << 1) /* HSPol=0, sync on falling edge */ - |(1 << 0); /* VSPol=1 */ - zr36060_write_8(zr, 0x031, reg); - - switch (zr->params.HorDcm) { - default: - case 1: - reg = (0 << 0); - break; /* HScale = 0 */ - - case 2: - reg = (1 << 0); - break; /* HScale = 1 */ - - case 4: - reg = (2 << 0); - break; /* HScale = 2 */ - } - if (zr->params.VerDcm == 2) - reg |= (1 << 2); - zr36060_write_8(zr, 0x032, reg); - - reg = 0x80; /* BackY */ - zr36060_write_8(zr, 0x033, reg); - - reg = 0xe0; /* BackU */ - zr36060_write_8(zr, 0x034, reg); - - reg = 0xe0; /* BackV */ - zr36060_write_8(zr, 0x035, reg); - - /* sync generator */ - - tvn = &tvnorms[zr->params.norm]; - - reg = tvn->Ht - 1; /* Vtotal */ - zr36060_write_16(zr, 0x036, reg); - - reg = tvn->Wt - 1; /* Htotal */ - zr36060_write_16(zr, 0x038, reg); - - reg = 6 - 1; /* VsyncSize */ - zr36060_write_8(zr, 0x03a, reg); - - reg = 100 - 1; /* HsyncSize */ - zr36060_write_8(zr, 0x03b, reg); - - reg = tvn->VStart - 1; /* BVstart */ - zr36060_write_8(zr, 0x03c, reg); - - reg += tvn->Ha / 2; /* BVend */ - zr36060_write_16(zr, 0x03e, reg); - - reg = tvn->HStart - 1; /* BHstart */ - zr36060_write_8(zr, 0x03d, reg); - - reg += tvn->Wa; /* BHend */ - zr36060_write_16(zr, 0x040, reg); - - /* active area */ - reg = zr->params.img_y + tvn->VStart; /* Vstart */ - zr36060_write_16(zr, 0x042, reg); - - reg += zr->params.img_height; /* Vend */ - zr36060_write_16(zr, 0x044, reg); - - reg = zr->params.img_x + tvn->HStart; /* Hstart */ - zr36060_write_16(zr, 0x046, reg); - - reg += zr->params.img_width; /* Hend */ - zr36060_write_16(zr, 0x048, reg); - - /* subimage area */ - reg = zr->params.img_y + tvn->VStart; /* SVstart */ - zr36060_write_16(zr, 0x04a, reg); - - reg += zr->params.img_height; /* SVend */ - zr36060_write_16(zr, 0x04c, reg); - - reg = zr->params.img_x + tvn->HStart; /* SHstart */ - zr36060_write_16(zr, 0x04e, reg); - - reg += zr->params.img_width; /* SHend */ - zr36060_write_16(zr, 0x050, reg); -} - -static void zr36060_set_jpg_SOF(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffc0; /* SOF marker */ - zr36060_write_16(zr, 0x060, reg); - - reg = 17; /* SOF length */ - zr36060_write_16(zr, 0x062, reg); - - reg = 8; /* precision 8 bits */ - zr36060_write_8(zr, 0x064, reg); - - reg = zr->params.img_height / zr->params.VerDcm; /* image height */ - zr36060_write_16(zr, 0x065, reg); - - reg = zr->params.img_width / zr->params.HorDcm; /* image width */ - zr36060_write_16(zr, 0x067, reg); - - reg = 3; /* 3 color components */ - zr36060_write_8(zr, 0x069, reg); - - reg = 0x002100; /* Y component */ - zr36060_write_24(zr, 0x06a, reg); - - reg = 0x011101; /* U component */ - zr36060_write_24(zr, 0x06d, reg); - - reg = 0x021101; /* V component */ - zr36060_write_24(zr, 0x070, reg); -} - -static void zr36060_set_jpg_SOS(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffda; /* SOS marker */ - zr36060_write_16(zr, 0x07a, reg); - - reg = 12; /* SOS length */ - zr36060_write_16(zr, 0x07c, reg); - - reg = 3; /* 3 color components */ - zr36060_write_8(zr, 0x07e, reg); - - reg = 0x0000; /* Y component */ - zr36060_write_16(zr, 0x07f, reg); - - reg = 0x0111; /* U component */ - zr36060_write_16(zr, 0x081, reg); - - reg = 0x0211; /* V component */ - zr36060_write_16(zr, 0x083, reg); - - reg = 0x003f00; /* Start, end spectral scans */ - zr36060_write_24(zr, 0x085, reg); -} - -static void zr36060_set_jpg_DRI(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffdd; /* DRI marker */ - zr36060_write_16(zr, 0x0c0, reg); - - reg = 4; /* DRI length */ - zr36060_write_16(zr, 0x0c2, reg); - - reg = 8; /* length in MCUs */ - zr36060_write_16(zr, 0x0c4, reg); -} - -static void zr36060_set_jpg_DQT(struct zoran *zr) -{ - unsigned i; - unsigned adr; - static const u8 dqt[] = - { - 0xff, 0xdb, /* DHT marker */ - 0x00, 0x84, /* DHT length */ - 0x00, /* table ID 0 */ - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, /* table ID 1 */ - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 - }; - - /* write fixed quantitization tables */ - adr = 0x0cc; - for (i = 0; i < sizeof(dqt); ++i) { - zr36060_write_8(zr, adr++, dqt[i]); - } -} - -static void zr36060_set_jpg_DHT(struct zoran *zr) -{ - unsigned i; - unsigned adr; - static const u8 dht[] = - { - 0xff, 0xc4, /* DHT marker */ - 0x01, 0xa2, /* DHT length */ - 0x00, /* table class 0, ID 0 */ - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ - 0x00, /* values for codes of length 2 */ - 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ - 0x06, /* values for codes of length 4 */ - 0x07, /* values for codes of length 5 */ - 0x08, /* values for codes of length 6 */ - 0x09, /* values for codes of length 7 */ - 0x0a, /* values for codes of length 8 */ - 0x0b, /* values for codes of length 9 */ - 0x01, /* table class 0, ID 1 */ - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ - 0x00, 0x01, 0x02, /* values for codes of length 2 */ - 0x03, /* values for codes of length 3 */ - 0x04, /* values for codes of length 4 */ - 0x05, /* values for codes of length 5 */ - 0x06, /* values for codes of length 6 */ - 0x07, /* values for codes of length 7 */ - 0x08, /* values for codes of length 8 */ - 0x09, /* values for codes of length 9 */ - 0x0a, /* values for codes of length 10 */ - 0x0b, /* values for codes of length 11 */ - 0x10, - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, - 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, - 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, - 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, - 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, - 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, - 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, - 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, - 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, - 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, - 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, - 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, - 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, - 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, - 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, - 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, - 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, - 0xf6, 0xf7, 0xf8, 0xf9, 0xfa - }; - - /* write fixed Huffman tables */ - adr = 0x1d4; - for (i = 0; i < sizeof(dht); ++i) { - zr36060_write_8(zr, adr++, dht[i]); - } -} - -static void zr36060_set_jpg_APP(struct zoran *zr) -{ - unsigned adr; - int len, i; - u32 reg; - - - len = zr->params.APP_len; - if (len < 0) - len = 0; - if (len > 60) - len = 60; - - i = zr->params.APPn; - if (i < 0) - i = 0; - if (i > 15) - i = 15; - - reg = 0xffe0 + i; /* APPn marker */ - zr36060_write_16(zr, 0x380, reg); - - reg = len + 2; /* APPn len */ - zr36060_write_16(zr, 0x382, reg); - - /* write APPn data */ - adr = 0x384; - for (i = 0; i < 60; i++) { - zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0)); - } -} - -static void zr36060_set_jpg_COM(struct zoran *zr) -{ - unsigned adr; - int len, i; - u32 reg; - - - len = zr->params.COM_len; - if (len < 0) - len = 0; - if (len > 60) - len = 60; - - reg = 0xfffe; /* COM marker */ - zr36060_write_16(zr, 0x3c0, reg); - - reg = len + 2; /* COM len */ - zr36060_write_16(zr, 0x3c2, reg); - - /* write COM data */ - adr = 0x3c4; - for (i = 0; i < 60; i++) { - zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0)); - } -} - -static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) -{ - unsigned i; - u32 reg; - - zr36060_reset(zr); - mdelay(10); - - reg = (0 << 7) /* Load=0 */ - |(1 << 0); /* SynRst=1 */ - zr36060_write_8(zr, 0x000, reg); - - zr36060_set_jpg(zr, mode); - zr36060_set_video(zr, mode); - zr36060_set_jpg_SOF(zr); - zr36060_set_jpg_SOS(zr); - zr36060_set_jpg_DRI(zr); - zr36060_set_jpg_DQT(zr); - zr36060_set_jpg_DHT(zr); - zr36060_set_jpg_APP(zr); - zr36060_set_jpg_COM(zr); - - reg = (1 << 7) /* Load=1 */ - |(0 << 0); /* SynRst=0 */ - zr36060_write_8(zr, 0x000, reg); - - /* wait for codec to unbusy */ - for (i = 0; i < 1000; ++i) { - reg = zr36060_read_8(zr, 0x001); - if ((reg & (1 << 7)) == 0) { - DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i)); - return; - } - udelay(1000); - } - printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg); -} - -static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - int i; - - tvn = &tvnorms[zr->params.norm]; - - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - - /* re-initialize DMA ring stuff */ - zr->jpg_que_head = 0; - zr->jpg_dma_head = 0; - zr->jpg_dma_tail = 0; - zr->jpg_que_tail = 0; - zr->jpg_seq_num = 0; - for (i = 0; i < BUZ_NUM_STAT_COM; ++i) { - zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ - } - for (i = 0; i < zr->jpg_nbufs; i++) { - zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ - } - - /* MJPEG compression mode */ - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - default: - reg = ZR36057_JMC_MJPGCmpMode; - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - reg = ZR36057_JMC_MJPGExpMode; - reg |= ZR36057_JMC_SyncMstr; - /* RJ: The following is experimental - improves the output to screen */ - if (zr->params.VFIFO_FB) - reg |= ZR36057_JMC_VFIFO_FB; - break; - - case BUZ_MODE_STILL_COMPRESS: - reg = ZR36057_JMC_JPGCmpMode; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - reg = ZR36057_JMC_JPGExpMode; - break; - - } - reg |= ZR36057_JMC_JPG; - if (zr->params.field_per_buff == 1) - reg |= ZR36057_JMC_Fld_per_buff; - btwrite(reg, ZR36057_JMC); - - /* vertical */ - btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); - reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); - btwrite(reg, ZR36057_VSP); - reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) - | (zr->params.img_height << ZR36057_FVAP_PAY); - btwrite(reg, ZR36057_FVAP); - - /* horizontal */ - btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot); - btwrite(reg, ZR36057_HSP); - reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX) - | (zr->params.img_width << ZR36057_FHAP_PAX); - btwrite(reg, ZR36057_FHAP); - - /* field process parameters */ - if (zr->params.odd_even) - reg = ZR36057_FPP_Odd_Even; - else - reg = 0; - btwrite(reg, ZR36057_FPP); - - /* Set proper VCLK Polarity, else colors will be wrong during playback */ - btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); - - /* code base address and FIFO threshold */ - reg = virt_to_bus(zr->stat_com); - btwrite(reg, ZR36057_JCBA); - reg = 0x50; - btwrite(reg, ZR36057_JCFT); - - /* JPEG codec guest ID */ - reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg); - btwrite(reg, ZR36057_JCGI); - - /* Code transfer guest ID */ - reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg); - reg |= ZR36057_MCTCR_CFlush; - btwrite(reg, ZR36057_MCTCR); - - /* deassert P_Reset */ - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); -} - -static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - static int zero = 0; - static int one = 1; - - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - zr36060_set_cap(zr, mode); - zr36057_set_jpg(zr, mode); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); - - /* deassert P_Reset, assert Code transfer enable */ - btwrite(IRQ_MASK, ZR36057_ISR); - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one); - zr36060_set_cap(zr, mode); - zr36057_set_jpg(zr, mode); - - /* deassert P_Reset, assert Code transfer enable */ - btwrite(IRQ_MASK, ZR36057_ISR); - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - break; - - case BUZ_MODE_IDLE: - default: - /* shut down processing */ - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); - btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); - btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - btwrite(0, ZR36057_ISR); - zr36060_reset(zr); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); - break; - - } - zr->codec_mode = mode; -} - -/* - * Queue a MJPEG buffer for capture/playback - */ - -static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode) -{ - unsigned long flags; - int res; - - /* Check if buffers are allocated */ - - if (!zr->jpg_buffers_allocated) { - printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name); - return -ENOMEM; - } - /* Does the user want to stop streaming? */ - - if (frame < 0) { - if (zr->codec_mode == mode) { - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - return 0; - } else { - printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name); - return -EINVAL; - } - } - /* No grabbing outside the buffer range! */ - - if (frame >= zr->jpg_nbufs) { - printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame); - return -EINVAL; - } - /* what is the codec mode right now? */ - - if (zr->codec_mode == BUZ_MODE_IDLE) { - /* Ok load up the zr36060 and go */ - zr36057_enable_jpg(zr, mode); - } else if (zr->codec_mode != mode) { - /* wrong codec mode active - invalid */ - printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name); - return -EINVAL; - } - spin_lock_irqsave(&zr->lock, flags); - - /* make sure a grab isn't going on currently with this buffer */ - - switch (zr->jpg_gbuf[frame].state) { - - default: - case BUZ_STATE_DMA: - case BUZ_STATE_PEND: - case BUZ_STATE_DONE: - res = -EBUSY; /* what are you doing? */ - break; - - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at least one more pend[] entry */ - zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; - zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; - zoran_feed_stat_com(zr); - res = 0; - break; - - } - - spin_unlock_irqrestore(&zr->lock, flags); - - /* Start the zr36060 when the first frame is queued */ - if (zr->jpg_que_head == 1) { - btor(ZR36057_JMC_Go_en, ZR36057_JMC); - btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC); - } - return res; -} - -/* - * Sync on a MJPEG buffer - */ - -static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) -{ - unsigned long flags; - int frame; - - if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { - return -EINVAL; - } - while (zr->jpg_que_tail == zr->jpg_dma_tail) { - interruptible_sleep_on(&zr->jpg_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&zr->lock, flags); - - frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; - - /* buffer should now be in BUZ_STATE_DONE */ - - if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) - printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name); - - *bs = zr->jpg_gbuf[frame].bs; - zr->jpg_gbuf[frame].state = BUZ_STATE_USER; - - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} - -/* when this is called the spinlock must be held */ -static void zoran_feed_stat_com(struct zoran *zr) -{ - /* move frames from pending queue to DMA */ - - int frame, i, max_stat_com; - - max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); - - while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com - && zr->jpg_dma_head != zr->jpg_que_head) { - - frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; - if (zr->params.TmpDcm == 1) { - /* fill 1 stat_com entry */ - i = zr->jpg_dma_head & BUZ_MASK_STAT_COM; - zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; - } else { - /* fill 2 stat_com entries */ - i = (zr->jpg_dma_head & 1) * 2; - zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; - zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus; - } - zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; - zr->jpg_dma_head++; - - } -} - -/* when this is called the spinlock must be held */ -static void zoran_reap_stat_com(struct zoran *zr) -{ - /* move frames from DMA queue to done queue */ - - int i; - u32 stat_com; - unsigned int seq; - unsigned int dif; - int frame; - struct zoran_gbuffer *gbuf; - - /* In motion decompress we don't have a hardware frame counter, - we just count the interrupts here */ - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) - zr->jpg_seq_num++; - - while (zr->jpg_dma_tail != zr->jpg_dma_head) { - if (zr->params.TmpDcm == 1) - i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM; - else - i = (zr->jpg_dma_tail & 1) * 2 + 1; - - stat_com = zr->stat_com[i]; - - if ((stat_com & 1) == 0) { - return; - } - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - gbuf = &zr->jpg_gbuf[frame]; - get_fast_time(&gbuf->bs.timestamp); - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - gbuf->bs.length = (stat_com & 0x7fffff) >> 1; - - /* update sequence number with the help of the counter in stat_com */ - - seq = stat_com >> 24; - dif = (seq - zr->jpg_seq_num) & 0xff; - zr->jpg_seq_num += dif; - } else { - gbuf->bs.length = 0; - } - gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; - gbuf->state = BUZ_STATE_DONE; - - zr->jpg_dma_tail++; - } -} - -static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - u32 stat, astat; - int count; - struct zoran *zr; - unsigned long flags; - - zr = (struct zoran *) dev_id; - count = 0; - - spin_lock_irqsave(&zr->lock, flags); - while (1) { - /* get/clear interrupt status bits */ - stat = btread(ZR36057_ISR); - astat = stat & IRQ_MASK; - if (!astat) { - break; - } - btwrite(astat, ZR36057_ISR); - IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat)); - -#if (IRQ_MASK & ZR36057_ISR_GIRQ0) - if (astat & ZR36057_ISR_GIRQ0) { - - /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. - We simply ignore them */ - - if (zr->v4l_memgrab_active) { - -/* A lot more checks should be here ... */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) - printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name); - - if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { - /* There is a grab on a frame going on, check if it has finished */ - - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { - /* it is finished, notify the user */ - - zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq++; - zr->v4l_pend_tail++; - } - } - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) - wake_up_interruptible(&zr->v4l_capq); - - /* Check if there is another grab queued */ - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && - zr->v4l_pend_tail != zr->v4l_pend_head) { - - int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; - u32 reg; - - zr->v4l_grab_frame = frame; - - /* Set zr36057 video front end and enable video */ - - /* Buffer address */ - - reg = zr->v4l_gbuf[frame].fbuffer_bus; - btwrite(reg, ZR36057_VDTR); - if (zr->video_interlace) - reg += zr->gbpl; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - -#ifdef XAWTV_HACK - reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0; -#else - reg = 0; -#endif - if (zr->video_interlace) - reg += zr->gbpl; - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; - reg |= ZR36057_VSSFGR_SnapShot; - reg |= ZR36057_VSSFGR_FrameGrab; - btwrite(reg, ZR36057_VSSFGR); - - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } - } - } -#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */ - -#if (IRQ_MASK & ZR36057_ISR_GIRQ1) - if (astat & ZR36057_ISR_GIRQ1) { - unsigned csr = zr36060_read_8(zr, 0x001); - unsigned isr = zr36060_read_8(zr, 0x008); - - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n", - zr->name, csr, isr)); - - btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - } -#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */ - -#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) - if (astat & ZR36057_ISR_CodRepIRQ) { - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name)); - btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); - } -#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ - -#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) - if ((astat & ZR36057_ISR_JPEGRepIRQ) && - (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - } -#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ - - count++; - if (count > 10) { - printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count); - if (count > 20) { - btwrite(0, ZR36057_ICR); - printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n", zr->name); - break; - } - } - } - spin_unlock_irqrestore(&zr->lock, flags); -} - -/* Check a zoran_params struct for correctness, insert default params */ - -static int zoran_check_params(struct zoran *zr, struct zoran_params *params) -{ - int err = 0, err0 = 0; - - /* insert constant params */ - - params->major_version = MAJOR_VERSION; - params->minor_version = MINOR_VERSION; - - /* Check input and norm */ - - if (params->input != 0 && params->input != 1) { - err++; - } - if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) { - err++; - } - /* Check decimation, set default values for decimation = 1, 2, 4 */ - - switch (params->decimation) { - case 1: - - params->HorDcm = 1; - params->VerDcm = 1; - params->TmpDcm = 1; - params->field_per_buff = 2; - - params->img_x = 0; - params->img_y = 0; - params->img_width = 720; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 2: - - params->HorDcm = 2; - params->VerDcm = 1; - params->TmpDcm = 2; - params->field_per_buff = 1; - - params->img_x = 8; - params->img_y = 0; - params->img_width = 704; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 4: - - params->HorDcm = 4; - params->VerDcm = 2; - params->TmpDcm = 2; - params->field_per_buff = 1; - - params->img_x = 8; - params->img_y = 0; - params->img_width = 704; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 0: - - /* We have to check the data the user has set */ - - if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4) - err0++; - if (params->VerDcm != 1 && params->VerDcm != 2) - err0++; - if (params->TmpDcm != 1 && params->TmpDcm != 2) - err0++; - if (params->field_per_buff != 1 && params->field_per_buff != 2) - err0++; - - if (params->img_x < 0) - err0++; - if (params->img_y < 0) - err0++; - if (params->img_width < 0) - err0++; - if (params->img_height < 0) - err0++; - if (params->img_x + params->img_width > 720) - err0++; - if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2) - err0++; - if (params->img_width % (16 * params->HorDcm) != 0) - err0++; - if (params->img_height % (8 * params->VerDcm) != 0) - err0++; - - if (err0) { - err++; - } - break; - - default: - err++; - break; - } - - if (params->quality > 100) - params->quality = 100; - if (params->quality < 5) - params->quality = 5; - - if (params->APPn < 0) - params->APPn = 0; - if (params->APPn > 15) - params->APPn = 15; - if (params->APP_len < 0) - params->APP_len = 0; - if (params->APP_len > 60) - params->APP_len = 60; - if (params->COM_len < 0) - params->COM_len = 0; - if (params->COM_len > 60) - params->COM_len = 60; - - if (err) - return -EINVAL; - - return 0; - -} -static void zoran_open_init_params(struct zoran *zr) -{ - int i; - - /* Per default, map the V4L Buffers */ - - zr->map_mjpeg_buffers = 0; - - /* User must explicitly set a window */ - - zr->window_set = 0; - - zr->window.x = 0; - zr->window.y = 0; - zr->window.width = 0; - zr->window.height = 0; - zr->window.chromakey = 0; - zr->window.flags = 0; - zr->window.clips = NULL; - zr->window.clipcount = 0; - - zr->video_interlace = 0; - - zr->v4l_memgrab_active = 0; - zr->v4l_overlay_active = 0; - - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq = 0; - - zr->gwidth = 0; - zr->gheight = 0; - zr->gformat = 0; - zr->gbpl = 0; - - /* DMA ring stuff for V4L */ - - zr->v4l_pend_tail = 0; - zr->v4l_pend_head = 0; - for (i = 0; i < v4l_nbufs; i++) { - zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ - } - - /* Set necessary params and call zoran_check_params to set the defaults */ - - zr->params.decimation = 1; - - zr->params.quality = 50; /* default compression factor 8 */ - zr->params.odd_even = 1; - - zr->params.APPn = 0; - zr->params.APP_len = 0; /* No APPn marker */ - for (i = 0; i < 60; i++) - zr->params.APP_data[i] = 0; - - zr->params.COM_len = 0; /* No COM marker */ - for (i = 0; i < 60; i++) - zr->params.COM_data[i] = 0; - - zr->params.VFIFO_FB = 0; - - memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); - - zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; - - i = zoran_check_params(zr, &zr->params); - if (i) - printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name); -} - -/* - * Open a buz card. Right now the flags stuff is just playing - */ - -static int zoran_open(struct video_device *dev, int flags) -{ - struct zoran *zr = (struct zoran *) dev; - - DEBUG(printk(KERN_INFO ": zoran_open\n")); - - switch (flags) { - - case 0: - if (zr->user) - return -EBUSY; - zr->user++; - - if (v4l_fbuffer_alloc(zr) < 0) { - zr->user--; - return -ENOMEM; - } - /* default setup */ - - zoran_open_init_params(zr); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - - btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts - - btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - - break; - - default: - return -EBUSY; - - } - MOD_INC_USE_COUNT; - return 0; -} - -static void zoran_close(struct video_device *dev) -{ - struct zoran *zr = (struct zoran *) dev; - - DEBUG(printk(KERN_INFO ": zoran_close\n")); - - /* disable interrupts */ - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - - /* wake up sleeping beauties */ - wake_up_interruptible(&zr->v4l_capq); - wake_up_interruptible(&zr->jpg_capq); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr36057_set_memgrab(zr, 0); - if (zr->v4l_overlay_active) - zr36057_overlay(zr, 0); - - zr->user--; - - v4l_fbuffer_free(zr); - jpg_fbuffer_free(zr); - zr->jpg_nbufs = 0; - - MOD_DEC_USE_COUNT; - DEBUG(printk(KERN_INFO ": zoran_close done\n")); -} - - -static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -/* - * ioctl routine - */ - - -static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct zoran *zr = (struct zoran *) dev; - - switch (cmd) { - - case VIDIOCGCAP: - { - struct video_capability b; - IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n")); - strncpy(b.name, zr->video_dev.name, sizeof(b.name)); - b.type = VID_TYPE_CAPTURE | - VID_TYPE_OVERLAY | - VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | - VID_TYPE_SCALES; - /* theoretically we could also flag VID_TYPE_SUBCAPTURE - but this is not even implemented in the BTTV driver */ - - b.channels = 2; /* composite, svhs */ - b.audios = 0; - b.maxwidth = BUZ_MAX_WIDTH; - b.maxheight = BUZ_MAX_HEIGHT; - b.minwidth = BUZ_MIN_WIDTH; - b.minheight = BUZ_MIN_HEIGHT; - 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; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel)); - switch (v.channel) { - case 0: - strcpy(v.name, "Composite"); - break; - case 1: - strcpy(v.name, "SVHS"); - break; - default: - return -EINVAL; - } - v.tuners = 0; - v.flags = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = zr->params.norm; - if (copy_to_user(arg, &v, sizeof(v))) { - return -EFAULT; - } - return 0; - } - - /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: - - * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." - * ^^^^^^^ - * The famos BTTV driver has it implemented with a struct video_channel argument - * and we follow it for compatibility reasons - * - * BTW: this is the only way the user can set the norm! - */ - - case VIDIOCSCHAN: - { - struct video_channel v; - int input; - int on, res; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm)); - switch (v.channel) { - case 0: - input = 3; - break; - case 1: - input = 7; - break; - default: - return -EINVAL; - } - - if (v.norm != VIDEO_MODE_PAL - && v.norm != VIDEO_MODE_NTSC) { - return -EINVAL; - } - zr->params.norm = v.norm; - zr->params.input = v.channel; - - /* We switch overlay off and on since a change in the norm - needs different VFE settings */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - - return 0; - } - - case VIDIOCGTUNER: - case VIDIOCSTUNER: - return -EINVAL; - - case VIDIOCGPICT: - { - struct video_picture p = zr->picture; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n")); - p.depth = zr->buffer.depth; - switch (zr->buffer.depth) { - case 15: - p.palette = VIDEO_PALETTE_RGB555; - break; - - case 16: - p.palette = VIDEO_PALETTE_RGB565; - break; - - case 24: - p.palette = VIDEO_PALETTE_RGB24; - break; - - case 32: - p.palette = VIDEO_PALETTE_RGB32; - break; - } - - 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; - } - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); - IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", - p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette)); - /* The depth and palette values have no meaning to us, - should we return -EINVAL if they don't fit ? */ - zr->picture = p; - return 0; - } - - case VIDIOCCAPTURE: - { - int v, res; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v)); - /* If there is nothing to do, return immediatly */ - - if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active)) - return 0; - - if (v == 0) { - zr->v4l_overlay_active = 0; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - /* When a grab is running, the video simply won't be switched on any more */ - } else { - if (!zr->buffer_set || !zr->window_set) { - return -EINVAL; - } - zr->v4l_overlay_active = 1; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 1); - /* When a grab is running, the video will be switched on when grab is finished */ - } - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - return 0; - } - - case VIDIOCGWIN: - { - IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n")); - if (copy_to_user(arg, &zr->window, sizeof(zr->window))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSWIN: - { - struct video_clip *vcp; - struct video_window vw; - int on, end, res; - - if (copy_from_user(&vw, arg, sizeof(vw))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount)); - if (!zr->buffer_set) { - return -EINVAL; - } - /* - * The video front end needs 4-byte alinged line sizes, we correct that - * silently here if necessary - */ - - if (zr->buffer.depth == 15 || zr->buffer.depth == 16) { - end = (vw.x + vw.width) & ~1; /* round down */ - vw.x = (vw.x + 1) & ~1; /* round up */ - vw.width = end - vw.x; - } - if (zr->buffer.depth == 24) { - end = (vw.x + vw.width) & ~3; /* round down */ - vw.x = (vw.x + 3) & ~3; /* round up */ - vw.width = end - vw.x; - } -#if 0 - // At least xawtv seems to care about the following - just leave it away - /* - * Also corrected silently (as long as window fits at all): - * video not fitting the screen - */ -#if 0 - if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width || - vw.y + vw.height > zr->buffer.height) { - printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n", - vw.width, vw.height, vw.x, vw.y); - return -EINVAL; - } -#else - if (vw.x < 0) - vw.x = 0; - if (vw.y < 0) - vw.y = 0; - if (vw.x + vw.width > zr->buffer.width) - vw.width = zr->buffer.width - vw.x; - if (vw.y + vw.height > zr->buffer.height) - vw.height = zr->buffer.height - vw.y; -#endif -#endif - - /* Check for vaild parameters */ - if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || - vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { - return -EINVAL; - } -#ifdef XAWTV_HACK - if (vw.width > 720) - vw.width = 720; -#endif - - zr->window.x = vw.x; - zr->window.y = vw.y; - zr->window.width = vw.width; - zr->window.height = vw.height; - zr->window.chromakey = 0; - zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? - - zr->window.clips = NULL; - zr->window.clipcount = vw.clipcount; - - /* - * If an overlay is running, we have to switch it off - * and switch it on again in order to get the new settings in effect. - * - * We also want to avoid that the overlay mask is written - * when an overlay is running. - */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - /* - * Write the overlay mask if clips are wanted. - */ - if (vw.clipcount) { - vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4)); - if (vcp == NULL) { - return -ENOMEM; - } - if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - write_overlay_mask(zr, vcp, vw.clipcount); - vfree(vcp); - } - if (on) - zr36057_overlay(zr, 1); - zr->window_set = 1; - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - - return 0; - } - - case VIDIOCGFBUF: - { - IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n")); - if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSFBUF: - { - struct video_buffer v; - - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline)); - if (zr->v4l_overlay_active) { - /* Has the user gotten crazy ... ? */ - return -EINVAL; - } - if (v.depth != 15 - && v.depth != 16 - && v.depth != 24 - && v.depth != 32) { - return -EINVAL; - } - if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) { - return -EINVAL; - } - if (v.bytesperline & 3) { - return -EINVAL; - } - if (v.base) { - zr->buffer.base = (void *) ((unsigned long) v.base & ~3); - } - zr->buffer.height = v.height; - zr->buffer.width = v.width; - zr->buffer.depth = v.depth; - zr->buffer.bytesperline = v.bytesperline; - - if (zr->buffer.base) - zr->buffer_set = 1; - zr->window_set = 0; /* The user should set new window parameters */ - return 0; - } - - /* RJ: what is VIDIOCKEY intended to do ??? */ - - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - - case VIDIOCSYNC: - { - int v; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v)); - return v4l_sync(zr, v); - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", - vm.frame, vm.height, vm.width, vm.format)); - return v4l_grab(zr, &vm); - } - - case VIDIOCGMBUF: - { - struct video_mbuf vm; - int i; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n")); - - vm.size = v4l_nbufs * v4l_bufsize; - vm.frames = v4l_nbufs; - for (i = 0; i < v4l_nbufs; i++) { - vm.offsets[i] = i * v4l_bufsize; - } - - /* The next mmap will map the V4L buffers */ - zr->map_mjpeg_buffers = 0; - - if (copy_to_user(arg, &vm, sizeof(vm))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCGUNIT: - { - struct video_unit vu; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n")); - vu.video = zr->video_dev.minor; - vu.vbi = VIDEO_NO_UNIT; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; - if (copy_to_user(arg, &vu, sizeof(vu))) - return -EFAULT; - return 0; - } - - /* - * RJ: In principal we could support subcaptures for V4L grabbing. - * Not even the famous BTTV driver has them, however. - * If there should be a strong demand, one could consider - * to implement them. - */ - case VIDIOCGCAPTURE: - case VIDIOCSCAPTURE: - return -EINVAL; - - case BUZIOC_G_PARAMS: - { - IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n")); - if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) - return -EFAULT; - return 0; - } - - case BUZIOC_S_PARAMS: - { - struct zoran_params bp; - int input, on; - - if (zr->codec_mode != BUZ_MODE_IDLE) { - return -EINVAL; - } - if (copy_from_user(&bp, arg, sizeof(bp))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n")); - - /* Check the params first before overwriting our internal values */ - - if (zoran_check_params(zr, &bp)) - return -EINVAL; - - zr->params = bp; - - /* Make changes of input and norm go into effect immediatly */ - - /* We switch overlay off and on since a change in the norm - needs different VFE settings */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - input = zr->params.input == 0 ? 3 : 7; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); - - if (on) - zr36057_overlay(zr, 1); - - if (copy_to_user(arg, &bp, sizeof(bp))) { - return -EFAULT; - } - return 0; - } - - case BUZIOC_REQBUFS: - { - struct zoran_requestbuffers br; - - if (zr->jpg_buffers_allocated) { - return -EINVAL; - } - if (copy_from_user(&br, arg, sizeof(br))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", - br.count, br.size)); - /* Enforce reasonable lower and upper limits */ - if (br.count < 4) - br.count = 4; /* Could be choosen smaller */ - if (br.count > BUZ_MAX_FRAME) - br.count = BUZ_MAX_FRAME; - br.size = PAGE_ALIGN(br.size); - if (br.size < 8192) - br.size = 8192; /* Arbitrary */ - /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ - if (br.size > (512 * 1024)) - br.size = (512 * 1024); /* 512 K should be enough */ - if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM) - br.size = MAX_KMALLOC_MEM; - - zr->jpg_nbufs = br.count; - zr->jpg_bufsize = br.size; - - if (jpg_fbuffer_alloc(zr)) - return -ENOMEM; - - /* The next mmap will map the MJPEG buffers */ - zr->map_mjpeg_buffers = 1; - - if (copy_to_user(arg, &br, sizeof(br))) { - return -EFAULT; - } - return 0; - } - - case BUZIOC_QBUF_CAPT: - { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb)); - return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); - } - - case BUZIOC_QBUF_PLAY: - { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb)); - return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS); - } - - case BUZIOC_SYNC: - { - struct zoran_sync bs; - int res; - - IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n")); - res = jpg_sync(zr, &bs); - if (copy_to_user(arg, &bs, sizeof(bs))) { - return -EFAULT; - } - return res; - } - - case BUZIOC_G_STATUS: - { - struct zoran_status bs; - int norm, input, status; - - if (zr->codec_mode != BUZ_MODE_IDLE) { - return -EINVAL; - } - if (copy_from_user(&bs, arg, sizeof(bs))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n")); - switch (bs.input) { - case 0: - input = 3; - break; - case 1: - input = 7; - break; - default: - return -EINVAL; - } - - /* Set video norm to VIDEO_MODE_AUTO */ - - norm = VIDEO_MODE_AUTO; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); - - /* sleep 1 second */ - - schedule_timeout(HZ); - - /* Get status of video decoder */ - - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status); - bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; - bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; - bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; - - /* restore previous input and norm */ - input = zr->params.input == 0 ? 3 : 7; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - - if (copy_to_user(arg, &bs, sizeof(bs))) { - return -EFAULT; - } - return 0; - } - - default: - return -ENOIOCTLCMD; - - } - return 0; -} - - -/* - * This maps the buffers to user space. - * - * Depending on the state of zr->map_mjpeg_buffers - * the V4L or the MJPEG buffers are mapped - * - */ - -static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - struct zoran *zr = (struct zoran *) dev; - unsigned long start = (unsigned long) adr; - unsigned long page, pos, todo, fraglen; - int i, j; - - if (zr->map_mjpeg_buffers) { - /* Map the MJPEG buffers */ - - if (!zr->jpg_buffers_allocated) { - return -ENOMEM; - } - if (size > zr->jpg_nbufs * zr->jpg_bufsize) { - return -EINVAL; - } - - for (i = 0; i < zr->jpg_nbufs; i++) { - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1; - todo = size; - if (todo > fraglen) - todo = fraglen; - pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; - page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ - if (remap_page_range(start, page, todo, PAGE_SHARED)) { - printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1) - break; /* was last fragment */ - } - if (size == 0) - break; - } - } else { - /* Map the V4L buffers */ - - if (size > v4l_nbufs * v4l_bufsize) { - return -EINVAL; - } - - for (i = 0; i < v4l_nbufs; i++) { - todo = size; - if (todo > v4l_bufsize) - todo = v4l_bufsize; - page = zr->v4l_gbuf[i].fbuffer_phys; - DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); - if (remap_page_range(start, page, todo, PAGE_SHARED)) { - printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - } - } - return 0; -} - -static int zoran_init_done(struct video_device *dev) -{ - return 0; -} - -static struct video_device zoran_template = -{ - BUZ_NAME, - VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | - VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - VID_HARDWARE_ZR36067, - zoran_open, - zoran_close, - zoran_read, - zoran_write, - NULL, - zoran_ioctl, - zoran_mmap, - zoran_init_done, - NULL, - 0, - 0 -}; - -static int zr36057_init(int i) -{ - struct zoran *zr = &zoran[i]; - unsigned long mem; - unsigned mem_needed; - int j; - int rev; - - /* reset zr36057 */ - btwrite(0, ZR36057_SPGPPCR); - mdelay(10); - - /* default setup of all parameters which will persist beetween opens */ - - zr->user = 0; - - init_waitqueue_head(&zr->v4l_capq); - init_waitqueue_head(&zr->jpg_capq); - - zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ - - zr->jpg_nbufs = 0; - zr->jpg_bufsize = 0; - zr->jpg_buffers_allocated = 0; - - zr->buffer_set = 0; /* Flag if frame buffer has been set */ - zr->buffer.base = (void *) vidmem; - zr->buffer.width = 0; - zr->buffer.height = 0; - zr->buffer.depth = 0; - zr->buffer.bytesperline = 0; - - zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */ - zr->params.input = default_input ? 1 : 0; /* Avoid nonsense settings from user */ - zr->video_interlace = 0; - - /* Should the following be reset at every open ? */ - - zr->picture.colour = 32768; - zr->picture.brightness = 32768; - zr->picture.hue = 32768; - zr->picture.contrast = 32768; - zr->picture.whiteness = 0; - zr->picture.depth = 0; - zr->picture.palette = 0; - - for (j = 0; j < VIDEO_MAX_FRAME; j++) { - zr->v4l_gbuf[i].fbuffer = 0; - zr->v4l_gbuf[i].fbuffer_phys = 0; - zr->v4l_gbuf[i].fbuffer_bus = 0; - } - - zr->stat_com = 0; - - /* default setup (will be repeated at every open) */ - - zoran_open_init_params(zr); - - /* allocate memory *before* doing anything to the hardware in case allocation fails */ - - /* STAT_COM table and overlay mask */ - - mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; - mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); - if (!mem) { - return -ENOMEM; - } - memset((void *) mem, 0, mem_needed); - - zr->stat_com = (u32 *) mem; - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ - } - zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); - - /* Initialize zr->jpg_gbuf */ - - for (j = 0; j < BUZ_MAX_FRAME; j++) { - zr->jpg_gbuf[j].frag_tab = 0; - zr->jpg_gbuf[j].frag_tab_bus = 0; - zr->jpg_gbuf[j].state = BUZ_STATE_USER; - zr->jpg_gbuf[j].bs.frame = j; - } - - /* take zr36057 out of reset now */ - btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); - mdelay(10); - - /* stop all DMA processes */ - btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - - switch(zr->board) - { - case BOARD_BUZ: - - /* set up GPIO direction */ - btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); - - /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */ - btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1); - mdelay(10); - - /* reset video decoder */ - - GPIO(zr, 0, 0); - mdelay(10); - GPIO(zr, 0, 1); - mdelay(10); - - /* reset JPEG codec */ - zr36060_sleep(zr, 0); - mdelay(10); - zr36060_reset(zr); - mdelay(10); - - /* display codec revision */ - if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { - printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", - zr->name, zr36060_read_8(zr, 0x023)); - } else { - printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev); - kfree((void *) zr->stat_com); - return -1; - } - break; - - case BOARD_LML33: -// btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); -// udelay(100); -// btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); -// udelay(1000); - - /* - * Set up the GPIO direction - */ - btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR); - /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */ - btwrite(0xFF00F888, ZR36057_GPPGCR1); - mdelay(10); - GPIO(zr, 5, 0); /* Analog video bypass */ - udelay(3000); - GPIO(zr, 0, 0); /* Reset 819 */ - udelay(3000); - GPIO(zr, 0, 1); /* 819 back */ - udelay(3000); - /* reset JPEG codec */ - zr36060_sleep(zr, 0); - udelay(3000); - zr36060_reset(zr); - udelay(3000); - - /* display codec revision */ - if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { - printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", - zr->name, zr36060_read_8(zr, 0x023)); - } else { - printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); - kfree((void *) zr->stat_com); - return -1; - } - break; - } - /* i2c */ - memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); - sprintf(zr->i2c.name, "zoran%u", zr->id); - zr->i2c.data = zr; - if (i2c_register_bus(&zr->i2c) < 0) { - kfree((void *) zr->stat_com); - return -1; - } - /* - * Now add the template and register the device unit. - */ - memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); - sprintf(zr->video_dev.name, "zoran%u", zr->id); - if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { - i2c_unregister_bus(&zr->i2c); - kfree((void *) zr->stat_com); - return -1; - } - /* toggle JPEG codec sleep to sync PLL */ - zr36060_sleep(zr, 1); - mdelay(10); - zr36060_sleep(zr, 0); - mdelay(10); - - /* Enable bus-mastering */ - pci_set_master(zr->pci_dev); - - j = zr->params.input == 0 ? 3 : 7; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); - - /* set individual interrupt enables (without GIRQ0) - but don't global enable until zoran_open() */ - - btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR); - - if(request_irq(zr->pci_dev->irq, zoran_irq, - SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0) - { - printk(KERN_ERR "%s: Can't assign irq.\n", zr->name); - video_unregister_device(&zr->video_dev); - i2c_unregister_bus(&zr->i2c); - kfree((void *) zr->stat_com); - return -1; - } - zr->initialized = 1; - return 0; -} - - - -static void release_zoran(void) -{ - u8 command; - int i; - struct zoran *zr; - - for (i = 0; i < zoran_num; i++) { - zr = &zoran[i]; - - if (!zr->initialized) - continue; - - /* unregister i2c_bus */ - i2c_unregister_bus((&zr->i2c)); - - /* disable PCI bus-mastering */ - pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); - - /* put chip into reset */ - btwrite(0, ZR36057_SPGPPCR); - - free_irq(zr->pci_dev->irq, zr); - - /* unmap and free memory */ - - kfree((void *) zr->stat_com); - - iounmap(zr->zr36057_mem); - - video_unregister_device(&zr->video_dev); - } -} - -/* - * Scan for a Buz card (actually for the PCI controller ZR36057), - * request the irq and map the io memory - */ - -static int find_zr36057(void) -{ - unsigned char latency; - struct zoran *zr; - struct pci_dev *dev = NULL; - - zoran_num = 0; - - while (zoran_num < BUZ_MAX - && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { - zr = &zoran[zoran_num]; - zr->pci_dev = dev; - zr->zr36057_mem = NULL; - zr->id = zoran_num; - sprintf(zr->name, "zoran%u", zr->id); - - spin_lock_init(&zr->lock); - - if (pci_enable_device(dev)) - continue; - - zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); - pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); - if (zr->revision < 2) { - printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", - zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); - } else { - unsigned short ss_vendor_id, ss_id; - - ss_vendor_id = zr->pci_dev->subsystem_vendor; - ss_id = zr->pci_dev->subsystem_device; - printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", - zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); - printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n", - zr->name, ss_vendor_id, ss_id); - if(ss_vendor_id==0xFF10 && ss_id == 0xDE41) - { - zr->board = BOARD_LML33; - printk(KERN_INFO "%s: LML33 detected.\n", zr->name); - } - } - - zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); - if (!zr->zr36057_mem) { - printk(KERN_ERR "%s: ioremap failed\n", zr->name); - /* XXX handle error */ - } - - /* set PCI latency timer */ - pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); - if (latency != 48) { - printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency); - latency = 48; - pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency); - } - zoran_num++; - } - if (zoran_num == 0) - printk(KERN_INFO "zoran: no cards found.\n"); - - return zoran_num; -} - -static void handle_chipset(void) -{ - if(pci_pci_problems&PCIPCI_FAIL) - { - printk(KERN_WARNING "buz: This configuration is known to have PCI to PCI DMA problems\n"); - printk(KERN_WARNING "buz: You may not be able to use overlay mode.\n"); - } - - - if(pci_pci_problems&PCIPCI_TRITON) - { - printk("buz: Enabling Triton support.\n"); - triton = 1; - } - - if(pci_pci_problems&PCIPCI_NATOMA) - { - printk("buz: Enabling Natoma workaround.\n"); - natoma = 1; - } -} - -#ifdef MODULE -int init_module(void) -#else -int init_zoran_cards(struct video_init *unused) -#endif -{ - int i; - - - printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n"); - - /* Look for Buz cards */ - - if (find_zr36057() <= 0) { - return -EIO; - } - printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num); - - if (zoran_num == 0) - return -ENXIO; - - - /* check the parameters we have been given, adjust if necessary */ - - if (v4l_nbufs < 0) - v4l_nbufs = 0; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specfies the in KB, we want them in byte (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - - printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10); - - /* Use parameter for vidmem or try to find a video card */ - - if (vidmem) { - printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem); - } - - /* check if we have a Triton or Natome chipset */ - - handle_chipset(); - - /* take care of Natoma chipset and a revision 1 zr36057 */ - - for (i = 0; i < zoran_num; i++) { - if (natoma && zoran[i].revision <= 1) { - zoran[i].need_contiguous = 1; - printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name); - } else { - zoran[i].need_contiguous = 0; - } - } - - /* initialize the Buzs */ - - /* We have to know which ones must be released if an error occurs */ - for (i = 0; i < zoran_num; i++) - zoran[i].initialized = 0; - - for (i = 0; i < zoran_num; i++) { - if (zr36057_init(i) < 0) { - release_zoran(); - return -EIO; - } - } - - return 0; -} - - - -#ifdef MODULE - -void cleanup_module(void) -{ - release_zoran(); -} - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/buz.h linux/drivers/char/buz.h --- v2.4.0-test6/linux/drivers/char/buz.h Mon Jul 5 20:07:02 1999 +++ linux/drivers/char/buz.h Wed Dec 31 16:00:00 1969 @@ -1,319 +0,0 @@ -/* - buz - Iomega Buz driver - - Copyright (C) 1999 Rainer Johanni - - based on - - buz.0.0.3 Copyright (C) 1998 Dave Perks - - and - - 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. - */ - -#ifndef _BUZ_H_ -#define _BUZ_H_ - -/* The Buz only supports a maximum width of 720, but some V4L - applications (e.g. xawtv are more happy with 768). - If XAWTV_HACK is defined, we try to fake a device with bigger width */ - -#define XAWTV_HACK - -#ifdef XAWTV_HACK -#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ -#else -#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ -#endif -#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ -#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ -#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ - -struct zoran_requestbuffers { - unsigned long count; /* Number of buffers for MJPEG grabbing */ - unsigned long size; /* Size PER BUFFER in bytes */ -}; - -struct zoran_sync { - unsigned long frame; /* number of buffer that has been free'd */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - struct timeval timestamp; /* timestamp */ -}; - -struct zoran_status { - int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ - int signal; /* Returned: 1 if valid video signal detected */ - int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int color; /* Returned: 1 if color signal detected */ -}; - -struct zoran_params { - - /* The following parameters can only be queried */ - - int major_version; /* Major version number of driver */ - int minor_version; /* Minor version number of driver */ - - /* Main control parameters */ - - int input; /* Input channel: 0 = Composite, 1 = S-VHS */ - int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int decimation; /* decimation of captured video, - enlargement of video played back. - Valid values are 1, 2, 4 or 0. - 0 is a special value where the user - has full control over video scaling */ - - /* The following parameters only have to be set if decimation==0, - for other values of decimation they provide the data how the image is captured */ - - int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ - int VerDcm; /* Vertical decimation: 1 or 2 */ - int TmpDcm; /* Temporal decimation: 1 or 2, - if TmpDcm==2 in capture every second frame is dropped, - in playback every frame is played twice */ - int field_per_buff; /* Number of fields per buffer: 1 or 2 */ - int img_x; /* start of image in x direction */ - int img_y; /* start of image in y direction */ - int img_width; /* image width BEFORE decimation, - must be a multiple of HorDcm*16 */ - int img_height; /* image height BEFORE decimation, - must be a multiple of VerDcm*8 */ - - /* --- End of parameters for decimation==0 only --- */ - - /* JPEG control parameters */ - - int quality; /* Measure for quality of compressed images. - Scales linearly with the size of the compressed images. - Must be beetween 0 and 100, 100 is a compression - ratio of 1:4 */ - - int odd_even; /* Which field should come first ??? */ - - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - unsigned long jpeg_markers; /* Which markers should go into the JPEG output. - Unless you exactly know what you do, leave them untouched. - Inluding less markers will make the resulting code - smaller, but there will be fewer aplications - which can read it. - The presence of the APP and COM marker is - influenced by APP0_len and COM_len ONLY! */ -#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ - - int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. - If this flag is turned on and JPEG decompressing - is going to the screen, the decompress process - is stopped every time the Video Fifo is full. - This enables a smooth decompress to the screen - but the video output signal will get scrambled */ - - /* Misc */ - - char reserved[312]; /* Makes 512 bytes for this structure */ -}; - -/* - Private IOCTL to set up for displaying MJPEG - */ -#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) -#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) -#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) -#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) -#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) -#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) -#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) - - -#ifdef __KERNEL__ - -#define BUZ_NUM_STAT_COM 4 -#define BUZ_MASK_STAT_COM 3 - -#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ -#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ - -#if VIDEO_MAX_FRAME <= 32 -#define V4L_MAX_FRAME 32 -#elif VIDEO_MAX_FRAME <= 64 -#define V4L_MAX_FRAME 64 -#else -#error "Too many video frame buffers to handle" -#endif -#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) - - -#include "zr36057.h" - -enum zoran_codec_mode { - BUZ_MODE_IDLE, /* nothing going on */ - BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ - BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ - BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ - BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ -}; - -enum zoran_buffer_state { - BUZ_STATE_USER, /* buffer is owned by application */ - BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ - BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ - BUZ_STATE_DONE /* buffer is ready to return to application */ -}; - -struct zoran_gbuffer { - u32 *frag_tab; /* addresses of frag table */ - u32 frag_tab_bus; /* same value cached to save time in ISR */ - enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ - struct zoran_sync bs; /* DONE: info to return to application */ -}; - -struct v4l_gbuffer { - char *fbuffer; /* virtual address of frame buffer */ - unsigned long fbuffer_phys; /* physical address of frame buffer */ - unsigned long fbuffer_bus; /* bus address of frame buffer */ - enum zoran_buffer_state state; /* state: unused/pending/done */ -}; - -struct zoran { - struct video_device video_dev; - struct i2c_bus i2c; - - int initialized; /* flag if zoran has been correctly initalized */ - int user; /* number of current users (0 or 1) */ - - unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ - struct pci_dev *pci_dev; /* PCI device */ - unsigned char revision; /* revision of zr36057 */ - int board; /* Board type */ -#define BOARD_BUZ 0 -#define BOARD_LML33 1 - unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ - unsigned char *zr36057_mem; /* pointer to mapped IO memory */ - - int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ - - spinlock_t lock; /* Spinlock */ - - /* Video for Linux parameters */ - - struct video_picture picture; /* Current picture params */ - struct video_buffer buffer; /* Current buffer params */ - struct video_window window; /* Current window params */ - int buffer_set, window_set; /* Flags if the above structures are set */ - int video_interlace; /* Image on screen is interlaced */ - - u32 *overlay_mask; - - wait_queue_head_t v4l_capq; /* wait here for grab to finish */ - - int v4l_overlay_active; /* Overlay grab is activated */ - int v4l_memgrab_active; /* Memory grab is activated */ - - int v4l_grab_frame; /* Frame number being currently grabbed */ -#define NO_GRAB_ACTIVE (-1) - int v4l_grab_seq; /* Number of frames grabbed */ - int gwidth; /* Width of current memory capture */ - int gheight; /* Height of current memory capture */ - int gformat; /* Format of ... */ - int gbpl; /* byte per line of ... */ - - /* V4L grab queue of frames pending */ - - unsigned v4l_pend_head; - unsigned v4l_pend_tail; - int v4l_pend[V4L_MAX_FRAME]; - - struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ - - /* Buz MJPEG parameters */ - - unsigned long jpg_nbufs; /* Number of buffers */ - unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ - int jpg_buffers_allocated; /* Flag if buffers are allocated */ - int need_contiguous; /* Flag if contiguous buffers are needed */ - - enum zoran_codec_mode codec_mode; /* status of codec */ - struct zoran_params params; /* structure with a lot of things to play with */ - - wait_queue_head_t jpg_capq; /* wait here for grab to finish */ - - /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ - /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ - /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ - unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ - unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ - unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ - unsigned long jpg_que_tail; /* Index of last buffer in queue */ - unsigned long jpg_seq_num; /* count of frames since grab/play started */ - - /* zr36057's code buffer table */ - u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ - - /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ - int jpg_pend[BUZ_MAX_FRAME]; - - /* array indexed by frame number */ - struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ -}; - -#endif - -/*The following should be done in more portable way. It depends on define - of _ALPHA_BUZ in the Makefile. */ - -#ifdef _ALPHA_BUZ -#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) -#define btread(adr) readl(zr->zr36057_adr+(adr)) -#else -#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) -#define btread(adr) readl(zr->zr36057_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) - -#define I2C_TSA5522 0xc2 -#define I2C_TDA9850 0xb6 -#define I2C_HAUPEE 0xa0 -#define I2C_STBEE 0xae -#define I2C_SAA7111 0x48 -#define I2C_SAA7185 0x88 - -#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.4.0-test6/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.4.0-test6/linux/drivers/char/bw-qcam.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/bw-qcam.c Wed Dec 31 16:00:00 1969 @@ -1,1066 +0,0 @@ -/* - * QuickCam Driver For Video4Linux. - * - * This version only works as a module. - * - * Video4Linux conversion work by Alan Cox. - * Parport compatibility by Phil Blundell. - * Busy loop avoidance by Mark Cooke. - * - * Module parameters: - * - * maxpoll=<1 - 5000> - * - * When polling the QuickCam for a response, busy-wait for a - * maximum of this many loops. The default of 250 gives little - * impact on interactive response. - * - * NOTE: If this parameter is set too high, the processor - * will busy wait until this loop times out, and then - * slowly poll for a further 5 seconds before failing - * the transaction. You have been warned. - * - * yieldlines=<1 - 250> - * - * When acquiring a frame from the camera, the data gathering - * loop will yield back to the scheduler after completing - * this many lines. The default of 4 provides a trade-off - * between increased frame acquisition time and impact on - * interactive response. - */ - -/* qcam-lib.c -- Library for programming with the Connectix QuickCam. - * See the included documentation for usage instructions and details - * of the protocol involved. */ - - -/* Version 0.5, August 4, 1996 */ -/* Version 0.7, August 27, 1996 */ -/* Version 0.9, November 17, 1996 */ - - -/****************************************************************** - -Copyright (C) 1996 by Scott Laird - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bw-qcam.h" - -static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ -static unsigned int yieldlines=4; /* Yield after this many during capture */ - -#if LINUX_VERSION_CODE >= 0x020117 -MODULE_PARM(maxpoll,"i"); -MODULE_PARM(yieldlines,"i"); -#endif - -extern __inline__ int read_lpstatus(struct qcam_device *q) -{ - return parport_read_status(q->pport); -} - -extern __inline__ int read_lpcontrol(struct qcam_device *q) -{ - return parport_read_control(q->pport); -} - -extern __inline__ int read_lpdata(struct qcam_device *q) -{ - return parport_read_data(q->pport); -} - -extern __inline__ void write_lpdata(struct qcam_device *q, int d) -{ - parport_write_data(q->pport, d); -} - -extern __inline__ void write_lpcontrol(struct qcam_device *q, int d) -{ - parport_write_control(q->pport, d); -} - -static int qc_waithand(struct qcam_device *q, int val); -static int qc_command(struct qcam_device *q, int command); -static int qc_readparam(struct qcam_device *q); -static int qc_setscanmode(struct qcam_device *q); -static int qc_readbytes(struct qcam_device *q, char buffer[]); - -static struct video_device qcam_template; - -static int qc_calibrate(struct qcam_device *q) -{ - /* - * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 - * The white balance is an individiual value for each - * quickcam. - */ - - int value; - int count = 0; - - qc_command(q, 27); /* AutoAdjustOffset */ - qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ - - /* GetOffset (33) will read 255 until autocalibration */ - /* is finished. After that, a value of 1-254 will be */ - /* returned. */ - - do { - qc_command(q, 33); - value = qc_readparam(q); - mdelay(1); - schedule(); - count++; - } while (value == 0xff && count<2048); - - q->whitebal = value; - return value; -} - -/* Initialize the QuickCam driver control structure. This is where - * defaults are set for people who don't have a config file.*/ - -static struct qcam_device *qcam_init(struct parport *port) -{ - struct qcam_device *q; - - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - if(q==NULL) - return NULL; - - q->pport = port; - q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, - NULL, 0, NULL); - if (q->pdev == NULL) - { - printk(KERN_ERR "bw-qcam: couldn't register for %s.\n", - port->name); - kfree(q); - return NULL; - } - - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - - init_MUTEX(&q->lock); - - q->port_mode = (QC_ANY | QC_NOTSET); - q->width = 320; - q->height = 240; - q->bpp = 4; - q->transfer_scale = 2; - q->contrast = 192; - q->brightness = 180; - q->whitebal = 105; - q->top = 1; - q->left = 14; - q->mode = -1; - q->status = QC_PARAM_CHANGE; - return q; -} - - -/* qc_command is probably a bit of a misnomer -- it's used to send - * bytes *to* the camera. Generally, these bytes are either commands - * or arguments to commands, so the name fits, but it still bugs me a - * bit. See the documentation for a list of commands. */ - -static int qc_command(struct qcam_device *q, int command) -{ - int n1, n2; - int cmd; - - write_lpdata(q, command); - write_lpcontrol(q, 6); - - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - -static int qc_readparam(struct qcam_device *q) -{ - int n1, n2; - int cmd; - - write_lpcontrol(q, 6); - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - -/* qc_waithand busy-waits for a handshake signal from the QuickCam. - * Almost all communication with the camera requires handshaking. */ - -static int qc_waithand(struct qcam_device *q, int val) -{ - int status; - int runs=0; - - if (val) - { - while (!((status = read_lpstatus(q)) & 8)) - { - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if(runs++>maxpoll) - { - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/200); - } - if(runs>(maxpoll+1000)) /* 5 seconds */ - return -1; - } - } - else - { - while (((status = read_lpstatus(q)) & 8)) - { - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if(runs++>maxpoll) - { - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/200); - } - if(runs++>(maxpoll+1000)) /* 5 seconds */ - return -1; - } - } - - return status; -} - -/* Waithand2 is used when the qcam is in bidirectional mode, and the - * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1 - * (bit 3 of status register). It also returns the last value read, - * since this data is useful. */ - -static unsigned int qc_waithand2(struct qcam_device *q, int val) -{ - unsigned int status; - int runs=0; - - do - { - status = read_lpdata(q); - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if(runs++>maxpoll) - { - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/200); - } - if(runs++>(maxpoll+1000)) /* 5 seconds */ - return 0; - } - while ((status & 1) != val); - - return status; -} - - -/* Try to detect a QuickCam. It appears to flash the upper 4 bits of - the status register at 5-10 Hz. This is only used in the autoprobe - code. Be aware that this isn't the way Connectix detects the - camera (they send a reset and try to handshake), but this should be - almost completely safe, while their method screws up my printer if - I plug it in before the camera. */ - -static int qc_detect(struct qcam_device *q) -{ - int reg, lastreg; - int count = 0; - int i; - - lastreg = reg = read_lpstatus(q) & 0xf0; - - for (i = 0; i < 500; i++) - { - reg = read_lpstatus(q) & 0xf0; - if (reg != lastreg) - count++; - lastreg = reg; - mdelay(2); - } - - -#if 0 - /* Force camera detection during testing. Sometimes the camera - won't be flashing these bits. Possibly unloading the module - in the middle of a grab? Or some timeout condition? - I've seen this parameter as low as 19 on my 450Mhz box - mpc */ - printk("Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); - return 1; -#endif - - /* Be (even more) liberal in what you accept... */ - -/* if (count > 30 && count < 200) */ - if (count > 20 && count < 300) - return 1; /* found */ - else - return 0; /* not found */ -} - - -/* Reset the QuickCam. This uses the same sequence the Windows - * QuickPic program uses. Someone with a bi-directional port should - * check that bi-directional mode is detected right, and then - * implement bi-directional mode in qc_readbyte(). */ - -static void qc_reset(struct qcam_device *q) -{ - switch (q->port_mode & QC_FORCE_MASK) - { - case QC_FORCE_UNIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - - case QC_FORCE_BIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - break; - - case QC_ANY: - write_lpcontrol(q, 0x20); - write_lpdata(q, 0x75); - - if (read_lpdata(q) != 0x75) { - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - } else { - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - } - break; - } - - write_lpcontrol(q, 0xb); - udelay(250); - write_lpcontrol(q, 0xe); - qc_setscanmode(q); /* in case port_mode changed */ -} - - -/* Decide which scan mode to use. There's no real requirement that - * the scanmode match the resolution in q->height and q-> width -- the - * camera takes the picture at the resolution specified in the - * "scanmode" and then returns the image at the resolution specified - * with the resolution commands. If the scan is bigger than the - * requested resolution, the upper-left hand corner of the scan is - * returned. If the scan is smaller, then the rest of the image - * returned contains garbage. */ - -static int qc_setscanmode(struct qcam_device *q) -{ - int old_mode = q->mode; - - switch (q->transfer_scale) - { - case 1: - q->mode = 0; - break; - case 2: - q->mode = 4; - break; - case 4: - q->mode = 8; - break; - } - - switch (q->bpp) - { - case 4: - break; - case 6: - q->mode += 2; - break; - } - - switch (q->port_mode & QC_MODE_MASK) - { - case QC_BIDIR: - q->mode += 1; - break; - case QC_NOTSET: - case QC_UNIDIR: - break; - } - - if (q->mode != old_mode) - q->status |= QC_PARAM_CHANGE; - - return 0; -} - - -/* Reset the QuickCam and program for brightness, contrast, - * white-balance, and resolution. */ - -void qc_set(struct qcam_device *q) -{ - int val; - int val2; - - qc_reset(q); - - /* Set the brightness. Yes, this is repetitive, but it works. - * Shorter versions seem to fail subtly. Feel free to try :-). */ - /* I think the problem was in qc_command, not here -- bls */ - - qc_command(q, 0xb); - qc_command(q, q->brightness); - - val = q->height / q->transfer_scale; - qc_command(q, 0x11); - qc_command(q, val); - if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) { - /* The normal "transfers per line" calculation doesn't seem to work - as expected here (and yet it works fine in qc_scan). No idea - why this case is the odd man out. Fortunately, Laird's original - working version gives me a good way to guess at working values. - -- bls */ - val = q->width; - val2 = q->transfer_scale * 4; - } else { - val = q->width * q->bpp; - val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * - q->transfer_scale; - } - val = (val + val2 - 1) / val2; - qc_command(q, 0x13); - qc_command(q, val); - - /* Setting top and left -- bls */ - qc_command(q, 0xd); - qc_command(q, q->top); - qc_command(q, 0xf); - qc_command(q, q->left / 2); - - qc_command(q, 0x19); - qc_command(q, q->contrast); - qc_command(q, 0x1f); - qc_command(q, q->whitebal); - - /* Clear flag that we must update the grabbing parameters on the camera - before we grab the next frame */ - q->status &= (~QC_PARAM_CHANGE); -} - -/* Qc_readbytes reads some bytes from the QC and puts them in - the supplied buffer. It returns the number of bytes read, - or -1 on error. */ - -extern __inline__ int qc_readbytes(struct qcam_device *q, char buffer[]) -{ - int ret=1; - unsigned int hi, lo; - unsigned int hi2, lo2; - static int state = 0; - - if (buffer == NULL) - { - state = 0; - return 0; - } - - switch (q->port_mode & QC_MODE_MASK) - { - case QC_BIDIR: /* Bi-directional Port */ - write_lpcontrol(q, 0x26); - lo = (qc_waithand2(q, 1) >> 1); - hi = (read_lpstatus(q) >> 3) & 0x1f; - write_lpcontrol(q, 0x2e); - lo2 = (qc_waithand2(q, 0) >> 1); - hi2 = (read_lpstatus(q) >> 3) & 0x1f; - switch (q->bpp) - { - case 4: - buffer[0] = lo & 0xf; - buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); - buffer[2] = (hi & 0x1e) >> 1; - buffer[3] = lo2 & 0xf; - buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); - buffer[5] = (hi2 & 0x1e) >> 1; - ret = 6; - break; - case 6: - buffer[0] = lo & 0x3f; - buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); - buffer[2] = lo2 & 0x3f; - buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); - ret = 4; - break; - } - break; - - case QC_UNIDIR: /* Unidirectional Port */ - write_lpcontrol(q, 6); - lo = (qc_waithand(q, 1) & 0xf0) >> 4; - write_lpcontrol(q, 0xe); - hi = (qc_waithand(q, 0) & 0xf0) >> 4; - - switch (q->bpp) - { - case 4: - buffer[0] = lo; - buffer[1] = hi; - ret = 2; - break; - case 6: - switch (state) - { - case 0: - buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); - q->saved_bits = (hi & 3) << 4; - state = 1; - ret = 1; - break; - case 1: - buffer[0] = lo | q->saved_bits; - q->saved_bits = hi << 2; - state = 2; - ret = 1; - break; - case 2: - buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits; - buffer[1] = ((lo & 3) << 4) | hi; - state = 0; - ret = 2; - break; - } - break; - } - break; - } - return ret; -} - -/* requests a scan from the camera. It sends the correct instructions - * to the camera and then reads back the correct number of bytes. In - * previous versions of this routine the return structure contained - * the raw output from the camera, and there was a 'qc_convertscan' - * function that converted that to a useful format. In version 0.3 I - * rolled qc_convertscan into qc_scan and now I only return the - * converted scan. The format is just an one-dimensional array of - * characters, one for each pixel, with 0=black up to n=white, where - * n=2^(bit depth)-1. Ask me for more details if you don't understand - * this. */ - -long qc_capture(struct qcam_device * q, char *buf, unsigned long len) -{ - int i, j, k, yield; - int bytes; - int linestotrans, transperline; - int divisor; - int pixels_per_line; - int pixels_read = 0; - int got=0; - char buffer[6]; - int shift=8-q->bpp; - char invert; - - if (q->mode == -1) - return -ENXIO; - - qc_command(q, 0x7); - qc_command(q, q->mode); - - if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) - { - write_lpcontrol(q, 0x2e); /* turn port around */ - write_lpcontrol(q, 0x26); - (void) qc_waithand(q, 1); - write_lpcontrol(q, 0x2e); - (void) qc_waithand(q, 0); - } - - /* strange -- should be 15:63 below, but 4bpp is odd */ - invert = (q->bpp == 4) ? 16 : 63; - - linestotrans = q->height / q->transfer_scale; - pixels_per_line = q->width / q->transfer_scale; - transperline = q->width * q->bpp; - divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * - q->transfer_scale; - transperline = (transperline + divisor - 1) / divisor; - - for (i = 0, yield = yieldlines; i < linestotrans; i++) - { - for (pixels_read = j = 0; j < transperline; j++) - { - bytes = qc_readbytes(q, buffer); - for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) - { - int o; - if (buffer[k] == 0 && invert == 16) - { - /* 4bpp is odd (again) -- inverter is 16, not 15, but output - must be 0-15 -- bls */ - buffer[k] = 16; - } - o=i*pixels_per_line + pixels_read + k; - if(o= yield) { - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/200); - yield = i + yieldlines; - } - } - - if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) - { - write_lpcontrol(q, 2); - write_lpcontrol(q, 6); - udelay(3); - write_lpcontrol(q, 0xe); - } - if(gotbrightness<<8; - p.contrast=qcam->contrast<<8; - p.whiteness=qcam->whitebal<<8; - p.depth=qcam->bpp; - p.palette=VIDEO_PALETTE_GREY; - 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_GREY) - return -EINVAL; - if(p.depth!=4 && p.depth!=6) - return -EINVAL; - - /* - * Now load the camera. - */ - - qcam->brightness = p.brightness>>8; - qcam->contrast = p.contrast>>8; - qcam->whitebal = p.whiteness>>8; - qcam->bpp = p.depth; - - down(&qcam->lock); - qc_setscanmode(qcam); - up(&qcam->lock); - qcam->status |= QC_PARAM_CHANGE; - - 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<60||vw.height>240) - return -EINVAL; - if(vw.width<80||vw.width>320) - return -EINVAL; - - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 4; - - if(vw.width>=160 && vw.height>=120) - { - qcam->transfer_scale = 2; - } - if(vw.width>=320 && vw.height>=240) - { - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 1; - } - down(&qcam->lock); - qc_setscanmode(qcam); - up(&qcam->lock); - - /* We must update the camera before we grab. We could - just have changed the grab size */ - qcam->status |= QC_PARAM_CHANGE; - - /* 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=qcam->width/qcam->transfer_scale; - vw.height=qcam->height/qcam->transfer_scale; - 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 qcam_read(struct video_device *v, char *buf, unsigned long count, int noblock) -{ - struct qcam_device *qcam=(struct qcam_device *)v; - int len; - parport_claim_or_block(qcam->pdev); - - down(&qcam->lock); - - qc_reset(qcam); - - /* Update the camera parameters if we need to */ - if (qcam->status & QC_PARAM_CHANGE) - qc_set(qcam); - - len=qc_capture(qcam, buf,count); - - up(&qcam->lock); - - parport_release(qcam->pdev); - return len; -} - -static struct video_device qcam_template= -{ - "Connectix Quickcam", - VID_TYPE_CAPTURE, - VID_HARDWARE_QCAM_BW, - qcam_open, - qcam_close, - qcam_read, - qcam_write, - NULL, - qcam_ioctl, - NULL, - qcam_init_done, - NULL, - 0, - 0 -}; - -#define MAX_CAMS 4 -static struct qcam_device *qcams[MAX_CAMS]; -static unsigned int num_cams = 0; - -int init_bwqcam(struct parport *port) -{ - struct qcam_device *qcam; - - if (num_cams == MAX_CAMS) - { - printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); - return -ENOSPC; - } - - qcam=qcam_init(port); - if(qcam==NULL) - return -ENODEV; - - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - if(qc_detect(qcam)==0) - { - parport_release(qcam->pdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - qc_calibrate(qcam); - - parport_release(qcam->pdev); - - printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); - - if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) - { - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - qcams[num_cams++] = qcam; - - return 0; -} - -void close_bwqcam(struct qcam_device *qcam) -{ - video_unregister_device(&qcam->vdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); -} - -/* The parport parameter controls which parports will be scanned. - * Scanning all parports causes some printers to print a garbage page. - * -- March 14, 1999 Billy Donahue */ -#ifdef MODULE -static char *parport[MAX_CAMS] = { NULL, }; -MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s"); -#endif - -#ifdef MODULE -int init_module(void) -{ - struct parport *port; - int n; - if(parport[0] && strncmp(parport[0], "auto", 4)){ - /* user gave parport parameters */ - for(n=0; parport[n] && nnext){ - if(r!=port->number) - continue; - init_bwqcam(port); - break; - } - } - return (num_cams)?0:-ENODEV; - } - /* no parameter or "auto" */ - for (port = parport_enumerate(); port; port=port->next) - init_bwqcam(port); - - /* Do some sanity checks on the module parameters. */ - if (maxpoll > 5000) { - printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n"); - maxpoll = 5000; - } - - if (yieldlines < 1) { - printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n"); - yieldlines = 1; - } - - return (num_cams)?0:-ENODEV; -} - -void cleanup_module(void) -{ - unsigned int i; - for (i = 0; i < num_cams; i++) - close_bwqcam(qcams[i]); -} -#else -int __init init_bw_qcams(struct video_init *unused) -{ - struct parport *port; - - for (port = parport_enumerate(); port; port=port->next) - init_bwqcam(port); - return 0; -} -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/bw-qcam.h linux/drivers/char/bw-qcam.h --- v2.4.0-test6/linux/drivers/char/bw-qcam.h Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/bw-qcam.h Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -/* - * Video4Linux bw-qcam driver - * - * Derived from code.. - */ - -/****************************************************************** - -Copyright (C) 1996 by Scott Laird - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -******************************************************************/ - -/* One from column A... */ -#define QC_NOTSET 0 -#define QC_UNIDIR 1 -#define QC_BIDIR 2 -#define QC_SERIAL 3 - -/* ... and one from column B */ -#define QC_ANY 0x00 -#define QC_FORCE_UNIDIR 0x10 -#define QC_FORCE_BIDIR 0x20 -#define QC_FORCE_SERIAL 0x30 -/* in the port_mode member */ - -#define QC_MODE_MASK 0x07 -#define QC_FORCE_MASK 0x70 - -#define MAX_HEIGHT 243 -#define MAX_WIDTH 336 - -/* Bit fields for status flags */ -#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ - -struct qcam_device { - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - struct semaphore lock; - int width, height; - int bpp; - int mode; - int contrast, brightness, whitebal; - int port_mode; - int transfer_scale; - int top, left; - int status; - unsigned int saved_bits; -}; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.4.0-test6/linux/drivers/char/c-qcam.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/c-qcam.c Wed Dec 31 16:00:00 1969 @@ -1,901 +0,0 @@ -/* - * Video4Linux Colour QuickCam driver - * Copyright 1997-2000 Philip Blundell - * - * Module parameters: - * - * parport=auto -- probe all parports (default) - * parport=0 -- parport0 becomes qcam1 - * parport=2,0,1 -- parports 2,0,1 are tried in that order - * - * probe=0 -- do no probing, assume camera is present - * probe=1 -- use IEEE-1284 autoprobe data only (default) - * probe=2 -- probe aggressively for cameras - * - * force_rgb=1 -- force data format to RGB (default is BGR) - * - * The parport parameter controls which parports will be scanned. - * Scanning all parports causes some printers to print a garbage page. - * -- March 14, 1999 Billy Donahue - * - * Fixed data format to BGR, added force_rgb parameter. Added missing - * parport_unregister_driver() on module removal. - * -- May 28, 2000 Claudio Matsuoka - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct qcam_device { - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - int width, height; - int ccd_width, ccd_height; - int mode; - int contrast, brightness, whitebal; - int top, left; - unsigned int bidirectional; - struct semaphore lock; -}; - -/* cameras maximum */ -#define MAX_CAMS 4 - -/* The three possible QuickCam modes */ -#define QC_MILLIONS 0x18 -#define QC_BILLIONS 0x10 -#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ - -/* The three possible decimations */ -#define QC_DECIMATION_1 0 -#define QC_DECIMATION_2 2 -#define QC_DECIMATION_4 4 - -#define BANNER "Colour QuickCam for Video4Linux v0.05" - -static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; -static int probe = 2; -static int force_rgb = 0; - -static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) -{ - /* note: the QC specs refer to the PCAck pin by voltage, not - software level. PC ports have builtin inverters. */ - parport_frob_control(qcam->pport, 8, i?8:0); -} - -static inline unsigned int qcam_ready1(struct qcam_device *qcam) -{ - return (parport_read_status(qcam->pport) & 0x8)?1:0; -} - -static inline unsigned int qcam_ready2(struct qcam_device *qcam) -{ - return (parport_read_data(qcam->pport) & 0x1)?1:0; -} - -static unsigned int qcam_await_ready1(struct qcam_device *qcam, - int value) -{ - unsigned long oldjiffies = jiffies; - unsigned int i; - - for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); ) - if (qcam_ready1(qcam) == value) - return 0; - - /* If the camera didn't respond within 1/25 second, poll slowly - for a while. */ - for (i = 0; i < 50; i++) - { - if (qcam_ready1(qcam) == value) - return 0; - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - } - - /* Probably somebody pulled the plug out. Not much we can do. */ - printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value, - parport_read_status(qcam->pport), - parport_read_control(qcam->pport)); - return 1; -} - -static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) -{ - unsigned long oldjiffies = jiffies; - unsigned int i; - - for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); ) - if (qcam_ready2(qcam) == value) - return 0; - - /* If the camera didn't respond within 1/25 second, poll slowly - for a while. */ - for (i = 0; i < 50; i++) - { - if (qcam_ready2(qcam) == value) - return 0; - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - } - - /* Probably somebody pulled the plug out. Not much we can do. */ - printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value, - parport_read_status(qcam->pport), - parport_read_control(qcam->pport), - parport_read_data(qcam->pport)); - return 1; -} - -static int qcam_read_data(struct qcam_device *qcam) -{ - unsigned int idata; - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) return -1; - idata = parport_read_status(qcam->pport) & 0xf0; - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) return -1; - idata |= (parport_read_status(qcam->pport) >> 4); - return idata; -} - -static int qcam_write_data(struct qcam_device *qcam, unsigned int data) -{ - unsigned int idata; - parport_write_data(qcam->pport, data); - idata = qcam_read_data(qcam); - if (data != idata) - { - printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, - idata); - return 1; - } - return 0; -} - -static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data) -{ - if (qcam_write_data(qcam, cmd)) - return -1; - if (qcam_write_data(qcam, data)) - return -1; - return 0; -} - -static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd) -{ - if (qcam_write_data(qcam, cmd)) - return -1; - return qcam_read_data(qcam); -} - -static int qc_detect(struct qcam_device *qcam) -{ - unsigned int stat, ostat, i, count = 0; - - /* The probe routine below is not very reliable. The IEEE-1284 - probe takes precedence. */ - /* XXX Currently parport provides no way to distinguish between - "the IEEE probe was not done" and "the probe was done, but - no device was found". Fix this one day. */ - if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA - && qcam->pport->probe_info[0].model - && !strcmp(qcam->pdev->port->probe_info[0].model, - "Color QuickCam 2.0")) { - printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n"); - return 1; - } - - if (probe < 2) - return 0; - - parport_write_control(qcam->pport, 0xc); - - /* look for a heartbeat */ - ostat = stat = parport_read_status(qcam->pport); - for (i=0; i<250; i++) - { - mdelay(1); - stat = parport_read_status(qcam->pport); - if (ostat != stat) - { - if (++count >= 3) return 1; - ostat = stat; - } - } - - /* Reset the camera and try again */ - parport_write_control(qcam->pport, 0xc); - parport_write_control(qcam->pport, 0x8); - mdelay(1); - parport_write_control(qcam->pport, 0xc); - mdelay(1); - count = 0; - - ostat = stat = parport_read_status(qcam->pport); - for (i=0; i<250; i++) - { - mdelay(1); - stat = parport_read_status(qcam->pport); - if (ostat != stat) - { - if (++count >= 3) return 1; - ostat = stat; - } - } - - /* no (or flatline) camera, give up */ - return 0; -} - -static void qc_reset(struct qcam_device *qcam) -{ - parport_write_control(qcam->pport, 0xc); - parport_write_control(qcam->pport, 0x8); - mdelay(1); - parport_write_control(qcam->pport, 0xc); - mdelay(1); -} - -/* Reset the QuickCam and program for brightness, contrast, - * white-balance, and resolution. */ - -static void qc_setup(struct qcam_device *q) -{ - qc_reset(q); - - /* Set the brightness. */ - qcam_set(q, 11, q->brightness); - - /* Set the height and width. These refer to the actual - CCD area *before* applying the selected decimation. */ - qcam_set(q, 17, q->ccd_height); - qcam_set(q, 19, q->ccd_width / 2); - - /* Set top and left. */ - qcam_set(q, 0xd, q->top); - qcam_set(q, 0xf, q->left); - - /* Set contrast and white balance. */ - qcam_set(q, 0x19, q->contrast); - qcam_set(q, 0x1f, q->whitebal); - - /* Set the speed. */ - qcam_set(q, 45, 2); -} - -/* Read some bytes from the camera and put them in the buffer. - nbytes should be a multiple of 3, because bidirectional mode gives - us three bytes at a time. */ - -static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) -{ - unsigned int bytes = 0; - - qcam_set_ack(q, 0); - if (q->bidirectional) - { - /* It's a bidirectional port */ - while (bytes < nbytes) - { - unsigned int lo1, hi1, lo2, hi2; - unsigned char r, g, b; - - if (qcam_await_ready2(q, 1)) return bytes; - lo1 = parport_read_data(q->pport) >> 1; - hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(q, 1); - if (qcam_await_ready2(q, 0)) return bytes; - lo2 = parport_read_data(q->pport) >> 1; - hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(q, 0); - r = (lo1 | ((hi1 & 1)<<7)); - g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); - b = (lo2 | ((hi2 & 1)<<7)); - if (force_rgb) { - buf[bytes++] = r; - buf[bytes++] = g; - buf[bytes++] = b; - } else { - buf[bytes++] = b; - buf[bytes++] = g; - buf[bytes++] = r; - } - } - } - else - { - /* It's a unidirectional port */ - int i = 0, n = bytes; - unsigned char rgb[3]; - - while (bytes < nbytes) - { - unsigned int hi, lo; - - if (qcam_await_ready1(q, 1)) return bytes; - hi = (parport_read_status(q->pport) & 0xf0); - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) return bytes; - lo = (parport_read_status(q->pport) & 0xf0); - qcam_set_ack(q, 0); - /* flip some bits */ - rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; - if (i >= 2) { -get_fragment: - if (force_rgb) { - buf[n++] = rgb[0]; - buf[n++] = rgb[1]; - buf[n++] = rgb[2]; - } else { - buf[n++] = rgb[2]; - buf[n++] = rgb[1]; - buf[n++] = rgb[0]; - } - } - } - if (i) { - i = 0; - goto get_fragment; - } - } - return bytes; -} - -#define BUFSZ 150 - -static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) -{ - unsigned lines, pixelsperline, bitsperxfer; - unsigned int is_bi_dir = q->bidirectional; - size_t wantlen, outptr = 0; - char tmpbuf[BUFSZ]; - - if (verify_area(VERIFY_WRITE, buf, len)) - return -EFAULT; - - /* Wait for camera to become ready */ - for (;;) - { - int i = qcam_get(q, 41); - if (i == -1) { - qc_setup(q); - return -EIO; - } - if ((i & 0x80) == 0) - break; - else - schedule(); - } - - if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1)) - return -EIO; - - lines = q->height; - pixelsperline = q->width; - bitsperxfer = (is_bi_dir) ? 24 : 8; - - if (is_bi_dir) - { - /* Turn the port around */ - parport_data_reverse(q->pport); - mdelay(3); - qcam_set_ack(q, 0); - if (qcam_await_ready1(q, 1)) { - qc_setup(q); - return -EIO; - } - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) { - qc_setup(q); - return -EIO; - } - } - - wantlen = lines * pixelsperline * 24 / 8; - - while (wantlen) - { - size_t t, s; - s = (wantlen > BUFSZ)?BUFSZ:wantlen; - t = qcam_read_bytes(q, tmpbuf, s); - if (outptr < len) - { - size_t sz = len - outptr; - if (sz > t) sz = t; - if (__copy_to_user(buf+outptr, tmpbuf, sz)) - break; - outptr += sz; - } - wantlen -= t; - if (t < s) - break; - if (current->need_resched) - schedule(); - } - - len = outptr; - - if (wantlen) - { - printk("qcam: short read.\n"); - if (is_bi_dir) - parport_data_forward(q->pport); - qc_setup(q); - return len; - } - - if (is_bi_dir) - { - int l; - do { - l = qcam_read_bytes(q, tmpbuf, 3); - if (current->need_resched) - schedule(); - } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); - if (force_rgb) { - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk("qcam: bad EOF\n"); - } else { - if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - printk("qcam: bad EOF\n"); - } - qcam_set_ack(q, 0); - if (qcam_await_ready1(q, 1)) - { - printk("qcam: no ack after EOF\n"); - parport_data_forward(q->pport); - qc_setup(q); - return len; - } - parport_data_forward(q->pport); - mdelay(3); - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) - { - printk("qcam: no ack to port turnaround\n"); - qc_setup(q); - return len; - } - } - else - { - int l; - do { - l = qcam_read_bytes(q, tmpbuf, 1); - if (current->need_resched) - schedule(); - } while (l && tmpbuf[0] == 0x7e); - l = qcam_read_bytes(q, tmpbuf+1, 2); - if (force_rgb) { - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk("qcam: bad EOF\n"); - } else { - if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - printk("qcam: bad EOF\n"); - } - } - - qcam_write_data(q, 0); - return len; -} - -/* - * Video4linux interfacing - */ - -static int qcam_open(struct video_device *dev, int flags) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static void qcam_close(struct video_device *dev) -{ - MOD_DEC_USE_COUNT; -} - -static int qcam_init_done(struct video_device *dev) -{ - return 0; -} - -static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock) -{ - return -EINVAL; -} - -static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct qcam_device *qcam=(struct qcam_device *)dev; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name, "Quickcam"); - b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES; - b.channels = 1; - b.audios = 0; - b.maxwidth = 320; - b.maxheight = 240; - b.minwidth = 80; - b.minheight = 60; - 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) - return -EINVAL; - v.flags=0; - v.tuners=0; - /* Good question.. its composite or SVHS so.. */ - v.type = VIDEO_TYPE_CAMERA; - strcpy(v.name, "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) - return -EINVAL; - 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= 0; - v.mode = VIDEO_MODE_AUTO; - 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; - if(v.mode!=VIDEO_MODE_AUTO) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture p; - p.colour=0x8000; - p.hue=0x8000; - p.brightness=qcam->brightness<<8; - p.contrast=qcam->contrast<<8; - p.whiteness=qcam->whitebal<<8; - p.depth=24; - p.palette=VIDEO_PALETTE_RGB24; - 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; - - /* - * Sanity check args - */ - if (p.depth != 24 || p.palette != VIDEO_PALETTE_RGB24) - return -EINVAL; - - /* - * Now load the camera. - */ - qcam->brightness = p.brightness>>8; - qcam->contrast = p.contrast>>8; - qcam->whitebal = p.whiteness>>8; - - down(&qcam->lock); - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - up(&qcam->lock); - 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<60||vw.height>240) - return -EINVAL; - if(vw.width<80||vw.width>320) - return -EINVAL; - - qcam->width = 80; - qcam->height = 60; - qcam->mode = QC_DECIMATION_4; - - if(vw.width>=160 && vw.height>=120) - { - qcam->width = 160; - qcam->height = 120; - qcam->mode = QC_DECIMATION_2; - } - if(vw.width>=320 && vw.height>=240) - { - qcam->width = 320; - qcam->height = 240; - qcam->mode = QC_DECIMATION_1; - } - qcam->mode |= QC_MILLIONS; -#if 0 - if(vw.width>=640 && vw.height>=480) - { - qcam->width = 640; - qcam->height = 480; - qcam->mode = QC_BILLIONS | QC_DECIMATION_1; - } -#endif - /* Ok we figured out what to use from our - wide choice */ - down(&qcam->lock); - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - up(&qcam->lock); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - vw.x=0; - vw.y=0; - vw.width=qcam->width; - vw.height=qcam->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 qcam_read(struct video_device *v, char *buf, unsigned long count, int noblock) -{ - struct qcam_device *qcam=(struct qcam_device *)v; - int len; - - down(&qcam->lock); - parport_claim_or_block(qcam->pdev); - /* Probably should have a semaphore against multiple users */ - len = qc_capture(qcam, buf,count); - parport_release(qcam->pdev); - up(&qcam->lock); - return len; -} - -/* video device template */ -static struct video_device qcam_template= -{ - "Colour QuickCam", - VID_TYPE_CAPTURE, - VID_HARDWARE_QCAM_C, - qcam_open, - qcam_close, - qcam_read, - qcam_write, - NULL, - qcam_ioctl, - NULL, - qcam_init_done, - NULL, - 0, - 0 -}; - -/* Initialize the QuickCam driver control structure. */ - -static struct qcam_device *qcam_init(struct parport *port) -{ - struct qcam_device *q; - - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - if(q==NULL) - return NULL; - - q->pport = port; - q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, - NULL, 0, NULL); - - q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0; - - if (q->pdev == NULL) - { - printk(KERN_ERR "c-qcam: couldn't register for %s.\n", - port->name); - kfree(q); - return NULL; - } - - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - - init_MUTEX(&q->lock); - q->width = q->ccd_width = 320; - q->height = q->ccd_height = 240; - q->mode = QC_MILLIONS | QC_DECIMATION_1; - q->contrast = 192; - q->brightness = 240; - q->whitebal = 128; - q->top = 1; - q->left = 14; - return q; -} - -static struct qcam_device *qcams[MAX_CAMS]; -static unsigned int num_cams = 0; - -int init_cqcam(struct parport *port) -{ - struct qcam_device *qcam; - - if (parport[0] != -1) - { - /* The user gave specific instructions */ - int i, found = 0; - for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) - { - if (parport[0] == port->number) - found = 1; - } - if (!found) - return -ENODEV; - } - - if (num_cams == MAX_CAMS) - return -ENOSPC; - - qcam = qcam_init(port); - if (qcam==NULL) - return -ENODEV; - - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - if (probe && qc_detect(qcam)==0) - { - parport_release(qcam->pdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - qc_setup(qcam); - - parport_release(qcam->pdev); - - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) - { - printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", - qcam->pport->name); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", - qcam->vdev.minor, qcam->pport->name); - - qcams[num_cams++] = qcam; - - return 0; -} - -void close_cqcam(struct qcam_device *qcam) -{ - video_unregister_device(&qcam->vdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); -} - -static void cq_attach(struct parport *port) -{ - init_cqcam(port); -} - -static void cq_detach(struct parport *port) -{ - /* Write this some day. */ -} - -static struct parport_driver cqcam_driver = { - "cqcam", - cq_attach, - cq_detach, - NULL -}; - -static int __init cqcam_init (void) -{ - printk(BANNER "\n"); - - return parport_register_driver(&cqcam_driver); -} - -static void __exit cqcam_cleanup (void) -{ - unsigned int i; - - for (i = 0; i < num_cams; i++) - close_cqcam(qcams[i]); - - parport_unregister_driver(&cqcam_driver); -} - -MODULE_AUTHOR("Philip Blundell "); -MODULE_DESCRIPTION(BANNER); -MODULE_PARM_DESC(parport ,"parport= for port detection method\n\ -probe=<0|1|2> for camera detection method\n\ -force_rgb=<0|1> for RGB data format (default BGR)"); -MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); -MODULE_PARM(probe, "i"); -MODULE_PARM(force_rgb, "i"); - -module_init(cqcam_init); -module_exit(cqcam_cleanup); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/cpia.c linux/drivers/char/cpia.c --- v2.4.0-test6/linux/drivers/char/cpia.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/cpia.c Wed Dec 31 16:00:00 1969 @@ -1,3324 +0,0 @@ -/* - * cpia CPiA driver - * - * Supports CPiA based Video Camera's. - * - * (C) Copyright 1999-2000 Peter Pregler, - * (C) Copyright 1999-2000 Scott J. Bertin, - * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.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 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. - */ - -/* #define _CPIA_DEBUG_ define for verbose debug output */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_KMOD -#include -#endif - -#include "cpia.h" - -#ifdef CONFIG_VIDEO_CPIA_PP -extern int cpia_pp_init(void); -#endif -#ifdef CONFIG_VIDEO_CPIA_USB -extern int cpia_usb_init(void); -#endif - -#ifdef MODULE -MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); -MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras"); -MODULE_SUPPORTED_DEVICE("video"); -#endif - -#define ABOUT "V4L-Driver for Vision CPiA based cameras" - -#ifndef VID_HARDWARE_CPIA -#define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */ -#endif - -#define CPIA_MODULE_CPIA (0<<5) -#define CPIA_MODULE_SYSTEM (1<<5) -#define CPIA_MODULE_VP_CTRL (5<<5) -#define CPIA_MODULE_CAPTURE (6<<5) -#define CPIA_MODULE_DEBUG (7<<5) - -#define INPUT (DATA_IN << 8) -#define OUTPUT (DATA_OUT << 8) - -#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1) -#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2) -#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3) -#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4) -#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5) -#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7) -#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8) -#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10) - -#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1) -#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2) -#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3) -#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4) -#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5) -#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6) -#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7) -#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8) -#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9) -#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10) -#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11) -#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12) -#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) - -#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) -#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) -#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) -#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) -#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7) -#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8) -#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9) -#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10) -#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11) -#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16) -#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17) -#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18) -#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19) -#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25) -#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30) -#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31) - -#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1) -#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2) -#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3) -#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4) -#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5) -#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6) -#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7) -#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8) -#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9) -#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10) -#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11) -#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) -#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) -#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) - -#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) -#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) -#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5) -#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6) -#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) -#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) -#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) - -enum { - FRAME_READY, /* Ready to grab into */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_UNUSED, /* Unused (no MCAPTURE) */ -}; - -#define COMMAND_NONE 0x0000 -#define COMMAND_SETCOMPRESSION 0x0001 -#define COMMAND_SETCOMPRESSIONTARGET 0x0002 -#define COMMAND_SETCOLOURPARAMS 0x0004 -#define COMMAND_SETFORMAT 0x0008 -#define COMMAND_PAUSE 0x0010 -#define COMMAND_RESUME 0x0020 -#define COMMAND_SETYUVTHRESH 0x0040 -#define COMMAND_SETECPTIMING 0x0080 -#define COMMAND_SETCOMPRESSIONPARAMS 0x0100 -#define COMMAND_SETEXPOSURE 0x0200 -#define COMMAND_SETCOLOURBALANCE 0x0400 -#define COMMAND_SETSENSORFPS 0x0800 -#define COMMAND_SETAPCOR 0x1000 -#define COMMAND_SETFLICKERCTRL 0x2000 -#define COMMAND_SETVLOFFSET 0x4000 - -/* Developer's Guide Table 5 p 3-34 - * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ -static u8 flicker_jumps[2][2][4] = -{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } }, - { { 64, 32, 16, 8 }, { 76, 38, 19, 9} } -}; - -/* forward declaration of local function */ -static void reset_camera_struct(struct cam_data *cam); - -/********************************************************************** - * - * Memory management - * - * This is a shameless copy from the USB-cpia driver (linux kernel - * version 2.3.29 or so, I have no idea what this code actually does ;). - * Actually it seems to be a copy of a shameless copy of the bttv-driver. - * Or that is a copy of a shameless copy of ... (To the powers: is there - * no generic kernel-function to do this sort of stuff?) - * - * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says - * there will be one, but apparentely not yet - jerdfelt - * - **********************************************************************/ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE-1)); - } - } - } - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = __pa(kva); - return ret; -} - -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); - adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr, page; - - if (!mem) - return; - - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); - adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - vfree(mem); -} - -/********************************************************************** - * - * /proc interface - * - **********************************************************************/ -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *cpia_proc_root=NULL; - -static int cpia_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *out = page; - int len, tmp; - struct cam_data *cam = data; - char tmpstr[20]; - - /* IMPORTANT: This output MUST be kept under PAGE_SIZE - * or we need to get more sophisticated. */ - - out += sprintf(out, "read-only\n-----------------------\n"); - out += sprintf(out, "V4L Driver version: %d.%d.%d\n", - CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); - out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n", - cam->params.version.firmwareVersion, - cam->params.version.firmwareRevision, - cam->params.version.vcVersion, - cam->params.version.vcRevision); - out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n", - cam->params.pnpID.vendor, cam->params.pnpID.product, - cam->params.pnpID.deviceRevision); - out += sprintf(out, "VP-Version: %d.%d %04x\n", - cam->params.vpVersion.vpVersion, - cam->params.vpVersion.vpRevision, - cam->params.vpVersion.cameraHeadID); - - out += sprintf(out, "system_state: %#04x\n", - cam->params.status.systemState); - out += sprintf(out, "grab_state: %#04x\n", - cam->params.status.grabState); - out += sprintf(out, "stream_state: %#04x\n", - cam->params.status.streamState); - out += sprintf(out, "fatal_error: %#04x\n", - cam->params.status.fatalError); - out += sprintf(out, "cmd_error: %#04x\n", - cam->params.status.cmdError); - out += sprintf(out, "debug_flags: %#04x\n", - cam->params.status.debugFlags); - out += sprintf(out, "vp_status: %#04x\n", - cam->params.status.vpStatus); - out += sprintf(out, "error_code: %#04x\n", - cam->params.status.errorCode); - out += sprintf(out, "video_size: %s\n", - cam->params.format.videoSize == VIDEOSIZE_CIF ? - "CIF " : "QCIF"); - out += sprintf(out, "sub_sample: %s\n", - cam->params.format.subSample == SUBSAMPLE_420 ? - "420" : "422"); - out += sprintf(out, "yuv_order: %s\n", - cam->params.format.yuvOrder == YUVORDER_YUYV ? - "YUYV" : "UYVY"); - out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n", - cam->params.roi.colStart*8, - cam->params.roi.rowStart*4, - cam->params.roi.colEnd*8, - cam->params.roi.rowEnd*4); - out += sprintf(out, "actual_fps: %3d\n", cam->fps); - out += sprintf(out, "transfer_rate: %4dkB/s\n", - cam->transfer_rate); - - out += sprintf(out, "\nread-write\n"); - out += sprintf(out, "----------------------- current min" - " max default comment\n"); - out += sprintf(out, "brightness: %8d %8d %8d %8d\n", - cam->params.colourParams.brightness, 0, 100, 50); - if (cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) - /* 1-02 firmware limits contrast to 80 */ - tmp = 80; - else - tmp = 96; - - out += sprintf(out, "contrast: %8d %8d %8d %8d" - " steps of 8\n", - cam->params.colourParams.contrast, 0, tmp, 48); - out += sprintf(out, "saturation: %8d %8d %8d %8d\n", - cam->params.colourParams.saturation, 0, 100, 50); - tmp = (25000+5000*cam->params.sensorFps.baserate)/ - (1<params.sensorFps.divisor); - out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n", - tmp/1000, tmp%1000, 3, 30, 15); - out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n", - 2*cam->params.streamStartLine, 0, - cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, - cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); - out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n", - cam->params.ecpTiming ? "slow" : "normal", "slow", - "normal", "normal"); - - if (cam->params.colourBalance.balanceModeIsAuto) { - sprintf(tmpstr, "auto"); - } else { - sprintf(tmpstr, "manual"); - } - out += sprintf(out, "color_balance_mode: %8s %8s %8s" - " %8s\n", tmpstr, "manual", "auto", "auto"); - out += sprintf(out, "red_gain: %8d %8d %8d %8d\n", - cam->params.colourBalance.redGain, 0, 212, 32); - out += sprintf(out, "green_gain: %8d %8d %8d %8d\n", - cam->params.colourBalance.greenGain, 0, 212, 6); - out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n", - cam->params.colourBalance.blueGain, 0, 212, 92); - - if (cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) - /* 1-02 firmware limits gain to 2 */ - sprintf(tmpstr, "%8d %8d", 1, 2); - else - sprintf(tmpstr, "1,2,4,8"); - - if (cam->params.exposure.gainMode == 0) - out += sprintf(out, "max_gain: unknown %18s" - " %8d\n", tmpstr, 2); - else - out += sprintf(out, "max_gain: %8d %18s %8d\n", - 1<<(cam->params.exposure.gainMode-1), tmpstr, 2); - - switch(cam->params.exposure.expMode) { - case 1: - case 3: - sprintf(tmpstr, "manual"); - break; - case 2: - sprintf(tmpstr, "auto"); - break; - default: - sprintf(tmpstr, "unknown"); - break; - } - out += sprintf(out, "exposure_mode: %8s %8s %8s" - " %8s\n", tmpstr, "manual", "auto", "auto"); - out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n", - (2-cam->params.exposure.centreWeight) ? "on" : "off", - "off", "on", "on"); - out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", - 1<params.exposure.gain, 1, 1); - if (cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) - /* 1-02 firmware limits fineExp to 127 */ - tmp = 255; - else - tmp = 511; - - out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n", - cam->params.exposure.fineExp*2, 0, tmp, 0); - if (cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) - /* 1-02 firmware limits coarseExpHi to 0 */ - tmp = 255; - else - tmp = 65535; - - out += sprintf(out, "coarse_exp: %8d %8d %8d" - " %8d\n", cam->params.exposure.coarseExpLo+ - 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); - out += sprintf(out, "red_comp: %8d %8d %8d %8d\n", - cam->params.exposure.redComp, 220, 255, 220); - out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n", - cam->params.exposure.green1Comp, 214, 255, 214); - out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n", - cam->params.exposure.green2Comp, 214, 255, 214); - out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n", - cam->params.exposure.blueComp, 230, 255, 230); - - out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n", - cam->params.apcor.gain1, 0, 0xff, 0x1c); - out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n", - cam->params.apcor.gain2, 0, 0xff, 0x1a); - out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n", - cam->params.apcor.gain4, 0, 0xff, 0x2d); - out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n", - cam->params.apcor.gain8, 0, 0xff, 0x2a); - out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n", - cam->params.vlOffset.gain1, 0, 255, 24); - out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n", - cam->params.vlOffset.gain2, 0, 255, 28); - out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n", - cam->params.vlOffset.gain4, 0, 255, 30); - out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n", - cam->params.vlOffset.gain8, 0, 255, 30); - out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n", - cam->params.flickerControl.flickerMode ? "on" : "off", - "off", "on", "off"); - out += sprintf(out, "mains_frequency: %8d %8d %8d %8d" - " only 50/60\n", - cam->mainsFreq ? 60 : 50, 50, 60, 50); - out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n", - cam->params.flickerControl.allowableOverExposure, 0, - 255, 0); - out += sprintf(out, "compression_mode: "); - switch(cam->params.compression.mode) { - case CPIA_COMPRESSION_NONE: - out += sprintf(out, "%8s", "none"); - break; - case CPIA_COMPRESSION_AUTO: - out += sprintf(out, "%8s", "auto"); - break; - case CPIA_COMPRESSION_MANUAL: - out += sprintf(out, "%8s", "manual"); - break; - default: - out += sprintf(out, "%8s", "unknown"); - break; - } - out += sprintf(out, " none,auto,manual auto\n"); - out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n", - cam->params.compression.decimation == - DECIMATION_ENAB ? "on":"off", "off", "off", - "off"); - out += sprintf(out, "compression_target: %9s %9s %9s %9s\n", - cam->params.compressionTarget.frTargeting == - CPIA_COMPRESSION_TARGET_FRAMERATE ? - "framerate":"quality", - "framerate", "quality", "quality"); - out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n", - cam->params.compressionTarget.targetFR, 0, 30, 7); - out += sprintf(out, "target_quality: %8d %8d %8d %8d\n", - cam->params.compressionTarget.targetQ, 0, 255, 10); - out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n", - cam->params.yuvThreshold.yThreshold, 0, 31, 15); - out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n", - cam->params.yuvThreshold.uvThreshold, 0, 31, 15); - out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n", - cam->params.compressionParams.hysteresis, 0, 255, 3); - out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n", - cam->params.compressionParams.threshMax, 0, 255, 11); - out += sprintf(out, "small_step: %8d %8d %8d %8d\n", - cam->params.compressionParams.smallStep, 0, 255, 1); - out += sprintf(out, "large_step: %8d %8d %8d %8d\n", - cam->params.compressionParams.largeStep, 0, 255, 3); - out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n", - cam->params.compressionParams.decimationHysteresis, - 0, 255, 2); - out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n", - cam->params.compressionParams.frDiffStepThresh, - 0, 255, 5); - out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n", - cam->params.compressionParams.qDiffStepThresh, - 0, 255, 3); - out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", - cam->params.compressionParams.decimationThreshMod, - 0, 255, 2); - - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) return 0; - } else - len = count; - - *start = page + off; - return len; -} - -static int cpia_write_proc(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct cam_data *cam = data; - struct cam_params new_params; - int retval, find_colon; - int size = count; - unsigned long val; - u32 command_flags = 0; - u8 new_mains; - - if (down_interruptible(&cam->param_lock)) - return -ERESTARTSYS; - - /* - * Skip over leading whitespace - */ - while (count && isspace(*buffer)) { - --count; - ++buffer; - } - - memcpy(&new_params, &cam->params, sizeof(struct cam_params)); - new_mains = cam->mainsFreq; - -#define MATCH(x) \ - ({ \ - int _len = strlen(x), _ret, _colon_found; \ - _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \ - if (_ret) { \ - buffer += _len; \ - count -= _len; \ - if (find_colon) { \ - _colon_found = 0; \ - while (count && (*buffer == ' ' || *buffer == '\t' || \ - (!_colon_found && *buffer == ':'))) { \ - if (*buffer == ':') \ - _colon_found = 1; \ - --count; \ - ++buffer; \ - } \ - if (!count || !_colon_found) \ - retval = -EINVAL; \ - find_colon = 0; \ - } \ - } \ - _ret; \ - }) -#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \ - new_params.version.firmwareRevision == (y)) -#define VALUE \ - ({ \ - char *_p; \ - unsigned long int _ret; \ - _ret = simple_strtoul(buffer, &_p, 0); \ - if (_p == buffer) \ - retval = -EINVAL; \ - else { \ - count -= _p - buffer; \ - buffer = _p; \ - } \ - _ret; \ - }) - - retval = 0; - while (count && !retval) { - find_colon = 1; - if (MATCH("brightness")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 100) - new_params.colourParams.brightness = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOLOURPARAMS; - } else if (MATCH("contrast")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 100) { - /* contrast is in steps of 8, so round*/ - val = ((val + 3) / 8) * 8; - /* 1-02 firmware limits contrast to 80*/ - if (FIRMWARE_VERSION(1,2) && val > 80) - val = 80; - - new_params.colourParams.contrast = val; - } else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOLOURPARAMS; - } else if (MATCH("saturation")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 100) - new_params.colourParams.saturation = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOLOURPARAMS; - } else if (MATCH("sensor_fps")) { - if (!retval) - val = VALUE; - - if (!retval) { - /* find values so that sensorFPS is minimized, - * but >= val */ - if (val > 30) - retval = -EINVAL; - else if (val > 25) { - new_params.sensorFps.divisor = 0; - new_params.sensorFps.baserate = 1; - } else if (val > 15) { - new_params.sensorFps.divisor = 0; - new_params.sensorFps.baserate = 0; - } else if (val > 12) { - new_params.sensorFps.divisor = 1; - new_params.sensorFps.baserate = 1; - } else if (val > 7) { - new_params.sensorFps.divisor = 1; - new_params.sensorFps.baserate = 0; - } else if (val > 6) { - new_params.sensorFps.divisor = 2; - new_params.sensorFps.baserate = 1; - } else if (val > 3) { - new_params.sensorFps.divisor = 2; - new_params.sensorFps.baserate = 0; - } else { - new_params.sensorFps.divisor = 3; - /* Either base rate would work here */ - new_params.sensorFps.baserate = 1; - } - new_params.flickerControl.coarseJump = - flicker_jumps[new_mains] - [new_params.sensorFps.baserate] - [new_params.sensorFps.divisor]; - if (new_params.flickerControl.flickerMode) - command_flags |= COMMAND_SETFLICKERCTRL; - } - command_flags |= COMMAND_SETSENSORFPS; - } else if (MATCH("stream_start_line")) { - if (!retval) - val = VALUE; - - if (!retval) { - int max_line = 288; - - if (new_params.format.videoSize == VIDEOSIZE_QCIF) - max_line = 144; - if (val <= max_line) - new_params.streamStartLine = val/2; - else - retval = -EINVAL; - } - } else if (MATCH("ecp_timing")) { - if (!retval && MATCH("normal")) - new_params.ecpTiming = 0; - else if (!retval && MATCH("slow")) - new_params.ecpTiming = 1; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETECPTIMING; - } else if (MATCH("color_balance_mode")) { - if (!retval && MATCH("manual")) - new_params.colourBalance.balanceModeIsAuto = 0; - else if (!retval && MATCH("auto")) - new_params.colourBalance.balanceModeIsAuto = 1; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETCOLOURBALANCE; - } else if (MATCH("red_gain")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 212) - new_params.colourBalance.redGain = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOLOURBALANCE; - } else if (MATCH("green_gain")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 212) - new_params.colourBalance.greenGain = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOLOURBALANCE; - } else if (MATCH("blue_gain")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 212) - new_params.colourBalance.blueGain = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOLOURBALANCE; - } else if (MATCH("max_gain")) { - if (!retval) - val = VALUE; - - if (!retval) { - /* 1-02 firmware limits gain to 2 */ - if (FIRMWARE_VERSION(1,2) && val > 2) - val = 2; - switch(val) { - case 1: - new_params.exposure.gainMode = 1; - break; - case 2: - new_params.exposure.gainMode = 2; - break; - case 4: - new_params.exposure.gainMode = 3; - break; - case 8: - new_params.exposure.gainMode = 4; - break; - default: - retval = -EINVAL; - break; - } - } - command_flags |= COMMAND_SETEXPOSURE; - } else if (MATCH("exposure_mode")) { - if (!retval && MATCH("auto")) - new_params.exposure.expMode = 2; - else if (!retval && MATCH("manual")) { - if (new_params.exposure.expMode == 2) - new_params.exposure.expMode = 3; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - } else - retval = -EINVAL; - - command_flags |= COMMAND_SETEXPOSURE; - } else if (MATCH("centre_weight")) { - if (!retval && MATCH("on")) - new_params.exposure.centreWeight = 1; - else if (!retval && MATCH("off")) - new_params.exposure.centreWeight = 2; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETEXPOSURE; - } else if (MATCH("gain")) { - if (!retval) - val = VALUE; - - if (!retval) { - switch(val) { - case 1: - new_params.exposure.gain = 0; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - break; - case 2: - new_params.exposure.gain = 1; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - break; - case 4: - new_params.exposure.gain = 2; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - break; - case 8: - new_params.exposure.gain = 3; - new_params.exposure.expMode = 1; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - break; - default: - retval = -EINVAL; - break; - } - command_flags |= COMMAND_SETEXPOSURE; - if (new_params.exposure.gain > - new_params.exposure.gainMode-1) - retval = -EINVAL; - } - } else if (MATCH("fine_exp")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val < 256) { - /* 1-02 firmware limits fineExp to 127*/ - if (FIRMWARE_VERSION(1,2) && val > 127) - val = 127; - new_params.exposure.fineExp = val; - new_params.exposure.expMode = 1; - command_flags |= COMMAND_SETEXPOSURE; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - } else - retval = -EINVAL; - } - } else if (MATCH("coarse_exp")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val < 65536) { - /* 1-02 firmware limits - * coarseExp to 255 */ - if (FIRMWARE_VERSION(1,2) && val > 255) - val = 255; - new_params.exposure.coarseExpLo = - val & 0xff; - new_params.exposure.coarseExpHi = - val >> 8; - new_params.exposure.expMode = 1; - command_flags |= COMMAND_SETEXPOSURE; - new_params.flickerControl.flickerMode = 0; - command_flags |= COMMAND_SETFLICKERCTRL; - } else - retval = -EINVAL; - } - } else if (MATCH("red_comp")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val >= 220 && val <= 255) { - new_params.exposure.redComp = val; - command_flags |= COMMAND_SETEXPOSURE; - } else - retval = -EINVAL; - } - } else if (MATCH("green1_comp")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val >= 214 && val <= 255) { - new_params.exposure.green1Comp = val; - command_flags |= COMMAND_SETEXPOSURE; - } else - retval = -EINVAL; - } - } else if (MATCH("green2_comp")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val >= 214 && val <= 255) { - new_params.exposure.green2Comp = val; - command_flags |= COMMAND_SETEXPOSURE; - } else - retval = -EINVAL; - } - } else if (MATCH("blue_comp")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val >= 230 && val <= 255) { - new_params.exposure.blueComp = val; - command_flags |= COMMAND_SETEXPOSURE; - } else - retval = -EINVAL; - } - } else if (MATCH("apcor_gain1")) { - if (!retval) - val = VALUE; - - if (!retval) { - command_flags |= COMMAND_SETAPCOR; - if (val <= 0xff) - new_params.apcor.gain1 = val; - else - retval = -EINVAL; - } - } else if (MATCH("apcor_gain2")) { - if (!retval) - val = VALUE; - - if (!retval) { - command_flags |= COMMAND_SETAPCOR; - if (val <= 0xff) - new_params.apcor.gain2 = val; - else - retval = -EINVAL; - } - } else if (MATCH("apcor_gain4")) { - if (!retval) - val = VALUE; - - if (!retval) { - command_flags |= COMMAND_SETAPCOR; - if (val <= 0xff) - new_params.apcor.gain4 = val; - else - retval = -EINVAL; - } - } else if (MATCH("apcor_gain8")) { - if (!retval) - val = VALUE; - - if (!retval) { - command_flags |= COMMAND_SETAPCOR; - if (val <= 0xff) - new_params.apcor.gain8 = val; - else - retval = -EINVAL; - } - } else if (MATCH("vl_offset_gain1")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.vlOffset.gain1 = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETVLOFFSET; - } else if (MATCH("vl_offset_gain2")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.vlOffset.gain2 = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETVLOFFSET; - } else if (MATCH("vl_offset_gain4")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.vlOffset.gain4 = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETVLOFFSET; - } else if (MATCH("vl_offset_gain8")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.vlOffset.gain8 = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETVLOFFSET; - } else if (MATCH("flicker_control")) { - if (!retval && MATCH("on")) { - new_params.flickerControl.flickerMode = 1; - new_params.exposure.expMode = 2; - command_flags |= COMMAND_SETEXPOSURE; - } else if (!retval && MATCH("off")) - new_params.flickerControl.flickerMode = 0; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETFLICKERCTRL; - } else if (MATCH("mains_frequency")) { - if (!retval && MATCH("50")) { - new_mains = 0; - new_params.flickerControl.coarseJump = - flicker_jumps[new_mains] - [new_params.sensorFps.baserate] - [new_params.sensorFps.divisor]; - if (new_params.flickerControl.flickerMode) - command_flags |= COMMAND_SETFLICKERCTRL; - } else if (!retval && MATCH("60")) { - new_mains = 1; - new_params.flickerControl.coarseJump = - flicker_jumps[new_mains] - [new_params.sensorFps.baserate] - [new_params.sensorFps.divisor]; - if (new_params.flickerControl.flickerMode) - command_flags |= COMMAND_SETFLICKERCTRL; - } else - retval = -EINVAL; - } else if (MATCH("allowable_overexposure")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) { - new_params.flickerControl. - allowableOverExposure = val; - command_flags |= COMMAND_SETFLICKERCTRL; - } else - retval = -EINVAL; - } - } else if (MATCH("compression_mode")) { - if (!retval && MATCH("none")) - new_params.compression.mode = - CPIA_COMPRESSION_NONE; - else if (!retval && MATCH("auto")) - new_params.compression.mode = - CPIA_COMPRESSION_AUTO; - else if (!retval && MATCH("manual")) - new_params.compression.mode = - CPIA_COMPRESSION_MANUAL; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETCOMPRESSION; - } else if (MATCH("decimation_enable")) { - if (!retval && MATCH("off")) - new_params.compression.decimation = 0; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETCOMPRESSION; - } else if (MATCH("compression_target")) { - if (!retval && MATCH("quality")) - new_params.compressionTarget.frTargeting = - CPIA_COMPRESSION_TARGET_QUALITY; - else if (!retval && MATCH("framerate")) - new_params.compressionTarget.frTargeting = - CPIA_COMPRESSION_TARGET_FRAMERATE; - else - retval = -EINVAL; - - command_flags |= COMMAND_SETCOMPRESSIONTARGET; - } else if (MATCH("target_framerate")) { - if (!retval) - val = VALUE; - - if (!retval) - new_params.compressionTarget.targetFR = val; - command_flags |= COMMAND_SETCOMPRESSIONTARGET; - } else if (MATCH("target_quality")) { - if (!retval) - val = VALUE; - - if (!retval) - new_params.compressionTarget.targetQ = val; - - command_flags |= COMMAND_SETCOMPRESSIONTARGET; - } else if (MATCH("y_threshold")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val < 32) - new_params.yuvThreshold.yThreshold = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETYUVTHRESH; - } else if (MATCH("uv_threshold")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val < 32) - new_params.yuvThreshold.uvThreshold = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETYUVTHRESH; - } else if (MATCH("hysteresis")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.hysteresis = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("threshold_max")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.threshMax = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("small_step")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.smallStep = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("large_step")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.largeStep = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("decimation_hysteresis")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.decimationHysteresis = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("fr_diff_step_thresh")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.frDiffStepThresh = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("q_diff_step_thresh")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.qDiffStepThresh = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else if (MATCH("decimation_thresh_mod")) { - if (!retval) - val = VALUE; - - if (!retval) { - if (val <= 0xff) - new_params.compressionParams.decimationThreshMod = val; - else - retval = -EINVAL; - } - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - } else { - DBG("No match found\n"); - retval = -EINVAL; - } - - if (!retval) { - while (count && isspace(*buffer) && *buffer != '\n') { - --count; - ++buffer; - } - if (count) { - if (*buffer != '\n' && *buffer != ';') - retval = -EINVAL; - else { - --count; - ++buffer; - } - } - } - } -#undef MATCH -#undef FIRMWARE_VERSION -#undef VALUE -#undef FIND_VALUE -#undef FIND_END - if (!retval) { - if (command_flags & COMMAND_SETCOLOURPARAMS) { - /* Adjust cam->vp to reflect these changes */ - cam->vp.brightness = - new_params.colourParams.brightness*65535/100; - cam->vp.contrast = - new_params.colourParams.contrast*65535/100; - cam->vp.colour = - new_params.colourParams.saturation*65535/100; - } - - memcpy(&cam->params, &new_params, sizeof(struct cam_params)); - cam->mainsFreq = new_mains; - cam->cmd_queue |= command_flags; - retval = size; - } else - DBG("error: %d\n", retval); - - up(&cam->param_lock); - - return retval; -} - -static void create_proc_cpia_cam(struct cam_data *cam) -{ - char name[7]; - struct proc_dir_entry *ent; - - if (!cpia_proc_root || !cam) - return; - - sprintf(name, "video%d", cam->vdev.minor); - - ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root); - if (!ent) - return; - - ent->data = cam; - ent->read_proc = cpia_read_proc; - ent->write_proc = cpia_write_proc; - ent->size = 3626; - cam->proc_entry = ent; -} - -static void destroy_proc_cpia_cam(struct cam_data *cam) -{ - char name[7]; - - if (!cam || !cam->proc_entry) - return; - - sprintf(name, "video%d", cam->vdev.minor); - remove_proc_entry(name, cpia_proc_root); - cam->proc_entry = NULL; -} - -static void proc_cpia_create(void) -{ - cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0); - - if (cpia_proc_root) - cpia_proc_root->owner = THIS_MODULE; - else - LOG("Unable to initialise /proc/cpia\n"); -} - -static void proc_cpia_destroy(void) -{ - remove_proc_entry("cpia", 0); -} -#endif /* CONFIG_PROC_FS */ - -/* ----------------------- debug functions ---------------------- */ - -#define printstatus(cam) \ - DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\ - cam->params.status.systemState, cam->params.status.grabState, \ - cam->params.status.streamState, cam->params.status.fatalError, \ - cam->params.status.cmdError, cam->params.status.debugFlags, \ - cam->params.status.vpStatus, cam->params.status.errorCode); - -/* ----------------------- v4l helpers -------------------------- */ - -/* supported frame palettes and depths */ -static inline int valid_mode(u16 palette, u16 depth) -{ - return (palette == VIDEO_PALETTE_GREY && depth == 8) || - (palette == VIDEO_PALETTE_RGB555 && depth == 16) || - (palette == VIDEO_PALETTE_RGB565 && depth == 16) || - (palette == VIDEO_PALETTE_RGB24 && depth == 24) || - (palette == VIDEO_PALETTE_RGB32 && depth == 32) || - (palette == VIDEO_PALETTE_YUV422 && depth == 16) || - (palette == VIDEO_PALETTE_YUYV && depth == 16) || - (palette == VIDEO_PALETTE_UYVY && depth == 16); -} - -static int match_videosize( int width, int height ) -{ - /* return the best match, where 'best' is as always - * the largest that is not bigger than what is requested. */ - if (width>=352 && height>=288) - return VIDEOSIZE_352_288; /* CIF */ - - if (width>=320 && height>=240) - return VIDEOSIZE_320_240; /* SIF */ - - if (width>=288 && height>=216) - return VIDEOSIZE_288_216; - - if (width>=256 && height>=192) - return VIDEOSIZE_256_192; - - if (width>=224 && height>=168) - return VIDEOSIZE_224_168; - - if (width>=192 && height>=144) - return VIDEOSIZE_192_144; - - if (width>=176 && height>=144) - return VIDEOSIZE_176_144; /* QCIF */ - - if (width>=160 && height>=120) - return VIDEOSIZE_160_120; /* QSIF */ - - if (width>=128 && height>=96) - return VIDEOSIZE_128_96; - - if (width>=88 && height>=72) - return VIDEOSIZE_88_72; - - if (width>=64 && height>=48) - return VIDEOSIZE_64_48; - - if (width>=48 && height>=48) - return VIDEOSIZE_48_48; - - return -1; -} - -/* these are the capture sizes we support */ -static void set_vw_size(struct cam_data *cam) -{ - /* the col/row/start/end values are the result of simple math */ - /* study the SetROI-command in cpia developers guide p 2-22 */ - /* streamStartLine is set to the recommended value in the cpia */ - /* developers guide p 3-37 */ - switch(cam->video_size) { - case VIDEOSIZE_CIF: - cam->vw.width = 352; - cam->vw.height = 288; - cam->params.format.videoSize=VIDEOSIZE_CIF; - cam->params.roi.colStart=0; - cam->params.roi.colEnd=44; - cam->params.roi.rowStart=0; - cam->params.roi.rowEnd=72; - cam->params.streamStartLine = 120; - break; - case VIDEOSIZE_SIF: - cam->vw.width = 320; - cam->vw.height = 240; - cam->params.format.videoSize=VIDEOSIZE_CIF; - cam->params.roi.colStart=2; - cam->params.roi.colEnd=42; - cam->params.roi.rowStart=6; - cam->params.roi.rowEnd=66; - cam->params.streamStartLine = 120; - break; - case VIDEOSIZE_288_216: - cam->vw.width = 288; - cam->vw.height = 216; - cam->params.format.videoSize=VIDEOSIZE_CIF; - cam->params.roi.colStart=4; - cam->params.roi.colEnd=40; - cam->params.roi.rowStart=9; - cam->params.roi.rowEnd=63; - cam->params.streamStartLine = 120; - break; - case VIDEOSIZE_256_192: - cam->vw.width = 256; - cam->vw.height = 192; - cam->params.format.videoSize=VIDEOSIZE_CIF; - cam->params.roi.colStart=6; - cam->params.roi.colEnd=38; - cam->params.roi.rowStart=12; - cam->params.roi.rowEnd=60; - cam->params.streamStartLine = 120; - break; - case VIDEOSIZE_224_168: - cam->vw.width = 224; - cam->vw.height = 168; - cam->params.format.videoSize=VIDEOSIZE_CIF; - cam->params.roi.colStart=8; - cam->params.roi.colEnd=36; - cam->params.roi.rowStart=15; - cam->params.roi.rowEnd=57; - cam->params.streamStartLine = 120; - break; - case VIDEOSIZE_192_144: - cam->vw.width = 192; - cam->vw.height = 144; - cam->params.format.videoSize=VIDEOSIZE_CIF; - cam->params.roi.colStart=10; - cam->params.roi.colEnd=34; - cam->params.roi.rowStart=18; - cam->params.roi.rowEnd=54; - cam->params.streamStartLine = 120; - break; - case VIDEOSIZE_QCIF: - cam->vw.width = 176; - cam->vw.height = 144; - cam->params.format.videoSize=VIDEOSIZE_QCIF; - cam->params.roi.colStart=0; - cam->params.roi.colEnd=22; - cam->params.roi.rowStart=0; - cam->params.roi.rowEnd=36; - cam->params.streamStartLine = 60; - break; - case VIDEOSIZE_QSIF: - cam->vw.width = 160; - cam->vw.height = 120; - cam->params.format.videoSize=VIDEOSIZE_QCIF; - cam->params.roi.colStart=1; - cam->params.roi.colEnd=21; - cam->params.roi.rowStart=3; - cam->params.roi.rowEnd=33; - cam->params.streamStartLine = 60; - break; - case VIDEOSIZE_128_96: - cam->vw.width = 128; - cam->vw.height = 96; - cam->params.format.videoSize=VIDEOSIZE_QCIF; - cam->params.roi.colStart=3; - cam->params.roi.colEnd=19; - cam->params.roi.rowStart=6; - cam->params.roi.rowEnd=30; - cam->params.streamStartLine = 60; - break; - case VIDEOSIZE_88_72: - cam->vw.width = 88; - cam->vw.height = 72; - cam->params.format.videoSize=VIDEOSIZE_QCIF; - cam->params.roi.colStart=5; - cam->params.roi.colEnd=16; - cam->params.roi.rowStart=9; - cam->params.roi.rowEnd=27; - cam->params.streamStartLine = 60; - break; - case VIDEOSIZE_64_48: - cam->vw.width = 64; - cam->vw.height = 48; - cam->params.format.videoSize=VIDEOSIZE_QCIF; - cam->params.roi.colStart=7; - cam->params.roi.colEnd=15; - cam->params.roi.rowStart=12; - cam->params.roi.rowEnd=24; - cam->params.streamStartLine = 60; - break; - case VIDEOSIZE_48_48: - cam->vw.width = 48; - cam->vw.height = 48; - cam->params.format.videoSize=VIDEOSIZE_QCIF; - cam->params.roi.colStart=8; - cam->params.roi.colEnd=14; - cam->params.roi.rowStart=6; - cam->params.roi.rowEnd=30; - cam->params.streamStartLine = 60; - break; - default: - LOG("bad videosize value: %d\n", cam->video_size); - } - - return; -} - -static int allocate_frame_buf(struct cam_data *cam) -{ - int i; - - cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE); - if (!cam->frame_buf) - return -ENOBUFS; - - for (i = 0; i < FRAME_NUM; i++) - cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE; - - return 0; -} - -static int free_frame_buf(struct cam_data *cam) -{ - int i; - - rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE); - cam->frame_buf = 0; - for (i=0; i < FRAME_NUM; i++) - cam->frame[i].data = NULL; - - return 0; -} - - -static void inline free_frames(struct cpia_frame frame[FRAME_NUM]) -{ - int i; - - for (i=0; i < FRAME_NUM; i++) - frame[i].state = FRAME_UNUSED; - return; -} - -/********************************************************************** - * - * General functions - * - **********************************************************************/ -/* send an arbitrary command to the camera */ -static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) -{ - int retval, datasize; - u8 cmd[8], data[8]; - - switch(command) { - case CPIA_COMMAND_GetCPIAVersion: - case CPIA_COMMAND_GetPnPID: - case CPIA_COMMAND_GetCameraStatus: - case CPIA_COMMAND_GetVPVersion: - datasize=8; - break; - case CPIA_COMMAND_GetColourParams: - case CPIA_COMMAND_GetColourBalance: - case CPIA_COMMAND_GetExposure: - down(&cam->param_lock); - datasize=8; - break; - default: - datasize=0; - break; - } - - cmd[0] = command>>8; - cmd[1] = command&0xff; - cmd[2] = a; - cmd[3] = b; - cmd[4] = c; - cmd[5] = d; - cmd[6] = datasize; - cmd[7] = 0; - - retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); - if (retval) { - DBG("%x - failed, retval=%d\n", command, retval); - if (command == CPIA_COMMAND_GetColourParams || - command == CPIA_COMMAND_GetColourBalance || - command == CPIA_COMMAND_GetExposure) - up(&cam->param_lock); - } else { - switch(command) { - case CPIA_COMMAND_GetCPIAVersion: - cam->params.version.firmwareVersion = data[0]; - cam->params.version.firmwareRevision = data[1]; - cam->params.version.vcVersion = data[2]; - cam->params.version.vcRevision = data[3]; - break; - case CPIA_COMMAND_GetPnPID: - cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8); - cam->params.pnpID.product = data[2]+(((u16)data[3])<<8); - cam->params.pnpID.deviceRevision = - data[4]+(((u16)data[5])<<8); - break; - case CPIA_COMMAND_GetCameraStatus: - cam->params.status.systemState = data[0]; - cam->params.status.grabState = data[1]; - cam->params.status.streamState = data[2]; - cam->params.status.fatalError = data[3]; - cam->params.status.cmdError = data[4]; - cam->params.status.debugFlags = data[5]; - cam->params.status.vpStatus = data[6]; - cam->params.status.errorCode = data[7]; - break; - case CPIA_COMMAND_GetVPVersion: - cam->params.vpVersion.vpVersion = data[0]; - cam->params.vpVersion.vpRevision = data[1]; - cam->params.vpVersion.cameraHeadID = - data[2]+(((u16)data[3])<<8); - break; - case CPIA_COMMAND_GetColourParams: - cam->params.colourParams.brightness = data[0]; - cam->params.colourParams.contrast = data[1]; - cam->params.colourParams.saturation = data[2]; - up(&cam->param_lock); - break; - case CPIA_COMMAND_GetColourBalance: - cam->params.colourBalance.redGain = data[0]; - cam->params.colourBalance.greenGain = data[1]; - cam->params.colourBalance.blueGain = data[2]; - up(&cam->param_lock); - break; - case CPIA_COMMAND_GetExposure: - cam->params.exposure.gain = data[0]; - cam->params.exposure.fineExp = data[1]; - cam->params.exposure.coarseExpLo = data[2]; - cam->params.exposure.coarseExpHi = data[3]; - cam->params.exposure.redComp = data[4]; - cam->params.exposure.green1Comp = data[5]; - cam->params.exposure.green2Comp = data[6]; - cam->params.exposure.blueComp = data[7]; - /* If the *Comp parameters are wacko, generate - * a warning, and reset them back to default - * values. - rich@annexia.org - */ - if (cam->params.exposure.redComp < 220 || - cam->params.exposure.redComp > 255 || - cam->params.exposure.green1Comp < 214 || - cam->params.exposure.green1Comp > 255 || - cam->params.exposure.green2Comp < 214 || - cam->params.exposure.green2Comp > 255 || - cam->params.exposure.blueComp < 230 || - cam->params.exposure.blueComp > 255) - { - printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n", - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); - cam->params.exposure.redComp = 220; - cam->params.exposure.green1Comp = 214; - cam->params.exposure.green2Comp = 214; - cam->params.exposure.blueComp = 230; - } - up(&cam->param_lock); - break; - default: - break; - } - } - return retval; -} - -/* send a command to the camera with an additional data transaction */ -static int do_command_extended(struct cam_data *cam, u16 command, - u8 a, u8 b, u8 c, u8 d, - u8 e, u8 f, u8 g, u8 h, - u8 i, u8 j, u8 k, u8 l) -{ - int retval; - u8 cmd[8], data[8]; - - cmd[0] = command>>8; - cmd[1] = command&0xff; - cmd[2] = a; - cmd[3] = b; - cmd[4] = c; - cmd[5] = d; - cmd[6] = 8; - cmd[7] = 0; - data[0] = e; - data[1] = f; - data[2] = g; - data[3] = h; - data[4] = i; - data[5] = j; - data[6] = k; - data[7] = l; - - retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); - if (retval) - LOG("%x - failed\n", command); - - return retval; -} - -/********************************************************************** - * - * Colorspace conversion - * - **********************************************************************/ -#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) - -static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt, - int in_uyvy, int mmap_kludge) -{ - int y, u, v, r, g, b, y1; - - switch(out_fmt) { - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_RGB32: - if (in_uyvy) { - u = *yuv++ - 128; - y = (*yuv++ - 16) * 76310; - v = *yuv++ - 128; - y1 = (*yuv - 16) * 76310; - } else { - y = (*yuv++ - 16) * 76310; - u = *yuv++ - 128; - y1 = (*yuv++ - 16) * 76310; - v = *yuv - 128; - } - r = 104635 * v; - g = -25690 * u + -53294 * v; - b = 132278 * u; - break; - default: - y = *yuv++; - u = *yuv++; - y1 = *yuv++; - v = *yuv; - /* Just to avoid compiler warnings */ - r = 0; - g = 0; - b = 0; - break; - } - switch(out_fmt) { - case VIDEO_PALETTE_RGB555: - *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3); - *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6); - *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3); - *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6); - return 4; - case VIDEO_PALETTE_RGB565: - *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3); - *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5); - *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3); - *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5); - return 4; - case VIDEO_PALETTE_RGB24: - if (mmap_kludge) { - *rgb++ = LIMIT(b+y); - *rgb++ = LIMIT(g+y); - *rgb++ = LIMIT(r+y); - *rgb++ = LIMIT(b+y1); - *rgb++ = LIMIT(g+y1); - *rgb = LIMIT(r+y1); - } else { - *rgb++ = LIMIT(r+y); - *rgb++ = LIMIT(g+y); - *rgb++ = LIMIT(b+y); - *rgb++ = LIMIT(r+y1); - *rgb++ = LIMIT(g+y1); - *rgb = LIMIT(b+y1); - } - return 6; - case VIDEO_PALETTE_RGB32: - if (mmap_kludge) { - *rgb++ = LIMIT(b+y); - *rgb++ = LIMIT(g+y); - *rgb++ = LIMIT(r+y); - rgb++; - *rgb++ = LIMIT(b+y1); - *rgb++ = LIMIT(g+y1); - *rgb = LIMIT(r+y1); - } else { - *rgb++ = LIMIT(r+y); - *rgb++ = LIMIT(g+y); - *rgb++ = LIMIT(b+y); - rgb++; - *rgb++ = LIMIT(r+y1); - *rgb++ = LIMIT(g+y1); - *rgb = LIMIT(b+y1); - } - return 8; - case VIDEO_PALETTE_GREY: - *rgb++ = y; - *rgb = y1; - return 2; - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - *rgb++ = y; - *rgb++ = u; - *rgb++ = y1; - *rgb = v; - return 4; - case VIDEO_PALETTE_UYVY: - *rgb++ = u; - *rgb++ = y; - *rgb++ = v; - *rgb = y1; - return 4; - default: - DBG("Empty: %d\n", out_fmt); - return 0; - } -} - -static int skipcount(int count, int fmt) -{ - switch(fmt) { - case VIDEO_PALETTE_GREY: - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_UYVY: - return 2*count; - case VIDEO_PALETTE_RGB24: - return 3*count; - case VIDEO_PALETTE_RGB32: - return 4*count; - default: - return 0; - } -} - -static int parse_picture(struct cam_data *cam, int size) -{ - u8 *obuf, *ibuf, *end_obuf; - int ll, in_uyvy, compressed, origsize, out_fmt; - - /* make sure params don't change while we are decoding */ - down(&cam->param_lock); - - obuf = cam->decompressed_frame.data; - end_obuf = obuf+CPIA_MAX_FRAME_SIZE; - ibuf = cam->raw_image; - origsize = size; - out_fmt = cam->vp.palette; - - if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) { - LOG("header not found\n"); - up(&cam->param_lock); - return -1; - } - - if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) { - LOG("wrong video size\n"); - up(&cam->param_lock); - return -1; - } - - if (ibuf[17] != SUBSAMPLE_422) { - LOG("illegal subtype %d\n",ibuf[17]); - up(&cam->param_lock); - return -1; - } - - if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) { - LOG("illegal yuvorder %d\n",ibuf[18]); - up(&cam->param_lock); - return -1; - } - in_uyvy = ibuf[18] == YUVORDER_UYVY; - -#if 0 - /* FIXME: ROI mismatch occurs when switching capture sizes */ - if ((ibuf[24] != cam->params.roi.colStart) || - (ibuf[25] != cam->params.roi.colEnd) || - (ibuf[26] != cam->params.roi.rowStart) || - (ibuf[27] != cam->params.roi.rowEnd)) { - LOG("ROI mismatch\n"); - up(&cam->param_lock); - return -1; - } -#endif - - if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) { - LOG("illegal compression %d\n",ibuf[28]); - up(&cam->param_lock); - return -1; - } - compressed = (ibuf[28] == COMPRESSED); - - if (ibuf[29] != NO_DECIMATION) { - LOG("decimation not supported\n"); - up(&cam->param_lock); - return -1; - } - - cam->params.yuvThreshold.yThreshold = ibuf[30]; - cam->params.yuvThreshold.uvThreshold = ibuf[31]; - cam->params.status.systemState = ibuf[32]; - cam->params.status.grabState = ibuf[33]; - cam->params.status.streamState = ibuf[34]; - cam->params.status.fatalError = ibuf[35]; - cam->params.status.cmdError = ibuf[36]; - cam->params.status.debugFlags = ibuf[37]; - cam->params.status.vpStatus = ibuf[38]; - cam->params.status.errorCode = ibuf[39]; - cam->fps = ibuf[41]; - up(&cam->param_lock); - - ibuf += FRAME_HEADER_SIZE; - size -= FRAME_HEADER_SIZE; - ll = ibuf[0] | (ibuf[1] << 8); - ibuf += 2; - - while (size > 0) { - size -= (ll+2); - if (size < 0) { - LOG("Insufficient data in buffer\n"); - return -1; - } - - while (ll > 1) { - if (!compressed || (compressed && !(*ibuf & 1))) { - obuf += yuvconvert(ibuf, obuf, out_fmt, - in_uyvy, cam->mmap_kludge); - ibuf += 4; - ll -= 4; - } else { - /*skip compressed interval from previous frame*/ - int skipsize = skipcount(*ibuf >> 1, out_fmt); - obuf += skipsize; - if (obuf > end_obuf) { - LOG("Insufficient data in buffer\n"); - return -1; - } - ++ibuf; - ll--; - } - } - if (ll == 1) { - if (*ibuf != EOL) { - LOG("EOL not found giving up after %d/%d" - " bytes\n", origsize-size, origsize); - return -1; - } - - ibuf++; /* skip over EOL */ - - if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) && - (ibuf[2] == EOI) && (ibuf[3] == EOI)) { - size -= 4; - break; - } - - if (size > 1) { - ll = ibuf[0] | (ibuf[1] << 8); - ibuf += 2; /* skip over line length */ - } - } else { - LOG("line length was not 1 but %d after %d/%d bytes\n", - ll, origsize-size, origsize); - return -1; - } - } - - cam->decompressed_frame.count = obuf-cam->decompressed_frame.data; - - return cam->decompressed_frame.count; -} - -/* InitStreamCap wrapper to select correct start line */ -static inline int init_stream_cap(struct cam_data *cam) -{ - return do_command(cam, CPIA_COMMAND_InitStreamCap, - 0, cam->params.streamStartLine, 0, 0); -} - -/* update various camera modes and settings */ -static void dispatch_commands(struct cam_data *cam) -{ - down(&cam->param_lock); - if (cam->cmd_queue==COMMAND_NONE) { - up(&cam->param_lock); - return; - } - DEB_BYTE(cam->cmd_queue); - DEB_BYTE(cam->cmd_queue>>8); - if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS) - do_command(cam, CPIA_COMMAND_SetColourParams, - cam->params.colourParams.brightness, - cam->params.colourParams.contrast, - cam->params.colourParams.saturation, 0); - - if (cam->cmd_queue & COMMAND_SETCOMPRESSION) - do_command(cam, CPIA_COMMAND_SetCompression, - cam->params.compression.mode, - cam->params.compression.decimation, 0, 0); - - if (cam->cmd_queue & COMMAND_SETFORMAT) { - do_command(cam, CPIA_COMMAND_SetFormat, - cam->params.format.videoSize, - cam->params.format.subSample, - cam->params.format.yuvOrder, 0); - do_command(cam, CPIA_COMMAND_SetROI, - cam->params.roi.colStart, cam->params.roi.colEnd, - cam->params.roi.rowStart, cam->params.roi.rowEnd); - cam->first_frame = 1; - } - - if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET) - do_command(cam, CPIA_COMMAND_SetCompressionTarget, - cam->params.compressionTarget.frTargeting, - cam->params.compressionTarget.targetFR, - cam->params.compressionTarget.targetQ, 0); - - if (cam->cmd_queue & COMMAND_SETYUVTHRESH) - do_command(cam, CPIA_COMMAND_SetYUVThresh, - cam->params.yuvThreshold.yThreshold, - cam->params.yuvThreshold.uvThreshold, 0, 0); - - if (cam->cmd_queue & COMMAND_SETECPTIMING) - do_command(cam, CPIA_COMMAND_SetECPTiming, - cam->params.ecpTiming, 0, 0, 0); - - if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS) - do_command_extended(cam, CPIA_COMMAND_SetCompressionParams, - 0, 0, 0, 0, - cam->params.compressionParams.hysteresis, - cam->params.compressionParams.threshMax, - cam->params.compressionParams.smallStep, - cam->params.compressionParams.largeStep, - cam->params.compressionParams.decimationHysteresis, - cam->params.compressionParams.frDiffStepThresh, - cam->params.compressionParams.qDiffStepThresh, - cam->params.compressionParams.decimationThreshMod); - - if (cam->cmd_queue & COMMAND_SETEXPOSURE) - do_command_extended(cam, CPIA_COMMAND_SetExposure, - cam->params.exposure.gainMode, - cam->params.exposure.expMode, - cam->params.exposure.compMode, - cam->params.exposure.centreWeight, - cam->params.exposure.gain, - cam->params.exposure.fineExp, - cam->params.exposure.coarseExpLo, - cam->params.exposure.coarseExpHi, - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); - - if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) { - if (cam->params.colourBalance.balanceModeIsAuto) { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 2, 0, 0, 0); - } else { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 1, - cam->params.colourBalance.redGain, - cam->params.colourBalance.greenGain, - cam->params.colourBalance.blueGain); - do_command(cam, CPIA_COMMAND_SetColourBalance, - 3, 0, 0, 0); - } - } - - if (cam->cmd_queue & COMMAND_SETSENSORFPS) - do_command(cam, CPIA_COMMAND_SetSensorFPS, - cam->params.sensorFps.divisor, - cam->params.sensorFps.baserate, 0, 0); - - if (cam->cmd_queue & COMMAND_SETAPCOR) - do_command(cam, CPIA_COMMAND_SetApcor, - cam->params.apcor.gain1, - cam->params.apcor.gain2, - cam->params.apcor.gain4, - cam->params.apcor.gain8); - - if (cam->cmd_queue & COMMAND_SETFLICKERCTRL) - do_command(cam, CPIA_COMMAND_SetFlickerCtrl, - cam->params.flickerControl.flickerMode, - cam->params.flickerControl.coarseJump, - cam->params.flickerControl.allowableOverExposure, 0); - - if (cam->cmd_queue & COMMAND_SETVLOFFSET) - do_command(cam, CPIA_COMMAND_SetVLOffset, - cam->params.vlOffset.gain1, - cam->params.vlOffset.gain2, - cam->params.vlOffset.gain4, - cam->params.vlOffset.gain8); - - if (cam->cmd_queue & COMMAND_PAUSE) - do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); - - if (cam->cmd_queue & COMMAND_RESUME) - init_stream_cap(cam); - - up(&cam->param_lock); - cam->cmd_queue = COMMAND_NONE; - return; -} - -/* kernel thread function to read image from camera */ -static void fetch_frame(void *data) -{ - int image_size, retry; - struct cam_data *cam = (struct cam_data *)data; - unsigned long oldjif, rate, diff; - - /* Allow up to two bad images in a row to be read and - * ignored before an error is reported */ - for (retry = 0; retry < 3; ++retry) { - if (retry) - DBG("retry=%d\n", retry); - - if (!cam->ops) - continue; - - /* load first frame always uncompressed */ - if (cam->first_frame && - cam->params.compression.mode != CPIA_COMPRESSION_NONE) - do_command(cam, CPIA_COMMAND_SetCompression, - CPIA_COMPRESSION_NONE, - NO_DECIMATION, 0, 0); - - /* init camera upload */ - if (do_command(cam, CPIA_COMMAND_SetGrabMode, - CPIA_GRAB_CONTINUOUS, 0, 0, 0)) - continue; - - if (do_command(cam, CPIA_COMMAND_GrabFrame, 0, - cam->params.streamStartLine, 0, 0)) - continue; - - if (cam->ops->wait_for_stream_ready) { - /* loop until image ready */ - do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0); - while (cam->params.status.streamState != STREAM_READY) { - if (current->need_resched) - schedule(); - - current->state = TASK_INTERRUPTIBLE; - - /* sleep for 10 ms, hopefully ;) */ - schedule_timeout(10*HZ/1000); - if (signal_pending(current)) - return; - - do_command(cam, CPIA_COMMAND_GetCameraStatus, - 0, 0, 0, 0); - } - } - - /* grab image from camera */ - if (current->need_resched) - schedule(); - - oldjif = jiffies; - image_size = cam->ops->streamRead(cam->lowlevel_data, - cam->raw_image, 0); - if (image_size <= 0) { - DBG("streamRead failed: %d\n", image_size); - continue; - } - - rate = image_size * HZ / 1024; - diff = jiffies-oldjif; - cam->transfer_rate = diff==0 ? rate : rate/diff; - /* diff==0 ? unlikely but possible */ - - /* camera idle now so dispatch queued commands */ - dispatch_commands(cam); - - /* Update our knowledge of the camera state - FIXME: necessary? */ - do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); - do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); - - /* decompress and convert image to by copying it from - * raw_image to decompressed_frame - */ - if (current->need_resched) - schedule(); - - cam->image_size = parse_picture(cam, image_size); - if (cam->image_size <= 0) - DBG("parse_picture failed %d\n", cam->image_size); - else - break; - } - - if (retry < 3) { - /* FIXME: this only works for double buffering */ - if (cam->frame[cam->curframe].state == FRAME_READY) { - memcpy(cam->frame[cam->curframe].data, - cam->decompressed_frame.data, - cam->decompressed_frame.count); - cam->frame[cam->curframe].state = FRAME_DONE; - } else - cam->decompressed_frame.state = FRAME_DONE; - -#if 0 - if (cam->first_frame && - cam->params.compression.mode != CPIA_COMPRESSION_NONE) { - cam->first_frame = 0; - cam->cmd_queue |= COMMAND_SETCOMPRESSION; - } -#else - if (cam->first_frame) { - cam->first_frame = 0; - cam->cmd_queue |= COMMAND_SETCOMPRESSION; - cam->cmd_queue |= COMMAND_SETEXPOSURE; - } -#endif - } -} - -static int capture_frame(struct cam_data *cam, struct video_mmap *vm) -{ - int retval = 0; - - if (!cam->frame_buf) { - /* we do lazy allocation */ - if ((retval = allocate_frame_buf(cam))) - return retval; - } - - /* FIXME: the first frame seems to be captured by the camera - without regards to any initial settings, so we throw away - that one, the next one is generated with our settings - (exposure, color balance, ...) - */ - if (cam->first_frame) { - cam->curframe = vm->frame; - cam->frame[cam->curframe].state = FRAME_READY; - fetch_frame(cam); - if (cam->frame[cam->curframe].state != FRAME_DONE) - retval = -EIO; - } - cam->curframe = vm->frame; - cam->frame[cam->curframe].state = FRAME_READY; - fetch_frame(cam); - if (cam->frame[cam->curframe].state != FRAME_DONE) - retval=-EIO; - - return retval; -} - -static int goto_high_power(struct cam_data *cam) -{ - if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0)) - return -1; - mdelay(100); /* windows driver does it too */ - if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) - return -1; - if (cam->params.status.systemState == HI_POWER_STATE) { - DBG("camera now in HIGH power state\n"); - return 0; - } - printstatus(cam); - return -1; -} - -static int goto_low_power(struct cam_data *cam) -{ - if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0)) - return -1; - if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) - return -1; - if (cam->params.status.systemState == LO_POWER_STATE) { - DBG("camera now in LOW power state\n"); - return 0; - } - printstatus(cam); - return -1; -} - -static void save_camera_state(struct cam_data *cam) -{ - do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); - do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); - - DBG("%d/%d/%d/%d/%d/%d/%d/%d\n", - cam->params.exposure.gain, - cam->params.exposure.fineExp, - cam->params.exposure.coarseExpLo, - cam->params.exposure.coarseExpHi, - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); - DBG("%d/%d/%d\n", - cam->params.colourBalance.redGain, - cam->params.colourBalance.greenGain, - cam->params.colourBalance.blueGain); -} - -static void set_camera_state(struct cam_data *cam) -{ - if(cam->params.colourBalance.balanceModeIsAuto) { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 2, 0, 0, 0); - } else { - do_command(cam, CPIA_COMMAND_SetColourBalance, - 1, - cam->params.colourBalance.redGain, - cam->params.colourBalance.greenGain, - cam->params.colourBalance.blueGain); - do_command(cam, CPIA_COMMAND_SetColourBalance, - 3, 0, 0, 0); - } - - - do_command_extended(cam, CPIA_COMMAND_SetExposure, - cam->params.exposure.gainMode, 1, 1, - cam->params.exposure.centreWeight, - cam->params.exposure.gain, - cam->params.exposure.fineExp, - cam->params.exposure.coarseExpLo, - cam->params.exposure.coarseExpHi, - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); - do_command_extended(cam, CPIA_COMMAND_SetExposure, - 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0); - - if (!cam->params.exposure.gainMode) - cam->params.exposure.gainMode = 2; - if (!cam->params.exposure.expMode) - cam->params.exposure.expMode = 2; - if (!cam->params.exposure.centreWeight) - cam->params.exposure.centreWeight = 1; - - cam->cmd_queue = COMMAND_SETCOMPRESSION | - COMMAND_SETCOMPRESSIONTARGET | - COMMAND_SETCOLOURPARAMS | - COMMAND_SETFORMAT | - COMMAND_SETYUVTHRESH | - COMMAND_SETECPTIMING | - COMMAND_SETCOMPRESSIONPARAMS | -#if 0 - COMMAND_SETEXPOSURE | -#endif - COMMAND_SETCOLOURBALANCE | - COMMAND_SETSENSORFPS | - COMMAND_SETAPCOR | - COMMAND_SETFLICKERCTRL | - COMMAND_SETVLOFFSET; - dispatch_commands(cam); - save_camera_state(cam); - - return; -} - -static void get_version_information(struct cam_data *cam) -{ - /* GetCPIAVersion */ - do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0); - - /* GetPnPID */ - do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0); -} - -/* initialize camera */ -static int reset_camera(struct cam_data *cam) -{ - /* Start the camera in low power mode */ - if (goto_low_power(cam)) { - if (cam->params.status.systemState != WARM_BOOT_STATE) - return -ENODEV; - - /* FIXME: this is just dirty trial and error */ - reset_camera_struct(cam); - goto_high_power(cam); - do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); - if (goto_low_power(cam)) - return -NODEV; - } - - /* procedure described in developer's guide p3-28 */ - - /* Check the firmware version FIXME: should we check PNPID? */ - cam->params.version.firmwareVersion = 0; - get_version_information(cam); - if (cam->params.version.firmwareVersion != 1) - return -ENODEV; - - /* The fatal error checking should be done after - * the camera powers up (developer's guide p 3-38) */ - - /* Set streamState before transition to high power to avoid bug - * in firmware 1-02 */ - do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0, - STREAM_NOT_READY, 0); - - /* GotoHiPower */ - if (goto_high_power(cam)) - return -ENODEV; - - /* Check the camera status */ - if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) - return -EIO; - - if (cam->params.status.fatalError) { - DBG("fatal_error: %#04x\n", - cam->params.status.fatalError); - DBG("vp_status: %#04x\n", - cam->params.status.vpStatus); - if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) { - /* Fatal error in camera */ - return -EIO; - } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) { - /* Firmware 1-02 may do this for parallel port cameras, - * just clear the flags (developer's guide p 3-38) */ - do_command(cam, CPIA_COMMAND_ModifyCameraStatus, - FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0); - } - } - - /* Check the camera status again */ - if (cam->params.status.fatalError) { - if (cam->params.status.fatalError) - return -EIO; - } - - /* VPVersion can't be retrieved before the camera is in HiPower, - * so get it here instead of in get_version_information. */ - do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); - - /* set camera to a known state */ - set_camera_state(cam); - - return 0; -} - -/* ------------------------- V4L interface --------------------- */ -static int cpia_open(struct video_device *dev, int flags) -{ - int i; - struct cam_data *cam = dev->priv; - - if (!cam) { - DBG("Internal error, cam_data not found!\n"); - return -EBUSY; - } - - if (cam->open_count > 0) { - DBG("Camera already open\n"); - return -EBUSY; - } - - if (!cam->raw_image) { - cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE); - if (!cam->raw_image) - return -ENOMEM; - } - - if (!cam->decompressed_frame.data) { - cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE); - if (!cam->decompressed_frame.data) { - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image = NULL; - return -ENOMEM; - } - } - - /* open cpia */ - if (cam->ops->open(cam->lowlevel_data)) { - rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data = NULL; - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image = NULL; - return -ENODEV; - } - - /* reset the camera */ - if ((i = reset_camera(cam)) != 0) { - cam->ops->close(cam->lowlevel_data); - rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data = NULL; - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image = NULL; - return i; - } - - /* Set ownership of /proc/cpia/videoX to current user */ - if(cam->proc_entry) - cam->proc_entry->uid = current->uid; - - /* set mark for loading first frame uncompressed */ - cam->first_frame = 1; - - /* init it to something */ - cam->mmap_kludge = 0; - - ++cam->open_count; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return 0; -} - -static void cpia_close(struct video_device *dev) -{ - struct cam_data *cam; - - cam = dev->priv; - - if (cam->ops) { - /* Return ownership of /proc/cpia/videoX to root */ - if(cam->proc_entry) - cam->proc_entry->uid = 0; - - /* save camera state for later open (developers guide ch 3.5.3) */ - save_camera_state(cam); - - /* GotoLoPower */ - goto_low_power(cam); - - /* Update the camera ststus */ - do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - - /* cleanup internal state stuff */ - free_frames(cam->frame); - - /* close cpia */ - cam->ops->close(cam->lowlevel_data); - } - - if (--cam->open_count == 0) { - /* clean up capture-buffers */ - if (cam->raw_image) { - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image = NULL; - } - - if (cam->decompressed_frame.data) { - rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data = NULL; - } - - if (cam->frame_buf) - free_frame_buf(cam); - - if (!cam->ops) { - video_unregister_device(dev); - kfree(cam); - } - } - - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return; -} - -static long cpia_read(struct video_device *dev, char *buf, - unsigned long count, int noblock) -{ - struct cam_data *cam = dev->priv; - - /* make this _really_ smp and multithredi-safe */ - if (down_interruptible(&cam->busy_lock)) - return -EINTR; - - if (!buf) { - DBG("buf NULL\n"); - up(&cam->busy_lock); - return -EINVAL; - } - - if (!count) { - DBG("count 0\n"); - up(&cam->busy_lock); - return 0; - } - - if (!cam->ops) { - DBG("ops NULL\n"); - up(&cam->busy_lock); - return -ENODEV; - } - - /* upload frame */ - cam->decompressed_frame.state = FRAME_READY; - cam->mmap_kludge=0; - fetch_frame(cam); - if (cam->decompressed_frame.state != FRAME_DONE) { - DBG("upload failed %d/%d\n", cam->decompressed_frame.count, - cam->decompressed_frame.state); - up(&cam->busy_lock); - return -EIO; - } - cam->decompressed_frame.state = FRAME_UNUSED; - - /* copy data to user space */ - if (cam->decompressed_frame.count > count) { - DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count, - count); - up(&cam->busy_lock); - return -EFAULT; - } - if (copy_to_user(buf, cam->decompressed_frame.data, - cam->decompressed_frame.count)) { - DBG("copy_to_user failed\n"); - up(&cam->busy_lock); - return -EFAULT; - } - - up(&cam->busy_lock); - return cam->decompressed_frame.count; -} - -static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg) -{ - struct cam_data *cam = dev->priv; - int retval = 0; - - if (!cam || !cam->ops) - return -ENODEV; - - /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) - return -EINTR; - - //DBG("cpia_ioctl: %u\n", ioctlnr); - - switch (ioctlnr) { - /* query capabilites */ - case VIDIOCGCAP: - { - struct video_capability b; - - DBG("VIDIOCGCAP\n"); - strcpy(b.name, "CPiA Camera"); - b.type = VID_TYPE_CAPTURE; - b.channels = 1; - b.audios = 0; - b.maxwidth = 352; /* VIDEOSIZE_CIF */ - b.maxheight = 288; - b.minwidth = 48; /* VIDEOSIZE_48_48 */ - b.minheight = 48; - - if (copy_to_user(arg, &b, sizeof(b))) - retval = -EFAULT; - - break; - } - - /* get/set video source - we are a camera and nothing else */ - case VIDIOCGCHAN: - { - struct video_channel v; - - DBG("VIDIOCGCHAN\n"); - if (copy_from_user(&v, arg, sizeof(v))) { - retval = -EFAULT; - break; - } - if (v.channel != 0) { - retval = -EINVAL; - break; - } - - v.channel = 0; - strcpy(v.name, "Camera"); - v.tuners = 0; - v.flags = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = 0; - - if (copy_to_user(arg, &v, sizeof(v))) - retval = -EFAULT; - break; - } - - case VIDIOCSCHAN: - { - int v; - - DBG("VIDIOCSCHAN\n"); - if (copy_from_user(&v, arg, sizeof(v))) - retval = -EFAULT; - - if (retval == 0 && v != 0) - retval = -EINVAL; - - break; - } - - /* image properties */ - case VIDIOCGPICT: - DBG("VIDIOCGPICT\n"); - if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture))) - retval = -EFAULT; - break; - - case VIDIOCSPICT: - { - struct video_picture vp; - - DBG("VIDIOCSPICT\n"); - - /* copy_from_user */ - if (copy_from_user(&vp, arg, sizeof(vp))) { - retval = -EFAULT; - break; - } - - /* check validity */ - DBG("palette: %d\n", vp.palette); - DBG("depth: %d\n", vp.depth); - if (!valid_mode(vp.palette, vp.depth)) { - retval = -EINVAL; - break; - } - - down(&cam->param_lock); - /* brightness, colour, contrast need no check 0-65535 */ - memcpy( &cam->vp, &vp, sizeof(vp) ); - /* update cam->params.colourParams */ - cam->params.colourParams.brightness = vp.brightness*100/65535; - cam->params.colourParams.contrast = vp.contrast*100/65535; - cam->params.colourParams.saturation = vp.colour*100/65535; - /* contrast is in steps of 8, so round */ - cam->params.colourParams.contrast = - ((cam->params.colourParams.contrast + 3) / 8) * 8; - if (cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2 && - cam->params.colourParams.contrast > 80) { - /* 1-02 firmware limits contrast to 80 */ - cam->params.colourParams.contrast = 80; - } - - /* queue command to update camera */ - cam->cmd_queue |= COMMAND_SETCOLOURPARAMS; - up(&cam->param_lock); - DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n", - vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour, - vp.contrast); - break; - } - - /* get/set capture window */ - case VIDIOCGWIN: - DBG("VIDIOCGWIN\n"); - - if (copy_to_user(arg, &cam->vw, sizeof(struct video_window))) - retval = -EFAULT; - break; - - case VIDIOCSWIN: - { - /* copy_from_user, check validity, copy to internal structure */ - struct video_window vw; - DBG("VIDIOCSWIN\n"); - if (copy_from_user(&vw, arg, sizeof(vw))) { - retval = -EFAULT; - break; - } - - if (vw.clipcount != 0) { /* clipping not supported */ - retval = -EINVAL; - break; - } - if (vw.clips != NULL) { /* clipping not supported */ - retval = -EINVAL; - break; - } - - /* we set the video window to something smaller or equal to what - * is requested by the user??? - */ - down(&cam->param_lock); - if (vw.width != cam->vw.width || vw.height != cam->vw.height) { - int video_size = match_videosize(vw.width, vw.height); - - if (video_size < 0) { - retval = -EINVAL; - up(&cam->param_lock); - break; - } - cam->video_size = video_size; - set_vw_size(cam); - DBG("%d / %d\n", cam->vw.width, cam->vw.height); - cam->cmd_queue |= COMMAND_SETFORMAT; - } - - // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw)); - up(&cam->param_lock); - - /* setformat ignored by camera during streaming, - * so stop/dispatch/start */ - if (cam->cmd_queue & COMMAND_SETFORMAT) { - DBG("\n"); - dispatch_commands(cam); - } - DBG("%d/%d:%d\n", cam->video_size, - cam->vw.width, cam->vw.height); - break; - } - - /* mmap interface */ - case VIDIOCGMBUF: - { - struct video_mbuf vm; - int i; - - DBG("VIDIOCGMBUF\n"); - memset(&vm, 0, sizeof(vm)); - vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM; - vm.frames = FRAME_NUM; - for (i = 0; i < FRAME_NUM; i++) - vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i; - - if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - retval = -EFAULT; - - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - int video_size; - - if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) { - retval = -EFAULT; - break; - } -#if 1 - DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame, - vm.width, vm.height); -#endif - if (vm.frame<0||vm.frame>FRAME_NUM) { - retval = -EINVAL; - break; - } - - /* set video format */ - cam->vp.palette = vm.format; - switch(vm.format) { - case VIDEO_PALETTE_GREY: - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_UYVY: - cam->vp.depth = 16; - break; - case VIDEO_PALETTE_RGB24: - cam->vp.depth = 24; - break; - case VIDEO_PALETTE_RGB32: - cam->vp.depth = 32; - break; - default: - retval = -EINVAL; - break; - } - if (retval) - break; - - /* set video size */ - video_size = match_videosize(vm.width, vm.height); - if (cam->video_size < 0) { - retval = -EINVAL; - break; - } - if (video_size != cam->video_size) { - cam->video_size = video_size; - set_vw_size(cam); - cam->cmd_queue |= COMMAND_SETFORMAT; - dispatch_commands(cam); - } -#if 0 - DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size, - cam->vw.width, cam->vw.height); -#endif - /* according to v4l-spec we must start streaming here */ - cam->mmap_kludge = 1; - retval = capture_frame(cam, &vm); - - break; - } - - case VIDIOCSYNC: - { - int frame; - - if (copy_from_user((void *)&frame, arg, sizeof(int))) { - retval = -EFAULT; - break; - } - //DBG("VIDIOCSYNC: %d\n", frame); - - if (frame<0 || frame >= FRAME_NUM) { - retval = -EINVAL; - break; - } - - switch (cam->frame[frame].state) { - case FRAME_UNUSED: - case FRAME_READY: - case FRAME_GRABBING: - DBG("sync to unused frame %d\n", frame); - retval = -EINVAL; - break; - - case FRAME_DONE: - cam->frame[frame].state = FRAME_UNUSED; - //DBG("VIDIOCSYNC: %d synced\n", frame); - break; - } - if (retval == -EINTR) { - /* FIXME - xawtv does not handle this nice */ - retval = 0; - } - break; - } - - /* pointless to implement overlay with this camera */ - case VIDIOCCAPTURE: - retval = -EINVAL; - break; - case VIDIOCGFBUF: - retval = -EINVAL; - break; - case VIDIOCSFBUF: - retval = -EINVAL; - break; - case VIDIOCKEY: - retval = -EINVAL; - break; - - /* tuner interface - we have none */ - case VIDIOCGTUNER: - retval = -EINVAL; - break; - case VIDIOCSTUNER: - retval = -EINVAL; - break; - case VIDIOCGFREQ: - retval = -EINVAL; - break; - case VIDIOCSFREQ: - retval = -EINVAL; - break; - - /* audio interface - we have none */ - case VIDIOCGAUDIO: - retval = -EINVAL; - break; - case VIDIOCSAUDIO: - retval = -EINVAL; - break; - default: - retval = -ENOIOCTLCMD; - break; - } - - up(&cam->param_lock); - up(&cam->busy_lock); - return retval; -} - -/* FIXME */ -static int cpia_mmap(struct video_device *dev, const char *adr, - unsigned long size) -{ - unsigned long start = (unsigned long)adr; - unsigned long page, pos; - struct cam_data *cam = dev->priv; - int retval; - - if (!cam || !cam->ops) - return -ENODEV; - - DBG("cpia_mmap: %ld\n", size); - - if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE) - return -EINVAL; - - if (!cam || !cam->ops) - return -ENODEV; - - /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) - return -EINTR; - - if (!cam->frame_buf) { /* we do lazy allocation */ - if ((retval = allocate_frame_buf(cam))) { - up(&cam->busy_lock); - return retval; - } - } - - pos = (unsigned long)(cam->frame_buf); - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&cam->busy_lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - DBG("cpia_mmap: %ld\n", size); - up(&cam->busy_lock); - - return 0; -} - -int cpia_video_init(struct video_device *vdev) -{ -#ifdef CONFIG_PROC_FS - create_proc_cpia_cam(vdev->priv); -#endif - return 0; -} - -static struct video_device cpia_template = { - "CPiA Camera", - VID_TYPE_CAPTURE, - VID_HARDWARE_CPIA, /* FIXME */ - cpia_open, /* open */ - cpia_close, /* close */ - cpia_read, /* read */ - NULL, /* no write */ - NULL, /* no poll */ - cpia_ioctl, /* ioctl */ - cpia_mmap, /* mmap */ - cpia_video_init, /* initialize */ - NULL, /* priv */ - 0, /* busy */ - -1 /* minor - unset */ -}; - -/* initialise cam_data structure */ -static void reset_camera_struct(struct cam_data *cam) -{ - /* The following parameter values are the defaults from - * "Software Developer's Guide for CPiA Cameras". Any changes - * to the defaults are noted in comments. */ - cam->params.colourParams.brightness = 50; - cam->params.colourParams.contrast = 48; - cam->params.colourParams.saturation = 50; - cam->params.exposure.gainMode = 2; - cam->params.exposure.expMode = 2; /* AEC */ - cam->params.exposure.compMode = 1; - cam->params.exposure.centreWeight = 1; - cam->params.exposure.gain = 0; - cam->params.exposure.fineExp = 0; - cam->params.exposure.coarseExpLo = 185; - cam->params.exposure.coarseExpHi = 0; - cam->params.exposure.redComp = 220; - cam->params.exposure.green1Comp = 214; - cam->params.exposure.green2Comp = 214; - cam->params.exposure.blueComp = 230; - cam->params.colourBalance.balanceModeIsAuto = 1; - cam->params.colourBalance.redGain = 32; - cam->params.colourBalance.greenGain = 6; - cam->params.colourBalance.blueGain = 92; - cam->params.apcor.gain1 = 0x1c; - cam->params.apcor.gain2 = 0x1a; - cam->params.apcor.gain4 = 0x2d; - cam->params.apcor.gain8 = 0x2a; - cam->params.flickerControl.flickerMode = 0; - cam->params.flickerControl.coarseJump = - flicker_jumps[cam->mainsFreq] - [cam->params.sensorFps.baserate] - [cam->params.sensorFps.divisor]; - cam->params.vlOffset.gain1 = 24; - cam->params.vlOffset.gain2 = 28; - cam->params.vlOffset.gain4 = 30; - cam->params.vlOffset.gain8 = 30; - cam->params.compressionParams.hysteresis = 3; - cam->params.compressionParams.threshMax = 11; - cam->params.compressionParams.smallStep = 1; - cam->params.compressionParams.largeStep = 3; - cam->params.compressionParams.decimationHysteresis = 2; - cam->params.compressionParams.frDiffStepThresh = 5; - cam->params.compressionParams.qDiffStepThresh = 3; - cam->params.compressionParams.decimationThreshMod = 2; - /* End of default values from Software Developer's Guide */ - - cam->transfer_rate = 0; - - /* Set Sensor FPS to 15fps. This seems better than 30fps - * for indoor lighting. */ - cam->params.sensorFps.divisor = 1; - cam->params.sensorFps.baserate = 1; - - cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */ - cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */ - - cam->params.format.subSample = SUBSAMPLE_422; - cam->params.format.yuvOrder = YUVORDER_YUYV; - - cam->params.compression.mode = CPIA_COMPRESSION_AUTO; - cam->params.compressionTarget.frTargeting = - CPIA_COMPRESSION_TARGET_QUALITY; - cam->params.compressionTarget.targetFR = 7; /* FIXME? */ - cam->params.compressionTarget.targetQ = 10; /* FIXME? */ - - cam->video_size = VIDEOSIZE_CIF; - - cam->vp.colour = 32768; /* 50% */ - cam->vp.hue = 32768; /* 50% */ - cam->vp.brightness = 32768; /* 50% */ - cam->vp.contrast = 32768; /* 50% */ - cam->vp.whiteness = 0; /* not used -> grayscale only */ - cam->vp.depth = 0; /* FIXME: to be set by user? */ - cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */ - - cam->vw.x = 0; - cam->vw.y = 0; - set_vw_size(cam); - cam->vw.chromakey = 0; - /* PP NOTE: my extension to use vw.flags for this, bear it! */ - cam->vw.flags = 0; - cam->vw.clipcount = 0; - cam->vw.clips = NULL; - - cam->cmd_queue = COMMAND_NONE; - cam->first_frame = 0; - - return; -} - -/* initialize cam_data structure */ -static void init_camera_struct(struct cam_data *cam, - struct cpia_camera_ops *ops ) -{ - int i; - - /* Default everything to 0 */ - memset(cam, 0, sizeof(struct cam_data)); - - cam->ops = ops; - init_MUTEX(&cam->param_lock); - init_MUTEX(&cam->busy_lock); - - reset_camera_struct(cam); - - cam->proc_entry = NULL; - - memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template)); - cam->vdev.priv = cam; - - cam->curframe = 0; - for (i = 0; i < FRAME_NUM; i++) { - cam->frame[i].width = 0; - cam->frame[i].height = 0; - cam->frame[i].state = FRAME_UNUSED; - cam->frame[i].data = NULL; - } - cam->decompressed_frame.width = 0; - cam->decompressed_frame.height = 0; - cam->decompressed_frame.state = FRAME_UNUSED; - cam->decompressed_frame.data = NULL; -} - -struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel) -{ - struct cam_data *camera; - - /* Need a lock when adding/removing cameras. This doesn't happen - * often and doesn't take very long, so grabbing the kernel lock - * should be OK. */ - - if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) { - unlock_kernel(); - return NULL; - } - - init_camera_struct( camera, ops ); - camera->lowlevel_data = lowlevel; - - /* register v4l device */ - if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) { - kfree(camera); - unlock_kernel(); - printk(KERN_DEBUG "video_register_device failed\n"); - return NULL; - } - - /* get version information from camera: open/reset/close */ - - /* open cpia */ - if (camera->ops->open(camera->lowlevel_data)) - return camera; - - /* reset the camera */ - if (reset_camera(camera) != 0) { - camera->ops->close(camera->lowlevel_data); - return camera; - } - - /* close cpia */ - camera->ops->close(camera->lowlevel_data); - -/* Eh? Feeling happy? - jerdfelt */ -/* - camera->ops->open(camera->lowlevel_data); - camera->ops->close(camera->lowlevel_data); -*/ - - printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n", - camera->params.version.firmwareVersion, - camera->params.version.firmwareRevision, - camera->params.version.vcVersion, - camera->params.version.vcRevision); - printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n", - camera->params.pnpID.vendor, - camera->params.pnpID.product, - camera->params.pnpID.deviceRevision); - printk(KERN_INFO " VP-Version: %d.%d %04x\n", - camera->params.vpVersion.vpVersion, - camera->params.vpVersion.vpRevision, - camera->params.vpVersion.cameraHeadID); - - return camera; -} - -void cpia_unregister_camera(struct cam_data *cam) -{ - if (!cam->open_count) { - DBG("unregistering video\n"); - video_unregister_device(&cam->vdev); - } else { - LOG("/dev/video%d removed while open, " - "deferring video_unregister_device\n", cam->vdev.minor); - DBG("camera open -- setting ops to NULL\n"); - cam->ops = NULL; - } - -#ifdef CONFIG_PROC_FS - DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor); - destroy_proc_cpia_cam(cam); -#endif - if (!cam->open_count) { - DBG("freeing camera\n"); - kfree(cam); - } -} - -/**************************************************************************** - * - * Module routines - * - ***************************************************************************/ - -#ifdef MODULE -int init_module(void) -{ - printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, - CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); -#ifdef CONFIG_PROC_FS - proc_cpia_create(); -#endif -#ifdef CONFIG_KMOD -#ifdef CONFIG_VIDEO_CPIA_PP_MODULE - request_module("cpia_pp"); -#endif -#ifdef CONFIG_VIDEO_CPIA_USB_MODULE - request_module("cpia_usb"); -#endif -#endif -return 0; -} - -void cleanup_module(void) -{ -#ifdef CONFIG_PROC_FS - proc_cpia_destroy(); -#endif -} - -#else - -int cpia_init(struct video_init *unused) -{ - printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, - CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); -#ifdef CONFIG_PROC_FS - proc_cpia_create(); -#endif - -#ifdef CONFIG_VIDEO_CPIA_PP - cpia_pp_init(); -#endif -#ifdef CONFIG_KMOD -#ifdef CONFIG_VIDEO_CPIA_PP_MODULE - request_module("cpia_pp"); -#endif - -#ifdef CONFIG_VIDEO_CPIA_USB_MODULE - request_module("cpia_usb"); -#endif -#endif /* CONFIG_KMOD */ -#ifdef CONFIG_VIDEO_CPIA_USB - cpia_usb_init(); -#endif - return 0; -} - -/* Exported symbols for modules. */ - -EXPORT_SYMBOL(cpia_register_camera); -EXPORT_SYMBOL(cpia_unregister_camera); - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/cpia.h linux/drivers/char/cpia.h --- v2.4.0-test6/linux/drivers/char/cpia.h Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/cpia.h Wed Dec 31 16:00:00 1969 @@ -1,421 +0,0 @@ -#ifndef cpia_h -#define cpia_h - -/* - * CPiA Parallel Port Video4Linux driver - * - * Supports CPiA based parallel port Video Camera's. - * - * (C) Copyright 1999 Bas Huisman, - * Peter Pregler, - * Scott J. Bertin, - * VLSI Vision Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This 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. - */ - -#define CPIA_MAJ_VER 0 -#define CPIA_MIN_VER 7 -#define CPIA_PATCH_VER 4 - -#define CPIA_PP_MAJ_VER 0 -#define CPIA_PP_MIN_VER 7 -#define CPIA_PP_PATCH_VER 4 - -#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */ -#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */ - -#ifdef __KERNEL__ - -#include -#include -#include - -struct cpia_camera_ops -{ - /* open sets privdata to point to structure for this camera. - * Returns negative value on error, otherwise 0. - */ - int (*open)(void *privdata); - - /* Registers callback function cb to be called with cbdata - * when an image is ready. If cb is NULL, only single image grabs - * should be used. cb should immediately call streamRead to read - * the data or data may be lost. Returns negative value on error, - * otherwise 0. - */ - int (*registerCallback)(void *privdata, void (*cb)(void *cbdata), - void *cbdata); - - /* transferCmd sends commands to the camera. command MUST point to - * an 8 byte buffer in kernel space. data can be NULL if no extra - * data is needed. The size of the data is given by the last 2 - * bytes of comand. data must also point to memory in kernel space. - * Returns negative value on error, otherwise 0. - */ - int (*transferCmd)(void *privdata, u8 *command, u8 *data); - - /* streamStart initiates stream capture mode. - * Returns negative value on error, otherwise 0. - */ - int (*streamStart)(void *privdata); - - /* streamStop terminates stream capture mode. - * Returns negative value on error, otherwise 0. - */ - int (*streamStop)(void *privdata); - - /* streamRead reads a frame from the camera. buffer points to a - * buffer large enough to hold a complete frame in kernel space. - * noblock indicates if this should be a non blocking read. - * Returns the number of bytes read, or negative value on error. - */ - int (*streamRead)(void *privdata, u8 *buffer, int noblock); - - /* close disables the device until open() is called again. - * Returns negative value on error, otherwise 0. - */ - int (*close)(void *privdata); - - /* If wait_for_stream_ready is non-zero, wait until the streamState - * is STREAM_READY before calling streamRead. - */ - int wait_for_stream_ready; -}; - -struct cpia_frame { - u8 *data; - int count; - int width; - int height; - volatile int state; -}; - -struct cam_params { - struct { - u8 firmwareVersion; - u8 firmwareRevision; - u8 vcVersion; - u8 vcRevision; - } version; - struct { - u16 vendor; - u16 product; - u16 deviceRevision; - } pnpID; - struct { - u8 vpVersion; - u8 vpRevision; - u16 cameraHeadID; - } vpVersion; - struct { - u8 systemState; - u8 grabState; - u8 streamState; - u8 fatalError; - u8 cmdError; - u8 debugFlags; - u8 vpStatus; - u8 errorCode; - } status; - struct { - u8 brightness; - u8 contrast; - u8 saturation; - } colourParams; - struct { - u8 gainMode; - u8 expMode; - u8 compMode; - u8 centreWeight; - u8 gain; - u8 fineExp; - u8 coarseExpLo; - u8 coarseExpHi; - u8 redComp; - u8 green1Comp; - u8 green2Comp; - u8 blueComp; - } exposure; - struct { - u8 balanceModeIsAuto; - u8 redGain; - u8 greenGain; - u8 blueGain; - } colourBalance; - struct { - u8 divisor; - u8 baserate; - } sensorFps; - struct { - u8 gain1; - u8 gain2; - u8 gain4; - u8 gain8; - } apcor; - struct { - u8 flickerMode; - u8 coarseJump; - u8 allowableOverExposure; - } flickerControl; - struct { - u8 gain1; - u8 gain2; - u8 gain4; - u8 gain8; - } vlOffset; - struct { - u8 mode; - u8 decimation; - } compression; - struct { - u8 frTargeting; - u8 targetFR; - u8 targetQ; - } compressionTarget; - struct { - u8 yThreshold; - u8 uvThreshold; - } yuvThreshold; - struct { - u8 hysteresis; - u8 threshMax; - u8 smallStep; - u8 largeStep; - u8 decimationHysteresis; - u8 frDiffStepThresh; - u8 qDiffStepThresh; - u8 decimationThreshMod; - } compressionParams; - struct { - u8 videoSize; /* CIF/QCIF */ - u8 subSample; - u8 yuvOrder; - } format; - struct { - u8 colStart; /* skip first 8*colStart pixels */ - u8 colEnd; /* finish at 8*colEnd pixels */ - u8 rowStart; /* skip first 4*rowStart lines */ - u8 rowEnd; /* finish at 4*rowEnd lines */ - } roi; - u8 ecpTiming; - u8 streamStartLine; -}; - -enum v4l_camstates { - CPIA_V4L_IDLE = 0, - CPIA_V4L_ERROR, - CPIA_V4L_COMMAND, - CPIA_V4L_GRABBING, - CPIA_V4L_STREAMING, - CPIA_V4L_STREAMING_PAUSED, -}; - -#define FRAME_NUM 2 /* double buffering for now */ - -struct cam_data { - struct cam_data **previous; - struct cam_data *next; - - struct semaphore busy_lock; /* guard against SMP multithreading */ - struct cpia_camera_ops *ops; /* lowlevel driver operations */ - void *lowlevel_data; /* private data for lowlevel driver */ - u8 *raw_image; /* buffer for raw image data */ - struct cpia_frame decompressed_frame; - /* buffer to hold decompressed frame */ - int image_size; /* sizeof last decompressed image */ - int open_count; /* # of process that have camera open */ - - /* camera status */ - int fps; /* actual fps reported by the camera */ - int transfer_rate; /* transfer rate from camera in kB/s */ - u8 mainsFreq; /* for flicker control */ - - /* proc interface */ - struct semaphore param_lock; /* params lock for this camera */ - struct cam_params params; /* camera settings */ - struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */ - - /* v4l */ - int video_size; /* VIDEO_SIZE_ */ - volatile enum v4l_camstates camstate; /* v4l layer status */ - struct video_device vdev; /* v4l videodev */ - struct video_picture vp; /* v4l camera settings */ - struct video_window vw; /* v4l capture area */ - - /* mmap interface */ - int curframe; /* the current frame to grab into */ - u8 *frame_buf; /* frame buffer data */ - struct cpia_frame frame[FRAME_NUM]; - /* FRAME_NUM-buffering, so we need a array */ - - int first_frame; - int mmap_kludge; /* 'wrong' byte order for mmap */ - volatile u32 cmd_queue; /* queued commands */ -}; - -/* cpia_register_camera is called by low level driver for each camera. - * A unique camera number is returned, or a negative value on error */ -struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel); - -/* cpia_unregister_camera is called by low level driver when a camera - * is removed. This must not fail. */ -void cpia_unregister_camera(struct cam_data *cam); - -/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI + - * one byte 16bit DMA alignment - */ -#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5) - -/* constant value's */ -#define MAGIC_0 0x19 -#define MAGIC_1 0x68 -#define DATA_IN 0xC0 -#define DATA_OUT 0x40 -#define VIDEOSIZE_QCIF 0 /* 176x144 */ -#define VIDEOSIZE_CIF 1 /* 352x288 */ -#define VIDEOSIZE_SIF 2 /* 320x240 */ -#define VIDEOSIZE_QSIF 3 /* 160x120 */ -#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */ -#define VIDEOSIZE_64_48 5 -#define VIDEOSIZE_128_96 6 -#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF -#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF -#define VIDEOSIZE_192_144 7 -#define VIDEOSIZE_224_168 8 -#define VIDEOSIZE_256_192 9 -#define VIDEOSIZE_288_216 10 -#define VIDEOSIZE_320_240 VIDEOSIZE_SIF -#define VIDEOSIZE_352_288 VIDEOSIZE_CIF -#define VIDEOSIZE_88_72 11 /* quarter CIF */ -#define SUBSAMPLE_420 0 -#define SUBSAMPLE_422 1 -#define YUVORDER_YUYV 0 -#define YUVORDER_UYVY 1 -#define NOT_COMPRESSED 0 -#define COMPRESSED 1 -#define NO_DECIMATION 0 -#define DECIMATION_ENAB 1 -#define EOI 0xff /* End Of Image */ -#define EOL 0xfd /* End Of Line */ -#define FRAME_HEADER_SIZE 64 - -/* Image grab modes */ -#define CPIA_GRAB_SINGLE 0 -#define CPIA_GRAB_CONTINUOUS 1 - -/* Compression parameters */ -#define CPIA_COMPRESSION_NONE 0 -#define CPIA_COMPRESSION_AUTO 1 -#define CPIA_COMPRESSION_MANUAL 2 -#define CPIA_COMPRESSION_TARGET_QUALITY 0 -#define CPIA_COMPRESSION_TARGET_FRAMERATE 1 - -/* Return offsets for GetCameraState */ -#define SYSTEMSTATE 0 -#define GRABSTATE 1 -#define STREAMSTATE 2 -#define FATALERROR 3 -#define CMDERROR 4 -#define DEBUGFLAGS 5 -#define VPSTATUS 6 -#define ERRORCODE 7 - -/* SystemState */ -#define UNINITIALISED_STATE 0 -#define PASS_THROUGH_STATE 1 -#define LO_POWER_STATE 2 -#define HI_POWER_STATE 3 -#define WARM_BOOT_STATE 4 - -/* GrabState */ -#define GRAB_IDLE 0 -#define GRAB_ACTIVE 1 -#define GRAB_DONE 2 - -/* StreamState */ -#define STREAM_NOT_READY 0 -#define STREAM_READY 1 -#define STREAM_OPEN 2 -#define STREAM_PAUSED 3 -#define STREAM_FINISHED 4 - -/* Fatal Error, CmdError, and DebugFlags */ -#define CPIA_FLAG 1 -#define SYSTEM_FLAG 2 -#define INT_CTRL_FLAG 4 -#define PROCESS_FLAG 8 -#define COM_FLAG 16 -#define VP_CTRL_FLAG 32 -#define CAPTURE_FLAG 64 -#define DEBUG_FLAG 128 - -/* VPStatus */ -#define VP_STATE_OK 0x00 - -#define VP_STATE_FAILED_VIDEOINIT 0x01 -#define VP_STATE_FAILED_AECACBINIT 0x02 -#define VP_STATE_AEC_MAX 0x04 -#define VP_STATE_ACB_BMAX 0x08 - -#define VP_STATE_ACB_RMIN 0x10 -#define VP_STATE_ACB_GMIN 0x20 -#define VP_STATE_ACB_RMAX 0x40 -#define VP_STATE_ACB_GMAX 0x80 - -/* ErrorCode */ -#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */ - -#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args) -#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args) - -#ifdef _CPIA_DEBUG_ -#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args) -#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args) -#else -#define DBG(fmn,args...) do {} while(0) -#endif - -#define DEB_BYTE(p)\ - DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\ - (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\ - (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0); - -#define ADD_TO_LIST(l, drv) \ - {\ - lock_kernel();\ - (drv)->next = l;\ - (drv)->previous = &(l);\ - (l) = drv;\ - unlock_kernel();\ - } while(0) - -#define REMOVE_FROM_LIST(drv) \ - {\ - if ((drv)->previous != NULL) {\ - lock_kernel();\ - if ((drv)->next != NULL)\ - (drv)->next->previous = (drv)->previous;\ - *((drv)->previous) = (drv)->next;\ - (drv)->previous = NULL;\ - (drv)->next = NULL;\ - unlock_kernel();\ - }\ - } while (0) - - -#endif /* __KERNEL__ */ - -#endif /* cpia_h */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/cpia_pp.c linux/drivers/char/cpia_pp.c --- v2.4.0-test6/linux/drivers/char/cpia_pp.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/cpia_pp.c Wed Dec 31 16:00:00 1969 @@ -1,745 +0,0 @@ -/* - * cpia_pp CPiA Parallel Port driver - * - * Supports CPiA based parallel port Video Camera's. - * - * (C) Copyright 1999 Bas Huisman - * (C) Copyright 1999-2000 Scott J. Bertin , - * (C) Copyright 1999-2000 Peter Pregler - * - * 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. - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_KMOD -#include -#endif - -/* #define _CPIA_DEBUG_ define for verbose debug output */ -#include "cpia.h" - -static int cpia_pp_open(void *privdata); -static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata), - void *cbdata); -static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data); -static int cpia_pp_streamStart(void *privdata); -static int cpia_pp_streamStop(void *privdata); -static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock); -static int cpia_pp_close(void *privdata); - -#define ABOUT "Parallel port driver for Vision CPiA based cameras" - -/* IEEE 1284 Compatiblity Mode signal names */ -#define nStrobe PARPORT_CONTROL_STROBE /* inverted */ -#define nAutoFd PARPORT_CONTROL_AUTOFD /* inverted */ -#define nInit PARPORT_CONTROL_INIT -#define nSelectIn PARPORT_CONTROL_SELECT -#define IntrEnable PARPORT_CONTROL_INTEN /* normally zero for no IRQ */ -#define DirBit PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse */ - -#define nFault PARPORT_STATUS_ERROR -#define Select PARPORT_STATUS_SELECT -#define PError PARPORT_STATUS_PAPEROUT -#define nAck PARPORT_STATUS_ACK -#define Busy PARPORT_STATUS_BUSY /* inverted */ - -/* some more */ -#define HostClk nStrobe -#define HostAck nAutoFd -#define nReverseRequest nInit -#define Active_1284 nSelectIn -#define nPeriphRequest nFault -#define XFlag Select -#define nAckReverse PError -#define PeriphClk nAck -#define PeriphAck Busy - -/* these can be used to correct for the inversion on some bits */ -#define STATUS_INVERSION_MASK (Busy) -#define CONTROL_INVERSION_MASK (nStrobe|nAutoFd|nSelectIn) - -#define ECR_empty 0x01 -#define ECR_full 0x02 -#define ECR_serviceIntr 0x04 -#define ECR_dmaEn 0x08 -#define ECR_nErrIntrEn 0x10 - -#define ECR_mode_mask 0xE0 -#define ECR_SPP_mode 0x00 -#define ECR_PS2_mode 0x20 -#define ECR_FIFO_mode 0x40 -#define ECR_ECP_mode 0x60 - -#define ECP_FIFO_SIZE 16 -#define DMA_BUFFER_SIZE PAGE_SIZE - /* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */ -#define PARPORT_CHUNK_SIZE PAGE_SIZE/* >=2.3.x */ - /* we read this many bytes at once */ - -#define GetECRMasked(port,mask) (parport_read_econtrol(port) & (mask)) -#define GetStatus(port) ((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8)) -#define SetStatus(port,val) parport_write_status(port,(val)^STATUS_INVERSION_MASK) -#define GetControl(port) ((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f)) -#define SetControl(port,val) parport_write_control(port,(val)^CONTROL_INVERSION_MASK) - -#define GetStatusMasked(port,mask) (GetStatus(port) & (mask)) -#define GetControlMasked(port,mask) (GetControl(port) & (mask)) -#define SetControlMasked(port,mask) SetControl(port,GetControl(port) | (mask)); -#define ClearControlMasked(port,mask) SetControl(port,GetControl(port)&~(mask)); -#define FrobControlBit(port,mask,value) SetControl(port,(GetControl(port)&~(mask))|((value)&(mask))); - -#define PACKET_LENGTH 8 - -/* Magic numbers for defining port-device mappings */ -#define PPCPIA_PARPORT_UNSPEC -4 -#define PPCPIA_PARPORT_AUTO -3 -#define PPCPIA_PARPORT_OFF -2 -#define PPCPIA_PARPORT_NONE -1 - -#ifdef MODULE -static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; -static char *parport[PARPORT_MAX] = {NULL,}; - -MODULE_AUTHOR("B. Huisman & Peter Pregler "); -MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras"); -MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s"); -MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); -#else -static int parport_nr[PARPORT_MAX] __initdata = - {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; -static int parport_ptr = 0; -#endif - -struct pp_cam_entry { - struct pardevice *pdev; - struct parport *port; - struct tq_struct cb_task; - int open_count; - wait_queue_head_t wq_stream; - /* image state flags */ - int image_ready; /* we got an interrupt */ - int image_complete; /* we have seen 4 EOI */ - - int streaming; /* we are in streaming mode */ - int stream_irq; -}; - -static struct cpia_camera_ops cpia_pp_ops = -{ - cpia_pp_open, - cpia_pp_registerCallback, - cpia_pp_transferCmd, - cpia_pp_streamStart, - cpia_pp_streamStop, - cpia_pp_streamRead, - cpia_pp_close, - 1 -}; - -static struct cam_data *cam_list; - -#ifdef _CPIA_DEBUG_ -#define DEB_PORT(port) { \ -u8 controll = GetControl(port); \ -u8 statusss = GetStatus(port); \ -DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir %c\n",\ -((controll & nSelectIn) ? 'U' : 'D'), \ -((statusss & PError) ? 'U' : 'D'), \ -((controll & nAutoFd) ? 'U' : 'D'), \ -((controll & nStrobe) ? 'U' : 'D'), \ -((statusss & nAck) ? 'U' : 'D'), \ -((statusss & Busy) ? 'U' : 'D'), \ -((statusss & nFault) ? 'U' : 'D'), \ -((statusss & Select) ? 'U' : 'D'), \ -((controll & nInit) ? 'U' : 'D'), \ -((controll & DirBit) ? 'R' : 'F') \ -); } -#else -#define DEB_PORT(port) {} -#endif - -#define WHILE_OUT_TIMEOUT (HZ/10) -#define DMA_TIMEOUT 10*HZ - -/* FIXME */ -static void cpia_parport_enable_irq( struct parport *port ) { - parport_enable_irq(port); - mdelay(10); - return; -} - -static void cpia_parport_disable_irq( struct parport *port ) { - parport_disable_irq(port); - mdelay(10); - return; -} - -/**************************************************************************** - * - * EndTransferMode - * - ***************************************************************************/ -static void EndTransferMode(struct pp_cam_entry *cam) -{ - parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); -} - -/**************************************************************************** - * - * ForwardSetup - * - ***************************************************************************/ -static int ForwardSetup(struct pp_cam_entry *cam) -{ - int retry; - - /* After some commands the camera needs extra time before - * it will respond again, so we try up to 3 times */ - for(retry=0; retry<3; ++retry) { - if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) { - break; - } - } - if(retry == 3) { - DBG("Unable to negotiate ECP mode\n"); - return -1; - } - return 0; -} - -/**************************************************************************** - * - * ReverseSetup - * - ***************************************************************************/ -static int ReverseSetup(struct pp_cam_entry *cam, int extensibility) -{ - int retry; - int mode = IEEE1284_MODE_ECP; - if(extensibility) mode = 8|3|IEEE1284_EXT_LINK; - - /* After some commands the camera needs extra time before - * it will respond again, so we try up to 3 times */ - for(retry=0; retry<3; ++retry) { - if(!parport_negotiate(cam->port, mode)) { - break; - } - } - if(retry == 3) { - if(extensibility) - DBG("Unable to negotiate extensibility mode\n"); - else - DBG("Unable to negotiate ECP mode\n"); - return -1; - } - if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP; - return 0; -} - -/**************************************************************************** - * - * WritePacket - * - ***************************************************************************/ -static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size) -{ - int retval=0; - int size_written; - - if (packet == NULL) { - return -EINVAL; - } - if (ForwardSetup(cam)) { - DBG("Write failed in setup\n"); - return -EIO; - } - size_written = parport_write(cam->port, packet, size); - if(size_written != size) { - DBG("Write failed, wrote %d/%d\n", size_written, size); - retval = -EIO; - } - EndTransferMode(cam); - return retval; -} - -/**************************************************************************** - * - * ReadPacket - * - ***************************************************************************/ -static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size) -{ - int retval=0; - if (packet == NULL) { - return -EINVAL; - } - if (ReverseSetup(cam, 0)) { - return -EIO; - } - if(parport_read(cam->port, packet, size) != size) { - retval = -EIO; - } - EndTransferMode(cam); - return retval; -} - -/**************************************************************************** - * - * cpia_pp_streamStart - * - ***************************************************************************/ -static int cpia_pp_streamStart(void *privdata) -{ - struct pp_cam_entry *cam = privdata; - DBG("\n"); - cam->streaming=1; - cam->image_ready=0; - //if (ReverseSetup(cam,1)) return -EIO; - if(cam->stream_irq) cpia_parport_enable_irq(cam->port); - return 0; -} - -/**************************************************************************** - * - * cpia_pp_streamStop - * - ***************************************************************************/ -static int cpia_pp_streamStop(void *privdata) -{ - struct pp_cam_entry *cam = privdata; - - DBG("\n"); - cam->streaming=0; - cpia_parport_disable_irq(cam->port); - //EndTransferMode(cam); - - return 0; -} - -static int cpia_pp_read(struct parport *port, u8 *buffer, int len) -{ - int bytes_read, new_bytes; - for(bytes_read=0; bytes_readstreaming) DBG("%d / %d\n", cam->image_ready, noblock); - if( cam->stream_irq ) { - DBG("%d\n", cam->image_ready); - cam->image_ready--; - } - cam->image_complete=0; - if (0/*cam->streaming*/) { - if(!cam->image_ready) { - if(noblock) return -EWOULDBLOCK; - interruptible_sleep_on(&cam->wq_stream); - if( signal_pending(current) ) return -EINTR; - DBG("%d\n", cam->image_ready); - } - } else { - if (ReverseSetup(cam, 1)) { - DBG("unable to ReverseSetup\n"); - return -EIO; - } - } - endseen = 0; - block_size = PARPORT_CHUNK_SIZE; - while( !cam->image_complete ) { - if(current->need_resched) schedule(); - - new_bytes = cpia_pp_read(cam->port, buffer, block_size ); - if( new_bytes <= 0 ) { - break; - } - i=-1; - while(++iimage_complete=1; - break; - } - if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) { - block_size=CPIA_MAX_IMAGE_SIZE-read_bytes; - } - } - EndTransferMode(cam); - return cam->image_complete ? read_bytes : -EIO; -} - -/**************************************************************************** - * - * cpia_pp_transferCmd - * - ***************************************************************************/ -static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data) -{ - int err; - int retval=0; - int databytes; - struct pp_cam_entry *cam = privdata; - - if(cam == NULL) { - DBG("Internal driver error: cam is NULL\n"); - return -EINVAL; - } - if(command == NULL) { - DBG("Internal driver error: command is NULL\n"); - return -EINVAL; - } - databytes = (((int)command[7])<<8) | command[6]; - if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) { - DBG("Error writing command\n"); - return err; - } - if(command[0] == DATA_IN) { - u8 buffer[8]; - if(data == NULL) { - DBG("Internal driver error: data is NULL\n"); - return -EINVAL; - } - if((err = ReadPacket(cam, buffer, 8)) < 0) { - return err; - DBG("Error reading command result\n"); - } - memcpy(data, buffer, databytes); - } else if(command[0] == DATA_OUT) { - if(databytes > 0) { - if(data == NULL) { - DBG("Internal driver error: data is NULL\n"); - retval = -EINVAL; - } else { - if((err=WritePacket(cam, data, databytes)) < 0){ - DBG("Error writing command data\n"); - return err; - } - } - } - } else { - DBG("Unexpected first byte of command: %x\n", command[0]); - retval = -EINVAL; - } - return retval; -} - -/**************************************************************************** - * - * cpia_pp_open - * - ***************************************************************************/ -static int cpia_pp_open(void *privdata) -{ - struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata; - - if (cam == NULL) - return -EINVAL; - - if(cam->open_count == 0) { - if (parport_claim(cam->pdev)) { - DBG("failed to claim the port\n"); - return -EBUSY; - } - parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); - parport_data_forward(cam->port); - parport_write_control(cam->port, PARPORT_CONTROL_SELECT); - udelay(50); - parport_write_control(cam->port, - PARPORT_CONTROL_SELECT - | PARPORT_CONTROL_INIT); - } - - ++cam->open_count; - -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return 0; -} - -/**************************************************************************** - * - * cpia_pp_registerCallback - * - ***************************************************************************/ -static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata) -{ - struct pp_cam_entry *cam = privdata; - int retval = 0; - - if(cam->port->irq != PARPORT_IRQ_NONE) { - cam->cb_task.routine = cb; - cam->cb_task.data = cbdata; - } else { - retval = -1; - } - return retval; -} - -/**************************************************************************** - * - * cpia_pp_close - * - ***************************************************************************/ -static int cpia_pp_close(void *privdata) -{ - struct pp_cam_entry *cam = privdata; -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - if (--cam->open_count == 0) { - parport_release(cam->pdev); - } - return 0; -} - -/**************************************************************************** - * - * cpia_pp_register - * - ***************************************************************************/ -static int cpia_pp_register(struct parport *port) -{ - struct pardevice *pdev = NULL; - struct pp_cam_entry *cam; - struct cam_data *cpia; - - if (!(port->modes & PARPORT_MODE_ECP) && - !(port->modes & PARPORT_MODE_TRISTATE)) { - LOG("port is not ECP capable\n"); - return -ENXIO; - } - - cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL); - if (cam == NULL) { - LOG("failed to allocate camera structure\n"); - return -ENOMEM; - } - memset(cam,0,sizeof(struct pp_cam_entry)); - - pdev = parport_register_device(port, "cpia_pp", NULL, NULL, - NULL, 0, cam); - - if (!pdev) { - LOG("failed to parport_register_device\n"); - kfree(cam); - return -ENXIO; - } - - cam->pdev = pdev; - cam->port = port; - init_waitqueue_head(&cam->wq_stream); - - cam->streaming = 0; - cam->stream_irq = 0; - - if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) { - LOG("failed to cpia_register_camera\n"); - parport_unregister_device(pdev); - kfree(cam); - return -ENXIO; - } - ADD_TO_LIST(cam_list, cpia); - - return 0; -} - -static void cpia_pp_detach (struct parport *port) -{ - struct cam_data *cpia; - - for(cpia = cam_list; cpia != NULL; cpia = cpia->next) { - struct pp_cam_entry *cam = cpia->lowlevel_data; - if (cam && cam->port->number == port->number) { - REMOVE_FROM_LIST(cpia); - - cpia_unregister_camera(cpia); - - if(cam->open_count > 0) { - cpia_pp_close(cam); - } - - parport_unregister_device(cam->pdev); - - kfree(cam); - cpia->lowlevel_data = NULL; - break; - } - } -} - -static void cpia_pp_attach (struct parport *port) -{ - unsigned int i; - - switch (parport_nr[0]) - { - case PPCPIA_PARPORT_UNSPEC: - case PPCPIA_PARPORT_AUTO: - if (port->probe_info[0].class != PARPORT_CLASS_MEDIA || - port->probe_info[0].cmdset == NULL || - strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0) - return; - - cpia_pp_register(port); - - break; - - default: - for (i = 0; i < PARPORT_MAX; ++i) { - if (port->number == parport_nr[i]) { - cpia_pp_register(port); - break; - } - } - break; - } -} - -static struct parport_driver cpia_pp_driver = { - "cpia_pp", - cpia_pp_attach, - cpia_pp_detach, - NULL -}; - -int cpia_pp_init(void) -{ - printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, - CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); - - if(parport_nr[0] == PPCPIA_PARPORT_OFF) { - printk(" disabled\n"); - return 0; - } - - if (parport_register_driver (&cpia_pp_driver)) { - LOG ("unable to register with parport\n"); - return -EIO; - } - - return 0; -} - -#ifdef MODULE -int init_module(void) -{ - if (parport[0]) { - /* The user gave some parameters. Let's see what they were. */ - if (!strncmp(parport[0], "auto", 4)) { - parport_nr[0] = PPCPIA_PARPORT_AUTO; - } else { - int n; - for (n = 0; n < PARPORT_MAX && parport[n]; n++) { - if (!strncmp(parport[n], "none", 4)) { - parport_nr[n] = PPCPIA_PARPORT_NONE; - } else { - char *ep; - unsigned long r = simple_strtoul(parport[n], &ep, 0); - if (ep != parport[n]) { - parport_nr[n] = r; - } else { - LOG("bad port specifier `%s'\n", parport[n]); - return -ENODEV; - } - } - } - } - } -#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE) - if(parport_enumerate() && !parport_enumerate()->probe_info.model) { - request_module("parport_probe"); - } -#endif - return cpia_pp_init(); -} - -void cleanup_module(void) -{ - parport_unregister_driver (&cpia_pp_driver); - return; -} - -#else /* !MODULE */ - -static int __init cpia_pp_setup(char *str) -{ -#if 0 - /* Is this only a 2.2ism? -jerdfelt */ - if (!str) { - if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "cpia_pp=" or "cpia_pp=0" */ - parport_nr[0] = PPCPIA_PARPORT_OFF; - } - } else -#endif - if (!strncmp(str, "parport", 7)) { - int n = simple_strtoul(str + 7, NULL, 10); - if (parport_ptr < PARPORT_MAX) { - parport_nr[parport_ptr++] = n; - } else { - LOG("too many ports, %s ignored.\n", str); - } - } else if (!strcmp(str, "auto")) { - parport_nr[0] = PPCPIA_PARPORT_AUTO; - } else if (!strcmp(str, "none")) { - parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; - } - - return 0; -} - -__setup("cpia_pp=", cpia_pp_setup); - -#endif /* !MODULE */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/cpia_usb.c linux/drivers/char/cpia_usb.c --- v2.4.0-test6/linux/drivers/char/cpia_usb.c Tue Apr 11 15:09:16 2000 +++ linux/drivers/char/cpia_usb.c Wed Dec 31 16:00:00 1969 @@ -1,626 +0,0 @@ -/* - * cpia_usb CPiA USB driver - * - * Supports CPiA based parallel port Video Camera's. - * - * Copyright (C) 1999 Jochen Scharrlach - * Copyright (C) 1999, 2000 Johannes Erdfelt - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpia.h" - -#define USB_REQ_CPIA_GRAB_FRAME 0xC1 -#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2 -#define WAIT_FOR_NEXT_FRAME 0 -#define FORCE_FRAME_UPLOAD 1 - -#define FRAMES_PER_DESC 10 -#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */ -#define CPIA_NUMSBUF 2 -#define STREAM_BUF_SIZE (PAGE_SIZE * 4) -#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) - -struct cpia_sbuf { - char *data; - urb_t *urb; -}; - -#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100) -enum framebuf_status { - FRAME_EMPTY, - FRAME_READING, - FRAME_READY, - FRAME_ERROR, -}; - -struct framebuf { - int length; - enum framebuf_status status; - u8 data[FRAMEBUF_LEN]; - struct framebuf *next; -}; - -struct usb_cpia { - /* Device structure */ - struct usb_device *dev; - - unsigned char iface; - wait_queue_head_t wq_stream; - - int cursbuf; /* Current receiving sbuf */ - struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */ - - int streaming; - int open; - int present; - struct framebuf *buffers[3]; - struct framebuf *curbuff, *workbuff; -}; - -static int cpia_usb_open(void *privdata); -static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata), - void *cbdata); -static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data); -static int cpia_usb_streamStart(void *privdata); -static int cpia_usb_streamStop(void *privdata); -static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock); -static int cpia_usb_close(void *privdata); - -#define ABOUT "USB driver for Vision CPiA based cameras" - -static struct cpia_camera_ops cpia_usb_ops = { - cpia_usb_open, - cpia_usb_registerCallback, - cpia_usb_transferCmd, - cpia_usb_streamStart, - cpia_usb_streamStop, - cpia_usb_streamRead, - cpia_usb_close, - 0 -}; - -static struct cam_data *cam_list; - -static void cpia_usb_complete(struct urb *urb) -{ - int i; - char *cdata; - struct usb_cpia *ucpia; - - if (!urb || !urb->context) - return; - - ucpia = (struct usb_cpia *) urb->context; - - if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open) - return; - - if (ucpia->workbuff->status == FRAME_EMPTY) { - ucpia->workbuff->status = FRAME_READING; - ucpia->workbuff->length = 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - int n = urb->iso_frame_desc[i].actual_length; - int st = urb->iso_frame_desc[i].status; - - cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (st) - printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st); - - if (FRAMEBUF_LEN < ucpia->workbuff->length + n) { - printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n); - return; - } - - if (n) { - if ((ucpia->workbuff->length > 0) || - (0x19 == cdata[0] && 0x68 == cdata[1])) { - memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n); - ucpia->workbuff->length += n; - } else - DBG("Ignoring packet!\n"); - } else { - if (ucpia->workbuff->length > 4 && - 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] && - 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] && - 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] && - 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) { - ucpia->workbuff->status = FRAME_READY; - ucpia->curbuff = ucpia->workbuff; - ucpia->workbuff = ucpia->workbuff->next; - ucpia->workbuff->status = FRAME_EMPTY; - ucpia->workbuff->length = 0; - - if (waitqueue_active(&ucpia->wq_stream)) - wake_up_interruptible(&ucpia->wq_stream); - } - } - } -} - -static int cpia_usb_open(void *privdata) -{ - struct usb_cpia *ucpia = (struct usb_cpia *) privdata; - urb_t *urb; - int ret, retval = 0, fx, err; - - if (!ucpia) - return -EINVAL; - - ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!ucpia->sbuf[0].data) - return -EINVAL; - - ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!ucpia->sbuf[1].data) { - retval = -EINVAL; - goto error_0; - } - - ret = usb_set_interface(ucpia->dev, ucpia->iface, 3); - if (ret < 0) { - printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret); - retval = -EBUSY; - goto error_all; - } - - ucpia->buffers[0]->status = FRAME_EMPTY; - ucpia->buffers[0]->length = 0; - ucpia->buffers[1]->status = FRAME_EMPTY; - ucpia->buffers[1]->length = 0; - ucpia->buffers[2]->status = FRAME_EMPTY; - ucpia->buffers[2]->length = 0; - ucpia->curbuff = ucpia->buffers[0]; - ucpia->workbuff = ucpia->buffers[1]; - - /* We double buffer the Iso lists */ - urb = usb_alloc_urb(FRAMES_PER_DESC); - if (!urb) { - printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); - retval = -ENOMEM; - goto error_all; - } - - ucpia->sbuf[0].urb = urb; - urb->dev = ucpia->dev; - urb->context = ucpia; - urb->pipe = usb_rcvisocpipe(ucpia->dev, 1); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ucpia->sbuf[0].data; - urb->complete = cpia_usb_complete; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; - urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; - } - - urb = usb_alloc_urb(FRAMES_PER_DESC); - if (!urb) { - printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); - retval = -ENOMEM; - goto error_all; - } - - ucpia->sbuf[1].urb = urb; - urb->dev = ucpia->dev; - urb->context = ucpia; - urb->pipe = usb_rcvisocpipe(ucpia->dev, 1); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ucpia->sbuf[1].data; - urb->complete = cpia_usb_complete; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; - urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; - } - - ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb; - ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb; - - err = usb_submit_urb(ucpia->sbuf[0].urb); - if (err) - printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n", - err); - err = usb_submit_urb(ucpia->sbuf[1].urb); - if (err) - printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n", - err); - - ucpia->streaming = 1; - ucpia->open = 1; - - return 0; - -error_all: - kfree (ucpia->sbuf[1].data); -error_0: - kfree (ucpia->sbuf[0].data); - - return retval; -} - -// -// convenience functions -// - -/**************************************************************************** - * - * WritePacket - * - ***************************************************************************/ -static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size) -{ - if (!packet) - return -EINVAL; - - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - packet[1] + (packet[0] << 8), - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - packet[2] + (packet[3] << 8), - packet[4] + (packet[5] << 8), buf, size, HZ); -} - -/**************************************************************************** - * - * ReadPacket - * - ***************************************************************************/ -static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size) -{ - if (!packet || size <= 0) - return -EINVAL; - - return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - packet[1] + (packet[0] << 8), - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - packet[2] + (packet[3] << 8), - packet[4] + (packet[5] << 8), buf, size, HZ); -} - -static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data) -{ - int err = 0; - int databytes; - struct usb_cpia *ucpia = (struct usb_cpia *)privdata; - struct usb_device *udev = ucpia->dev; - - if (!udev) { - DBG("Internal driver error: udev is NULL\n"); - return -EINVAL; - } - - if (!command) { - DBG("Internal driver error: command is NULL\n"); - return -EINVAL; - } - - databytes = (((int)command[7])<<8) | command[6]; - - if (command[0] == DATA_IN) { - u8 buffer[8]; - - if (!data) { - DBG("Internal driver error: data is NULL\n"); - return -EINVAL; - } - - err = ReadPacket(udev, command, buffer, 8); - if (err < 0) - return err; - - memcpy(data, buffer, databytes); - } else if(command[0] == DATA_OUT) - WritePacket(udev, command, data, databytes); - else { - DBG("Unexpected first byte of command: %x\n", command[0]); - err = -EINVAL; - } - - return 0; -} - -static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata), - void *cbdata) -{ - return -ENODEV; -} - -static int cpia_usb_streamStart(void *privdata) -{ - return -ENODEV; -} - -static int cpia_usb_streamStop(void *privdata) -{ - return -ENODEV; -} - -static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock) -{ - struct usb_cpia *ucpia = (struct usb_cpia *) privdata; - struct framebuf *mybuff; - - if (!ucpia || !ucpia->present) - return -1; - - if (ucpia->curbuff->status != FRAME_READY) - interruptible_sleep_on(&ucpia->wq_stream); - else - DBG("Frame already waiting!\n"); - - mybuff = ucpia->curbuff; - - if (!mybuff) - return -1; - - if (mybuff->status != FRAME_READY || mybuff->length < 4) { - DBG("Something went wrong!\n"); - return -1; - } - - memcpy(frame, mybuff->data, mybuff->length); - mybuff->status = FRAME_EMPTY; - -/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */ -/* mybuff->length, frame[0], frame[1], */ -/* frame[mybuff->length-4], frame[mybuff->length-3], */ -/* frame[mybuff->length-2], frame[mybuff->length-1]); */ - - return mybuff->length; -} - -static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try) -{ - if (!ucpia->streaming) - return; - - ucpia->streaming = 0; - - /* Set packet size to 0 */ - if (try) { - int ret; - - ret = usb_set_interface(ucpia->dev, ucpia->iface, 0); - if (ret < 0) { - printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret); - return; - } - } - - /* Unschedule all of the iso td's */ - if (ucpia->sbuf[1].urb) { - usb_unlink_urb(ucpia->sbuf[1].urb); - usb_free_urb(ucpia->sbuf[1].urb); - ucpia->sbuf[1].urb = NULL; - } - - if (ucpia->sbuf[0].urb) { - usb_unlink_urb(ucpia->sbuf[0].urb); - usb_free_urb(ucpia->sbuf[0].urb); - ucpia->sbuf[0].urb = NULL; - } -} - -static int cpia_usb_close(void *privdata) -{ - struct usb_cpia *ucpia = (struct usb_cpia *) privdata; - - ucpia->open = 0; - - cpia_usb_free_resources(ucpia, 1); - - if (!ucpia->present) - kfree(ucpia); - - return 0; -} - -int cpia_usb_init(void) -{ - /* return -ENODEV; */ - return 0; -} - -/* Probing and initializing */ - -static void *cpia_probe(struct usb_device *udev, unsigned int ifnum) -{ - struct usb_interface_descriptor *interface; - struct usb_cpia *ucpia; - struct cam_data *cam; - int ret; - - /* A multi-config CPiA camera? */ - if (udev->descriptor.bNumConfigurations != 1) - return NULL; - - interface = &udev->actconfig->interface[ifnum].altsetting[0]; - - /* Is it a CPiA? */ - if (udev->descriptor.idVendor != 0x0553) - return NULL; - if (udev->descriptor.idProduct != 0x0002) - return NULL; - - /* We found a CPiA */ - printk(KERN_INFO "USB CPiA camera found\n"); - - ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL); - if (!ucpia) { - printk(KERN_ERR "couldn't kmalloc cpia struct\n"); - return NULL; - } - - memset(ucpia, 0, sizeof(*ucpia)); - - ucpia->dev = udev; - ucpia->iface = interface->bInterfaceNumber; - init_waitqueue_head(&ucpia->wq_stream); - - ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0])); - if (!ucpia->buffers[0]) { - printk(KERN_ERR "couldn't vmalloc frame buffer 0\n"); - goto fail_alloc_0; - } - - ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1])); - if (!ucpia->buffers[1]) { - printk(KERN_ERR "couldn't vmalloc frame buffer 1\n"); - goto fail_alloc_1; - } - - ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2])); - if (!ucpia->buffers[2]) { - printk(KERN_ERR "couldn't vmalloc frame buffer 2\n"); - goto fail_alloc_2; - } - - ucpia->buffers[0]->next = ucpia->buffers[1]; - ucpia->buffers[1]->next = ucpia->buffers[2]; - ucpia->buffers[2]->next = ucpia->buffers[0]; - - ret = usb_set_interface(udev, ucpia->iface, 0); - if (ret < 0) { - printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret); - /* goto fail_all; */ - } - - /* Before register_camera, important */ - ucpia->present = 1; - - cam = cpia_register_camera(&cpia_usb_ops, ucpia); - if (!cam) { - LOG("failed to cpia_register_camera\n"); - goto fail_all; - } - - ADD_TO_LIST(cam_list, cam); - - return cam; - -fail_all: - vfree(ucpia->buffers[2]); - ucpia->buffers[2] = NULL; -fail_alloc_2: - vfree(ucpia->buffers[1]); - ucpia->buffers[1] = NULL; -fail_alloc_1: - vfree(ucpia->buffers[0]); - ucpia->buffers[0] = NULL; -fail_alloc_0: - - return NULL; -} - -static void cpia_disconnect(struct usb_device *dev, void *ptr); - -static struct usb_driver cpia_driver = { - "cpia", - cpia_probe, - cpia_disconnect, - { NULL, NULL } -}; - -/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */ -/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */ -/* will do it for us as well as passing a udev structure - jerdfelt */ -static void cpia_disconnect(struct usb_device *udev, void *ptr) -{ - struct cam_data *cam = (struct cam_data *) ptr; - struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data; - - REMOVE_FROM_LIST(cam); - - /* Don't even try to reset the altsetting if we're disconnected */ - cpia_usb_free_resources(ucpia, 0); - - ucpia->present = 0; - - cpia_unregister_camera(cam); - - ucpia->curbuff->status = FRAME_ERROR; - - if (waitqueue_active(&ucpia->wq_stream)) - wake_up_interruptible(&ucpia->wq_stream); - - usb_driver_release_interface(&cpia_driver, - &udev->actconfig->interface[0]); - - ucpia->curbuff = ucpia->workbuff = NULL; - - if (ucpia->buffers[2]) { - vfree(ucpia->buffers[2]); - ucpia->buffers[2] = NULL; - } - - if (ucpia->buffers[1]) { - vfree(ucpia->buffers[1]); - ucpia->buffers[1] = NULL; - } - - if (ucpia->buffers[0]) { - vfree(ucpia->buffers[0]); - ucpia->buffers[0] = NULL; - } - - if (!ucpia->open) - kfree(ucpia); -} - -int usb_cpia_init(void) -{ - cam_list = NULL; - - return usb_register(&cpia_driver); -} - -void usb_cpia_cleanup(void) -{ -/* - struct cam_data *cam; - - while ((cam = cam_list) != NULL) - cpia_disconnect(NULL, cam); -*/ - - usb_deregister(&cpia_driver); -} - -#ifdef MODULE -int init_module(void) -{ - return usb_cpia_init(); -} - -void cleanup_module(void) -{ - usb_cpia_cleanup(); -} -#endif /* !MODULE */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/cs8420.h linux/drivers/char/cs8420.h --- v2.4.0-test6/linux/drivers/char/cs8420.h Thu Nov 11 20:11:33 1999 +++ linux/drivers/char/cs8420.h Wed Dec 31 16:00:00 1969 @@ -1,50 +0,0 @@ -/* cs8420.h - cs8420 initializations - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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 __CS8420_H__ -#define __CS8420_H__ - -/* Initialization Sequence */ - -static __u8 init8420[] = { - 1, 0x01, 2, 0x02, 3, 0x00, 4, 0x46, - 5, 0x24, 6, 0x84, 18, 0x18, 19, 0x13, -}; - -#define INIT8420LEN (sizeof(init8420)/2) - -static __u8 mode8420pro[] = { /* professional output mode */ - 32, 0xa1, 33, 0x00, 34, 0x00, 35, 0x00, - 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, - 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, - 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, - 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, - 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, -}; -#define MODE8420LEN (sizeof(mode8420pro)/2) - -static __u8 mode8420con[] = { /* consumer output mode */ - 32, 0x20, 33, 0x00, 34, 0x00, 35, 0x48, - 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, - 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, - 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, - 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, - 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, -}; - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/agpsupport.c linux/drivers/char/drm/agpsupport.c --- v2.4.0-test6/linux/drivers/char/drm/agpsupport.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/agpsupport.c Sun Aug 13 19:37:15 2000 @@ -309,7 +309,9 @@ #if LINUX_VERSION_CODE >= 0x020400 case VIA_MVP4: head->chipset = "VIA MVP4"; break; - case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; + case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133"; + break; + case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133"; break; #endif @@ -322,7 +324,7 @@ case ALI_M1541: head->chipset = "ALi M1541"; break; default: head->chipset = "Unknown"; break; } - DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n", + DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", head->agp_info.version.major, head->agp_info.version.minor, head->chipset, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/auth.c linux/drivers/char/drm/auth.c --- v2.4.0-test6/linux/drivers/char/drm/auth.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/auth.c Mon Aug 21 08:08:12 2000 @@ -126,12 +126,12 @@ if (priv->magic) { auth.magic = priv->magic; } else { - spin_lock(&lock); do { + spin_lock(&lock); if (!sequence) ++sequence; /* reserve 0 */ auth.magic = sequence++; + spin_unlock(&lock); } while (drm_find_file(dev, auth.magic)); - spin_unlock(&lock); priv->magic = auth.magic; drm_add_magic(dev, priv, auth.magic); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h --- v2.4.0-test6/linux/drivers/char/drm/drmP.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/drmP.h Wed Aug 23 11:55:00 2000 @@ -328,6 +328,7 @@ int low_mark; /* Low water mark */ int high_mark; /* High water mark */ atomic_t wfh; /* If waiting for high mark */ + spinlock_t lock; } drm_freelist_t; typedef struct drm_buf_entry { @@ -450,6 +451,11 @@ extern drm_agp_func_t drm_agp; #endif +typedef struct drm_sigdata { + int context; + drm_hw_lock_t *lock; +} drm_sigdata_t; + typedef struct drm_device { const char *name; /* Simple driver name */ char *unique; /* Unique identifier: e.g., busid */ @@ -534,6 +540,8 @@ #endif unsigned long *ctx_bitmap; void *dev_private; + drm_sigdata_t sigdata; /* For block_all_signals */ + sigset_t sigmask; } drm_device_t; @@ -728,6 +736,7 @@ drm_lock_flags_t flags); extern int drm_flush_block_and_flush(drm_device_t *dev, int context, drm_lock_flags_t flags); +extern int drm_notifier(void *priv); /* Context Bitmap support (ctxbitmap.c) */ extern int drm_ctxbitmap_init(drm_device_t *dev); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c --- v2.4.0-test6/linux/drivers/char/drm/ffb_drv.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/ffb_drv.c Thu Aug 10 12:43:12 2000 @@ -1,4 +1,4 @@ -/* $Id: ffb_drv.c,v 1.5 2000/07/26 01:03:57 davem Exp $ +/* $Id: ffb_drv.c,v 1.6 2000/08/10 05:26:23 davem Exp $ * ffb_drv.c: Creator/Creator3D direct rendering driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -754,6 +754,7 @@ extern struct vm_operations_struct drm_vm_ops; extern struct vm_operations_struct drm_vm_shm_ops; +extern struct vm_operations_struct drm_vm_shm_lock_ops; static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) { @@ -766,7 +767,6 @@ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", vma->vm_start, vma->vm_end, VM_OFFSET(vma)); - lock_kernel(); minor = MINOR(filp->f_dentry->d_inode->i_rdev); ffb_priv = NULL; for (i = 0; i < ffb_dev_table_size; i++) { @@ -774,15 +774,13 @@ if (ffb_priv->miscdev.minor == minor) break; } - if (i >= ffb_dev_table_size) { - unlock_kernel(); + if (i >= ffb_dev_table_size) return -EINVAL; - } + /* We don't support/need dma mappings, so... */ - if (!VM_OFFSET(vma)) { - unlock_kernel(); + if (!VM_OFFSET(vma)) return -EINVAL; - } + for (i = 0; i < dev->map_count; i++) { unsigned long off; @@ -794,19 +792,16 @@ break; } - if (i >= dev->map_count) { - unlock_kernel(); + if (i >= dev->map_count) return -EINVAL; - } + if (!map || - ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) { - unlock_kernel(); + ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) return -EPERM; - } - if (map->size != (vma->vm_end - vma->vm_start)) { - unlock_kernel(); + + if (map->size != (vma->vm_end - vma->vm_start)) return -EINVAL; - } + /* Set read-only attribute before mappings are created * so it works for fb/reg maps too. */ @@ -829,15 +824,19 @@ if (io_remap_page_range(vma->vm_start, ffb_priv->card_phys_base + VM_OFFSET(vma), vma->vm_end - vma->vm_start, - vma->vm_page_prot, 0)) { - unlock_kernel(); + vma->vm_page_prot, 0)) return -EAGAIN; - } + vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock); - vma->vm_ops = &drm_vm_shm_ops; + if (map->flags & _DRM_CONTAINS_LOCK) + vma->vm_ops = &drm_vm_shm_lock_ops; + else { + vma->vm_ops = &drm_vm_shm_ops; + vma->vm_private_data = (void *) map; + } /* Don't let this area swap. Change when * DRM_KERNEL advisory is supported. @@ -845,10 +844,8 @@ vma->vm_flags |= VM_LOCKED; break; default: - unlock_kernel(); return -EINVAL; /* This should never happen. */ }; - unlock_kernel(); vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/lists.c linux/drivers/char/drm/lists.c --- v2.4.0-test6/linux/drivers/char/drm/lists.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/lists.c Mon Aug 21 08:08:12 2000 @@ -116,6 +116,7 @@ bl->low_mark = 0; bl->high_mark = 0; atomic_set(&bl->wfh, 0); + bl->lock = SPIN_LOCK_UNLOCKED; ++bl->initialized; return 0; } @@ -130,8 +131,6 @@ int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) { - drm_buf_t *old, *prev; - int count = 0; drm_device_dma_t *dma = dev->dma; if (!dma) { @@ -152,15 +151,12 @@ drm_histogram_compute(dev, buf); #endif buf->list = DRM_LIST_FREE; - do { - old = bl->next; - buf->next = old; - prev = cmpxchg(&bl->next, old, buf); - if (++count > DRM_LOOPING_LIMIT) { - DRM_ERROR("Looping\n"); - return 1; - } - } while (prev != old); + + spin_lock(&bl->lock); + buf->next = bl->next; + bl->next = buf; + spin_unlock(&bl->lock); + atomic_inc(&bl->count); if (atomic_read(&bl->count) > dma->buf_count) { DRM_ERROR("%d of %d buffers free after addition of %d\n", @@ -177,26 +173,21 @@ static drm_buf_t *drm_freelist_try(drm_freelist_t *bl) { - drm_buf_t *old, *new, *prev; drm_buf_t *buf; - int count = 0; if (!bl) return NULL; /* Get buffer */ - do { - old = bl->next; - if (!old) return NULL; - new = bl->next->next; - prev = cmpxchg(&bl->next, old, new); - if (++count > DRM_LOOPING_LIMIT) { - DRM_ERROR("Looping\n"); - return NULL; - } - } while (prev != old); - atomic_dec(&bl->count); + spin_lock(&bl->lock); + if (!bl->next) { + spin_unlock(&bl->lock); + return NULL; + } + buf = bl->next; + bl->next = bl->next->next; + spin_unlock(&bl->lock); - buf = old; + atomic_dec(&bl->count); buf->next = NULL; buf->list = DRM_LIST_NONE; DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/lock.c linux/drivers/char/drm/lock.c --- v2.4.0-test6/linux/drivers/char/drm/lock.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/drm/lock.c Mon Aug 21 11:46:57 2000 @@ -223,3 +223,35 @@ drm_flush_unblock(dev, lock.context, lock.flags); return ret; } + +/* If we get here, it means that the process has called DRM_IOCTL_LOCK + without calling DRM_IOCTL_UNLOCK. + + If the lock is not held, then let the signal proceed as usual. + + If the lock is held, then set the contended flag and keep the signal + blocked. + + + Return 1 if the signal should be delivered normally. + Return 0 if the signal should be blocked. */ + +int drm_notifier(void *priv) +{ + drm_sigdata_t *s = (drm_sigdata_t *)priv; + unsigned int old, new, prev; + + + /* Allow signal delivery if lock isn't held */ + if (!_DRM_LOCK_IS_HELD(s->lock->lock) + || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1; + + /* Otherwise, set flag to force call to + drmUnlock */ + do { + old = s->lock->lock; + new = old | _DRM_LOCK_CONT; + prev = cmpxchg(&s->lock->lock, old, new); + } while (prev != old); + return 0; +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/mga_dma.c linux/drivers/char/drm/mga_dma.c --- v2.4.0-test6/linux/drivers/char/drm/mga_dma.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/mga_dma.c Mon Aug 21 08:08:12 2000 @@ -765,7 +765,7 @@ dev_priv->mAccess = init->mAccess; init_waitqueue_head(&dev_priv->flush_queue); init_waitqueue_head(&dev_priv->buf_queue); - dev_priv->WarpPipe = -1; + dev_priv->WarpPipe = 0xff000000; DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", dev_priv->chipset, dev_priv->warp_ucode_size, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/r128_drv.c linux/drivers/char/drm/r128_drv.c --- v2.4.0-test6/linux/drivers/char/drm/r128_drv.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/r128_drv.c Mon Aug 21 11:46:57 2000 @@ -656,6 +656,14 @@ #endif if (!ret) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); if (lock.flags & _DRM_LOCK_READY) { /* Wait for space in DMA/FIFO */ } @@ -719,6 +727,6 @@ current->priority = DEF_PRIORITY; } #endif - + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/drm/vm.c linux/drivers/char/drm/vm.c --- v2.4.0-test6/linux/drivers/char/drm/vm.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/drm/vm.c Fri Aug 11 19:14:46 2000 @@ -250,7 +250,7 @@ vma->vm_start, vma->vm_end, VM_OFFSET(vma)); /* Length must match exact page count */ - if ((length >> PAGE_SHIFT) != dma->page_count) { + if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { unlock_kernel(); return -EINVAL; } @@ -323,6 +323,9 @@ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } +#elif defined(__ia64__) + if (map->type != _DRM_AGP) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #endif vma->vm_flags |= VM_IO; /* not in core dump */ } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/ds1620.c linux/drivers/char/ds1620.c --- v2.4.0-test6/linux/drivers/char/ds1620.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/ds1620.c Sun Aug 13 09:54:15 2000 @@ -13,6 +13,7 @@ #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c --- v2.4.0-test6/linux/drivers/char/efirtc.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/efirtc.c Fri Aug 11 19:09:06 2000 @@ -395,11 +395,10 @@ return 0; } -static int __exit +static void __exit efi_rtc_exit(void) { /* not yet used */ - return 0; } module_init(efi_rtc_init); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c --- v2.4.0-test6/linux/drivers/char/generic_serial.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/generic_serial.c Fri Aug 11 14:54:17 2000 @@ -12,7 +12,12 @@ * Version 0.1 -- December, 1998. Initial version. * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc. * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus. - */ + * + * BitWizard is actively maintaining this file. We sometimes find + * that someone submitted changes to this file. We really appreciate + * your help, but please submit changes through us. We're doing our + * best to be responsive. -- REW + * */ #include #include @@ -80,10 +85,18 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; DECL - /* func_enter (); */ + func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + + if (! (port->flags & ASYNC_INITIALIZED)) return; /* Take a lock on the serial tranmit buffer! */ LOCKIT; @@ -99,7 +112,7 @@ port->xmit_cnt++; /* Characters in buffer */ RELEASEIT; - /* func_exit ();*/ + func_exit (); } @@ -115,11 +128,17 @@ int gs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; int c, total = 0; int t; - /* func_enter (); */ + func_enter (); + + if (!tty) return 0; + + port = tty->driver; + + if (!port) return 0; if (! (port->flags & ASYNC_INITIALIZED)) return 0; @@ -170,7 +189,7 @@ port->flags |= GS_TX_INTEN; port->rd->enable_tx_interrupts (port); } - /* func_exit (); */ + func_exit (); return total; } #else @@ -309,11 +328,11 @@ struct gs_port *port = tty->driver_data; int ret; - /* func_enter (); */ + func_enter (); ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; if (ret < 0) ret = 0; - /* func_exit (); */ + func_exit (); return ret; } @@ -361,7 +380,7 @@ if (!port || port->xmit_cnt < 0 || !port->xmit_buf) { gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n"); - func_exit(); + func_exit(); return -EINVAL; /* This is an error which we don't know how to handle. */ } @@ -399,7 +418,7 @@ gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies " "(%d chars).\n", jiffies_to_transmit, charsleft); - current->state = TASK_INTERRUPTIBLE; + set_current_state (TASK_INTERRUPTIBLE); schedule_timeout(jiffies_to_transmit); if (signal_pending (current)) { gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: "); @@ -409,7 +428,7 @@ } gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); - current->state = TASK_RUNNING; + set_current_state (TASK_RUNNING); func_exit(); return rv; @@ -419,10 +438,17 @@ void gs_flush_buffer(struct tty_struct *tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; unsigned long flags; func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + /* XXX Would the write semaphore do? */ save_flags(flags); cli(); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; @@ -438,9 +464,16 @@ void gs_flush_chars(struct tty_struct * tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) { func_exit (); @@ -456,9 +489,16 @@ void gs_stop(struct tty_struct * tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; + if (port->xmit_cnt && port->xmit_buf && (port->flags & GS_TX_INTEN) ) { @@ -471,7 +511,13 @@ void gs_start(struct tty_struct * tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; + + if (!tty) return; + + port = tty->driver_data; + + if (!port) return; if (port->xmit_cnt && port->xmit_buf && @@ -486,7 +532,11 @@ void gs_shutdown_port (struct gs_port *port) { long flags; + func_enter(); + + if (!port) return; + if (!(port->flags & ASYNC_INITIALIZED)) return; @@ -505,16 +555,20 @@ port->flags &= ~ASYNC_INITIALIZED; restore_flags (flags); + func_exit(); } void gs_hangup(struct tty_struct *tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); + if (!tty) return; + + port = tty->driver_data; tty = port->tty; if (!tty) return; @@ -534,8 +588,13 @@ struct gs_port *port = private_; struct tty_struct *tty; + func_enter (); + + if (!port) return; + tty = port->tty; - if(!tty) return; + + if (!tty) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && @@ -557,8 +616,13 @@ struct tty_struct *tty; func_enter (); + + if (!port) return 0; + tty = port->tty; + if (!tty) return 0; + gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n"); /* * If the device is in the middle of being closed, then block @@ -571,6 +635,7 @@ else return -ERESTARTSYS; } + gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); /* @@ -593,6 +658,7 @@ } gs_dprintk (GS_DEBUG_BTR, "after subtype\n"); + /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -606,6 +672,7 @@ } gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); + if (port->flags & ASYNC_CALLOUT_ACTIVE) { if (port->normal_termios.c_cflag & CLOCAL) do_clocal = 1; @@ -614,7 +681,6 @@ do_clocal = 1; } - gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n"); /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -623,9 +689,9 @@ * exit, either normal or abnormal. */ retval = 0; - + add_wait_queue(&port->open_wait, &wait); - + gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); cli(); if (!tty_hung_up_p(filp)) @@ -635,7 +701,7 @@ while (1) { CD = port->rd->get_CD (port); gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state (TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) @@ -679,12 +745,11 @@ func_enter (); + if (!tty) return; + port = (struct gs_port *) tty->driver_data; - if(! port) { - func_exit(); - return; - } + if (!port) return; if (!port->tty) { /* This seems to happen when this is called from vhangup. */ @@ -693,6 +758,7 @@ } save_flags(flags); cli(); + if (tty_hung_up_p(filp)) { restore_flags(flags); port->rd->hungup (port); @@ -761,7 +827,7 @@ if (port->blocked_open) { if (port->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state (TASK_INTERRUPTIBLE); schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); @@ -784,14 +850,19 @@ void gs_set_termios (struct tty_struct * tty, struct termios * old_termios) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; int baudrate, tmp, rv; struct termios *tiosp; func_enter(); - tiosp = tty->termios; + if (!tty) return; + + port = tty->driver_data; + if (!port) return; + + tiosp = tty->termios; if (gs_debug & GS_DEBUG_TERMIOS) { gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/i2c-old.c linux/drivers/char/i2c-old.c --- v2.4.0-test6/linux/drivers/char/i2c-old.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/i2c-old.c Wed Dec 31 16:00:00 1969 @@ -1,458 +0,0 @@ -/* - * Generic i2c interface for linux - * - * (c) 1998 Gerd Knorr - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REGPRINT(x) if (verbose) (x) -#define I2C_DEBUG(x) if (i2c_debug) (x) - -static int scan = 0; -static int verbose = 0; -static int i2c_debug = 0; - -#if LINUX_VERSION_CODE >= 0x020117 -MODULE_PARM(scan,"i"); -MODULE_PARM(verbose,"i"); -MODULE_PARM(i2c_debug,"i"); -#endif - -/* ----------------------------------------------------------------------- */ - -static struct i2c_bus *busses[I2C_BUS_MAX]; -static struct i2c_driver *drivers[I2C_DRIVER_MAX]; -static int bus_count = 0, driver_count = 0; - -#ifdef CONFIG_VIDEO_BT848 -extern int i2c_tuner_init(void); -extern int msp3400c_init(void); -#endif -#ifdef CONFIG_VIDEO_BUZ -extern int saa7111_init(void); -extern int saa7185_init(void); -#endif -#ifdef CONFIG_VIDEO_LML33 -extern int bt819_init(void); -extern int bt856_init(void); -#endif - -int i2c_init(void) -{ - printk(KERN_INFO "i2c: initialized%s\n", - scan ? " (i2c bus scan enabled)" : ""); - /* anything to do here ? */ -#ifdef CONFIG_VIDEO_BT848 - i2c_tuner_init(); - msp3400c_init(); -#endif -#ifdef CONFIG_VIDEO_BUZ - saa7111_init(); - saa7185_init(); -#endif -#ifdef CONFIG_VIDEO_LML33 - bt819_init(); - bt856_init(); -#endif - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver) -{ - struct i2c_device *device; - int i,j,ack=1; - unsigned char addr; - LOCK_FLAGS; - - /* probe for device */ - LOCK_I2C_BUS(bus); - for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,addr,0); - i2c_stop(bus); - if (!ack) - break; - } - UNLOCK_I2C_BUS(bus); - if (ack) - return; - - /* got answer */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (NULL == driver->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - return; - - for (j = 0; j < I2C_DEVICE_MAX; j++) - if (NULL == bus->devices[j]) - break; - if (I2C_DEVICE_MAX == j) - return; - - if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL))) - return; - device->bus = bus; - device->driver = driver; - device->addr = addr; - - /* Attach */ - - if (driver->attach(device)!=0) - { - kfree(device); - return; - } - driver->devices[i] = device; - driver->devcount++; - bus->devices[j] = device; - bus->devcount++; - - if (bus->attach_inform) - bus->attach_inform(bus,driver->id); - REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name)); -} - -static void i2c_detach_device(struct i2c_device *device) -{ - int i; - - if (device->bus->detach_inform) - device->bus->detach_inform(device->bus,device->driver->id); - device->driver->detach(device); - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->driver->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", - device->name); - return; - } - device->driver->devices[i] = NULL; - device->driver->devcount--; - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->bus->devices[i]) - break; - if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", - device->name); - return; - } - device->bus->devices[i] = NULL; - device->bus->devcount--; - - REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name)); - kfree(device); -} - -/* ----------------------------------------------------------------------- */ - -int i2c_register_bus(struct i2c_bus *bus) -{ - int i,ack; - LOCK_FLAGS; - - memset(bus->devices,0,sizeof(bus->devices)); - bus->devcount = 0; - - for (i = 0; i < I2C_BUS_MAX; i++) - if (NULL == busses[i]) - break; - if (I2C_BUS_MAX == i) - return -ENOMEM; - - busses[i] = bus; - bus_count++; - REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); - - MOD_INC_USE_COUNT; - - if (scan) - { - /* scan whole i2c bus */ - LOCK_I2C_BUS(bus); - for (i = 0; i < 256; i+=2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,i,0); - i2c_stop(bus); - if (!ack) - { - printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", - bus->name,i); - } - } - UNLOCK_I2C_BUS(bus); - } - - /* probe available drivers */ - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (drivers[i]) - i2c_attach_device(bus,drivers[i]); - return 0; -} - -int i2c_unregister_bus(struct i2c_bus *bus) -{ - int i; - - /* detach devices */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (bus->devices[i]) - i2c_detach_device(bus->devices[i]); - - for (i = 0; i < I2C_BUS_MAX; i++) - if (bus == busses[i]) - break; - if (I2C_BUS_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", - bus->name); - return -ENODEV; - } - - MOD_DEC_USE_COUNT; - - busses[i] = NULL; - bus_count--; - REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int i2c_register_driver(struct i2c_driver *driver) -{ - int i; - - memset(driver->devices,0,sizeof(driver->devices)); - driver->devcount = 0; - - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (NULL == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) - return -ENOMEM; - - drivers[i] = driver; - driver_count++; - - MOD_INC_USE_COUNT; - - REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); - - /* Probe available busses */ - for (i = 0; i < I2C_BUS_MAX; i++) - if (busses[i]) - i2c_attach_device(busses[i],driver); - - return 0; -} - -int i2c_unregister_driver(struct i2c_driver *driver) -{ - int i; - - /* detach devices */ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (driver->devices[i]) - i2c_detach_device(driver->devices[i]); - - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (driver == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", - driver->name); - return -ENODEV; - } - - MOD_DEC_USE_COUNT; - - drivers[i] = NULL; - driver_count--; - REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int i2c_control_device(struct i2c_bus *bus, int id, - unsigned int cmd, void *arg) -{ - int i; - - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (bus->devices[i] && bus->devices[i]->driver->id == id) - break; - if (i == I2C_DEVICE_MAX) - return -ENODEV; - if (NULL == bus->devices[i]->driver->command) - return -ENODEV; - return bus->devices[i]->driver->command(bus->devices[i],cmd,arg); -} - -/* ----------------------------------------------------------------------- */ - -#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data)) -#define I2C_GET(bus) (bus->i2c_getdataline(bus)) - -void i2c_start(struct i2c_bus *bus) -{ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - I2C_SET(bus,1,0); - I2C_SET(bus,0,0); - I2C_DEBUG(printk("%s: < ",bus->name)); -} - -void i2c_stop(struct i2c_bus *bus) -{ - I2C_SET(bus,0,0); - I2C_SET(bus,1,0); - I2C_SET(bus,1,1); - I2C_DEBUG(printk(">\n")); -} - -void i2c_one(struct i2c_bus *bus) -{ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - I2C_SET(bus,0,1); -} - -void i2c_zero(struct i2c_bus *bus) -{ - I2C_SET(bus,0,0); - I2C_SET(bus,1,0); - I2C_SET(bus,0,0); -} - -int i2c_ack(struct i2c_bus *bus) -{ - int ack; - - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - ack = I2C_GET(bus); - I2C_SET(bus,0,1); - return ack; -} - -int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) -{ - int i, ack; - - I2C_SET(bus,0,0); - for (i=7; i>=0; i--) - (data&(1<=0; i--) - { - I2C_SET(bus,1,1); - if (I2C_GET(bus)) - data |= (1<i2c_read) - return bus->i2c_read(bus, addr); - - i2c_start(bus); - i2c_sendbyte(bus,addr,0); - ret = i2c_readbyte(bus,1); - i2c_stop(bus); - return ret; -} - -int i2c_write(struct i2c_bus *bus, unsigned char addr, - unsigned char data1, unsigned char data2, int both) -{ - int ack; - - if (bus->i2c_write) - return bus->i2c_write(bus, addr, data1, data2, both); - - i2c_start(bus); - i2c_sendbyte(bus,addr,0); - ack = i2c_sendbyte(bus,data1,0); - if (both) - ack = i2c_sendbyte(bus,data2,0); - i2c_stop(bus); - return ack ? -1 : 0 ; -} - -/* ----------------------------------------------------------------------- */ - -#ifdef MODULE - -#if LINUX_VERSION_CODE >= 0x020100 -EXPORT_SYMBOL(i2c_register_bus); -EXPORT_SYMBOL(i2c_unregister_bus); -EXPORT_SYMBOL(i2c_register_driver); -EXPORT_SYMBOL(i2c_unregister_driver); -EXPORT_SYMBOL(i2c_control_device); -EXPORT_SYMBOL(i2c_start); -EXPORT_SYMBOL(i2c_stop); -EXPORT_SYMBOL(i2c_one); -EXPORT_SYMBOL(i2c_zero); -EXPORT_SYMBOL(i2c_ack); -EXPORT_SYMBOL(i2c_sendbyte); -EXPORT_SYMBOL(i2c_readbyte); -EXPORT_SYMBOL(i2c_read); -EXPORT_SYMBOL(i2c_write); -#endif - -int init_module(void) -{ - return i2c_init(); -} - -void cleanup_module(void) -{ -} -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/i2c-parport.c linux/drivers/char/i2c-parport.c --- v2.4.0-test6/linux/drivers/char/i2c-parport.c Fri Jul 14 12:12:09 2000 +++ linux/drivers/char/i2c-parport.c Wed Dec 31 16:00:00 1969 @@ -1,147 +0,0 @@ -/* - * I2C driver for parallel port - * - * Author: Phil Blundell - * - * 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 driver implements a simple I2C protocol by bit-twiddling some - * signals on the parallel port. Since the outputs on the parallel port - * aren't open collector, three lines rather than two are used: - * - * D0 clock out - * D1 data out - * BUSY data in - */ - -#include -#include -#include -#include -#include -#include - -#define I2C_DELAY 10 - -static int debug = 0; - -struct parport_i2c_bus -{ - struct i2c_bus i2c; - struct parport_i2c_bus *next; -}; - -static struct parport_i2c_bus *bus_list; - -static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED; - -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus, int clk, int data) -{ - struct parport *p = bus->data; - parport_write_data(p, (clk?1:0) | (data?2:0)); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct parport *p = bus->data; - return (parport_read_status(p) & PARPORT_STATUS_BUSY) ? 0 : 1; -} - -static struct i2c_bus parport_i2c_bus_template = -{ - "...", - I2C_BUSID_PARPORT, - NULL, - - SPIN_LOCK_UNLOCKED, - - NULL, - NULL, - - i2c_setlines, - i2c_getdataline, - NULL, - NULL, -}; - -static void i2c_parport_attach(struct parport *port) -{ - struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), - GFP_KERNEL); - b->i2c = parport_i2c_bus_template; - b->i2c.data = parport_get_port (port); - strncpy(b->i2c.name, port->name, 32); - spin_lock(&bus_list_lock); - b->next = bus_list; - bus_list = b; - spin_unlock(&bus_list_lock); - i2c_register_bus(&b->i2c); - if (debug) - printk(KERN_DEBUG "i2c: attached to %s\n", port->name); -} - -static void i2c_parport_detach(struct parport *port) -{ - struct parport_i2c_bus *b, *old_b = NULL; - spin_lock(&bus_list_lock); - b = bus_list; - while (b) - { - if (b->i2c.data == port) - { - if (old_b) - old_b->next = b->next; - else - bus_list = b->next; - i2c_unregister_bus(&b->i2c); - kfree(b); - break; - } - old_b = b; - b = b->next; - } - spin_unlock(&bus_list_lock); - if (debug) - printk(KERN_DEBUG "i2c: detached from %s\n", port->name); -} - -static struct parport_driver parport_i2c_driver = -{ - "i2c", - i2c_parport_attach, - i2c_parport_detach -}; - -#ifdef MODULE -int init_module(void) -#else -int __init i2c_parport_init(void) -#endif -{ - printk("I2C: driver for parallel port v0.1 philb@gnu.org\n"); - parport_register_driver(&parport_i2c_driver); - return 0; -} - -#ifdef MODULE -MODULE_PARM(debug, "i"); - -void cleanup_module(void) -{ - struct parport_i2c_bus *b = bus_list; - while (b) - { - struct parport_i2c_bus *next = b->next; - i2c_unregister_bus(&b->i2c); - kfree(b); - b = next; - } - parport_unregister_driver(&parport_i2c_driver); -} -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c --- v2.4.0-test6/linux/drivers/char/i810-tco.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/i810-tco.c Fri Aug 11 17:56:40 2000 @@ -0,0 +1,326 @@ +/* + * i810-tco 0.02: TCO timer driver for i810 chipsets + * + * (c) Copyright 2000 kernel concepts , All Rights Reserved. + * http://www.kernelconcepts.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. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i810/i815 chipsets + * based on softdog.c by Alan Cox + * + * The TCO timer is implemented in the 82801AA (82801AB) chip, + * see intel documentation from http://developer.intel.com, + * order number 290655-003 + * + * 20000710 Nils Faerber + * Initial Version 0.01 + * 20000728 Nils Faerber + * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i810-tco.h" + + +/* Just in case that the PCI vendor and device IDs are not yet defined */ +#ifndef PCI_DEVICE_ID_INTEL_82801AA_0 +#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 +#endif + +/* Default expire timeout */ +#define TIMER_MARGIN 50 /* steps of 0.6sec, 2 0x3f || tmrval < 0x03) + return -1; + + val = inb (TCO1_TMR); + val &= 0xc0; + val |= tmrval; + outb (val, TCO1_TMR); + val = inb (TCO1_TMR); + if ((val & 0x3f) != tmrval) + return -1; + + return 0; +} + +/* + * Reload (trigger) the timer + */ +static void tco_timer_reload (void) +{ + outb (0x01, TCO1_RLD); +} + +/* + * Read the current timer value + */ +static unsigned char tco_timer_read (void) +{ + return (inb (TCO1_RLD)); +} + + +/* + * Allow only one person to hold it open + */ + +static int i810tco_open (struct inode *inode, struct file *file) +{ + if (timer_alive) + return -EBUSY; + + /* + * Reload and activate timer + */ + tco_timer_reload (); + tco_timer_start (); + timer_alive = 1; + return 0; +} + +static int i810tco_release (struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + */ + tco_timer_stop (); + timer_alive = 0; + return 0; +} + +static ssize_t i810tco_write (struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if (len) { + tco_timer_reload (); + return 1; + } + return 0; +} + +static int i810tco_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + 0, + 0, + "i810 TCO timer" + }; + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + return put_user (tco_timer_read (), + (unsigned int *) (int) arg); + case WDIOC_GETBOOTSTATUS: + return put_user (boot_status, (int *) arg); + case WDIOC_KEEPALIVE: + tco_timer_reload (); + return 0; + } +} + +static struct pci_dev *i810tco_pci; + +static unsigned char i810tco_getdevice (void) +{ + u8 val1, val2; + u16 badr; + /* + * Find the PCI device which has vendor id 0x8086 + * and device ID 0x2410 + */ + i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801AA_0, NULL); + if (i810tco_pci) { + /* + * Find the ACPI base I/O address which is the base + * for the TCO registers (TCOBASE=ACPIBASE + 0x60) + * ACPIBASE is bits [15:7] from 0x40-0x43 + */ + pci_read_config_byte (i810tco_pci, 0x40, &val1); + pci_read_config_byte (i810tco_pci, 0x41, &val2); + badr = ((val2 << 1) | (val1 >> 7)) << 7; + ACPIBASE = badr; + /* Something's wrong here, ACPIBASE has to be set */ + if (badr == 0x0001 || badr == 0x0000) { + printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n"); + return 0; + } + /* + * Check chipset's NO_REBOOT bit + */ + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + val1 &= 0xfd; + pci_write_config_byte (i810tco_pci, 0xd4, val1); + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag\n"); + return 0; /* Cannot reset NO_REBOOT bit */ + } + } + /* Set the TCO_EN bit in SMI_EN register */ + val1 = inb (SMI_EN + 1); + val1 &= 0xdf; + outb (val1, SMI_EN + 1); + /* Clear out the (probably old) status */ + outb (0, TCO1_STS); + boot_status = (int) inb (TCO2_STS); + outb (3, TCO2_STS); + return 1; + } + return 0; +} + +static struct file_operations i810tco_fops = { + owner: THIS_MODULE, + write: i810tco_write, + ioctl: i810tco_ioctl, + open: i810tco_open, + release: i810tco_release, +}; + +static struct miscdevice i810tco_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &i810tco_fops +}; + +static int __init watchdog_init (void) +{ + if (!i810tco_getdevice () || i810tco_pci == NULL) + return -ENODEV; + if (!request_region (TCOBASE, 0x10, "i810 TCO")) { + printk (KERN_ERR + "i810 TCO timer: I/O address 0x%04x already in use\n", + TCOBASE); + return -EIO; + } + if (misc_register (&i810tco_miscdev) != 0) { + release_region (TCOBASE, 0x10); + printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n"); + return -EIO; + } + tco_timer_settimer ((unsigned char) i810_margin); + tco_timer_reload (); + + /* FIXME: no floating point math */ + printk (KERN_INFO + "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n", + (int) (i810_margin * 0.6), TCOBASE); + return 0; +} + +static void __exit watchdog_cleanup (void) +{ + u8 val; + + /* Reset the timer before we leave */ + tco_timer_reload (); + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i810tco_pci, 0xd4, &val); + val |= 0x02; + pci_write_config_byte (i810tco_pci, 0xd4, val); + release_region (TCOBASE, 0x10); + misc_deregister (&i810tco_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_cleanup); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/i810-tco.h linux/drivers/char/i810-tco.h --- v2.4.0-test6/linux/drivers/char/i810-tco.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/i810-tco.h Fri Aug 11 15:57:57 2000 @@ -0,0 +1,45 @@ +/* + * i810-tco 0.02: TCO timer driver for i810 chipsets + * + * (c) Copyright 2000 kernel concepts , All Rights Reserved. + * http://www.kernelconcepts.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. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i810 chipsets + * based on softdog.c by Alan Cox + * + * The TCO timer is implemented in the 82801AA (82801AB) chip, + * see intel documentation from http://developer.intel.com, + * order number 290655-003 + * + * For history see i810-tco.c + */ + + +/* + * Some address definitions for the i810 TCO + */ + +#define TCOBASE ACPIBASE + 0x60 /* TCO base address */ +#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ +#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */ +#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ +#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ +#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ +#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ +#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ +#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ + +#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/ibmmpeg2.h linux/drivers/char/ibmmpeg2.h --- v2.4.0-test6/linux/drivers/char/ibmmpeg2.h Thu Nov 11 20:11:33 1999 +++ linux/drivers/char/ibmmpeg2.h Wed Dec 31 16:00:00 1969 @@ -1,94 +0,0 @@ -/* ibmmpeg2.h - IBM MPEGCD21 definitions */ - -#ifndef __IBM_MPEG2__ -#define __IBM_MPEG2__ - -/* Define all MPEG Decoder registers */ -/* Chip Control and Status */ -#define IBM_MP2_CHIP_CONTROL 0x200*2 -#define IBM_MP2_CHIP_MODE 0x201*2 -/* Timer Control and Status */ -#define IBM_MP2_SYNC_STC2 0x202*2 -#define IBM_MP2_SYNC_STC1 0x203*2 -#define IBM_MP2_SYNC_STC0 0x204*2 -#define IBM_MP2_SYNC_PTS2 0x205*2 -#define IBM_MP2_SYNC_PTS1 0x206*2 -#define IBM_MP2_SYNC_PTS0 0x207*2 -/* Video FIFO Control */ -#define IBM_MP2_FIFO 0x208*2 -#define IBM_MP2_FIFOW 0x100*2 -#define IBM_MP2_FIFO_STAT 0x209*2 -#define IBM_MP2_RB_THRESHOLD 0x22b*2 -/* Command buffer */ -#define IBM_MP2_COMMAND 0x20a*2 -#define IBM_MP2_CMD_DATA 0x20b*2 -#define IBM_MP2_CMD_STAT 0x20c*2 -#define IBM_MP2_CMD_ADDR 0x20d*2 -/* Internal Processor Control and Status */ -#define IBM_MP2_PROC_IADDR 0x20e*2 -#define IBM_MP2_PROC_IDATA 0x20f*2 -#define IBM_MP2_WR_PROT 0x235*2 -/* DRAM Access */ -#define IBM_MP2_DRAM_ADDR 0x210*2 -#define IBM_MP2_DRAM_DATA 0x212*2 -#define IBM_MP2_DRAM_CMD_STAT 0x213*2 -#define IBM_MP2_BLOCK_SIZE 0x23b*2 -#define IBM_MP2_SRC_ADDR 0x23c*2 -/* Onscreen Display */ -#define IBM_MP2_OSD_ADDR 0x214*2 -#define IBM_MP2_OSD_DATA 0x215*2 -#define IBM_MP2_OSD_MODE 0x217*2 -#define IBM_MP2_OSD_LINK_ADDR 0x229*2 -#define IBM_MP2_OSD_SIZE 0x22a*2 -/* Interrupt Control */ -#define IBM_MP2_HOST_INT 0x218*2 -#define IBM_MP2_MASK0 0x219*2 -#define IBM_MP2_HOST_INT1 0x23e*2 -#define IBM_MP2_MASK1 0x23f*2 -/* Audio Control */ -#define IBM_MP2_AUD_IADDR 0x21a*2 -#define IBM_MP2_AUD_IDATA 0x21b*2 -#define IBM_MP2_AUD_FIFO 0x21c*2 -#define IBM_MP2_AUD_FIFOW 0x101*2 -#define IBM_MP2_AUD_CTL 0x21d*2 -#define IBM_MP2_BEEP_CTL 0x21e*2 -#define IBM_MP2_FRNT_ATTEN 0x22d*2 -/* Display Control */ -#define IBM_MP2_DISP_MODE 0x220*2 -#define IBM_MP2_DISP_DLY 0x221*2 -#define IBM_MP2_VBI_CTL 0x222*2 -#define IBM_MP2_DISP_LBOR 0x223*2 -#define IBM_MP2_DISP_TBOR 0x224*2 -/* Polarity Control */ -#define IBM_MP2_INFC_CTL 0x22c*2 - -/* control commands */ -#define IBM_MP2_PLAY 0 -#define IBM_MP2_PAUSE 1 -#define IBM_MP2_SINGLE_FRAME 2 -#define IBM_MP2_FAST_FORWARD 3 -#define IBM_MP2_SLOW_MOTION 4 -#define IBM_MP2_IMED_NORM_PLAY 5 -#define IBM_MP2_RESET_WINDOW 6 -#define IBM_MP2_FREEZE_FRAME 7 -#define IBM_MP2_RESET_VID_RATE 8 -#define IBM_MP2_CONFIG_DECODER 9 -#define IBM_MP2_CHANNEL_SWITCH 10 -#define IBM_MP2_RESET_AUD_RATE 11 -#define IBM_MP2_PRE_OP_CHN_SW 12 -#define IBM_MP2_SET_STILL_MODE 14 - -/* Define Xilinx FPGA Internal Registers */ - -/* general control register 0 */ -#define XILINX_CTL0 0x600 -/* genlock delay resister 1 */ -#define XILINX_GLDELAY 0x602 -/* send 16 bits to CS3310 port */ -#define XILINX_CS3310 0x604 -/* send 16 bits to CS3310 and complete */ -#define XILINX_CS3310_CMPLT 0x60c -/* pulse width modulator control */ -#define XILINX_PWM 0x606 - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in --- v2.4.0-test6/linux/drivers/char/joystick/Config.in Fri Jul 14 12:12:09 2000 +++ linux/drivers/char/joystick/Config.in Tue Aug 22 11:55:47 2000 @@ -5,50 +5,50 @@ mainmenu_option next_comment comment 'Joysticks' -tristate 'Joystick support' CONFIG_JOYSTICK +dep_mbool 'Joystick support' CONFIG_JOYSTICK $CONFIG_INPUT if [ "$CONFIG_JOYSTICK" != "n" ]; then - define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK - comment 'Game port support' - dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_JOYSTICK - dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_JOYSTICK - dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_JOYSTICK + dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT + dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT + dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT comment 'Gameport joysticks' - dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_JOYSTICK - dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_JOYSTICK - dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_JOYSTICK - dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_JOYSTICK - dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_JOYSTICK - dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_JOYSTICK - dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_JOYSTICK - dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_JOYSTICK - dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_JOYSTICK + dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT + dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_INPUT + dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_INPUT + dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_INPUT + dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_INPUT + dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_INPUT + dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT + dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT + dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT comment 'Serial port support' - dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_JOYSTICK + dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_INPUT comment 'Serial port joysticks' - dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_JOYSTICK - dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_JOYSTICK - dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_JOYSTICK - dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_JOYSTICK - dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_JOYSTICK - if [ "$CONFIG_INPUT_IFORCE_232" != "n" ]; then - define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_232 - fi + dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT + dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT + dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT + dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT + dep_tristate ' I-Force/Serial controllers' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT + dep_tristate ' I-Force/USB controllers' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB - if [ "$CONFIG_PARPORT" != "n" ]; then comment 'Parallel port joysticks' - dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK - dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK - dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_INPUT $CONFIG_PARPORT + dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_INPUT $CONFIG_PARPORT + dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_INPUT $CONFIG_PARPORT + else + comment ' Parport support is needed for parallel port joysticks' fi if [ "$CONFIG_AMIGA" = "y" ]; then comment 'System joysticks' - dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_JOYSTICK + dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_INPUT fi +else + comment 'Input core support is needed for joysticks' fi - + endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/Makefile linux/drivers/char/joystick/Makefile --- v2.4.0-test6/linux/drivers/char/joystick/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/joystick/Makefile Tue Aug 22 11:41:14 2000 @@ -19,6 +19,19 @@ export-objs := serio.o gameport.o +# I-Force may need both USB and RS-232 + +ifeq ($(CONFIG_INPUT_IFORCE_232),m) + ifeq ($(CONFIG_INPUT_IFORCE_USB),y) + CONFIG_INPUT_IFORCE_USB := m + endif +endif +ifeq ($(CONFIG_INPUT_IFORCE_USB),m) + ifeq ($(CONFIG_INPUT_IFORCE_232),y) + CONFIG_INPUT_IFORCE_232 := m + endif +endif + # Object file lists. obj-y := @@ -38,7 +51,8 @@ obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o -obj-$(CONFIG_INPUT_IFORCE_232) += serio.o +obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o serio.o +obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o obj-$(CONFIG_INPUT_ANALOG) += analog.o gameport.o obj-$(CONFIG_INPUT_A3D) += a3d.o gameport.o diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/amijoy.c linux/drivers/char/joystick/amijoy.c --- v2.4.0-test6/linux/drivers/char/joystick/amijoy.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/joystick/amijoy.c Mon Aug 14 13:55:01 2000 @@ -1,5 +1,5 @@ /* - * $Id: amijoy.c,v 1.4 2000/05/29 10:39:54 vojtech Exp $ + * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -77,7 +77,7 @@ return 0; if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) { - amijoy_used--; + (*used)--; printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq); return -EBUSY; } @@ -89,7 +89,7 @@ { int *used = dev->private; - if (!--(*port->used)) + if (!--(*used)) free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); } @@ -112,13 +112,21 @@ for (i = 0; i < 2; i++) if (amijoy[i]) { + if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2, + amijoy [Denise]")) { + if (i == 1 && amijoy[0]) { + input_unregister_device(amijoy_dev); + release_mem_region(CUSTOM_PHYSADDR+10, 2); + } + return -EBUSY; + } amijoy_dev[i].open = amijoy_open; amijoy_dev[i].close = amijoy_close; amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y); amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - for (j = 0; j < 2; j++) + for (j = 0; j < 2; j++) { amijoy_dev[i].absmin[ABS_X + j] = -1; amijoy_dev[i].absmax[ABS_X + j] = 1; } @@ -134,6 +142,7 @@ input_register_device(amijoy_dev + i); printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i); } + return 0; } static void _exit amijoy_exit(void) @@ -141,8 +150,10 @@ int i; for (i = 0; i < 2; i++) - if (amijoy[i]) + if (amijoy[i]) { input_unregister_device(amijoy_dev + i); + release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2); + } } module_init(amijoy_init); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/db9.c linux/drivers/char/joystick/db9.c --- v2.4.0-test6/linux/drivers/char/joystick/db9.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/joystick/db9.c Mon Aug 14 13:55:01 2000 @@ -1,5 +1,5 @@ /* - * $Id: db9.c,v 1.5 2000/05/29 20:39:38 vojtech Exp $ + * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $ * * Copyright (c) 1999 Vojtech Pavlik * @@ -95,7 +95,7 @@ static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START }; static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 }; -static short *db9_btn[DB9_MAX_PAD] = { db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, +static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn, db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn }; static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad", NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick", @@ -113,36 +113,36 @@ data = parport_read_data(port) >> 3; - input_report_abs(dev + 1, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev + 1, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev + 1, BTN_TRIGGER, ~data&DB9_FIRE1); + input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1); case DB9_MULTI_0802: data = parport_read_status(port) >> 3; - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_TRIGGER, data&DB9_FIRE1); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1); break; case DB9_MULTI_STICK: data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1); break; case DB9_MULTI2_STICK: data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_TRIGGER, ~data&DB9_FIRE1); - input_report_key(dev, BTN_THUMB, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1); + input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2); break; case DB9_GENESIS_PAD: @@ -150,16 +150,16 @@ parport_write_control(port, DB9_NOSELECT); data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_B, ~data&DB9_FIRE1); - input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_B, ~data & DB9_FIRE1); + input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); data=parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_FIRE1); - input_report_key(dev, BTN_START, ~data&DB9_FIRE2); + input_report_key(dev, BTN_A, ~data & DB9_FIRE1); + input_report_key(dev, BTN_START, ~data & DB9_FIRE2); break; case DB9_GENESIS5_PAD: @@ -167,18 +167,18 @@ parport_write_control(port, DB9_NOSELECT); data=parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_B, ~data&DB9_FIRE1); - input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_B, ~data & DB9_FIRE1); + input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); data=parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_FIRE1); - input_report_key(dev, BTN_X, ~data&DB9_FIRE2); - input_report_key(dev, BTN_Y, ~data&DB9_LEFT); - input_report_key(dev, BTN_START, ~data&DB9_RIGHT); + input_report_key(dev, BTN_A, ~data & DB9_FIRE1); + input_report_key(dev, BTN_X, ~data & DB9_FIRE2); + input_report_key(dev, BTN_Y, ~data & DB9_LEFT); + input_report_key(dev, BTN_START, ~data & DB9_RIGHT); break; case DB9_GENESIS6_PAD: @@ -187,17 +187,17 @@ udelay(DB9_GENESIS6_DELAY); data=parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); - input_report_key(dev, BTN_B, ~data&DB9_FIRE1); - input_report_key(dev, BTN_C, ~data&DB9_FIRE2); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); + input_report_key(dev, BTN_B, ~data & DB9_FIRE1); + input_report_key(dev, BTN_C, ~data & DB9_FIRE2); parport_write_control(port, DB9_NORMAL); udelay(DB9_GENESIS6_DELAY); data=parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_FIRE1); - input_report_key(dev, BTN_X, ~data&DB9_FIRE2); + input_report_key(dev, BTN_A, ~data & DB9_FIRE1); + input_report_key(dev, BTN_X, ~data & DB9_FIRE2); parport_write_control(port, DB9_NOSELECT); /* 2 */ udelay(DB9_GENESIS6_DELAY); @@ -207,10 +207,10 @@ udelay(DB9_GENESIS6_DELAY); data=parport_read_data(port); - input_report_key(dev, BTN_Y, ~data&DB9_LEFT); - input_report_key(dev, BTN_Z, ~data&DB9_DOWN); - input_report_key(dev, BTN_MODE, ~data&DB9_UP); - input_report_key(dev, BTN_START, ~data&DB9_RIGHT); + input_report_key(dev, BTN_Y, ~data & DB9_LEFT); + input_report_key(dev, BTN_Z, ~data & DB9_DOWN); + input_report_key(dev, BTN_MODE, ~data & DB9_UP); + input_report_key(dev, BTN_START, ~data & DB9_RIGHT); parport_write_control(port, DB9_NORMAL); udelay(DB9_GENESIS6_DELAY); @@ -224,32 +224,32 @@ parport_write_control(port, DB9_SATURN0); data = parport_read_data(port); - input_report_key(dev, BTN_Y, ~data&DB9_LEFT); - input_report_key(dev, BTN_Z, ~data&DB9_DOWN); - input_report_key(dev, BTN_TL,~data&DB9_UP); - input_report_key(dev, BTN_TR,~data&DB9_RIGHT); + input_report_key(dev, BTN_Y, ~data & DB9_LEFT); + input_report_key(dev, BTN_Z, ~data & DB9_DOWN); + input_report_key(dev, BTN_TL, ~data & DB9_UP); + input_report_key(dev, BTN_TR, ~data & DB9_RIGHT); parport_write_control(port, DB9_SATURN2); data = parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); parport_write_control(port, DB9_NORMAL); data = parport_read_data(port); - input_report_key(dev, BTN_A, ~data&DB9_LEFT); - input_report_key(dev, BTN_B, ~data&DB9_UP); - input_report_key(dev, BTN_C, ~data&DB9_DOWN); - input_report_key(dev, BTN_X, ~data&DB9_RIGHT); + input_report_key(dev, BTN_A, ~data & DB9_LEFT); + input_report_key(dev, BTN_B, ~data & DB9_UP); + input_report_key(dev, BTN_C, ~data & DB9_DOWN); + input_report_key(dev, BTN_X, ~data & DB9_RIGHT); break; case DB9_CD32_PAD: data=parport_read_data(port); - input_report_abs(dev, ABS_X, (data&DB9_DOWN ?0:1) - (data&DB9_UP ?0:1)); - input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?0:1)); + input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1)); + input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1)); parport_write_control(port, 0x0a); @@ -257,7 +257,7 @@ data = parport_read_data(port); parport_write_control(port, 0x02); parport_write_control(port, 0x0a); - input_report_key(dev, db9_cd32_btn[i], ~data&DB9_FIRE2); + input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2); } parport_write_control(port, 0x00); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/gamecon.c linux/drivers/char/joystick/gamecon.c --- v2.4.0-test6/linux/drivers/char/joystick/gamecon.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/joystick/gamecon.c Mon Aug 14 13:55:01 2000 @@ -1,5 +1,5 @@ /* - * $Id: gamecon.c,v 1.4 2000/05/29 21:08:45 vojtech Exp $ + * $Id: gamecon.c,v 1.5 2000/06/25 09:56:58 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -157,7 +157,7 @@ static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 }; static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 }; -static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_START, BTN_SELECT, BTN_X, BTN_Y, BTN_TL, BTN_TR }; +static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR }; /* * gc_nes_read_packet() reads a NES/SNES packet. @@ -515,7 +515,7 @@ case GC_N64: for (j = 0; j < 10; j++) - set_bit(gc_n64_btn[j], gc->dev[j].keybit); + set_bit(gc_n64_btn[j], gc->dev[i].keybit); for (j = 0; j < 2; j++) { set_bit(ABS_X + j, gc->dev[i].absbit); @@ -530,18 +530,15 @@ break; case GC_SNES: - for (j = 0; j < 8; j++) - set_bit(gc_snes_btn[j], gc->dev[j].keybit); - break; - + for (j = 4; j < 8; j++) + set_bit(gc_snes_btn[j], gc->dev[i].keybit); case GC_NES: for (j = 0; j < 4; j++) - set_bit(gc_snes_btn[j], gc->dev[j].keybit); + set_bit(gc_snes_btn[j], gc->dev[i].keybit); break; case GC_MULTI2: set_bit(BTN_THUMB, gc->dev[i].keybit); - case GC_MULTI: set_bit(BTN_TRIGGER, gc->dev[i].keybit); break; @@ -656,12 +653,13 @@ { int i, j; - for (i = 0; i < 3; i++) { - for (j = 0; j < 5; j++) - if (gc_base[i]->pads[0] & gc_status_bit[j]) - input_unregister_device(gc_base[i]->dev + j); - parport_unregister_device(gc_base[i]->pd); - } + for (i = 0; i < 3; i++) + if (gc_base[i]) { + for (j = 0; j < 5; j++) + if (gc_base[i]->pads[0] & gc_status_bit[j]) + input_unregister_device(gc_base[i]->dev + j); + parport_unregister_device(gc_base[i]->pd); + } } module_init(gc_init); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/iforce.c linux/drivers/char/joystick/iforce.c --- v2.4.0-test6/linux/drivers/char/joystick/iforce.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick/iforce.c Tue Aug 22 11:41:14 2000 @@ -0,0 +1,342 @@ +/* + * $Id: iforce.c,v 1.7 2000/06/04 14:03:36 vojtech Exp $ + * + * Copyright (c) 2000 Vojtech Pavlik + * + * USB/RS232 I-Force joysticks and wheels. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); + +#define USB_VENDOR_ID_LOGITECH 0x046d +#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281 + +#define IFORCE_MAX_LENGTH 16 + +#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE) +#define IFORCE_232 +#endif +#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE) +#define IFORCE_USB +#endif + +struct iforce { + signed char data[IFORCE_MAX_LENGTH]; + struct input_dev dev; + struct urb irq; + int open; + int idx, pkt, len, id; + unsigned char csum; +}; + +static struct { + __s32 x; + __s32 y; +} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +static char *iforce_name = "I-Force joystick/wheel"; + +static void iforce_process_packet(struct input_dev *dev, unsigned char id, int idx, unsigned char *data) +{ + switch (id) { + + case 1: /* joystick position data */ + case 3: /* wheel position data */ + + if (id == 1) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + } else { + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + } + + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + input_report_key(dev, BTN_TRIGGER, data[5] & 0x01); + input_report_key(dev, BTN_TOP, data[5] & 0x02); + input_report_key(dev, BTN_THUMB, data[5] & 0x04); + input_report_key(dev, BTN_TOP2, data[5] & 0x08); + input_report_key(dev, BTN_BASE, data[5] & 0x10); + input_report_key(dev, BTN_BASE2, data[5] & 0x20); + input_report_key(dev, BTN_BASE3, data[5] & 0x40); + input_report_key(dev, BTN_BASE4, data[5] & 0x80); + input_report_key(dev, BTN_BASE5, data[6] & 0x01); + input_report_key(dev, BTN_A, data[6] & 0x02); + input_report_key(dev, BTN_B, data[6] & 0x04); + input_report_key(dev, BTN_C, data[6] & 0x08); + break; + + case 2: /* force feedback effect status */ + break; + } +} + +#ifdef IFORCE_USB + +static int iforce_open(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + if (dev->idbus == BUS_USB && !iforce->open++) + if (usb_submit_urb(&iforce->irq)) + return -EIO; + + return 0; +} + +static void iforce_close(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + if (dev->idbus == BUS_USB && !--iforce->open) + usb_unlink_urb(&iforce->irq); +} + +#endif + +static void iforce_input_setup(struct iforce *iforce) +{ + int i; + + iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + iforce->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) | + BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5); + iforce->dev.keybit[LONG(BTN_GAMEPAD)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C); + iforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) + | BIT(ABS_WHEEL) | BIT(ABS_GAS) | BIT(ABS_BRAKE); + + for (i = ABS_X; i <= ABS_Y; i++) { + iforce->dev.absmax[i] = 1920; + iforce->dev.absmin[i] = -1920; + iforce->dev.absflat[i] = 128; + iforce->dev.absfuzz[i] = 16; + } + + for (i = ABS_THROTTLE; i <= ABS_RUDDER; i++) { + iforce->dev.absmax[i] = 255; + iforce->dev.absmin[i] = 0; + } + + for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) { + iforce->dev.absmax[i] = 1; + iforce->dev.absmin[i] = -1; + } + + iforce->dev.private = iforce; + +#ifdef IFORCE_USB + iforce->dev.open = iforce_open; + iforce->dev.close = iforce_close; +#endif + + input_register_device(&iforce->dev); +} + +#ifdef IFORCE_USB + +static void iforce_usb_irq(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1); +} + +static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_endpoint_descriptor *endpoint; + struct iforce *iforce; + + if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH || + dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE) + return NULL; + + endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return NULL; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->dev.name = iforce_name; + iforce->dev.idbus = BUS_USB; + iforce->dev.idvendor = dev->descriptor.idVendor; + iforce->dev.idproduct = dev->descriptor.idProduct; + iforce->dev.idversion = dev->descriptor.bcdDevice; + + FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), + iforce->data, 8, iforce_usb_irq, iforce, endpoint->bInterval); + + iforce_input_setup(iforce); + + printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", + iforce->dev.number, iforce_name, dev->bus->busnum, dev->devnum, ifnum); + + return iforce; +} + +static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct iforce *iforce = ptr; + usb_unlink_urb(&iforce->irq); + input_unregister_device(&iforce->dev); + kfree(iforce); +} + +static struct usb_driver iforce_usb_driver = { + name: "iforce", + probe: iforce_usb_probe, + disconnect: iforce_usb_disconnect, +}; + +#endif + +#ifdef IFORCE_232 + +static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct iforce* iforce = serio->private; + + if (!iforce->pkt) { + if (data != 0x2b) { + return; + } + iforce->pkt = 1; + return; + } + + if (!iforce->id) { + if (data > 3) { + iforce->pkt = 0; + return; + } + iforce->id = data; + return; + } + + if (!iforce->len) { + if (data > IFORCE_MAX_LENGTH) { + iforce->pkt = 0; + iforce->id = 0; + return; + } + iforce->len = data; + return; + } + + if (iforce->idx < iforce->len) { + iforce->csum += iforce->data[iforce->idx++] = data; + return; + } + + if (iforce->idx == iforce->len) { + iforce_process_packet(&iforce->dev, iforce->id, iforce->idx, iforce->data); + iforce->pkt = 0; + iforce->id = 0; + iforce->len = 0; + iforce->idx = 0; + iforce->csum = 0; + } +} + +static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +{ + struct iforce *iforce; + + if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) + return; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->dev.name = iforce_name; + iforce->dev.idbus = BUS_RS232; + iforce->dev.idvendor = SERIO_IFORCE; + iforce->dev.idproduct = 0x0001; + iforce->dev.idversion = 0x0100; + + serio->private = iforce; + + if (serio_open(serio, dev)) { + kfree(iforce); + return; + } + + iforce_input_setup(iforce); + + printk(KERN_INFO "input%d: %s on serio%d\n", + iforce->dev.number, iforce_name, serio->number); +} + +static void iforce_serio_disconnect(struct serio *serio) +{ + struct iforce* iforce = serio->private; + input_unregister_device(&iforce->dev); + serio_close(serio); + kfree(iforce); +} + +static struct serio_dev iforce_serio_dev = { + interrupt: iforce_serio_irq, + connect: iforce_serio_connect, + disconnect: iforce_serio_disconnect, +}; + +#endif + +static int __init iforce_init(void) +{ +#ifdef IFORCE_USB + usb_register(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_register_device(&iforce_serio_dev); +#endif + return 0; +} + +static void __exit iforce_exit(void) +{ +#ifdef IFORCE_USB + usb_deregister(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_unregister_device(&iforce_serio_dev); +#endif +} + +module_init(iforce_init); +module_exit(iforce_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/ns558.c linux/drivers/char/joystick/ns558.c --- v2.4.0-test6/linux/drivers/char/joystick/ns558.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/joystick/ns558.c Mon Aug 21 08:52:53 2000 @@ -1,5 +1,5 @@ /* - * $Id: ns558.c,v 1.11 2000/06/20 23:35:03 vojtech Exp $ + * $Id: ns558.c,v 1.16 2000/08/17 20:03:56 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst @@ -138,7 +138,7 @@ port->next = next; port->type = NS558_ISA; - port->gameport.io = io; + port->gameport.io = io & (-1 << i); port->gameport.size = (1 << i); request_region(port->gameport.io, port->gameport.size, "ns558-isa"); @@ -182,6 +182,7 @@ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { printk(KERN_ERR "Memory allocation failed.\n"); + release_region(ioport, iolen); return -ENOMEM; } memset(port, 0, sizeof(struct ns558)); @@ -208,6 +209,7 @@ { struct ns558 *port = (struct ns558 *)pdev->driver_data; release_region(port->gameport.io, port->gameport.size); + kfree(port); } static struct pci_driver ns558_pci_driver = { @@ -216,10 +218,16 @@ probe: ns558_pci_probe, remove: ns558_pci_remove, }; +#else +static struct pci_driver ns558_pci_driver; #endif /* CONFIG_PCI */ -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) +#define NSS558_ISAPNP +#endif + +#ifdef NSS558_ISAPNP /* * PnP IDs: * @@ -297,7 +305,7 @@ int __init ns558_init(void) { int i = 0; -#ifdef CONFIG_ISAPNP +#ifdef NSS558_ISAPNP struct pci_dev *dev = NULL; struct pnp_devid *devid; #endif @@ -310,17 +318,10 @@ ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558); /* - * Probe for PCI ports. - */ -#ifdef CONFIG_PCI - pci_register_driver(&ns558_pci_driver); -#endif - -/* * Probe for PnP ports. */ -#ifdef CONFIG_ISAPNP +#ifdef NSS558_ISAPNP for (devid = pnp_devids; devid->vendor; devid++) { while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) { ns558 = ns558_pnp_probe(dev, ns558); @@ -328,7 +329,14 @@ } #endif - return -!ns558; +/* + * Probe for PCI ports. + */ + + if (!ns558 && pci_module_init(&ns558_pci_driver)) + return -ENODEV; + + return 0; } void __exit ns558_exit(void) @@ -339,7 +347,7 @@ gameport_unregister_port(&port->gameport); switch (port->type) { -#ifdef CONFIG_ISAPNP +#ifdef NSS558_ISAPNP case NS558_PNP: if (port->dev->deactivate) port->dev->deactivate(port->dev); @@ -357,9 +365,7 @@ port = port->next; } -#ifdef CONFIG_PCI pci_unregister_driver(&ns558_pci_driver); -#endif } module_init(ns558_init); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/sidewinder.c linux/drivers/char/joystick/sidewinder.c --- v2.4.0-test6/linux/drivers/char/joystick/sidewinder.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/joystick/sidewinder.c Mon Aug 14 13:55:01 2000 @@ -1,5 +1,5 @@ /* - * $Id: sidewinder.c,v 1.14 2000/05/29 11:27:55 vojtech Exp $ + * $Id: sidewinder.c,v 1.16 2000/07/14 09:02:41 vojtech Exp $ * * Copyright (c) 1998-2000 Vojtech Pavlik * @@ -330,8 +330,8 @@ if (sw_parity(GB(i*15,15))) return -1; - input_report_key(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); - input_report_key(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); + input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); + input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); for (j = 0; j < 10; j++) input_report_key(dev, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/joystick/spaceball.c linux/drivers/char/joystick/spaceball.c --- v2.4.0-test6/linux/drivers/char/joystick/spaceball.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/joystick/spaceball.c Mon Aug 14 13:55:01 2000 @@ -1,5 +1,5 @@ /* - * $Id: spaceball.c,v 1.6 2000/05/29 11:19:51 vojtech Exp $ + * $Id: spaceball.c,v 1.7 2000/06/24 11:55:40 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -46,7 +46,7 @@ */ #define JS_SBALL_MAX_LENGTH 128 -static int spaceball_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; +static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; /* @@ -70,10 +70,12 @@ { struct input_dev *dev = &spaceball->dev; unsigned char *data = spaceball->data; - int i, d; + int i; if (spaceball->idx < 2) return; + printk("%c %d\n", spaceball->data[0], spaceball->idx); + switch (spaceball->data[0]) { case '@': /* Reset packet */ @@ -84,17 +86,17 @@ break; case 'D': /* Ball data */ - if (spaceball->idx != 16) return; + if (spaceball->idx != 15) return; for (i = 0; i < 6; i++) { - d = ((data[2 * i + 3] << 8) | data[2 * i + 2]); - input_report_abs(dev, spaceball_axes[i], d - ((d & 0x8000) ? 0x10000 : 0)); + input_report_abs(dev, spaceball_axes[i], + (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); } break; case '.': /* Button data, part2 */ - if (spaceball->idx != 4) return; - input_report_key(dev, BTN_LEFT, data[2] & 1); - input_report_key(dev, BTN_RIGHT, data[2] & 2); + if (spaceball->idx != 3) return; + input_report_key(dev, BTN_0, data[2] & 1); + input_report_key(dev, BTN_1, data[2] & 2); break; case '?': /* Error packet */ @@ -118,22 +120,27 @@ switch (data) { case 0xd: - if (spaceball->idx) - spaceball_process_packet(spaceball); + spaceball_process_packet(spaceball); spaceball->idx = 0; spaceball->escape = 0; return; + case '^': + if (!spaceball->escape) { + spaceball->escape ^= 1; + return; + } + spaceball->escape = 0; case 'M': case 'Q': case 'S': - if (spaceball->escape) + if (spaceball->escape) { + spaceball->escape = 0; data = 0xd; - case '^': - spaceball->escape ^= 1; + } default: if (spaceball->escape) { - printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x\n", data); spaceball->escape = 0; + printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data); } if (spaceball->idx < JS_SBALL_MAX_LENGTH) spaceball->data[spaceball->idx++] = data; @@ -172,15 +179,15 @@ memset(spaceball, 0, sizeof(struct spaceball)); spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - spaceball->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1); for (i = 0; i < 6; i++) { t = spaceball_axes[i]; set_bit(t, spaceball->dev.absbit); - spaceball->dev.absmin[t] = i < 3 ? -10000 : -2000; - spaceball->dev.absmax[t] = i < 3 ? 10000 : 2000; - spaceball->dev.absflat[t] = i < 3 ? 50 : 10; - spaceball->dev.absfuzz[t] = i < 3 ? 12 : 2; + spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600; + spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600; + spaceball->dev.absflat[t] = i < 3 ? 40 : 8; + spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2; } spaceball->serio = serio; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.4.0-test6/linux/drivers/char/msp3400.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/msp3400.c Wed Dec 31 16:00:00 1969 @@ -1,1454 +0,0 @@ -/* - * programming the msp34* sound processor family - * - * (c) 1997-2000 Gerd Knorr - * - * what works and what doesn't: - * - * AM-Mono - * Support for Hauppauge cards added (decoding handled by tuner) added by - * Frederic Crozat - * - * FM-Mono - * should work. The stereo modes are backward compatible to FM-mono, - * therefore FM-Mono should be allways available. - * - * FM-Stereo (B/G, used in germany) - * should work, with autodetect - * - * FM-Stereo (satellite) - * should work, no autodetect (i.e. default is mono, but you can - * switch to stereo -- untested) - * - * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) - * should work, with autodetect. Support for NICAM was added by - * Pekka Pietikainen - * - * - * TODO: - * - better SAT support - * - * - * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) - * using soundcore instead of OSS - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SMP -#include -#include -#endif -/* kernel_thread */ -#define __KERNEL_SYSCALLS__ -#include - -#include "audiochip.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -/* insmod parameters */ -static int debug = 0; /* debug output */ -static int once = 0; /* no continous stereo monitoring */ -static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), - the autoscan seems work well only with FM... */ -static int simple = -1; /* use short programming (>= msp3410 only) */ -static int dolby = 0; - -struct msp3400c { - int simple; - int nicam; - int mode; - int norm; - int stereo; - int nicam_on; - int main, second; /* sound carrier */ - - int left, right; /* volume */ - int bass, treble; - - /* thread */ - struct task_struct *thread; - wait_queue_head_t wq; - - struct semaphore *notify; - int active,restart,rmmod; - - int watch_stereo; - struct timer_list wake_stereo; -}; - -#define MSP3400_MAX 4 -static struct i2c_client *msps[MSP3400_MAX]; - -#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ - -/* ---------------------------------------------------------------------- */ - -#define dprintk if (debug) printk - -MODULE_PARM(once,"i"); -MODULE_PARM(debug,"i"); -MODULE_PARM(simple,"i"); -MODULE_PARM(amsound,"i"); -MODULE_PARM(dolby,"i"); - -/* ---------------------------------------------------------------------- */ - -#define I2C_MSP3400C 0x80 -#define I2C_MSP3400C_DEM 0x10 -#define I2C_MSP3400C_DFP 0x12 - -/* ----------------------------------------------------------------------- */ -/* functions for talking to the MSP3400C Sound processor */ - -static int msp3400c_reset(struct i2c_client *client) -{ - static char reset_off[3] = { 0x00, 0x80, 0x00 }; - static char reset_on[3] = { 0x00, 0x00, 0x00 }; - - i2c_master_send(client,reset_off,3); /* XXX ignore errors here */ - if (3 != i2c_master_send(client,reset_on, 3)) { - printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n"); - return -1; - } - return 0; -} - -static int -msp3400c_read(struct i2c_client *client, int dev, int addr) -{ - int err; - - unsigned char write[3]; - unsigned char read[2]; - struct i2c_msg msgs[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read } - }; - write[0] = dev+1; - write[1] = addr >> 8; - write[2] = addr & 0xff; - - for (err = 0; err < 3;) { - if (2 == i2c_transfer(client->adapter,msgs,2)) - break; - err++; - printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", - err, dev, addr); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - } - if (3 == err) { - printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(client); - return -1; - } - return read[0] << 8 | read[1]; -} - -static int -msp3400c_write(struct i2c_client *client, int dev, int addr, int val) -{ - int err; - unsigned char buffer[5]; - - buffer[0] = dev; - buffer[1] = addr >> 8; - buffer[2] = addr & 0xff; - buffer[3] = val >> 8; - buffer[4] = val & 0xff; - - for (err = 0; err < 3;) { - if (5 == i2c_master_send(client, buffer, 5)) - break; - err++; - printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", - err, dev, addr); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - } - if (3 == err) { - printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(client); - return -1; - } - return 0; -} - -/* ------------------------------------------------------------------------ */ - -/* This macro is allowed for *constants* only, gcc must calculate it - at compile time. Remember -- no floats in kernel mode */ -#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) - -#define MSP_MODE_AM_DETECT 0 -#define MSP_MODE_FM_RADIO 2 -#define MSP_MODE_FM_TERRA 3 -#define MSP_MODE_FM_SAT 4 -#define MSP_MODE_FM_NICAM1 5 -#define MSP_MODE_FM_NICAM2 6 -#define MSP_MODE_AM_NICAM 7 -#define MSP_MODE_BTSC 8 - -static struct MSP_INIT_DATA_DEM { - int fir1[6]; - int fir2[6]; - int cdo1; - int cdo2; - int ad_cv; - int mode_reg; - int dfp_src; - int dfp_matrix; -} msp_init_data[] = { - /* AM (for carrier detect / msp3400) */ - { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0500, 0x0020, 0x3000}, - - /* AM (for carrier detect / msp3410) */ - { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0100, 0x0020, 0x3000}, - - /* FM Radio */ - { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, - MSP_CARRIER(10.7), MSP_CARRIER(10.7), - 0x00d0, 0x0480, 0x0020, 0x3000 }, - - /* Terrestial FM-mono + FM-stereo */ - { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0480, 0x0030, 0x3000}, - - /* Sat FM-mono */ - { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0480, 0x0000, 0x3000}, - - /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ - { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0040, 0x0120, 0x3000}, - - /* NICAM/FM -- I (6.0/6.552) */ - { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, - MSP_CARRIER(6.0), MSP_CARRIER(6.0), - 0x00d0, 0x0040, 0x0120, 0x3000}, - - /* NICAM/AM -- L (6.5/5.85) */ - { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0140, 0x0120, 0x7c03}, -}; - -struct CARRIER_DETECT { - int cdo; - char *name; -}; - -static struct CARRIER_DETECT carrier_detect_main[] = { - /* main carrier */ - { MSP_CARRIER(4.5), "4.5 NTSC" }, - { MSP_CARRIER(5.5), "5.5 PAL B/G" }, - { MSP_CARRIER(6.0), "6.0 PAL I" }, - { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } -}; - -static struct CARRIER_DETECT carrier_detect_55[] = { - /* PAL B/G */ - { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, - { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } -}; - -static struct CARRIER_DETECT carrier_detect_65[] = { - /* PAL SAT / SECAM */ - { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, - { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, - { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, - { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, - { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, - { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, -}; - -#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) - -/* ------------------------------------------------------------------------ */ - -static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) -{ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ -} - -static void msp3400c_setvolume(struct i2c_client *client, int left, int right) -{ - int vol,val,balance; - - vol = (left > right) ? left : right; - val = (vol * 0x73 / 65535) << 8; - balance = 0; - if (vol > 0) - balance = ((right-left) * 127) / vol; - - dprintk("msp34xx: setvolume: %d:%d 0x%02x 0x%02x\n", - left,right,val>>8,balance); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ - /* scart - on/off only */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8); -} - -static void msp3400c_setbass(struct i2c_client *client, int bass) -{ - int val = ((bass-32768) * 0x60 / 65535) << 8; - - dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ -} - -static void msp3400c_settreble(struct i2c_client *client, int treble) -{ - int val = ((treble-32768) * 0x60 / 65535) << 8; - - dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ -} - -static void msp3400c_setmode(struct i2c_client *client, int type) -{ - struct msp3400c *msp = client->data; - int i; - - dprintk("msp3400: setmode: %d\n",type); - msp->mode = type; - msp->stereo = VIDEO_SOUND_MONO; - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ - msp_init_data[type].ad_cv); - - for (i = 5; i >= 0; i--) /* fir 1 */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, - msp_init_data[type].fir1[i]); - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); - for (i = 5; i >= 0; i--) - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, - msp_init_data[type].fir2[i]); - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ - msp_init_data[type].mode_reg); - - msp3400c_setcarrier(client, msp_init_data[type].cdo1, - msp_init_data[type].cdo2); - - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ - - if (dolby) { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, - 0x0520); /* I2S1 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, - 0x0620); /* I2S2 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, - msp_init_data[type].dfp_src); - } else { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, - msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, - msp_init_data[type].dfp_src); - } - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, - msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, - msp_init_data[type].dfp_matrix); - - if (msp->nicam) { - /* nicam prescale */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ - } -} - -/* turn on/off nicam + stereo */ -static void msp3400c_setstereo(struct i2c_client *client, int mode) -{ - struct msp3400c *msp = client->data; - int nicam=0; /* channel source: FM/AM or nicam */ - int src=0; - - /* switch demodulator */ - switch (msp->mode) { - case MSP_MODE_FM_TERRA: - dprintk("msp3400: FM setstereo: %d\n",mode); - msp3400c_setcarrier(client,msp->second,msp->main); - switch (mode) { - case VIDEO_SOUND_STEREO: - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); - break; - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_LANG1: - case VIDEO_SOUND_LANG2: - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); - break; - } - break; - case MSP_MODE_FM_SAT: - dprintk("msp3400: SAT setstereo: %d\n",mode); - switch (mode) { - case VIDEO_SOUND_MONO: - msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); - break; - case VIDEO_SOUND_STEREO: - msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); - break; - case VIDEO_SOUND_LANG1: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - case VIDEO_SOUND_LANG2: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - } - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - dprintk("msp3400: NICAM setstereo: %d\n",mode); - msp3400c_setcarrier(client,msp->second,msp->main); - if (msp->nicam_on) - nicam=0x0100; - break; - case MSP_MODE_BTSC: - dprintk("msp3400: BTSC setstereo: %d\n",mode); - nicam=0x0300; - break; - default: - dprintk("msp3400: mono setstereo\n"); - return; - } - - /* switch audio */ - switch (mode) { - case VIDEO_SOUND_STEREO: - src = 0x0020 | nicam; -#if 0 - /* spatial effect */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); -#endif - break; - case VIDEO_SOUND_MONO: - if (msp->mode == MSP_MODE_AM_NICAM) { - dprintk("msp3400: switching to AM mono\n"); - /* AM mono decoding is handled by tuner, not MSP chip */ - /* so let's redirect sound from tuner via SCART */ - /* volume prescale for SCART */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); - /* SCART switching control register*/ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900); - src = 0x0200; - break; - } - case VIDEO_SOUND_LANG1: - src = 0x0000 | nicam; - break; - case VIDEO_SOUND_LANG2: - src = 0x0010 | nicam; - break; - } - if (dolby) { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); - } else { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); - } -} - -static void -msp3400c_print_mode(struct msp3400c *msp) -{ - if (msp->main == msp->second) { - printk("msp3400: mono sound carrier: %d.%03d MHz\n", - msp->main/910000,(msp->main/910)%1000); - } else { - printk("msp3400: main sound carrier: %d.%03d MHz\n", - msp->main/910000,(msp->main/910)%1000); - } - if (msp->mode == MSP_MODE_FM_NICAM1 || - msp->mode == MSP_MODE_FM_NICAM2) - printk("msp3400: NICAM/FM carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - if (msp->mode == MSP_MODE_AM_NICAM) - printk("msp3400: NICAM/AM carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - if (msp->mode == MSP_MODE_FM_TERRA && - msp->main != msp->second) { - printk("msp3400: FM-stereo carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - } -} - -/* ----------------------------------------------------------------------- */ - -struct REGISTER_DUMP { - int addr; - char *name; -}; - -struct REGISTER_DUMP d1[] = { - { 0x007e, "autodetect" }, - { 0x0023, "C_AD_BITS " }, - { 0x0038, "ADD_BITS " }, - { 0x003e, "CIB_BITS " }, - { 0x0057, "ERROR_RATE" }, -}; - -static int -autodetect_stereo(struct i2c_client *client) -{ - struct msp3400c *msp = client->data; - int val; - int newstereo = msp->stereo; - int newnicam = msp->nicam_on; - int update = 0; - - switch (msp->mode) { - case MSP_MODE_FM_TERRA: - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); - if (val > 32768) - val -= 65536; - dprintk("msp34xx: stereo detect register: %d\n",val); - - if (val > 4096) { - newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO; - } else if (val < -4096) { - newstereo = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } else { - newstereo = VIDEO_SOUND_MONO; - } - newnicam = 0; - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); - dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1); - - if (val & 1) { - /* nicam synced */ - switch ((val & 0x1e) >> 1) { - case 0: - case 8: - newstereo = VIDEO_SOUND_STEREO; - break; - case 1: - case 9: - newstereo = VIDEO_SOUND_MONO - | VIDEO_SOUND_LANG1; - break; - case 2: - case 10: - newstereo = VIDEO_SOUND_MONO - | VIDEO_SOUND_LANG1 - | VIDEO_SOUND_LANG2; - break; - default: - newstereo = VIDEO_SOUND_MONO; - break; - } - newnicam=1; - } else { - newnicam = 0; - newstereo = VIDEO_SOUND_MONO; - } - break; - case MSP_MODE_BTSC: - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); - dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", - val, - (val & 0x0002) ? "no" : "yes", - (val & 0x0004) ? "no" : "yes", - (val & 0x0040) ? "stereo" : "mono", - (val & 0x0080) ? ", nicam 2nd mono" : "", - (val & 0x0100) ? ", bilingual/SAP" : ""); - newstereo = VIDEO_SOUND_MONO; - if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO; - if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1; - break; - } - if (newstereo != msp->stereo) { - update = 1; - dprintk("msp34xx: watch: stereo %d => %d\n", - msp->stereo,newstereo); - msp->stereo = newstereo; - } - if (newnicam != msp->nicam_on) { - update = 1; - dprintk("msp34xx: watch: nicam %d => %d\n", - msp->nicam_on,newnicam); - msp->nicam_on = newnicam; - } - return update; -} - -/* - * A kernel thread for msp3400 control -- we don't want to block the - * in the ioctl while doing the sound carrier & stereo detect - */ - -static void msp3400c_stereo_wake(unsigned long data) -{ - struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */ - - wake_up_interruptible(&msp->wq); -} - -/* stereo/multilang monitoring */ -static void watch_stereo(struct i2c_client *client) -{ - struct msp3400c *msp = client->data; - - if (autodetect_stereo(client)) { - if (msp->stereo & VIDEO_SOUND_STEREO) - msp3400c_setstereo(client,VIDEO_SOUND_STEREO); - else if (msp->stereo & VIDEO_SOUND_LANG1) - msp3400c_setstereo(client,VIDEO_SOUND_LANG1); - else - msp3400c_setstereo(client,VIDEO_SOUND_MONO); - } - if (once) - msp->watch_stereo = 0; - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+5*HZ); -} - -static int msp3400c_thread(void *data) -{ - struct i2c_client *client = data; - struct msp3400c *msp = client->data; - - struct CARRIER_DETECT *cd; - int count, max1,max2,val1,val2, val,this; - -#ifdef CONFIG_SMP - lock_kernel(); -#endif - - daemonize(); - sigfillset(¤t->blocked); - strcpy(current->comm,"msp3400"); - - msp->thread = current; - -#ifdef CONFIG_SMP - unlock_kernel(); -#endif - - printk("msp3400: daemon started\n"); - if(msp->notify != NULL) - up(msp->notify); - - for (;;) { - if (msp->rmmod) - goto done; - if (debug > 1) - printk("msp3400: thread: sleep\n"); - interruptible_sleep_on(&msp->wq); - if (debug > 1) - printk("msp3400: thread: wakeup\n"); - if (msp->rmmod || signal_pending(current)) - goto done; - - if (VIDEO_MODE_RADIO == msp->norm) - continue; /* nothing to do */ - - msp->active = 1; - - if (msp->watch_stereo) { - watch_stereo(client); - msp->active = 0; - continue; - } - - /* some time for the tuner to sync */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/5); - if (signal_pending(current)) - goto done; - - restart: - msp->restart = 0; - msp3400c_setvolume(client, 0, 0); - msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); - val1 = val2 = 0; - max1 = max2 = -1; - del_timer(&msp->wake_stereo); - msp->watch_stereo = 0; - - /* carrier detect pass #1 -- main carrier */ - cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); - - if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { - /* autodetect doesn't work well with AM ... */ - max1 = 3; - count = 0; - dprintk("msp3400: AM sound override\n"); - } - - for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - if (signal_pending(current)) - goto done; - if (msp->restart) - msp->restart = 0; - - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32768) - val -= 65536; - if (val1 < val) - val1 = val, max1 = this; - dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); - } - - /* carrier detect pass #2 -- second (stereo) carrier */ - switch (max1) { - case 1: /* 5.5 */ - cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55); - break; - case 3: /* 6.5 */ - cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65); - break; - case 0: /* 4.5 */ - case 2: /* 6.0 */ - default: - cd = NULL; count = 0; - break; - } - - if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { - /* autodetect doesn't work well with AM ... */ - cd = NULL; count = 0; max2 = 0; - } - for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - if (signal_pending(current)) - goto done; - if (msp->restart) - goto restart; - - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32768) - val -= 65536; - if (val2 < val) - val2 = val, max2 = this; - dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); - } - - /* programm the msp3400 according to the results */ - msp->main = carrier_detect_main[max1].cdo; - switch (max1) { - case 1: /* 5.5 */ - if (max2 == 0) { - /* B/G FM-stereo */ - msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_setstereo(client, VIDEO_SOUND_MONO); - msp->watch_stereo = 1; - } else if (max2 == 1 && msp->nicam) { - /* B/G NICAM */ - msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 2: /* 6.0 */ - /* PAL I NICAM */ - msp->second = MSP_CARRIER(6.552); - msp3400c_setmode(client, MSP_MODE_FM_NICAM2); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - break; - case 3: /* 6.5 */ - if (max2 == 1 || max2 == 2) { - /* D/K FM-stereo */ - msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_setstereo(client, VIDEO_SOUND_MONO); - msp->watch_stereo = 1; - } else if (max2 == 0 && - msp->norm == VIDEO_MODE_SECAM) { - /* L NICAM or AM-mono */ - msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_AM_NICAM); - msp->nicam_on = 0; - msp3400c_setstereo(client, VIDEO_SOUND_MONO); - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - } else if (max2 == 0 && msp->nicam) { - /* D/K NICAM */ - msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 0: /* 4.5 */ - default: - no_second: - msp->second = carrier_detect_main[max1].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->stereo = VIDEO_SOUND_MONO; - msp3400c_setstereo(client, VIDEO_SOUND_MONO); - break; - } - - /* unmute */ - msp3400c_setvolume(client, msp->left, msp->right); - - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+5*HZ); - - if (debug) - msp3400c_print_mode(msp); - - msp->active = 0; - } - -done: - dprintk("msp3400: thread: exit\n"); - msp->active = 0; - msp->thread = NULL; - - if(msp->notify != NULL) - up(msp->notify); - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* this one uses the automatic sound standard detection of newer */ -/* msp34xx chip versions */ - -static struct MODES { - int retval; - int main, second; - char *name; -} modelist[] = { - { 0x0000, 0, 0, "ERROR" }, - { 0x0001, 0, 0, "autodetect start" }, - { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, - { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, - { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, - { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, - { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, - { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, - { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, - { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, - { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, - { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, - { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, - { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, - { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, - { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, - { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, - { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, - { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, - { -1, 0, 0, NULL }, /* EOF */ -}; - -static int msp3410d_thread(void *data) -{ - struct i2c_client *client = data; - struct msp3400c *msp = client->data; - int mode,val,i,std; - -#ifdef CONFIG_SMP - lock_kernel(); -#endif - - daemonize(); - sigfillset(¤t->blocked); - strcpy(current->comm,"msp3410 [auto]"); - - msp->thread = current; - -#ifdef CONFIG_SMP - unlock_kernel(); -#endif - - printk("msp3410: daemon started\n"); - if(msp->notify != NULL) - up(msp->notify); - - for (;;) { - if (msp->rmmod) - goto done; - if (debug > 1) - printk("msp3410: thread: sleep\n"); - interruptible_sleep_on(&msp->wq); - if (debug > 1) - printk("msp3410: thread: wakeup\n"); - if (msp->rmmod || signal_pending(current)) - goto done; - - if (VIDEO_MODE_RADIO == msp->norm) - continue; /* nothing to do */ - - msp->active = 1; - - if (msp->watch_stereo) { - watch_stereo(client); - msp->active = 0; - continue; - } - - /* some time for the tuner to sync */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/5); - if (signal_pending(current)) - goto done; - - restart: - msp->restart = 0; - del_timer(&msp->wake_stereo); - msp->watch_stereo = 0; - - /* put into sane state (and mute) */ - msp3400c_reset(client); - - /* start autodetect */ - switch (msp->norm) { - case VIDEO_MODE_PAL: - mode = 0x1003; - std = 1; - break; - case VIDEO_MODE_NTSC: /* BTSC */ - mode = 0x2003; - std = 0x0020; - break; - case VIDEO_MODE_SECAM: - mode = 0x0003; - std = 1; - break; - default: - mode = 0x0003; - std = 1; - break; - } - msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); - msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); - if (debug) { - int i; - for (i = 0; modelist[i].name != NULL; i++) - if (modelist[i].retval == std) - break; - printk("msp3410: setting mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown",std); - } - - if (std != 1) { - /* programmed some specific mode */ - val = std; - } else { - /* triggered autodetect */ - for (;;) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - if (signal_pending(current)) - goto done; - if (msp->restart) - goto restart; - - /* check results */ - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); - if (val < 0x07ff) - break; - dprintk("msp3410: detection still in progress\n"); - } - } - for (i = 0; modelist[i].name != NULL; i++) - if (modelist[i].retval == val) - break; - dprintk("msp3410: current mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown", - val); - msp->main = modelist[i].main; - msp->second = modelist[i].second; - - if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { - /* autodetection has failed, let backup */ - dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n", - modelist[8].name ? modelist[8].name : "unknown",val); - val = 0x0009; - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); - } - - /* set prescale / stereo */ - switch (val) { - case 0x0009: - msp->mode = MSP_MODE_AM_NICAM; - msp->stereo = VIDEO_SOUND_MONO; - msp3400c_setstereo(client,VIDEO_SOUND_MONO); - msp->watch_stereo = 1; - break; - case 0x0020: /* BTSC */ - /* just turn on stereo */ - msp->mode = MSP_MODE_BTSC; - msp->stereo = VIDEO_SOUND_STEREO; - msp->watch_stereo = 1; - msp3400c_setstereo(client,VIDEO_SOUND_STEREO); - /* set prescale */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ - break; - case 0x0003: - msp->mode = MSP_MODE_FM_TERRA; - msp->stereo = VIDEO_SOUND_MONO; - msp->watch_stereo = 1; - /* fall */ - default: - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */ - break; - } - - /* unmute */ - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->left, msp->right); - - if (msp->watch_stereo) - mod_timer(&msp->wake_stereo, jiffies+HZ); - - msp->active = 0; - } - -done: - dprintk("msp3410: thread: exit\n"); - msp->active = 0; - msp->thread = NULL; - - if(msp->notify != NULL) - up(msp->notify); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int msp_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind); -static int msp_detach(struct i2c_client *client); -static int msp_probe(struct i2c_adapter *adap); -static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); - -static struct i2c_driver driver = { - "i2c msp3400 driver", - I2C_DRIVERID_MSP3400, - I2C_DF_NOTIFY, - msp_probe, - msp_detach, - msp_command, -}; - -static struct i2c_client client_template = -{ - "unset", - -1, - 0, - 0, - NULL, - &driver -}; - -static int msp_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - DECLARE_MUTEX_LOCKED(sem); - struct msp3400c *msp; - struct i2c_client *c; - int rev1,rev2,i; - - client_template.adapter = adap; - client_template.addr = addr; - - if (-1 == msp3400c_reset(&client_template)) { - dprintk("msp3400: no chip found\n"); - return -1; - } - - if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) - return -ENOMEM; - memcpy(c,&client_template,sizeof(struct i2c_client)); - if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { - kfree(c); - return -ENOMEM; - } - - memset(msp,0,sizeof(struct msp3400c)); - msp->left = 65535; - msp->right = 65535; - msp->bass = 32768; - msp->treble = 32768; - c->data = msp; - init_waitqueue_head(&msp->wq); - - if (-1 == msp3400c_reset(c)) { - kfree(msp); - dprintk("msp3400: no chip found\n"); - return -1; - } - - rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e); - rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f); - if (0 == rev1 && 0 == rev2) { - kfree(msp); - printk("msp3400: error while reading chip version\n"); - return -1; - } - -#if 0 - /* this will turn on a 1kHz beep - might be useful for debugging... */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0014, 0x1040); -#endif - - sprintf(c->name,"MSP34%02d%c-%c%d", - (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); - msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; - - if (simple == -1) { - /* default mode */ - /* msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; */ - msp->simple = ((rev1&0xff)+'@' > 'C'); - } else { - /* use insmod option */ - msp->simple = simple; - } - - /* timer for stereo checking */ - msp->wake_stereo.function = msp3400c_stereo_wake; - msp->wake_stereo.data = (unsigned long)msp; - - /* hello world :-) */ - printk(KERN_INFO "msp3400: init: chip=%s",c->name); - if (msp->nicam) - printk(", has NICAM support"); - printk("\n"); - - /* startup control thread */ - MOD_INC_USE_COUNT; - msp->notify = &sem; - kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread, - (void *)c, 0); - down(&sem); - msp->notify = NULL; - wake_up_interruptible(&msp->wq); - -#ifdef REGISTER_MIXER - if ((msp->mixer_num = register_sound_mixer(&msp3400c_mixer_fops,mixer)) < 0) - printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); -#endif - - /* update our own array */ - for (i = 0; i < MSP3400_MAX; i++) { - if (NULL == msps[i]) { - msps[i] = c; - break; - } - } - - /* done */ - i2c_attach_client(c); - return 0; -} - -static int msp_detach(struct i2c_client *client) -{ - DECLARE_MUTEX_LOCKED(sem); - struct msp3400c *msp = (struct msp3400c*)client->data; - int i; - -#ifdef REGISTER_MIXER - if (msp->mixer_num >= 0) - unregister_sound_mixer(msp->mixer_num); -#endif - - /* shutdown control thread */ - del_timer(&msp->wake_stereo); - if (msp->thread) - { - msp->notify = &sem; - msp->rmmod = 1; - wake_up_interruptible(&msp->wq); - down(&sem); - msp->notify = NULL; - } - msp3400c_reset(client); - - /* update our own array */ - for (i = 0; i < MSP3400_MAX; i++) { - if (client == msps[i]) { - msps[i] = NULL; - break; - } - } - - i2c_detach_client(client); - kfree(msp); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int msp_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, msp_attach); - return 0; -} - -static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) -{ - struct msp3400c *msp = (struct msp3400c*)client->data; -#if 0 - int *iarg = (int*)arg; - __u16 *sarg = arg; -#endif - - switch (cmd) { - - case AUDC_SET_RADIO: - msp->norm = VIDEO_MODE_RADIO; - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - if (msp->simple) { - msp3400c_reset(client); - msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, 0x0003); /* automatic */ - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, 0x0040); /* FM Radio */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM prescale */ - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->left, msp->right); - } else { - msp3400c_setmode(client,MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); - msp3400c_setvolume(client,msp->left, msp->right); - } - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - va->volume=MAX(msp->left,msp->right); - va->balance=(32768*MIN(msp->left,msp->right))/ - (va->volume ? va->volume : 1); - va->balance=(msp->leftright)? - (65535-va->balance) : va->balance; - va->bass = msp->bass; - va->treble = msp->treble; - - autodetect_stereo(client); - va->mode = msp->stereo; - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - - msp->left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - msp->right = (MIN(va->balance,32768) * - va->volume) / 32768; - msp->bass = va->bass; - msp->treble = va->treble; - msp3400c_setvolume(client,msp->left, msp->right); - msp3400c_setbass(client,msp->bass); - msp3400c_settreble(client,msp->treble); - - if (va->mode != 0) { - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - msp->stereo = va->mode; - msp3400c_setstereo(client,va->mode); - } - break; - } - case VIDIOCSCHAN: - { - struct video_channel *vc = arg; - - msp->norm = vc->norm; - break; - } - case VIDIOCSFREQ: - { - /* new channel -- kick audio carrier scan */ - msp3400c_setvolume(client,0,0); - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - if (msp->active) - msp->restart = 1; - wake_up_interruptible(&msp->wq); - break; - } - - /* --- v4l2 ioctls --- */ - /* NOT YET */ - -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_SET_TVNORM: - msp->norm = *iarg; - break; - case AUDC_SWITCH_MUTE: - /* channels switching step one -- mute */ - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - msp3400c_setvolume(client,0,0); - break; - case AUDC_NEWCHANNEL: - /* channels switching step two -- trigger sound carrier scan */ - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - if (msp->active) - msp->restart = 1; - wake_up_interruptible(&msp->wq); - break; - - case AUDC_GET_VOLUME_LEFT: - *sarg = msp->left; - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = msp->right; - break; - case AUDC_SET_VOLUME_LEFT: - msp->left = *sarg; - msp3400c_setvolume(client,msp->left, msp->right); - break; - case AUDC_SET_VOLUME_RIGHT: - msp->right = *sarg; - msp3400c_setvolume(client,msp->left, msp->right); - break; - - case AUDC_GET_BASS: - *sarg = msp->bass; - break; - case AUDC_SET_BASS: - msp->bass = *sarg; - msp3400c_setbass(client,msp->bass); - break; - - case AUDC_GET_TREBLE: - *sarg = msp->treble; - break; - case AUDC_SET_TREBLE: - msp->treble = *sarg; - msp3400c_settreble(client,msp->treble); - break; - - case AUDC_GET_STEREO: - autodetect_stereo(client); - *sarg = msp->stereo; - break; - case AUDC_SET_STEREO: - if (*sarg) { - msp->watch_stereo=0; - del_timer(&msp->wake_stereo); - msp->stereo = *sarg; - msp3400c_setstereo(client,*sarg); - } - break; - - case AUDC_GET_DC: - if (msp->simple) - break; /* fixme */ - *sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) + - (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c)); - break; -#endif - default: - /* nothing */ - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int msp3400_init_module(void) -{ - i2c_add_driver(&driver); - return 0; -} - -void msp3400_cleanup_module(void) -{ - i2c_del_driver(&driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/nwbutton.c linux/drivers/char/nwbutton.c --- v2.4.0-test6/linux/drivers/char/nwbutton.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/nwbutton.c Sun Aug 13 09:54:15 2000 @@ -19,6 +19,8 @@ #include #include +#include + #define __NWBUTTON_C /* Tell the header file who we are */ #include "nwbutton.h" diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/nwflash.c linux/drivers/char/nwflash.c --- v2.4.0-test6/linux/drivers/char/nwflash.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/nwflash.c Sun Aug 13 09:54:15 2000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.4.0-test6/linux/drivers/char/pcxx.c Mon Jul 10 16:47:22 2000 +++ linux/drivers/char/pcxx.c Tue Aug 22 15:21:54 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/char/pcxe.c + * linux/drivers/char/pcxx.c * * Written by Troy De Jongh, November, 1994 * @@ -12,13 +12,11 @@ * This driver does NOT support DigiBoard's fastcook FEP option and * does not support the transparent print (i.e. digiprint) option. * - * This Driver is currently maintained by Christoph Lameter (clameter@fuller.edu) - * Please contact the mailing list for problems first. + * This Driver is currently maintained by Christoph Lameter (christoph@lameter.com) * - * Sources of Information: - * 1. The Linux Digiboard Page at http://private.fuller.edu/clameter/digi.html - * 2. The Linux Digiboard Mailing list at digiboard@list.fuller.edu - * (Simply write a message to introduce yourself to subscribe) + * Please contact digi for support issues at digilnux@dgii.com. Some + * information (mostly of historical interest) can be found at + * http://lameter.com/digi. * * 1.5.2 Fall 1995 Bug fixes by David Nugent * 1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory @@ -39,6 +37,8 @@ * verbose messages to assist user during card configuration. * Currently only tested on a PC/Xi card, but should work on Xe * and Xeve also. + * 1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo + * get rid of panics, release previously allocated resources * */ @@ -81,7 +81,7 @@ #include #include -#define VERSION "1.6.1" +#define VERSION "1.6.2" #include "digi.h" #include "fep.h" @@ -193,6 +193,30 @@ #define TZ_BUFSZ 4096 /* function definitions */ + +/*****************************************************************************/ + +static void cleanup_board_resources(void) +{ + int crd, i; + struct board_info *bd; + struct channel *ch; + + for(crd = 0; crd < numcards; crd++) { + bd = &boards[crd]; + ch = digi_channels + bd->first_minor; + + if (bd->region) + release_region(bd->port, 4); + + for(i = 0; i < bd->numports; i++, ch++) + if (ch->tmp_buf) + kfree(ch->tmp_buf); + } +} + +/*****************************************************************************/ + #ifdef MODULE /* @@ -209,10 +233,7 @@ { unsigned long flags; - int crd, i; int e1, e2; - struct board_info *bd; - struct channel *ch; printk(KERN_NOTICE "Unloading PC/Xx version %s\n", VERSION); @@ -226,14 +247,7 @@ if ((e2 = tty_unregister_driver(&pcxe_callout))) printk("SERIAL: failed to unregister callout driver (%d)\n",e2); - for(crd=0; crd < numcards; crd++) { - bd = &boards[crd]; - ch = digi_channels+bd->first_minor; - for(i=0; i < bd->numports; i++, ch++) { - kfree(ch->tmp_buf); - } - release_region(bd->port, 4); - } + cleanup_board_resources(); kfree(digi_channels); kfree(pcxe_termios_locked); kfree(pcxe_termios); @@ -620,7 +634,7 @@ ** worth noting that while I'm not sure what this hunk of code is supposed ** to do, it is not present in the serial.c driver. Hmmm. If you know, ** please send me a note. brian@ilinx.com -** Don't know either what this is supposed to do clameter@waterf.org. +** Don't know either what this is supposed to do christoph@lameter.com. */ if(tty->ldisc.num != ldiscs[N_TTY].num) { if(tty->ldisc.close) @@ -1090,6 +1104,7 @@ { ulong memory_seg=0, memory_size=0; int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L; + int ret = -ENOMEM; unchar *fepos, *memaddr, *bios, v; volatile struct global_data *gd; volatile struct board_chan *bc; @@ -1099,7 +1114,7 @@ printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION); #ifdef MODULE - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_DIGI_BOARDS; i++) { if (io[i]) { numcards = 0; break; @@ -1108,7 +1123,7 @@ if (numcards == 0) { int first_minor = 0; - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_DIGI_BOARDS; i++) { if (io[i] == 0) { boards[i].port = 0; boards[i].status = DISABLED; @@ -1139,6 +1154,7 @@ else boards[i].numports = 16; + boards[i].region = NULL; first_minor += boards[i].numports; } } @@ -1178,23 +1194,31 @@ * unused spaces. */ digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL); - if (!digi_channels) - panic("Unable to allocate digi_channel struct"); + if (!digi_channels) { + printk(KERN_ERR "Unable to allocate digi_channel struct\n"); + return -ENOMEM; + } memset(digi_channels, 0, sizeof(struct channel) * nbdevs); pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL); - if (!pcxe_table) - panic("Unable to allocate pcxe_table struct"); + if (!pcxe_table) { + printk(KERN_ERR "Unable to allocate pcxe_table struct\n"); + goto cleanup_digi_channels; + } memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs); pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); - if (!pcxe_termios) - panic("Unable to allocate pcxe_termios struct"); + if (!pcxe_termios) { + printk(KERN_ERR "Unable to allocate pcxe_termios struct\n"); + goto cleanup_pcxe_table; + } memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs); pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); - if (!pcxe_termios_locked) - panic("Unable to allocate pcxe_termios_locked struct"); + if (!pcxe_termios_locked) { + printk(KERN_ERR "Unable to allocate pcxe_termios_locked struct\n"); + goto cleanup_pcxe_termios; + } memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs); init_bh(DIGI_BH,do_pcxe_bh); @@ -1512,7 +1536,13 @@ if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3)) shrinkmem = 1; - request_region(bd->port, 4, "PC/Xx"); + bd->region = request_region(bd->port, 4, "PC/Xx"); + + if (!bd->region) { + printk(KERN_ERR "I/O port 0x%x is already used\n", bd->port); + ret = -EBUSY; + goto cleanup_boards; + } for(i=0; i < bd->numports; i++, ch++, bc++) { if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) { @@ -1562,6 +1592,12 @@ ch->txbufsize = bc->tmax + 1; ch->rxbufsize = bc->rmax + 1; ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); + + if (!ch->tmp_buf) { + printk(KERN_ERR "Unable to allocate memory for temp buffers\n"); + goto cleanup_boards; + } + lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2; fepcmd(ch, STXLWATER, lowwater, 0, 10, 0); fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0); @@ -1608,14 +1644,21 @@ if (enabled_cards <= 0) { printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n"); - return -EIO; + ret = -EIO; + goto cleanup_boards; } - if(tty_register_driver(&pcxe_driver)) - panic("Couldn't register PC/Xe driver"); + ret = tty_register_driver(&pcxe_driver); + if(ret) { + printk(KERN_ERR "Couldn't register PC/Xe driver\n"); + goto cleanup_boards; + } - if(tty_register_driver(&pcxe_callout)) - panic("Couldn't register PC/Xe callout"); + ret = tty_register_driver(&pcxe_callout); + if(ret) { + printk(KERN_ERR "Couldn't register PC/Xe callout\n"); + goto cleanup_pcxe_driver; + } /* * Start up the poller to check for events on all enabled boards @@ -1626,6 +1669,13 @@ printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards); return 0; +cleanup_pcxe_driver: tty_unregister_driver(&pcxe_driver); +cleanup_boards: cleanup_board_resources(); + kfree(pcxe_termios_locked); +cleanup_pcxe_termios: kfree(pcxe_termios); +cleanup_pcxe_table: kfree(pcxe_table); +cleanup_digi_channels: kfree(digi_channels); + return ret; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/pcxx.h linux/drivers/char/pcxx.h --- v2.4.0-test6/linux/drivers/char/pcxx.h Sat May 15 15:05:36 1999 +++ linux/drivers/char/pcxx.h Tue Aug 22 15:21:54 2000 @@ -51,6 +51,7 @@ ulong membase; ulong memsize; ushort first_minor; + void *region; }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/planb.c linux/drivers/char/planb.c --- v2.4.0-test6/linux/drivers/char/planb.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/planb.c Wed Dec 31 16:00:00 1969 @@ -1,2341 +0,0 @@ -/* - planb - PlanB frame grabber driver - - PlanB is used in the 7x00/8x00 series of PowerMacintosh - Computers as video input DMA controller. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - - Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) - - 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. -*/ - -/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "planb.h" -#include "saa7196.h" - - -/* Would you mind for some ugly debugging? */ -//#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */ -#define DEBUG(x...) /* Don't debug driver */ -//#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */ -#define IDEBUG(x...) /* Don't debug interrupt part */ - -/* Ever seen a Mac with more than 1 of these? */ -#define PLANB_MAX 1 - -static int planb_num; -static struct planb planbs[PLANB_MAX]; -static volatile struct planb_registers *planb_regs; - -static int def_norm = PLANB_DEF_NORM; /* default norm */ - -MODULE_PARM(def_norm, "i"); -MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); - -/* ------------------ PlanB Exported Functions ------------------ */ -static long planb_write(struct video_device *, const char *, unsigned long, int); -static long planb_read(struct video_device *, char *, unsigned long, int); -static int planb_open(struct video_device *, int); -static void planb_close(struct video_device *); -static int planb_ioctl(struct video_device *, unsigned int, void *); -static int planb_init_done(struct video_device *); -static int planb_mmap(struct video_device *, const char *, unsigned long); -static void planb_irq(int, void *, struct pt_regs *); -static void release_planb(void); -int init_planbs(struct video_init *); - -/* ------------------ PlanB Internal Functions ------------------ */ -static int planb_prepare_open(struct planb *); -static void planb_prepare_close(struct planb *); -static void saa_write_reg(unsigned char, unsigned char); -static unsigned char saa_status(int, struct planb *); -static void saa_set(unsigned char, unsigned char, struct planb *); -static void saa_init_regs(struct planb *); -static int grabbuf_alloc(struct planb *); -static int vgrab(struct planb *, struct video_mmap *); -static void add_clip(struct planb *, struct video_clip *); -static void fill_cmd_buff(struct planb *); -static void cmd_buff(struct planb *); -static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *); -static void overlay_start(struct planb *); -static void overlay_stop(struct planb *); -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short, - unsigned int); -static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int, - unsigned int); -static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short, - unsigned short, unsigned int, unsigned int); -static int init_planb(struct planb *); -static int find_planb(void); -static void planb_pre_capture(int, int, struct planb *); -static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *, - int, int, int, int, int, struct planb *); -static inline void planb_dbdma_stop(volatile struct dbdma_regs *); -static unsigned int saa_geo_setup(int, int, int, int, struct planb *); -static inline int overlay_is_active(struct planb *); - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -static int grabbuf_alloc(struct planb *pb) -{ - int i, npage; - - npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1) -#ifndef PLANB_GSCANLINE - + MAX_LNUM -#endif /* PLANB_GSCANLINE */ - ); - if ((pb->rawbuf = (unsigned char**) kmalloc (npage - * sizeof(unsigned long), GFP_KERNEL)) == 0) - return -ENOMEM; - for (i = 0; i < npage; i++) { - pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL - |GFP_DMA, 0); - if (!pb->rawbuf[i]) - break; - mem_map_reserve(virt_to_page(pb->rawbuf[i])); - } - if (i-- < npage) { - printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); - for (; i > 0; i--) { - mem_map_unreserve(virt_to_page(pb->rawbuf[i])); - free_pages((unsigned long)pb->rawbuf[i], 0); - } - kfree(pb->rawbuf); - return -ENOBUFS; - } - pb->rawbuf_size = npage; - return 0; -} - -/*****************************/ -/* Hardware access functions */ -/*****************************/ - -static void saa_write_reg(unsigned char addr, unsigned char val) -{ - planb_regs->saa_addr = addr; eieio(); - planb_regs->saa_regval = val; eieio(); - return; -} - -/* return status byte 0 or 1: */ -static unsigned char saa_status(int byte, struct planb *pb) -{ - saa_regs[pb->win.norm][SAA7196_STDC] = - (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1); - saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]); - - /* Let's wait 30msec for this one */ - current->state = TASK_INTERRUPTIBLE; -#if LINUX_VERSION_CODE >= 0x02017F - schedule_timeout(30 * HZ / 1000); -#else - current->timeout = jiffies + 30 * HZ / 1000; /* 30 ms */; - schedule(); -#endif - - return (unsigned char)in_8 (&planb_regs->saa_status); -} - -static void saa_set(unsigned char addr, unsigned char val, struct planb *pb) -{ - if(saa_regs[pb->win.norm][addr] != val) { - saa_regs[pb->win.norm][addr] = val; - saa_write_reg (addr, val); - } - return; -} - -static void saa_init_regs(struct planb *pb) -{ - int i; - - for (i = 0; i < SAA7196_NUMREGS; i++) - saa_write_reg (i, saa_regs[pb->win.norm][i]); -} - -static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp, - struct planb *pb) -{ - int ht, norm = pb->win.norm; - - switch(bpp) { - case 2: - /* RGB555+a 1x16-bit + 16-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x3; - break; - case 1: - case 4: - /* RGB888 1x24-bit + 8-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x1; - saa_regs[norm][SAA7196_FMTS] |= 0x2; - break; - default: - return -EINVAL; - } - ht = (interlace ? height / 2 : height); - saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff); - saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3) - | (width >> 8 & 0x3); - saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff); - saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3) - | (ht >> 8 & 0x3); - /* feed both fields if interlaced, or else feed only even fields */ - saa_regs[norm][SAA7196_FMTS] = (interlace) ? - (saa_regs[norm][SAA7196_FMTS] & ~0x60) - : (saa_regs[norm][SAA7196_FMTS] | 0x60); - /* transparent mode; extended format enabled */ - saa_regs[norm][SAA7196_DPATH] |= 0x3; - - return 0; -} - -/***************************/ -/* DBDMA support functions */ -/***************************/ - -static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch) -{ - out_le32(&ch->control, PLANB_CLR(RUN)); - out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE)); -} - -static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch) -{ - int i = 0; - - out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH)); - while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { - IDEBUG("PlanB: waiting for DMA to stop\n"); - i++; - } -} - -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned int cmd_dep) -{ - st_le16(&ch->command, command); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static inline void tab_cmd_store(volatile struct dbdma_cmd *ch, - unsigned int phy_addr, unsigned int cmd_dep) -{ - st_le16(&ch->command, STORE_WORD | KEY_SYSTEM); - st_le16(&ch->req_count, 4); - st_le32(&ch->phy_addr, phy_addr); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned short req_count, - unsigned int phy_addr, unsigned int cmd_dep) -{ - st_le16(&ch->command, command); - st_le16(&ch->req_count, req_count); - st_le32(&ch->phy_addr, phy_addr); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static volatile struct dbdma_cmd *cmd_geo_setup( - volatile struct dbdma_cmd *c1, int width, int height, int interlace, - int bpp, int clip, struct planb *pb) -{ - int norm = pb->win.norm; - - if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0) - return (volatile struct dbdma_cmd *)NULL; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_FMTS); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_FMTS]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_DPATH); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_DPATH]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTPIX); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTPIX]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_HFILT); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_HFILT]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTLINE); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTLINE]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_VYP); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_VYP]); - return c1; -} - -/******************************/ -/* misc. supporting functions */ -/******************************/ - -static void __planb_wait(struct planb *pb) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&pb->lockq, &wait); -repeat: - set_current_state(TASK_UNINTERRUPTIBLE); - if (pb->lock) { - schedule(); - goto repeat; - } - remove_wait_queue(&pb->lockq, &wait); - current->state = TASK_RUNNING; -} - -static inline void planb_wait(struct planb *pb) -{ - DEBUG("PlanB: planb_wait\n"); - if(pb->lock) - __planb_wait(pb); -} - -static inline void planb_lock(struct planb *pb) -{ - DEBUG("PlanB: planb_lock\n"); - if(pb->lock) - __planb_wait(pb); - pb->lock = 1; -} - -static inline void planb_unlock(struct planb *pb) -{ - DEBUG("PlanB: planb_unlock\n"); - pb->lock = 0; - wake_up(&pb->lockq); -} - -/***************/ -/* Driver Core */ -/***************/ - -static int planb_prepare_open(struct planb *pb) -{ - int i, size; - - /* allocate memory for two plus alpha command buffers (size: max lines, - plus 40 commands handling, plus 1 alignment), plus dummy command buf, - plus clipmask buffer, plus frame grabbing status */ - size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS - * PLANB_DUMMY)*sizeof(struct dbdma_cmd) - +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 - +MAX_GBUFFERS*sizeof(unsigned int); - if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0) - return -ENOMEM; - memset ((void *) pb->priv_space, 0, size); - pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) - DBDMA_ALIGN (pb->priv_space); - pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; - pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd); - pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size; - pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR; - for (i = 1; i < MAX_GBUFFERS; i++) { - pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY; - pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR; - } - pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1] - + PLANB_DUMMY); - pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); - - pb->rawbuf = NULL; - pb->rawbuf_size = 0; - pb->grabbing = 0; - for (i = 0; i < MAX_GBUFFERS; i++) { - pb->frame_stat[i] = GBUFFER_UNUSED; - pb->gwidth[i] = 0; - pb->gheight[i] = 0; - pb->gfmt[i] = 0; - pb->gnorm_switch[i] = 0; -#ifndef PLANB_GSCANLINE - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif /* PLANB_GSCANLINE */ - } - pb->gcount = 0; - pb->suspend = 0; - pb->last_fr = -999; - pb->prev_last_fr = -999; - - /* Reset DMA controllers */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - return 0; -} - -static void planb_prepare_close(struct planb *pb) -{ - int i; - - /* make sure the dma's are idle */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - /* free kernel memory of command buffers */ - if(pb->priv_space != 0) { - kfree (pb->priv_space); - pb->priv_space = 0; - pb->cmd_buff_inited = 0; - } - if(pb->rawbuf) { - for (i = 0; i < pb->rawbuf_size; i++) { - mem_map_unreserve(virt_to_page(pb->rawbuf[i])); - free_pages((unsigned long)pb->rawbuf[i], 0); - } - kfree(pb->rawbuf); - } - pb->rawbuf = NULL; -} - -/*****************************/ -/* overlay support functions */ -/*****************************/ - -static void overlay_start(struct planb *pb) -{ - - DEBUG("PlanB: overlay_start()\n"); - - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - - DEBUG("PlanB: presumably, grabbing is in progress...\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - out_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - planb_dbdma_restart(&pb->planb_base->ch2); - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - eieio(); - pb->prev_last_fr = pb->last_fr; - pb->last_fr = -2; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - IDEBUG("PlanB: became inactive " - "in the mean time... reactivating\n"); - planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } else { - - DEBUG("PlanB: currently idle, so can do whatever\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - st_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - st_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - planb_dbdma_restart(&pb->planb_base->ch2); - planb_dbdma_restart(&pb->planb_base->ch1); - pb->last_fr = -1; - } - return; -} - -static void overlay_stop(struct planb *pb) -{ - DEBUG("PlanB: overlay_stop()\n"); - - if(pb->last_fr == -1) { - - DEBUG("PlanB: no grabbing, it seems...\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->last_fr = -999; - } else if(pb->last_fr == -2) { - unsigned int cmd_dep; - tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); - eieio(); - cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); - if(overlay_is_active(pb)) { - - DEBUG("PlanB: overlay is currently active\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - if(cmd_dep != pb->ch1_cmd_phys) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } - pb->last_fr = pb->prev_last_fr; - pb->prev_last_fr = -999; - } - return; -} - -static void suspend_overlay(struct planb *pb) -{ - int fr = -1; - struct dbdma_cmd last; - - DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); - - if(pb->suspend++) - return; - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - if(pb->last_fr == -2) { - fr = pb->prev_last_fr; - memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - } - if(overlay_is_active(pb)) { - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->suspended.overlay = 1; - pb->suspended.frame = fr; - memcpy(&pb->suspended.cmd, &last, sizeof(last)); - return; - } - } - pb->suspended.overlay = 0; - pb->suspended.frame = fr; - memcpy(&pb->suspended.cmd, &last, sizeof(last)); - return; -} - -static void resume_overlay(struct planb *pb) -{ - - DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); - - if(pb->suspend > 1) - return; - if(pb->suspended.frame != -1) { - memcpy((void*)pb->last_cmd[pb->suspended.frame], - &pb->suspended.cmd, sizeof(pb->suspended.cmd)); - } - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - goto finish; - } - if(pb->suspended.overlay) { - - DEBUG("PlanB: overlay being resumed\n"); - - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); - /* Set command buffer addresses */ - st_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - out_le32(&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->overlay_last2)); - /* Start the DMA controller */ - out_le32 (&pb->planb_base->ch2.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - } else if(pb->suspended.frame != -1) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->last_cmd[pb->suspended.frame])); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - } - -finish: - pb->suspend--; - wake_up_interruptible(&pb->suspendq); -} - -static void add_clip(struct planb *pb, struct video_clip *clip) -{ - volatile unsigned char *base; - int xc = clip->x, yc = clip->y; - int wc = clip->width, hc = clip->height; - int ww = pb->win.width, hw = pb->win.height; - int x, y, xtmp1, xtmp2; - - DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); - - if(xc < 0) { - wc += xc; - xc = 0; - } - if(yc < 0) { - hc += yc; - yc = 0; - } - if(xc + wc > ww) - wc = ww - xc; - if(wc <= 0) /* Nothing to do */ - return; - if(yc + hc > hw) - hc = hw - yc; - - for (y = yc; y < yc+hc; y++) { - xtmp1=xc>>3; - xtmp2=(xc+wc)>>3; - base = pb->mask + y*96; - if(xc != 0 || wc >= 8) - *(base + xtmp1) &= (unsigned char)(0x00ff & - (0xff00 >> (xc&7))); - for (x = xtmp1 + 1; x < xtmp2; x++) { - *(base + x) = 0; - } - if(xc < (ww & ~0x7)) - *(base + xtmp2) &= (unsigned char)(0x00ff >> - ((xc+wc) & 7)); - } - - return; -} - -static void fill_cmd_buff(struct planb *pb) -{ - int restore = 0; - volatile struct dbdma_cmd last; - - DEBUG("PlanB: fill_cmd_buff()\n"); - - if(pb->overlay_last1 != pb->ch1_cmd) { - restore = 1; - last = *(pb->overlay_last1); - } - memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size - * sizeof(struct dbdma_cmd)); - cmd_buff (pb); - if(restore) - *(pb->overlay_last1) = last; - if(pb->suspended.overlay) { - unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep); - if(jump_addr != pb->ch1_cmd_phys) { - int i; - - DEBUG("PlanB: adjusting ch1's jump address\n"); - - for(i = 0; i < MAX_GBUFFERS; i++) { - if(pb->need_pre_capture[i]) { - if(jump_addr == virt_to_bus(pb->pre_cmd[i])) - goto found; - } else { - if(jump_addr == virt_to_bus(pb->cap_cmd[i])) - goto found; - } - } - - DEBUG("PlanB: not found...\n"); - - goto out; -found: - if(pb->need_pre_capture[i]) - out_le32(&pb->pre_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); - else - out_le32(&pb->cap_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); - } - } -out: - pb->cmd_buff_inited = 1; - - return; -} - -static void cmd_buff(struct planb *pb) -{ - int i, bpp, count, nlines, stepsize, interlace; - unsigned long base, jump, addr_com, addr_dep; - volatile struct dbdma_cmd *c1 = pb->ch1_cmd; - volatile struct dbdma_cmd *c2 = pb->ch2_cmd; - - interlace = pb->win.interlace; - bpp = pb->win.bpp; - count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ? - (pb->win.swidth - pb->win.x) : pb->win.width)); - nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ? - (pb->win.sheight - pb->win.y) : pb->win.height); - - /* Do video in: */ - - /* Preamble commands: */ - addr_com = virt_to_bus(c1); - addr_dep = virt_to_bus(&c1->cmd_dep); - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ - if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, - bpp, 1, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); - tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); - return; - } - tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); - tab_cmd_store(c1++, addr_dep, jump); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - /* (1) wait for field sync to be set */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - /* wait for field sync to be cleared */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - /* if not odd field, wait until field sync is set again */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl - + pb->win.pad) + pb->win.x * bpp); - - if (interlace) { - stepsize = 2; - jump = virt_to_bus(c1 + (nlines + 1) / 2); - } else { - stepsize = 1; - jump = virt_to_bus(c1 + nlines); - } - - /* even field data: */ - for (i=0; i < nlines; i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, - count, base + i * (pb->win.bpl + pb->win.pad), jump); - - /* For non-interlaced, we use even fields only */ - if (!interlace) - goto cmd_tab_data_end; - - /* Resync to odd field */ - /* (2) wait for field sync to be set */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - /* wait for field sync to be cleared */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - /* if not odd field, wait until field sync is set again */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - /* odd field data: */ - jump = virt_to_bus(c1 + nlines / 2); - for (i=1; i < nlines; i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + i * (pb->win.bpl + pb->win.pad), jump); - - /* And jump back to the start */ -cmd_tab_data_end: - pb->overlay_last1 = c1; /* keep a pointer to the last command */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd)); - - /* Clipmask command buffer */ - - /* Preamble commands: */ - tab_cmd_dbdma(c2++, DBDMA_NOP, 0); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), - PLANB_SET(CH_SYNC)); - /* wait until ch1 asserts ch_sync */ - tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); - /* clear ch_sync asserted by ch1 */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_CLR(CH_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(ODD_FIELD)); - - /* jump to end of even field if appropriate */ - /* this points to (interlace)? pos. C: pos. B */ - jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2): - virt_to_bus(c2 + nlines + 2); - /* if odd field, skip over to odd field clipmasking */ - tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); - - /* even field mask: */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(DMA_ABORT)); - /* this points to pos. B */ - jump = (interlace) ? virt_to_bus(c2 + nlines + 1): - virt_to_bus(c2 + nlines); - base = virt_to_bus(pb->mask); - for (i=0; i < nlines; i += stepsize, c2++) - tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, - base + i * 96, jump); - - /* For non-interlaced, we use only even fields */ - if(!interlace) - goto cmd_tab_mask_end; - - /* odd field mask: */ -/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(DMA_ABORT)); - /* this points to pos. B */ - jump = virt_to_bus(c2 + nlines / 2); - base = virt_to_bus(pb->mask); - for (i=1; i < nlines; i += 2, c2++) /* abort if set */ - tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, - base + i * 96, jump); - - /* Inform channel 1 and jump back to start */ -cmd_tab_mask_end: - /* ok, I just realized this is kind of flawed. */ - /* this part is reached only after odd field clipmasking. */ - /* wanna clean up? */ - /* wait for field sync to be set */ - /* corresponds to fsync (1) of ch1 */ -/* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); - /* restart ch1, meant to clear any dead bit or something */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), - PLANB_CLR(RUN)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), - PLANB_SET(RUN)); - pb->overlay_last2 = c2; /* keep a pointer to the last command */ - /* start over even field clipmasking */ - tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd)); - - eieio(); - return; -} - -/*********************************/ -/* grabdisplay support functions */ -/*********************************/ - -static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; - -#define PLANB_PALETTE_MAX 15 - -static inline int overlay_is_active(struct planb *pb) -{ - unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); - unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr); - - return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys) - && (caddr < (pb->ch1_cmd_phys + size)) - && (caddr >= (unsigned)pb->ch1_cmd_phys); -} - -static int vgrab(struct planb *pb, struct video_mmap *mp) -{ - unsigned int fr = mp->frame; - unsigned int format; - - if(pb->rawbuf==NULL) { - int err; - if((err=grabbuf_alloc(pb))) - return err; - } - - IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, - mp->width, mp->height, fr); - - if(pb->grabbing >= MAX_GBUFFERS) - return -ENOBUFS; - if(fr > (MAX_GBUFFERS - 1) || fr < 0) - return -EINVAL; - if(mp->height <= 0 || mp->width <= 0) - return -EINVAL; - if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) - return -EINVAL; - if((format = palette2fmt[mp->format]) == 0) - return -EINVAL; - if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ - return -EINVAL; - - planb_lock(pb); - if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || - format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { - int i; -#ifndef PLANB_GSCANLINE - unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] - * pb->gfmt[fr]; - unsigned int nsize = mp->width * mp->height * format; -#endif - - IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", - mp->width, mp->height, mp->format); - -#ifndef PLANB_GSCANLINE - if(pb->gnorm_switch[fr]) - nsize = 0; - if (nsize < osize) { - for(i = pb->gbuf_idx[fr]; osize > 0; i++) { - memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); - osize -= PAGE_SIZE; - } - } - for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] - + pb->lnum[fr]; i++) - memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); -#else -/* XXX TODO */ -/* - if(pb->gnorm_switch[fr]) - memset((void *)pb->gbuffer[fr], 0, - pb->gbytes_per_line * pb->gheight[fr]); - else { - if(mp-> - for(i = 0; i < pb->gheight[fr]; i++) { - memset((void *)(pb->gbuffer[fr] - + pb->gbytes_per_line * i - } - } -*/ -#endif - pb->gwidth[fr] = mp->width; - pb->gheight[fr] = mp->height; - pb->gfmt[fr] = format; - pb->last_cmd[fr] = setup_grab_cmd(fr, pb); - planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */ - pb->need_pre_capture[fr] = 1; - pb->gnorm_switch[fr] = 0; - } else - pb->need_pre_capture[fr] = 0; - pb->frame_stat[fr] = GBUFFER_GRABBING; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - - IDEBUG("PlanB: ch1 inactive, initiating grabbing\n"); - - planb_dbdma_stop(&pb->planb_base->ch1); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->pre_cmd[fr])); - } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - /* let's be on the safe side. here is not timing critical. */ - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); - } - planb_dbdma_restart(&pb->planb_base->ch1); - pb->last_fr = fr; - } else { - int i; - - IDEBUG("PlanB: ch1 active, grabbing being queued\n"); - - if((pb->last_fr == -1) || ((pb->last_fr == -2) && - overlay_is_active(pb))) { - - IDEBUG("PlanB: overlay is active, grabbing defered\n"); - - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_store(pb->pre_cmd[fr], - virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->pre_cmd[fr])); - } else { - tab_cmd_store(pb->cap_cmd[fr], - virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->cap_cmd[fr])); - } - for(i = 0; overlay_is_active(pb) && i < 999; i++) - IDEBUG("PlanB: waiting for overlay done\n"); - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - pb->prev_last_fr = fr; - pb->last_fr = -2; - } else if(pb->last_fr == -2) { - - IDEBUG("PlanB: mixed mode detected, grabbing" - " will be done before activating overlay\n"); - - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); - eieio(); - } else { - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->prev_last_fr] != - pb->gwidth[fr] - || pb->gheight[pb->prev_last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->prev_last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); - eieio(); - } - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - eieio(); - pb->prev_last_fr = fr; - pb->last_fr = -2; - } else { - - IDEBUG("PlanB: active grabbing session detected\n"); - - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); - eieio(); - } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->last_fr] != pb->gwidth[fr] - || pb->gheight[pb->last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); - eieio(); - } - pb->last_fr = fr; - } - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - - IDEBUG("PlanB: became inactive in the mean time..." - "reactivating\n"); - - planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } - pb->grabbing++; - planb_unlock(pb); - - return 0; -} - -static void planb_pre_capture(int fr, int bpp, struct planb *pb) -{ - volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr]; - int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered some problems\n"); - tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0); - return; - } - /* Sync to even field */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - /* For non-interlaced, we use even fields only */ - if (pb->gheight[fr] <= pb->maxlines/2) - goto cmd_tab_data_end; - /* Sync to odd field */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); -cmd_tab_data_end: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr])); - - eieio(); -} - -static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) -{ - int i, bpp, count, nlines, stepsize, interlace; -#ifdef PLANB_GSCANLINE - int scanline; -#else - int nlpp, leftover1; - unsigned long base; -#endif - unsigned long jump; - int pagei; - volatile struct dbdma_cmd *c1; - volatile struct dbdma_cmd *jump_addr; - - c1 = pb->cap_cmd[fr]; - interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - bpp = pb->gfmt[fr]; /* gfmt = bpp */ - count = bpp * pb->gwidth[fr]; - nlines = pb->gheight[fr]; -#ifdef PLANB_GSCANLINE - scanline = pb->gbytes_per_line; -#else - pb->lsize[fr] = count; - pb->lnum[fr] = 0; -#endif - - /* Do video in: */ - - /* Preamble commands: */ - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0); - return (pb->cap_cmd[fr] + 2); - } - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - if (interlace) { - stepsize = 2; - jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2; - } else { - stepsize = 1; - jump_addr = c1 + TAB_FACTOR * nlines; - } - jump = virt_to_bus(jump_addr); - - /* even field data: */ - - pagei = pb->gbuf_idx[fr]; -#ifdef PLANB_GSCANLINE - for (i = 0; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); - } -#else - i = 0; - leftover1 = 0; - do { - int j; - - base = virt_to_bus(pb->rawbuf[pagei]); - nlpp = (PAGE_SIZE - leftover1) / count / stepsize; - for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, - count, base + count * j * stepsize + leftover1, jump); - if(i < nlines) { - int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; - - if(lov0 == 0) - leftover1 = 0; - else { - if(lov0 >= count) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base - + count * nlpp * stepsize + leftover1, jump); - } else { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] - + count * nlpp * stepsize + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; - } - leftover1 = count * stepsize - lov0; - i += stepsize; - } - } - pagei++; - } while(i < nlines); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); - c1 = jump_addr; -#endif /* PLANB_GSCANLINE */ - - /* For non-interlaced, we use even fields only */ - if (!interlace) - goto cmd_tab_data_end; - - /* Sync to odd field */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - /* odd field data: */ - jump_addr = c1 + TAB_FACTOR * nlines / 2; - jump = virt_to_bus(jump_addr); -#ifdef PLANB_GSCANLINE - for (i = 1; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); - } -#else - i = 1; - leftover1 = 0; - pagei = pb->gbuf_idx[fr]; - if(nlines <= 1) - goto skip; - do { - int j; - - base = virt_to_bus(pb->rawbuf[pagei]); - nlpp = (PAGE_SIZE - leftover1) / count / stepsize; - if(leftover1 >= count) { - tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + leftover1 - count, jump); - i += stepsize; - } - for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + count * (j * stepsize + 1) + leftover1, jump); - if(i < nlines) { - int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; - - if(lov0 == 0) - leftover1 = 0; - else { - if(lov0 > count) { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] - + count * (nlpp * stepsize + 1) + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize - - lov0; - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; - i += stepsize; - } - leftover1 = count * stepsize - lov0; - } - } - pagei++; - } while(i < nlines); -skip: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); - c1 = jump_addr; -#endif /* PLANB_GSCANLINE */ - -cmd_tab_data_end: - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), - (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); - /* stop it */ - tab_cmd_dbdma(c1, DBDMA_STOP, 0); - - eieio(); - return c1; -} - -static void planb_irq(int irq, void *dev_id, struct pt_regs * regs) -{ - unsigned int stat, astat; - struct planb *pb = (struct planb *)dev_id; - - IDEBUG("PlanB: planb_irq()\n"); - - /* get/clear interrupt status bits */ - eieio(); - stat = in_le32(&pb->planb_base->intr_stat); - astat = stat & pb->intr_mask; - out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ - & ~astat & stat & ~PLANB_GEN_IRQ); - IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); - - if(astat & PLANB_FRM_IRQ) { - unsigned int fr = stat >> 9; -#ifndef PLANB_GSCANLINE - int i; -#endif - IDEBUG("PlanB: PLANB_FRM_IRQ\n"); - - pb->gcount++; - - IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n", - pb->grabbing, fr, pb->gcount); -#ifndef PLANB_GSCANLINE - IDEBUG("PlanB: %d * %d bytes are being copied over\n", - pb->lnum[fr], pb->lsize[fr]); - for(i = 0; i < pb->lnum[fr]; i++) { - int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; - - memcpy(pb->l_to_addr[fr][i], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i], - first); - memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, - pb->l_to_next_size[fr][i]); - } -#endif - pb->frame_stat[fr] = GBUFFER_DONE; - pb->grabbing--; - wake_up_interruptible(&pb->capq); - return; - } - /* incorrect interrupts? */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts" - " unconditionally\n"); -} - -/******************************* - * Device Operations functions * - *******************************/ - -static int planb_open(struct video_device *dev, int mode) -{ - struct planb *pb = (struct planb *)dev; - - if (pb->user == 0) { - int err; - if((err = planb_prepare_open(pb)) != 0) - return err; - } - pb->user++; - - DEBUG("PlanB: device opened\n"); - - MOD_INC_USE_COUNT; - return 0; -} - -static void planb_close(struct video_device *dev) -{ - struct planb *pb = (struct planb *)dev; - - if(pb->user < 1) /* ??? */ - return; - planb_lock(pb); - if (pb->user == 1) { - if (pb->overlay) { - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->overlay = 0; - } - planb_prepare_close(pb); - } - pb->user--; - planb_unlock(pb); - - DEBUG("PlanB: device closed\n"); - - MOD_DEC_USE_COUNT; -} - -static long planb_read(struct video_device *v, char *buf, unsigned long count, - int nonblock) -{ - DEBUG("planb: read request\n"); - return -EINVAL; -} - -static long planb_write(struct video_device *v, const char *buf, - unsigned long count, int nonblock) -{ - DEBUG("planb: write request\n"); - return -EINVAL; -} - -static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct planb *pb=(struct planb *)dev; - - switch (cmd) - { - case VIDIOCGCAP: - { - struct video_capability b; - - DEBUG("PlanB: IOCTL VIDIOCGCAP\n"); - - strcpy (b.name, pb->video_dev.name); - b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | VID_TYPE_SCALES | - VID_TYPE_CAPTURE; - b.channels = 2; /* composite & svhs */ - b.audios = 0; - b.maxwidth = PLANB_MAXPIXELS; - b.maxheight = PLANB_MAXLINES; - b.minwidth = 32; /* wild guess */ - b.minheight = 32; - if (copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer v; - unsigned short bpp; - unsigned int fmt; - - DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); - - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) - return -EPERM; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - planb_lock(pb); - switch(v.depth) { - case 8: - bpp = 1; - fmt = PLANB_GRAY; - break; - case 15: - case 16: - bpp = 2; - fmt = PLANB_COLOUR15; - break; - case 24: - case 32: - bpp = 4; - fmt = PLANB_COLOUR32; - break; - default: - planb_unlock(pb); - return -EINVAL; - } - if (bpp * v.width > v.bytesperline) { - planb_unlock(pb); - return -EINVAL; - } - pb->win.bpp = bpp; - pb->win.color_fmt = fmt; - pb->frame_buffer_phys = (unsigned long) v.base; - pb->win.sheight = v.height; - pb->win.swidth = v.width; - pb->picture.depth = pb->win.depth = v.depth; - pb->win.bpl = pb->win.bpp * pb->win.swidth; - pb->win.pad = v.bytesperline - pb->win.bpl; - - DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d," - " bpl %d (+ %d)\n", v.base, v.width,v.height, - pb->win.bpp, pb->win.bpl, pb->win.pad); - - pb->cmd_buff_inited = 0; - if(pb->overlay) { - suspend_overlay(pb); - fill_cmd_buff(pb); - resume_overlay(pb); - } - planb_unlock(pb); - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer v; - - DEBUG("PlanB: IOCTL VIDIOCGFBUF\n"); - - v.base = (void *)pb->frame_buffer_phys; - v.height = pb->win.sheight; - v.width = pb->win.swidth; - v.depth = pb->win.depth; - v.bytesperline = pb->win.bpl + pb->win.pad; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCCAPTURE: - { - int i; - - if(copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - if(i==0) { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); - - if (!(pb->overlay)) - return 0; - planb_lock(pb); - pb->overlay = 0; - overlay_stop(pb); - planb_unlock(pb); - } else { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); - - if (pb->frame_buffer_phys == 0 || - pb->win.width == 0 || - pb->win.height == 0) - return -EINVAL; - if (pb->overlay) - return 0; - planb_lock(pb); - pb->overlay = 1; - if(!(pb->cmd_buff_inited)) - fill_cmd_buff(pb); - overlay_start(pb); - planb_unlock(pb); - } - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel v; - - DEBUG("PlanB: IOCTL VIDIOCGCHAN\n"); - - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - v.flags = 0; - v.tuners = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = pb->win.norm; - switch(v.channel) - { - case 0: - strcpy(v.name,"Composite"); - break; - case 1: - strcpy(v.name,"SVHS"); - break; - default: - return -EINVAL; - break; - } - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel v; - - DEBUG("PlanB: IOCTL VIDIOCSCHAN\n"); - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - if (v.norm != pb->win.norm) { - int i, maxlines; - - switch (v.norm) - { - case VIDEO_MODE_PAL: - case VIDEO_MODE_SECAM: - maxlines = PLANB_MAXLINES; - break; - case VIDEO_MODE_NTSC: - maxlines = PLANB_NTSC_MAXLINES; - break; - default: - return -EINVAL; - break; - } - planb_lock(pb); - /* empty the grabbing queue */ - while(pb->grabbing) - interruptible_sleep_on(&pb->capq); - pb->maxlines = maxlines; - pb->win.norm = v.norm; - /* Stop overlay if running */ - suspend_overlay(pb); - for(i = 0; i < MAX_GBUFFERS; i++) - pb->gnorm_switch[i] = 1; - /* I know it's an overkill, but.... */ - fill_cmd_buff(pb); - /* ok, now init it accordingly */ - saa_init_regs (pb); - /* restart overlay if it was running */ - resume_overlay(pb); - planb_unlock(pb); - } - - switch(v.channel) - { - case 0: /* Composite */ - saa_set (SAA7196_IOCC, - ((saa_regs[pb->win.norm][SAA7196_IOCC] & - ~7) | 3), pb); - break; - case 1: /* SVHS */ - saa_set (SAA7196_IOCC, - ((saa_regs[pb->win.norm][SAA7196_IOCC] & - ~7) | 4), pb); - break; - default: - return -EINVAL; - break; - } - - return 0; - } - case VIDIOCGPICT: - { - struct video_picture vp = pb->picture; - - DEBUG("PlanB: IOCTL VIDIOCGPICT\n"); - - switch(pb->win.color_fmt) { - case PLANB_GRAY: - vp.palette = VIDEO_PALETTE_GREY; - case PLANB_COLOUR15: - vp.palette = VIDEO_PALETTE_RGB555; - break; - case PLANB_COLOUR32: - vp.palette = VIDEO_PALETTE_RGB32; - break; - default: - vp.palette = 0; - break; - } - - if(copy_to_user(arg,&vp,sizeof(vp))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture vp; - - DEBUG("PlanB: IOCTL VIDIOCSPICT\n"); - - if(copy_from_user(&vp,arg,sizeof(vp))) - return -EFAULT; - pb->picture = vp; - /* Should we do sanity checks here? */ - saa_set (SAA7196_BRIG, (unsigned char) - ((pb->picture.brightness) >> 8), pb); - saa_set (SAA7196_HUEC, (unsigned char) - ((pb->picture.hue) >> 8) ^ 0x80, pb); - saa_set (SAA7196_CSAT, (unsigned char) - ((pb->picture.colour) >> 9), pb); - saa_set (SAA7196_CONT, (unsigned char) - ((pb->picture.contrast) >> 9), pb); - - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip clip; - int i; - - DEBUG("PlanB: IOCTL VIDIOCSWIN\n"); - - if(copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - - planb_lock(pb); - /* Stop overlay if running */ - suspend_overlay(pb); - pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0; - if (pb->win.x != vw.x || - pb->win.y != vw.y || - pb->win.width != vw.width || - pb->win.height != vw.height || - !pb->cmd_buff_inited) { - pb->win.x = vw.x; - pb->win.y = vw.y; - pb->win.width = vw.width; - pb->win.height = vw.height; - fill_cmd_buff(pb); - } - /* Reset clip mask */ - memset ((void *) pb->mask, 0xff, (pb->maxlines - * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); - /* Add any clip rects */ - for (i = 0; i < vw.clipcount; i++) { - if (copy_from_user(&clip, vw.clips + i, - sizeof(struct video_clip))) - return -EFAULT; - add_clip(pb, &clip); - } - /* restart overlay if it was running */ - resume_overlay(pb); - planb_unlock(pb); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - - DEBUG("PlanB: IOCTL VIDIOCGWIN\n"); - - vw.x=pb->win.x; - vw.y=pb->win.y; - vw.width=pb->win.width; - vw.height=pb->win.height; - vw.chromakey=0; - vw.flags=0; - if(pb->win.interlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - if(copy_to_user(arg,&vw,sizeof(vw))) - return -EFAULT; - return 0; - } - case VIDIOCSYNC: { - int i; - - IDEBUG("PlanB: IOCTL VIDIOCSYNC\n"); - - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - - IDEBUG("PlanB: sync to frame %d\n", i); - - if(i > (MAX_GBUFFERS - 1) || i < 0) - return -EINVAL; -chk_grab: - switch (pb->frame_stat[i]) { - case GBUFFER_UNUSED: - return -EINVAL; - case GBUFFER_GRABBING: - IDEBUG("PlanB: waiting for grab" - " done (%d)\n", i); - interruptible_sleep_on(&pb->capq); - if(signal_pending(current)) - return -EINTR; - goto chk_grab; - case GBUFFER_DONE: - pb->frame_stat[i] = GBUFFER_UNUSED; - break; - } - return 0; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - volatile unsigned int status; - - IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n"); - - if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) - return -EFAULT; - status = pb->frame_stat[vm.frame]; - if (status != GBUFFER_UNUSED) - return -EBUSY; - - return vgrab(pb, &vm); - } - - case VIDIOCGMBUF: - { - int i; - struct video_mbuf vm; - - DEBUG("PlanB: IOCTL VIDIOCGMBUF\n"); - - memset(&vm, 0 , sizeof(vm)); - vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; - vm.frames = MAX_GBUFFERS; - for(i = 0; i= SAA7196_NUMREGS) - return -EINVAL; - preg.val = saa_regs[pb->win.norm][preg.addr]; - if(copy_to_user((void *)arg, (void *)&preg, - sizeof(preg))) - return -EFAULT; - return 0; - } - - case PLANBIOCSSAAREGS: - { - struct planb_saa_regs preg; - - DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); - - if(copy_from_user(&preg, arg, sizeof(preg))) - return -EFAULT; - if(preg.addr >= SAA7196_NUMREGS) - return -EINVAL; - saa_set (preg.addr, preg.val, pb); - return 0; - } - - case PLANBIOCGSTAT: - { - struct planb_stat_regs pstat; - - DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); - - pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); - pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); - pstat.saa_stat0 = saa_status(0, pb); - pstat.saa_stat1 = saa_status(1, pb); - - if(copy_to_user((void *)arg, (void *)&pstat, - sizeof(pstat))) - return -EFAULT; - return 0; - } - - case PLANBIOCSMODE: { - int v; - - DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - switch(v) - { - case PLANB_TV_MODE: - saa_set (SAA7196_STDC, - (saa_regs[pb->win.norm][SAA7196_STDC] & - 0x7f), pb); - break; - case PLANB_VTR_MODE: - saa_set (SAA7196_STDC, - (saa_regs[pb->win.norm][SAA7196_STDC] | - 0x80), pb); - break; - default: - return -EINVAL; - break; - } - pb->win.mode = v; - return 0; - } - case PLANBIOCGMODE: { - int v=pb->win.mode; - - DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } -#ifdef PLANB_GSCANLINE - case PLANBG_GRAB_BPL: { - int v=pb->gbytes_per_line; - - DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } -#endif /* PLANB_GSCANLINE */ - case PLANB_INTR_DEBUG: { - int i; - - DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); - - if(copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - /* avoid hang ups all together */ - for (i = 0; i < MAX_GBUFFERS; i++) { - if(pb->frame_stat[i] == GBUFFER_GRABBING) { - pb->frame_stat[i] = GBUFFER_DONE; - } - } - if(pb->grabbing) - pb->grabbing--; - wake_up_interruptible(&pb->capq); - return 0; - } - case PLANB_INV_REGS: { - int i; - struct planb_any_regs any; - - DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); - - if(copy_from_user(&any, arg, sizeof(any))) - return -EFAULT; - if(any.offset < 0 || any.offset + any.bytes > 0x400) - return -EINVAL; - if(any.bytes > 128) - return -EINVAL; - for (i = 0; i < any.bytes; i++) { - any.data[i] = - in_8((unsigned char *)pb->planb_base - + any.offset + i); - } - if(copy_to_user(arg,&any,sizeof(any))) - return -EFAULT; - return 0; - } - default: - { - DEBUG("PlanB: Unimplemented IOCTL\n"); - return -ENOIOCTLCMD; - } - /* Some IOCTLs are currently unsupported on PlanB */ - case VIDIOCGTUNER: { - DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); - goto unimplemented; } - case VIDIOCSTUNER: { - DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); - goto unimplemented; } - case VIDIOCSFREQ: { - DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); - goto unimplemented; } - case VIDIOCGFREQ: { - DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); - goto unimplemented; } - case VIDIOCKEY: { - DEBUG("PlanB: IOCTL VIDIOCKEY\n"); - goto unimplemented; } - case VIDIOCSAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); - goto unimplemented; } - case VIDIOCGAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); - goto unimplemented; } -unimplemented: - DEBUG(" Unimplemented\n"); - return -ENOIOCTLCMD; - } - return 0; -} - -static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - int i; - struct planb *pb = (struct planb *)dev; - unsigned long start = (unsigned long)adr; - - if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) - return -EINVAL; - if (!pb->rawbuf) { - int err; - if((err=grabbuf_alloc(pb))) - return err; - } - for (i = 0; i < pb->rawbuf_size; i++) { - if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), - PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - if (size <= PAGE_SIZE) - break; - size -= PAGE_SIZE; - } - return 0; -} - -/* This gets called upon device registration */ -/* we could do some init here */ -static int planb_init_done(struct video_device *dev) -{ - return 0; -} - -static struct video_device planb_template= -{ - PLANB_DEVICE_NAME, - VID_TYPE_OVERLAY, - VID_HARDWARE_PLANB, - planb_open, - planb_close, - planb_read, - planb_write, -#if LINUX_VERSION_CODE >= 0x020100 - NULL, /* poll */ -#endif - planb_ioctl, - planb_mmap, /* mmap? */ - planb_init_done, - NULL, /* pointer to private data */ - 0, - 0 -}; - -static int init_planb(struct planb *pb) -{ - unsigned char saa_rev; - int i, result; - unsigned long flags; - - memset ((void *) &pb->win, 0, sizeof (struct planb_window)); - /* Simple sanity check */ - if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { - printk(KERN_ERR "PlanB: Option(s) invalid\n"); - return -2; - } - pb->win.norm = def_norm; - pb->win.mode = PLANB_TV_MODE; /* TV mode */ - pb->win.interlace=1; - pb->win.x=0; - pb->win.y=0; - pb->win.width=768; /* 640 */ - pb->win.height=576; /* 480 */ - pb->maxlines=576; -#if 0 - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; -#endif - pb->win.pad=0; - pb->win.bpp=4; - pb->win.depth=32; - pb->win.color_fmt=PLANB_COLOUR32; - pb->win.bpl=1024*pb->win.bpp; - pb->win.swidth=1024; - pb->win.sheight=768; -#ifdef PLANB_GSCANLINE - if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE - || (pb->gbytes_per_line <= 0)) - return -3; - else { - /* page align pb->gbytes_per_line for DMA purpose */ - for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) - i>>=1; - pb->gbytes_per_line = i; - } -#endif - pb->tab_size = PLANB_MAXLINES + 40; - pb->suspend = 0; - pb->lock = 0; - init_waitqueue_head(&pb->lockq); - pb->ch1_cmd = 0; - pb->ch2_cmd = 0; - pb->mask = 0; - pb->priv_space = 0; - pb->offset = 0; - pb->user = 0; - pb->overlay = 0; - init_waitqueue_head(&pb->suspendq); - pb->cmd_buff_inited = 0; - pb->frame_buffer_phys = 0; - - /* Reset DMA controllers */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - saa_rev = (saa_status(0, pb) & 0xf0) >> 4; - printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev); - /* Initialize the SAA registers in memory and on chip */ - saa_init_regs (pb); - - /* clear interrupt mask */ - pb->intr_mask = PLANB_CLR_IRQ; - - save_flags(flags); cli(); - result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb); - if (result < 0) { - if (result==-EINVAL) - printk(KERN_ERR "PlanB: Bad irq number (%d) " - "or handler\n", (int)pb->irq); - else if (result==-EBUSY) - printk(KERN_ERR "PlanB: I don't know why, " - "but IRQ %d is busy\n", (int)pb->irq); - restore_flags(flags); - return result; - } - disable_irq(pb->irq); - restore_flags(flags); - - /* Now add the template and register the device unit. */ - memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); - - pb->picture.brightness=0x90<<8; - pb->picture.contrast = 0x70 << 8; - pb->picture.colour = 0x70<<8; - pb->picture.hue = 0x8000; - pb->picture.whiteness = 0; - pb->picture.depth = pb->win.depth; - - pb->frame_stat=NULL; - init_waitqueue_head(&pb->capq); - for(i=0; igbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; - pb->gwidth[i]=0; - pb->gheight[i]=0; - pb->gfmt[i]=0; - pb->cap_cmd[i]=NULL; -#ifndef PLANB_GSCANLINE - pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF - / PAGE_SIZE + 1) + MAX_LNUM * i; - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif - } - pb->rawbuf=NULL; - pb->grabbing=0; - - /* enable interrupts */ - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - pb->intr_mask = PLANB_FRM_IRQ; - enable_irq(pb->irq); - - if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0) - return -1; - - return 0; -} - -/* - * Scan for a PlanB controller, request the irq and map the io memory - */ - -static int find_planb(void) -{ - struct planb *pb; - struct device_node *planb_devices; - unsigned char dev_fn, confreg, bus; - unsigned int old_base, new_base; - unsigned int irq; - struct pci_dev *pdev; - - if (_machine != _MACH_Pmac) - return 0; - - planb_devices = find_devices("planb"); - if (planb_devices == 0) { - planb_num=0; - printk(KERN_WARNING "PlanB: no device found!\n"); - return planb_num; - } - - if (planb_devices->next != NULL) - printk(KERN_ERR "Warning: only using first PlanB device!\n"); - pb = &planbs[0]; - planb_num = 1; - - if (planb_devices->n_addrs != 1) { - printk (KERN_WARNING "PlanB: expecting 1 address for planb " - "(got %d)", planb_devices->n_addrs); - return 0; - } - - if (planb_devices->n_intrs == 0) { - printk(KERN_WARNING "PlanB: no intrs for device %s\n", - planb_devices->full_name); - return 0; - } else { - irq = planb_devices->intrs[0].line; - } - - /* Initialize PlanB's PCI registers */ - - /* There is a bug with the way OF assigns addresses - to the devices behind the chaos bridge. - control needs only 0x1000 of space, but decodes only - the upper 16 bits. It therefore occupies a full 64K. - OF assigns the planb controller memory within this space; - so we need to change that here in order to access planb. */ - - /* We remap to 0xf1000000 in hope that nobody uses it ! */ - - bus = (planb_devices->addrs[0].space >> 16) & 0xff; - dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; - confreg = planb_devices->addrs[0].space & 0xff; - old_base = planb_devices->addrs[0].address; - new_base = 0xf1000000; - - DEBUG("PlanB: Found on bus %d, dev %d, func %d, " - "membase 0x%x (base reg. 0x%x)\n", - bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); - - pdev = pci_find_slot (bus, dev_fn); - if (!pdev) { - printk(KERN_ERR "cannot find slot\n"); - /* XXX handle error */ - } - - /* Enable response in memory space, bus mastering, - use memory write and invalidate */ - pci_write_config_word (pdev, PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - PCI_COMMAND_INVALIDATE); - /* Set PCI Cache line size & latency timer */ - pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, 0x8); - pci_write_config_byte (pdev, PCI_LATENCY_TIMER, 0x40); - - /* Set the new base address */ - pci_write_config_dword (pdev, confreg, new_base); - - planb_regs = (volatile struct planb_registers *) - ioremap (new_base, 0x400); - pb->planb_base = planb_regs; - pb->planb_base_phys = (struct planb_registers *)new_base; - pb->irq = irq; - - return planb_num; -} - -static void release_planb(void) -{ - int i; - struct planb *pb; - - for (i=0;iplanb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - /* clear and free interrupts */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - free_irq(pb->irq, pb); - - /* make sure all allocated memory are freed */ - planb_prepare_close(pb); - - printk(KERN_INFO "PlanB: unregistering with v4l\n"); - video_unregister_device(&pb->video_dev); - - /* note that iounmap() does nothing on the PPC right now */ - iounmap ((void *)pb->planb_base); - } -} - -#ifdef MODULE - -int init_module(void) -{ -#else -int __init init_planbs(struct video_init *unused) -{ -#endif - int i; - - if (find_planb()<=0) - return -EIO; - - for (i=0; i -#include "saa7196.h" -#endif /* __KERNEL__ */ - -#define PLANB_DEVICE_NAME "Apple PlanB Video-In" -#define PLANB_REV "1.0" - -#ifdef __KERNEL__ -//#define PLANB_GSCANLINE /* use this if apps have the notion of */ - /* grab buffer scanline */ -/* This should be safe for both PAL and NTSC */ -#define PLANB_MAXPIXELS 768 -#define PLANB_MAXLINES 576 -#define PLANB_NTSC_MAXLINES 480 - -/* Uncomment your preferred norm ;-) */ -#define PLANB_DEF_NORM VIDEO_MODE_PAL -//#define PLANB_DEF_NORM VIDEO_MODE_NTSC -//#define PLANB_DEF_NORM VIDEO_MODE_SECAM - -/* fields settings */ -#define PLANB_GRAY 0x1 /* 8-bit mono? */ -#define PLANB_COLOUR15 0x2 /* 16-bit mode */ -#define PLANB_COLOUR32 0x4 /* 32-bit mode */ -#define PLANB_CLIPMASK 0x8 /* hardware clipmasking */ - -/* misc. flags for PlanB DMA operation */ -#define CH_SYNC 0x1 /* synchronize channels (set by ch1; - cleared by ch2) */ -#define FIELD_SYNC 0x2 /* used for the start of each field - (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */ -#define EVEN_FIELD 0x0 /* even field is detected if unset */ -#define DMA_ABORT 0x2 /* error or just out of sync if set */ -#define ODD_FIELD 0x4 /* odd field is detected if set */ - -/* for capture operations */ -#define MAX_GBUFFERS 2 -/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ -#ifdef PLANB_GSCANLINE -#define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ -#define TAB_FACTOR (1) -#else -#define PLANB_MAX_FBUF 0x1b0000 /* 576 * 768 * 4 */ -#define TAB_FACTOR (2) -#endif -#endif /* __KERNEL__ */ - -struct planb_saa_regs { - unsigned char addr; - unsigned char val; -}; - -struct planb_stat_regs { - unsigned int ch1_stat; - unsigned int ch2_stat; - unsigned char saa_stat0; - unsigned char saa_stat1; -}; - -struct planb_any_regs { - unsigned int offset; - unsigned int bytes; - unsigned char data[128]; -}; - -/* planb private ioctls */ -#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) /* Read a saa7196 reg value */ -#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) /* Set a saa7196 reg value */ -#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) /* Read planb status */ -#define PLANB_TV_MODE 1 -#define PLANB_VTR_MODE 2 -#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) /* Get TV/VTR mode */ -#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) /* Set TV/VTR mode */ - -#ifdef PLANB_GSCANLINE -#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) /* # of bytes per scanline in grab buffer */ -#endif - -/* call wake_up_interruptible() with appropriate actions */ -#define PLANB_INTR_DEBUG _IOW('v', BASE_VIDIOCPRIVATE + 20, int) -/* investigate which reg does what */ -#define PLANB_INV_REGS _IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs) - -#ifdef __KERNEL__ - -/* Potentially useful macros */ -#define PLANB_SET(x) ((x) << 16 | (x)) -#define PLANB_CLR(x) ((x) << 16) - -/* This represents the physical register layout */ -struct planb_registers { - volatile struct dbdma_regs ch1; /* 0x00: video in */ - volatile unsigned int even; /* 0x40: even field setting */ - volatile unsigned int odd; /* 0x44; odd field setting */ - unsigned int pad1[14]; /* empty? */ - volatile struct dbdma_regs ch2; /* 0x80: clipmask out */ - unsigned int pad2[16]; /* 0xc0: empty? */ - volatile unsigned int reg3; /* 0x100: ???? */ - volatile unsigned int intr_stat; /* 0x104: irq status */ -#define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ -#define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ -#define PLANB_FRM_IRQ 0x0100 /* end of frame */ - unsigned int pad3[1]; /* empty? */ - volatile unsigned int reg5; /* 0x10c: ??? */ - unsigned int pad4[60]; /* empty? */ - volatile unsigned char saa_addr; /* 0x200: SAA subadr */ - char pad5[3]; - volatile unsigned char saa_regval; /* SAA7196 write reg. val */ - char pad6[3]; - volatile unsigned char saa_status; /* SAA7196 status byte */ - /* There is more unused stuff here */ -}; - -struct planb_window { - int x, y; - ushort width, height; - ushort bpp, bpl, depth, pad; - ushort swidth, sheight; - int norm; - int interlace; - u32 color_fmt; - int chromakey; - int mode; /* used to switch between TV/VTR modes */ -}; - -struct planb_suspend { - int overlay; - int frame; - struct dbdma_cmd cmd; -}; - -struct planb { - struct video_device video_dev; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ - - volatile struct planb_registers *planb_base; /* virt base of planb */ - struct planb_registers *planb_base_phys; /* phys base of planb */ - void *priv_space; /* Org. alloc. mem for kfree */ - int user; - unsigned int tab_size; - int maxlines; - int lock; - wait_queue_head_t lockq; - unsigned int irq; /* interrupt number */ - volatile unsigned int intr_mask; - - int overlay; /* overlay running? */ - struct planb_window win; - unsigned long frame_buffer_phys; /* We need phys for DMA */ - int offset; /* offset of pixel 1 */ - volatile struct dbdma_cmd *ch1_cmd; /* Video In DMA cmd buffer */ - volatile struct dbdma_cmd *ch2_cmd; /* Clip Out DMA cmd buffer */ - volatile struct dbdma_cmd *overlay_last1; - volatile struct dbdma_cmd *overlay_last2; - unsigned long ch1_cmd_phys; - volatile unsigned char *mask; /* Clipmask buffer */ - int suspend; - wait_queue_head_t suspendq; - struct planb_suspend suspended; - int cmd_buff_inited; /* cmd buffer inited? */ - - int grabbing; - unsigned int gcount; - wait_queue_head_t capq; - int last_fr; - int prev_last_fr; - unsigned char **rawbuf; - int rawbuf_size; - int gbuf_idx[MAX_GBUFFERS]; - volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; - int need_pre_capture[MAX_GBUFFERS]; -#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ - int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS]; - unsigned int gfmt[MAX_GBUFFERS]; - int gnorm_switch[MAX_GBUFFERS]; - volatile unsigned int *frame_stat; -#define GBUFFER_UNUSED 0x00U -#define GBUFFER_GRABBING 0x01U -#define GBUFFER_DONE 0x02U -#ifdef PLANB_GSCANLINE - int gbytes_per_line; -#else -#define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ - /* PLANB_MAXPIXELS changes */ - int l_fr_addr_idx[MAX_GBUFFERS]; - unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; - int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; -#endif -}; - -#endif /* __KERNEL__ */ - -#endif /* _PLANB_H_ */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/pms.c linux/drivers/char/pms.c --- v2.4.0-test6/linux/drivers/char/pms.c Thu Nov 11 20:11:34 1999 +++ linux/drivers/char/pms.c Wed Dec 31 16:00:00 1969 @@ -1,1074 +0,0 @@ -/* - * 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@redhat.com 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); -} - -static int pms_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); -} - -static int pms_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; -} - -static int pms_i2c_read(int slave, int sub) -{ - int i=0; - for(i=0;i>8)&0x01); -} - -#endif - -static void pms_secamcross(short cross) -{ - if(decoder==PHILIPS2) - pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5); - else if(decoder==PHILIPS1) - pms_i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5); -} - - -static void pms_swsense(short sense) -{ - if(decoder==PHILIPS2) - { - pms_i2c_write(0x8A, 0x0A, sense); - pms_i2c_write(0x8A, 0x0B, sense); - } - else if(decoder==PHILIPS1) - { - pms_i2c_write(0x42, 0x0A, sense); - pms_i2c_write(0x42, 0x0B, sense); - } -} - - -static void pms_framerate(short frr) -{ - int fps=(standard==1)?30:25; - if(frr==0) - return; - fps=fps/frr; - mvv_write(0x14,0x80|fps); - mvv_write(0x15,1); -} - -static void pms_vert(u8 deciden, u8 decinum) -{ - mvv_write(0x1C, deciden); /* Denominator */ - mvv_write(0x1D, decinum); /* Numerator */ -} - -/* - * Turn 16bit ratios into best small ratio the chipset can grok - */ - -static void pms_vertdeci(unsigned short decinum, unsigned short deciden) -{ - /* Knock it down by /5 once */ - if(decinum%5==0) - { - deciden/=5; - decinum/=5; - } - /* - * 3's - */ - while(decinum%3==0 && deciden%3==0) - { - deciden/=3; - decinum/=3; - } - /* - * 2's - */ - while(decinum%2==0 && deciden%2==0) - { - decinum/=2; - deciden/=2; - } - /* - * Fudgyify - */ - while(deciden>32) - { - 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|deciden)&1)==0) - { - decinum>>=1; - deciden>>=1; - } - while(deciden>32) - { - deciden>>=1; - decinum=(decinum+1)>>1; - } - if(deciden==32) - deciden--; - - mvv_write(0x24, 0x80|deciden); - mvv_write(0x25, decinum); -} - -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>fg_height) - 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); -} - - -/* - * Set Input - */ - -static void pms_vcrinput(short input) -{ - if(decoder==PHILIPS2) - pms_i2c_andor(0x8A,0x0D,0x7F,(input&1)<<7); - else if(decoder==PHILIPS1) - pms_i2c_andor(0x42,0x0D,0x7F,(input&1)<<7); -} - - -static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count) -{ - int y; - int dw = 2*dev->width; - u32 src = mem_base; - - char tmp[dw+32]; /* using a temp buffer is faster than direct */ - int cnt = 0; - int len=0; - unsigned char r8 = 0x5; /* value for reg8 */ - - if (rgb555) - r8 |= 0x20; /* else use untranslated rgb = 565 */ - mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */ - -/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */ - - for (y = 0; y < dev->height; y++ ) - { - isa_writeb(0, src); /* synchronisiert neue Zeile */ - - /* - * This is in truth a fifo, be very careful as if you - * forgot this odd things will occur 8) - */ - - isa_memcpy_fromio(tmp, src, dw+32); /* discard 16 word */ - cnt -= dev->height; - while (cnt <= 0) - { - /* - * Don't copy too far - */ - int dt=dw; - if(dt+len>count) - dt=count-len; - cnt += dev->height; - copy_to_user(buf, tmp+32, dt); - buf += dt; - len += dt; - } - } - 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; - switch(v.channel) - { - case 0: - strcpy(v.name, "Composite");break; - case 1: - strcpy(v.name, "SVideo");break; - case 2: - strcpy(v.name, "Composite(VCR)");break; - case 3: - strcpy(v.name, "SVideo(VCR)");break; - } - 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>>8); - pms_hue(p.hue>>8); - pms_colour(p.colour>>8); - pms_contrast(p.contrast>>8); - 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, - NULL, /* FIXME - we can use POLL on this board with the irq */ - 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=pms_i2c_stat(0x43); - - if(decst!=-1) - idec=2; - else if(pms_i2c_stat(0xb9)!=-1) - idec=3; - else if(pms_i2c_stat(0x8b)!=-1) - idec=1; - else - idec=0; - - printk(KERN_INFO "PMS type is %d\n", idec); - 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) - pms_i2c_andor(0x8A, i, 0x07,0x00); - else - pms_i2c_write(0x8A, i, i2c_defs[i]); - } - - pms_i2c_write(0xB8,0x00,0x12); - pms_i2c_write(0xB8,0x04,0x00); - pms_i2c_write(0xB8,0x07,0x00); - pms_i2c_write(0xB8,0x08,0x00); - pms_i2c_write(0xB8,0x09,0xFF); - pms_i2c_write(0xB8,0x0A,0x00); - pms_i2c_write(0xB8,0x0B,0x10); - pms_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; -} - -/* - * Initialization and module stuff - */ - -static int __init init_pms_cards(void) -{ - printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n"); - - data_port = io_port +1; - - 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_swsense(75); - pms_resolution(320,240); - return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER); -} - -MODULE_PARM(io_port,"i"); -MODULE_PARM(mem_base,"i"); - -static void __exit shutdown_mediavision(void) -{ - release_region(io_port,3); - release_region(0x9A01, 1); -} - -static void __exit cleanup_pms_module(void) -{ - shutdown_mediavision(); - video_unregister_device((struct video_device *)&pms_device); -} - -module_init(init_pms_cards); -module_exit(cleanup_pms_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-aimslab.c linux/drivers/char/radio-aimslab.c --- v2.4.0-test6/linux/drivers/char/radio-aimslab.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/radio-aimslab.c Wed Dec 31 16:00:00 1969 @@ -1,390 +0,0 @@ -/* radiotrack (radioreveal) driver for Linux radio support - * (c) 1997 M. Kirkwood - * Coverted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * - * History: - * 1999-02-24 Russell Kroll - * Fine tuning/VIDEO_TUNER_LOW - * Frequency range expanded to start at 87 MHz - * - * TODO: Allow for more than one of these foolish entities :-) - * - * Notes on the hardware (reverse engineered from other peoples' - * reverse engineering of AIMS' code :-) - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * - * The signal strength query is unsurprisingly inaccurate. And it seems - * to indicate that (on my card, at least) the frequency setting isn't - * too great. (I have to tune up .025MHz from what the freq should be - * to get a report that the thing is tuned.) - * - * Volume control is (ugh) analogue: - * out(port, start_increasing_volume); - * wait(a_wee_while); - * out(port, stop_changing_the_volume); - * - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_RTRACK_PORT */ -#include /* Lock for the I/O */ - -#ifndef CONFIG_RADIO_RTRACK_PORT -#define CONFIG_RADIO_RTRACK_PORT -1 -#endif - -static int io = CONFIG_RADIO_RTRACK_PORT; -static int users = 0; -static struct semaphore lock; - -struct rt_device -{ - int port; - int curvol; - unsigned long curfreq; - int muted; -}; - - -/* local things */ - -static void sleep_delay(long n) -{ - /* Sleep nicely for 'n' uS */ - int d=n/(1000000/HZ); - if(!d) - udelay(n); - else - { - /* Yield CPU time */ - unsigned long x=jiffies; - while((jiffies-x)<=d) - schedule(); - } -} - -static void rt_decvol(void) -{ - outb(0x58, io); /* volume down + sigstr + on */ - sleep_delay(100000); - outb(0xd8, io); /* volume steady + sigstr + on */ -} - -static void rt_incvol(void) -{ - outb(0x98, io); /* volume up + sigstr + on */ - sleep_delay(100000); - outb(0xd8, io); /* volume steady + sigstr + on */ -} - -static void rt_mute(struct rt_device *dev) -{ - dev->muted = 1; - down(&lock); - outb(0xd0, io); /* volume steady, off */ - up(&lock); -} - -static int rt_setvol(struct rt_device *dev, int vol) -{ - int i; - - down(&lock); - - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - outb (0xd8, io); /* enable card */ - } - up(&lock); - return 0; - } - - if(vol == 0) { /* volume = 0 means mute the card */ - outb(0x48, io); /* volume down but still "on" */ - sleep_delay(2000000); /* make sure it's totally down */ - outb(0xd0, io); /* volume steady, off */ - dev->curvol = 0; /* track the volume state! */ - up(&lock); - return 0; - } - - dev->muted = 0; - if(vol > dev->curvol) - for(i = dev->curvol; i < vol; i++) - rt_incvol(); - else - for(i = dev->curvol; i > vol; i--) - rt_decvol(); - - dev->curvol = vol; - up(&lock); - return 0; -} - -/* the 128+64 on these outb's is to keep the volume stable while tuning - * without them, the volume _will_ creep up with each frequency change - * and bit 4 (+16) is to keep the signal strength meter enabled - */ - -void send_0_byte(int port, struct rt_device *dev) -{ - if ((dev->curvol == 0) || (dev->muted)) { - outb_p(128+64+16+ 1, port); /* wr-enable + data low */ - outb_p(128+64+16+2+1, port); /* clock */ - } - else { - outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */ - outb_p(128+64+16+8+2+1, port); /* clock */ - } - sleep_delay(1000); -} - -void send_1_byte(int port, struct rt_device *dev) -{ - if ((dev->curvol == 0) || (dev->muted)) { - outb_p(128+64+16+4 +1, port); /* wr-enable+data high */ - outb_p(128+64+16+4+2+1, port); /* clock */ - } - else { - outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */ - outb_p(128+64+16+8+4+2+1, port); /* clock */ - } - - sleep_delay(1000); -} - -static int rt_setfreq(struct rt_device *dev, unsigned long freq) -{ - int i; - - /* adapted from radio-aztech.c */ - - /* now uses VIDEO_TUNER_LOW for fine tuning */ - - freq += 171200; /* Add 10.7 MHz IF */ - freq /= 800; /* Convert to 50 kHz units */ - - down(&lock); /* Stop other ops interfering */ - - send_0_byte (io, dev); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ - if (freq & (1 << i)) - send_1_byte (io, dev); - else - send_0_byte (io, dev); - - send_0_byte (io, dev); /* 14: test bit - always 0 */ - send_0_byte (io, dev); /* 15: test bit - always 0 */ - - send_0_byte (io, dev); /* 16: band data 0 - always 0 */ - send_0_byte (io, dev); /* 17: band data 1 - always 0 */ - send_0_byte (io, dev); /* 18: band data 2 - always 0 */ - send_0_byte (io, dev); /* 19: time base - always 0 */ - - send_0_byte (io, dev); /* 20: spacing (0 = 25 kHz) */ - send_1_byte (io, dev); /* 21: spacing (1 = 25 kHz) */ - send_0_byte (io, dev); /* 22: spacing (0 = 25 kHz) */ - send_1_byte (io, dev); /* 23: AM/FM (FM = 1, always) */ - - if ((dev->curvol == 0) || (dev->muted)) - outb (0xd0, io); /* volume steady + sigstr */ - else - outb (0xd8, io); /* volume steady + sigstr + on */ - - up(&lock); - - return 0; -} - -static int rt_getsigstr(struct rt_device *dev) -{ - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} - -static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct rt_device *rt=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - strcpy(v.name, "RadioTrack"); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow=(87*16000); - v.rangehigh=(108*16000); - v.flags=VIDEO_TUNER_LOW; - v.mode=VIDEO_MODE_AUTO; - strcpy(v.name, "FM"); - v.signal=0xFFFF*rt_getsigstr(rt); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq))) - return -EFAULT; - rt_setfreq(rt, rt->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - v.volume=rt->curvol * 6554; - v.step=6554; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - - if(v.flags&VIDEO_AUDIO_MUTE) - rt_mute(rt); - else - rt_setvol(rt,v.volume/6554); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int rt_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void rt_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct rt_device rtrack_unit; - -static struct video_device rtrack_radio= -{ - "RadioTrack radio", - VID_TYPE_TUNER, - VID_HARDWARE_RTRACK, - rt_open, - rt_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* No poll */ - rt_ioctl, - NULL, - NULL -}; - -static int __init rtrack_init(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - - if (check_region(io, 2)) - { - printk(KERN_ERR "rtrack: port 0x%x already in use\n", io); - return -EBUSY; - } - - rtrack_radio.priv=&rtrack_unit; - - if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 2, "rtrack"); - printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n"); - - /* Set up the I/O locking */ - - init_MUTEX(&lock); - - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - outb(0x48, io); /* volume down but still "on" */ - sleep_delay(2000000); /* make sure it's totally down */ - outb(0xc0, io); /* steady volume, mute card */ - rtrack_unit.curvol = 0; - - return 0; -} - -MODULE_AUTHOR("M.Kirkwood"); -MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); - -EXPORT_NO_SYMBOLS; - -static void __exit cleanup_rtrack_module(void) -{ - video_unregister_device(&rtrack_radio); - release_region(io,2); -} - -module_init(rtrack_init); -module_exit(cleanup_rtrack_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-aztech.c linux/drivers/char/radio-aztech.c --- v2.4.0-test6/linux/drivers/char/radio-aztech.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/radio-aztech.c Wed Dec 31 16:00:00 1969 @@ -1,330 +0,0 @@ -/* radio-aztech.c - Aztech radio card driver for Linux 2.2 - * - * Adapted to support the Video for Linux API by - * Russell Kroll . Based on original tuner code by: - * - * Quay Ly - * Donald Song - * Jason Lewis (jlewis@twilight.vtc.vsc.edu) - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * - * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ - * along with more information on the card itself. - * - * History: - * 1999-02-24 Russell Kroll - * Fine tuning/VIDEO_TUNER_LOW - * Range expanded to 87-108 MHz (from 87.9-107.8) - * - * Notable changes from the original source: - * - includes stripped down to the essentials - * - for loops used as delays replaced with udelay() - * - #defines removed, changed to static values - * - tuning structure changed - no more character arrays, other changes -*/ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_AZTECH_PORT */ - -/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ - -#ifndef CONFIG_RADIO_AZTECH_PORT -#define CONFIG_RADIO_AZTECH_PORT -1 -#endif - -static int io = CONFIG_RADIO_AZTECH_PORT; -static int radio_wait_time = 1000; -static int users = 0; -static struct semaphore lock; - -struct az_device -{ - int curvol; - unsigned long curfreq; - int stereo; -}; - -static int volconvert(int level) -{ - level>>=14; /* Map 16bits down to 2 bit */ - level&=3; - - /* convert to card-friendly values */ - switch (level) - { - case 0: - return 0; - case 1: - return 1; - case 2: - return 4; - case 3: - return 5; - } - return 0; /* Quieten gcc */ -} - -static void send_0_byte (struct az_device *dev) -{ - udelay(radio_wait_time); - outb_p(2+volconvert(dev->curvol), io); - outb_p(64+2+volconvert(dev->curvol), io); -} - -static void send_1_byte (struct az_device *dev) -{ - udelay (radio_wait_time); - outb_p(128+2+volconvert(dev->curvol), io); - outb_p(128+64+2+volconvert(dev->curvol), io); -} - -static int az_setvol(struct az_device *dev, int vol) -{ - down(&lock); - outb (volconvert(vol), io); - up(&lock); - return 0; -} - -/* thanks to Michael Dwyer for giving me a dose of clues in - * the signal strength department.. - * - * This card has a stereo bit - bit 0 set = mono, not set = stereo - * It also has a "signal" bit - bit 1 set = bad signal, not set = good - * - */ - -static int az_getsigstr(struct az_device *dev) -{ - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} - -static int az_getstereo(struct az_device *dev) -{ - if (inb(io) & 1) /* bit set = mono */ - return 0; - return 1; /* stereo */ -} - -static int az_setfreq(struct az_device *dev, unsigned long frequency) -{ - int i; - - frequency += 171200; /* Add 10.7 MHz IF */ - frequency /= 800; /* Convert to 50 kHz units */ - - down(&lock); - - send_0_byte (dev); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ - if (frequency & (1 << i)) - send_1_byte (dev); - else - send_0_byte (dev); - - send_0_byte (dev); /* 14: test bit - always 0 */ - send_0_byte (dev); /* 15: test bit - always 0 */ - send_0_byte (dev); /* 16: band data 0 - always 0 */ - if (dev->stereo) /* 17: stereo (1 to enable) */ - send_1_byte (dev); - else - send_0_byte (dev); - - send_1_byte (dev); /* 18: band data 1 - unknown */ - send_0_byte (dev); /* 19: time base - always 0 */ - send_0_byte (dev); /* 20: spacing (0 = 25 kHz) */ - send_1_byte (dev); /* 21: spacing (1 = 25 kHz) */ - send_0_byte (dev); /* 22: spacing (0 = 25 kHz) */ - send_1_byte (dev); /* 23: AM/FM (FM = 1, always) */ - - /* latch frequency */ - - udelay (radio_wait_time); - outb_p(128+64+volconvert(dev->curvol), io); - - up(&lock); - - return 0; -} - -static int az_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct az_device *az=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - strcpy(v.name, "Aztech Radio"); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow=(87*16000); - v.rangehigh=(108*16000); - v.flags=VIDEO_TUNER_LOW; - v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*az_getsigstr(az); - if(az_getstereo(az)) - v.flags|=VIDEO_TUNER_STEREO_ON; - strcpy(v.name, "FM"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &az->curfreq, sizeof(az->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&az->curfreq, arg,sizeof(az->curfreq))) - return -EFAULT; - az_setfreq(az, az->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - if(az->stereo) - v.mode=VIDEO_SOUND_STEREO; - else - v.mode=VIDEO_SOUND_MONO; - v.volume=az->curvol; - v.step=16384; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - az->curvol=v.volume; - - az->stereo=(v.mode&VIDEO_SOUND_STEREO)?1:0; - if(v.flags&VIDEO_AUDIO_MUTE) - az_setvol(az,0); - else - az_setvol(az,az->curvol); - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int az_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void az_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct az_device aztech_unit; - -static struct video_device aztech_radio= -{ - "Aztech radio", - VID_TYPE_TUNER, - VID_HARDWARE_AZTECH, - az_open, - az_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* No poll */ - az_ioctl, - NULL, - NULL -}; - -static int __init aztech_init(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - - if (check_region(io, 2)) - { - printk(KERN_ERR "aztech: port 0x%x already in use\n", io); - return -EBUSY; - } - - init_MUTEX(&lock); - aztech_radio.priv=&aztech_unit; - - if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 2, "aztech"); - printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); - /* mute card - prevents noisy bootups */ - outb (0, io); - return 0; -} - -MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the Aztech radio card."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); - -EXPORT_NO_SYMBOLS; - -static void __exit aztech_cleanup(void) -{ - video_unregister_device(&aztech_radio); - release_region(io,2); -} - -module_init(aztech_init); -module_exit(aztech_cleanup); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c --- v2.4.0-test6/linux/drivers/char/radio-cadet.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/radio-cadet.c Wed Dec 31 16:00:00 1969 @@ -1,603 +0,0 @@ -/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card - * - * by Fred Gleason - * Version 0.3.3 - * - * (Loosely) based on code for the Aztech radio card by - * - * Russell Kroll (rkroll@exploits.org) - * Quay Ly - * Donald Song - * Jason Lewis (jlewis@twilight.vtc.vsc.edu) - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * -*/ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_CADET_PORT */ -#include - -#ifndef CONFIG_RADIO_CADET_PORT -#define CONFIG_RADIO_CADET_PORT 0x330 -#endif -#define RDS_BUFFER 256 - -static int io=CONFIG_RADIO_CADET_PORT; -static int users=0; -static int curtuner=0; -static int tunestat=0; -static int sigstrength=0; -static wait_queue_head_t tunerq,rdsq,readq; -struct timer_list tunertimer,rdstimer,readtimer; -static __u8 rdsin=0,rdsout=0,rdsstat=0; -static unsigned char rdsbuf[RDS_BUFFER]; -static int cadet_lock=0; - -/* - * Signal Strength Threshold Values - * The V4L API spec does not define any particular unit for the signal - * strength value. These values are in microvolts of RF at the tuner's input. - */ -static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; - - - -void cadet_wake(unsigned long qnum) -{ - switch(qnum) { - case 0: /* cadet_setfreq */ - wake_up(&tunerq); - break; - case 1: /* cadet_getrds */ - wake_up(&rdsq); - break; - } -} - - - -static int cadet_getrds(void) -{ - int rdsstat=0; - - cadet_lock++; - outb(3,io); /* Select Decoder Control/Status */ - outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */ - cadet_lock--; - init_timer(&rdstimer); - rdstimer.function=cadet_wake; - rdstimer.data=(unsigned long)1; - rdstimer.expires=jiffies+(HZ/10); - init_waitqueue_head(&rdsq); - add_timer(&rdstimer); - sleep_on(&rdsq); - - cadet_lock++; - outb(3,io); /* Select Decoder Control/Status */ - if((inb(io+1)&0x80)!=0) { - rdsstat|=VIDEO_TUNER_RDS_ON; - } - if((inb(io+1)&0x10)!=0) { - rdsstat|=VIDEO_TUNER_MBS_ON; - } - cadet_lock--; - return rdsstat; -} - - - - -static int cadet_getstereo(void) -{ - if(curtuner!=0) { /* Only FM has stereo capability! */ - return 0; - } - cadet_lock++; - outb(7,io); /* Select tuner control */ - if((inb(io+1)&0x40)==0) { - cadet_lock--; - return 1; /* Stereo pilot detected */ - } - else { - cadet_lock--; - return 0; /* Mono */ - } -} - - - -static unsigned cadet_gettune(void) -{ - int curvol,i; - unsigned fifo=0; - - /* - * Prepare for read - */ - cadet_lock++; - outb(7,io); /* Select tuner control */ - curvol=inb(io+1); /* Save current volume/mute setting */ - outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */ - tunestat=0xffff; - - /* - * Read the shift register - */ - for(i=0;i<25;i++) { - fifo=(fifo<<1)|((inb(io+1)>>7)&0x01); - if(i<24) { - outb(0x01,io+1); - tunestat&=inb(io+1); - outb(0x00,io+1); - } - } - - /* - * Restore volume/mute setting - */ - outb(curvol,io+1); - cadet_lock--; - - return fifo; -} - - - -static unsigned cadet_getfreq(void) -{ - int i; - unsigned freq=0,test,fifo=0; - - /* - * Read current tuning - */ - fifo=cadet_gettune(); - - /* - * Convert to actual frequency - */ - if(curtuner==0) { /* FM */ - test=12500; - for(i=0;i<14;i++) { - if((fifo&0x01)!=0) { - freq+=test; - } - test=test<<1; - fifo=fifo>>1; - } - freq-=10700000; /* IF frequency is 10.7 MHz */ - freq=(freq*16)/1000000; /* Make it 1/16 MHz */ - } - if(curtuner==1) { /* AM */ - freq=((fifo&0x7fff)-2010)*16; - } - - return freq; -} - - - -static void cadet_settune(unsigned fifo) -{ - int i; - unsigned test; - - cadet_lock++; - outb(7,io); /* Select tuner control */ - /* - * Write the shift register - */ - test=0; - test=(fifo>>23)&0x02; /* Align data for SDO */ - test|=0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ - outb(7,io); /* Select tuner control */ - outb(test,io+1); /* Initialize for write */ - for(i=0;i<25;i++) { - test|=0x01; /* Toggle SCK High */ - outb(test,io+1); - test&=0xfe; /* Toggle SCK Low */ - outb(test,io+1); - fifo=fifo<<1; /* Prepare the next bit */ - test=0x1c|((fifo>>23)&0x02); - outb(test,io+1); - } - cadet_lock--; -} - - - -static void cadet_setfreq(unsigned freq) -{ - unsigned fifo; - int i,j,test; - int curvol; - - /* - * Formulate a fifo command - */ - fifo=0; - if(curtuner==0) { /* FM */ - test=102400; - freq=(freq*1000)/16; /* Make it kHz */ - freq+=10700; /* IF is 10700 kHz */ - for(i=0;i<14;i++) { - fifo=fifo<<1; - if(freq>=test) { - fifo|=0x01; - freq-=test; - } - test=test>>1; - } - } - if(curtuner==1) { /* AM */ - fifo=(freq/16)+2010; /* Make it kHz */ - fifo|=0x100000; /* Select AM Band */ - } - - /* - * Save current volume/mute setting - */ - cadet_lock++; - outb(7,io); /* Select tuner control */ - curvol=inb(io+1); - - /* - * Tune the card - */ - for(j=3;j>-1;j--) { - cadet_settune(fifo|(j<<16)); - outb(7,io); /* Select tuner control */ - outb(curvol,io+1); - cadet_lock--; - init_timer(&tunertimer); - tunertimer.function=cadet_wake; - tunertimer.data=(unsigned long)0; - tunertimer.expires=jiffies+(HZ/10); - init_waitqueue_head(&tunerq); - add_timer(&tunertimer); - sleep_on(&tunerq); - cadet_gettune(); - if((tunestat&0x40)==0) { /* Tuned */ - sigstrength=sigtable[curtuner][j]; - return; - } - cadet_lock++; - } - cadet_lock--; - sigstrength=0; -} - - -static int cadet_getvol(void) -{ - cadet_lock++; - outb(7,io); /* Select tuner control */ - if((inb(io+1)&0x20)!=0) { - cadet_lock--; - return 0xffff; - } - else { - cadet_lock--; - return 0; - } -} - - -static void cadet_setvol(int vol) -{ - cadet_lock++; - outb(7,io); /* Select tuner control */ - if(vol>0) { - outb(0x20,io+1); - } - else { - outb(0x00,io+1); - } - cadet_lock--; -} - - - -void cadet_handler(unsigned long data) -{ - /* - * Service the RDS fifo - */ - if(cadet_lock==0) { - outb(0x3,io); /* Select RDS Decoder Control */ - if((inb(io+1)&0x20)!=0) { - printk(KERN_CRIT "cadet: RDS fifo overflow\n"); - } - outb(0x80,io); /* Select RDS fifo */ - while((inb(io)&0x80)!=0) { - rdsbuf[rdsin++]=inb(io+1); - if(rdsin==rdsout) { - printk(KERN_CRIT "cadet: RDS buffer overflow\n"); - } - } - } - - /* - * Service pending read - */ - if( rdsin!=rdsout) { - wake_up_interruptible(&readq); - } - - /* - * Clean up and exit - */ - init_timer(&readtimer); - readtimer.function=cadet_handler; - readtimer.data=(unsigned long)0; - readtimer.expires=jiffies+(HZ/20); - add_timer(&readtimer); -} - - - -static long cadet_read(struct video_device *v,char *buf,unsigned long count, - int nonblock) -{ - int i=0; - unsigned char readbuf[RDS_BUFFER]; - - if(rdsstat==0) { - cadet_lock++; - rdsstat=1; - outb(0x80,io); /* Select RDS fifo */ - cadet_lock--; - init_timer(&readtimer); - readtimer.function=cadet_handler; - readtimer.data=(unsigned long)0; - readtimer.expires=jiffies+(HZ/20); - add_timer(&readtimer); - } - if(rdsin==rdsout) { - if(nonblock) { - return -EWOULDBLOCK; - } - interruptible_sleep_on(&readq); - } - while((i1)) { - return -EINVAL; - } - switch(v.tuner) { - case 0: - strcpy(v.name,"FM"); - v.rangelow=1400; /* 87.5 MHz */ - v.rangehigh=1728; /* 108.0 MHz */ - v.flags=0; - v.mode=0; - v.mode|=VIDEO_MODE_AUTO; - v.signal=sigstrength; - if(cadet_getstereo()==1) { - v.flags|=VIDEO_TUNER_STEREO_ON; - } - v.flags|=cadet_getrds(); - if(copy_to_user(arg,&v, sizeof(v))) { - return -EFAULT; - } - break; - case 1: - strcpy(v.name,"AM"); - v.rangelow=8320; /* 520 kHz */ - v.rangehigh=26400; /* 1650 kHz */ - v.flags=0; - v.flags|=VIDEO_TUNER_LOW; - v.mode=0; - v.mode|=VIDEO_MODE_AUTO; - v.signal=sigstrength; - if(copy_to_user(arg,&v, sizeof(v))) { - return -EFAULT; - } - break; - } - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - if((v.tuner<0)||(v.tuner>1)) { - return -EINVAL; - } - curtuner=v.tuner; - return 0; - } - case VIDIOCGFREQ: - freq=cadet_getfreq(); - if(copy_to_user(arg, &freq, sizeof(freq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&freq, arg,sizeof(freq))) - return -EFAULT; - if((curtuner==0)&&((freq<1400)||(freq>1728))) { - return -EINVAL; - } - if((curtuner==1)&&((freq<8320)||(freq>26400))) { - return -EINVAL; - } - cadet_setfreq(freq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - if(cadet_getstereo()==0) { - v.mode=VIDEO_SOUND_MONO; - } - else { - v.mode=VIDEO_SOUND_STEREO; - } - v.volume=cadet_getvol(); - v.step=0xffff; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - cadet_setvol(v.volume); - if(v.flags&VIDEO_AUDIO_MUTE) - cadet_setvol(0); - else - cadet_setvol(0xffff); - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - - -static int cadet_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - init_waitqueue_head(&readq); - return 0; -} - -static void cadet_close(struct video_device *dev) -{ - if(rdsstat==1) { - del_timer(&readtimer); - rdsstat=0; - } - users--; - MOD_DEC_USE_COUNT; -} - - -static struct video_device cadet_radio= -{ - "Cadet radio", - VID_TYPE_TUNER, - VID_HARDWARE_CADET, - cadet_open, - cadet_close, - cadet_read, - NULL, /* Can't write */ - NULL, /* No poll */ - cadet_ioctl, - NULL, - NULL -}; - -#ifndef MODULE -static int cadet_probe(void) -{ - static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e}; - int i; - - for(i=0;i<8;i++) { - io=iovals[i]; - if(check_region(io,2)>=0) { - cadet_setfreq(1410); - if(cadet_getfreq()==1410) { - return io; - } - } - } - return -1; -} -#endif - -static int __init cadet_init(void) -{ -#ifndef MODULE - io = cadet_probe (); -#endif - - if(io < 0) { -#ifdef MODULE - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); -#endif - return -EINVAL; - } - if (!request_region(io,2,"cadet")) - return -EBUSY; - if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) { - release_region(io,2); - return -EINVAL; - } - printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io); - return 0; -} - - - -MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); - -EXPORT_NO_SYMBOLS; - -static void __exit cadet_cleanup_module(void) -{ - video_unregister_device(&cadet_radio); - release_region(io,2); -} - -module_init(cadet_init); -module_exit(cadet_cleanup_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-gemtek.c linux/drivers/char/radio-gemtek.c --- v2.4.0-test6/linux/drivers/char/radio-gemtek.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/char/radio-gemtek.c Wed Dec 31 16:00:00 1969 @@ -1,319 +0,0 @@ -/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin - * - * GemTek hasn't released any specs on the card, so the protocol had to - * be reverse engineered with dosemu. - * - * Besides the protocol changes, this is mostly a copy of: - * - * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff - * - * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Coverted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * - * TODO: Allow for more than one of these foolish entities :-) - * - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_GEMTEK_PORT */ -#include - -#ifndef CONFIG_RADIO_GEMTEK_PORT -#define CONFIG_RADIO_GEMTEK_PORT -1 -#endif - -static int io = CONFIG_RADIO_GEMTEK_PORT; -static int users = 0; -static spinlock_t lock; - -struct gemtek_device -{ - int port; - unsigned long curfreq; - int muted; -}; - - -/* local things */ - -/* the correct way to mute the gemtek may be to write the last written - * frequency || 0x10, but just writing 0x10 once seems to do it as well - */ -static void gemtek_mute(struct gemtek_device *dev) -{ - if(dev->muted) - return; - spin_lock(&lock); - outb(0x10, io); - spin_unlock(&lock); - dev->muted = 1; -} - -static void gemtek_unmute(struct gemtek_device *dev) -{ - if(dev->muted == 0) - return; - spin_lock(&lock); - outb(0x20, io); - spin_unlock(&lock); - dev->muted = 0; -} - -static void zero(void) -{ - outb_p(0x04, io); - udelay(5); - outb_p(0x05, io); - udelay(5); -} - -static void one(void) -{ - outb_p(0x06, io); - udelay(5); - outb_p(0x07, io); - udelay(5); -} - -static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) -{ - int i; - -/* freq = 78.25*((float)freq/16000.0 + 10.52); */ - - freq /= 16; - freq += 10520; - freq *= 7825; - freq /= 100000; - - spin_lock(&lock); - - /* 2 start bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); - - /* 28 frequency bits (lsb first) */ - for (i = 0; i < 14; i++) - if (freq & (1 << i)) - one(); - else - zero(); - /* 36 unknown bits */ - for (i = 0; i < 11; i++) - zero(); - one(); - for (i = 0; i < 4; i++) - zero(); - one(); - zero(); - - /* 2 end bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); - - spin_unlock(&lock); - - return 0; -} - -int gemtek_getsigstr(struct gemtek_device *dev) -{ - spin_lock(&lock); - inb(io); - udelay(5); - spin_unlock(&lock); - if (inb(io) & 8) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} - -static int gemtek_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct gemtek_device *rt=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - strcpy(v.name, "GemTek"); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow=87*16000; - v.rangehigh=108*16000; - v.flags=VIDEO_TUNER_LOW; - v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*gemtek_getsigstr(rt); - strcpy(v.name, "FM"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq))) - return -EFAULT; - /* needs to be called twice in order for getsigstr to work */ - gemtek_setfreq(rt, rt->curfreq); - gemtek_setfreq(rt, rt->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE; - v.volume=1; - v.step=65535; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - - if(v.flags&VIDEO_AUDIO_MUTE) - gemtek_mute(rt); - else - gemtek_unmute(rt); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int gemtek_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void gemtek_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct gemtek_device gemtek_unit; - -static struct video_device gemtek_radio= -{ - "GemTek radio", - VID_TYPE_TUNER, - VID_HARDWARE_GEMTEK, - gemtek_open, - gemtek_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* Can't poll */ - gemtek_ioctl, - NULL, - NULL -}; - -static int __init gemtek_init(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n"); - return -EINVAL; - } - - if (check_region(io, 4)) - { - printk(KERN_ERR "gemtek: port 0x%x already in use\n", io); - return -EBUSY; - } - - gemtek_radio.priv=&gemtek_unit; - - if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 4, "gemtek"); - printk(KERN_INFO "GemTek Radio Card driver.\n"); - - spin_lock_init(&lock); - /* mute card - prevents noisy bootups */ - outb(0x10, io); - udelay(5); - gemtek_unit.muted = 1; - - /* this is _maybe_ unnecessary */ - outb(0x01, io); - - return 0; -} - -MODULE_AUTHOR("Jonas Munsin"); -MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); - -EXPORT_NO_SYMBOLS; - -static void __exit gemtek_cleanup(void) -{ - video_unregister_device(&gemtek_radio); - release_region(io,4); -} - -module_init(gemtek_init); -module_exit(gemtek_cleanup); - -/* - Local variables: - compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" - End: -*/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-miropcm20.c linux/drivers/char/radio-miropcm20.c --- v2.4.0-test6/linux/drivers/char/radio-miropcm20.c Fri Mar 10 16:40:42 2000 +++ linux/drivers/char/radio-miropcm20.c Wed Dec 31 16:00:00 1969 @@ -1,239 +0,0 @@ -/* Miro PCM20 radio driver for Linux radio support - * (c) 1998 Ruurd Reitsma - * Thanks to Norberto Pellici for the ACI device interface specification - * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c) - * Look there for further info... - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include "../sound/miroaci.h" /* ACI Control by acimixer */ - -static int users = 0; - -struct pcm20_device -{ - int port; - int curvol; - unsigned long curfreq; - int muted; -}; - - -/* local things */ - - -static void pcm20_mute(struct pcm20_device *dev) -{ - - dev->muted = 1; - aci_write_cmd(0xa3,0x01); - -} - -static int pcm20_setvol(struct pcm20_device *dev, int vol) -{ - - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - aci_write_cmd(0xa3,0x00); /* enable card */ - } - - return 0; - } - - if(vol == 0) { /* volume = 0 means mute the card */ - aci_write_cmd(0x3d, 0x20); - aci_write_cmd(0x35, 0x20); - return 0; - } - - dev->muted = 0; - aci_write_cmd(0x3d, 32-vol); /* Right Channel */ - aci_write_cmd(0x35, 32-vol); /* Left Channel */ - dev->curvol = vol; - - return 0; -} - -static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) -{ - unsigned char freql; - unsigned char freqh; - - freq = (freq * 10) / 16; - freql = freq & 0xff; - freqh = freq >> 8; - - - aci_write_cmd_d(0xa7, freql, freqh); /* Tune to frequency */ - - return 0; -} - -int pcm20_getsigstr(struct pcm20_device *dev) -{ - unsigned char buf; - aci_indexed_cmd(0xf0, 0x32, &buf); - if ((buf & 0x80) == 0x80) - return 0; - return 1; /* signal present */ -} - -static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct pcm20_device *pcm20=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - v.type=VID_TYPE_TUNER; - strcpy(v.name, "Miro PCM20"); - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow=(int)(87.5*16); - v.rangehigh=(int)(108.0*16); - v.flags=0; - v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*pcm20_getsigstr(pcm20); - strcpy(v.name, "FM"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq))) - return -EFAULT; - pcm20_setfreq(pcm20, pcm20->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - v.volume=pcm20->curvol * 2048; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - - if(v.flags&VIDEO_AUDIO_MUTE) - pcm20_mute(pcm20); - else - pcm20_setvol(pcm20,v.volume/2048); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int pcm20_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void pcm20_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct pcm20_device pcm20_unit; - -static struct video_device pcm20_radio= -{ - "Miro PCM 20 radio", - VID_TYPE_TUNER, - VID_HARDWARE_RTRACK, - pcm20_open, - pcm20_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* Can't poll */ - pcm20_ioctl, - NULL, - NULL -}; - -static int __init pcm20_init(void) -{ - - pcm20_radio.priv=&pcm20_unit; - - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - printk(KERN_INFO "Miro PCM20 radio card driver.\n"); - - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - - pcm20_unit.curvol = 0; - - return 0; -} - -MODULE_AUTHOR("Ruurd Reitsma"); -MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); - -EXPORT_NO_SYMBOLS; - -static void __exit pcm20_cleanup(void) -{ - video_unregister_device(&pcm20_radio); -} - -module_init(pcm20_init); -module_exit(pcm20_cleanup); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-rtrack2.c linux/drivers/char/radio-rtrack2.c --- v2.4.0-test6/linux/drivers/char/radio-rtrack2.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/char/radio-rtrack2.c Wed Dec 31 16:00:00 1969 @@ -1,280 +0,0 @@ -/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff - * - * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Coverted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * - * TODO: Allow for more than one of these foolish entities :-) - * - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_RTRACK2_PORT */ -#include - -#ifndef CONFIG_RADIO_RTRACK2_PORT -#define CONFIG_RADIO_RTRACK2_PORT -1 -#endif - -static int io = CONFIG_RADIO_RTRACK2_PORT; -static int users = 0; -static spinlock_t lock; - -struct rt_device -{ - int port; - unsigned long curfreq; - int muted; -}; - - -/* local things */ - -static void rt_mute(struct rt_device *dev) -{ - if(dev->muted) - return; - spin_lock(&lock); - outb(1, io); - spin_unlock(&lock); - dev->muted = 1; -} - -static void rt_unmute(struct rt_device *dev) -{ - if(dev->muted == 0) - return; - spin_lock(&lock); - outb(0, io); - spin_unlock(&lock); - dev->muted = 0; -} - -static void zero(void) -{ - outb_p(1, io); - outb_p(3, io); - outb_p(1, io); -} - -static void one(void) -{ - outb_p(5, io); - outb_p(7, io); - outb_p(5, io); -} - -static int rt_setfreq(struct rt_device *dev, unsigned long freq) -{ - int i; - - freq = freq / 200 + 856; - - spin_lock(&lock); - - outb_p(0xc8, io); - outb_p(0xc9, io); - outb_p(0xc9, io); - - for (i = 0; i < 10; i++) - zero (); - - for (i = 14; i >= 0; i--) - if (freq & (1 << i)) - one (); - else - zero (); - - outb_p(0xc8, io); - if (!dev->muted) - outb_p(0, io); - - spin_unlock(&lock); - return 0; -} - -static int rt_getsigstr(struct rt_device *dev) -{ - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} - -static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct rt_device *rt=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - strcpy(v.name, "RadioTrack II"); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow=88*16000; - v.rangehigh=108*16000; - v.flags=VIDEO_TUNER_LOW; - v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*rt_getsigstr(rt); - strcpy(v.name, "FM"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq))) - return -EFAULT; - rt_setfreq(rt, rt->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE; - v.volume=1; - v.step=65535; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - - if(v.flags&VIDEO_AUDIO_MUTE) - rt_mute(rt); - else - rt_unmute(rt); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int rt_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void rt_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct rt_device rtrack2_unit; - -static struct video_device rtrack2_radio= -{ - "RadioTrack II radio", - VID_TYPE_TUNER, - VID_HARDWARE_RTRACK2, - rt_open, - rt_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* Can't poll */ - rt_ioctl, - NULL, - NULL -}; - -static int __init rtrack2_init(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n"); - return -EINVAL; - } - if (check_region(io, 4)) - { - printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io); - return -EBUSY; - } - - rtrack2_radio.priv=&rtrack2_unit; - - spin_lock_init(&lock); - if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 4, "rtrack2"); - printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n"); - - /* mute card - prevents noisy bootups */ - outb(1, io); - rtrack2_unit.muted = 1; - - return 0; -} - -MODULE_AUTHOR("Ben Pfaff"); -MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); - -EXPORT_NO_SYMBOLS; - -static void __exit rtrack2_cleanup_module(void) -{ - video_unregister_device(&rtrack2_radio); - release_region(io,4); -} - -module_init(rtrack2_init); -module_exit(rtrack2_cleanup_module); - -/* - Local variables: - compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" - End: -*/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-sf16fmi.c linux/drivers/char/radio-sf16fmi.c --- v2.4.0-test6/linux/drivers/char/radio-sf16fmi.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/char/radio-sf16fmi.c Wed Dec 31 16:00:00 1969 @@ -1,339 +0,0 @@ -/* SF16FMI radio driver for Linux radio support - * heavily based on rtrack driver... - * (c) 1997 M. Kirkwood - * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz - * - * Fitted to new interface by Alan Cox - * Made working and cleaned up functions - * - * Notes on the hardware - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * No volume control - only mute/unmute - you have to use line volume - * control on SB-part of SF16FMI - * - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_SF16MI_PORT */ -#include - -struct fmi_device -{ - int port; - int curvol; /* 1 or 0 */ - unsigned long curfreq; /* freq in kHz */ - __u32 flags; -}; - -#ifndef CONFIG_RADIO_SF16FMI_PORT -#define CONFIG_RADIO_SF16FMI_PORT -1 -#endif - -static int io = CONFIG_RADIO_SF16FMI_PORT; -static int users = 0; -static struct semaphore lock; - -/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ -/* It is only usefull to give freq in intervall of 800 (=0.05Mhz), - * other bits will be truncated, e.g 92.7400016 -> 92.7, but - * 92.7400017 -> 92.75 - */ -#define RSF16_ENCODE(x) ((x)/800+214) -#define RSF16_MINFREQ 87*16000 -#define RSF16_MAXFREQ 108*16000 - -static void outbits(int bits, unsigned int data, int port) -{ - while(bits--) { - if(data & 1) { - outb(5, port); - udelay(6); - outb(7, port); - udelay(6); - } else { - outb(1, port); - udelay(6); - outb(3, port); - udelay(6); - } - data>>=1; - } -} - -static inline void fmi_mute(int port) -{ - down(&lock); - outb(0x00, port); - up(&lock); -} - -static inline void fmi_unmute(int port) -{ - down(&lock); - outb(0x08, port); - up(&lock); -} - -static inline int fmi_setfreq(struct fmi_device *dev) -{ - int myport = dev->port; - unsigned long freq = dev->curfreq; - int i; - - down(&lock); - - outbits(16, RSF16_ENCODE(freq), myport); - outbits(8, 0xC0, myport); - for(i=0; i< 100; i++) - { - udelay(1400); - if(current->need_resched) - schedule(); - } -/* If this becomes allowed use it ... - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/7); -*/ - - up(&lock); - if (dev->curvol) fmi_unmute(myport); - return 0; -} - -static inline int fmi_getsigstr(struct fmi_device *dev) -{ - int val; - int res; - int myport = dev->port; - int i; - - down(&lock); - val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ - outb(val, myport); - outb(val | 0x10, myport); - for(i=0; i< 100; i++) - { - udelay(1400); - if(current->need_resched) - schedule(); - } -/* If this becomes allowed use it ... - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/7); -*/ - res = (int)inb(myport+1); - outb(val, myport); - - up(&lock); - return (res & 2) ? 0 : 0xFFFF; -} - -static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct fmi_device *fmi=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - strcpy(v.name, "SF16-FMx radio"); - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - int mult; - - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - strcpy(v.name, "FM"); - mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000; - v.rangelow = RSF16_MINFREQ/mult; - v.rangehigh = RSF16_MAXFREQ/mult; - v.flags=fmi->flags; - v.mode=VIDEO_MODE_AUTO; - v.signal = fmi_getsigstr(fmi); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - fmi->flags = v.flags & VIDEO_TUNER_LOW; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - { - unsigned long tmp = fmi->curfreq; - if (!(fmi->flags & VIDEO_TUNER_LOW)) - tmp /= 1000; - if(copy_to_user(arg, &tmp, sizeof(tmp))) - return -EFAULT; - return 0; - } - case VIDIOCSFREQ: - { - unsigned long tmp; - if(copy_from_user(&tmp, arg, sizeof(tmp))) - return -EFAULT; - if (!(fmi->flags & VIDEO_TUNER_LOW)) - tmp *= 1000; - if ( tmpRSF16_MAXFREQ ) - return -EINVAL; - /*rounding in steps of 800 to match th freq - that will be used */ - fmi->curfreq = (tmp/800)*800; - fmi_setfreq(fmi); - return 0; - } - case VIDIOCGAUDIO: - { - struct video_audio v; - v.audio=0; - v.volume=0; - v.bass=0; - v.treble=0; - v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE); - strcpy(v.name, "Radio"); - v.mode=VIDEO_SOUND_STEREO; - v.balance=0; - v.step=0; /* No volume, just (un)mute */ - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - fmi->curvol= v.flags&VIDEO_AUDIO_MUTE ? 0 : 1; - fmi->curvol ? - fmi_unmute(fmi->port) : fmi_mute(fmi->port); - return 0; - } - case VIDIOCGUNIT: - { - struct video_unit v; - v.video=VIDEO_NO_UNIT; - v.vbi=VIDEO_NO_UNIT; - v.radio=dev->minor; - v.audio=0; /* How do we find out this??? */ - v.teletext=VIDEO_NO_UNIT; - if(copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int fmi_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void fmi_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct fmi_device fmi_unit; - -static struct video_device fmi_radio= -{ - "SF16FMx radio", - VID_TYPE_TUNER, - VID_HARDWARE_SF16MI, - fmi_open, - fmi_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* Can't poll */ - fmi_ioctl, - NULL, - NULL -}; - -static int __init fmi_init(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - if (check_region(io, 2)) - { - printk(KERN_ERR "fmi: port 0x%x already in use\n", io); - return -EBUSY; - } - - fmi_unit.port = io; - fmi_unit.curvol = 0; - fmi_unit.curfreq = 0; - fmi_unit.flags = VIDEO_TUNER_LOW; - fmi_radio.priv = &fmi_unit; - - init_MUTEX(&lock); - - if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 2, "fmi"); - printk(KERN_INFO "SF16FMx radio card driver at 0x%x.\n", io); - printk(KERN_INFO "(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n"); - /* mute card - prevents noisy bootups */ - fmi_mute(io); - return 0; -} - -MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); -MODULE_DESCRIPTION("A driver for the SF16MI radio."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); - -EXPORT_NO_SYMBOLS; - -static void __exit fmi_cleanup_module(void) -{ - video_unregister_device(&fmi_radio); - release_region(io,2); -} - -module_init(fmi_init); -module_exit(fmi_cleanup_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-terratec.c linux/drivers/char/radio-terratec.c --- v2.4.0-test6/linux/drivers/char/radio-terratec.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/char/radio-terratec.c Wed Dec 31 16:00:00 1969 @@ -1,358 +0,0 @@ -/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support - * (c) 1999 R. Offermanns (rolf@offermanns.de) - * based on the aimslab radio driver from M. Kirkwood - * many thanks to Michael Becker and Friedhelm Birth (from TerraTec) - * - * - * History: - * 1999-05-21 First preview release - * - * Notes on the hardware: - * There are two "main" chips on the card: - * - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf) - * - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf) - * (you can get the datasheet at the above links) - * - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * Volume Control is done digitally - * - * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday - * (as soon i have understand how to get started :) - * If you can help me out with that, please contact me!! - * - * - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_TERRATEC_PORT */ -#include - -#ifndef CONFIG_RADIO_TERRATEC_PORT -#define CONFIG_RADIO_TERRATEC_PORT 0x590 -#endif - -/**************** this ones are for the terratec *******************/ -#define BASEPORT 0x590 -#define VOLPORT 0x591 -#define WRT_DIS 0x00 -#define CLK_OFF 0x00 -#define IIC_DATA 0x01 -#define IIC_CLK 0x02 -#define DATA 0x04 -#define CLK_ON 0x08 -#define WRT_EN 0x10 -/*******************************************************************/ - -static int io = CONFIG_RADIO_TERRATEC_PORT; -static int users = 0; -static spinlock_t lock; - -struct tt_device -{ - int port; - int curvol; - unsigned long curfreq; - int muted; -}; - - -/* local things */ - -static void cardWriteVol(int volume) -{ - int i; - volume = volume+(volume * 32); // change both channels - spin_lock(&lock); - for (i=0;i<8;i++) - { - if (volume & (0x80>>i)) - outb(0x80, VOLPORT); - else outb(0x00, VOLPORT); - } - spin_unlock(&lock); -} - - - -static void tt_mute(struct tt_device *dev) -{ - dev->muted = 1; - cardWriteVol(0); -} - -static int tt_setvol(struct tt_device *dev, int vol) -{ - -// printk(KERN_ERR "setvol called, vol = %d\n", vol); - - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - cardWriteVol(vol); /* enable card */ - } - - return 0; - } - - if(vol == 0) { /* volume = 0 means mute the card */ - cardWriteVol(0); /* "turn off card" by setting vol to 0 */ - dev->curvol = vol; /* track the volume state! */ - return 0; - } - - dev->muted = 0; - - cardWriteVol(vol); - - dev->curvol = vol; - - return 0; - -} - - -/* this is the worst part in this driver */ -/* many more or less strange things are going on here, but hey, it works :) */ - -static int tt_setfreq(struct tt_device *dev, unsigned long freq1) -{ - int freq; - int i; - int p; - int temp; - long rest; - - unsigned char buffer[25]; /* we have to bit shift 25 registers */ - freq = freq1/160; /* convert the freq. to a nice to handel value */ - for(i=24;i>-1;i--) - buffer[i]=0; - - rest = freq*10+10700; /* i once had understood what is going on here */ - /* maybe some wise guy (friedhelm?) can comment this stuff */ - i=13; - p=10; - temp=102400; - while (rest!=0) - { - if (rest%temp == rest) - buffer[i] = 0; - else - { - buffer[i] = 1; - rest = rest-temp; - } - i--; - p--; - temp = temp/2; - } - - spin_lock(&lock); - - for (i=24;i>-1;i--) /* bit shift the values to the radiocard */ - { - if (buffer[i]==1) - { - outb(WRT_EN|DATA, BASEPORT); - outb(WRT_EN|DATA|CLK_ON , BASEPORT); - outb(WRT_EN|DATA, BASEPORT); - } - else - { - outb(WRT_EN|0x00, BASEPORT); - outb(WRT_EN|0x00|CLK_ON , BASEPORT); - } - } - outb(0x00, BASEPORT); - - spin_unlock(&lock); - - return 0; -} - -int tt_getsigstr(struct tt_device *dev) /* TODO */ -{ - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} - - -/* implement the video4linux api */ - -static int tt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct tt_device *tt=dev->priv; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - strcpy(v.name, "ActiveRadio"); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow=(87*16000); - v.rangehigh=(108*16000); - v.flags=VIDEO_TUNER_LOW; - v.mode=VIDEO_MODE_AUTO; - strcpy(v.name, "FM"); - v.signal=0xFFFF*tt_getsigstr(tt); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &tt->curfreq, sizeof(tt->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if(copy_from_user(&tt->curfreq, arg,sizeof(tt->curfreq))) - return -EFAULT; - tt_setfreq(tt, tt->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v,0, sizeof(v)); - v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; - v.volume=tt->curvol * 6554; - v.step=6554; - strcpy(v.name, "Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - - if(v.flags&VIDEO_AUDIO_MUTE) - tt_mute(tt); - else - tt_setvol(tt,v.volume/6554); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int tt_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void tt_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct tt_device terratec_unit; - -static struct video_device terratec_radio= -{ - "TerraTec ActiveRadio", - VID_TYPE_TUNER, - VID_HARDWARE_TERRATEC, - tt_open, - tt_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* No poll */ - tt_ioctl, - NULL, - NULL -}; - -static int __init terratec_init(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - if (check_region(io, 2)) - { - printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io); - return -EBUSY; - } - - terratec_radio.priv=&terratec_unit; - - spin_lock_init(&lock); - - if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 2, "terratec"); - printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n"); - - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - cardWriteVol(0); - terratec_unit.curvol = 0; - - return 0; -} - -MODULE_AUTHOR("R.OFFERMANNS & others"); -MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); - -EXPORT_NO_SYMBOLS; - -static void __exit terratec_cleanup_module(void) -{ - video_unregister_device(&terratec_radio); - release_region(io,2); - printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); -} - -module_init(terratec_init); -module_exit(terratec_cleanup_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-trust.c linux/drivers/char/radio-trust.c --- v2.4.0-test6/linux/drivers/char/radio-trust.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/char/radio-trust.c Wed Dec 31 16:00:00 1969 @@ -1,350 +0,0 @@ -/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 - * by Eric Lammerts - * - * Based on radio-aztech.c. Original notes: - * - * Adapted to support the Video for Linux API by - * Russell Kroll . Based on original tuner code by: - * - * Quay Ly - * Donald Song - * Jason Lewis (jlewis@twilight.vtc.vsc.edu) - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * - * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* CONFIG_RADIO_TRUST_PORT */ - -/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ - -#ifndef CONFIG_RADIO_TRUST_PORT -#define CONFIG_RADIO_TRUST_PORT -1 -#endif - -static int io = CONFIG_RADIO_TRUST_PORT; -static int ioval = 0xf; -static int users = 0; -static __u16 curvol; -static __u16 curbass; -static __u16 curtreble; -static unsigned long curfreq; -static int curstereo; -static int curmute; - -/* i2c addresses */ -#define TDA7318_ADDR 0x88 -#define TSA6060T_ADDR 0xc4 - -#define TR_DELAY do { inb(io); inb(io); inb(io); } while(0) -#define TR_SET_SCL outb(ioval |= 2, io) -#define TR_CLR_SCL outb(ioval &= 0xfd, io) -#define TR_SET_SDA outb(ioval |= 1, io) -#define TR_CLR_SDA outb(ioval &= 0xfe, io) - -static void write_i2c(int n, ...) -{ - unsigned char val, mask; - va_list args; - - va_start(args, n); - - /* start condition */ - TR_SET_SDA; - TR_SET_SCL; - TR_DELAY; - TR_CLR_SDA; - TR_CLR_SCL; - TR_DELAY; - - for(; n; n--) { - val = va_arg(args, unsigned); - for(mask = 0x80; mask; mask >>= 1) { - if(val & mask) - TR_SET_SDA; - else - TR_CLR_SDA; - TR_SET_SCL; - TR_DELAY; - TR_CLR_SCL; - TR_DELAY; - } - /* acknowledge bit */ - TR_SET_SDA; - TR_SET_SCL; - TR_DELAY; - TR_CLR_SCL; - TR_DELAY; - } - - /* stop condition */ - TR_CLR_SDA; - TR_DELAY; - TR_SET_SCL; - TR_DELAY; - TR_SET_SDA; - TR_DELAY; - - va_end(args); -} - -static void tr_setvol(__u16 vol) -{ - curvol = vol / 2048; - write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f); -} - -static int basstreble2chip[15] = { - 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 -}; - -static void tr_setbass(__u16 bass) -{ - curbass = bass / 4370; - write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]); -} - -static void tr_settreble(__u16 treble) -{ - curtreble = treble / 4370; - write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]); -} - -static void tr_setstereo(int stereo) -{ - curstereo = !!stereo; - ioval = (ioval & 0xfb) | (!curstereo << 2); - outb(ioval, io); -} - -static void tr_setmute(int mute) -{ - curmute = !!mute; - ioval = (ioval & 0xf7) | (curmute << 3); - outb(ioval, io); -} - -static int tr_getsigstr(void) -{ - int i, v; - - for(i = 0, v = 0; i < 100; i++) v |= inb(io); - return (v & 1)? 0 : 0xffff; -} - -static int tr_getstereo(void) -{ - /* don't know how to determine it, just return the setting */ - return curstereo; -} - -static void tr_setfreq(unsigned long f) -{ - f /= 160; /* Convert to 10 kHz units */ - f += 1070; /* Add 10.7 MHz IF */ - - write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); -} - -static int tr_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability v; - - v.type=VID_TYPE_TUNER; - v.channels=1; - v.audios=1; - - /* No we don't do pictures */ - v.maxwidth=0; - v.maxheight=0; - v.minwidth=0; - v.minheight=0; - - strcpy(v.name, "Trust FM Radio"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - - if(copy_from_user(&v, arg,sizeof(v))!=0) - return -EFAULT; - - if(v.tuner) /* Only 1 tuner */ - return -EINVAL; - - v.rangelow = 87500 * 16; - v.rangehigh = 108000 * 16; - v.flags = VIDEO_TUNER_LOW; - v.mode = VIDEO_MODE_AUTO; - - v.signal = tr_getsigstr(); - if(tr_getstereo()) - v.flags |= VIDEO_TUNER_STEREO_ON; - - strcpy(v.name, "FM"); - - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.tuner != 0) - return -EINVAL; - - return 0; - } - case VIDIOCGFREQ: - if(copy_to_user(arg, &curfreq, sizeof(curfreq))) - return -EFAULT; - return 0; - - case VIDIOCSFREQ: - { - unsigned long f; - - if(copy_from_user(&f, arg, sizeof(curfreq))) - return -EFAULT; - tr_setfreq(f); - return 0; - } - case VIDIOCGAUDIO: - { - struct video_audio v; - - memset(&v,0, sizeof(v)); - v.flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; - v.mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - v.volume = curvol * 2048; - v.step = 2048; - v.bass = curbass * 4370; - v.treble = curtreble * 4370; - - strcpy(v.name, "Trust FM Radio"); - if(copy_to_user(arg,&v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if(v.audio) - return -EINVAL; - - tr_setvol(v.volume); - tr_setbass(v.bass); - tr_settreble(v.treble); - tr_setstereo(v.mode & VIDEO_SOUND_STEREO); - tr_setmute(v.flags & VIDEO_AUDIO_MUTE); - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int tr_open(struct video_device *dev, int flags) -{ - if(users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void tr_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct video_device trust_radio= -{ - "Trust FM Radio", - VID_TYPE_TUNER, - VID_HARDWARE_TRUST, - tr_open, - tr_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* No poll */ - tr_ioctl, - NULL, - NULL -}; - -static int __init trust_init(void) -{ - if(io == -1) { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - if(check_region(io, 2)) { - printk(KERN_ERR "trust: port 0x%x already in use\n", io); - return -EBUSY; - } - if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io, 2, "Trust FM Radio"); - - printk(KERN_INFO "Trust FM Radio card driver v1.0.\n"); - - write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ - - tr_setvol(0x8000); - tr_setbass(0x8000); - tr_settreble(0x8000); - tr_setstereo(1); - - /* mute card - prevents noisy bootups */ - tr_setmute(1); - - return 0; -} - -MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); - -EXPORT_NO_SYMBOLS; - -static void __exit cleanup_trust_module(void) -{ - video_unregister_device(&trust_radio); - release_region(io, 2); -} - -module_init(trust_init); -module_exit(cleanup_trust_module); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-typhoon.c linux/drivers/char/radio-typhoon.c --- v2.4.0-test6/linux/drivers/char/radio-typhoon.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/radio-typhoon.c Wed Dec 31 16:00:00 1969 @@ -1,402 +0,0 @@ -/* Typhoon Radio Card driver for radio support - * (c) 1999 Dr. Henrik Seidel - * - * Card manufacturer: - * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e - * - * Notes on the hardware - * - * This card has two output sockets, one for speakers and one for line. - * The speaker output has volume control, but only in four discrete - * steps. The line output has neither volume control nor mute. - * - * The card has auto-stereo according to its manual, although it all - * sounds mono to me (even with the Win/DOS drivers). Maybe it's my - * antenna - I really don't know for sure. - * - * Frequency control is done digitally. - * - * Volume control is done digitally, but there are only four different - * possible values. So you should better always turn the volume up and - * use line control. I got the best results by connecting line output - * to the sound card microphone input. For such a configuration the - * volume control has no effect, since volume control only influences - * the speaker output. - * - * There is no explicit mute/unmute. So I set the radio frequency to a - * value where I do expect just noise and turn the speaker volume down. - * The frequency change is necessary since the card never seems to be - * completely silent. - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* radio card status report */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_TYPHOON_* */ - -#define BANNER "Typhoon Radio Card driver v0.1\n" - -#ifndef CONFIG_RADIO_TYPHOON_PORT -#define CONFIG_RADIO_TYPHOON_PORT -1 -#endif - -#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ -#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 -#endif - -#ifndef CONFIG_PROC_FS -#undef CONFIG_RADIO_TYPHOON_PROC_FS -#endif - -struct typhoon_device { - int users; - int iobase; - int curvol; - int muted; - unsigned long curfreq; - unsigned long mutefreq; -}; - -static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); -static int typhoon_setfreq_generic(struct typhoon_device *dev, - unsigned long frequency); -static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); -static void typhoon_mute(struct typhoon_device *dev); -static void typhoon_unmute(struct typhoon_device *dev); -static int typhoon_setvol(struct typhoon_device *dev, int vol); -static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg); -static int typhoon_open(struct video_device *dev, int flags); -static void typhoon_close(struct video_device *dev); -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS -static int typhoon_get_info(char *buf, char **start, off_t offset, int len); -#endif - -static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) -{ - vol >>= 14; /* Map 16 bit to 2 bit */ - vol &= 3; - outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */ - outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */ -} - -static int typhoon_setfreq_generic(struct typhoon_device *dev, - unsigned long frequency) -{ - unsigned long outval; - unsigned long x; - - /* - * The frequency transfer curve is not linear. The best fit I could - * get is - * - * outval = -155 + exp((f + 15.55) * 0.057)) - * - * where frequency f is in MHz. Since we don't have exp in the kernel, - * I approximate this function by a third order polynomial. - * - */ - - x = frequency / 160; - outval = (x * x + 2500) / 5000; - outval = (outval * x + 5000) / 10000; - outval -= (10 * x * x + 10433) / 20866; - outval += 4 * x - 11505; - - outb_p((outval >> 8) & 0x01, dev->iobase + 4); - outb_p(outval >> 9, dev->iobase + 6); - outb_p(outval & 0xff, dev->iobase + 8); - - return 0; -} - -static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency) -{ - typhoon_setfreq_generic(dev, frequency); - dev->curfreq = frequency; - return 0; -} - -static void typhoon_mute(struct typhoon_device *dev) -{ - if (dev->muted == 1) - return; - typhoon_setvol_generic(dev, 0); - typhoon_setfreq_generic(dev, dev->mutefreq); - dev->muted = 1; -} - -static void typhoon_unmute(struct typhoon_device *dev) -{ - if (dev->muted == 0) - return; - typhoon_setfreq_generic(dev, dev->curfreq); - typhoon_setvol_generic(dev, dev->curvol); - dev->muted = 0; -} - -static int typhoon_setvol(struct typhoon_device *dev, int vol) -{ - if (dev->muted && vol != 0) { /* user is unmuting the card */ - dev->curvol = vol; - typhoon_unmute(dev); - return 0; - } - if (vol == dev->curvol) /* requested volume == current */ - return 0; - - if (vol == 0) { /* volume == 0 means mute the card */ - typhoon_mute(dev); - dev->curvol = vol; - return 0; - } - typhoon_setvol_generic(dev, vol); - dev->curvol = vol; - return 0; -} - - -static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct typhoon_device *typhoon = dev->priv; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability v; - v.type = VID_TYPE_TUNER; - v.channels = 1; - v.audios = 1; - /* No we don't do pictures */ - v.maxwidth = 0; - v.maxheight = 0; - v.minwidth = 0; - v.minheight = 0; - strcpy(v.name, "Typhoon Radio"); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v)) != 0) - return -EFAULT; - if (v.tuner) /* Only 1 tuner */ - return -EINVAL; - v.rangelow = 875 * 1600; - v.rangehigh = 1080 * 1600; - v.flags = VIDEO_TUNER_LOW; - v.mode = VIDEO_MODE_AUTO; - v.signal = 0xFFFF; /* We can't get the signal strength */ - strcpy(v.name, "FM"); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.tuner != 0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if (copy_to_user(arg, &typhoon->curfreq, - sizeof(typhoon->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if (copy_from_user(&typhoon->curfreq, arg, - sizeof(typhoon->curfreq))) - return -EFAULT; - typhoon_setfreq(typhoon, typhoon->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v, 0, sizeof(v)); - v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; - v.mode |= VIDEO_SOUND_MONO; - v.volume = typhoon->curvol; - v.step = 1 << 14; - strcpy(v.name, "Typhoon Radio"); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.audio) - return -EINVAL; - - if (v.flags & VIDEO_AUDIO_MUTE) - typhoon_mute(typhoon); - else - typhoon_unmute(typhoon); - - if (v.flags & VIDEO_AUDIO_VOLUME) - typhoon_setvol(typhoon, v.volume); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int typhoon_open(struct video_device *dev, int flags) -{ - struct typhoon_device *typhoon = dev->priv; - if (typhoon->users) - return -EBUSY; - typhoon->users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void typhoon_close(struct video_device *dev) -{ - struct typhoon_device *typhoon = dev->priv; - typhoon->users--; - MOD_DEC_USE_COUNT; -} - -static struct typhoon_device typhoon_unit = -{ - 0, /* users */ - CONFIG_RADIO_TYPHOON_PORT, /* iobase */ - 0, /* curvol */ - 0, /* muted */ - CONFIG_RADIO_TYPHOON_MUTEFREQ, /* curfreq */ - CONFIG_RADIO_TYPHOON_MUTEFREQ /* mutefreq */ -}; - -static struct video_device typhoon_radio = -{ - "Typhoon Radio", - VID_TYPE_TUNER, - VID_HARDWARE_TYPHOON, - typhoon_open, - typhoon_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, /* Can't poll */ - typhoon_ioctl, - NULL, - NULL -}; - -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - -static int typhoon_get_info(char *buf, char **start, off_t offset, int len) -{ - char *out = buf; - - #ifdef MODULE - #define MODULEPROCSTRING "Driver loaded as a module" - #else - #define MODULEPROCSTRING "Driver compiled into kernel" - #endif - - /* output must be kept under PAGE_SIZE */ - out += sprintf(out, BANNER); - out += sprintf(out, "Load type: " MODULEPROCSTRING "\n\n"); - out += sprintf(out, "frequency = %lu kHz\n", - typhoon_unit.curfreq >> 4); - out += sprintf(out, "volume = %d\n", typhoon_unit.curvol); - out += sprintf(out, "mute = %s\n", typhoon_unit.muted ? - "on" : "off"); - out += sprintf(out, "iobase = 0x%x\n", typhoon_unit.iobase); - out += sprintf(out, "mute frequency = %lu kHz\n", - typhoon_unit.mutefreq >> 4); - return out - buf; -} - -#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ - -MODULE_AUTHOR("Dr. Henrik Seidel"); -MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); -MODULE_PARM(mutefreq, "i"); -MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); - -EXPORT_NO_SYMBOLS; - -static int io = -1; - -#ifdef MODULE -static unsigned long mutefreq = 0; -#endif - -static int __init typhoon_init(void) -{ -#ifdef MODULE - if (io == -1) { - printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); - return -EINVAL; - } - typhoon_unit.iobase = io; - - if (mutefreq < 87000 || mutefreq > 108500) { - printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n"); - printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); - return -EINVAL; - } - typhoon_unit.mutefreq = mutefreq; -#endif /* MODULE */ - - printk(KERN_INFO BANNER); - io = typhoon_unit.iobase; - if (check_region(io, 8)) { - printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", - typhoon_unit.iobase); - return -EBUSY; - } - - typhoon_radio.priv = &typhoon_unit; - if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) - return -EINVAL; - - request_region(typhoon_unit.iobase, 8, "typhoon"); - printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); - printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", - typhoon_unit.mutefreq); - typhoon_unit.mutefreq <<= 4; - - /* mute card - prevents noisy bootups */ - typhoon_mute(&typhoon_unit); - -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL, - typhoon_get_info)) - printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n"); -#endif - - return 0; -} - -static void __exit typhoon_cleanup_module(void) -{ - -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - remove_proc_entry("driver/radio-typhoon", NULL); -#endif - - video_unregister_device(&typhoon_radio); - release_region(io, 8); -} - -module_init(typhoon_init); -module_exit(typhoon_cleanup_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/radio-zoltrix.c linux/drivers/char/radio-zoltrix.c --- v2.4.0-test6/linux/drivers/char/radio-zoltrix.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/char/radio-zoltrix.c Wed Dec 31 16:00:00 1969 @@ -1,412 +0,0 @@ -/* zoltrix radio plus driver for Linux radio support - * (c) 1998 C. van Schaik - * - * BUGS - * Due to the inconsistancy in reading from the signal flags - * it is difficult to get an accurate tuned signal. - * - * It seems that the card is not linear to 0 volume. It cuts off - * at a low volume, and it is not possible (at least I have not found) - * to get fine volume control over the low volume range. - * - * Some code derived from code by Romolo Manfredini - * romolo@bicnet.it - * - * 1999-05-06 - (C. van Schaik) - * - Make signal strength and stereo scans - * kinder to cpu while in delay - * 1999-01-05 - (C. van Schaik) - * - Changed tuning to 1/160Mhz accuracy - * - Added stereo support - * (card defaults to stereo) - * (can explicitly force mono on the card) - * (can detect if station is in stereo) - * - Added unmute function - * - Reworked ioctl functions - */ - -#include /* Modules */ -#include /* Initdata */ -#include /* check_region, request_region */ -#include /* udelay */ -#include /* outb, outb_p */ -#include /* copy to/from user */ -#include /* kernel radio structs */ -#include /* CONFIG_RADIO_ZOLTRIX_PORT */ - -#ifndef CONFIG_RADIO_ZOLTRIX_PORT -#define CONFIG_RADIO_ZOLTRIX_PORT -1 -#endif - -static int io = CONFIG_RADIO_ZOLTRIX_PORT; -static int users = 0; - -struct zol_device { - int port; - int curvol; - unsigned long curfreq; - int muted; - unsigned int stereo; - struct semaphore lock; -}; - - -/* local things */ - -static void sleep_delay(void) -{ - /* Sleep nicely for +/- 10 mS */ - schedule(); -} - -static int zol_setvol(struct zol_device *dev, int vol) -{ - dev->curvol = vol; - if (dev->muted) - return 0; - - down(&dev->lock); - if (vol == 0) { - outb(0, io); - outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ - up(&dev->lock); - return 0; - } - - outb(dev->curvol-1, io); - sleep_delay(); - inb(io + 2); - up(&dev->lock); - return 0; -} - -static void zol_mute(struct zol_device *dev) -{ - dev->muted = 1; - down(&dev->lock); - outb(0, io); - outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ - up(&dev->lock); -} - -static void zol_unmute(struct zol_device *dev) -{ - dev->muted = 0; - zol_setvol(dev, dev->curvol); -} - -static int zol_setfreq(struct zol_device *dev, unsigned long freq) -{ - /* tunes the radio to the desired frequency */ - unsigned long long bitmask, f, m; - unsigned int stereo = dev->stereo; - int i; - - if (freq == 0) - return 1; - m = (freq / 160 - 8800) * 2; - f = (unsigned long long) m + 0x4d1c; - - bitmask = 0xc480402c10080000ull; - i = 45; - - down(&dev->lock); - - outb(0, io); - outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ - - outb(0x40, io); - outb(0xc0, io); - - bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31)); - while (i--) { - if ((bitmask & 0x8000000000000000ull) != 0) { - outb(0x80, io); - udelay(50); - outb(0x00, io); - udelay(50); - outb(0x80, io); - udelay(50); - } else { - outb(0xc0, io); - udelay(50); - outb(0x40, io); - udelay(50); - outb(0xc0, io); - udelay(50); - } - bitmask *= 2; - } - /* termination sequence */ - outb(0x80, io); - outb(0xc0, io); - outb(0x40, io); - udelay(1000); - inb(io+2); - - udelay(1000); - - if (dev->muted) - { - outb(0, io); - outb(0, io); - inb(io + 3); - udelay(1000); - } - - up(&dev->lock); - - if(!dev->muted) - { - zol_setvol(dev, dev->curvol); - } - return 0; -} - -/* Get signal strength */ - -int zol_getsigstr(struct zol_device *dev) -{ - int a, b; - - down(&dev->lock); - outb(0x00, io); /* This stuff I found to do nothing */ - outb(dev->curvol, io); - sleep_delay(); - sleep_delay(); - - a = inb(io); - sleep_delay(); - b = inb(io); - - up(&dev->lock); - - if (a != b) - return (0); - - if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */ - || (a == 0xef)) /* with a binary scanner on the card io */ - return (1); - return (0); -} - -int zol_is_stereo (struct zol_device *dev) -{ - int x1, x2; - - down(&dev->lock); - - outb(0x00, io); - outb(dev->curvol, io); - sleep_delay(); - sleep_delay(); - - x1 = inb(io); - sleep_delay(); - x2 = inb(io); - - up(&dev->lock); - - if ((x1 == x2) && (x1 == 0xcf)) - return 1; - return 0; -} - -static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct zol_device *zol = dev->priv; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability v; - v.type = VID_TYPE_TUNER; - v.channels = 1 + zol->stereo; - v.audios = 1; - /* No we don't do pictures */ - v.maxwidth = 0; - v.maxheight = 0; - v.minwidth = 0; - v.minheight = 0; - strcpy(v.name, "Zoltrix Radio"); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.tuner) - return -EINVAL; - strcpy(v.name, "FM"); - v.rangelow = (int) (88.0 * 16000); - v.rangehigh = (int) (108.0 * 16000); - v.flags = zol_is_stereo(zol) - ? VIDEO_TUNER_STEREO_ON : 0; - v.flags |= VIDEO_TUNER_LOW; - v.mode = VIDEO_MODE_AUTO; - v.signal = 0xFFFF * zol_getsigstr(zol); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.tuner != 0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - if (copy_to_user(arg, &zol->curfreq, sizeof(zol->curfreq))) - return -EFAULT; - return 0; - case VIDIOCSFREQ: - if (copy_from_user(&zol->curfreq, arg, sizeof(zol->curfreq))) - return -EFAULT; - zol_setfreq(zol, zol->curfreq); - return 0; - case VIDIOCGAUDIO: - { - struct video_audio v; - memset(&v, 0, sizeof(v)); - v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; - v.mode != zol_is_stereo(zol) - ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - v.volume = zol->curvol * 4096; - v.step = 4096; - strcpy(v.name, "Zoltrix Radio"); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.audio) - return -EINVAL; - - if (v.flags & VIDEO_AUDIO_MUTE) - zol_mute(zol); - else - { - zol_unmute(zol); - zol_setvol(zol, v.volume / 4096); - } - - if (v.mode & VIDEO_SOUND_STEREO) - { - zol->stereo = 1; - zol_setfreq(zol, zol->curfreq); - } - if (v.mode & VIDEO_SOUND_MONO) - { - zol->stereo = 0; - zol_setfreq(zol, zol->curfreq); - } - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int zol_open(struct video_device *dev, int flags) -{ - if (users) - return -EBUSY; - users++; - MOD_INC_USE_COUNT; - return 0; -} - -static void zol_close(struct video_device *dev) -{ - users--; - MOD_DEC_USE_COUNT; -} - -static struct zol_device zoltrix_unit; - -static struct video_device zoltrix_radio = -{ - "Zoltrix Radio Plus", - VID_TYPE_TUNER, - VID_HARDWARE_ZOLTRIX, - zol_open, - zol_close, - NULL, /* Can't read (no capture ability) */ - NULL, /* Can't write */ - NULL, - zol_ioctl, - NULL, - NULL -}; - -static int __init zoltrix_init(void) -{ - if (io == -1) { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - if (check_region(io, 2)) { - printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); - return -EBUSY; - } - if ((io != 0x20c) && (io != 0x30c)) { - printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n"); - return -ENXIO; - } - zoltrix_radio.priv = &zoltrix_unit; - - if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1) - return -EINVAL; - - request_region(io, 2, "zoltrix"); - printk(KERN_INFO "Zoltrix Radio Plus card driver.\n"); - - init_MUTEX(&zoltrix_unit.lock); - - /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - - outb(0, io); - outb(0, io); - sleep_delay(); - sleep_delay(); - inb(io + 3); - - zoltrix_unit.curvol = 0; - zoltrix_unit.stereo = 1; - - return 0; -} - -MODULE_AUTHOR("C.van Schaik"); -MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); - -EXPORT_NO_SYMBOLS; - -static void __exit zoltrix_cleanup_module(void) -{ - video_unregister_device(&zoltrix_radio); - release_region(io, 2); -} - -module_init(zoltrix_init); -module_exit(zoltrix_cleanup_module); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/linux_compat.h linux/drivers/char/rio/linux_compat.h --- v2.4.0-test6/linux/drivers/char/rio/linux_compat.h Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/linux_compat.h Fri Aug 11 14:51:33 2000 @@ -72,8 +72,6 @@ extern int rio_debug; -#define rio_dprint(f, p) do {if (rio_debug & f) printk p;} while (0) - #define RIO_DEBUG_INIT 0x000001 #define RIO_DEBUG_BOOT 0x000002 #define RIO_DEBUG_CMD 0x000004 @@ -92,7 +90,7 @@ #define RIO_DEBUG_REC 0x008000 #define RIO_DEBUG_SPINLOCK 0x010000 #define RIO_DEBUG_DELAY 0x020000 - +#define RIO_DEBUG_MOD_COUNT 0x040000 /* Copied over from riowinif.h . This is ugly. The winif file declares also much other stuff which is incompatible with the headers from diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c --- v2.4.0-test6/linux/drivers/char/rio/rio_linux.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/rio/rio_linux.c Fri Aug 11 14:51:33 2000 @@ -249,6 +249,8 @@ #ifndef TWO_ZERO #ifdef MODULE +MODULE_AUTHOR("Rogier Wolff , Patrick van de Lageweg "); +MODULE_DESCRIPTION("RIO driver"); MODULE_PARM(rio_poll, "i"); MODULE_PARM(rio_debug, "i"); MODULE_PARM(rio_irqmask, "i"); @@ -394,26 +396,37 @@ void rio_inc_mod_count (void) { +#ifdef MODULE func_enter (); + rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_inc_mod_count\n"); MOD_INC_USE_COUNT; func_exit (); +#endif } void rio_dec_mod_count (void) { +#ifdef MODULE func_enter (); + rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_dec_mod_count\n"); MOD_DEC_USE_COUNT; func_exit (); +#endif } static int rio_set_real_termios (void *ptr) { - int rv; + int rv, modem; + struct tty_struct *tty; func_enter(); - rv = RIOParam( (struct Port *) ptr, CONFIG, 0, 1); + tty = ((struct Port *)ptr)->gs.tty; + + modem = (MAJOR(tty->device) == RIO_NORMAL_MAJOR0) || (MAJOR(tty->device) == RIO_NORMAL_MAJOR1); + + rv = RIOParam( (struct Port *) ptr, CONFIG, modem, 1); func_exit (); @@ -631,6 +644,7 @@ func_exit(); } + /* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug @@ -641,7 +655,7 @@ static void rio_hungup (void *ptr) { func_enter (); - /* rio_dec_mod_count (); */ + rio_dec_mod_count (); func_exit (); } @@ -652,9 +666,22 @@ */ static void rio_close (void *ptr) { + struct Port *PortP; + func_enter (); + + PortP = (struct Port *)ptr; + riotclose (ptr); + + if(PortP->gs.count) { + printk (KERN_ERR "WARNING port count:%d\n", PortP->gs.count); + PortP->gs.count = 0; + } + + rio_dec_mod_count (); + func_exit (); } @@ -974,13 +1001,12 @@ port->gs.close_delay = HZ/2; port->gs.closing_wait = 30 * HZ; port->gs.rd = &rio_real_driver; - + port->portSem = SPIN_LOCK_UNLOCKED; /* * Initializing wait queue */ init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); - + init_waitqueue_head(&port->gs.close_wait); } #else /* We could postpone initializing them to when they are configured. */ @@ -1010,7 +1036,7 @@ return -ENOMEM; } - +#ifdef MODULE static void rio_release_drivers(void) { func_enter(); @@ -1020,6 +1046,7 @@ tty_unregister_driver (&rio_driver); func_exit(); } +#endif #ifdef TWO_ZERO #define PDEV unsigned char pci_bus, unsigned pci_fun @@ -1120,7 +1147,7 @@ while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { - if (pci_enable_device(pdev)) continue; + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, @@ -1157,6 +1184,7 @@ hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; + hp->HostLock = SPIN_LOCK_UNLOCKED; rio_reset_interrupt (hp); rio_start_card_running (hp); @@ -1206,7 +1234,7 @@ while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { - if (pci_enable_device(pdev)) continue; + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rio_linux.h linux/drivers/char/rio/rio_linux.h --- v2.4.0-test6/linux/drivers/char/rio/rio_linux.h Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/rio_linux.h Fri Aug 11 14:51:33 2000 @@ -29,6 +29,8 @@ #define RIO_PORTSPERBOARD 128 #define RIO_NPORTS (RIO_NBOARDS * RIO_PORTSPERBOARD) +#define MODEM_SUPPORT + #ifdef __KERNEL__ #define RIO_MAGIC 0x12345678 @@ -85,31 +87,34 @@ #endif +void rio_dec_mod_count (void); +void rio_inc_mod_count (void); + /* Allow us to debug "in the field" without requiring clients to recompile.... */ #if 1 #define rio_spin_lock_irqsave(sem, flags) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlockirqsave: %p %s:%d\n", \ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \ + sem, __FILE__, __LINE__);\ spin_lock_irqsave(sem, flags);\ } while (0) #define rio_spin_unlock_irqrestore(sem, flags) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlockirqrestore: %p %s:%d\n",\ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\ + sem, __FILE__, __LINE__);\ spin_unlock_irqrestore(sem, flags);\ } while (0) #define rio_spin_lock(sem) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinlock: %p %s:%d\n",\ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\ + sem, __FILE__, __LINE__);\ spin_lock(sem);\ } while (0) #define rio_spin_unlock(sem) do { \ - rio_dprint(RIO_DEBUG_SPINLOCK, ("spinunlock: %p %s:%d\n",\ - sem, __FILE__, __LINE__));\ + rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlock: %p %s:%d\n",\ + sem, __FILE__, __LINE__);\ spin_unlock(sem);\ } while (0) #else @@ -173,7 +178,7 @@ */ #ifdef DEBUG -#define rio_dprintk(f, str...) if (rio_debug & f) printk (str) +#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0) #define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ "\n") #define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit " __FUNCTION__ "\n") #define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ \ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rioboot.c linux/drivers/char/rio/rioboot.c --- v2.4.0-test6/linux/drivers/char/rio/rioboot.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/rioboot.c Fri Aug 11 14:51:33 2000 @@ -118,13 +118,13 @@ "copyin". (Crash when a pagefault occurs). */ /* disable(oldspl); */ - rio_dprint(RIO_DEBUG_BOOT, ("Data at user address 0x%x\n",(int)rbp->DataP)); + rio_dprintk (RIO_DEBUG_BOOT, "Data at user address 0x%x\n",(int)rbp->DataP); /* ** Check that we have set asside enough memory for this */ if ( rbp->Count > SIXTY_FOUR_K ) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code Too Large!\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n"); p->RIOError.Error = HOST_FILE_TOO_LARGE; /* restore(oldspl); */ func_exit (); @@ -132,7 +132,7 @@ } if ( p->RIOBooting ) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot Code : BUSY BUSY BUSY!\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n"); p->RIOError.Error = BOOT_IN_PROGRESS; /* restore(oldspl); */ func_exit (); @@ -160,7 +160,7 @@ if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset, rbp->Count) ==COPYFAIL ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bad data copy from user space\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bad data copy from user space\n"); p->RIOError.Error = COPYIN_FAILED; /* restore(oldspl); */ func_exit (); @@ -185,7 +185,7 @@ switch ( HostP->Type ) { case RIO_AT: - rio_dprint(RIO_DEBUG_BOOT, ("Start ISA card running\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Start ISA card running\n"); WBYTE(HostP->Control, BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode @@ -198,7 +198,7 @@ ** MCA handles IRQ vectors differently, so we don't write ** them to this register. */ - rio_dprint(RIO_DEBUG_BOOT, ("Start MCA card running\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Start MCA card running\n"); WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode); break; @@ -206,7 +206,7 @@ /* ** EISA is totally different and expects OUTBZs to turn it on. */ - rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_DAEMON,"Start EISA card running\n"); + rio_dprintk (RIO_DEBUG_BOOT, "Start EISA card running\n"); OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM ); break; #endif @@ -217,11 +217,11 @@ ** mapped, so we are writing to memory registers instead of io ** ports. */ - rio_dprint(RIO_DEBUG_BOOT, ("Start PCI card running\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Start PCI card running\n"); WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode); break; default: - rio_dprint(RIO_DEBUG_BOOT, ("Unknown host type %d\n",HostP->Type)); + rio_dprintk (RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type); break; } /* @@ -260,15 +260,15 @@ HostP = NULL; /* Assure the compiler we've initialized it */ for ( host=0; hostRIONumHosts; host++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Attempt to boot host %d\n",host)); + rio_dprintk (RIO_DEBUG_BOOT, "Attempt to boot host %d\n",host); HostP = &p->RIOHosts[host]; - rio_dprint(RIO_DEBUG_BOOT, ("Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", - HostP->Type, HostP->Mode, HostP->Ivec ) ); + rio_dprintk (RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", + HostP->Type, HostP->Mode, HostP->Ivec); if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) { - rio_dprint(RIO_DEBUG_BOOT, ("%s %d already running\n","Host",host)); + rio_dprintk (RIO_DEBUG_BOOT, "%s %d already running\n","Host",host); continue; } @@ -285,13 +285,13 @@ */ StartP = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count]; - rio_dprint(RIO_DEBUG_BOOT, ("kernel virtual address for host is 0x%x\n", (int)Cad ) ); - rio_dprint(RIO_DEBUG_BOOT, ("kernel virtual address for download is 0x%x\n", (int)StartP ) ); - rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase)); - rio_dprint(RIO_DEBUG_BOOT, ("size of download is 0x%x\n", rbp->Count ) ); + rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for host is 0x%x\n", (int)Cad ); + rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for download is 0x%x\n", (int)StartP); + rio_dprintk (RIO_DEBUG_BOOT, "host loadbase is 0x%x\n",p->RIOConf.HostLoadBase); + rio_dprintk (RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count); if ( p->RIOConf.HostLoadBase < rbp->Count ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bin too large\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bin too large\n"); p->RIOError.Error = HOST_FILE_TOO_LARGE; func_exit (); return EFBIG; @@ -307,7 +307,7 @@ ** This ain't going to be none too clever if the download ** code is bigger than this segment. */ - rio_dprint(RIO_DEBUG_BOOT, ("Copy in code\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Copy in code\n"); /* ** PCI hostcard can't cope with 32 bit accesses and so need to copy @@ -318,7 +318,7 @@ DownCode = sysbrk(rbp->Count); if ( !DownCode ) { - rio_dprint(RIO_DEBUG_BOOT, ("No system memory available\n")); + rio_dprintk (RIO_DEBUG_BOOT, "No system memory available\n"); p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY; func_exit (); return ENOMEM; @@ -326,7 +326,7 @@ bzero(DownCode, rbp->Count); if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); p->RIOError.Error = COPYIN_FAILED; func_exit (); return EFAULT; @@ -337,13 +337,13 @@ sysfree( DownCode, rbp->Count ); } else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_BOOT, ("Bad copyin of host data\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); p->RIOError.Error = COPYIN_FAILED; func_exit (); return EFAULT; } - rio_dprint(RIO_DEBUG_BOOT, ("Copy completed\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Copy completed\n"); /* ** S T O P ! @@ -444,8 +444,8 @@ WBYTE( DestP[6] , NFIX(0) ); WBYTE( DestP[7] , JUMP(8) ); - rio_dprint(RIO_DEBUG_BOOT, ("host loadbase is 0x%x\n",p->RIOConf.HostLoadBase)); - rio_dprint(RIO_DEBUG_BOOT, ("startup offset is 0x%x\n",offset)); + rio_dprintk (RIO_DEBUG_BOOT, "host loadbase is 0x%x\n",p->RIOConf.HostLoadBase); + rio_dprintk (RIO_DEBUG_BOOT, "startup offset is 0x%x\n",offset); /* ** Flag what is going on @@ -459,19 +459,19 @@ */ OldParmMap = RWORD(HostP->__ParmMapR); - rio_dprint(RIO_DEBUG_BOOT, ("Original parmmap is 0x%x\n",OldParmMap)); + rio_dprintk (RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n",OldParmMap); /* ** And start it running (I hope). ** As there is nothing dodgy or obscure about the ** above code, this is guaranteed to work every time. */ - rio_dprint(RIO_DEBUG_BOOT, ("Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", - HostP->Type, HostP->Mode, HostP->Ivec ) ); + rio_dprintk (RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", + HostP->Type, HostP->Mode, HostP->Ivec); rio_start_card_running(HostP); - rio_dprint(RIO_DEBUG_BOOT, ("Set control port\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Set control port\n"); /* ** Now, wait for upto five seconds for the Tp to setup the parmmap @@ -479,7 +479,7 @@ */ for ( wait_count=0; (wait_countRIOConf.StartupTime)&& (RWORD(HostP->__ParmMapR)==OldParmMap); wait_count++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR))); + rio_dprintk (RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR)); delay(HostP, HUNDRED_MS); } @@ -489,8 +489,8 @@ ** has crashed & burned in a really spectacular way */ if ( RWORD(HostP->__ParmMapR) == OldParmMap ) { - rio_dprint(RIO_DEBUG_BOOT, ("parmmap 0x%x\n", RWORD(HostP->__ParmMapR))); - rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail\n")); + rio_dprintk (RIO_DEBUG_BOOT, "parmmap 0x%x\n", RWORD(HostP->__ParmMapR)); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n"); #define HOST_DISABLE \ HostP->Flags &= ~RUN_STATE; \ @@ -501,7 +501,7 @@ HOST_DISABLE; } - rio_dprint(RIO_DEBUG_BOOT, ("Running 0x%x\n",RWORD(HostP->__ParmMapR))); + rio_dprintk (RIO_DEBUG_BOOT, "Running 0x%x\n", RWORD(HostP->__ParmMapR)); /* ** Well, the board thought it was OK, and setup its parmmap @@ -513,10 +513,10 @@ ** Grab a 32 bit pointer to the parmmap structure */ ParmMapP = (PARM_MAP *)RIO_PTR(Cad,RWORD(HostP->__ParmMapR)); - rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP)); + rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); ParmMapP = (PARM_MAP *)((unsigned long)Cad + (unsigned long)((RWORD((HostP->__ParmMapR))) & 0xFFFF)); - rio_dprint(RIO_DEBUG_BOOT, ("ParmMapP : %x\n", (int)ParmMapP)); + rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); /* ** The links entry should be 0xFFFF; we set it up @@ -524,8 +524,8 @@ ** which links to use. */ if ( (RWORD(ParmMapP->links) & 0xFFFF) != 0xFFFF ) { - rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name)); - rio_dprint(RIO_DEBUG_BOOT, ("Links = 0x%x\n",RWORD(ParmMapP->links))); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); + rio_dprintk (RIO_DEBUG_BOOT, "Links = 0x%x\n",RWORD(ParmMapP->links)); HOST_DISABLE; } @@ -535,28 +535,28 @@ ** now wait for the card to set all the parmmap->XXX stuff ** this is a wait of upto two seconds.... */ - rio_dprint(RIO_DEBUG_BOOT, ("Looking for init_done - %d ticks\n",p->RIOConf.StartupTime)); + rio_dprintk (RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n",p->RIOConf.StartupTime); HostP->timeout_id = 0; for ( wait_count=0; (wait_countRIOConf.StartupTime) && !RWORD(ParmMapP->init_done); wait_count++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Waiting for init_done\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Waiting for init_done\n"); delay(HostP, HUNDRED_MS); } - rio_dprint(RIO_DEBUG_BOOT, ("OK! init_done!\n")); + rio_dprintk (RIO_DEBUG_BOOT, "OK! init_done!\n"); if (RWORD(ParmMapP->error) != E_NO_ERROR || !RWORD(ParmMapP->init_done) ) { - rio_dprint(RIO_DEBUG_BOOT, ("RIO Mesg Run Fail %s\n", HostP->Name)); - rio_dprint(RIO_DEBUG_BOOT, ("Timedout waiting for init_done\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); + rio_dprintk (RIO_DEBUG_BOOT, "Timedout waiting for init_done\n"); HOST_DISABLE; } - rio_dprint(RIO_DEBUG_BOOT, ("Got init_done\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Got init_done\n"); /* ** It runs! It runs! */ - rio_dprint(RIO_DEBUG_BOOT, ("Host ID %x Running\n",HostP->UniqueNum)); + rio_dprintk (RIO_DEBUG_BOOT, "Host ID %x Running\n",HostP->UniqueNum); /* ** set the time period between interrupts. @@ -580,12 +580,14 @@ HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN]; HostP->UnixRups[RupN].Id = RupN+1; HostP->UnixRups[RupN].BaseSysPort = NO_PORT; + HostP->UnixRups[RupN].RupLock = SPIN_LOCK_UNLOCKED; } for ( RupN = 0; RupNUnixRups[RupN+MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup; HostP->UnixRups[RupN+MAX_RUP].Id = 0; HostP->UnixRups[RupN+MAX_RUP].BaseSysPort = NO_PORT; + HostP->UnixRups[RupN+MAX_RUP].RupLock = SPIN_LOCK_UNLOCKED; } /* @@ -622,7 +624,7 @@ } } - rio_dprint(RIO_DEBUG_BOOT, ("Set the card running... \n")); + rio_dprintk (RIO_DEBUG_BOOT, "Set the card running... \n"); /* ** last thing - show the world that everything is in place */ @@ -638,7 +640,7 @@ p->RIOSystemUp++; - rio_dprint(RIO_DEBUG_BOOT, ("Done everything %x\n", HostP->Ivec)); + rio_dprintk (RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec); func_exit (); return 0; } @@ -672,7 +674,7 @@ ** If we haven't been told what to boot, we can't boot it. */ if ( p->RIONumBootPkts == 0 ) { - rio_dprint(RIO_DEBUG_BOOT, ("No RTA code to download yet\n")); + rio_dprintk (RIO_DEBUG_BOOT, "No RTA code to download yet\n"); return 0; } @@ -693,7 +695,7 @@ ** try to unhook a command block from the command free list. */ if ( !(CmdBlkP = RIOGetCmdBlk()) ) { - rio_dprint(RIO_DEBUG_BOOT, ("No command blocks to boot RTA! come back later.\n")); + rio_dprintk (RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n"); return 0; } @@ -716,8 +718,8 @@ ** We only expect one type of command - a BOOT_REQUEST! */ if ( RBYTE(PktCmdP->Command) != BOOT_REQUEST ) { - rio_dprint(RIO_DEBUG_BOOT, ("Unexpected command %d on BOOT RUP %d of host %d\n", - PktCmdP->Command,Rup,HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %d\n", + PktCmdP->Command,Rup,HostP-p->RIOHosts); ShowPacket( DBG_BOOT, PacketP ); RIOFreeCmdBlk( CmdBlkP ); return 1; @@ -754,9 +756,9 @@ bcopy("BOOT",(void *)&CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN],4); - rio_dprint(RIO_DEBUG_BOOT, ("Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n", + rio_dprintk (RIO_DEBUG_BOOT, "Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n", HostP-p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, - p->RIOConf.RtaLoadBase)); + p->RIOConf.RtaLoadBase); /* ** If this host is in slave mode, send the RTA an invalid boot @@ -775,11 +777,11 @@ */ sequence = RWORD(PktCmdP->Sequence); - rio_dprint(RIO_DEBUG_BOOT, ("Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup)); + rio_dprintk (RIO_DEBUG_BOOT, "Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup); if ( sequence >= p->RIONumBootPkts ) { - rio_dprint(RIO_DEBUG_BOOT, ("Got a request for packet %d, max is %d\n", sequence, - p->RIONumBootPkts)); + rio_dprintk (RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, + p->RIONumBootPkts); ShowPacket( DBG_BOOT, PacketP ); } @@ -821,26 +823,26 @@ driver will never think that the RTA has booted... -- REW */ p->RIOBooting = 0; - rio_dprint(RIO_DEBUG_BOOT, ("RTA Boot completed - BootInProgress now %d\n", p->RIOBooting)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting); /* ** Determine type of unit (16/8 port RTA). */ RtaType = GetUnitType(RtaUniq); if ( Rup >= (ushort)MAX_RUP ) { - rio_dprint(RIO_DEBUG_BOOT, ("RIO: Host %s has booted an RTA(%d) on link %c\n", - HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A' )); + rio_dprintk (RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", + HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A'); } else { - rio_dprint(RIO_DEBUG_BOOT, ("RIO: RTA %s has booted an RTA(%d) on link %c\n", + rio_dprintk (RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", HostP->Mapping[Rup].Name, 8 * RtaType, - RBYTE(PktCmdP->LinkNum)+'A')); + RBYTE(PktCmdP->LinkNum)+'A'); } - rio_dprint(RIO_DEBUG_BOOT, ("UniqNum is 0x%x\n",RtaUniq)); + rio_dprintk (RIO_DEBUG_BOOT, "UniqNum is 0x%x\n",RtaUniq); if ( ( RtaUniq == 0x00000000 ) || ( RtaUniq == 0xffffffff ) ) { - rio_dprint(RIO_DEBUG_BOOT, ( "Illegal RTA Uniq Number\n")); + rio_dprintk (RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n"); return TRUE; } @@ -861,8 +863,8 @@ */ if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA failed to suspend booting on link %c\n", - 'A' + MyLink)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", + 'A' + MyLink); } } else @@ -874,8 +876,8 @@ */ WWORD(HostP->LinkStrP[MyLink].WaitNoBoot, 30); } - rio_dprint(RIO_DEBUG_BOOT, ("RTA %x not owned - suspend booting down link %c on unit %x\n", - RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", + RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum); return TRUE; } @@ -925,16 +927,16 @@ } } if (RtaType == TYPE_RTA16) { - rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given IDs %d+%d\n", - entry+1, entry2+1)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", + entry+1, entry2+1); } else { - rio_dprint(RIO_DEBUG_BOOT, ("RTA will be given ID %d\n",entry+1)); + rio_dprintk (RIO_DEBUG_BOOT, "RTA will be given ID %d\n",entry+1); } return TRUE; } } - rio_dprint(RIO_DEBUG_BOOT, ("RTA not configured for this host\n")); + rio_dprintk (RIO_DEBUG_BOOT, "RTA not configured for this host\n"); if ( Rup >= (ushort)MAX_RUP ) { @@ -978,13 +980,13 @@ entry2 = HostP->Mapping[entry].ID2 - 1; if ( (HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq) ) - rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slots (%d+%d)\n", - entry, entry2)); + rio_dprintk (RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", + entry, entry2); else continue; } else - rio_dprint(RIO_DEBUG_BOOT, ("Found previous tentative slot (%d)\n",entry)); + rio_dprintk (RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n",entry); if (! p->RIONoMessage) cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A'); return TRUE; @@ -1013,7 +1015,7 @@ ** + Configure RTA on host A. We now have the same RTA configured ** with different ports on two different hosts. */ - rio_dprint(RIO_DEBUG_BOOT, ("Have we seen RTA %x before?\n", RtaUniq )); + rio_dprintk (RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq ); found = 0; Flag = 0; /* Convince the compiler this variable is initialized */ for ( host = 0; !found && (host < p->RIONumHosts); host++ ) @@ -1029,12 +1031,12 @@ if (RtaType == TYPE_RTA16) { MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1]; - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is units %d+%d from host %s\n", - rta+1, MapP->ID2, p->RIOHosts[host].Name )); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", + rta+1, MapP->ID2, p->RIOHosts[host].Name); } else - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is unit %d from host %s\n", - rta+1, p->RIOHosts[host].Name )); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", + rta+1, p->RIOHosts[host].Name); found = 1; break; } @@ -1052,12 +1054,12 @@ */ if ( !MapP ) { - rio_dprint(RIO_DEBUG_BOOT, ("Look for RTA %x in RIOSavedTable\n",RtaUniq)); + rio_dprintk (RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n",RtaUniq); for ( rta=0; rta < TOTAL_MAP_ENTRIES; rta++ ) { - rio_dprint(RIO_DEBUG_BOOT, ("Check table entry %d (%x)", + rio_dprintk (RIO_DEBUG_BOOT, "Check table entry %d (%x)", rta, - p->RIOSavedTable[rta].RtaUniqueNum )); + p->RIOSavedTable[rta].RtaUniqueNum); if ( (p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq) ) @@ -1073,11 +1075,11 @@ break; } MapP2 = &p->RIOSavedTable[entry2]; - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entries %d+%d\n", - rta, entry2)); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", + rta, entry2); } else - rio_dprint(RIO_DEBUG_BOOT, ("This RTA is from table entry %d\n", rta)); + rio_dprintk (RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta); break; } } @@ -1133,8 +1135,8 @@ { if (Flag & SLOT_IN_USE) { - rio_dprint(RIO_DEBUG_BOOT, ( - "This RTA configured on another host - move entry to current host (1)\n")); + rio_dprintk (RIO_DEBUG_BOOT, + "This RTA configured on another host - move entry to current host (1)\n"); HostP->Mapping[entry].SysPort = MapP->SysPort; CCOPY( MapP->Name, HostP->Mapping[entry].Name, MAX_NAME_LEN ); HostP->Mapping[entry].Flags = @@ -1147,12 +1149,12 @@ p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort; if ( HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted ) p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort; - rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name)); + rio_dprintk (RIO_DEBUG_BOOT, "SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name); } else { - rio_dprint(RIO_DEBUG_BOOT, ( - "This RTA has a tentative entry on another host - delete that entry (1)\n")); + rio_dprintk (RIO_DEBUG_BOOT, + "This RTA has a tentative entry on another host - delete that entry (1)\n"); HostP->Mapping[entry].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT; #if NEED_TO_FIX @@ -1177,9 +1179,9 @@ p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort; if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted) p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort; - rio_dprint(RIO_DEBUG_BOOT, ("SysPort %d, Name %s\n", + rio_dprintk (RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int)HostP->Mapping[entry2].SysPort, - HostP->Mapping[entry].Name)); + HostP->Mapping[entry].Name); } else HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | @@ -1272,7 +1274,7 @@ { int link; - rio_dprint(RIO_DEBUG_BOOT, ("FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq)); + rio_dprintk (RIO_DEBUG_BOOT, "FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq); HostP->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE); HostP->Mapping[entry].SysPort = NO_PORT; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/riocmd.c linux/drivers/char/rio/riocmd.c --- v2.4.0-test6/linux/drivers/char/rio/riocmd.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/riocmd.c Fri Aug 11 14:51:33 2000 @@ -91,12 +91,12 @@ { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA\n")); + rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -111,7 +111,7 @@ CmdBlkP->Packet.data[3] = (IFOAD_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("FOAD RTA: Failed to queue foad command\n")); + rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA: Failed to queue foad command\n"); return EIO; } return 0; @@ -124,12 +124,12 @@ { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA\n")); + rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -144,7 +144,7 @@ CmdBlkP->Packet.data[3] = (ZOMBIE_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("ZOMBIE RTA: Failed to queue zombie command\n")); + rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA: Failed to queue zombie command\n"); return EIO; } return 0; @@ -158,7 +158,7 @@ { uint Host; - rio_dprint(RIO_DEBUG_CMD, ("Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func )); + rio_dprintk (RIO_DEBUG_CMD, "Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func); if ( !RtaUnique ) return(0); @@ -203,7 +203,7 @@ uint Host; if ( copyin( (int)arg, (caddr_t)&IdRta, sizeof(IdRta) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("RIO_IDENTIFY_RTA copy failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "RIO_IDENTIFY_RTA copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -231,12 +231,12 @@ */ struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA\n")); + rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -249,9 +249,8 @@ CmdBlkP->Packet.data[1] = 0; CmdBlkP->Packet.data[2] = IdRta.ID; - if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) - == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("IDENTIFY RTA: Failed to queue command\n")); + if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { + rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA: Failed to queue command\n"); return EIO; } return 0; @@ -274,11 +273,10 @@ struct Host *HostP; struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("KILL HOST NEIGHBOUR\n")); + rio_dprintk (RIO_DEBUG_CMD, "KILL HOST NEIGHBOUR\n"); - if ( copyin( (int)arg, (caddr_t)&KillUnit, - sizeof(KillUnit) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("RIO_KILL_NEIGHBOUR copy failed\n")); + if ( copyin( (int)arg, (caddr_t)&KillUnit, sizeof(KillUnit) ) == COPYFAIL ) { + rio_dprintk (RIO_DEBUG_CMD, "RIO_KILL_NEIGHBOUR copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -289,7 +287,7 @@ CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("UFOAD: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "UFOAD: GetCmdBlk failed\n"); return ENXIO; } @@ -310,7 +308,7 @@ if ( HostP->UniqueNum == KillUnit.UniqueNum ) { if ( RIOQueueCmdBlk( HostP, RTAS_PER_HOST+KillUnit.Link, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n")); + rio_dprintk (RIO_DEBUG_CMD, "UFOAD: Failed queue command\n"); return EIO; } return 0; @@ -320,7 +318,7 @@ if ( HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum ) { CmdBlkP->Packet.dest_unit = ID+1; if ( RIOQueueCmdBlk( HostP, ID, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("UFOAD: Failed queue command\n")); + rio_dprintk (RIO_DEBUG_CMD, "UFOAD: Failed queue command\n"); return EIO; } return 0; @@ -339,12 +337,12 @@ { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link)); + rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: GetCmdBlk failed\n"); return ENXIO; } @@ -359,7 +357,7 @@ CmdBlkP->Packet.data[3] = (IWAIT_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, ID - 1, CmdBlkP) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CMD, ("SUSPEND BOOT ON RTA: Failed to queue iwait command\n")); + rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: Failed to queue iwait command\n"); return EIO; } return 0; @@ -416,6 +414,7 @@ ushort subCommand; unsigned long flags; + func_enter (); #ifdef CHECK CheckHost( Host ); @@ -435,34 +434,35 @@ UnixRupP = &HostP->UnixRups[rup]; SysPort = UnixRupP->BaseSysPort + (RBYTE(PktCmdP->PhbNum) % (ushort)PORTS_PER_RTA); - rio_dprint(RIO_DEBUG_CMD, ("Command on rup %d, port %d\n", rup, SysPort)); + rio_dprintk (RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort); #ifdef CHECK CheckRup( rup ); CheckUnixRupP( UnixRupP ); #endif if ( UnixRupP->BaseSysPort == NO_PORT ) { - rio_dprint(RIO_DEBUG_CMD, ("OBSCURE ERROR!\n")); - rio_dprint(RIO_DEBUG_CMD, ("Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n")); - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Host number %d, name ``%s''\n", - HostP-p->RIOHosts, HostP->Name )); - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: Rup number 0x%x\n", rup)); - - if ( Rup >= (ushort)MAX_RUP ) - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for RTA ``%s''\n", - HostP->Mapping[Rup].Name )); - else - rio_dprint(RIO_DEBUG_CMD, ("CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", 'A' + Rup - MAX_RUP, HostP->Name )); - - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Destination 0x%x:0x%x\n", - PacketP->dest_unit, PacketP->dest_port )); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Source 0x%x:0x%x\n", - PacketP->src_unit, PacketP->src_port )); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Length 0x%x (%d)\n", PacketP->len,PacketP->len )); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Control 0x%x (%d)\n", PacketP->control, PacketP->control)); - rio_dprint(RIO_DEBUG_CMD, ("PACKET information: Check 0x%x (%d)\n", PacketP->csum, PacketP->csum )); - rio_dprint(RIO_DEBUG_CMD, ("COMMAND information: Host Port Number 0x%x, - Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command )); + rio_dprintk (RIO_DEBUG_CMD, "OBSCURE ERROR!\n"); + rio_dprintk (RIO_DEBUG_CMD, "Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n"); + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Host number %d, name ``%s''\n", + HostP-p->RIOHosts, HostP->Name ); + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); + + if ( Rup >= (ushort)MAX_RUP ) { + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", + HostP->Mapping[Rup].Name); + } else + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", + ('A' + Rup - MAX_RUP), HostP->Name); + + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Destination 0x%x:0x%x\n", + PacketP->dest_unit, PacketP->dest_port ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Source 0x%x:0x%x\n", + PacketP->src_unit, PacketP->src_port ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Length 0x%x (%d)\n", PacketP->len,PacketP->len ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Control 0x%x (%d)\n", PacketP->control, PacketP->control); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Check 0x%x (%d)\n", PacketP->csum, PacketP->csum ); + rio_dprintk (RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, + Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command ); return TRUE; } @@ -470,13 +470,10 @@ CheckSysPort( SysPort ); #endif PortP = p->RIOPortp[ SysPort ]; -#if 0 - ttyP = PortP->TtyP; -#endif rio_spin_lock_irqsave(&PortP->portSem, flags); switch( RBYTE(PktCmdP->Command) ) { case BREAK_RECEIVED: - rio_dprint(RIO_DEBUG_CMD, ("Received a break!\n")); + rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n"); /* If the current line disc. is not multi-threading and the current processor is not the default, reset rup_intr and return FALSE to ensure that the command packet is @@ -486,16 +483,16 @@ break; case COMPLETE: - rio_dprint(RIO_DEBUG_CMD, ("Command complete on phb %d host %d\n", - RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n", + RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts); subCommand = 1; switch (RBYTE(PktCmdP->SubCommand)) { case MEMDUMP : - rio_dprint(RIO_DEBUG_CMD, ("Memory dump cmd (0x%x) from addr 0x%x\n", - RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr))); + rio_dprintk (RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", + RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr)); break; case READ_REGISTER : - rio_dprint(RIO_DEBUG_CMD, ("Read register (0x%x)\n", RWORD(PktCmdP->SubAddr))); + rio_dprintk (RIO_DEBUG_CMD, "Read register (0x%x)\n", RWORD(PktCmdP->SubAddr)); p->CdRegister = (RBYTE(PktCmdP->ModemStatus) & MSVR1_HOST); break; default : @@ -504,18 +501,16 @@ } if (subCommand) break; - rio_dprint(RIO_DEBUG_CMD, ("New status is 0x%x was 0x%x\n", - RBYTE(PktCmdP->PortStatus),PortP->PortState)); + rio_dprintk (RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", + RBYTE(PktCmdP->PortStatus),PortP->PortState); if (PortP->PortState != RBYTE(PktCmdP->PortStatus)) { - rio_dprint(RIO_DEBUG_CMD, ("Mark status & wakeup\n")); + rio_dprintk (RIO_DEBUG_CMD, "Mark status & wakeup\n"); PortP->PortState = RBYTE(PktCmdP->PortStatus); /* What should we do here ... wakeup( &PortP->PortState ); */ - } - else { - rio_dprint(RIO_DEBUG_CMD, ("No change\n")); - } + } else + rio_dprintk (RIO_DEBUG_CMD, "No change\n"); /* FALLTHROUGH */ case MODEM_STATUS: @@ -527,7 +522,7 @@ ReportedModemStatus = RBYTE(PktCmdP->ModemStatus); if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) { - rio_dprint(RIO_DEBUG_CMD, ("Modem status unchanged 0x%x\n", PortP->ModemState)); + rio_dprintk (RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState); /* ** Update ModemState just in case tbusy or tstop states have ** changed. @@ -535,8 +530,8 @@ PortP->ModemState = ReportedModemStatus; } else { - rio_dprint(RIO_DEBUG_CMD, ("Modem status change from 0x%x to 0x%x\n", - PortP->ModemState, ReportedModemStatus)); + rio_dprintk (RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", + PortP->ModemState, ReportedModemStatus); PortP->ModemState = ReportedModemStatus; #ifdef MODEM_SUPPORT if ( PortP->Mapped ) { @@ -551,50 +546,41 @@ ** If the device is a modem, then check the modem ** carrier. */ - if(!(ttyP->t_cflag & CLOCAL) && - ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) - { + if (PortP->gs.tty == NULL) + break; + + if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && + ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) { + + rio_dprintk (RIO_DEBUG_CMD, "Is there a Carrier?\n"); /* ** Is there a carrier? */ - if ( PortP->ModemState & MSVR1_CD ) - { + if ( PortP->ModemState & MSVR1_CD ) { /* ** Has carrier just appeared? */ - if (!(ttyP->t_state & CARR_ON)) - { - rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just came up.\n"); - ttyP->t_state |=CARR_ON; + if (!(PortP->State & RIO_CARR_ON)) { + rio_dprintk (RIO_DEBUG_CMD, "Carrier just came up.\n"); + PortP->State |= RIO_CARR_ON; /* ** wakeup anyone in WOPEN */ - if ( ttyP->t_state & (ISOPEN|WOPEN) ) - wakeup((caddr_t)&ttyP->t_canq); + if (PortP->State & (PORT_ISOPEN | RIO_WOPEN) ) + wake_up_interruptible (&PortP->gs.open_wait); #ifdef STATS PortP->Stat.ModemOnCnt++; #endif } - } - else - { + } else { /* ** Has carrier just dropped? */ - if (ttyP->t_state & CARR_ON) - { - /* - ** send SIGHUP to the process group - */ - if ( ttyP->t_state & (ISOPEN|WOPEN) ) - { - signal(ttyP->t_pgrp,SIGHUP); - ttyflush(ttyP,(FREAD|FWRITE)); - } - ttyP->t_state &= ~CARR_ON; - wakeup( (caddr_t)&PortP->TxBufferOut ); - wakeup( (caddr_t)&PortP->TxBufferIn ); - rio_dprint(RIO_DEBUG_CMD, PortP,DBG_MODEM,"Carrier just went down.\n"); + if (PortP->State & RIO_CARR_ON) { + if (PortP->State & (PORT_ISOPEN|RIO_WOPEN|RIO_MOPEN)) + tty_hangup (PortP->gs.tty); + PortP->State &= ~RIO_CARR_ON; + rio_dprintk (RIO_DEBUG_CMD, "Carrirer just went down\n"); #ifdef STATS PortP->Stat.ModemOffCnt++; #endif @@ -607,11 +593,14 @@ break; default: - rio_dprint(RIO_DEBUG_CMD, ("Unknown command %d on CMD_RUP of host %d\n", - RBYTE(PktCmdP->Command),HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %d\n", + RBYTE(PktCmdP->Command),HostP-p->RIOHosts); break; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); + + func_exit (); + return TRUE; } /* @@ -667,11 +656,8 @@ CheckRup( Rup ); CheckCmdBlkP( CmdBlkP ); #endif - - rio_dprint(RIO_DEBUG_CMD, ("RIOQueueCmdBlk(Host, Rup %d, 0x%x)\n", Rup, (int)CmdBlkP )); - if ( Rup >= (ushort)(MAX_RUP+LINKS_PER_UNIT) ) { - rio_dprint(RIO_DEBUG_CMD, ("Illegal rup number %d in RIOQueueCmdBlk\n",Rup)); + rio_dprintk (RIO_DEBUG_CMD, "Illegal rup number %d in RIOQueueCmdBlk\n",Rup); RIOFreeCmdBlk( CmdBlkP ); return RIO_FAIL; } @@ -685,11 +671,12 @@ ** straight on the RUP.... */ if ( (UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && - (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) && + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE ) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg,CmdBlkP) :TRUE)) { - rio_dprint(RIO_DEBUG_CMD, ("RUP inactive-placing command straight on. Cmd byte is 0x%x\n", - CmdBlkP->Packet.data[0])); + rio_dprintk (RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n", + CmdBlkP->Packet.data[0]); + /* ** Whammy! blat that pack! @@ -711,28 +698,27 @@ return RIO_SUCCESS; } - - rio_dprint(RIO_DEBUG_CMD, ("RUP active - en-queing\n")); + rio_dprintk (RIO_DEBUG_CMD, "RUP active - en-queing\n"); if ( UnixRupP->CmdsWaitingP != NULL) - rio_dprint(RIO_DEBUG_CMD, ("Rup active - command waiting\n")); + rio_dprintk (RIO_DEBUG_CMD, "Rup active - command waiting\n"); if ( UnixRupP->CmdPendingP != NULL ) - rio_dprint(RIO_DEBUG_CMD, ("Rup active - command pending\n")); + rio_dprintk (RIO_DEBUG_CMD, "Rup active - command pending\n"); if ( RWORD(UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE ) - rio_dprint(RIO_DEBUG_CMD, ("Rup active - command rup not ready\n")); + rio_dprintk (RIO_DEBUG_CMD, "Rup active - command rup not ready\n"); Base = &UnixRupP->CmdsWaitingP; - rio_dprint(RIO_DEBUG_CMD, ("First try to queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base)); + rio_dprintk (RIO_DEBUG_CMD, "First try to queue cmdblk 0x%x at 0x%x\n", (int)CmdBlkP,(int)Base); while ( *Base ) { - rio_dprint(RIO_DEBUG_CMD, ("Command cmdblk 0x%x here\n",(int)(*Base))); + rio_dprintk (RIO_DEBUG_CMD, "Command cmdblk 0x%x here\n", (int)(*Base)); Base = &((*Base)->NextP); - rio_dprint(RIO_DEBUG_CMD, ("Now try to queue cmd cmdblk 0x%x at 0x%x\n", - (int)CmdBlkP,(int)Base)); + rio_dprintk (RIO_DEBUG_CMD, "Now try to queue cmd cmdblk 0x%x at 0x%x\n", + (int)CmdBlkP,(int)Base); } - rio_dprint(RIO_DEBUG_CMD, ("Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base)); + rio_dprintk (RIO_DEBUG_CMD, "Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base); *Base = CmdBlkP; @@ -775,17 +761,15 @@ if ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) { int FreeMe; - /* rio_dprint(RIO_DEBUG_CMD, ("RIORupCmd( %d, %d )\n", HostP-p->RIOHosts, Rup )); */ - PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt)); ShowPacket( DBG_CMD, PacketP ); switch ( RBYTE(PacketP->dest_port) ) { case BOOT_RUP: - rio_dprint(RIO_DEBUG_CMD, ("Incoming Boot %s packet '%x'\n", + rio_dprintk (RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", RBYTE(PacketP->len) & 0x80 ? "Command":"Data", - RBYTE(PacketP->data[0]) )); + RBYTE(PacketP->data[0])); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOBootRup(p, Rup,HostP,PacketP); rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); @@ -800,8 +784,8 @@ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOCommandRup(p, Rup,HostP,PacketP); if (PacketP->data[5] == MEMDUMP) { - rio_dprint(RIO_DEBUG_CMD, ("Memdump from 0x%x complete\n", - *(ushort *) &(PacketP->data[6]))); + rio_dprintk (RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", + *(ushort *) &(PacketP->data[6])); HostP->Copy( (caddr_t)&(PacketP->data[8]), (caddr_t)p->RIOMemDump, 32 ); } @@ -815,19 +799,19 @@ break; default: - rio_dprint(RIO_DEBUG_CMD, ("Unknown RUP %d\n", RBYTE(PacketP->dest_port))); + rio_dprintk (RIO_DEBUG_CMD, "Unknown RUP %d\n", RBYTE(PacketP->dest_port)); FreeMe = 1; break; } if ( FreeMe ) { - rio_dprint(RIO_DEBUG_CMD, ("Free processed incoming command packet\n")); + rio_dprintk (RIO_DEBUG_CMD, "Free processed incoming command packet\n"); put_free_end(HostP,PacketP); WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE); if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) { - rio_dprint(RIO_DEBUG_CMD, ("Handshake rup %d\n",Rup)); + rio_dprintk (RIO_DEBUG_CMD, "Handshake rup %d\n",Rup); WWORD(UnixRupP->RupP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } @@ -839,7 +823,7 @@ ** and it has completed, then tidy it up. */ if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ - (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) { + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** we are idle. ** there is a command in pending. @@ -848,11 +832,11 @@ ** what happened). */ if ( CmdBlkP->Packet.dest_port == BOOT_RUP ) - rio_dprint(RIO_DEBUG_CMD, ("Free Boot %s Command Block '%x'\n", + rio_dprintk (RIO_DEBUG_CMD, "Free Boot %s Command Block '%x'\n", CmdBlkP->Packet.len & 0x80 ? "Command":"Data", - CmdBlkP->Packet.data[0] )); + CmdBlkP->Packet.data[0]); - rio_dprint(RIO_DEBUG_CMD, ("Command 0x%x completed\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CMD, "Command 0x%x completed\n",(int)CmdBlkP); /* ** Clear the Rup lock to prevent mutual exclusion. @@ -880,27 +864,27 @@ */ if ( (CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */ (UnixRupP->CmdPendingP == NULL) && - (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) ) { + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** if the pre-function is non-zero, call it. ** If it returns RIO_FAIL then don't ** send this command yet! */ #ifdef CHECK -CheckCmdBlkP( CmdBlkP ); + CheckCmdBlkP (CmdBlkP); #endif if ( !(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) { - rio_dprint(RIO_DEBUG_CMD, ("Not ready to start command 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CMD, "Not ready to start command 0x%x\n",(int)CmdBlkP); } else { - rio_dprint(RIO_DEBUG_CMD, ("Start new command 0x%x Cmd byte is 0x%x\n", - (int)CmdBlkP, CmdBlkP->Packet.data[0])); + rio_dprintk (RIO_DEBUG_CMD, "Start new command 0x%x Cmd byte is 0x%x\n", + (int)CmdBlkP, CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */ #ifdef CHECK -CheckPacketP( (PKT *)RIO_PTR(HostP->Caddr,UnixRupP->RupP->txpkt) ); + CheckPacketP ((PKT *)RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt)); #endif HostP->Copy( (caddr_t)&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(PKT)); @@ -1026,7 +1010,7 @@ ** MAGIC! (Basically, handshake the RX buffer, so that ** the RTAs upstream can be re-enabled.) */ - rio_dprint(RIO_DEBUG_CMD, ("Util: Set RX handshake bit\n")); + rio_dprintk (RIO_DEBUG_CMD, "Util: Set RX handshake bit\n"); WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -1046,7 +1030,7 @@ #ifdef CHECK CheckPortP( PortP ); #endif - rio_dprint(RIO_DEBUG_CMD, ("Decrement in use count for port\n")); + rio_dprintk (RIO_DEBUG_CMD, "Decrement in use count for port\n"); if (PortP->InUse) { if ( --PortP->InUse != NOT_INUSE ) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rioctrl.c linux/drivers/char/rio/rioctrl.c --- v2.4.0-test6/linux/drivers/char/rio/rioctrl.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/rioctrl.c Fri Aug 11 14:51:33 2000 @@ -137,7 +137,7 @@ { int rv; - rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes from user %p to %p.\n", siz, (void *) arg, dp)); + rio_dprintk (RIO_DEBUG_CTRL, "Copying %d bytes from user %p to %p.\n", siz, (void *)arg, dp); rv = copy_from_user (dp, (void *)arg, siz); if (rv < 0) return COPYFAIL; else return rv; @@ -148,7 +148,7 @@ { int rv; - rio_dprint (RIO_DEBUG_CTRL, ("Copying %d bytes to user %p from %p.\n", siz, (void *) arg, dp)); + rio_dprintk (RIO_DEBUG_CTRL, "Copying %d bytes to user %p from %p.\n", siz, (void *)arg, dp); rv = copy_to_user ((void *)arg, dp, siz); if (rv < 0) return COPYFAIL; else return rv; @@ -207,7 +207,7 @@ Host=0; PortP = NULL; - rio_dprint(RIO_DEBUG_CTRL, ("control ioctl cmd: 0x%x arg: 0x%x\n", cmd, (int)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "control ioctl cmd: 0x%x arg: 0x%x\n", cmd, (int)arg); switch (cmd) { /* @@ -218,7 +218,7 @@ ** otherwise just the specified host card will be changed. */ case RIO_SET_TIMER: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_TIMER to %dms\n", (uint)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_TIMER to %dms\n", (uint)arg); { int host, value; host = (uint)arg >> 16; @@ -296,42 +296,42 @@ */ case RIO_FOAD_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_FOAD_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_FOAD_RTA\n"); return RIOCommandRta(p, (uint)arg, RIOFoadRta); case RIO_ZOMBIE_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ZOMBIE_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ZOMBIE_RTA\n"); return RIOCommandRta(p, (uint)arg, RIOZombieRta); case RIO_IDENTIFY_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_IDENTIFY_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_IDENTIFY_RTA\n"); return RIOIdentifyRta(p, arg); case RIO_KILL_NEIGHBOUR: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_KILL_NEIGHBOUR\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_KILL_NEIGHBOUR\n"); return RIOKillNeighbour(p, arg); case SPECIAL_RUP_CMD: { struct CmdBlk *CmdBlkP; - rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD\n")); + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD\n"); if (copyin((int)arg, (caddr_t)&SpecialRupCmd, sizeof(SpecialRupCmd)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { - rio_dprint(RIO_DEBUG_CTRL, ("SPECIAL_RUP_CMD GetCmdBlk failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD GetCmdBlk failed\n"); return ENXIO; } CmdBlkP->Packet = SpecialRupCmd.Packet; if ( SpecialRupCmd.Host >= p->RIONumHosts ) SpecialRupCmd.Host = 0; - rio_dprint(RIO_DEBUG_CTRL, ("Queue special rup command for host %d rup %d\n", - SpecialRupCmd.Host, SpecialRupCmd.RupNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue special rup command for host %d rup %d\n", + SpecialRupCmd.Host, SpecialRupCmd.RupNum); if (RIOQueueCmdBlk(&p->RIOHosts[SpecialRupCmd.Host], SpecialRupCmd.RupNum, CmdBlkP) == RIO_FAIL) { cprintf("FAILED TO QUEUE SPECIAL RUP COMMAND\n"); @@ -348,7 +348,7 @@ return EPERM; case RIO_ALL_MODEM: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ALL_MODEM\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ALL_MODEM\n"); p->RIOError.Error = IOCTL_COMMAND_UNKNOWN; return EINVAL; @@ -356,44 +356,44 @@ /* ** Read the routing table from the device driver to user space */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_TABLE\n"); if ((retval = RIOApel(p)) != 0) return retval; if (copyout((caddr_t)p->RIOConnectTable, (int)arg, TOTAL_MAP_ENTRIES*sizeof(struct Map)) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_TABLE copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_TABLE copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } { int entry; - rio_dprint(RIO_DEBUG_CTRL, ("*****\nMAP ENTRIES\n") ); + rio_dprintk (RIO_DEBUG_CTRL, "*****\nMAP ENTRIES\n"); for ( entry=0; entryRIOConnectTable[entry].ID == 0) && (p->RIOConnectTable[entry].HostUniqueNum == 0) && (p->RIOConnectTable[entry].RtaUniqueNum == 0)) continue; - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Flags = 0x%x\n", entry, (int)p->RIOConnectTable[entry].Flags ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.SysPort = 0x%x\n", entry, (int)p->RIOConnectTable[entry].SysPort ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) ); - rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Flags = 0x%x\n", entry, (int)p->RIOConnectTable[entry].Flags ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.SysPort = 0x%x\n", entry, (int)p->RIOConnectTable[entry].SysPort ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link ); + rio_dprintk (RIO_DEBUG_CTRL, "Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ); } - rio_dprint(RIO_DEBUG_CTRL, ("*****\nEND MAP ENTRIES\n") ); + rio_dprintk (RIO_DEBUG_CTRL, "*****\nEND MAP ENTRIES\n"); } p->RIOQuickCheck = NOT_CHANGED; /* a table has been gotten */ return 0; @@ -402,16 +402,16 @@ /* ** Write the routing table to the device driver from user space */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_TABLE\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_TABLE !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if ( copyin((int)arg, (caddr_t)&p->RIOConnectTable[0], TOTAL_MAP_ENTRIES*sizeof(struct Map) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_TABLE copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_TABLE copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -449,17 +449,17 @@ ** Send bindings table, containing unique numbers of RTAs owned ** by this system to user space */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_BINDINGS\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_BINDINGS !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyout((caddr_t) p->RIOBindTab, (int)arg, (sizeof(ulong) * MAX_RTA_BINDINGS)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_BINDINGS copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_BINDINGS copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -470,17 +470,17 @@ ** Receive a bindings table, containing unique numbers of RTAs owned ** by this system */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&p->RIOBindTab[0], (sizeof(ulong) * MAX_RTA_BINDINGS))==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PUT_BINDINGS copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -493,10 +493,10 @@ ** Bind this RTA to host, so that it will be booted by ** host in 'boot owned RTAs' mode. */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_BIND_RTA\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_BIND_RTA !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_BIND_RTA !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } @@ -508,8 +508,8 @@ ** Already exists - delete */ p->RIOBindTab[Entry] = 0L; - rio_dprint(RIO_DEBUG_CTRL, ("Removing Rta %x from p->RIOBindTab\n", - (int) arg)); + rio_dprintk (RIO_DEBUG_CTRL, "Removing Rta %x from p->RIOBindTab\n", + (int) arg); return 0; } } @@ -518,90 +518,90 @@ */ if (EmptySlot != -1) { p->RIOBindTab[EmptySlot] = (int) arg; - rio_dprint(RIO_DEBUG_CTRL, ("Adding Rta %x to p->RIOBindTab\n", - (int) arg)); + rio_dprintk (RIO_DEBUG_CTRL, "Adding Rta %x to p->RIOBindTab\n", + (int) arg); } else { - rio_dprint(RIO_DEBUG_CTRL, ("p->RIOBindTab full! - Rta %x not added\n", - (int) arg)); + rio_dprintk (RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %x not added\n", + (int) arg); return 1; } return 0; } case RIO_RESUME : - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME\n"); port = (uint) arg; if ((port < 0) || (port > 511)) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Bad port number %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Bad port number %d\n", port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } PortP = p->RIOPortp[port]; if (!PortP->Mapped) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not mapped\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not mapped\n", port); p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM; return EINVAL; } if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d not open\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not open\n", port); return EINVAL; } rio_spin_lock_irqsave(&PortP->portSem, flags); if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return EBUSY; } else { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESUME: Port %d resumed\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME: Port %d resumed\n", port); PortP->State |= RIO_BUSY; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); return retval; case RIO_ASSIGN_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_ASSIGN_RTA !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Copy from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } return RIOAssignRta(p, &MapEnt); case RIO_CHANGE_NAME: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_CHANGE_NAME\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_CHANGE_NAME !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_CHANGE_NAME !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("Copy from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Copy from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } return RIOChangeName(p, &MapEnt); case RIO_DELETE_RTA: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DELETE_RTA\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DELETE_RTA !Root\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DELETE_RTA !Root\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("Copy from data space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Copy from data space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -638,7 +638,7 @@ return 0; case RIO_GET_LOG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_LOG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_LOG\n"); #ifdef LOGGING RIOGetLog(arg); return 0; @@ -653,17 +653,17 @@ p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("Get module type for port %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "Get module type for port %d\n", port); if ( port < 0 || port > 511 ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Bad port number %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Bad port number %d\n", port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } PortP = (p->RIOPortp[port]); if (!PortP->Mapped) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_MODTYPE: Port %d not mapped\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Port %d not mapped\n", port); p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM; return EINVAL; } @@ -703,7 +703,7 @@ */ case RIO_BLOCK_OPENS: - rio_dprint(RIO_DEBUG_CTRL, ("Opens block until booted\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Opens block until booted\n"); for ( Entry=0; Entry < RIO_PORTS; Entry++ ) { rio_spin_lock_irqsave(&PortP->portSem, flags); p->RIOPortp[Entry]->WaitUntilBooted = 1; @@ -712,33 +712,33 @@ return 0; case RIO_SETUP_PORTS: - rio_dprint(RIO_DEBUG_CTRL, ("Setup ports\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Setup ports\n"); if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("EFAULT")); + rio_dprintk (RIO_DEBUG_CTRL, "EFAULT"); return EFAULT; } if ( PortSetup.From > PortSetup.To || PortSetup.To >= RIO_PORTS ) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("ENXIO")); + rio_dprintk (RIO_DEBUG_CTRL, "ENXIO"); return ENXIO; } if ( PortSetup.XpCps > p->RIOConf.MaxXpCps || PortSetup.XpCps < p->RIOConf.MinXpCps ) { p->RIOError.Error = XPRINT_CPS_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("EINVAL")); + rio_dprintk (RIO_DEBUG_CTRL, "EINVAL"); return EINVAL; } if ( !p->RIOPortp ) { cprintf("No p->RIOPortp array!\n"); - rio_dprint(RIO_DEBUG_CTRL, ("No p->RIOPortp array!\n")); + rio_dprintk (RIO_DEBUG_CTRL, "No p->RIOPortp array!\n"); return EIO; } - rio_dprint(RIO_DEBUG_CTRL, ("entering loop (%d %d)!\n", PortSetup.From, PortSetup.To)); + rio_dprintk (RIO_DEBUG_CTRL, "entering loop (%d %d)!\n", PortSetup.From, PortSetup.To); for (loop=PortSetup.From; loop<=PortSetup.To; loop++) { - rio_dprint(RIO_DEBUG_CTRL, ("in loop (%d)!\n", loop)); + rio_dprintk (RIO_DEBUG_CTRL, "in loop (%d)!\n", loop); #if 0 PortP = p->RIOPortp[loop]; if ( !PortP->TtyP ) @@ -791,12 +791,12 @@ rio_spin_unlock_irqrestore( &PortP->portSem , flags); #endif } - rio_dprint(RIO_DEBUG_CTRL, ("after loop (%d)!\n", loop)); - rio_dprint(RIO_DEBUG_CTRL, ("Retval:%x\n", retval ) ); + rio_dprintk (RIO_DEBUG_CTRL, "after loop (%d)!\n", loop); + rio_dprintk (RIO_DEBUG_CTRL, "Retval:%x\n", retval); return retval; case RIO_GET_PORT_SETUP : - rio_dprint(RIO_DEBUG_CTRL, ("Get port setup\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Get port setup\n"); if (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -832,7 +832,7 @@ return retval; case RIO_GET_PORT_PARAMS : - rio_dprint(RIO_DEBUG_CTRL, ("Get port params\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Get port params\n"); if (copyin( (int)arg, (caddr_t)&PortParams, sizeof(struct PortParams)) == COPYFAIL) { p->RIOError.Error = COPYIN_FAILED; @@ -845,7 +845,7 @@ PortP = (p->RIOPortp[PortParams.Port]); PortParams.Config = PortP->Config; PortParams.State = PortP->State; - rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortParams.Port)); + rio_dprintk (RIO_DEBUG_CTRL, "Port %d\n", PortParams.Port); if (copyout((caddr_t)&PortParams, (int)arg, sizeof(struct PortParams)) == COPYFAIL ) { @@ -855,7 +855,7 @@ return retval; case RIO_GET_PORT_TTY : - rio_dprint(RIO_DEBUG_CTRL, ("Get port tty\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Get port tty\n"); if (copyin((int)arg, (caddr_t)&PortTty, sizeof(struct PortTty)) == COPYFAIL) { p->RIOError.Error = COPYIN_FAILED; @@ -866,7 +866,7 @@ return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Port %d\n", PortTty.port)); + rio_dprintk (RIO_DEBUG_CTRL, "Port %d\n", PortTty.port); PortP = (p->RIOPortp[PortTty.port]); #if 0 PortTty.Tty.tm.c_iflag = PortP->TtyP->tm.c_iflag; @@ -887,7 +887,7 @@ p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("Set port %d tty\n", PortTty.port)); + rio_dprintk (RIO_DEBUG_CTRL, "Set port %d tty\n", PortTty.port); if (PortTty.port >= (ushort) RIO_PORTS) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; @@ -906,7 +906,7 @@ return retval; case RIO_SET_PORT_PARAMS : - rio_dprint(RIO_DEBUG_CTRL, ("Set port params\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Set port params\n"); if ( copyin((int)arg, (caddr_t)&PortParams, sizeof(PortParams)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -923,7 +923,7 @@ return retval; case RIO_GET_PORT_STATS : - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GET_PORT_STATS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_PORT_STATS\n"); if ( copyin((int)arg, (caddr_t)&portStats, sizeof(struct portStats)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -949,7 +949,7 @@ case RIO_RESET_PORT_STATS : port = (uint) arg; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_RESET_PORT_STATS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESET_PORT_STATS\n"); if ( port >= RIO_PORTS ) { p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; @@ -965,7 +965,7 @@ return retval; case RIO_GATHER_PORT_STATS : - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GATHER_PORT_STATS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GATHER_PORT_STATS\n"); if ( copyin( (int)arg, (caddr_t)&portStats, sizeof(struct portStats)) == COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -985,22 +985,22 @@ case RIO_READ_LEVELS: { int num; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_LEVELS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_LEVELS\n"); for ( num=0; RIODbInf[num].Flag; num++ ) ; - rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copy\n",num)); + rio_dprintk (RIO_DEBUG_CTRL, "%d levels to copy\n",num); if (copyout((caddr_t)RIODbInf,(int)arg, sizeof(struct DbInf)*(num+1))==COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("ReadLevels Copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "ReadLevels Copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("%d levels to copied\n",num)); + rio_dprintk (RIO_DEBUG_CTRL, "%d levels to copied\n",num); return retval; } #endif case RIO_READ_CONFIG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_CONFIG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_CONFIG\n"); if (copyout((caddr_t)&p->RIOConf, (int)arg, sizeof(struct Conf)) ==COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; @@ -1009,7 +1009,7 @@ return retval; case RIO_SET_CONFIG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_CONFIG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_CONFIG\n"); if ( !su ) { p->RIOError.Error = NOT_SUPER_USER; return EPERM; @@ -1029,11 +1029,11 @@ return retval; case RIO_START_POLLER: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_START_POLLER\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_START_POLLER\n"); return EINVAL; case RIO_STOP_POLLER: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_STOP_POLLER\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_STOP_POLLER\n"); if ( !su ) { p->RIOError.Error = NOT_SUPER_USER; return EPERM; @@ -1043,7 +1043,7 @@ case RIO_SETDEBUG: case RIO_GETDEBUG: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG/RIO_GETDEBUG\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SETDEBUG/RIO_GETDEBUG\n"); if ( copyin( (int)arg, (caddr_t)&DebugCtrl, sizeof(DebugCtrl) ) ==COPYFAIL ) { p->RIOError.Error = COPYIN_FAILED; @@ -1057,18 +1057,18 @@ } p->rio_debug = DebugCtrl.Debug; p->RIODebugWait = DebugCtrl.Wait; - rio_dprint(RIO_DEBUG_CTRL, ("Set global debug to 0x%x set wait to 0x%x\n", - p->rio_debug,p->RIODebugWait)); + rio_dprintk (RIO_DEBUG_CTRL, "Set global debug to 0x%x set wait to 0x%x\n", + p->rio_debug,p->RIODebugWait); } else { - rio_dprint(RIO_DEBUG_CTRL, ("Get global debug 0x%x wait 0x%x\n", - p->rio_debug,p->RIODebugWait)); + rio_dprintk (RIO_DEBUG_CTRL, "Get global debug 0x%x wait 0x%x\n", + p->rio_debug,p->RIODebugWait); DebugCtrl.Debug = p->rio_debug; DebugCtrl.Wait = p->RIODebugWait; if ( copyout((caddr_t)&DebugCtrl,(int)arg, sizeof(DebugCtrl)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n", - DebugCtrl.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", + DebugCtrl.SysPort); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1076,8 +1076,8 @@ } else if ( DebugCtrl.SysPort >= RIO_PORTS && DebugCtrl.SysPort != NO_PORT ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET/GET DEBUG: bad port number %d\n", - DebugCtrl.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", + DebugCtrl.SysPort); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; } @@ -1089,16 +1089,16 @@ rio_spin_lock_irqsave(&PortP->portSem, flags); p->RIOPortp[DebugCtrl.SysPort]->Debug = DebugCtrl.Debug; rio_spin_unlock_irqrestore( &PortP->portSem , flags); - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SETDEBUG 0x%x\n", - p->RIOPortp[DebugCtrl.SysPort]->Debug)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SETDEBUG 0x%x\n", + p->RIOPortp[DebugCtrl.SysPort]->Debug); } else { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG 0x%x\n", - p->RIOPortp[DebugCtrl.SysPort]->Debug)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GETDEBUG 0x%x\n", + p->RIOPortp[DebugCtrl.SysPort]->Debug); DebugCtrl.Debug = p->RIOPortp[DebugCtrl.SysPort]->Debug; if ( copyout((caddr_t)&DebugCtrl,(int)arg, sizeof(DebugCtrl))==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_GETDEBUG: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GETDEBUG: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1111,12 +1111,12 @@ ** We return MAX_VERSION_LEN bytes, being a ** textual null terminated string. */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID\n") ); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_VERSID\n"); if ( copyout( (caddr_t)RIOVersid(), (int)arg, sizeof(struct rioVersion) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID: Bad copy to user space (host=%d)\n",Host) ); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_VERSID: Bad copy to user space (host=%d)\n", Host); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1150,10 +1150,10 @@ ** Enquire as to the number of hosts located ** at init time. */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_NUM_HOSTS\n"); if (copyout((caddr_t)&p->RIONumHosts, (int)arg, sizeof(p->RIONumHosts) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_NUM_HOSTS: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_NUM_HOSTS: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1163,9 +1163,9 @@ /* ** Kill host. This may not be in the final version... */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD %d\n", (int)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_FOAD %d\n", (int)arg); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_FOAD: Not super user\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_FOAD: Not super user\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } @@ -1213,27 +1213,27 @@ return retval; case RIO_DOWNLOAD: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD\n"); if ( !su ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Not super user\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Not super user\n"); p->RIOError.Error = NOT_SUPER_USER; return EPERM; } if ( copyin((int)arg, (caddr_t)&DownLoad, sizeof(DownLoad) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("Copied in download code for product code 0x%x\n", - DownLoad.ProductCode ) ); + rio_dprintk (RIO_DEBUG_CTRL, "Copied in download code for product code 0x%x\n", + DownLoad.ProductCode); /* ** It is important that the product code is an unsigned object! */ if ( DownLoad.ProductCode > MAX_PRODUCT ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_DOWNLOAD: Bad product code %d passed\n", - DownLoad.ProductCode)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Bad product code %d passed\n", + DownLoad.ProductCode); p->RIOError.Error = NO_SUCH_PRODUCT; return ENXIO; } @@ -1254,63 +1254,63 @@ if (copyin((int)arg, (caddr_t)&host, sizeof(host) ) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ( - "RIO_HOST_REQ: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, + "RIO_HOST_REQ: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } /* ** Fetch the parmmap */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PARMS\n"); if ( copyout( (caddr_t)p->RIOHosts[host].ParmMapP, (int)arg, sizeof(PARM_MAP) )==COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_PARMS: Copy out to user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_PARMS: Copy out to user space failed\n"); return EFAULT; } } return retval; case RIO_HOST_REQ: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ\n"); if (copyin((int)arg, (caddr_t)&HostReq, sizeof(HostReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if ( HostReq.HostNum >= p->RIONumHosts ) { p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Illegal host number %d\n", - HostReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ: Illegal host number %d\n", + HostReq.HostNum); return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for host %d\n", HostReq.HostNum); if (copyout((caddr_t)&p->RIOHosts[HostReq.HostNum], (int)HostReq.HostP,sizeof(struct Host) ) == COPYFAIL) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_REQ: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_REQ: Bad copy to user space\n"); return EFAULT; } return retval; case RIO_HOST_DPRAM: - rio_dprint(RIO_DEBUG_CTRL, ("Request for DPRAM\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Request for DPRAM\n"); if ( copyin( (int)arg, (caddr_t)&HostDpRam, sizeof(HostDpRam) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if ( HostDpRam.HostNum >= p->RIONumHosts ) { p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Illegal host number %d\n", - HostDpRam.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Illegal host number %d\n", + HostDpRam.HostNum); return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for host %d\n", HostDpRam.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for host %d\n", HostDpRam.HostNum); if (p->RIOHosts[HostDpRam.HostNum].Type == RIO_PCI) { int off; @@ -1321,7 +1321,7 @@ if ( copyout( (caddr_t)copy, (int)HostDpRam.DpRamP, sizeof(struct DpRam) ) == COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n"); return EFAULT; } } @@ -1329,15 +1329,15 @@ (int)HostDpRam.DpRamP, sizeof(struct DpRam) ) == COPYFAIL ) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_DPRAM: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n"); return EFAULT; } return retval; case RIO_SET_BUSY: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_BUSY\n"); if ( (int)arg < 0 || (int)arg > 511 ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SET_BUSY: Bad port number %d\n",(int)arg)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_BUSY: Bad port number %d\n",(int)arg); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1351,26 +1351,26 @@ ** The daemon want port information ** (probably for debug reasons) */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT\n"); if ( copyin((int)arg, (caddr_t)&PortReq, sizeof(PortReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if (PortReq.SysPort >= RIO_PORTS) { /* SysPort is unsigned */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Illegal port number %d\n", - PortReq.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT: Illegal port number %d\n", + PortReq.SysPort); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return ENXIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for port %d\n", PortReq.SysPort)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for port %d\n", PortReq.SysPort); if (copyout((caddr_t)p->RIOPortp[PortReq.SysPort], (int)PortReq.PortP, sizeof(struct Port) ) == COPYFAIL) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_PORT: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_PORT: Bad copy to user space\n"); return EFAULT; } return retval; @@ -1380,40 +1380,40 @@ ** The daemon want rup information ** (probably for debug reasons) */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP\n"); if (copyin((int)arg, (caddr_t)&RupReq, sizeof(RupReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Copy in from user space failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Copy in from user space failed\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if (RupReq.HostNum >= p->RIONumHosts) { /* host is unsigned */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal host number %d\n", - RupReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal host number %d\n", + RupReq.HostNum); p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; return ENXIO; } if ( RupReq.RupNum >= MAX_RUP+LINKS_PER_UNIT ) { /* eek! */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Illegal rup number %d\n", - RupReq.RupNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal rup number %d\n", + RupReq.RupNum); p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE; return EINVAL; } HostP = &p->RIOHosts[RupReq.HostNum]; if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Host %d not running\n", - RupReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Host %d not running\n", + RupReq.HostNum); p->RIOError.Error = HOST_NOT_RUNNING; return EIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for rup %d from host %d\n", - RupReq.RupNum,RupReq.HostNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for rup %d from host %d\n", + RupReq.RupNum,RupReq.HostNum); if (copyout((caddr_t)HostP->UnixRups[RupReq.RupNum].RupP, (int)RupReq.RupP,sizeof(struct RUP) ) == COPYFAIL) { p->RIOError.Error = COPYOUT_FAILED; - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_RUP: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_RUP: Bad copy to user space\n"); return EFAULT; } return retval; @@ -1423,39 +1423,39 @@ ** The daemon want lpb information ** (probably for debug reasons) */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB\n"); if (copyin((int)arg, (caddr_t)&LpbReq, sizeof(LpbReq) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy from user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy from user space\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } if (LpbReq.Host >= p->RIONumHosts) { /* host is unsigned */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal host number %d\n", - LpbReq.Host)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal host number %d\n", + LpbReq.Host); p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE; return ENXIO; } if ( LpbReq.Link >= LINKS_PER_UNIT ) { /* eek! */ - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Illegal link number %d\n", - LpbReq.Link)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal link number %d\n", + LpbReq.Link); p->RIOError.Error = LINK_NUMBER_OUT_OF_RANGE; return EINVAL; } HostP = &p->RIOHosts[LpbReq.Host]; if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Host %d not running\n", - LpbReq.Host)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Host %d not running\n", + LpbReq.Host ); p->RIOError.Error = HOST_NOT_RUNNING; return EIO; } - rio_dprint(RIO_DEBUG_CTRL, ("Request for lpb %d from host %d\n", - LpbReq.Link, LpbReq.Host)); + rio_dprintk (RIO_DEBUG_CTRL, "Request for lpb %d from host %d\n", + LpbReq.Link, LpbReq.Host); if (copyout((caddr_t)&HostP->LinkStrP[LpbReq.Link], (int)LpbReq.LpbP,sizeof(struct LPB) ) == COPYFAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_HOST_LPB: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1494,7 +1494,7 @@ p->RIOError.Error = NOT_RECEIVING_PROCESS; return EPERM; } - rio_dprint(RIO_DEBUG_CTRL, ("Clear signal process to zero\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Clear signal process to zero\n"); p->RIOSignalProcess = 0; return retval; @@ -1526,10 +1526,10 @@ case RIO_MAP_B50_TO_57600: case RIO_MAP_B110_TO_110: case RIO_MAP_B110_TO_115200: - rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Baud rate mapping\n"); port = (uint) arg; if ( port < 0 || port > 511 ) { - rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", port)); + rio_dprintk (RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1553,14 +1553,14 @@ return retval; case RIO_STREAM_INFO: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_STREAM_INFO\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_STREAM_INFO\n"); return EINVAL; case RIO_SEND_PACKET: - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SEND_PACKET\n"); if ( copyin( (int)arg, (caddr_t)&SendPack, sizeof(SendPack) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_SEND_PACKET: Bad copy from user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SEND_PACKET: Bad copy from user space\n"); p->RIOError.Error = COPYIN_FAILED; return EFAULT; } @@ -1605,7 +1605,7 @@ case RIO_WHAT_MESG: if ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, sizeof(p->RIONoMessage) )==COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_WHAT_MESG: Bad copy to user space\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_WHAT_MESG: Bad copy to user space\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1617,8 +1617,8 @@ p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP host %d rup %d addr %x\n", - SubCmd.Host, SubCmd.Rup, SubCmd.Addr)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP host %d rup %d addr %x\n", + SubCmd.Host, SubCmd.Rup, SubCmd.Addr); if (SubCmd.Rup >= MAX_RUP+LINKS_PER_UNIT ) { p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE; @@ -1638,7 +1638,7 @@ rio_spin_lock_irqsave(&PortP->portSem, flags); if ( RIOPreemptiveCmd(p, PortP, MEMDUMP ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n"); rio_spin_unlock_irqrestore( &PortP->portSem , flags); return EBUSY; } @@ -1648,7 +1648,7 @@ rio_spin_unlock_irqrestore( &PortP->portSem , flags); if ( copyout( (caddr_t)p->RIOMemDump, (int)arg, MEMDUMP_SIZE) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_MEM_DUMP copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1657,14 +1657,14 @@ case RIO_TICK: if ((int)arg < 0 || (int)arg >= p->RIONumHosts) return EINVAL; - rio_dprint(RIO_DEBUG_CTRL, ("Set interrupt for host %d\n", (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Set interrupt for host %d\n", (int)arg); WBYTE(p->RIOHosts[(int)arg].SetInt , 0xff); return 0; case RIO_TOCK: if ((int)arg < 0 || (int)arg >= p->RIONumHosts) return EINVAL; - rio_dprint(RIO_DEBUG_CTRL, ("Clear interrupt for host %d\n", (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Clear interrupt for host %d\n", (int)arg); WBYTE((p->RIOHosts[(int)arg].ResetInt) , 0xff); return 0; @@ -1684,12 +1684,12 @@ p->RIOError.Error = COPYIN_FAILED; return EFAULT; } - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER host %d rup %d port %d reg %x\n", - SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr)); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_REGISTER host %d rup %d port %d reg %x\n", + SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr); if (SubCmd.Port > 511) { - rio_dprint(RIO_DEBUG_CTRL, ("Baud rate mapping: Bad port number %d\n", - SubCmd.Port)); + rio_dprintk (RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", + SubCmd.Port); p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1711,7 +1711,7 @@ rio_spin_lock_irqsave(&PortP->portSem, flags); if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n"); rio_spin_unlock_irqrestore( &PortP->portSem , flags); return EBUSY; } @@ -1721,7 +1721,7 @@ rio_spin_unlock_irqrestore( &PortP->portSem , flags); if (copyout((caddr_t)&p->CdRegister, (int)arg, sizeof(uint)) == COPYFAIL ) { - rio_dprint(RIO_DEBUG_CTRL, ("RIO_READ_REGISTER copy failed\n")); + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_REGISTER copy failed\n"); p->RIOError.Error = COPYOUT_FAILED; return EFAULT; } @@ -1738,18 +1738,18 @@ switch ( (uint)arg & RIO_DEV_MASK ) { case RIO_DEV_DIRECT: arg = (caddr_t)drv_makedev(major(dev), port); - rio_dprint(RIO_DEBUG_CTRL, ("Makedev direct 0x%x is 0x%x\n",port, (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev direct 0x%x is 0x%x\n",port, (int)arg); return (int)arg; case RIO_DEV_MODEM: arg = (caddr_t)drv_makedev(major(dev), (port|RIO_MODEM_BIT) ); - rio_dprint(RIO_DEBUG_CTRL, ("Makedev modem 0x%x is 0x%x\n",port, (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev modem 0x%x is 0x%x\n",port, (int)arg); return (int)arg; case RIO_DEV_XPRINT: arg = (caddr_t)drv_makedev(major(dev), port); - rio_dprint(RIO_DEBUG_CTRL, ("Makedev printer 0x%x is 0x%x\n",port, (int)arg )); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev printer 0x%x is 0x%x\n",port, (int)arg); return (int)arg; } - rio_dprint(RIO_DEBUG_CTRL, ("MAKE Device is called\n")); + rio_dprintk (RIO_DEBUG_CTRL, "MAKE Device is called\n"); return EINVAL; } /* @@ -1766,17 +1766,17 @@ mino = RIO_UNMODEM(dv); if ( RIO_ISMODEM(dv) ) { - rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: modem %d\n", dv, mino)); + rio_dprintk (RIO_DEBUG_CTRL, "Minor for device 0x%x: modem %d\n", dv, mino); arg = (caddr_t)(mino | RIO_DEV_MODEM); } else { - rio_dprint(RIO_DEBUG_CTRL, ("Minor for device 0x%x: direct %d\n", dv, mino)); + rio_dprintk (RIO_DEBUG_CTRL, "Minor for device 0x%x: direct %d\n", dv, mino); arg = (caddr_t)(mino | RIO_DEV_DIRECT); } return (int)arg; } } - rio_dprint(RIO_DEBUG_CTRL, ("INVALID DAEMON IOCTL 0x%x\n",cmd)); + rio_dprintk (RIO_DEBUG_CTRL, "INVALID DAEMON IOCTL 0x%x\n",cmd); p->RIOError.Error = IOCTL_COMMAND_UNKNOWN; func_exit (); @@ -1803,18 +1803,18 @@ #endif if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_CTRL, ("Preemptive command to deleted RTA ignored\n")); + rio_dprintk (RIO_DEBUG_CTRL, "Preemptive command to deleted RTA ignored\n"); return RIO_FAIL; } if (((int)((char)PortP->InUse) == -1) || ! (CmdBlkP = RIOGetCmdBlk()) ) { - rio_dprint(RIO_DEBUG_CTRL, ("Cannot allocate command block for command %d on port %d\n", - Cmd, PortP->PortNum)); + rio_dprintk (RIO_DEBUG_CTRL, "Cannot allocate command block for command %d on port %d\n", + Cmd, PortP->PortNum); return RIO_FAIL; } - rio_dprint(RIO_DEBUG_CTRL, ("Command blk 0x%x - InUse now %d\n", - (int)CmdBlkP,PortP->InUse)); + rio_dprintk (RIO_DEBUG_CTRL, "Command blk 0x%x - InUse now %d\n", + (int)CmdBlkP,PortP->InUse); PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0]; @@ -1840,40 +1840,40 @@ switch ( Cmd ) { case MEMDUMP: - rio_dprint(RIO_DEBUG_CTRL, ("Queue MEMDUMP command blk 0x%x (addr 0x%x)\n", - (int)CmdBlkP, (int)SubCmd.Addr)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue MEMDUMP command blk 0x%x (addr 0x%x)\n", + (int)CmdBlkP, (int)SubCmd.Addr); PktCmdP->SubCommand = MEMDUMP; PktCmdP->SubAddr = SubCmd.Addr; break; case FCLOSE: - rio_dprint(RIO_DEBUG_CTRL, ("Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP); break; case READ_REGISTER: - rio_dprint(RIO_DEBUG_CTRL, ("Queue READ_REGISTER (0x%x) command blk 0x%x\n", - (int)SubCmd.Addr, (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk 0x%x\n", + (int)SubCmd.Addr, (int)CmdBlkP); PktCmdP->SubCommand = READ_REGISTER; PktCmdP->SubAddr = SubCmd.Addr; break; case RESUME: - rio_dprint(RIO_DEBUG_CTRL, ("Queue RESUME command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue RESUME command blk 0x%x\n",(int)CmdBlkP); break; case RFLUSH: - rio_dprint(RIO_DEBUG_CTRL, ("Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP); CmdBlkP->PostFuncP = RIORFlushEnable; break; case SUSPEND: - rio_dprint(RIO_DEBUG_CTRL, ("Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP); break; case MGET : - rio_dprint(RIO_DEBUG_CTRL, ("Queue MGET command blk 0x%x\n", (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue MGET command blk 0x%x\n", (int)CmdBlkP); break; case MSET : case MBIC : case MBIS : CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; - rio_dprint(RIO_DEBUG_CTRL, ("Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP); break; case WFLUSH: @@ -1883,12 +1883,12 @@ ** RTA. */ if ((int)((char)PortP->WflushFlag) == (int)-1) { - rio_dprint(RIO_DEBUG_CTRL, ("Trashed WFLUSH, WflushFlag about to wrap!")); + rio_dprintk (RIO_DEBUG_CTRL, "Trashed WFLUSH, WflushFlag about to wrap!"); RIOFreeCmdBlk(CmdBlkP); return(RIO_FAIL); } else { - rio_dprint(RIO_DEBUG_CTRL, ("Queue WFLUSH command blk 0x%x\n", - (int)CmdBlkP)); + rio_dprintk (RIO_DEBUG_CTRL, "Queue WFLUSH command blk 0x%x\n", + (int)CmdBlkP); CmdBlkP->PostFuncP = RIOWFlushMark; } break; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rioinit.c linux/drivers/char/rio/rioinit.c --- v2.4.0-test6/linux/drivers/char/rio/rioinit.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/rioinit.c Fri Aug 11 14:51:33 2000 @@ -81,7 +81,7 @@ #include "control.h" #include "cirrus.h" #include "rioioctl.h" - +#include "rio_linux.h" #undef bcopy #define bcopy rio_pcicopy @@ -109,7 +109,7 @@ */ if ( !p->RIOPortp ) { - rio_dprint(RIO_DEBUG_INIT, ("Allocating and setting up driver data structures\n") ); + rio_dprintk (RIO_DEBUG_INIT, "Allocating and setting up driver data structures\n"); RIOAllocDataStructs(p); /* allocate host/port structs */ RIOSetupDataStructs(p); /* setup topology structs */ @@ -155,16 +155,16 @@ if ( info->bus & ISA_BUS ) { - rio_dprint(RIO_DEBUG_INIT, ("initialising card %d (ISA)\n", p->RIONumHosts) ); + rio_dprintk (RIO_DEBUG_INIT, "initialising card %d (ISA)\n", p->RIONumHosts); RIOISAinit(p, p->mode); } else { - rio_dprint(RIO_DEBUG_INIT, ("initialising card %d (PCI)\n", p->RIONumHosts) ); + rio_dprintk (RIO_DEBUG_INIT, "initialising card %d (PCI)\n", p->RIONumHosts); RIOPCIinit(p, RIO_PCI_DEFAULT_MODE); } - rio_dprint(RIO_DEBUG_INIT, ("Total hosts initialised so far : %d\n", p->RIONumHosts) ); + rio_dprintk (RIO_DEBUG_INIT, "Total hosts initialised so far : %d\n", p->RIONumHosts); #ifdef FUTURE_RELEASE @@ -193,13 +193,13 @@ p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec, (int (*)())rio_intr, (char*)p->RIONumHosts); - rio_dprint(RIO_DEBUG_INIT, ("Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ) ); + rio_dprintk (RIO_DEBUG_INIT, "Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ); if (RIODoAT(p, p->RIOHosts[p->RIONumHosts].PaddrP, mode)) { return; } else { - rio_dprint(RIO_DEBUG_INIT, ("RIODoAT failed\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIODoAT failed\n"); p->RIOFailed++; } #endif @@ -268,7 +268,7 @@ ** map it in in one 64K block. */ if (RIOMapin(Base, RIO_AT_MEM_SIZE, &virtAddr) == -1) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't map the board in!\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Couldn't map the board in!\n"); return((caddr_t)0); } @@ -285,8 +285,8 @@ ** Signature mismatch - card not at this address */ RIOMapout(Base, RIO_AT_MEM_SIZE, virtAddr); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Couldn't match the signature 0x%x 0x%x!\n", - (int)cardp, off)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Couldn't match the signature 0x%x 0x%x!\n", + (int)cardp, off); return((caddr_t)0); } } @@ -356,10 +356,10 @@ ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)| ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)| ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum); p->RIONumHosts++; - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Tests Passed at 0x%x\n", Base)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Tests Passed at 0x%x\n", Base); return(1); } #if 0 @@ -378,7 +378,7 @@ ** is only FAST LINKS */ Mode = (Mode & FAST_LINKS) ? McaTpFastLinks : McaTpSlowLinks; - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOMCAinit(%d)\n",Mode); + rio_dprintk (RIO_DEBUG_INIT, "RIOMCAinit(%d)\n",Mode); /* @@ -395,7 +395,7 @@ */ if (((inb(McaIdHigh)<< 8)|inb(McaIdLow)) == McaRIOId) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Potential MCA card in slot %d\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Potential MCA card in slot %d\n", SlotNumber); /* ** Card appears to be a RIO MCA card! @@ -417,48 +417,44 @@ */ Ivec = inb(McaIrqEnable); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Ivec is %x\n",Ivec); + rio_dprintk (RIO_DEBUG_INIT, "Ivec is %x\n", Ivec); switch ( Ivec & McaIrqMask ) { case McaIrq9: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ9\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ9\n"); break; case McaIrq3: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ3\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ3\n"); break; case McaIrq4: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ4\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ4\n"); break; case McaIrq7: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ7\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ7\n"); break; case McaIrq10: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ10\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ10\n"); break; case McaIrq11: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ11\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ11\n"); break; case McaIrq12: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ12\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ12\n"); break; case McaIrq15: - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"IRQ15\n"); + rio_dprintk (RIO_DEBUG_INIT, "IRQ15\n"); break; } /* ** If the card enable bit isn't set, then set it! */ - if ((Ivec & McaCardEnable) != McaCardEnable ) - { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable not set - setting!\n"); - outb(McaIrqEnable,Ivec|McaCardEnable); - } - else - { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"McaCardEnable already set\n"); - } + if ((Ivec & McaCardEnable) != McaCardEnable) { + rio_dprintk (RIO_DEBUG_INIT, "McaCardEnable not set - setting!\n"); + outb(McaIrqEnable,Ivec|McaCardEnable); + } else + rio_dprintk (RIO_DEBUG_INIT, "McaCardEnable already set\n"); /* ** Convert the IRQ enable mask into something useful @@ -468,10 +464,10 @@ /* ** Find the physical address */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"inb(McaMemory) is %x\n",inb(McaMemory)); + rio_dprintk (RIO_DEBUG_INIT, "inb(McaMemory) is %x\n", inb(McaMemory)); Paddr = McaAddress(inb(McaMemory)); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"MCA card has Ivec %d Addr %x\n",Ivec,Paddr); + rio_dprintk (RIO_DEBUG_INIT, "MCA card has Ivec %d Addr %x\n", Ivec, Paddr); if ( Paddr != 0 ) { @@ -482,21 +478,20 @@ Handle = RIOMapin( Paddr, RIO_MCA_MEM_SIZE, &Caddr ); if ( Handle == -1 ) { - rio_dprint(RIO_DEBUG_INIT, ("Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE,Paddr); + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE, Paddr; continue; } - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board mapped to vaddr 0x%x\n",Caddr); + rio_dprintk (RIO_DEBUG_INIT, "Board mapped to vaddr 0x%x\n", Caddr); /* ** And check that it is actually there! */ if ( RIOBoardTest( Paddr,Caddr,RIO_MCA,SlotNumber ) == RIO_SUCCESS ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Board has passed test\n"); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, - "Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", - SlotNumber,RIO_MCA,Paddr,Caddr,Mode); + rio_dprintk (RIO_DEBUG_INIT, "Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", + SlotNumber, RIO_MCA, Paddr, Caddr, Mode); /* ** Board has passed its scrub test. Fill in all the @@ -524,25 +519,25 @@ /* ** It failed the test, so ignore it. */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_FAIL,"TEST FAILED\n"); + rio_dprintk (RIO_DEBUG_INIT, "TEST FAILED\n"); RIOMapout(Paddr, RIO_MCA_MEM_SIZE, Caddr ); } } else { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d - Paddr zero!\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d - Paddr zero!\n", SlotNumber); } } else { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d NOT RIO\n", SlotNumber); } } /* ** Now we have checked all the slots, turn off the MCA slot selector */ outb(McaSlotSelect,0); - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Slot %d NOT RIO\n",SlotNumber); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d NOT RIO\n", SlotNumber); return ret; } @@ -565,13 +560,13 @@ if ( EISADone ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit() - already done, return.\n"); + rio_dprintk (RIO_DEBUG_INIT, "RIOEISAinit() - already done, return.\n"); return(0); } EISADone++; - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIOEISAinit()\n"); + rio_dprintk (RIO_DEBUG_INIT, "RIOEISAinit()\n"); /* @@ -584,23 +579,21 @@ Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) | INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO); - /* rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT, "Check EISA slot %d, ID=%x\n",EisaSlot,Ident); */ - if ( Ident == RIO_EISA_IDENT ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Found Specialix product\n"); + rio_dprintk (RIO_DEBUG_INIT, "Found Specialix product\n"); if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Not Specialix RIO - Product number %x\n", - INBZ(EisaSlot,EISA_PRODUCT_NUMBER)); + rio_dprintk (RIO_DEBUG_INIT, "Not Specialix RIO - Product number %x\n", + INBZ(EisaSlot, EISA_PRODUCT_NUMBER)); continue; /* next slot */ } /* ** Its a Specialix RIO! */ - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"RIO Revision %d\n", - INBZ(EisaSlot,EISA_REVISION_NUMBER)); + rio_dprintk (RIO_DEBUG_INIT, "RIO Revision %d\n", + INBZ(EisaSlot, EISA_REVISION_NUMBER)); RIOMachineType |= (1<RIOLastPCISearch != RIO_SUCCESS) ) { - rio_dprint(RIO_DEBUG_INIT, ("Currently testing slot %d\n", slot ) ); + rio_dprintk (RIO_DEBUG_INIT, "Currently testing slot %d\n", slot); if (read_config(0,slot,0) == RIO_PCI_JET_CARD) { p->RIOHosts[p->RIONumHosts].Ivec = 0; @@ -934,7 +927,7 @@ Paddr = Paddr - (Paddr & 0x1); /* Mask off the io bit */ if ( (Paddr == 0) || ((Paddr & 0xffff0000) == 0xffff0000) ) { - rio_dprint(RIO_DEBUG_INIT, ("Goofed up slot\n") ); /* what! */ + rio_dprintk (RIO_DEBUG_INIT, "Goofed up slot\n"); /* what! */ slot++; continue; } @@ -942,11 +935,11 @@ p->RIOHosts[p->RIONumHosts].PaddrP = Paddr; Ivec = (read_config(0,slot,0x3c) & 0xff); - rio_dprint(RIO_DEBUG_INIT, ("PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec ) ); + rio_dprintk (RIO_DEBUG_INIT, "PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec); Handle = RIOMapin( Paddr, RIO_PCI_MEM_SIZE, &Caddr ); if (Handle == -1) { - rio_dprint(RIO_DEBUG_INIT, ("Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr ) ); + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr); slot++; continue; } @@ -954,9 +947,8 @@ p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec, (int (*)())rio_intr, (char *)p->RIONumHosts); if (RIOBoardTest( Paddr, Caddr, RIO_PCI, 0 ) == RIO_SUCCESS) { - rio_dprint(RIO_DEBUG_INIT, ("Board has passed test\n")); - rio_dprint(RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, - Mode)); + rio_dprintk (RIO_DEBUG_INIT, ("Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, Mode); /* ** Board has passed its scrub test. Fill in all the @@ -991,8 +983,8 @@ ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)| ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24); - rio_dprint(RIO_DEBUG_INIT, ("Unique no 0x%x.\n", - p->RIOHosts[p->RIONumHosts].UniqueNum ) ); + rio_dprintk (RIO_DEBUG_INIT, "Unique no 0x%x.\n", + p->RIOHosts[p->RIONumHosts].UniqueNum); p->RIOLastPCISearch = RIO_SUCCESS; p->RIONumHosts++; @@ -1002,8 +994,8 @@ } if ( slot >= MAX_PCI_SLOT ) { - rio_dprint(RIO_DEBUG_INIT, ("All %d PCI slots have tested for RIO cards !!!\n", - MAX_PCI_SLOT ) ); + rio_dprintk (RIO_DEBUG_INIT, "All %d PCI slots have tested for RIO cards !!!\n", + MAX_PCI_SLOT); } @@ -1025,7 +1017,7 @@ int host; for ( host=0; hostRIONumHosts; host++ ) { - rio_dprint(RIO_DEBUG_INIT, NULL,DBG_INIT,"Stop host %d\n",host); + rio_dprintk (RIO_DEBUG_INIT, "Stop host %d\n", host); (void)RIOBoardTest( p->RIOHosts[host].PaddrP, p->RIOHosts[host].Caddr, p->RIOHosts[host].Type,p->RIOHosts[host].Slot ); } } @@ -1058,8 +1050,8 @@ int op, bank; int nbanks; - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n", - type,(int)DpRam,slot)); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n", + type,(int)DpRam, slot); RIOHostReset(type, DpRam, slot); @@ -1071,7 +1063,7 @@ ** scratch - 1000h bytes */ - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Setup ram/size arrays\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Setup ram/size arrays\n"); size[0] = DP_SRAM1_SIZE; size[1] = DP_SRAM2_SIZE; @@ -1087,12 +1079,12 @@ if (nbanks == 3) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", - (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2])); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", + (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2]); } else { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2], (int)ram[3], - size[3])); + size[3]); } /* @@ -1103,14 +1095,14 @@ for (op=0; opRIOPortp = (struct Port *)sysbrk(RIO_PORTS * sizeof(struct Port)); if (!p->RIOPortp) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for port structures\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: No memory for port structures\n"); p->RIOFailed++; return; } bzero( p->RIOPortp, sizeof(struct Port) * RIO_PORTS ); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: allocated and cleared memory for port structs\n") ); - rio_dprint(RIO_DEBUG_INIT, ("First RIO port struct @0x%x, size=0x%x bytes\n", - (int)p->RIOPortp, sizeof(struct Port) ) ); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: allocated and cleared memory for port structs\n"); + rio_dprintk (RIO_DEBUG_INIT, "First RIO port struct @0x%x, size=0x%x bytes\n", + (int)p->RIOPortp, sizeof(struct Port)); for( port=0; portRIOPortp[port].PortNum = port; @@ -1404,14 +1396,14 @@ p->RIOHosts = (struct Host *)sysbrk(RIO_HOSTS * sizeof(struct Host)); if (!p->RIOHosts) { - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: No memory for host structures\n")); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: No memory for host structures\n"); p->RIOFailed++; return; } bzero(p->RIOHosts, sizeof(struct Host)*RIO_HOSTS); - rio_dprint(RIO_DEBUG_INIT, ("RIO-init: allocated and cleared memory for host structs\n")); - rio_dprint(RIO_DEBUG_INIT, ("First RIO host struct @0x%x, size=0x%x bytes\n", - (int)p->RIOHosts, sizeof(struct Host) ) ); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: allocated and cleared memory for host structs\n"); + rio_dprintk (RIO_DEBUG_INIT, "First RIO host struct @0x%x, size=0x%x bytes\n", + (int)p->RIOHosts, sizeof(struct Host)); for( host=0; hostRIOHosts[host].HostLock); @@ -1494,10 +1486,10 @@ char * RIORelID = RELEASE_ID; int host; - rio_dprint(RIO_DEBUG_INIT, ("RIO : Release: %s ID: %s\n", RIORelease, RIORelID)); + rio_dprintk (RIO_DEBUG_INIT, "RIO : Release: %s ID: %s\n", RIORelease, RIORelID); if ( p->RIONumHosts==0 ) { - rio_dprint(RIO_DEBUG_INIT, ("\nNo Hosts configured\n")); + rio_dprintk (RIO_DEBUG_INIT, "\nNo Hosts configured\n"); return(0); } @@ -1505,7 +1497,7 @@ struct Host *HostP = &p->RIOHosts[host]; switch ( HostP->Type ) { case RIO_AT: - rio_dprint(RIO_DEBUG_INIT, ("AT BUS : found the card at 0x%x\n", HostP->PaddrP)); + rio_dprintk (RIO_DEBUG_INIT, "AT BUS : found the card at 0x%x\n", HostP->PaddrP); } } return 0; @@ -1587,17 +1579,17 @@ /* ** Reset the Tpu */ - rio_dprint(RIO_DEBUG_INIT, ("RIOHostReset: type 0x%x", Type ) ); + rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: type 0x%x", Type); switch ( Type ) { case RIO_AT: - rio_dprint(RIO_DEBUG_INIT, (" (RIO_AT)\n")); + rio_dprintk (RIO_DEBUG_INIT, " (RIO_AT)\n"); WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); WBYTE(DpRamP->DpResetTpu, 0xFF); rio_udelay (3); - rio_dprint(RIO_DEBUG_INIT, ("RIOHostReset: Don't know if it worked. Try reset again\n") ); + rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); @@ -1630,7 +1622,7 @@ break; #endif case RIO_PCI: - rio_dprint(RIO_DEBUG_INIT, (" (RIO_PCI)\n") ); + rio_dprintk (RIO_DEBUG_INIT, " (RIO_PCI)\n"); DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; DpRamP->DpResetInt = 0xFF; DpRamP->DpResetTpu = 0xFF; @@ -1645,7 +1637,7 @@ #endif default: - rio_dprint(RIO_DEBUG_INIT, (" (UNKNOWN)\n") ); + rio_dprintk (RIO_DEBUG_INIT, " (UNKNOWN)\n"); break; } return; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/riointr.c linux/drivers/char/rio/riointr.c --- v2.4.0-test6/linux/drivers/char/rio/riointr.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/rio/riointr.c Fri Aug 11 14:51:33 2000 @@ -190,8 +190,8 @@ tty = PortP->gs.tty; - rio_dprint (RIO_DEBUG_INTR, ("tx port %d: %d chars queued.\n", - PortP->PortNum, PortP->gs.xmit_cnt)); + rio_dprintk (RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", + PortP->PortNum, PortP->gs.xmit_cnt); if (!PortP->gs.xmit_cnt) return; @@ -215,10 +215,10 @@ { int t; t = (c > 10)?10:c; - rio_dprint (RIO_DEBUG_INTR, ("tx port %d: copying %d chars: %s - %s\n", - PortP->PortNum, c, - firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail , t), - firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t))); + rio_dprintk (RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n", + PortP->PortNum, c, + firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail , t), + firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t)); } /* If for one reason or another, we can't copy more data, we're done! */ @@ -244,14 +244,14 @@ rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2*PKT_MAX_DATA_LEN)) { - rio_dprint (RIO_DEBUG_INTR, ("Waking up.... ldisc:%d (%d/%d)....", + rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), - PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); + PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty); - rio_dprint (RIO_DEBUG_INTR, ("(%d/%d)\n", - PortP->gs.wakeup_chars, PortP->gs.xmit_cnt)); + rio_dprintk (RIO_DEBUG_INTR, "(%d/%d)\n", + PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); wake_up_interruptible(&PortP->gs.tty->write_wait); } @@ -273,7 +273,7 @@ for ( host=0; hostRIONumHosts; host++ ) { struct Host *HostP = &p->RIOHosts[host]; - rio_dprint(RIO_DEBUG_INTR, ("riointr() doing host %d type %d\n", host, HostP->Type ) ); + rio_dprintk (RIO_DEBUG_INTR, "riointr() doing host %d type %d\n", host, HostP->Type); switch( HostP->Type ) { case RIO_AT: @@ -363,7 +363,7 @@ static int t =0; rio_spin_unlock (&HostP->HostLock); if ((t++ % 200) == 0) - rio_dprint(RIO_DEBUG_INTR, ("Interrupt but host not running. flags=%x.\n", (int)HostP->Flags)); + rio_dprintk (RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int)HostP->Flags); return; } rio_spin_unlock (&HostP->HostLock); @@ -372,7 +372,7 @@ WWORD( HostP->ParmMapP->rup_intr , 0 ); p->RIORupCount++; RupIntr++; - rio_dprint(RIO_DEBUG_INTR, ("RUP interrupt on host %d\n", HostP-p->RIOHosts )); + rio_dprintk (RIO_DEBUG_INTR, "rio: RUP interrupt on host %d\n", HostP-p->RIOHosts); RIOPollHostCommands(p, HostP ); } @@ -383,7 +383,7 @@ p->RIORxCount++; RxIntr++; - rio_dprint(RIO_DEBUG_INTR, ("RX interrupt on host %d\n", HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_INTR, "rio: RX interrupt on host %d\n", HostP-p->RIOHosts); /* ** Loop through every port. If the port is mapped into ** the system ( i.e. has /dev/ttyXXXX associated ) then it is @@ -451,7 +451,7 @@ ** MAGIC! ( Basically, handshake the RX buffer, so that ** the RTAs upstream can be re-enabled. ) */ - rio_dprint(RIO_DEBUG_INTR, ("Set RX handshake bit\n" )); + rio_dprintk (RIO_DEBUG_INTR, "Set RX handshake bit\n"); WWORD( PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET ); } @@ -466,7 +466,7 @@ p->RIOTxCount++; TxIntr++; - rio_dprint(RIO_DEBUG_INTR, ("TX interrupt on host %d\n", HostP-p->RIOHosts)); + rio_dprintk (RIO_DEBUG_INTR, "rio: TX interrupt on host %d\n", HostP-p->RIOHosts); /* ** Loop through every port. @@ -504,7 +504,7 @@ continue; } - rio_dprint (RIO_DEBUG_INTR, ("Looking into port %d.\n", port)); + rio_dprintk (RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port); /* ** Lock the port before we begin working on it. */ @@ -515,7 +515,7 @@ ** we need do none of this processing. */ if ( !can_add_transmit( &PacketP, PortP ) ) { - rio_dprint (RIO_DEBUG_INTR, ("Can't add to port, so skipping.\n")); + rio_dprintk (RIO_DEBUG_INTR, "Can't add to port, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } @@ -527,7 +527,7 @@ ttyP = PortP->gs.tty; /* If ttyP is NULL, the port is getting closed. Forget about it. */ if (!ttyP) { - rio_dprint (RIO_DEBUG_INTR, ("no tty, so skipping.\n")); + rio_dprintk (RIO_DEBUG_INTR, "no tty, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } @@ -603,10 +603,10 @@ ** with WFLUSH */ if ( PortP->WflushFlag ) { - rio_dprint(RIO_DEBUG_INTR, ("Want to WFLUSH mark this port\n")); + rio_dprintk (RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n"); if ( PortP->InUse ) - rio_dprint(RIO_DEBUG_INTR, ("FAILS - PORT IS IN USE\n")); + rio_dprintk (RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n"); } while ( PortP->WflushFlag && @@ -615,7 +615,7 @@ int p; struct PktCmd *PktCmdP; - rio_dprint(RIO_DEBUG_INTR, ("Add WFLUSH marker to data queue\n")); + rio_dprintk (RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n"); /* ** make it look just like a WFLUSH command */ @@ -670,8 +670,8 @@ PortP->MagicFlags &= ~MAGIC_FLUSH; } - rio_dprint(RIO_DEBUG_INTR, ("Wflush count now stands at %d\n", - PortP->WflushFlag)); + rio_dprintk (RIO_DEBUG_INTR, "Wflush count now stands at %d\n", + PortP->WflushFlag); } if ( PortP->MagicFlags & MORE_OUTPUT_EYGOR ) { if ( PortP->MagicFlags & MAGIC_FLUSH ) { @@ -747,12 +747,12 @@ TtyP = PortP->gs.tty; if (!TtyP) { - rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: tty is null. \n")); + rio_dprintk (RIO_DEBUG_INTR, "RIOReceive: tty is null. \n"); return; } if (PortP->State & RIO_THROTTLE_RX) { - rio_dprint (RIO_DEBUG_INTR, ("RIOReceive: Throttled. Can't handle more input.\n")); + rio_dprintk (RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n"); return; } @@ -786,18 +786,18 @@ ** check that it is not a command! */ if ( PacketP->len & PKT_CMD_BIT ) { - rio_dprint(RIO_DEBUG_INTR, ("RIO: unexpected command packet received on PHB\n")); + rio_dprintk (RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n"); /* rio_dprint(RIO_DEBUG_INTR, (" sysport = %d\n", p->RIOPortp->PortNum)); */ - rio_dprint(RIO_DEBUG_INTR, (" dest_unit = %d\n", PacketP->dest_unit)); - rio_dprint(RIO_DEBUG_INTR, (" dest_port = %d\n", PacketP->dest_port)); - rio_dprint(RIO_DEBUG_INTR, (" src_unit = %d\n", PacketP->src_unit)); - rio_dprint(RIO_DEBUG_INTR, (" src_port = %d\n", PacketP->src_port)); - rio_dprint(RIO_DEBUG_INTR, (" len = %d\n", PacketP->len)); - rio_dprint(RIO_DEBUG_INTR, (" control = %d\n", PacketP->control)); - rio_dprint(RIO_DEBUG_INTR, (" csum = %d\n", PacketP->csum)); - rio_dprint(RIO_DEBUG_INTR, (" data bytes: ")); + rio_dprintk (RIO_DEBUG_INTR, " dest_unit = %d\n", PacketP->dest_unit); + rio_dprintk (RIO_DEBUG_INTR, " dest_port = %d\n", PacketP->dest_port); + rio_dprintk (RIO_DEBUG_INTR, " src_unit = %d\n", PacketP->src_unit); + rio_dprintk (RIO_DEBUG_INTR, " src_port = %d\n", PacketP->src_port); + rio_dprintk (RIO_DEBUG_INTR, " len = %d\n", PacketP->len); + rio_dprintk (RIO_DEBUG_INTR, " control = %d\n", PacketP->control); + rio_dprintk (RIO_DEBUG_INTR, " csum = %d\n", PacketP->csum); + rio_dprintk (RIO_DEBUG_INTR, " data bytes: "); for ( DataCnt=0; DataCntdata[DataCnt])); + rio_dprintk (RIO_DEBUG_INTR, "%d\n", PacketP->data[DataCnt]); remove_receive( PortP ); put_free_end( PortP->HostP, PacketP ); continue; /* with next packet */ @@ -820,8 +820,8 @@ transCount = min(PacketP->len & PKT_LEN_MASK, TTY_FLIPBUF_SIZE - TtyP->flip.count); - rio_dprint(RIO_DEBUG_REC, ("port %d: Copy %d bytes\n", - PortP->PortNum, transCount ) ); + rio_dprintk (RIO_DEBUG_REC, "port %d: Copy %d bytes\n", + PortP->PortNum, transCount); /* ** To use the following 'kkprintfs' for debugging - change the '#undef' ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the @@ -880,7 +880,7 @@ } } if (copied) { - rio_dprint ( RIO_DEBUG_REC, ("port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied)); + rio_dprintk (RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied); tty_flip_buffer_push (TtyP); } @@ -906,25 +906,25 @@ SysPort = port; /* Believe me, it works. */ if ( SysPort < 0 || SysPort >= RIO_PORTS ) { - rio_dprint(RIO_DEBUG_INTR, ("Illegal port %d derived from TTY in riotproc()\n",SysPort)); + rio_dprintk (RIO_DEBUG_INTR, "Illegal port %d derived from TTY in riotproc()\n",SysPort); return 0; } PortP = p->RIOPortp[SysPort]; if ((uint)PortP->PhbP < (uint)PortP->Caddr || (uint)PortP->PhbP >= (uint)PortP->Caddr+SIXTY_FOUR_K ) { - rio_dprint(RIO_DEBUG_INTR, ("RIO: NULL or BAD PhbP on sys port %d in proc routine\n", - SysPort)); - rio_dprint(RIO_DEBUG_INTR, (" PortP = 0x%x\n",PortP)); - rio_dprint(RIO_DEBUG_INTR, (" PortP->PhbP = 0x%x\n",PortP->PhbP)); - rio_dprint(RIO_DEBUG_INTR, (" PortP->Caddr = 0x%x\n",PortP->PhbP)); - rio_dprint(RIO_DEBUG_INTR, (" PortP->HostPort = 0x%x\n",PortP->HostPort)); + rio_dprintk (RIO_DEBUG_INTR, "RIO: NULL or BAD PhbP on sys port %d in proc routine\n", + SysPort); + rio_dprintk (RIO_DEBUG_INTR, " PortP = 0x%x\n",PortP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->PhbP = 0x%x\n",PortP->PhbP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->Caddr = 0x%x\n",PortP->PhbP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->HostPort = 0x%x\n",PortP->HostPort); return 0; } switch(cmd) { case T_WFLUSH: - rio_dprint(RIO_DEBUG_INTR, "T_WFLUSH\n"); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH\n"); /* ** Because of the spooky way the RIO works, we don't need ** to issue a flush command on any of the SET*F commands, @@ -941,14 +941,14 @@ ** form a wflush packet - 1 byte long, no data */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("WFLUSH on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "WFLUSH on deleted RTA\n"); } else { if ( RIOPreemptiveCmd(p, PortP, WFLUSH ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command failed\n"); } else - rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command\n"); } /* ** WFLUSH operation - flush the data! @@ -956,7 +956,7 @@ PortP->TxBufferIn = PortP->TxBufferOut = 0; } else { - rio_dprint(RIO_DEBUG_INTR, ("T_WFLUSH Command ignored\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command ignored\n"); } /* ** sort out the line discipline @@ -966,16 +966,16 @@ break; case T_RESUME: - rio_dprint(RIO_DEBUG_INTR, ("T_RESUME\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RESUME\n"); /* ** send pre-emptive resume packet */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("RESUME on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "RESUME on deleted RTA\n"); } else { if ( RIOPreemptiveCmd(p, PortP, RESUME ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_RESUME Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RESUME Command failed\n"); } } /* @@ -986,7 +986,7 @@ break; case T_TIME: - rio_dprint(RIO_DEBUG_INTR, ("T_TIME\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_TIME\n"); /* ** T_TIME is called when xDLY is set in oflags and ** the line discipline timeout has expired. It's @@ -1008,16 +1008,16 @@ break; case T_SUSPEND: - rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_SUSPEND\n"); /* ** send a suspend pre-emptive packet. */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("SUSPEND deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "SUSPEND deleted RTA\n"); } else { if ( RIOPreemptiveCmd(p, PortP, SUSPEND ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_SUSPEND Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_SUSPEND Command failed\n"); } } /* @@ -1026,18 +1026,18 @@ break; case T_BLOCK: - rio_dprint(RIO_DEBUG_INTR, ("T_BLOCK\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_BLOCK\n"); break; case T_RFLUSH: - rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RFLUSH\n"); if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("RFLUSH on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "RFLUSH on deleted RTA\n"); PortP->RxDataStart = 0; } else { if ( RIOPreemptiveCmd( p, PortP, RFLUSH ) == RIO_FAIL ) { - rio_dprint(RIO_DEBUG_INTR, ("T_RFLUSH Command failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_RFLUSH Command failed\n"); return 0; } PortP->RxDataStart = 0; @@ -1050,14 +1050,14 @@ /* ** MAGIC! */ - rio_dprint(RIO_DEBUG_INTR, ("Set receive handshake bit\n")); + rio_dprintk (RIO_DEBUG_INTR, "Set receive handshake bit\n"); PortP->PhbP->handshake |= PHB_HANDSHAKE_RESET; } } break; /* FALLTHROUGH */ case T_UNBLOCK: - rio_dprint(RIO_DEBUG_INTR, ("T_UNBLOCK\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_UNBLOCK\n"); /* ** If there is any data to receive set a timeout to service it. */ @@ -1065,7 +1065,7 @@ break; case T_BREAK: - rio_dprint(RIO_DEBUG_INTR, ("T_BREAK\n")); + rio_dprintk (RIO_DEBUG_INTR, "T_BREAK\n"); /* ** Send a break command. For Sys V ** this is a timed break, so we @@ -1075,12 +1075,12 @@ ** Build a BREAK command */ if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_INTR, ("BREAK on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_INTR, "BREAK on deleted RTA\n"); } else { if (RIOShortCommand(PortP,SBREAK,2, p->RIOConf.BreakInterval)==RIO_FAIL) { - rio_dprint(RIO_DEBUG_INTR, ("SBREAK RIOShortCommand failed\n")); + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); } } @@ -1090,18 +1090,18 @@ break; case T_INPUT: - rio_dprint(RIO_DEBUG_INTR, ("Proc T_INPUT called - I don't know what to do!\n")); + rio_dprintk (RIO_DEBUG_INTR, "Proc T_INPUT called - I don't know what to do!\n"); break; case T_PARM: - rio_dprint(RIO_DEBUG_INTR, ("Proc T_PARM called - I don't know what to do!\n")); + rio_dprintk (RIO_DEBUG_INTR, "Proc T_PARM called - I don't know what to do!\n"); break; case T_SWTCH: - rio_dprint(RIO_DEBUG_INTR, ("Proc T_SWTCH called - I don't know what to do!\n")); + rio_dprintk (RIO_DEBUG_INTR, "Proc T_SWTCH called - I don't know what to do!\n"); break; default: - rio_dprint(RIO_DEBUG_INTR, ("Proc UNKNOWN command %d\n",cmd)); + rio_dprintk (RIO_DEBUG_INTR, "Proc UNKNOWN command %d\n",cmd); } /* ** T_OUTPUT returns without passing through this point! diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rioparam.c linux/drivers/char/rio/rioparam.c --- v2.4.0-test6/linux/drivers/char/rio/rioparam.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/rio/rioparam.c Fri Aug 11 14:51:33 2000 @@ -176,13 +176,18 @@ int retries = 0xff; unsigned long flags; + func_enter (); + TtyP = PortP->gs.tty; - rio_dprint(RIO_DEBUG_PARAM, ("RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", - PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP) ); + rio_dprintk (RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", + PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP); if (!TtyP) { - rio_dprint (RIO_DEBUG_PARAM, ("Can't call rioparam with null tty.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Can't call rioparam with null tty.\n"); + + func_exit (); + return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags ); @@ -205,7 +210,7 @@ PortP->FirstOpen = 0; } else if (PortP->Store || PortP->Lock) { - rio_dprint(RIO_DEBUG_PARAM, ("OPEN: Restoring stored/locked params\n")); + rio_dprintk (RIO_DEBUG_PARAM, "OPEN: Restoring stored/locked params\n"); TtyP->tm.c_iflag = PortP->StoredTty.iflag; TtyP->tm.c_oflag = PortP->StoredTty.oflag; TtyP->tm.c_cflag = PortP->StoredTty.cflag; @@ -226,41 +231,49 @@ break; } if ( PortP->InUse != NOT_INUSE ) { - rio_dprint(RIO_DEBUG_PARAM, ("Port IN_USE for pre-emptive command\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Port IN_USE for pre-emptive command\n"); } if ( !res ) { - rio_dprint(RIO_DEBUG_PARAM, ("Port has no space on transmit queue\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Port has no space on transmit queue\n"); } if ( SleepFlag != OK_TO_SLEEP ) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit(); + return RIO_FAIL; } - rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit\n")); + rio_dprintk (RIO_DEBUG_PARAM, "wait for can_add_transmit\n"); rio_spin_unlock_irqrestore( &PortP->portSem, flags); retval = RIODelay(PortP, HUNDRED_MS); rio_spin_lock_irqsave( &PortP->portSem, flags); if (retval == RIO_FAIL) { - rio_dprint(RIO_DEBUG_PARAM, ("wait for can_add_transmit broken by signal\n")); + rio_dprintk (RIO_DEBUG_PARAM, "wait for can_add_transmit broken by signal\n"); rio_spin_unlock_irqrestore( &PortP->portSem, flags); pseterr(EINTR); + func_exit(); + return RIO_FAIL; } if ( PortP->State & RIO_DELETED ) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + return RIO_SUCCESS; } } if (!res) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + return RIO_FAIL; } - rio_dprint(RIO_DEBUG_PARAM, ("can_add_transmit() returns %x\n",res)); - rio_dprint(RIO_DEBUG_PARAM, ("Packet is 0x%x\n",(int) PacketP)); + rio_dprintk (RIO_DEBUG_PARAM, "can_add_transmit() returns %x\n",res); + rio_dprintk (RIO_DEBUG_PARAM, "Packet is 0x%x\n",(int) PacketP); phb_param_ptr = (struct phb_param *)PacketP->data; @@ -270,7 +283,7 @@ ** COR 1 */ if ( TtyP->tm.c_iflag & INPCK ) { - rio_dprint(RIO_DEBUG_PARAM, ("Parity checking on input enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Parity checking on input enabled\n"); Cor1 |= COR1_INPCK; } #endif @@ -278,53 +291,53 @@ switch ( TtyP->termios->c_cflag & CSIZE ) { case CS5: { - rio_dprint(RIO_DEBUG_PARAM, ("5 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "5 bit data\n"); Cor1 |= COR1_5BITS; break; } case CS6: { - rio_dprint(RIO_DEBUG_PARAM, ("6 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "6 bit data\n"); Cor1 |= COR1_6BITS; break; } case CS7: { - rio_dprint(RIO_DEBUG_PARAM, ("7 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "7 bit data\n"); Cor1 |= COR1_7BITS; break; } case CS8: { - rio_dprint(RIO_DEBUG_PARAM, ("8 bit data\n")); + rio_dprintk (RIO_DEBUG_PARAM, "8 bit data\n"); Cor1 |= COR1_8BITS; break; } } if ( TtyP->termios->c_cflag & CSTOPB ) { - rio_dprint(RIO_DEBUG_PARAM, ("2 stop bits\n")); + rio_dprintk (RIO_DEBUG_PARAM, "2 stop bits\n"); Cor1 |= COR1_2STOP; } else { - rio_dprint(RIO_DEBUG_PARAM, ("1 stop bit\n")); + rio_dprintk (RIO_DEBUG_PARAM, "1 stop bit\n"); Cor1 |= COR1_1STOP; } if ( TtyP->termios->c_cflag & PARENB ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable parity\n"); Cor1 |= COR1_NORMAL; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Disable parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Disable parity\n"); Cor1 |= COR1_NOP; } if ( TtyP->termios->c_cflag & PARODD ) { - rio_dprint(RIO_DEBUG_PARAM, ("Odd parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Odd parity\n"); Cor1 |= COR1_ODD; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Even parity\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Even parity\n"); Cor1 |= COR1_EVEN; } @@ -332,89 +345,89 @@ ** COR 2 */ if ( TtyP->termios->c_iflag & IXON ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop output control\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable start/stop output control\n"); Cor2 |= COR2_IXON; } else { if ( PortP->Config & RIO_IXON ) { - rio_dprint(RIO_DEBUG_PARAM, ("Force enable start/stop output control\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Force enable start/stop output control\n"); Cor2 |= COR2_IXON; } else - rio_dprint(RIO_DEBUG_PARAM, ("IXON has been disabled.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "IXON has been disabled.\n"); } if (TtyP->termios->c_iflag & IXANY) { if ( PortP->Config & RIO_IXANY ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable any key to restart output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable any key to restart output\n"); Cor2 |= COR2_IXANY; } else - rio_dprint(RIO_DEBUG_PARAM, ("IXANY has been disabled due to sanity reasons.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n"); } if ( TtyP->termios->c_iflag & IXOFF ) { - rio_dprint(RIO_DEBUG_PARAM, ("Enable start/stop input control 2\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable start/stop input control 2\n"); Cor2 |= COR2_IXOFF; } if ( TtyP->termios->c_cflag & HUPCL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Hangup on last close\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Hangup on last close\n"); Cor2 |= COR2_HUPCL; } if ( C_CRTSCTS (TtyP)) { - rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n"); Cor2 |= COR2_CTSFLOW; Cor2 |= COR2_RTSFLOW; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Rx hardware flow control disabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n"); Cor2 &= ~COR2_CTSFLOW; Cor2 &= ~COR2_RTSFLOW; } if ( TtyP->termios->c_cflag & CLOCAL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Local line\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Local line\n"); } else { - rio_dprint(RIO_DEBUG_PARAM, ("Possible Modem line\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Possible Modem line\n"); } /* ** COR 4 (there is no COR 3) */ if ( TtyP->termios->c_iflag & IGNBRK ) { - rio_dprint(RIO_DEBUG_PARAM, ("Ignore break condition\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Ignore break condition\n"); Cor4 |= COR4_IGNBRK; } if ( !(TtyP->termios->c_iflag & BRKINT) ) { - rio_dprint(RIO_DEBUG_PARAM, ("Break generates NULL condition\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Break generates NULL condition\n"); Cor4 |= COR4_NBRKINT; } else { - rio_dprint(RIO_DEBUG_PARAM, ("Interrupt on break condition\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Interrupt on break condition\n"); } if ( TtyP->termios->c_iflag & INLCR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage return on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map newline to carriage return on input\n"); Cor4 |= COR4_INLCR; } if ( TtyP->termios->c_iflag & IGNCR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Ignore carriage return on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Ignore carriage return on input\n"); Cor4 |= COR4_IGNCR; } if ( TtyP->termios->c_iflag & ICRNL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map carriage return to newline on input\n"); Cor4 |= COR4_ICRNL; } if ( TtyP->termios->c_iflag & IGNPAR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Ignore characters with parity errors\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Ignore characters with parity errors\n"); Cor4 |= COR4_IGNPAR; } if ( TtyP->termios->c_iflag & PARMRK ) { - rio_dprint(RIO_DEBUG_PARAM, ("Mark parity errors\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Mark parity errors\n"); Cor4 |= COR4_PARMRK; } @@ -444,24 +457,24 @@ ** Could set LNE here if you wanted LNext processing. SVR4 will use it. */ if ( TtyP->termios->c_iflag & ISTRIP ) { - rio_dprint(RIO_DEBUG_PARAM, ("Strip input characters\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Strip input characters\n"); if (! (PortP->State & RIO_TRIAD_MODE)) { Cor5 |= COR5_ISTRIP; } } if ( TtyP->termios->c_oflag & ONLCR ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map newline to carriage-return, newline on output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n"); if ( PortP->CookMode == COOK_MEDIUM ) Cor5 |= COR5_ONLCR; } if ( TtyP->termios->c_oflag & OCRNL ) { - rio_dprint(RIO_DEBUG_PARAM, ("Map carriage return to newline on output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map carriage return to newline on output\n"); if ( PortP->CookMode == COOK_MEDIUM ) Cor5 |= COR5_OCRNL; } if ( ( TtyP->termios->c_oflag & TABDLY) == TAB3 ) { - rio_dprint(RIO_DEBUG_PARAM, ("Tab delay 3 set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Tab delay 3 set\n"); if ( PortP->CookMode == COOK_MEDIUM ) Cor5 |= COR5_TAB3; } @@ -481,8 +494,8 @@ /* ** Baud rate bytes */ - rio_dprint(RIO_DEBUG_PARAM, ("Mapping of rx/tx baud %x (%x)\n", - TtyP->termios->c_cflag, CBAUD)); + rio_dprintk (RIO_DEBUG_PARAM, "Mapping of rx/tx baud %x (%x)\n", + TtyP->termios->c_cflag, CBAUD); switch (TtyP->termios->c_cflag & CBAUD) { #define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break @@ -494,77 +507,77 @@ /* XXX MIssing conversion table. XXX */ /* (TtyP->termios->c_cflag & V_CBAUD); */ - rio_dprint(RIO_DEBUG_PARAM, ("tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud)); + rio_dprintk (RIO_DEBUG_PARAM, "tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud); /* ** Leftovers */ if ( TtyP->termios->c_cflag & CREAD ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable receiver\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable receiver\n"); #ifdef RCV1EN if ( TtyP->termios->c_cflag & RCV1EN ) - rio_dprint(RIO_DEBUG_PARAM, ("RCV1EN (?)\n")); + rio_dprintk (RIO_DEBUG_PARAM, "RCV1EN (?)\n"); #endif #ifdef XMT1EN if ( TtyP->termios->c_cflag & XMT1EN ) - rio_dprint(RIO_DEBUG_PARAM, ("XMT1EN (?)\n")); + rio_dprintk (RIO_DEBUG_PARAM, "XMT1EN (?)\n"); #endif #if 0 if ( TtyP->termios->c_cflag & LOBLK ) - rio_dprint(RIO_DEBUG_PARAM, ("LOBLK - JCL output blocks when not current\n")); + rio_dprintk (RIO_DEBUG_PARAM, "LOBLK - JCL output blocks when not current\n"); #endif if ( TtyP->termios->c_lflag & ISIG ) - rio_dprint(RIO_DEBUG_PARAM, ("Input character signal generating enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Input character signal generating enabled\n"); if ( TtyP->termios->c_lflag & ICANON ) - rio_dprint(RIO_DEBUG_PARAM, ("Canonical input: erase and kill enabled\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Canonical input: erase and kill enabled\n"); if ( TtyP->termios->c_lflag & XCASE ) - rio_dprint(RIO_DEBUG_PARAM, ("Canonical upper/lower presentation\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Canonical upper/lower presentation\n"); if ( TtyP->termios->c_lflag & ECHO ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable input echo\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable input echo\n"); if ( TtyP->termios->c_lflag & ECHOE ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable echo erase\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable echo erase\n"); if ( TtyP->termios->c_lflag & ECHOK ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable echo kill\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable echo kill\n"); if ( TtyP->termios->c_lflag & ECHONL ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable echo newline\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable echo newline\n"); if ( TtyP->termios->c_lflag & NOFLSH ) - rio_dprint(RIO_DEBUG_PARAM, ("Disable flush after interrupt or quit\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Disable flush after interrupt or quit\n"); #ifdef TOSTOP if ( TtyP->termios->c_lflag & TOSTOP ) - rio_dprint(RIO_DEBUG_PARAM, ("Send SIGTTOU for background output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Send SIGTTOU for background output\n"); #endif #ifdef XCLUDE if ( TtyP->termios->c_lflag & XCLUDE ) - rio_dprint(RIO_DEBUG_PARAM, ("Exclusive use of this line\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Exclusive use of this line\n"); #endif if ( TtyP->termios->c_iflag & IUCLC ) - rio_dprint(RIO_DEBUG_PARAM, ("Map uppercase to lowercase on input\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map uppercase to lowercase on input\n"); if ( TtyP->termios->c_oflag & OPOST ) - rio_dprint(RIO_DEBUG_PARAM, ("Enable output post-processing\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Enable output post-processing\n"); if ( TtyP->termios->c_oflag & OLCUC ) - rio_dprint(RIO_DEBUG_PARAM, ("Map lowercase to uppercase on output\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Map lowercase to uppercase on output\n"); if ( TtyP->termios->c_oflag & ONOCR ) - rio_dprint(RIO_DEBUG_PARAM, ("No carriage return output at column 0\n")); + rio_dprintk (RIO_DEBUG_PARAM, "No carriage return output at column 0\n"); if ( TtyP->termios->c_oflag & ONLRET ) - rio_dprint(RIO_DEBUG_PARAM, ("Newline performs carriage return function\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Newline performs carriage return function\n"); if ( TtyP->termios->c_oflag & OFILL ) - rio_dprint(RIO_DEBUG_PARAM, ("Use fill characters for delay\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Use fill characters for delay\n"); if ( TtyP->termios->c_oflag & OFDEL ) - rio_dprint(RIO_DEBUG_PARAM, ("Fill character is DEL\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Fill character is DEL\n"); if ( TtyP->termios->c_oflag & NLDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Newline delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Newline delay set\n"); if ( TtyP->termios->c_oflag & CRDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Carriage return delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Carriage return delay set\n"); if ( TtyP->termios->c_oflag & TABDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Tab delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Tab delay set\n"); #if 0 if ( TtyP->termios->c_oflag & BSDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Back-space delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Back-space delay set\n"); if ( TtyP->termios->c_oflag & VTDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Vertical tab delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Vertical tab delay set\n"); if ( TtyP->termios->c_oflag & FFDLY ) - rio_dprint(RIO_DEBUG_PARAM, ("Form-feed delay set\n")); + rio_dprintk (RIO_DEBUG_PARAM, "Form-feed delay set\n"); #endif /* ** These things are kind of useful in a later life! @@ -573,6 +586,8 @@ if ( PortP->State & RIO_DELETED ) { rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + return RIO_FAIL; } @@ -610,10 +625,12 @@ rio_spin_unlock_irqrestore( &PortP->portSem, flags); - rio_dprint(RIO_DEBUG_PARAM, ("add_transmit returned.\n")); + rio_dprintk (RIO_DEBUG_PARAM, "add_transmit returned.\n"); /* ** job done. */ + func_exit (); + return RIO_SUCCESS; } @@ -644,7 +661,7 @@ struct Port *PortP; { if (RWORD(*PortP->TxAdd) & PKT_IN_USE) { - rio_dprint (RIO_DEBUG_PARAM, ("add_transmit: Packet has been stolen!")); + rio_dprintk (RIO_DEBUG_PARAM, "add_transmit: Packet has been stolen!"); } WWORD( *(ushort *)PortP->TxAdd, RWORD(*PortP->TxAdd) | PKT_IN_USE); PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : @@ -672,7 +689,7 @@ * ************************************************/ - rio_dprint(RIO_DEBUG_PFE, ("put_free_end(PktP=%x)\n",(int)PktP)); + rio_dprintk (RIO_DEBUG_PFE, "put_free_end(PktP=%x)\n",(int)PktP); if ((old_end=RWORD(HostP->ParmMapP->free_list_end)) != TPNULL) { new_end = RIO_OFF(HostP->Caddr,PktP); @@ -683,12 +700,13 @@ WWORD(HostP->ParmMapP->free_list_end, new_end); } else { /* First packet on the free list this should never happen! */ - rio_dprint(RIO_DEBUG_PFE, ("put_free_end(): This should never happen\n")); + rio_dprintk (RIO_DEBUG_PFE, "put_free_end(): This should never happen\n"); WWORD(HostP->ParmMapP->free_list_end , RIO_OFF(HostP->Caddr,PktP)); tmp_pointer = (FREE_LIST *)PktP; WWORD(tmp_pointer->prev , TPNULL); WWORD(tmp_pointer->next , TPNULL); } + rio_dprintk (RIO_DEBUG_CMD, "Before unlock: %p\n", &HostP->HostLock); rio_spin_unlock_irqrestore(&HostP->HostLock, flags); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/rioroute.c linux/drivers/char/rio/rioroute.c --- v2.4.0-test6/linux/drivers/char/rio/rioroute.c Thu May 11 15:30:06 2000 +++ linux/drivers/char/rio/rioroute.c Fri Aug 11 14:51:33 2000 @@ -178,8 +178,8 @@ if ( Lies ) { - rio_dprint(RIO_DEBUG_ROUTE, ("LIES! DAMN LIES! %d LIES!\n",Lies)); - rio_dprint(RIO_DEBUG_ROUTE, ("%d:%c %d:%c %d:%c %d:%c\n", + rio_dprintk (RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n",Lies); + rio_dprintk (RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n", RBYTE(PktCmdP->RouteTopology[0].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[0].Link), RBYTE(PktCmdP->RouteTopology[1].Unit), @@ -187,7 +187,7 @@ RBYTE(PktCmdP->RouteTopology[2].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[2].Link), RBYTE(PktCmdP->RouteTopology[3].Unit), - 'A'+RBYTE(PktCmdP->RouteTopology[3].Link))); + 'A'+RBYTE(PktCmdP->RouteTopology[3].Link)); return TRUE; } @@ -219,11 +219,11 @@ NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT ) { - rio_dprint(RIO_DEBUG_ROUTE, ("I have a link from %s %s to unit %d:%d - I don't like it.\n", + rio_dprintk (RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, - NewLink)); + NewLink); } else { @@ -248,8 +248,8 @@ RIOConCon(p,HostP,ThisUnit,ThisLink,NewUnit,NewLink,CONNECT); if ( NewUnit == ROUTE_NO_ID ) - rio_dprint(RIO_DEBUG_ROUTE, ("%s %s (%c) is connected to an unconfigured unit.\n", - MyType,MyName,'A'+ThisLink)); + rio_dprintk (RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", + MyType,MyName,'A'+ThisLink); if ( NewUnit == ROUTE_INTERCONNECT ) { @@ -267,14 +267,14 @@ if ( HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink ) { - rio_dprint(RIO_DEBUG_ROUTE, ("SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A'); HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT; HostP->Topology[OldLink].Link = NO_LINK; } else { - rio_dprint(RIO_DEBUG_ROUTE, ("HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", - OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", + OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } else if ( OldUnit <= MAX_RUP ) @@ -282,29 +282,29 @@ if ( HostP->Mapping[OldUnit-1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit-1].Topology[OldLink].Link == ThisLink ) { - rio_dprint(RIO_DEBUG_ROUTE, ("SETTING RTA %s (%c) TO DISCONNECTED!\n", - HostP->Mapping[OldUnit-1].Name,OldLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", + HostP->Mapping[OldUnit-1].Name,OldLink+'A'); HostP->Mapping[OldUnit-1].Topology[OldLink].Unit=ROUTE_DISCONNECT; HostP->Mapping[OldUnit-1].Topology[OldLink].Link=NO_LINK; } else { - rio_dprint(RIO_DEBUG_ROUTE, ("RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", + rio_dprintk (RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit-1].Name,OldLink+'A', - HostP->Mapping[ThisUnit-1].Name,ThisLink+'A')); + HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } if ( NewUnit == HOST_ID ) { - rio_dprint(RIO_DEBUG_ROUTE, ("MARKING HOST (%c) CONNECTED TO %s (%c)\n", - NewLink+'A',MyName,ThisLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", + NewLink+'A',MyName,ThisLink+'A'); HostP->Topology[NewLink].Unit = ThisUnit; HostP->Topology[NewLink].Link = ThisLink; } else if ( NewUnit <= MAX_RUP ) { - rio_dprint(RIO_DEBUG_ROUTE, ("MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", - HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A')); + rio_dprintk (RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", + HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A'); HostP->Mapping[NewUnit-1].Topology[NewLink].Unit=ThisUnit; HostP->Mapping[NewUnit-1].Topology[NewLink].Link=ThisLink; } @@ -321,8 +321,8 @@ */ if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Unknown command %d received on rup %d host %d ROUTE_RUP\n", - RBYTE(PktCmdP->Command),Rup,(int)HostP)); + rio_dprintk (RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %d ROUTE_RUP\n", + RBYTE(PktCmdP->Command),Rup,(int)HostP); return TRUE; } @@ -336,7 +336,7 @@ */ RtaType = GetUnitType(RtaUniq); - rio_dprint(RIO_DEBUG_ROUTE, ("Received a request for an ID for serial number %x\n", RtaUniq)); + rio_dprintk (RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq); Mod = RBYTE(PktCmdP->ModuleTypes); Mod1 = LONYBLE(Mod); @@ -347,14 +347,14 @@ ** with 8 port, set 2nd ident in Mod2 to the same as Mod1. */ Mod2 = Mod1; - rio_dprint(RIO_DEBUG_ROUTE, ("Backplane type is %s (all ports)\n", - p->RIOModuleTypes[Mod1].Name )); + rio_dprintk (RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", + p->RIOModuleTypes[Mod1].Name); } else { Mod2 = HINYBLE(Mod); - rio_dprint(RIO_DEBUG_ROUTE, ("Module types are %s (ports 0-3) and %s (ports 4-7)\n", - p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name )); + rio_dprintk (RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", + p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name); } if ( RtaUniq == 0xffffffff ) @@ -367,7 +367,7 @@ */ if ( !(CmdBlkP = RIOGetCmdBlk()) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("No command blocks to route RTA! come back later.\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n"); return 0; } @@ -384,8 +384,8 @@ if (! RIOBootOk(p, HostP, RtaUniq)) { - rio_dprint(RIO_DEBUG_ROUTE, ("RTA %x tried to get an ID, but does not belong - FOAD it!\n", - RtaUniq)); + rio_dprintk (RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", + RtaUniq); PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); @@ -397,13 +397,13 @@ */ for ( ThisUnit=0; ThisUnitMapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use":"Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative":"Not Tentative", - HostP->Mapping[ThisUnit].RtaUniqueNum )); + HostP->Mapping[ThisUnit].RtaUniqueNum); /* ** We have an entry for it. @@ -414,12 +414,12 @@ if (RtaType == TYPE_RTA16) { ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1; - rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slots %d+%d\n", - RtaUniq,ThisUnit,ThisUnit2)); + rio_dprintk (RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", + RtaUniq,ThisUnit,ThisUnit2); } else - rio_dprint(RIO_DEBUG_ROUTE, ("Found unit 0x%x at slot %d\n", - RtaUniq,ThisUnit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", + RtaUniq,ThisUnit); /* ** If we have no knowledge of booting it, then the host has ** been re-booted, and so we must kill the RTA, so that it @@ -458,14 +458,14 @@ */ RIOFixPhbs(p, HostP, ThisUnit2); PktReplyP->IDNum2 = ThisUnit2+1; - rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated IDs %d+%d\n", - HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2)); + rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", + HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2); } else { PktReplyP->IDNum2 = ROUTE_NO_ID; - rio_dprint(RIO_DEBUG_ROUTE, ("RTA '%s' has been allocated ID %d\n", - HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum)); + rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", + HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum); } HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,10); @@ -489,7 +489,7 @@ PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -502,7 +502,7 @@ PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Re-opened this port\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -628,7 +628,7 @@ unsigned long flags; int PortN = HostP->Mapping[unit].SysPort; - rio_dprint(RIO_DEBUG_ROUTE, ("RIOFixPhbs unit %d sysport %d\n", unit, PortN)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN); if (PortN != -1) { ushort dest_unit = HostP->Mapping[unit].ID2; @@ -656,7 +656,7 @@ ** unset, so go no further. */ if (PortP->TxStart == 0) { - rio_dprint(RIO_DEBUG_ROUTE, ("Tx pkts not set up yet\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n"); break; } @@ -691,10 +691,10 @@ WBYTE(Pkt->dest_unit, dest_unit); WBYTE(Pkt->dest_port, dest_port); } - rio_dprint(RIO_DEBUG_ROUTE, ("phb dest: Old %x:%x New %x:%x\n", + rio_dprintk (RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", RWORD(PortP->PhbP->destination) & 0xff, (RWORD(PortP->PhbP->destination) >> 8) & 0xff, - dest_unit, dest_port)); + dest_unit, dest_port); WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8)); WWORD(PortP->PhbP->link, link); @@ -706,7 +706,7 @@ */ if (link > 3) return; if (((unit * 8) + 7) > RWORD(HostP->LinkStrP[link].last_port)) { - rio_dprint(RIO_DEBUG_ROUTE, ("last port on host link %d: %d\n", link, (unit * 8) + 7)); + rio_dprintk (RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7); WWORD(HostP->LinkStrP[link].last_port, (unit * 8) + 7); } } @@ -732,7 +732,7 @@ CheckUnitId( UnitId ); #endif if ( RIOCheck( HostP, UnitId ) ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated\n",UnitId)); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit %d is NOT isolated\n", UnitId); rio_spin_unlock_irqrestore(&HostP->HostLock, flags); return(0); } @@ -771,7 +771,7 @@ HostP->Mapping[UnitId].Flags |= BEEN_HERE; if ( p->RIOPrintDisabled == DO_PRINT ) - rio_dprint(RIO_DEBUG_ROUTE, ("RIOMesgIsolated %s",HostP->Mapping[UnitId].Name)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOMesgIsolated %s", HostP->Mapping[UnitId].Name); for ( link=0; linkMapping[UnitId].Topology[link].Unit; @@ -795,7 +795,7 @@ CheckUnitId( UnitId ); #endif /* rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */ - rio_dprint(RIO_DEBUG_ROUTE, ("RIOCheck : UnitID = %d\n",UnitId)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOCheck : UnitID = %d\n", UnitId); if ( UnitId == HOST_ID ) { /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */ @@ -854,16 +854,16 @@ case RIO_MCA: case RIO_EISA: case RIO_PCI: - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Host\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: Host\n"); return(TYPE_HOST); case RIO_RTA_16: - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 16 port RTA\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: 16 port RTA\n"); return(TYPE_RTA16); case RIO_RTA: - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: 8 port RTA\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: 8 port RTA\n"); return(TYPE_RTA8); default : - rio_dprint(RIO_DEBUG_ROUTE, ("Unit type: Unrecognised\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Unit type: Unrecognised\n"); return(99); } } @@ -876,7 +876,7 @@ return(0); p->RIOQuickCheck = CHANGED; if ( p->RIOSignalProcess ) { - rio_dprint(RIO_DEBUG_ROUTE, ("Send SIG-HUP")); + rio_dprintk (RIO_DEBUG_ROUTE, "Send SIG-HUP"); /* psignal( RIOSignalProcess, SIGHUP ); */ @@ -951,10 +951,10 @@ ToName = ToId ? HostP->Mapping[ToId-1].Name : HostP->Name; ToType = ToId ? "RTA" : "HOST"; - rio_dprint(RIO_DEBUG_ROUTE, ("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", + rio_dprintk (RIO_DEBUG_ROUTE, "Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A'+FromLink, ToType, ToName, 'A'+ToLink, - (Change==CONNECT) ? "established" : "disconnected")); + (Change==CONNECT) ? "established" : "disconnected"); cprintf("Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A'+FromLink, ToType, ToName, 'A'+ToLink, @@ -1000,7 +1000,7 @@ int link; - rio_dprint(RIO_DEBUG_ROUTE, ("RIOFreeDisconnect unit %d\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "RIOFreeDisconnect unit %d\n", unit); /* ** If the slot is tentative and does not belong to the ** second half of a 16 port RTA then scan to see if @@ -1023,17 +1023,17 @@ ** made this slot tentative and not yet received a topology update. ** Lets check how long ago we made it tentative. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Just about to check LBOLT on entry %d\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Just about to check LBOLT on entry %d\n", unit); if (drv_getparm(LBOLT, (ulong_t *) ¤t_time)) - rio_dprint(RIO_DEBUG_ROUTE, ("drv_getparm(LBOLT,....) Failed.\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "drv_getparm(LBOLT,....) Failed.\n"); elapse_time = current_time - TentTime[unit]; - rio_dprint(RIO_DEBUG_ROUTE, ("elapse %d = current %d - tent %d (%d usec)\n", - elapse_time, current_time, TentTime[unit],drv_hztousec(elapse_time))); + rio_dprintk (RIO_DEBUG_ROUTE, "elapse %d = current %d - tent %d (%d usec)\n", + elapse_time, current_time, TentTime[unit], drv_hztousec(elapse_time)); if (drv_hztousec(elapse_time) < WAIT_TO_FINISH) { - rio_dprint(RIO_DEBUG_ROUTE, ("Skipping slot %d, not timed out yet %d\n" - ,unit,drv_hztousec(elapse_time))); + rio_dprintk (RIO_DEBUG_ROUTE, "Skipping slot %d, not timed out yet %d\n", + unit, drv_hztousec(elapse_time)); return 1; } #endif @@ -1046,7 +1046,7 @@ { int nOther = (HostP->Mapping[unit].ID2) -1; - rio_dprint(RIO_DEBUG_ROUTE, ("RioFreedis second slot %d.\n",nOther)); + rio_dprintk (RIO_DEBUG_ROUTE, "RioFreedis second slot %d.\n", nOther); bzero((caddr_t)&HostP->Mapping[nOther], sizeof(struct Map)); } RIORemoveFromSavedTable(p, &HostP->Mapping[unit]); @@ -1082,19 +1082,19 @@ */ for (unit = 0; unit < MAX_RUP; unit++) { - rio_dprint(RIO_DEBUG_ROUTE, ("Scanning unit %d\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Scanning unit %d\n",unit); /* ** If the flags are zero then the slot is empty. */ if (HostP->Mapping[unit].Flags == 0) { - rio_dprint(RIO_DEBUG_ROUTE, (" This slot is empty.\n")); + rio_dprintk (RIO_DEBUG_ROUTE, " This slot is empty.\n"); /* ** If we haven't allocated the first ID then do it now. */ if (*pID1 == MAX_RUP) { - rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for first unit %d\n", unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Make tentative entry for first unit %d\n", unit); *pID1 = unit; /* @@ -1109,7 +1109,7 @@ /* ** Allocate the second slot and return. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Make tentative entry for second unit %d\n", unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Make tentative entry for second unit %d\n", unit); *pID2 = unit; return 0; } @@ -1121,18 +1121,18 @@ ** need to start all over again looking for tentative slots ** that we can re-use. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Starting to scan for tentative slots\n")); + rio_dprintk (RIO_DEBUG_ROUTE, "Starting to scan for tentative slots\n"); for (unit = 0; unit < MAX_RUP; unit++) { if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) || (HostP->Mapping[unit].Flags == 0)) && ! (HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT )) { - rio_dprint(RIO_DEBUG_ROUTE, (" Slot %d looks promising.\n",unit)); + rio_dprintk (RIO_DEBUG_ROUTE, " Slot %d looks promising.\n",unit); if(unit == *pID1) { - rio_dprint(RIO_DEBUG_ROUTE, (" No it isn't, its the 1st half\n")); + rio_dprintk (RIO_DEBUG_ROUTE, " No it isn't, its the 1st half\n"); continue; } @@ -1152,7 +1152,7 @@ */ if (*pID1 == MAX_RUP) { - rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative entry for first unit %d\n", unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Grab tentative entry for first unit %d\n", unit); *pID1 = unit; /* @@ -1172,8 +1172,8 @@ /* ** Allocate the second slot and return. */ - rio_dprint(RIO_DEBUG_ROUTE, ("Grab tentative/empty entry for second unit %d\n", - unit)); + rio_dprintk (RIO_DEBUG_ROUTE, "Grab tentative/empty entry for second unit %d\n", + unit); *pID2 = unit; /* @@ -1190,7 +1190,7 @@ if (*pID1 > *pID2) { - rio_dprint(RIO_DEBUG_ROUTE, ("Swapping IDS %d %d\n",*pID1,*pID2)); + rio_dprintk (RIO_DEBUG_ROUTE, "Swapping IDS %d %d\n", *pID1, *pID2); tempID = *pID1; *pID1 = *pID2; *pID2 = tempID; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c --- v2.4.0-test6/linux/drivers/char/rio/riotable.c Thu May 11 15:30:07 2000 +++ linux/drivers/char/rio/riotable.c Fri Aug 11 14:51:33 2000 @@ -120,7 +120,7 @@ ** (9) That names aren't duplicated ** xx (10) That hosts that actually exist are mentioned in the table. xx */ - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(1)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(1)\n"); if ( p->RIOSystemUp ) { /* (1) */ p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED; return EBUSY; @@ -133,7 +133,7 @@ for ( Entry=0; EntryRIOConnectTable[Entry]; if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) { - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(2)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(2)\n"); cptr = MapP->Name; /* (2) */ cptr[MAX_NAME_LEN-1]='\0'; if ( cptr[0]=='\0' ) { @@ -161,19 +161,19 @@ continue; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(3)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(3)\n"); if ( !MapP->RtaUniqueNum && !MapP->HostUniqueNum ) { /* (3) */ if ( MapP->ID || MapP->SysPort || MapP->Flags ) { - rio_dprint(RIO_DEBUG_TABLE, ("%s pretending to be empty but isn't\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "%s pretending to be empty but isn't\n",MapP->Name); p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL; p->RIOError.Entry = Entry; return ENXIO; } - rio_dprint(RIO_DEBUG_TABLE, ("!RIO: Daemon: test (3) passes\n")); + rio_dprintk (RIO_DEBUG_TABLE, "!RIO: Daemon: test (3) passes\n"); continue; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(4)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(4)\n"); for ( Host=0; HostRIONumHosts; Host++ ) { /* (4) */ if ( p->RIOHosts[Host].UniqueNum==MapP->HostUniqueNum ) { HostP = &p->RIOHosts[Host]; @@ -187,8 +187,8 @@ } if ( Host >= p->RIONumHosts ) { - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has unknown host unique number 0x%x\n", - MapP->Name,MapP->HostUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s has unknown host unique number 0x%x\n", + MapP->Name, MapP->HostUniqueNum); MapP->HostUniqueNum = 0; /* MapP->RtaUniqueNum = 0; */ /* MapP->ID = 0; */ @@ -198,18 +198,18 @@ continue; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(5)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(5)\n"); if ( MapP->RtaUniqueNum ) { /* (5) */ if ( !MapP->ID ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an ID of zero!\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an ID of zero!\n", + MapP->Name); p->RIOError.Error = ZERO_RTA_ID; p->RIOError.Entry = Entry; return ENXIO; } if ( MapP->ID > MAX_RUP ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an illegal ID %d\n", - MapP->Name, MapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an illegal ID %d\n", + MapP->Name, MapP->ID); p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; p->RIOError.Entry = Entry; return ENXIO; @@ -218,8 +218,8 @@ if ( MapP->HostUniqueNum == p->RIOConnectTable[SubEnt].HostUniqueNum && MapP->ID == p->RIOConnectTable[SubEnt].ID ) { - rio_dprint(RIO_DEBUG_TABLE, ("Dupl. ID number allocated to RTA %s and RTA %s\n", - MapP->Name,p->RIOConnectTable[SubEnt].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Dupl. ID number allocated to RTA %s and RTA %s\n", + MapP->Name, p->RIOConnectTable[SubEnt].Name); p->RIOError.Error = DUPLICATED_RTA_ID; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; @@ -232,29 +232,29 @@ if ((MapP->RtaUniqueNum == p->RIOConnectTable[SubEnt].RtaUniqueNum) && (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) { - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",MapP->Name)); - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n", - p->RIOConnectTable[SubEnt].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n",MapP->Name); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n", + p->RIOConnectTable[SubEnt].Name); p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; return ENXIO; } } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7a)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(7a)\n"); /* (7a) */ if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort % PORTS_PER_RTA)) { - rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d-RTA %s is not a multiple of %d!\n", - (int)MapP->SysPort,MapP->Name,PORTS_PER_RTA)); + rio_dprintk (RIO_DEBUG_TABLE, "TTY Port number %d-RTA %s is not a multiple of %d!\n", + (int)MapP->SysPort,MapP->Name, PORTS_PER_RTA); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; p->RIOError.Entry = Entry; return ENXIO; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7b)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(7b)\n"); /* (7b) */ if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort >= RIO_PORTS)) { - rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d for RTA %s is too big\n", - (int)MapP->SysPort,MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "TTY Port number %d for RTA %s is too big\n", + (int)MapP->SysPort, MapP->Name); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; p->RIOError.Entry = Entry; return ENXIO; @@ -263,22 +263,22 @@ if ( p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT ) continue; if ( p->RIOConnectTable[SubEnt].RtaUniqueNum ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(8)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(8)\n"); /* (8) */ if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort == p->RIOConnectTable[SubEnt].SysPort) ) { - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s:same TTY port # as RTA %s (%d)\n", + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s:same TTY port # as RTA %s (%d)\n", MapP->Name, p->RIOConnectTable[SubEnt].Name, - (int)MapP->SysPort)); + (int)MapP->SysPort); p->RIOError.Error = TTY_NUMBER_IN_USE; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; return ENXIO; } - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(9)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(9)\n"); if (RIOStrCmp(MapP->Name, p->RIOConnectTable[SubEnt].Name)==0 && !(MapP->Flags & RTA16_SECOND_SLOT)) { /* (9) */ - rio_dprint(RIO_DEBUG_TABLE, ("RTA name %s used twice\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA name %s used twice\n", MapP->Name); p->RIOError.Error = NAME_USED_TWICE; p->RIOError.Entry = Entry; p->RIOError.Other = SubEnt; @@ -288,17 +288,17 @@ } } else { /* (6) */ - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(6)\n")); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: entering(6)\n"); if ( MapP->ID ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO:HOST %s has been allocated ID that isn't zero!\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO:HOST %s has been allocated ID that isn't zero!\n", + MapP->Name); p->RIOError.Error = HOST_ID_NOT_ZERO; p->RIOError.Entry = Entry; return ENXIO; } if ( MapP->SysPort != NO_PORT ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIO: HOST %s has been allocated port numbers!\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RIO: HOST %s has been allocated port numbers!\n", + MapP->Name); p->RIOError.Error = HOST_SYSPORT_BAD; p->RIOError.Entry = Entry; return ENXIO; @@ -326,7 +326,7 @@ ** Copy in the new table entries */ for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) { - rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: Copy table for Host entry %d\n", Entry)); + rio_dprintk (RIO_DEBUG_TABLE, "RIONewTable: Copy table for Host entry %d\n", Entry); MapP = &p->RIOConnectTable[Entry]; /* @@ -344,7 +344,7 @@ ** If it is a host, then we only need to fill in the name field. */ if ( MapP->ID==0 ) { - rio_dprint(RIO_DEBUG_TABLE, ("Host entry found. Name %s\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Host entry found. Name %s\n", MapP->Name); bcopy(MapP->Name,HostP->Name,MAX_NAME_LEN); continue; } @@ -357,7 +357,7 @@ HostMapP = &HostP->Mapping[MapP->ID-1]; if (MapP->Flags & SLOT_IN_USE) { - rio_dprint(RIO_DEBUG_TABLE, ("Rta entry found. Name %s\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Rta entry found. Name %s\n", MapP->Name); /* ** structure assign, then sort out the bits we shouldn't have done */ @@ -370,7 +370,7 @@ RIOReMapPorts(p, HostP, HostMapP ); } else { - rio_dprint(RIO_DEBUG_TABLE, ("TENTATIVE Rta entry found. Name %s\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "TENTATIVE Rta entry found. Name %s\n", MapP->Name); } } @@ -420,11 +420,11 @@ */ if (Host1 != Host) { - rio_dprint(RIO_DEBUG_TABLE, ("Default name %s already used\n", p->RIOHosts[Host].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Default name %s already used\n", p->RIOHosts[Host].Name); bcopy("HOST 1",p->RIOHosts[Host].Name,7); p->RIOHosts[Host].Name[5] += Host1; } - rio_dprint(RIO_DEBUG_TABLE, ("Assigning default name %s\n", p->RIOHosts[Host].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Assigning default name %s\n", p->RIOHosts[Host].Name); } return 0; } @@ -447,13 +447,13 @@ disable(oldspl); /* strange but true! */ - rio_dprint(RIO_DEBUG_TABLE, ("Generating a table to return to config.rio\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Generating a table to return to config.rio\n"); bzero((caddr_t)&p->RIOConnectTable[0], sizeof(struct Map) * TOTAL_MAP_ENTRIES ); for ( Host=0; HostRIOHosts[Host]; MapP = &p->RIOConnectTable[Next++]; MapP->HostUniqueNum = HostP->UniqueNum; @@ -501,8 +501,8 @@ int work_done = 0; unsigned long flags; - rio_dprint(RIO_DEBUG_TABLE, ("Delete entry on host %x, rta %x\n", - MapP->HostUniqueNum,MapP->RtaUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n", + MapP->HostUniqueNum, MapP->RtaUniqueNum); for ( host=0; host < p->RIONumHosts; host++ ) { HostP = &p->RIOHosts[host]; @@ -517,15 +517,15 @@ for ( entry=0; entryRtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum ) { HostMapP = &HostP->Mapping[entry]; - rio_dprint(RIO_DEBUG_TABLE, ("Found entry offset %d on host %s\n", - entry,HostP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Found entry offset %d on host %s\n", + entry, HostP->Name); /* ** Check all four links of the unit are disconnected */ for ( link=0; link< LINKS_PER_UNIT; link++ ) { if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) { - rio_dprint(RIO_DEBUG_TABLE, ("Entry is in use and cannot be deleted!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n"); p->RIOError.Error = UNIT_IS_IN_USE; rio_spin_unlock_irqrestore( &HostP->HostLock, flags); return EBUSY; @@ -540,7 +540,7 @@ if ( SysPort != NO_PORT ) { for (port=SysPort; port < SysPort+PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port]; - rio_dprint(RIO_DEBUG_TABLE, ("Unmap port\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Unmap port\n"); rio_spin_lock_irqsave( &PortP->portSem, flags ); @@ -548,7 +548,7 @@ if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { - rio_dprint(RIO_DEBUG_TABLE, ("Gob on port\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Gob on port\n"); PortP->TxBufferIn = PortP->TxBufferOut = 0; /* What should I do wakeup( &PortP->TxBufferIn ); @@ -585,25 +585,25 @@ */ Pkt = (PKT *) RIO_PTR(HostP->Caddr, RWORD(*TxPktP)); - rio_dprint(RIO_DEBUG_TABLE, ( + rio_dprintk (RIO_DEBUG_TABLE, "Tx packet (%x) destination: Old %x:%x New %x:%x\n", *TxPktP, Pkt->dest_unit, - Pkt->dest_port, dest_unit, dest_port)); + Pkt->dest_port, dest_unit, dest_port); WWORD(Pkt->dest_unit, dest_unit); WWORD(Pkt->dest_port, dest_port); } - rio_dprint(RIO_DEBUG_TABLE, ( + rio_dprintk (RIO_DEBUG_TABLE, "Port %d phb destination: Old %x:%x New %x:%x\n", port, PortP->PhbP->destination & 0xff, (PortP->PhbP->destination >> 8) & 0xff, - dest_unit, dest_port)); + dest_unit, dest_port); WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8)); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } - rio_dprint(RIO_DEBUG_TABLE, ("Entry nulled.\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Entry nulled.\n"); bzero((char *)HostMapP,sizeof(struct Map)); work_done++; } @@ -625,7 +625,7 @@ if ( work_done ) return 0; - rio_dprint(RIO_DEBUG_TABLE, ("Couldn't find entry to be deleted\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Couldn't find entry to be deleted\n"); p->RIOError.Error = COULDNT_FIND_ENTRY; return ENXIO; } @@ -638,32 +638,32 @@ int link; - rio_dprint(RIO_DEBUG_TABLE, ("Assign entry on host %x, rta %x, ID %d, Sysport %d\n", + rio_dprintk (RIO_DEBUG_TABLE, "Assign entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum,MapP->RtaUniqueNum, - MapP->ID, (int)MapP->SysPort )); + MapP->ID, (int)MapP->SysPort); if ((MapP->ID != (ushort)-1) && ((int)MapP->ID < (int)1 || (int)MapP->ID > MAX_RUP )) { - rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Bad ID in map entry!\n"); p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; return EINVAL; } if (MapP->RtaUniqueNum == 0) { - rio_dprint(RIO_DEBUG_TABLE, ("Rta Unique number zero!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Rta Unique number zero!\n"); p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO; return EINVAL; } if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA) ) { - rio_dprint(RIO_DEBUG_TABLE, ("Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA)); + rio_dprintk (RIO_DEBUG_TABLE, "Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; return EINVAL; } if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS) ) { - rio_dprint(RIO_DEBUG_TABLE, ("Port %d not valid!\n",(int)MapP->SysPort)); + rio_dprintk (RIO_DEBUG_TABLE, "Port %d not valid!\n",(int)MapP->SysPort); p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -677,7 +677,7 @@ { if ( *sptr<' ' || *sptr>'~' ) { - rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n"); p->RIOError.Error = BAD_CHARACTER_IN_NAME; return EINVAL; } @@ -702,8 +702,8 @@ { int nNewID; - rio_dprint(RIO_DEBUG_TABLE, ("Attempting to get a new ID for rta \"%s\"\n", - MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Attempting to get a new ID for rta \"%s\"\n", + MapP->Name); /* ** The idea here is to allow RTA's to be assigned ** before they actually appear on the network. @@ -721,7 +721,7 @@ return EBUSY; } MapP->ID = (ushort)nNewID + 1; - rio_dprint(RIO_DEBUG_TABLE, ("Allocated ID %d for this new RTA.\n",MapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "Allocated ID %d for this new RTA.\n", MapP->ID); HostMapP = &p->RIOHosts[host].Mapping[nNewID]; HostMapP->RtaUniqueNum = MapP->RtaUniqueNum; HostMapP->HostUniqueNum = MapP->HostUniqueNum; @@ -747,9 +747,9 @@ HostMapP->Flags |= RTA16_SECOND_SLOT; HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID; p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID; - rio_dprint(RIO_DEBUG_TABLE, ("Cross referenced id %d to ID %d.\n", + rio_dprintk (RIO_DEBUG_TABLE, "Cross referenced id %d to ID %d.\n", MapP->ID, - p->RIOHosts[host].Mapping[unit].ID)); + p->RIOHosts[host].Mapping[unit].ID); } } @@ -757,7 +757,7 @@ if ( HostMapP->Flags & SLOT_IN_USE ) { - rio_dprint(RIO_DEBUG_TABLE, ("Map table slot for ID %d is already in use.\n",MapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "Map table slot for ID %d is already in use.\n", MapP->ID); p->RIOError.Error = ID_ALREADY_IN_USE; return EBUSY; } @@ -791,15 +791,15 @@ p->RIOLastPortsBooted = HostMapP->SysPort; } if (MapP->Flags & RTA16_SECOND_SLOT) - rio_dprint(RIO_DEBUG_TABLE, ("Second map of RTA %s added to configuration\n", - p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name)); + rio_dprintk (RIO_DEBUG_TABLE, "Second map of RTA %s added to configuration\n", + p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name); else - rio_dprint(RIO_DEBUG_TABLE, ("RTA %s added to configuration\n",MapP->Name)); + rio_dprintk (RIO_DEBUG_TABLE, "RTA %s added to configuration\n", MapP->Name); return 0; } } p->RIOError.Error = UNKNOWN_HOST_NUMBER; - rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum); return ENXIO; } @@ -822,7 +822,7 @@ CheckHostMapP( HostMapP ); #endif - rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d to id %d\n",(int)HostMapP->SysPort, HostMapP->ID)); + rio_dprintk (RIO_DEBUG_TABLE, "Mapping sysport %d to id %d\n", (int)HostMapP->SysPort, HostMapP->ID); /* ** We need to tell the UnixRups which sysport the rup corresponds to @@ -833,26 +833,26 @@ return(0); RtaType = GetUnitType(HostMapP->RtaUniqueNum); - rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d-%d\n", - (int)HostMapP->SysPort,(int)HostMapP->SysPort+PORTS_PER_RTA-1)); + rio_dprintk (RIO_DEBUG_TABLE, "Mapping sysport %d-%d\n", + (int)HostMapP->SysPort, (int)HostMapP->SysPort+PORTS_PER_RTA-1); /* ** now map each of its eight ports */ for ( SubEnt=0; SubEntSysPort = %d\n", - SubEnt, (int) HostMapP->SysPort)); + rio_dprintk (RIO_DEBUG_TABLE, "subent = %d, HostMapP->SysPort = %d\n", + SubEnt, (int)HostMapP->SysPort); SysPort = HostMapP->SysPort+SubEnt; /* portnumber within system */ /* portnumber on host */ HostPort = (HostMapP->ID-1)*PORTS_PER_RTA+SubEnt; - rio_dprint (RIO_DEBUG_TABLE, ("c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp)); + rio_dprintk (RIO_DEBUG_TABLE, "c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp); PortP = p->RIOPortp[SysPort]; #if 0 PortP->TtyP = &p->channel[SysPort]; #endif - rio_dprint(RIO_DEBUG_TABLE, ("Map port\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Map port\n"); /* ** Point at all the real neat data structures @@ -1008,12 +1008,12 @@ struct Map *HostMapP; char *sptr; - rio_dprint(RIO_DEBUG_TABLE, ("Change name entry on host %x, rta %x, ID %d, Sysport %d\n", + rio_dprintk (RIO_DEBUG_TABLE, "Change name entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum,MapP->RtaUniqueNum, - MapP->ID, (int)MapP->SysPort )); + MapP->ID, (int)MapP->SysPort); if ( MapP->ID > MAX_RUP ) { - rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Bad ID in map entry!\n"); p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; return EINVAL; } @@ -1023,7 +1023,7 @@ while ( *sptr ) { if ( *sptr<' ' || *sptr>'~' ) { - rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n")); + rio_dprintk (RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n"); p->RIOError.Error = BAD_CHARACTER_IN_NAME; return EINVAL; } @@ -1052,6 +1052,6 @@ } } p->RIOError.Error = UNKNOWN_HOST_NUMBER; - rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum)); + rio_dprintk (RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum); return ENXIO; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/rio/riotty.c linux/drivers/char/rio/riotty.c --- v2.4.0-test6/linux/drivers/char/rio/riotty.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/rio/riotty.c Fri Aug 11 14:51:33 2000 @@ -164,15 +164,15 @@ Modem = rio_ismodem (tty->device); if ( p->RIOFailed ) { - rio_dprint(RIO_DEBUG_TTY, ("System initialisation failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "System initialisation failed\n"); pseterr(ENXIO); func_exit (); return -ENXIO; } - rio_dprint(RIO_DEBUG_TTY, ("port open SysPort %d (%s) (mapped:%d)\n", + rio_dprintk (RIO_DEBUG_TTY, "port open SysPort %d (%s) (mapped:%d)\n", SysPort, Modem ? "Modem" : "tty", - p->RIOPortp[SysPort]->Mapped ) ); + p->RIOPortp[SysPort]->Mapped); /* ** Validate that we have received a legitimate request. @@ -181,7 +181,7 @@ ** has been mapped onto a host. */ if (SysPort >= RIO_PORTS) { /* out of range ? */ - rio_dprint(RIO_DEBUG_TTY, ("Illegal port number %d\n",SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "Illegal port number %d\n",SysPort); pseterr(ENXIO); func_exit(); return -ENXIO; @@ -197,7 +197,7 @@ ** The system doesn't know which RTA this port ** corresponds to. */ - rio_dprint(RIO_DEBUG_TTY, ("port not mapped into system\n")); + rio_dprintk (RIO_DEBUG_TTY, "port not mapped into system\n"); func_exit (); pseterr(ENXIO); return -ENXIO; @@ -206,17 +206,26 @@ tty->driver_data = PortP; PortP->gs.tty = tty; + if (!PortP->gs.count) + rio_inc_mod_count (); PortP->gs.count++; - rio_dprint(RIO_DEBUG_TTY, ("%d bytes in tx buffer\n", - PortP->gs.xmit_cnt)); - gs_init_port (&PortP->gs); + rio_dprintk (RIO_DEBUG_TTY, "%d bytes in tx buffer\n", + PortP->gs.xmit_cnt); + + retval = gs_init_port (&PortP->gs); + if (retval) { + PortP->gs.count--; + if (PortP->gs.count) + rio_dec_mod_count (); + return -ENXIO; + } /* ** If the host hasn't been booted yet, then ** fail */ if ( (PortP->HostP->Flags & RUN_STATE) != RC_RUNNING ) { - rio_dprint(RIO_DEBUG_TTY, ("Host not running\n")); + rio_dprintk (RIO_DEBUG_TTY, "Host not running\n"); pseterr(ENXIO); func_exit (); return -ENXIO; @@ -230,24 +239,24 @@ #if 0 if (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { if (PortP->WaitUntilBooted) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot\n"); do { if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); func_exit (); return -EINTR; } if (repeat_this -- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); pseterr(EINTR); func_exit (); return -EIO; } } while(!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)); - rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA has been booted\n"); } else { - rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA never booted\n"); pseterr(ENXIO); func_exit (); return 0; @@ -258,10 +267,10 @@ easier to read and shorter. Now, if it works too that would be great... -- REW */ - rio_dprint(RIO_DEBUG_TTY, ("Checking if RTA has booted... \n")); + rio_dprintk (RIO_DEBUG_TTY, "Checking if RTA has booted... \n"); while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { if (!PortP->WaitUntilBooted) { - rio_dprint(RIO_DEBUG_TTY, ("RTA never booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA never booted\n"); func_exit (); return -ENXIO; } @@ -271,17 +280,17 @@ now. --REW */ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("RTA_wait_for_boot: EINTR in delay \n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA_wait_for_boot: EINTR in delay \n"); func_exit (); return -EINTR; } if (repeat_this -- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RTA to boot timeout\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); func_exit (); return -EIO; } } - rio_dprint(RIO_DEBUG_TTY, ("RTA has been booted\n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA has been booted\n"); #endif #if 0 tp = PortP->TtyP; /* get tty struct */ @@ -304,9 +313,9 @@ ** for it to finish, so that it doesn't close us! */ while ( (PortP->State & RIO_CLOSING) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for RIO_CLOSING to go away\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n"); if (repeat_this -- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); retval = -EINTR; goto bombout; @@ -321,7 +330,7 @@ } if ( !PortP->Mapped ) { - rio_dprint(RIO_DEBUG_TTY, ("Port unmapped while closing!\n")); + rio_dprintk (RIO_DEBUG_TTY, "Port unmapped while closing!\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); retval = -ENXIO; func_exit (); @@ -344,8 +353,8 @@ } if (!(PortP->firstOpen)) { /* First time ? */ - rio_dprint(RIO_DEBUG_TTY, ("First open for this port\n")); - rio_inc_mod_count (); + rio_dprintk (RIO_DEBUG_TTY, "First open for this port\n"); + PortP->firstOpen++; PortP->CookMode = 0; /* XXX RIOCookMode(tp); */ @@ -375,7 +384,7 @@ ** wait for the port to be not closed. */ while ( !(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for PORT_ISOPEN-currently %x\n",PortP->PortState)); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for PORT_ISOPEN-currently %x\n",PortP->PortState); /* ** 15.10.1998 ARG - ESIL 0759 ** (Part) fix for port being trashed when opened whilst RTA "disconnected" @@ -392,7 +401,7 @@ */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish broken by signal\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); func_exit (); return -EINTR; @@ -407,52 +416,67 @@ rio_spin_unlock_irqrestore(&PortP->portSem, flags); return retval; } - rio_dprint(RIO_DEBUG_TTY, ("PORT_ISOPEN found\n")); + rio_dprintk (RIO_DEBUG_TTY, "PORT_ISOPEN found\n"); } #ifdef MODEM_SUPPORT if (Modem) { - rio_dprint(RIO_DEBUG_TTY, ("Modem - test for carrier\n")); + rio_dprintk (RIO_DEBUG_TTY, "Modem - test for carrier\n"); /* ** ACTION ** insert test for carrier here. -- ??? ** I already see that test here. What's the deal? -- REW */ - if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) + if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) { - rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) Modem carr on\n",SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort); + /* tp->tm.c_state |= CARR_ON; wakeup((caddr_t) &tp->tm.c_canq); + */ + PortP->State |= RIO_CARR_ON; + wake_up_interruptible (&PortP->gs.open_wait); } else /* no carrier - wait for DCD */ { - while (!(tp->tm.c_state&CARR_ON) && - !(filp->f_flags&O_NONBLOCK) && !p->RIOHalted ) - { - rio_dprint(RIO_DEBUG_TTY, (PortP,DBG_OPEN,"open(%d) sleeping for carr on\n",SysPort)); - tp->tm.c_state |= WOPEN; + /* + while (!(PortP->gs.tty->termios->c_state & CARR_ON) && + !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) + */ + while (!(PortP->State & RIO_CARR_ON) && + !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) { + + rio_dprintk (RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n",SysPort); + /* + PortP->gs.tty->termios->c_state |= WOPEN; + */ PortP->State |= RIO_WOPEN; - if ( sleep((caddr_t)&tp->tm.c_canq, TTIPRI|PCATCH)) +#if 0 + if ( sleep((caddr_t)&tp->tm.c_canqo, TTIPRI|PCATCH)) { /* ** ACTION: verify that this is a good thing ** to do here. -- ??? ** I think it's OK. -- REW */ - rio_dprint(RIO_DEBUG_TTY, ("open(%d) sleeping for carr broken by signal\n", - SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", + SysPort); RIOPreemptiveCmd( p, PortP, FCLOSE ); + /* tp->tm.c_state &= ~WOPEN; + */ PortP->State &= ~RIO_WOPEN; rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit (); return -EINTR; } +#endif } PortP->State &= ~RIO_WOPEN; } - if ( RIOHalted ) + if ( p->RIOHalted ) goto bombout; + rio_dprintk (RIO_DEBUG_TTY, "Setting RIO_MOPEN\n"); PortP->State |= RIO_MOPEN; } else @@ -470,7 +494,7 @@ goto bombout; } - rio_dprint(RIO_DEBUG_TTY, ("high level open done\n")); + rio_dprintk (RIO_DEBUG_TTY, "high level open done\n"); #ifdef STATS PortP->Stat.OpenCnt++; @@ -482,7 +506,7 @@ PortP->opens++; rio_spin_unlock_irqrestore(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Returning from open\n")); + rio_dprintk (RIO_DEBUG_TTY, "Returning from open\n"); func_exit (); return 0; } @@ -509,13 +533,13 @@ int Modem; int rv =0; - rio_dprint(RIO_DEBUG_TTY, ("port close SysPort %d\n",PortP->PortNum)); + rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum); /* PortP = p->RIOPortp[SysPort]; */ - rio_dprint(RIO_DEBUG_TTY, ("Port is at address 0x%x\n",(int)PortP)); + rio_dprintk (RIO_DEBUG_TTY, "Port is at address 0x%x\n",(int)PortP); /* tp = PortP->TtyP;*/ /* Get tty */ tty = PortP->gs.tty; - rio_dprint(RIO_DEBUG_TTY, ("TTY is at address 0x%x\n",(int)tty)); + rio_dprintk (RIO_DEBUG_TTY, "TTY is at address 0x%x\n",(int)tty); Modem = rio_ismodem(tty->device); #if 0 /* What F.CKING cache? Even then, a higly idle multiprocessor, @@ -533,7 +557,7 @@ PortP->State |= RIO_CLOSING; if ( (PortP->State & RIO_DELETED) ) { - rio_dprint(RIO_DEBUG_TTY, ("Close on deleted RTA\n")); + rio_dprintk (RIO_DEBUG_TTY, "Close on deleted RTA\n"); deleted = 1; } @@ -543,7 +567,7 @@ goto close_end; } - rio_dprint(RIO_DEBUG_TTY, ("Clear bits\n")); + rio_dprintk (RIO_DEBUG_TTY, "Clear bits\n"); /* ** clear the open bits for this device */ @@ -561,7 +585,7 @@ ** The port is still open for the other task - ** return, pretending that we are still active. */ - rio_dprint(RIO_DEBUG_TTY, ("Channel %d still open !\n",PortP->PortNum)); + rio_dprintk (RIO_DEBUG_TTY, "Channel %d still open !\n",PortP->PortNum); PortP->State &= ~RIO_CLOSING; if (PortP->firstOpen) PortP->firstOpen--; @@ -569,7 +593,7 @@ return -EIO; } - rio_dprint(RIO_DEBUG_TTY, ("Closing down - everything must go!\n")); + rio_dprintk (RIO_DEBUG_TTY, "Closing down - everything must go!\n"); PortP->State &= ~RIO_DYNOROD; @@ -578,7 +602,7 @@ ** to drain down before closing. Bye-bye.... ** (We never meant to do this) */ - rio_dprint(RIO_DEBUG_TTY, ("Timeout 1 starts\n")); + rio_dprintk (RIO_DEBUG_TTY, "Timeout 1 starts\n"); #if 0 if (!deleted) @@ -587,14 +611,14 @@ cprintf("Need to flush the ttyport\n"); if (repeat_this -- <= 0) { rv = -EINTR; - rio_dprint(RIO_DEBUG_TTY, ("Waiting for not idle closed broken by signal\n")); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE ); goto close_end; } - rio_dprint(RIO_DEBUG_TTY, ("Calling timeout to flush in closing\n")); + rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay_ni(PortP, HUNDRED_MS*10) == RIO_FAIL) { - rio_dprint(RIO_DEBUG_TTY, ("RTA EINTR in delay \n")); + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); rv = -EINTR; rio_spin_lock_irqsave(&PortP->portSem, flags); goto close_end; @@ -611,7 +635,7 @@ ** The port has been re-opened for the other task - ** return, pretending that we are still active. */ - rio_dprint(RIO_DEBUG_TTY, ("Channel %d re-open!\n", PortP->PortNum)); + rio_dprintk (RIO_DEBUG_TTY, "Channel %d re-open!\n", PortP->PortNum); PortP->State &= ~RIO_CLOSING; rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->firstOpen) @@ -638,12 +662,12 @@ while (try && (PortP->PortState & PORT_ISOPEN)) { try--; if (try == 0) { - rio_dprint(RIO_DEBUG_TTY, ("Run out of tries - force the bugger shut!\n" )); + rio_dprintk (RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n" ); RIOPreemptiveCmd(p, PortP,FCLOSE); break; } - rio_dprint(RIO_DEBUG_TTY, ("Close: PortState:ISOPEN is %d\n", - PortP->PortState & PORT_ISOPEN)); + rio_dprintk (RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", + PortP->PortState & PORT_ISOPEN); if ( p->RIOHalted ) { RIOClearUp( PortP ); @@ -652,7 +676,7 @@ RIODelay_ni(PortP, HUNDRED_MS); } rio_spin_lock_irqsave(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Close: try was %d on completion\n", try )); + rio_dprintk (RIO_DEBUG_TTY, "Close: try was %d on completion\n", try ); /* RIOPreemptiveCmd(p, PortP, FCLOSE); */ @@ -682,7 +706,7 @@ if (PortP->firstOpen) PortP->firstOpen--; rio_spin_unlock_irqrestore(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Return from close\n")); + rio_dprintk (RIO_DEBUG_TTY, "Return from close\n"); return rv; } @@ -731,7 +755,7 @@ RIOClearUp(PortP) struct Port *PortP; { - rio_dprint(RIO_DEBUG_TTY, ("RIOHalted set\n")); + rio_dprintk (RIO_DEBUG_TTY, "RIOHalted set\n"); PortP->Config = 0; /* Direct semaphore */ PortP->PortState = 0; PortP->firstOpen = 0; @@ -761,7 +785,7 @@ int retries = 20; /* at 10 per second -> 2 seconds */ unsigned long flags; - rio_dprint(RIO_DEBUG_TTY, ("entering shortcommand.\n")); + rio_dprintk (RIO_DEBUG_TTY, "entering shortcommand.\n"); #ifdef CHECK CheckPortP( PortP ); if ( len < 1 || len > 2 ) @@ -769,7 +793,7 @@ #endif if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n")); + rio_dprintk (RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n"); return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags); @@ -779,8 +803,8 @@ ** be free again. */ while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting for not in use (%d)\n", - retries)); + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not in use (%d)\n", + retries); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (retries-- <= 0) { return RIO_FAIL; @@ -791,16 +815,16 @@ rio_spin_lock_irqsave(&PortP->portSem, flags); } if ( PortP->State & RIO_DELETED ) { - rio_dprint(RIO_DEBUG_TTY, ("Short command to deleted RTA ignored\n")); + rio_dprintk (RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIO_FAIL; } while ( !can_add_transmit(&PacketP,PortP) && !p->RIOHalted ) { - rio_dprint(RIO_DEBUG_TTY, ("Waiting to add short command to queue (%d)\n", retries)); + rio_dprintk (RIO_DEBUG_TTY, "Waiting to add short command to queue (%d)\n", retries); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (retries-- <= 0) { - rio_dprint(RIO_DEBUG_TTY, ("out of tries. Failing\n")); + rio_dprintk (RIO_DEBUG_TTY, "out of tries. Failing\n"); return RIO_FAIL; } if ( RIODelay_ni(PortP, HUNDRED_MS)==RIO_FAIL ) { @@ -865,11 +889,11 @@ int Modem = rio_ismodem(dev); int ioctl_processed; - rio_dprint(RIO_DEBUG_TTY, ("port ioctl SysPort %d command 0x%x argument 0x%x %s\n", - SysPort,cmd,arg,Modem?"Modem":"tty")); + rio_dprintk (RIO_DEBUG_TTY, "port ioctl SysPort %d command 0x%x argument 0x%x %s\n", + SysPort, cmd, arg, Modem?"Modem":"tty") ; if ( SysPort >= RIO_PORTS ) { - rio_dprint(RIO_DEBUG_TTY, ("Bad port number %d\n",SysPort)); + rio_dprintk (RIO_DEBUG_TTY, "Bad port number %d\n", SysPort); return -ENXIO; } @@ -926,22 +950,22 @@ return 0; case TCRIOTSTATE: - rio_dprint(RIO_DEBUG_TTY, ("tbusy/tstop monitoring %sabled\n", - arg ? "en" : "dis")); + rio_dprintk (RIO_DEBUG_TTY, "tbusy/tstop monitoring %sabled\n", + arg ? "en" : "dis"); /* MonitorTstate = 0 ;*/ rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP, CONFIG, Modem, OK_TO_SLEEP); return 0; case TCRIOSTATE: /* current state of Modem input pins */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOSTATE\n"); if (RIOPreemptiveCmd(p, PortP, MGET) == RIO_FAIL) - rio_dprint(RIO_DEBUG_TTY, ("TCRIOSTATE command failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOSTATE command failed\n"); PortP->State |= RIO_BUSY; current = PortP->ModemState; if ( copyout((caddr_t)¤t, (int)arg, sizeof(current))==COPYFAIL ) { - rio_dprint(RIO_DEBUG_TTY, ("Copyout failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "Copyout failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EFAULT); } @@ -950,15 +974,15 @@ case TCRIOMBIS: /* Set modem lines */ case TCRIOMBIC: /* Clear modem lines */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIS/TCRIOMBIC\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOMBIS/TCRIOMBIC\n"); if (cmd == TCRIOMBIS) { uint state; state = (uint)arg; PortP->ModemState |= (ushort)state; PortP->ModemLines = (ulong) arg; if (RIOPreemptiveCmd(p, PortP, MBIS) == RIO_FAIL) - rio_dprint(RIO_DEBUG_TTY, ( - "TCRIOMBIS command failed\n")); + rio_dprintk (RIO_DEBUG_TTY, + "TCRIOMBIS command failed\n"); } else { uint state; @@ -967,17 +991,17 @@ PortP->ModemState &= ~(ushort)state; PortP->ModemLines = (ulong) arg; if (RIOPreemptiveCmd(p, PortP, MBIC) == RIO_FAIL) - rio_dprint(RIO_DEBUG_TTY, ("TCRIOMBIC command failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOMBIC command failed\n"); } PortP->State |= RIO_BUSY; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOXPON: /* set Xprint ON string */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPON\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPON\n"); if ( copyin((int)arg, (caddr_t)PortP->Xprint.XpOn, MAX_XP_CTRL_LEN)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "Copyin failed\n"); PortP->Xprint.XpOn[0] = '\0'; rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EFAULT); @@ -989,10 +1013,10 @@ return 0; case TCRIOXPOFF: /* set Xprint OFF string */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPOFF\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPOFF\n"); if ( copyin( (int)arg, (caddr_t)PortP->Xprint.XpOff, MAX_XP_CTRL_LEN)==COPYFAIL ) { - rio_dprint(RIO_DEBUG_TTY, ("Copyin failed\n")); + rio_dprintk (RIO_DEBUG_TTY, "Copyin failed\n"); PortP->Xprint.XpOff[0] = '\0'; rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EFAULT); @@ -1004,10 +1028,10 @@ return 0; case TCRIOXPCPS: /* set Xprint CPS string */ - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPCPS\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPCPS\n"); if ( (uint)arg > p->RIOConf.MaxXpCps || (uint)arg < p->RIOConf.MinXpCps ) { - rio_dprint(RIO_DEBUG_TTY, ("%d CPS out of range\n",arg)); + rio_dprintk (RIO_DEBUG_TTY, "%d CPS out of range\n",arg); rio_spin_unlock_irqrestore(&PortP->portSem, flags); pseterr(EINVAL); return 0; @@ -1017,7 +1041,7 @@ return 0; case TCRIOXPRINT: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOXPRINT\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPRINT\n"); if ( copyout((caddr_t)&PortP->Xprint, (int)arg, sizeof(struct Xprint))==COPYFAIL ) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); @@ -1027,25 +1051,25 @@ return 0; case TCRIOIXANYON: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYON\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXANYON\n"); PortP->Config |= RIO_IXANY; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOIXANYOFF: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXANYOFF\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXANYOFF\n"); PortP->Config &= ~RIO_IXANY; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOIXONON: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONON\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXONON\n"); PortP->Config |= RIO_IXON; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; case TCRIOIXONOFF: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOIXONOFF\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXONOFF\n"); PortP->Config &= ~RIO_IXON; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; @@ -1055,28 +1079,28 @@ ** Added support for CTS and RTS flow control ioctls : */ case TCRIOCTSFLOWEN: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWEN\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOCTSFLOWEN\n"); PortP->Config |= RIO_CTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); return 0; case TCRIOCTSFLOWDIS: - rio_dprint(RIO_DEBUG_TTY, ("TCRIOCTSFLOWDIS\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIOCTSFLOWDIS\n"); PortP->Config &= ~RIO_CTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); return 0; case TCRIORTSFLOWEN: - rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWEN\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIORTSFLOWEN\n"); PortP->Config |= RIO_RTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); return 0; case TCRIORTSFLOWDIS: - rio_dprint(RIO_DEBUG_TTY, ("TCRIORTSFLOWDIS\n")); + rio_dprintk (RIO_DEBUG_TTY, "TCRIORTSFLOWDIS\n"); PortP->Config &= ~RIO_RTSFLOW; rio_spin_unlock_irqrestore(&PortP->portSem, flags); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); @@ -1100,13 +1124,13 @@ case TCSETAW: case TCSETAF: ioctl_processed++; - rio_dprint(RIO_DEBUG_TTY, ("NON POSIX ioctl\n")); + rio_dprintk (RIO_DEBUG_TTY, "NON POSIX ioctl\n"); ttyseth_pv(PortP, tp, (struct termios *)arg, 0); break; case TCSETAP: /* posix tcsetattr() */ case TCSETAWP: /* posix tcsetattr() */ case TCSETAFP: /* posix tcsetattr() */ - rio_dprint(RIO_DEBUG_TTY, ("NON POSIX SYSV ioctl\n")); + rio_dprintk (RIO_DEBUG_TTY, "NON POSIX SYSV ioctl\n"); ttyseth_pv(PortP, tp, (struct termios *)arg, 1); ioctl_processed++; break; @@ -1141,7 +1165,7 @@ #endif case TIOCSETD: case TIOCSETN: - rio_dprint(RIO_DEBUG_TTY, ("wait for non-BUSY, semaphore set\n")); + rio_dprintk (RIO_DEBUG_TTY, "wait for non-BUSY, semaphore set\n"); /* ** Wait for drain here, at least as far as the double buffer ** being empty. @@ -1208,8 +1232,8 @@ PortP->CookMode = RIOCookMode(tp); /* Set new cooking mode */ - rio_dprint(RIO_DEBUG_TTY, ("RIOIoctl changed %d newcook %d oldcook %d\n", - changed,PortP->CookMode,oldcook)); + rio_dprintk (RIO_DEBUG_TTY, "RIOIoctl changed %d newcook %d oldcook %d\n", + changed,PortP->CookMode,oldcook); #ifdef MODEM_SUPPORT /* @@ -1232,7 +1256,7 @@ */ if (changed || oldcook != PortP->CookMode || (ioctl_processed)) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); - rio_dprint(RIO_DEBUG_TTY, ("Ioctl changing the PORT settings\n")); + rio_dprintk (RIO_DEBUG_TTY, "Ioctl changing the PORT settings\n"); RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); rio_spin_lock_irqsave(&PortP->portSem, flags); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa5249.c linux/drivers/char/saa5249.c --- v2.4.0-test6/linux/drivers/char/saa5249.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/saa5249.c Wed Dec 31 16:00:00 1969 @@ -1,683 +0,0 @@ -/* - * Cleaned up to use existing videodev interface and allow the idea - * of multiple teletext decoders on the video4linux iface. Changed i2c - * to cover addressing clashes on device busses. It's also rebuilt so - * you can add arbitary multiple teletext devices to Linux video4linux - * now (well 32 anyway). - * - * Alan Cox - * - * The original driver was heavily modified to match the i2c interface - * It was truncated to use the WinTV boards, too. - * - * Copyright (c) 1998 Richard Guenther - * - * $Id: saa5249.c,v 1.1 1998/03/30 22:23:23 alan Exp $ - * - * Derived From - * - * vtx.c: - * This is a loadable character-device-driver for videotext-interfaces - * (aka teletext). Please check the Makefile/README for a list of supported - * interfaces. - * - * Copyright (c) 1994-97 Martin Buck - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define VTX_VER_MAJ 1 -#define VTX_VER_MIN 7 - - - -#define NUM_DAUS 4 -#define NUM_BUFS 8 -#define IF_NAME "SAA5249" - -static const int disp_modes[8][3] = -{ - { 0x46, 0x03, 0x03 }, /* DISPOFF */ - { 0x46, 0xcc, 0xcc }, /* DISPNORM */ - { 0x44, 0x0f, 0x0f }, /* DISPTRANS */ - { 0x46, 0xcc, 0x46 }, /* DISPINS */ - { 0x44, 0x03, 0x03 }, /* DISPOFF, interlaced */ - { 0x44, 0xcc, 0xcc }, /* DISPNORM, interlaced */ - { 0x44, 0x0f, 0x0f }, /* DISPTRANS, interlaced */ - { 0x44, 0xcc, 0x46 } /* DISPINS, interlaced */ -}; - - - -#define PAGE_WAIT (300*HZ/1000) /* Time between requesting page and */ - /* checking status bits */ -#define PGBUF_EXPIRE (15*HZ) /* Time to wait before retransmitting */ - /* page regardless of infobits */ -typedef struct { - u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */ - u8 laststat[10]; /* Last value of infobits for DAU */ - u8 sregs[7]; /* Page-request registers */ - unsigned long expire; /* Time when page will be expired */ - unsigned clrfound : 1; /* VTXIOCCLRFOUND has been called */ - unsigned stopped : 1; /* VTXIOCSTOPDAU has been called */ -} vdau_t; - -struct saa5249_device -{ - vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */ - /* real DAU, so we have to simulate some more) */ - int vtx_use_count; - int is_searching[NUM_DAUS]; - int disp_mode; - int virtual_mode; - struct i2c_client *client; -}; - - -#define CCTWR 34 /* I²C write/read-address of vtx-chip */ -#define CCTRD 35 -#define NOACK_REPEAT 10 /* Retry access this many times on failure */ -#define CLEAR_DELAY (HZ/20) /* Time required to clear a page */ -#define READY_TIMEOUT (30*HZ/1000) /* Time to wait for ready signal of I²C-bus interface */ -#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */ -#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */ - -#define VTX_DEV_MINOR 0 - -/* General defines and debugging support */ - -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif - -#define RESCHED \ - do { \ - if (current->need_resched) \ - schedule(); \ - } while (0) - -static struct video_device saa_template; /* Declared near bottom */ - -/* Addresses to scan */ -static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -static struct i2c_client client_template; - -static int saa5249_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) -{ - int pgbuf; - int err; - struct i2c_client *client; - struct video_device *vd; - struct saa5249_device *t; - - printk(KERN_INFO "saa5249: teletext chip found.\n"); - client=kmalloc(sizeof(*client), GFP_KERNEL); - if(client==NULL) - return -ENOMEM; - client_template.adapter = adap; - client_template.addr = addr; - memcpy(client, &client_template, sizeof(*client)); - t = kmalloc(sizeof(*t), GFP_KERNEL); - if(t==NULL) - { - kfree(client); - return -ENOMEM; - } - memset(t, 0, sizeof(*t)); - strcpy(client->name, IF_NAME); - - /* - * Now create a video4linux device - */ - - client->data = vd=(struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL); - if(vd==NULL) - { - kfree(t); - kfree(client); - return -ENOMEM; - } - memcpy(vd, &saa_template, sizeof(*vd)); - - for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) - { - memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); - memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); - memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); - t->vdau[pgbuf].expire = 0; - t->vdau[pgbuf].clrfound = TRUE; - t->vdau[pgbuf].stopped = TRUE; - t->is_searching[pgbuf] = FALSE; - } - vd->priv=t; - - /* - * Register it - */ - - if((err=video_register_device(vd, VFL_TYPE_VTX))<0) - { - kfree(t); - kfree(vd); - kfree(client); - return err; - } - t->client = client; - i2c_attach_client(client); - MOD_INC_USE_COUNT; - return 0; -} - -/* - * We do most of the hard work when we become a device on the i2c. - */ - -static int saa5249_probe(struct i2c_adapter *adap) -{ - /* Only attach these chips to the BT848 bus for now */ - - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - { - return i2c_probe(adap, &addr_data, saa5249_attach); - } - return 0; -} - -static int saa5249_detach(struct i2c_client *client) -{ - struct video_device *vd=client->data; - i2c_detach_client(client); - video_unregister_device(vd); - kfree(vd->priv); - kfree(vd); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int saa5249_command(struct i2c_client *device, - unsigned int cmd, void *arg) -{ - return -EINVAL; -} - -/* new I2C driver support */ - -static struct i2c_driver i2c_driver_videotext = -{ - IF_NAME, /* name */ - I2C_DRIVERID_SAA5249, /* in i2c.h */ - I2C_DF_NOTIFY, - saa5249_probe, - saa5249_detach, - saa5249_command -}; - -static struct i2c_client client_template = { - "(unset)", - -1, - 0, - 0, - NULL, - &i2c_driver_videotext -}; - -/* - * Wait the given number of jiffies (10ms). This calls the scheduler, so the actual - * delay may be longer. - */ - -static void jdelay(unsigned long delay) -{ - sigset_t oldblocked = current->blocked; - - spin_lock_irq(¤t->sigmask_lock); - sigfillset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(delay); - - spin_lock_irq(¤t->sigmask_lock); - current->blocked = oldblocked; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); -} - - -/* - * I2C interfaces - */ - -static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data) -{ - char buf[64]; - - buf[0] = reg; - memcpy(buf+1, data, count); - - if(i2c_master_send(t->client, buf, count+1)==count+1) - return 0; - return -1; -} - -static int i2c_senddata(struct saa5249_device *t, ...) -{ - unsigned char buf[64]; - int v; - int ct=0; - va_list argp; - va_start(argp,t); - - while((v=va_arg(argp,int))!=-1) - buf[ct++]=v; - return i2c_sendbuf(t, buf[0], ct-1, buf+1); -} - -/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop - * handshaking is done by this routine, ack will be sent after the last byte to inhibit further - * sending of data. If uaccess is TRUE, data is written to user-space with put_user. - * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise - */ - -static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf) -{ - if(i2c_master_recv(t->client, buf, count)!=count) - return -1; - return 0; -} - - -/* - * Standard character-device-driver functions - */ - -static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg) -{ - struct saa5249_device *t=vd->priv; - static int virtual_mode = FALSE; - - switch(cmd) - { - case VTXIOCGETINFO: - { - vtx_info_t info; - info.version_major = VTX_VER_MAJ; - info.version_minor = VTX_VER_MIN; - info.numpages = NUM_DAUS; - /*info.cct_type = CCT_TYPE;*/ - if(copy_to_user((void*)arg, &info, sizeof(vtx_info_t))) - return -EFAULT; - return 0; - } - - case VTXIOCCLRPAGE: - { - vtx_pagereq_t req; - - if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) - return -EFAULT; - if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) - return -EINVAL; - memset(t->vdau[req.pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); - t->vdau[req.pgbuf].clrfound = TRUE; - return 0; - } - - case VTXIOCCLRFOUND: - { - vtx_pagereq_t req; - - if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) - return -EFAULT; - if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) - return -EINVAL; - t->vdau[req.pgbuf].clrfound = TRUE; - return 0; - } - - case VTXIOCPAGEREQ: - { - vtx_pagereq_t req; - if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) - return -EFAULT; - if (!(req.pagemask & PGMASK_PAGE)) - req.page = 0; - if (!(req.pagemask & PGMASK_HOUR)) - req.hour = 0; - if (!(req.pagemask & PGMASK_MINUTE)) - req.minute = 0; - if (req.page < 0 || req.page > 0x8ff) /* 7FF ?? */ - return -EINVAL; - req.page &= 0x7ff; - if (req.hour < 0 || req.hour > 0x3f || req.minute < 0 || req.minute > 0x7f || - req.pagemask < 0 || req.pagemask >= PGMASK_MAX || req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) - return -EINVAL; - t->vdau[req.pgbuf].sregs[0] = (req.pagemask & PG_HUND ? 0x10 : 0) | (req.page / 0x100); - t->vdau[req.pgbuf].sregs[1] = (req.pagemask & PG_TEN ? 0x10 : 0) | ((req.page / 0x10) & 0xf); - t->vdau[req.pgbuf].sregs[2] = (req.pagemask & PG_UNIT ? 0x10 : 0) | (req.page & 0xf); - t->vdau[req.pgbuf].sregs[3] = (req.pagemask & HR_TEN ? 0x10 : 0) | (req.hour / 0x10); - t->vdau[req.pgbuf].sregs[4] = (req.pagemask & HR_UNIT ? 0x10 : 0) | (req.hour & 0xf); - t->vdau[req.pgbuf].sregs[5] = (req.pagemask & MIN_TEN ? 0x10 : 0) | (req.minute / 0x10); - t->vdau[req.pgbuf].sregs[6] = (req.pagemask & MIN_UNIT ? 0x10 : 0) | (req.minute & 0xf); - t->vdau[req.pgbuf].stopped = FALSE; - t->vdau[req.pgbuf].clrfound = TRUE; - t->is_searching[req.pgbuf] = TRUE; - return 0; - } - - case VTXIOCGETSTAT: - { - vtx_pagereq_t req; - u8 infobits[10]; - vtx_pageinfo_t info; - int a; - - if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) - return -EFAULT; - if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) - return -EINVAL; - if (!t->vdau[req.pgbuf].stopped) - { - if (i2c_senddata(t, 2, 0, -1) || - i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req.pgbuf].sregs) || - i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) || - i2c_senddata(t, 2, 0, t->vdau[req.pgbuf].sregs[0] | 8, -1) || - i2c_senddata(t, 8, 0, 25, 0, -1)) - return -EIO; - jdelay(PAGE_WAIT); - if (i2c_getdata(t, 10, infobits)) - return -EIO; - - if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) && /* check FOUND-bit */ - (memcmp(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)) || - time_after_eq(jiffies, t->vdau[req.pgbuf].expire))) - { /* check if new page arrived */ - if (i2c_senddata(t, 8, 0, 0, 0, -1) || - i2c_getdata(t, VTX_PAGESIZE, t->vdau[req.pgbuf].pgbuf)) - return -EIO; - t->vdau[req.pgbuf].expire = jiffies + PGBUF_EXPIRE; - memset(t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE); - if (t->virtual_mode) - { - /* Packet X/24 */ - if (i2c_senddata(t, 8, 0, 0x20, 0, -1) || - i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40)) - return -EIO; - /* Packet X/27/0 */ - if (i2c_senddata(t, 8, 0, 0x21, 0, -1) || - i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40)) - return -EIO; - /* Packet 8/30/0...8/30/15 - * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30, - * so we should undo this here. - */ - if (i2c_senddata(t, 8, 0, 0x22, 0, -1) || - i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40)) - return -EIO; - } - t->vdau[req.pgbuf].clrfound = FALSE; - memcpy(t->vdau[req.pgbuf].laststat, infobits, sizeof(infobits)); - } - else - { - memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)); - } - } - else - { - memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)); - } - - info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f); - if (info.pagenum < 0x100) - info.pagenum += 0x800; - info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f); - info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f); - info.charset = ((infobits[7] >> 1) & 7); - info.delete = !!(infobits[3] & 8); - info.headline = !!(infobits[5] & 4); - info.subtitle = !!(infobits[5] & 8); - info.supp_header = !!(infobits[6] & 1); - info.update = !!(infobits[6] & 2); - info.inter_seq = !!(infobits[6] & 4); - info.dis_disp = !!(infobits[6] & 8); - info.serial = !!(infobits[7] & 1); - info.notfound = !!(infobits[8] & 0x10); - info.pblf = !!(infobits[9] & 0x20); - info.hamming = 0; - for (a = 0; a <= 7; a++) - { - if (infobits[a] & 0xf0) - { - info.hamming = 1; - break; - } - } - if (t->vdau[req.pgbuf].clrfound) - info.notfound = 1; - if(copy_to_user(req.buffer, &info, sizeof(vtx_pageinfo_t))) - return -EFAULT; - if (!info.hamming && !info.notfound) - { - t->is_searching[req.pgbuf] = FALSE; - } - return 0; - } - - case VTXIOCGETPAGE: - { - vtx_pagereq_t req; - int start, end; - - if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) - return -EFAULT; - if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS || req.start < 0 || - req.start > req.end || req.end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE)) - return -EINVAL; - if(copy_to_user(req.buffer, &t->vdau[req.pgbuf].pgbuf[req.start], req.end - req.start + 1)) - return -EFAULT; - - /* - * Always read the time directly from SAA5249 - */ - - if (req.start <= 39 && req.end >= 32) - { - int len; - char buf[16]; - start = MAX(req.start, 32); - end = MIN(req.end, 39); - len=end-start+1; - if (i2c_senddata(t, 8, 0, 0, start, -1) || - i2c_getdata(t, len, buf)) - return -EIO; - if(copy_to_user(req.buffer+start-req.start, buf, len)) - return -EFAULT; - } - /* Insert the current header if DAU is still searching for a page */ - if (req.start <= 31 && req.end >= 7 && t->is_searching[req.pgbuf]) - { - char buf[32]; - int len; - start = MAX(req.start, 7); - end = MIN(req.end, 31); - len=end-start+1; - if (i2c_senddata(t, 8, 0, 0, start, -1) || - i2c_getdata(t, len, buf)) - return -EIO; - if(copy_to_user(req.buffer+start-req.start, buf, len)) - return -EFAULT; - } - return 0; - } - - case VTXIOCSTOPDAU: - { - vtx_pagereq_t req; - - if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) - return -EFAULT; - if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) - return -EINVAL; - t->vdau[req.pgbuf].stopped = TRUE; - t->is_searching[req.pgbuf] = FALSE; - return 0; - } - - case VTXIOCPUTPAGE: - case VTXIOCSETDISP: - case VTXIOCPUTSTAT: - return 0; - - case VTXIOCCLRCACHE: - { - if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11, - ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', - ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1)) - return -EIO; - if (i2c_senddata(t, 3, 0x20, -1)) - return -EIO; - jdelay(10 * CLEAR_DELAY); /* I have no idea how long we have to wait here */ - return 0; - } - - case VTXIOCSETVIRT: - { - /* The SAA5249 has virtual-row reception turned on always */ - t->virtual_mode = (int)arg; - return 0; - } - } - return -EINVAL; -} - - -static int saa5249_open(struct video_device *vd, int nb) -{ - struct saa5249_device *t=vd->priv; - int pgbuf; - - if (t->client==NULL) - return -ENODEV; - - if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */ - /* Turn off parity checks (we do this ourselves) */ - i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) || - /* Display TV-picture, no virtual rows */ - i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */ - - { - return -EIO; - } - - for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) - { - memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); - memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); - memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); - t->vdau[pgbuf].expire = 0; - t->vdau[pgbuf].clrfound = TRUE; - t->vdau[pgbuf].stopped = TRUE; - t->is_searching[pgbuf] = FALSE; - } - t->virtual_mode=FALSE; - MOD_INC_USE_COUNT; - return 0; -} - - - -static void saa5249_release(struct video_device *vd) -{ - struct saa5249_device *t=vd->priv; - i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */ - i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */ - MOD_DEC_USE_COUNT; - return; -} - -static long saa5249_write(struct video_device *v, const char *buf, unsigned long l, int nb) -{ - return -EINVAL; -} - -static int __init init_saa_5249 (void) -{ - printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n", - VTX_VER_MAJ, VTX_VER_MIN); - return i2c_add_driver(&i2c_driver_videotext); -} - -static void __exit cleanup_saa_5249 (void) -{ - i2c_del_driver(&i2c_driver_videotext); -} - -module_init(init_saa_5249); -module_exit(cleanup_saa_5249); - -static struct video_device saa_template = -{ - IF_NAME, - VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */ - VID_HARDWARE_SAA5249, - saa5249_open, - saa5249_release, - NULL, /* read */ - saa5249_write, - NULL, /* poll */ - saa5249_ioctl, - /* the rest are null */ -}; - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7110.c linux/drivers/char/saa7110.c --- v2.4.0-test6/linux/drivers/char/saa7110.c Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/saa7110.c Wed Dec 31 16:00:00 1969 @@ -1,429 +0,0 @@ -/* - saa7110 - Philips SAA7110(A) video decoder driver - - Copyright (C) 1998 Pauline Middelink - - 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. -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include "linux/video_decoder.h" - -#define DEBUG(x...) /* remove when no long debugging */ - -#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ -#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ - -#define I2C_SAA7110 0x9C /* or 0x9E */ - -#define I2C_DELAY 10 /* 10 us or 100khz */ - -struct saa7110 { - struct i2c_bus *bus; - int addr; - unsigned char reg[36]; - - int norm; - int input; - int enable; - int bright; - int contrast; - int hue; - int sat; -}; - -/* ----------------------------------------------------------------------- */ -/* I2C support functions */ -/* ----------------------------------------------------------------------- */ -static -int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data) -{ - int ack; - - LOCK_I2C_BUS(decoder->bus); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); - i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY); - ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY); - i2c_stop(decoder->bus); - decoder->reg[subaddr] = data; - UNLOCK_I2C_BUS(decoder->bus); - return ack; -} - -static -int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len) -{ - unsigned subaddr = *data; - - LOCK_I2C_BUS(decoder->bus); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY); - while (len-- > 0) { - if (i2c_sendbyte(decoder->bus,*data,0)) { - i2c_stop(decoder->bus); - return -EAGAIN; - } - decoder->reg[subaddr++] = *data++; - } - i2c_stop(decoder->bus); - UNLOCK_I2C_BUS(decoder->bus); - - return 0; -} - -static -int saa7110_read(struct saa7110* decoder) -{ - int data; - - LOCK_I2C_BUS(decoder->bus); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); - i2c_start(decoder->bus); - i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY); - data = i2c_readbyte(decoder->bus, 1); - i2c_stop(decoder->bus); - UNLOCK_I2C_BUS(decoder->bus); - return data; -} - -/* ----------------------------------------------------------------------- */ -/* SAA7110 functions */ -/* ----------------------------------------------------------------------- */ -static -int saa7110_selmux(struct i2c_device *device, int chan) -{ -static const unsigned char modes[9][8] = { -/* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, -/* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, -/* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, -/* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, -/* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, -/* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, -/* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, -/* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, -/* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; - struct saa7110* decoder = device->data; - const unsigned char* ptr = modes[chan]; - - saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ - saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */ - saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */ - saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */ - saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */ - saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */ - saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */ - saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */ - - return 0; -} - -static -int determine_norm(struct i2c_device* dev) -{ - struct saa7110* decoder = dev->data; - int status; - - /* mode changed, start automatic detection */ - status = saa7110_read(decoder); - if ((status & 3) == 0) { - saa7110_write(decoder,0x06,0x80); - if (status & 0x20) { - DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); - saa7110_write(decoder,0x2E,0x81); - return VIDEO_MODE_NTSC; - } - DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); - saa7110_write(decoder,0x2E,0x9A); - return VIDEO_MODE_PAL; - } - - saa7110_write(decoder,0x06,0x00); - if (status & 0x20) { /* 60Hz */ - DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); - saa7110_write(decoder,0x0D,0x06); - saa7110_write(decoder,0x11,0x2C); - saa7110_write(decoder,0x2E,0x81); - return VIDEO_MODE_NTSC; - } - - /* 50Hz -> PAL/SECAM */ - saa7110_write(decoder,0x0D,0x06); - saa7110_write(decoder,0x11,0x59); - saa7110_write(decoder,0x2E,0x9A); - - mdelay(150); /* pause 150 ms */ - - status = saa7110_read(decoder); - if ((status & 0x03) == 0x01) { - DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); - saa7110_write(decoder,0x0D,0x07); - return VIDEO_MODE_SECAM; - } - DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); - return VIDEO_MODE_PAL; -} - -static -int saa7110_attach(struct i2c_device *device) -{ -static const unsigned char initseq[] = { - 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, - 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90, - 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, - 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, - 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, - 0x40, 0x75, 0x01, 0x8C, 0x03}; - struct saa7110* decoder; - int rv; - - device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); - if (device->data == 0) - return -ENOMEM; - - MOD_INC_USE_COUNT; - - /* clear our private data */ - memset(decoder, 0, sizeof(struct saa7110)); - strcpy(device->name, "saa7110"); - decoder->bus = device->bus; - decoder->addr = device->addr; - decoder->norm = VIDEO_MODE_PAL; - decoder->input = 0; - decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; - - rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); - if (rv < 0) - printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); - else { - saa7110_write(decoder,0x21,0x16); - saa7110_write(decoder,0x0D,0x04); - DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); - saa7110_write(decoder,0x0D,0x06); - } - - /* setup and implicit mode 0 select has been performed */ - return 0; -} - -static -int saa7110_detach(struct i2c_device *device) -{ - struct saa7110* decoder = device->data; - - DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); - - /* stop further output */ - saa7110_write(decoder,0x0E,0x00); - - kfree(device->data); - - MOD_DEC_USE_COUNT; - return 0; -} - -static -int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) -{ - struct saa7110* decoder = device->data; - int v; - - switch (cmd) { - case DECODER_GET_CAPABILITIES: - { - struct video_decoder_capability *dc = arg; - dc->flags = VIDEO_DECODER_PAL - | VIDEO_DECODER_NTSC - | VIDEO_DECODER_SECAM - | VIDEO_DECODER_AUTO - | VIDEO_DECODER_CCIR; - dc->inputs = SAA7110_MAX_INPUT; - dc->outputs = SAA7110_MAX_OUTPUT; - } - break; - - case DECODER_GET_STATUS: - { - struct saa7110* decoder = device->data; - int status; - int res = 0; - - status = i2c_read(device->bus,device->addr|1); - if (status & 0x40) - res |= DECODER_STATUS_GOOD; - if (status & 0x03) - res |= DECODER_STATUS_COLOR; - - switch (decoder->norm) { - case VIDEO_MODE_NTSC: - res |= DECODER_STATUS_NTSC; - break; - case VIDEO_MODE_PAL: - res |= DECODER_STATUS_PAL; - break; - case VIDEO_MODE_SECAM: - res |= DECODER_STATUS_SECAM; - break; - } - *(int*)arg = res; - } - break; - - case DECODER_SET_NORM: - v = *(int*)arg; - if (decoder->norm != v) { - decoder->norm = v; - saa7110_write(decoder, 0x06, 0x00); - switch (v) { - case VIDEO_MODE_NTSC: - saa7110_write(decoder, 0x0D, 0x06); - saa7110_write(decoder, 0x11, 0x2C); - saa7110_write(decoder, 0x30, 0x81); -saa7110_write(decoder, 0x2A, 0xDF); - break; - case VIDEO_MODE_PAL: - saa7110_write(decoder, 0x0D, 0x06); - saa7110_write(decoder, 0x11, 0x59); - saa7110_write(decoder, 0x2E, 0x9A); - break; - case VIDEO_MODE_SECAM: - saa7110_write(decoder, 0x0D, 0x07); - saa7110_write(decoder, 0x11, 0x59); - saa7110_write(decoder, 0x2E, 0x9A); - break; - case VIDEO_MODE_AUTO: - *(int*)arg = determine_norm(device); - break; - default: - return -EPERM; - } - } - break; - - case DECODER_SET_INPUT: - v = *(int*)arg; - if (v<0 || v>SAA7110_MAX_INPUT) - return -EINVAL; - if (decoder->input != v) { - decoder->input = v; - saa7110_selmux(device, v); - } - break; - - case DECODER_SET_OUTPUT: - v = *(int*)arg; - /* not much choice of outputs */ - if (v != 0) - return -EINVAL; - break; - - case DECODER_ENABLE_OUTPUT: - v = *(int*)arg; - if (decoder->enable != v) { - decoder->enable = v; - saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); - } - break; - - case DECODER_SET_PICTURE: - { - struct video_picture *pic = arg; - - if (decoder->bright != pic->brightness) { - /* We want 0 to 255 we get 0-65535 */ - decoder->bright = pic->brightness; - saa7110_write(decoder, 0x19, decoder->bright >> 8); - } - if (decoder->contrast != pic->contrast) { - /* We want 0 to 127 we get 0-65535 */ - decoder->contrast = pic->contrast; - saa7110_write(decoder, 0x13, decoder->contrast >> 9); - } - if (decoder->sat != pic->colour) { - /* We want 0 to 127 we get 0-65535 */ - decoder->sat = pic->colour; - saa7110_write(decoder, 0x12, decoder->sat >> 9); - } - if (decoder->hue != pic->hue) { - /* We want -128 to 127 we get 0-65535 */ - decoder->hue = pic->hue; - saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); - } - } - break; - - case DECODER_DUMP: - for (v=0; v<34; v+=16) { - int j; - DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); - for (j=0; j<16; j++) { - DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); - } - DEBUG(printk(KERN_INFO "\n")); - } - break; - - default: - DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd)); - return -EINVAL; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -struct i2c_driver i2c_driver_saa7110 = -{ - "saa7110", /* name */ - - I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ - I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ - - saa7110_attach, - saa7110_detach, - saa7110_command -}; - -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -int init_module(void) -#else -int saa7110_init(void) -#endif -{ - return i2c_register_driver(&i2c_driver_saa7110); -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_unregister_driver(&i2c_driver_saa7110); -} -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7111.c linux/drivers/char/saa7111.c --- v2.4.0-test6/linux/drivers/char/saa7111.c Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/saa7111.c Wed Dec 31 16:00:00 1969 @@ -1,418 +0,0 @@ -/* - saa7111 - Philips SAA7111A video decoder driver version 0.0.3 - - Copyright (C) 1998 Dave Perks - - 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#define DEBUG(x) /* Debug driver */ - -/* ----------------------------------------------------------------------- */ - -struct saa7111 { - struct i2c_bus *bus; - int addr; - unsigned char reg[32]; - - int norm; - int input; - int enable; - int bright; - int contrast; - int hue; - int sat; -}; - -#define I2C_SAA7111 0x48 - -#define I2C_DELAY 10 - -/* ----------------------------------------------------------------------- */ - -static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) -{ - int ack; - - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); - dev->reg[subaddr] = data; - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - return ack; -} - -static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) -{ - int ack = 0; - unsigned subaddr; - - while (len > 1) { - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); - len -= 2; - while (len > 1 && *data == ++subaddr) { - data++; - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); - len -= 2; - } - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - } - return ack; -} - -static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) -{ - int data; - - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); - data = i2c_readbyte(dev->bus, 1); - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - return data; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7111_attach(struct i2c_device *device) -{ - int i; - struct saa7111 *decoder; - - static const unsigned char init[] = - { - 0x00, 0x00, /* 00 - ID byte */ - 0x01, 0x00, /* 01 - reserved */ - - /*front end */ - 0x02, 0xd0, /* 02 - FUSE=3, GUDL=2, MODE=0 */ - 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ - 0x04, 0x00, /* 04 - GAI1=256 */ - 0x05, 0x00, /* 05 - GAI2=256 */ - - /* decoder */ - 0x06, 0xf6, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ - 0x07, 0xdd, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ - 0x08, 0xc8, /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */ - 0x09, 0x01, /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */ - 0x0a, 0x80, /* 0a - BRIG=128 */ - 0x0b, 0x47, /* 0b - CONT=1.109 */ - 0x0c, 0x40, /* 0c - SATN=1.0 */ - 0x0d, 0x00, /* 0d - HUE=0 */ - 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */ - 0x0f, 0x00, /* 0f - reserved */ - 0x10, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ - 0x11, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */ - 0x12, 0x00, /* 12 - output control 2 */ - 0x13, 0x00, /* 13 - output control 3 */ - 0x14, 0x00, /* 14 - reserved */ - 0x15, 0x00, /* 15 - VBI */ - 0x16, 0x00, /* 16 - VBI */ - 0x17, 0x00, /* 17 - VBI */ - }; - - device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); - if (decoder == NULL) { - return -ENOMEM; - } - MOD_INC_USE_COUNT; - - memset(decoder, 0, sizeof(struct saa7111)); - strcpy(device->name, "saa7111"); - decoder->bus = device->bus; - decoder->addr = device->addr; - decoder->norm = VIDEO_MODE_NTSC; - decoder->input = 0; - decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; - - i = saa7111_write_block(decoder, init, sizeof(init)); - if (i < 0) { - printk(KERN_ERR "%s_attach: init status %d\n", device->name, i); - } else { - printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00)); - } - return 0; -} - - -static int saa7111_detach(struct i2c_device *device) -{ - kfree(device->data); - MOD_DEC_USE_COUNT; - return 0; -} - -static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg) -{ - struct saa7111 *decoder = device->data; - - switch (cmd) { - -#if defined(DECODER_DUMP) - case DECODER_DUMP: - { - int i; - - for (i = 0; i < 32; i += 16) { - int j; - - printk("KERN_DEBUG %s: %03x", device->name, i); - for (j = 0; j < 16; ++j) { - printk(" %02x", saa7111_read(decoder, i + j)); - } - printk("\n"); - } - } - break; -#endif /* defined(DECODER_DUMP) */ - - case DECODER_GET_CAPABILITIES: - { - struct video_decoder_capability *cap = arg; - - cap->flags - = VIDEO_DECODER_PAL - | VIDEO_DECODER_NTSC - | VIDEO_DECODER_AUTO - | VIDEO_DECODER_CCIR; - cap->inputs = 8; - cap->outputs = 1; - } - break; - - case DECODER_GET_STATUS: - { - int *iarg = arg; - int status; - int res; - - status = saa7111_read(decoder, 0x1f); - res = 0; - if ((status & (1 << 6)) == 0) { - res |= DECODER_STATUS_GOOD; - } - switch (decoder->norm) { - case VIDEO_MODE_NTSC: - res |= DECODER_STATUS_NTSC; - break; - case VIDEO_MODE_PAL: - res |= DECODER_STATUS_PAL; - break; - default: - case VIDEO_MODE_AUTO: - if ((status & (1 << 5)) != 0) { - res |= DECODER_STATUS_NTSC; - } else { - res |= DECODER_STATUS_PAL; - } - break; - } - if ((status & (1 << 0)) != 0) { - res |= DECODER_STATUS_COLOR; - } - *iarg = res; - } - break; - - case DECODER_SET_NORM: - { - int *iarg = arg; - - switch (*iarg) { - - case VIDEO_MODE_NTSC: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); - break; - - case VIDEO_MODE_PAL: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); - break; - - case VIDEO_MODE_AUTO: - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); - break; - - default: - return -EINVAL; - - } - decoder->norm = *iarg; - } - break; - - case DECODER_SET_INPUT: - { - int *iarg = arg; - - if (*iarg < 0 || *iarg > 7) { - return -EINVAL; - } - if (decoder->input != *iarg) { - decoder->input = *iarg; - /* select mode */ - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); - /* bypass chrominance trap for modes 4..7 */ - saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); - } - } - break; - - case DECODER_SET_OUTPUT: - { - int *iarg = arg; - - /* not much choice of outputs */ - if (*iarg != 0) { - return -EINVAL; - } - } - break; - - case DECODER_ENABLE_OUTPUT: - { - int *iarg = arg; - int enable = (*iarg != 0); - - if (decoder->enable != enable) { - decoder->enable = enable; - -// RJ: If output should be disabled (for playing videos), we also need a open PLL. - // The input is set to 0 (where no input source is connected), although this - // is not necessary. - // - // If output should be enabled, we have to reverse the above. - - if (decoder->enable) { - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb)); - saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); - } else { - saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8)); - saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); - saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3)); - } - } - } - break; - - case DECODER_SET_PICTURE: - { - struct video_picture *pic = arg; - - if (decoder->bright != pic->brightness) { - /* We want 0 to 255 we get 0-65535 */ - decoder->bright = pic->brightness; - saa7111_write(decoder, 0x0a, decoder->bright >> 8); - } - if (decoder->contrast != pic->contrast) { - /* We want 0 to 127 we get 0-65535 */ - decoder->contrast = pic->contrast; - saa7111_write(decoder, 0x0b, decoder->contrast >> 9); - } - if (decoder->sat != pic->colour) { - /* We want 0 to 127 we get 0-65535 */ - decoder->sat = pic->colour; - saa7111_write(decoder, 0x0c, decoder->sat >> 9); - } - if (decoder->hue != pic->hue) { - /* We want -128 to 127 we get 0-65535 */ - decoder->hue = pic->hue; - saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8); - } - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -struct i2c_driver i2c_driver_saa7111 = -{ - "saa7111", /* name */ - I2C_DRIVERID_VIDEODECODER, /* ID */ - I2C_SAA7111, I2C_SAA7111 + 1, - - saa7111_attach, - saa7111_detach, - saa7111_command -}; - -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -int init_module(void) -#else -int saa7111_init(void) -#endif -{ - return i2c_register_driver(&i2c_driver_saa7111); -} - - - -#ifdef MODULE - -void cleanup_module(void) -{ - i2c_unregister_driver(&i2c_driver_saa7111); -} - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7121.h linux/drivers/char/saa7121.h --- v2.4.0-test6/linux/drivers/char/saa7121.h Thu Nov 11 20:11:34 1999 +++ linux/drivers/char/saa7121.h Wed Dec 31 16:00:00 1969 @@ -1,132 +0,0 @@ -/* saa7121.h - saa7121 initializations - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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 __SAA7121_H__ -#define __SAA7121_H__ - -#define NTSC_BURST_START 0x19 /* 28 */ -#define NTSC_BURST_END 0x1d /* 29 */ -#define NTSC_CHROMA_PHASE 0x67 /* 5a */ -#define NTSC_GAINU 0x76 /* 5b */ -#define NTSC_GAINV 0xa5 /* 5c */ -#define NTSC_BLACK_LEVEL 0x2a /* 5d */ -#define NTSC_BLANKING_LEVEL 0x2e /* 5e */ -#define NTSC_VBI_BLANKING 0x2e /* 5f */ -#define NTSC_DAC_CONTROL 0x11 /* 61 */ -#define NTSC_BURST_AMP 0x3f /* 62 */ -#define NTSC_SUBC3 0x1f /* 63 */ -#define NTSC_SUBC2 0x7c /* 64 */ -#define NTSC_SUBC1 0xf0 /* 65 */ -#define NTSC_SUBC0 0x21 /* 66 */ -#define NTSC_HTRIG 0x72 /* 6c */ -#define NTSC_VTRIG 0x00 /* 6c */ -#define NTSC_MULTI 0x30 /* 6e */ -#define NTSC_CCTTX 0x11 /* 6f */ -#define NTSC_FIRST_ACTIVE 0x12 /* 7a */ -#define NTSC_LAST_ACTIVE 0x02 /* 7b */ -#define NTSC_MSB_VERTICAL 0x40 /* 7c */ - -#define PAL_BURST_START 0x21 /* 28 */ -#define PAL_BURST_END 0x1d /* 29 */ -#define PAL_CHROMA_PHASE 0x3f /* 5a */ -#define PAL_GAINU 0x7d /* 5b */ -#define PAL_GAINV 0xaf /* 5c */ -#define PAL_BLACK_LEVEL 0x23 /* 5d */ -#define PAL_BLANKING_LEVEL 0x35 /* 5e */ -#define PAL_VBI_BLANKING 0x35 /* 5f */ -#define PAL_DAC_CONTROL 0x02 /* 61 */ -#define PAL_BURST_AMP 0x2f /* 62 */ -#define PAL_SUBC3 0xcb /* 63 */ -#define PAL_SUBC2 0x8a /* 64 */ -#define PAL_SUBC1 0x09 /* 65 */ -#define PAL_SUBC0 0x2a /* 66 */ -#define PAL_HTRIG 0x86 /* 6c */ -#define PAL_VTRIG 0x04 /* 6d */ -#define PAL_MULTI 0x20 /* 6e */ -#define PAL_CCTTX 0x15 /* 6f */ -#define PAL_FIRST_ACTIVE 0x16 /* 7a */ -#define PAL_LAST_ACTIVE 0x36 /* 7b */ -#define PAL_MSB_VERTICAL 0x40 /* 7c */ - -/* Initialization Sequence */ - -static __u8 init7121ntsc[] = { - 0x26, 0x0, 0x27, 0x0, - 0x28, NTSC_BURST_START, 0x29, NTSC_BURST_END, - 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, - 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, - 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, - 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, - 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, - 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, - 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, - 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, - 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, - 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, - 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, - 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, - 0x5a, NTSC_CHROMA_PHASE, 0x5b, NTSC_GAINU, - 0x5c, NTSC_GAINV, 0x5d, NTSC_BLACK_LEVEL, - 0x5e, NTSC_BLANKING_LEVEL, 0x5f, NTSC_VBI_BLANKING, - 0x60, 0x0, 0x61, NTSC_DAC_CONTROL, - 0x62, NTSC_BURST_AMP, 0x63, NTSC_SUBC3, - 0x64, NTSC_SUBC2, 0x65, NTSC_SUBC1, - 0x66, NTSC_SUBC0, 0x67, 0x80, 0x68, 0x80, - 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, - 0x6c, NTSC_HTRIG, 0x6d, NTSC_VTRIG, - 0x6e, NTSC_MULTI, 0x6f, NTSC_CCTTX, - 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, - 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, - 0x78, 0x0, 0x79, 0x0, 0x7a, NTSC_FIRST_ACTIVE, - 0x7b, NTSC_LAST_ACTIVE, 0x7c, NTSC_MSB_VERTICAL, - 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 -}; -#define INIT7121LEN (sizeof(init7121ntsc)/2) - -static __u8 init7121pal[] = { - 0x26, 0x0, 0x27, 0x0, - 0x28, PAL_BURST_START, 0x29, PAL_BURST_END, - 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, - 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, - 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, - 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, - 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, - 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, - 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, - 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, - 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, - 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, - 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, - 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, - 0x5a, PAL_CHROMA_PHASE, 0x5b, PAL_GAINU, - 0x5c, PAL_GAINV, 0x5d, PAL_BLACK_LEVEL, - 0x5e, PAL_BLANKING_LEVEL, 0x5f, PAL_VBI_BLANKING, - 0x60, 0x0, 0x61, PAL_DAC_CONTROL, - 0x62, PAL_BURST_AMP, 0x63, PAL_SUBC3, - 0x64, PAL_SUBC2, 0x65, PAL_SUBC1, - 0x66, PAL_SUBC0, 0x67, 0x80, 0x68, 0x80, - 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, - 0x6c, PAL_HTRIG, 0x6d, PAL_VTRIG, - 0x6e, PAL_MULTI, 0x6f, PAL_CCTTX, - 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, - 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, - 0x78, 0x0, 0x79, 0x0, 0x7a, PAL_FIRST_ACTIVE, - 0x7b, PAL_LAST_ACTIVE, 0x7c, PAL_MSB_VERTICAL, - 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 -}; -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7146.h linux/drivers/char/saa7146.h --- v2.4.0-test6/linux/drivers/char/saa7146.h Thu Nov 11 20:11:34 1999 +++ linux/drivers/char/saa7146.h Wed Dec 31 16:00:00 1969 @@ -1,117 +0,0 @@ -/* - saa7146.h - definitions philips saa7146 based cards - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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 __SAA7146__ -#define __SAA7146__ - -#define SAA7146_VERSION_CODE 0x000101 - -#include -#include - -#include -#include - -#ifndef O_NONCAP -#define O_NONCAP O_TRUNC -#endif - -#define MAX_GBUFFERS 2 -#define FBUF_SIZE 0x190000 - -#ifdef __KERNEL__ - -struct saa7146_window -{ - int x, y; - ushort width, height; - ushort bpp, bpl; - ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; - unsigned long vidadr; - int color_fmt; - ushort depth; -}; - -/* Per-open data for handling multiple opens on one device */ -struct device_open -{ - int isopen; - int noncapturing; - struct saa7146 *dev; -}; -#define MAX_OPENS 3 - -struct saa7146 -{ - struct video_device video_dev; - struct video_picture picture; - struct video_audio audio_dev; - struct video_info vidinfo; - int user; - int cap; - int capuser; - int irqstate; /* irq routine is state driven */ - int writemode; - int playmode; - unsigned int nr; - unsigned long irq; /* IRQ used by SAA7146 card */ - unsigned short id; - struct i2c_bus i2c; - struct pci_dev *dev; - unsigned char revision; - unsigned char boardcfg[64]; /* 64 bytes of config from eeprom */ - unsigned long saa7146_adr; /* bus address of IO mem from PCI BIOS */ - struct saa7146_window win; - unsigned char *saa7146_mem; /* pointer to mapped IO memory */ - struct device_open open_data[MAX_OPENS]; -#define MAX_MARKS 16 - /* for a/v sync */ - int endmark[MAX_MARKS], endmarkhead, endmarktail; - u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2, - *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out, - *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in, - *pagea1out, *pagea2in, *pagea2out; - wait_queue_head_t i2cq, debiq, audq, vidq; - u8 *vidbuf, *audbuf, *osdbuf, *dmadebi; - int audhead, vidhead, osdhead, audtail, vidtail, osdtail; - spinlock_t lock; /* the device lock */ -}; -#endif - -#ifdef _ALPHA_SAA7146 -#define saawrite(dat,adr) writel((dat),(char *) (saa->saa7146_adr+(adr))) -#define saaread(adr) readl(saa->saa7146_adr+(adr)) -#else -#define saawrite(dat,adr) writel((dat), (char *) (saa->saa7146_mem+(adr))) -#define saaread(adr) readl(saa->saa7146_mem+(adr)) -#endif - -#define saaand(dat,adr) saawrite((dat) & saaread(adr), adr) -#define saaor(dat,adr) saawrite((dat) | saaread(adr), adr) -#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr) - -/* bitmask of attached hardware found */ -#define SAA7146_UNKNOWN 0x00000000 -#define SAA7146_SAA7111 0x00000001 -#define SAA7146_SAA7121 0x00000002 -#define SAA7146_IBMMPEG 0x00000004 - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7146reg.h linux/drivers/char/saa7146reg.h --- v2.4.0-test6/linux/drivers/char/saa7146reg.h Thu Nov 11 20:11:34 1999 +++ linux/drivers/char/saa7146reg.h Wed Dec 31 16:00:00 1969 @@ -1,283 +0,0 @@ -/* - saa7146.h - definitions philips saa7146 based cards - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - 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 __SAA7146_REG__ -#define __SAA7146_REG__ -#define SAA7146_BASE_ODD1 0x00 -#define SAA7146_BASE_EVEN1 0x04 -#define SAA7146_PROT_ADDR1 0x08 -#define SAA7146_PITCH1 0x0c -#define SAA7146_PAGE1 0x10 -#define SAA7146_NUM_LINE_BYTE1 0x14 -#define SAA7146_BASE_ODD2 0x18 -#define SAA7146_BASE_EVEN2 0x1c -#define SAA7146_PROT_ADDR2 0x20 -#define SAA7146_PITCH2 0x24 -#define SAA7146_PAGE2 0x28 -#define SAA7146_NUM_LINE_BYTE2 0x2c -#define SAA7146_BASE_ODD3 0x30 -#define SAA7146_BASE_EVEN3 0x34 -#define SAA7146_PROT_ADDR3 0x38 -#define SAA7146_PITCH3 0x3c -#define SAA7146_PAGE3 0x40 -#define SAA7146_NUM_LINE_BYTE3 0x44 -#define SAA7146_PCI_BT_V1 0x48 -#define SAA7146_PCI_BT_V2 0x49 -#define SAA7146_PCI_BT_V3 0x4a -#define SAA7146_PCI_BT_DEBI 0x4b -#define SAA7146_PCI_BT_A 0x4c -#define SAA7146_DD1_INIT 0x50 -#define SAA7146_DD1_STREAM_B 0x54 -#define SAA7146_DD1_STREAM_A 0x56 -#define SAA7146_BRS_CTRL 0x58 -#define SAA7146_HPS_CTRL 0x5c -#define SAA7146_HPS_V_SCALE 0x60 -#define SAA7146_HPS_V_GAIN 0x64 -#define SAA7146_HPS_H_PRESCALE 0x68 -#define SAA7146_HPS_H_SCALE 0x6c -#define SAA7146_BCS_CTRL 0x70 -#define SAA7146_CHROMA_KEY_RANGE 0x74 -#define SAA7146_CLIP_FORMAT_CTRL 0x78 -#define SAA7146_DEBI_CONFIG 0x7c -#define SAA7146_DEBI_COMMAND 0x80 -#define SAA7146_DEBI_PAGE 0x84 -#define SAA7146_DEBI_AD 0x88 -#define SAA7146_I2C_TRANSFER 0x8c -#define SAA7146_I2C_STATUS 0x90 -#define SAA7146_BASE_A1_IN 0x94 -#define SAA7146_PROT_A1_IN 0x98 -#define SAA7146_PAGE_A1_IN 0x9C -#define SAA7146_BASE_A1_OUT 0xa0 -#define SAA7146_PROT_A1_OUT 0xa4 -#define SAA7146_PAGE_A1_OUT 0xa8 -#define SAA7146_BASE_A2_IN 0xac -#define SAA7146_PROT_A2_IN 0xb0 -#define SAA7146_PAGE_A2_IN 0xb4 -#define SAA7146_BASE_A2_OUT 0xb8 -#define SAA7146_PROT_A2_OUT 0xbc -#define SAA7146_PAGE_A2_OUT 0xc0 -#define SAA7146_RPS_PAGE0 0xc4 -#define SAA7146_RPS_PAGE1 0xc8 -#define SAA7146_RPS_THRESH0 0xcc -#define SAA7146_RPS_THRESH1 0xd0 -#define SAA7146_RPS_TOV0 0xd4 -#define SAA7146_RPS_TOV1 0xd8 -#define SAA7146_IER 0xdc -#define SAA7146_GPIO_CTRL 0xe0 -#define SAA7146_EC1SSR 0xe4 -#define SAA7146_EC2SSR 0xe8 -#define SAA7146_ECT1R 0xec -#define SAA7146_ECT2R 0xf0 -#define SAA7146_ACON1 0xf4 -#define SAA7146_ACON2 0xf8 -#define SAA7146_MC1 0xfc -#define SAA7146_MC2 0x100 -#define SAA7146_RPS_ADDR0 0x104 -#define SAA7146_RPS_ADDR1 0x108 -#define SAA7146_ISR 0x10c -#define SAA7146_PSR 0x110 -#define SAA7146_SSR 0x114 -#define SAA7146_EC1R 0x118 -#define SAA7146_EC2R 0x11c -#define SAA7146_VDP1 0x120 -#define SAA7146_VDP2 0x124 -#define SAA7146_VDP3 0x128 -#define SAA7146_ADP1 0x12c -#define SAA7146_ADP2 0x130 -#define SAA7146_ADP3 0x134 -#define SAA7146_ADP4 0x138 -#define SAA7146_DDP 0x13c -#define SAA7146_LEVEL_REP 0x140 -#define SAA7146_FB_BUFFER1 0x144 -#define SAA7146_FB_BUFFER2 0x148 -#define SAA7146_A_TIME_SLOT1 0x180 -#define SAA7146_A_TIME_SLOT2 0x1C0 - -/* bitfield defines */ -#define MASK_31 0x80000000 -#define MASK_30 0x40000000 -#define MASK_29 0x20000000 -#define MASK_28 0x10000000 -#define MASK_27 0x08000000 -#define MASK_26 0x04000000 -#define MASK_25 0x02000000 -#define MASK_24 0x01000000 -#define MASK_23 0x00800000 -#define MASK_22 0x00400000 -#define MASK_21 0x00200000 -#define MASK_20 0x00100000 -#define MASK_19 0x00080000 -#define MASK_18 0x00040000 -#define MASK_17 0x00020000 -#define MASK_16 0x00010000 -#define MASK_15 0x00008000 -#define MASK_14 0x00004000 -#define MASK_13 0x00002000 -#define MASK_12 0x00001000 -#define MASK_11 0x00000800 -#define MASK_10 0x00000400 -#define MASK_09 0x00000200 -#define MASK_08 0x00000100 -#define MASK_07 0x00000080 -#define MASK_06 0x00000040 -#define MASK_05 0x00000020 -#define MASK_04 0x00000010 -#define MASK_03 0x00000008 -#define MASK_02 0x00000004 -#define MASK_01 0x00000002 -#define MASK_00 0x00000001 -#define MASK_B0 0x000000ff -#define MASK_B1 0x0000ff00 -#define MASK_B2 0x00ff0000 -#define MASK_B3 0xff000000 -#define MASK_W0 0x0000ffff -#define MASK_W1 0xffff0000 -#define MASK_PA 0xfffffffc -#define MASK_PR 0xfffffffe -#define MASK_ER 0xffffffff -#define MASK_NONE 0x00000000 - -#define SAA7146_PAGE_MAP_EN MASK_11 -/* main control register 1 */ -#define SAA7146_MC1_MRST_N MASK_15 -#define SAA7146_MC1_ERPS1 MASK_13 -#define SAA7146_MC1_ERPS0 MASK_12 -#define SAA7146_MC1_EDP MASK_11 -#define SAA7146_MC1_EVP MASK_10 -#define SAA7146_MC1_EAP MASK_09 -#define SAA7146_MC1_EI2C MASK_08 -#define SAA7146_MC1_TR_E_DEBI MASK_07 -#define SAA7146_MC1_TR_E_1 MASK_06 -#define SAA7146_MC1_TR_E_2 MASK_05 -#define SAA7146_MC1_TR_E_3 MASK_04 -#define SAA7146_MC1_TR_E_A2_OUT MASK_03 -#define SAA7146_MC1_TR_E_A2_IN MASK_02 -#define SAA7146_MC1_TR_E_A1_OUT MASK_01 -#define SAA7146_MC1_TR_E_A1_IN MASK_00 -/* main control register 2 */ -#define SAA7146_MC2_RPS_SIG4 MASK_15 -#define SAA7146_MC2_RPS_SIG3 MASK_14 -#define SAA7146_MC2_RPS_SIG2 MASK_13 -#define SAA7146_MC2_RPS_SIG1 MASK_12 -#define SAA7146_MC2_RPS_SIG0 MASK_11 -#define SAA7146_MC2_UPLD_D1_B MASK_10 -#define SAA7146_MC2_UPLD_D1_A MASK_09 -#define SAA7146_MC2_UPLD_BRS MASK_08 -#define SAA7146_MC2_UPLD_HPS_H MASK_06 -#define SAA7146_MC2_UPLD_HPS_V MASK_05 -#define SAA7146_MC2_UPLD_DMA3 MASK_04 -#define SAA7146_MC2_UPLD_DMA2 MASK_03 -#define SAA7146_MC2_UPLD_DMA1 MASK_02 -#define SAA7146_MC2_UPLD_DEBI MASK_01 -#define SAA7146_MC2_UPLD_I2C MASK_00 -/* Primary Status Register and Interrupt Enable/Status Registers */ -#define SAA7146_PSR_PPEF MASK_31 -#define SAA7146_PSR_PABO MASK_30 -#define SAA7146_PSR_PPED MASK_29 -#define SAA7146_PSR_RPS_I1 MASK_28 -#define SAA7146_PSR_RPS_I0 MASK_27 -#define SAA7146_PSR_RPS_LATE1 MASK_26 -#define SAA7146_PSR_RPS_LATE0 MASK_25 -#define SAA7146_PSR_RPS_E1 MASK_24 -#define SAA7146_PSR_RPS_E0 MASK_23 -#define SAA7146_PSR_RPS_TO1 MASK_22 -#define SAA7146_PSR_RPS_TO0 MASK_21 -#define SAA7146_PSR_UPLD MASK_20 -#define SAA7146_PSR_DEBI_S MASK_19 -#define SAA7146_PSR_DEBI_E MASK_18 -#define SAA7146_PSR_I2C_S MASK_17 -#define SAA7146_PSR_I2C_E MASK_16 -#define SAA7146_PSR_A2_IN MASK_15 -#define SAA7146_PSR_A2_OUT MASK_14 -#define SAA7146_PSR_A1_IN MASK_13 -#define SAA7146_PSR_A1_OUT MASK_12 -#define SAA7146_PSR_AFOU MASK_11 -#define SAA7146_PSR_V_PE MASK_10 -#define SAA7146_PSR_VFOU MASK_09 -#define SAA7146_PSR_FIDA MASK_08 -#define SAA7146_PSR_FIDB MASK_07 -#define SAA7146_PSR_PIN3 MASK_06 -#define SAA7146_PSR_PIN2 MASK_05 -#define SAA7146_PSR_PIN1 MASK_04 -#define SAA7146_PSR_PIN0 MASK_03 -#define SAA7146_PSR_ECS MASK_02 -#define SAA7146_PSR_EC3S MASK_01 -#define SAA7146_PSR_EC0S MASK_00 -/* Secondary Status Register */ -#define SAA7146_SSR_PRQ MASK_31 -#define SAA7146_SSR_PMA MASK_30 -#define SAA7146_SSR_RPS_RE1 MASK_29 -#define SAA7146_SSR_RPS_PE1 MASK_28 -#define SAA7146_SSR_RPS_A1 MASK_27 -#define SAA7146_SSR_RPS_RE0 MASK_26 -#define SAA7146_SSR_RPS_PE0 MASK_25 -#define SAA7146_SSR_RPS_A0 MASK_24 -#define SAA7146_SSR_DEBI_TO MASK_23 -#define SAA7146_SSR_DEBI_EF MASK_22 -#define SAA7146_SSR_I2C_EA MASK_21 -#define SAA7146_SSR_I2C_EW MASK_20 -#define SAA7146_SSR_I2C_ER MASK_19 -#define SAA7146_SSR_I2C_EL MASK_18 -#define SAA7146_SSR_I2C_EF MASK_17 -#define SAA7146_SSR_V3P MASK_16 -#define SAA7146_SSR_V2P MASK_15 -#define SAA7146_SSR_V1P MASK_14 -#define SAA7146_SSR_VF3 MASK_13 -#define SAA7146_SSR_VF2 MASK_12 -#define SAA7146_SSR_VF1 MASK_11 -#define SAA7146_SSR_AF2_IN MASK_10 -#define SAA7146_SSR_AF2_OUT MASK_09 -#define SAA7146_SSR_AF1_IN MASK_08 -#define SAA7146_SSR_AF1_OUT MASK_07 -#define SAA7146_SSR_VGT MASK_05 -#define SAA7146_SSR_LNQG MASK_04 -#define SAA7146_SSR_EC5S MASK_03 -#define SAA7146_SSR_EC4S MASK_02 -#define SAA7146_SSR_EC2S MASK_01 -#define SAA7146_SSR_EC1S MASK_00 -/* I2C status register */ -#define SAA7146_I2C_ABORT MASK_07 -#define SAA7146_I2C_SPERR MASK_06 -#define SAA7146_I2C_APERR MASK_05 -#define SAA7146_I2C_DTERR MASK_04 -#define SAA7146_I2C_DRERR MASK_03 -#define SAA7146_I2C_AL MASK_02 -#define SAA7146_I2C_ERR MASK_01 -#define SAA7146_I2C_BUSY MASK_00 -/* output formats */ -#define SAA7146_YUV422 0 -#define SAA7146_RGB16 0 -#define SAA7146_YUV444 1 -#define SAA7146_RGB24 1 -#define SAA7146_ARGB32 2 -#define SAA7146_YUV411 3 -#define SAA7146_ARGB15 3 -#define SAA7146_YUV2 4 -#define SAA7146_RGAB15 4 -#define SAA7146_Y8 6 -#define SAA7146_YUV8 7 -#define SAA7146_RGB8 7 -#define SAA7146_YUV444p 8 -#define SAA7146_YUV422p 9 -#define SAA7146_YUV420p 10 -#define SAA7146_YUV1620 11 -#define SAA7146_Y1 13 -#define SAA7146_Y2 14 -#define SAA7146_YUV1 15 -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7185.c linux/drivers/char/saa7185.c --- v2.4.0-test6/linux/drivers/char/saa7185.c Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/saa7185.c Wed Dec 31 16:00:00 1969 @@ -1,377 +0,0 @@ -/* - saa7185 - Philips SAA7185B video encoder driver version 0.0.3 - - Copyright (C) 1998 Dave Perks - - 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#define DEBUG(x) x /* Debug driver */ - -/* ----------------------------------------------------------------------- */ - -struct saa7185 { - struct i2c_bus *bus; - int addr; - unsigned char reg[128]; - - int norm; - int enable; - int bright; - int contrast; - int hue; - int sat; -}; - -#define I2C_SAA7185 0x88 - -#define I2C_DELAY 10 - -/* ----------------------------------------------------------------------- */ - -static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) -{ - int ack; - - LOCK_I2C_BUS(dev->bus); - - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); - dev->reg[subaddr] = data; - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - return ack; -} - -static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) -{ - int ack = 0; - unsigned subaddr; - - while (len > 1) { - LOCK_I2C_BUS(dev->bus); - i2c_start(dev->bus); - i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); - ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); - len -= 2; - while (len > 1 && *data == ++subaddr) { - data++; - ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); - len -= 2; - } - i2c_stop(dev->bus); - UNLOCK_I2C_BUS(dev->bus); - } - return ack; -} - -/* ----------------------------------------------------------------------- */ - -static const unsigned char init_common[] = -{ - 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */ - - 0x42, 0x6b, /* OVLY0=107 */ - 0x43, 0x00, /* OVLU0=0 white */ - 0x44, 0x00, /* OVLV0=0 */ - 0x45, 0x22, /* OVLY1=34 */ - 0x46, 0xac, /* OVLU1=172 yellow */ - 0x47, 0x0e, /* OVLV1=14 */ - 0x48, 0x03, /* OVLY2=3 */ - 0x49, 0x1d, /* OVLU2=29 cyan */ - 0x4a, 0xac, /* OVLV2=172 */ - 0x4b, 0xf0, /* OVLY3=240 */ - 0x4c, 0xc8, /* OVLU3=200 green */ - 0x4d, 0xb9, /* OVLV3=185 */ - 0x4e, 0xd4, /* OVLY4=212 */ - 0x4f, 0x38, /* OVLU4=56 magenta */ - 0x50, 0x47, /* OVLV4=71 */ - 0x51, 0xc1, /* OVLY5=193 */ - 0x52, 0xe3, /* OVLU5=227 red */ - 0x53, 0x54, /* OVLV5=84 */ - 0x54, 0xa3, /* OVLY6=163 */ - 0x55, 0x54, /* OVLU6=84 blue */ - 0x56, 0xf2, /* OVLV6=242 */ - 0x57, 0x90, /* OVLY7=144 */ - 0x58, 0x00, /* OVLU7=0 black */ - 0x59, 0x00, /* OVLV7=0 */ - - 0x5a, 0x00, /* CHPS=0 */ - 0x5b, 0x76, /* GAINU=118 */ - 0x5c, 0xa5, /* GAINV=165 */ - 0x5d, 0x3c, /* BLCKL=60 */ - 0x5e, 0x3a, /* BLNNL=58 */ - 0x5f, 0x3a, /* CCRS=0, BLNVB=58 */ - 0x60, 0x00, /* NULL */ - -/* 0x61 - 0x66 set according to norm */ - - 0x67, 0x00, /* 0 : caption 1st byte odd field */ - 0x68, 0x00, /* 0 : caption 2nd byte odd field */ - 0x69, 0x00, /* 0 : caption 1st byte even field */ - 0x6a, 0x00, /* 0 : caption 2nd byte even field */ - - 0x6b, 0x91, /* MODIN=2, PCREF=0, SCCLN=17 */ - 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */ - 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ - - 0x6e, 0x0e, /* HTRIG=0x00e, approx. centered, at least for PAL */ - 0x6f, 0x00, /* HTRIG upper bits */ - 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ - -/* The following should not be needed */ - - 0x71, 0x15, /* BMRQ=0x115 */ - 0x72, 0x90, /* EMRQ=0x690 */ - 0x73, 0x61, /* EMRQ=0x690, BMRQ=0x115 */ - 0x74, 0x00, /* NULL */ - 0x75, 0x00, /* NULL */ - 0x76, 0x00, /* NULL */ - 0x77, 0x15, /* BRCV=0x115 */ - 0x78, 0x90, /* ERCV=0x690 */ - 0x79, 0x61, /* ERCV=0x690, BRCV=0x115 */ - -/* Field length controls */ - - 0x7a, 0x70, /* FLC=0 */ - -/* The following should not be needed if SBLN = 1 */ - - 0x7b, 0x16, /* FAL=22 */ - 0x7c, 0x35, /* LAL=244 */ - 0x7d, 0x20, /* LAL=244, FAL=22 */ -}; - -static const unsigned char init_pal[] = -{ - 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ - 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ - 0x63, 0xcb, /* FSC0 */ - 0x64, 0x8a, /* FSC1 */ - 0x65, 0x09, /* FSC2 */ - 0x66, 0x2a, /* FSC3 */ -}; - -static const unsigned char init_ntsc[] = -{ - 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ - 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ - 0x63, 0x1f, /* FSC0 */ - 0x64, 0x7c, /* FSC1 */ - 0x65, 0xf0, /* FSC2 */ - 0x66, 0x21, /* FSC3 */ -}; - -static int saa7185_attach(struct i2c_device *device) -{ - int i; - struct saa7185 *encoder; - - device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); - if (encoder == NULL) { - return -ENOMEM; - } - MOD_INC_USE_COUNT; - - memset(encoder, 0, sizeof(struct saa7185)); - strcpy(device->name, "saa7185"); - encoder->bus = device->bus; - encoder->addr = device->addr; - encoder->norm = VIDEO_MODE_NTSC; - encoder->enable = 1; - - i = saa7185_write_block(encoder, init_common, sizeof(init_common)); - if (i >= 0) { - i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); - } - if (i < 0) { - printk(KERN_ERR "%s_attach: init error %d\n", device->name, i); - } - return 0; -} - - -static int saa7185_detach(struct i2c_device *device) -{ - kfree(device->data); - MOD_DEC_USE_COUNT; - return 0; -} - -static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg) -{ - struct saa7185 *encoder = device->data; - - switch (cmd) { - - case ENCODER_GET_CAPABILITIES: - { - struct video_encoder_capability *cap = arg; - - cap->flags - = VIDEO_ENCODER_PAL - | VIDEO_ENCODER_NTSC - | VIDEO_ENCODER_SECAM - | VIDEO_ENCODER_CCIR; - cap->inputs = 1; - cap->outputs = 1; - } - break; - - case ENCODER_SET_NORM: - { - int *iarg = arg; - - switch (*iarg) { - - case VIDEO_MODE_NTSC: - saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); - break; - - case VIDEO_MODE_PAL: - saa7185_write_block(encoder, init_pal, sizeof(init_pal)); - break; - - case VIDEO_MODE_SECAM: - default: - return -EINVAL; - - } - encoder->norm = *iarg; - } - break; - - case ENCODER_SET_INPUT: - { - int *iarg = arg; - -#if 0 - /* not much choice of inputs */ - if (*iarg != 0) { - return -EINVAL; - } -#else - /* RJ: *iarg = 0: input is from SA7111 - *iarg = 1: input is from ZR36060 */ - - switch (*iarg) { - - case 0: - /* Switch RTCE to 1 */ - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); - break; - - case 1: - /* Switch RTCE to 0 */ - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); - break; - - default: - return -EINVAL; - - } -#endif - } - break; - - case ENCODER_SET_OUTPUT: - { - int *iarg = arg; - - /* not much choice of outputs */ - if (*iarg != 0) { - return -EINVAL; - } - } - break; - - case ENCODER_ENABLE_OUTPUT: - { - int *iarg = arg; - - encoder->enable = !!*iarg; - saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40)); - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -struct i2c_driver i2c_driver_saa7185 = -{ - "saa7185", /* name */ - I2C_DRIVERID_VIDEOENCODER, /* ID */ - I2C_SAA7185, I2C_SAA7185 + 1, - - saa7185_attach, - saa7185_detach, - saa7185_command -}; - -EXPORT_NO_SYMBOLS; - -#ifdef MODULE -int init_module(void) -#else -int saa7185_init(void) -#endif -{ - return i2c_register_driver(&i2c_driver_saa7185); -} - - - -#ifdef MODULE - -void cleanup_module(void) -{ - i2c_unregister_driver(&i2c_driver_saa7185); -} - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/saa7196.h linux/drivers/char/saa7196.h --- v2.4.0-test6/linux/drivers/char/saa7196.h Fri May 7 11:05:30 1999 +++ linux/drivers/char/saa7196.h Wed Dec 31 16:00:00 1969 @@ -1,117 +0,0 @@ -/* - Definitions for the Philips SAA7196 digital video decoder, - scaler, and clock generator circuit (DESCpro), as used in - the PlanB video input of the Powermac 7x00/8x00 series. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - The register defines are shamelessly copied from the meteor - driver out of NetBSD (with permission), - and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe - (Thanks !) - - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) - - The default values used for PlanB are my mistakes. -*/ - -/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */ - -#ifndef _SAA7196_H_ -#define _SAA7196_H_ - -#define SAA7196_NUMREGS 0x31 /* Number of registers (used)*/ -#define NUM_SUPPORTED_NORM 3 /* Number of supported norms by PlanB */ - -/* Decoder part: */ -#define SAA7196_IDEL 0x00 /* Increment delay */ -#define SAA7196_HSB5 0x01 /* H-sync begin; 50 hz */ -#define SAA7196_HSS5 0x02 /* H-sync stop; 50 hz */ -#define SAA7196_HCB5 0x03 /* H-clamp begin; 50 hz */ -#define SAA7196_HCS5 0x04 /* H-clamp stop; 50 hz */ -#define SAA7196_HSP5 0x05 /* H-sync after PHI1; 50 hz */ -#define SAA7196_LUMC 0x06 /* Luminance control */ -#define SAA7196_HUEC 0x07 /* Hue control */ -#define SAA7196_CKTQ 0x08 /* Colour Killer Threshold QAM (PAL, NTSC) */ -#define SAA7196_CKTS 0x09 /* Colour Killer Threshold SECAM */ -#define SAA7196_PALS 0x0a /* PAL switch sensitivity */ -#define SAA7196_SECAMS 0x0b /* SECAM switch sensitivity */ -#define SAA7196_CGAINC 0x0c /* Chroma gain control */ -#define SAA7196_STDC 0x0d /* Standard/Mode control */ -#define SAA7196_IOCC 0x0e /* I/O and Clock Control */ -#define SAA7196_CTRL1 0x0f /* Control #1 */ -#define SAA7196_CTRL2 0x10 /* Control #2 */ -#define SAA7196_CGAINR 0x11 /* Chroma Gain Reference */ -#define SAA7196_CSAT 0x12 /* Chroma Saturation */ -#define SAA7196_CONT 0x13 /* Luminance Contrast */ -#define SAA7196_HSB6 0x14 /* H-sync begin; 60 hz */ -#define SAA7196_HSS6 0x15 /* H-sync stop; 60 hz */ -#define SAA7196_HCB6 0x16 /* H-clamp begin; 60 hz */ -#define SAA7196_HCS6 0x17 /* H-clamp stop; 60 hz */ -#define SAA7196_HSP6 0x18 /* H-sync after PHI1; 60 hz */ -#define SAA7196_BRIG 0x19 /* Luminance Brightness */ - -/* Scaler part: */ -#define SAA7196_FMTS 0x20 /* Formats and sequence */ -#define SAA7196_OUTPIX 0x21 /* Output data pixel/line */ -#define SAA7196_INPIX 0x22 /* Input data pixel/line */ -#define SAA7196_HWS 0x23 /* Horiz. window start */ -#define SAA7196_HFILT 0x24 /* Horiz. filter */ -#define SAA7196_OUTLINE 0x25 /* Output data lines/field */ -#define SAA7196_INLINE 0x26 /* Input data lines/field */ -#define SAA7196_VWS 0x27 /* Vertical window start */ -#define SAA7196_VYP 0x28 /* AFS/vertical Y processing */ -#define SAA7196_VBS 0x29 /* Vertical Bypass start */ -#define SAA7196_VBCNT 0x2a /* Vertical Bypass count */ -#define SAA7196_VBP 0x2b /* veritcal Bypass Polarity */ -#define SAA7196_VLOW 0x2c /* Colour-keying lower V limit */ -#define SAA7196_VHIGH 0x2d /* Colour-keying upper V limit */ -#define SAA7196_ULOW 0x2e /* Colour-keying lower U limit */ -#define SAA7196_UHIGH 0x2f /* Colour-keying upper U limit */ -#define SAA7196_DPATH 0x30 /* Data path setting */ - -/* Initialization default values: */ - -unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = { - -/* PAL, 768x576 (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, - 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98, - 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0xa2, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 }, - -/* NTSC, 640x480? (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00, - 0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98, - 0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0x98, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d, - 0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 }, - -/* SECAM, 768x576 (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, - 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98, - 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0xa2, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 } - }; - -#endif /* _SAA7196_H_ */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/scan_keyb.c linux/drivers/char/scan_keyb.c --- v2.4.0-test6/linux/drivers/char/scan_keyb.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/scan_keyb.c Fri Aug 11 15:57:57 2000 @@ -82,18 +82,21 @@ { struct scan_keyboard *kbd; - if((kbd=kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL))==NULL) + kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL); + if (kbd == NULL) goto error_out; kbd->scan=scan; kbd->table=table; kbd->length=length; - kbd->s0=kbd->s1=NULL; - if((kbd->s0=kmalloc(length, GFP_KERNEL))==NULL) - goto error_mem_free; - if((kbd->s1=kmalloc(length, GFP_KERNEL))==NULL) - goto error_mem_free; + kbd->s0 = kmalloc(length, GFP_KERNEL); + if (kbd->s0 == NULL) + goto error_free_kbd; + + kbd->s1 = kmalloc(length, GFP_KERNEL); + if (kbd->s1 == NULL) + goto error_free_s0; kbd->scan(kbd->s0); kbd->scan(kbd->s1); @@ -103,11 +106,10 @@ return 0; - error_mem_free: - if(kbd->s0) - kfree(kbd->s0); - if(kbd->s1) - kfree(kbd->s1); + error_free_s0: + kfree(kbd->s0); + + error_free_kbd: kfree(kbd); error_out: diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.0-test6/linux/drivers/char/serial.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/serial.c Sun Aug 13 10:17:16 2000 @@ -51,13 +51,16 @@ * * 7/00: Support Timedia/Sunix/Exsys PCI cards * + * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT. + * Arnaldo Carvalho de Melo + * * This module exports the following rs232 io functions: * * int rs_init(void); */ -static char *serial_version = "5.01"; -static char *serial_revdate = "2000-05-29"; +static char *serial_version = "5.02"; +static char *serial_revdate = "2000-08-09"; /* * Serial driver configuration section. Here are the various options: @@ -142,6 +145,10 @@ #endif #endif +#ifdef MODULE +#undef CONFIG_SERIAL_CONSOLE +#endif + #define CONFIG_SERIAL_RSA #define RS_STROBE_TIME (10*HZ) @@ -260,8 +267,9 @@ static int IRQ_timeout[NR_IRQS]; #ifdef CONFIG_SERIAL_CONSOLE static struct console sercons; +static int lsr_break_flag = 0; #endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) static unsigned long break_pressed; /* break, really ... */ #endif @@ -281,7 +289,7 @@ { "16550", 1, 0 }, { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, { "cirrus", 1, 0 }, /* usurped by cyclades.c */ - { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, @@ -302,7 +310,9 @@ static int force_rsa[PORT_RSA_MAX]; MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); #endif /* CONFIG_SERIAL_RSA */ static struct serial_state rs_table[RS_TABLE_SIZE] = { @@ -313,7 +323,7 @@ #if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) #define NR_PCI_BOARDS 8 -/* We don't unregister PCI boards right now */ + static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; static int serial_pci_board_idx = 0; @@ -573,6 +583,23 @@ if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); icount->brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + goto ignore_char; + } + break_pressed = 0; + } +#endif + if (info->flags & ASYNC_SAK) + do_SAK(tty); } else if (*status & UART_LSR_PE) icount->parity++; else if (*status & UART_LSR_FE) @@ -591,23 +618,19 @@ goto ignore_char; } *status &= info->read_status_mask; - + +#ifdef CONFIG_SERIAL_CONSOLE + if (info->line == sercons.index) { + /* Recover the break flag from console xmit */ + *status |= lsr_break_flag; + lsr_break_flag = 0; + } +#endif if (*status & (UART_LSR_BI)) { #ifdef SERIAL_DEBUG_INTR printk("handling break...."); #endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) - if (info->line == sercons.index) { - if (!break_pressed) { - break_pressed = jiffies; - goto ignore_char; - } - break_pressed = 0; - } -#endif *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); } else if (*status & UART_LSR_PE) *tty->flip.flag_buf_ptr = TTY_PARITY; else if (*status & UART_LSR_FE) @@ -626,7 +649,7 @@ goto ignore_char; } } -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { @@ -1076,7 +1099,7 @@ #endif restore_flags(flags); - mod_timer(&serial_timer, jiffies + IRQ_timeout[0] - 2); + mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); } } @@ -1111,7 +1134,7 @@ } if (!irq) timeout = timeout / 2; - IRQ_timeout[irq] = timeout ? timeout : 1; + IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1; } #ifdef CONFIG_SERIAL_RSA @@ -2077,7 +2100,7 @@ new_serial.irq = irq_cannonicalize(new_serial.irq); - if ((new_serial.irq >= NR_IRQS) || + if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || (new_serial.type == PORT_STARTECH)) { @@ -2310,7 +2333,7 @@ static int do_autoconfig(struct async_struct * info) { - int retval; + int irq, retval; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -2323,8 +2346,11 @@ autoconfig(info->state); if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0) && - (info->state->type != PORT_UNKNOWN)) - info->state->irq = detect_uart_irq(info->state); + (info->state->type != PORT_UNKNOWN)) { + irq = detect_uart_irq(info->state); + if (irq > 0) + info->state->irq = irq; + } retval = startup(info); if (retval) @@ -3111,8 +3137,10 @@ } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) + if (serial_paranoia_check(info, tty->device, "rs_open")) { + MOD_DEC_USE_COUNT; return -ENODEV; + } #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -3125,6 +3153,7 @@ if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); if (!page) { + MOD_DEC_USE_COUNT; return -ENOMEM; } if (tmp_buf) @@ -3140,6 +3169,7 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); + MOD_DEC_USE_COUNT; #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -3153,6 +3183,7 @@ */ retval = startup(info); if (retval) { + MOD_DEC_USE_COUNT; return retval; } @@ -3162,6 +3193,7 @@ printk("rs_open returning after block_til_ready with %d\n", retval); #endif + MOD_DEC_USE_COUNT; return retval; } @@ -3486,6 +3518,7 @@ * (Exoray@isys.ca) claims that it's needed for 952 * dual UART's (which are not recommended for new designs). */ + info->ACR = 0; serial_out(info, UART_LCR, 0xBF); serial_out(info, UART_EFR, 0x10); serial_out(info, UART_LCR, 0x00); @@ -3804,10 +3837,11 @@ if (idx >= max_port) return 1; } - + offset = board->first_uart_offset; /* Timedia/SUNIX uses a mixture of BARs and offsets */ + /* Ugh, this is ugly as all hell --- TYT */ if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ switch(idx) { case 0: base_idx=0; @@ -4090,6 +4124,62 @@ return(0); } +/* + * Timedia has an explosion of boards, and to avoid the PCI table from + * growing *huge*, we use this function to collapse some 70 entries + * in the PCI table into one, for sanity's and compactness's sake. + */ +static unsigned short timedia_single_port[] = { + 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 }; +static unsigned short timedia_dual_port[] = { + 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, + 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, + 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, + 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, + 0xD079, 0 }; +static unsigned short timedia_quad_port[] = { + 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, + 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, + 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, + 0xB157, 0 }; +static unsigned short timedia_eight_port[] = { + 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, + 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; +static struct timedia_struct { + int num; + unsigned short *ids; +} timedia_data[] = { + { 1, timedia_single_port }, + { 2, timedia_dual_port }, + { 4, timedia_quad_port }, + { 8, timedia_eight_port }, + { 0, 0 } +}; + +static int +#ifndef MODULE +__init +#endif +pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + int i, j; + unsigned short *ids; + + if (!enable) + return 0; + + for (i=0; timedia_data[i].num; i++) { + ids = timedia_data[i].ids; + for (j=0; ids[j]; j++) { + if (pci_get_subvendor(dev) == ids[j]) { + board->num_ports = timedia_data[i].num; + return 0; + } + } + } + return 0; +} + /* * This is the configuration table for all of the PCI serial boards @@ -4116,58 +4206,50 @@ PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, SPCI_FL_BASE1, 2, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, SPCI_FL_BASE1, 8, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, SPCI_FL_BASE1, 4, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, SPCI_FL_BASE1, 2, 1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, SPCI_FL_BASE1, 2, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, SPCI_FL_BASE1, 8, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, - SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, SPCI_FL_BASE1, 4, 921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, - SPCI_FL_BASE1, 2, 921600 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, @@ -4196,6 +4278,9 @@ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2, 8, 921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 4, 921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2, @@ -4265,75 +4350,10 @@ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, - /* PCI_VENDOR_ID_TIMEDIA/Sunix, PCI_DEVICE_ID_TIMEDIA_1889, */ - { 0x1409, 0x7168, 0x1409, 0x0002, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4036A*/ - { 0x1409, 0x7168, 0x1409, 0x4025, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4025A*/ - { 0x1409, 0x7168, 0x1409, 0x4027, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4027A*/ - { 0x1409, 0x7168, 0x1409, 0x4028, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4028D*/ - { 0x1409, 0x7168, 0x1409, 0x4036, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4036D*/ - { 0x1409, 0x7168, 0x1409, 0x4037, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4037A*/ - { 0x1409, 0x7168, 0x1409, 0x4038, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4038D*/ - { 0x1409, 0x7168, 0x1409, 0x4055, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4055A*/ - { 0x1409, 0x7168, 0x1409, 0x4056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4056A*/ - { 0x1409, 0x7168, 0x1409, 0x4065, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4065A*/ - { 0x1409, 0x7168, 0x1409, 0x4066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4066A*/ - { 0x1409, 0x7168, 0x1409, 0x4078, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4078A*/ - { 0x1409, 0x7168, 0x1409, 0x4079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079H*/ - { 0x1409, 0x7168, 0x1409, 0x4085, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4085H*/ - { 0x1409, 0x7168, 0x1409, 0x4088, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4088A*/ - { 0x1409, 0x7168, 0x1409, 0x4089, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4089A*/ - { 0x1409, 0x7168, 0x1409, 0x4095, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4095A*/ - { 0x1409, 0x7168, 0x1409, 0x4096, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4096A*/ - { 0x1409, 0x7168, 0x1409, 0x5025, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4025D*/ - { 0x1409, 0x7168, 0x1409, 0x5027, SPCI_FL_BASE_TABLE, 1, 921600 }, /*4027D*/ - { 0x1409, 0x7168, 0x1409, 0x5037, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4037D*/ - { 0x1409, 0x7168, 0x1409, 0x5056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*4056R*/ - { 0x1409, 0x7168, 0x1409, 0x5065, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4065R*/ - { 0x1409, 0x7168, 0x1409, 0x5066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*4066R*/ - { 0x1409, 0x7168, 0x1409, 0x5078, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4078U*/ - { 0x1409, 0x7168, 0x1409, 0x5079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079A*/ - { 0x1409, 0x7168, 0x1409, 0x5085, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4085U*/ - { 0x1409, 0x7168, 0x1409, 0x6079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079R*/ - { 0x1409, 0x7168, 0x1409, 0x7079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079S*/ - { 0x1409, 0x7168, 0x1409, 0x8079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079D*/ - { 0x1409, 0x7168, 0x1409, 0x8137, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8137*/ - { 0x1409, 0x7168, 0x1409, 0x8138, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8138*/ - { 0x1409, 0x7168, 0x1409, 0x8156, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8156*/ - { 0x1409, 0x7168, 0x1409, 0x8157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8157*/ - { 0x1409, 0x7168, 0x1409, 0x8166, SPCI_FL_BASE_TABLE, 8, 921600 }, /*8166*/ - { 0x1409, 0x7168, 0x1409, 0x8237, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8237*/ - { 0x1409, 0x7168, 0x1409, 0x8238, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8238*/ - { 0x1409, 0x7168, 0x1409, 0x8256, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8256*/ - { 0x1409, 0x7168, 0x1409, 0x8257, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8257*/ - { 0x1409, 0x7168, 0x1409, 0x9056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9056A*/ - { 0x1409, 0x7168, 0x1409, 0x9066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9066A*/ - { 0x1409, 0x7168, 0x1409, 0x9079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079E*/ - { 0x1409, 0x7168, 0x1409, 0x9137, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8137S*/ - { 0x1409, 0x7168, 0x1409, 0x9138, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8138S*/ - { 0x1409, 0x7168, 0x1409, 0x9156, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8156S*/ - { 0x1409, 0x7168, 0x1409, 0x9157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8157S*/ - { 0x1409, 0x7168, 0x1409, 0x9158, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9158*/ - { 0x1409, 0x7168, 0x1409, 0x9159, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9159*/ - { 0x1409, 0x7168, 0x1409, 0x9166, SPCI_FL_BASE_TABLE, 8, 921600 }, /*8166S*/ - { 0x1409, 0x7168, 0x1409, 0x9167, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9167*/ - { 0x1409, 0x7168, 0x1409, 0x9168, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9168*/ - { 0x1409, 0x7168, 0x1409, 0x9237, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8237S*/ - { 0x1409, 0x7168, 0x1409, 0x9238, SPCI_FL_BASE_TABLE, 2, 921600 }, /*8238S*/ - { 0x1409, 0x7168, 0x1409, 0x9256, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8256S*/ - { 0x1409, 0x7168, 0x1409, 0x9257, SPCI_FL_BASE_TABLE, 4, 921600 }, /*8257S*/ - { 0x1409, 0x7168, 0x1409, 0xA056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9056B*/ - { 0x1409, 0x7168, 0x1409, 0xA066, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9066B*/ - { 0x1409, 0x7168, 0x1409, 0xA079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*4079F*/ - { 0x1409, 0x7168, 0x1409, 0xA157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9157*/ - { 0x1409, 0x7168, 0x1409, 0xA158, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9158S*/ - { 0x1409, 0x7168, 0x1409, 0xA159, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9159S*/ - { 0x1409, 0x7168, 0x1409, 0xA167, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9167S*/ - { 0x1409, 0x7168, 0x1409, 0xA168, SPCI_FL_BASE_TABLE, 8, 921600 }, /*9168S*/ - { 0x1409, 0x7168, 0x1409, 0xB056, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9056C*/ - { 0x1409, 0x7168, 0x1409, 0xB079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*9079A*/ - { 0x1409, 0x7168, 0x1409, 0xB157, SPCI_FL_BASE_TABLE, 4, 921600 }, /*9157S*/ - { 0x1409, 0x7168, 0x1409, 0xC079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*9079B*/ - { 0x1409, 0x7168, 0x1409, 0xD079, SPCI_FL_BASE_TABLE, 2, 921600 }, /*9079C*/ + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, + SPCI_FL_BASE_TABLE, 1, 921600, + 0, 0, pci_timedia_fn }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, @@ -4540,7 +4560,7 @@ { PCI_VENDOR_ID_ROCKWELL, 0x1004, 0x1048, 0x1500, SPCI_FL_BASE1, 1, 115200 }, -#ifdef CONFIG_DDB5074 +#if CONFIG_DDB5074 /* * NEC Vrc-5074 (Nile 4) builtin UART. * Conditionally compiled in since this is a motherboard device. @@ -4580,7 +4600,7 @@ for (i=0; i < 6; i++) { if (IS_PCI_REGION_IOPORT(dev, i)) { - num_port = 0; + num_port++; if (first_port == -1) first_port = i; } else { @@ -5077,16 +5097,6 @@ int i; struct serial_state * state; - if (serial_timer.function) { - printk("RS_TIMER already set, another serial driver " - "already loaded?\n"); -#ifdef MODULE - printk("Can't load serial driver module over built-in " - "serial driver\n"); -#endif - return -EBUSY; - } - init_bh(SERIAL_BH, do_serial_bh); init_timer(&serial_timer); serial_timer.function = rs_timer; @@ -5419,6 +5429,8 @@ module_init(rs_init); module_exit(rs_fini); +MODULE_DESCRIPTION("Standard/generic (dumb) serial driver"); +MODULE_AUTHOR("Theodore Ts'o "); /* @@ -5437,10 +5449,17 @@ */ static inline void wait_for_xmitr(struct async_struct *info) { - unsigned int tmout = 1000000; + unsigned int status, tmout = 1000000; + + do { + status = serial_in(info, UART_LSR); - while (--tmout && - ((serial_in(info, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)); + if (status & UART_LSR_BI) + lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + } while((status & BOTH_EMPTY) != BOTH_EMPTY); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/serial_21285.c linux/drivers/char/serial_21285.c --- v2.4.0-test6/linux/drivers/char/serial_21285.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/serial_21285.c Sun Aug 13 10:04:17 2000 @@ -0,0 +1,511 @@ +/* + * linux/drivers/char/serial_21285.c + * + * Driver for the serial port on the 21285 StrongArm-110 core logic chip. + * + * Based on drivers/char/serial.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define BAUD_BASE (mem_fclk_21285/64) + +#define SERIAL_21285_NAME "ttyFB" +#define SERIAL_21285_MAJOR 204 +#define SERIAL_21285_MINOR 4 + +#define SERIAL_21285_AUXNAME "cuafb" +#define SERIAL_21285_AUXMAJOR 205 +#define SERIAL_21285_AUXMINOR 4 + +static struct tty_driver rs285_driver, callout_driver; +static int rs285_refcount; +static struct tty_struct *rs285_table[1]; + +static struct termios *rs285_termios[1]; +static struct termios *rs285_termios_locked[1]; + +static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; +static struct tty_struct *rs285_tty; +static int rs285_use_count; + +static int rs285_write_room(struct tty_struct *tty) +{ + return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1); +} + +static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + if (!rs285_tty) { + disable_irq(IRQ_CONRX); + return; + } + while (!(*CSR_UARTFLG & 0x10)) { + int ch, flag; + ch = *CSR_UARTDR; + flag = *CSR_RXSTAT; + if (flag & 4) + tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN); + if (flag & 2) + flag = TTY_PARITY; + else if (flag & 1) + flag = TTY_FRAME; + tty_insert_flip_char(rs285_tty, ch, flag); + } + tty_flip_buffer_push(rs285_tty); +} + +static void rs285_send_xchar(struct tty_struct *tty, char ch) +{ + x_char = ch; + enable_irq(IRQ_CONTX); +} + +static void rs285_throttle(struct tty_struct *tty) +{ + if (I_IXOFF(tty)) + rs285_send_xchar(tty, STOP_CHAR(tty)); +} + +static void rs285_unthrottle(struct tty_struct *tty) +{ + if (I_IXOFF(tty)) { + if (x_char) + x_char = 0; + else + rs285_send_xchar(tty, START_CHAR(tty)); + } +} + +static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs) +{ + while (!(*CSR_UARTFLG & 0x20)) { + if (x_char) { + *CSR_UARTDR = x_char; + x_char = 0; + continue; + } + if (putp == getp) { + disable_irq(IRQ_CONTX); + break; + } + *CSR_UARTDR = *getp; + if (++getp >= wbuf + sizeof(wbuf)) + getp = wbuf; + } + if (rs285_tty) + wake_up_interruptible(&rs285_tty->write_wait); +} + +static inline int rs285_xmit(int ch) +{ + if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf)) + return 0; + *putp = ch; + if (++putp >= wbuf + sizeof(wbuf)) + putp = wbuf; + enable_irq(IRQ_CONTX); + return 1; +} + +static int rs285_write(struct tty_struct *tty, int from_user, + const u_char * buf, int count) +{ + int i; + + if (from_user && verify_area(VERIFY_READ, buf, count)) + return -EINVAL; + + for (i = 0; i < count; i++) { + char ch; + if (from_user) + __get_user(ch, buf + i); + else + ch = buf[i]; + if (!rs285_xmit(ch)) + break; + } + return i; +} + +static void rs285_put_char(struct tty_struct *tty, u_char ch) +{ + rs285_xmit(ch); +} + +static int rs285_chars_in_buffer(struct tty_struct *tty) +{ + return sizeof(wbuf) - rs285_write_room(tty); +} + +static void rs285_flush_buffer(struct tty_struct *tty) +{ + disable_irq(IRQ_CONTX); + putp = getp = wbuf; + if (x_char) + enable_irq(IRQ_CONTX); +} + +static inline void rs285_set_cflag(int cflag) +{ + int h_lcr, baud, quot; + + switch (cflag & CSIZE) { + case CS5: + h_lcr = 0x10; + break; + case CS6: + h_lcr = 0x30; + break; + case CS7: + h_lcr = 0x50; + break; + default: /* CS8 */ + h_lcr = 0x70; + break; + + } + if (cflag & CSTOPB) + h_lcr |= 0x08; + if (cflag & PARENB) + h_lcr |= 0x02; + if (!(cflag & PARODD)) + h_lcr |= 0x04; + + switch (cflag & CBAUD) { + case B200: baud = 200; break; + case B300: baud = 300; break; + case B1200: baud = 1200; break; + case B1800: baud = 1800; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + default: + case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + } + + /* + * The documented expression for selecting the divisor is: + * BAUD_BASE / baud - 1 + * However, typically BAUD_BASE is not divisible by baud, so + * we want to select the divisor that gives us the minimum + * error. Therefore, we want: + * int(BAUD_BASE / baud - 0.5) -> + * int(BAUD_BASE / baud - (baud >> 1) / baud) -> + * int((BAUD_BASE - (baud >> 1)) / baud) + */ + quot = (BAUD_BASE - (baud >> 1)) / baud; + + *CSR_UARTCON = 0; + *CSR_L_UBRLCR = quot & 0xff; + *CSR_M_UBRLCR = (quot >> 8) & 0x0f; + *CSR_H_UBRLCR = h_lcr; + *CSR_UARTCON = 1; +} + +static void rs285_set_termios(struct tty_struct *tty, struct termios *old) +{ + if (old && tty->termios->c_cflag == old->c_cflag) + return; + rs285_set_cflag(tty->termios->c_cflag); +} + + +static void rs285_stop(struct tty_struct *tty) +{ + disable_irq(IRQ_CONTX); +} + +static void rs285_start(struct tty_struct *tty) +{ + enable_irq(IRQ_CONTX); +} + +static void rs285_wait_until_sent(struct tty_struct *tty, int timeout) +{ + int orig_jiffies = jiffies; + while (*CSR_UARTFLG & 8) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + current->state = TASK_RUNNING; +} + +static int rs285_open(struct tty_struct *tty, struct file *filp) +{ + int line; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if (line) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + tty->driver_data = NULL; + if (!rs285_tty) + rs285_tty = tty; + + enable_irq(IRQ_CONRX); + rs285_use_count++; + return 0; +} + +static void rs285_close(struct tty_struct *tty, struct file *filp) +{ + if (!--rs285_use_count) { + rs285_wait_until_sent(tty, 0); + disable_irq(IRQ_CONRX); + disable_irq(IRQ_CONTX); + rs285_tty = NULL; + } + MOD_DEC_USE_COUNT; +} + +static int __init rs285_init(void) +{ + int baud = B9600; + + if (machine_is_personal_server()) + baud = B57600; + + rs285_driver.magic = TTY_DRIVER_MAGIC; + rs285_driver.driver_name = "serial_21285"; + rs285_driver.name = SERIAL_21285_NAME; + rs285_driver.major = SERIAL_21285_MAJOR; + rs285_driver.minor_start = SERIAL_21285_MINOR; + rs285_driver.num = 1; + rs285_driver.type = TTY_DRIVER_TYPE_SERIAL; + rs285_driver.subtype = SERIAL_TYPE_NORMAL; + rs285_driver.init_termios = tty_std_termios; + rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL; + rs285_driver.flags = TTY_DRIVER_REAL_RAW; + rs285_driver.refcount = &rs285_refcount; + rs285_driver.table = rs285_table; + rs285_driver.termios = rs285_termios; + rs285_driver.termios_locked = rs285_termios_locked; + + rs285_driver.open = rs285_open; + rs285_driver.close = rs285_close; + rs285_driver.write = rs285_write; + rs285_driver.put_char = rs285_put_char; + rs285_driver.write_room = rs285_write_room; + rs285_driver.chars_in_buffer = rs285_chars_in_buffer; + rs285_driver.flush_buffer = rs285_flush_buffer; + rs285_driver.throttle = rs285_throttle; + rs285_driver.unthrottle = rs285_unthrottle; + rs285_driver.send_xchar = rs285_send_xchar; + rs285_driver.set_termios = rs285_set_termios; + rs285_driver.stop = rs285_stop; + rs285_driver.start = rs285_start; + rs285_driver.wait_until_sent = rs285_wait_until_sent; + + callout_driver = rs285_driver; + callout_driver.name = SERIAL_21285_AUXNAME; + callout_driver.major = SERIAL_21285_AUXMAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL)) + panic("Couldn't get rx irq for rs285"); + + if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL)) + panic("Couldn't get tx irq for rs285"); + + if (tty_register_driver(&rs285_driver)) + printk(KERN_ERR "Couldn't register 21285 serial driver\n"); + if (tty_register_driver(&callout_driver)) + printk(KERN_ERR "Couldn't register 21285 callout driver\n"); + + return 0; +} + +static void __exit rs285_fini(void) +{ + unsigned long flags; + int ret; + + save_flags(flags); + cli(); + ret = tty_unregister_driver(&callout_driver); + if (ret) + printk(KERN_ERR "Unable to unregister 21285 callout driver " + "(%d)\n", ret); + ret = tty_unregister_driver(&rs285_driver); + if (ret) + printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n", + ret); + free_irq(IRQ_CONTX, NULL); + free_irq(IRQ_CONRX, NULL); + restore_flags(flags); +} + +module_init(rs285_init); +module_exit(rs285_fini); + +#ifdef CONFIG_SERIAL_21285_CONSOLE +/************** console driver *****************/ + +static void rs285_console_write(struct console *co, const char *s, u_int count) +{ + int i; + + disable_irq(IRQ_CONTX); + for (i = 0; i < count; i++) { + while (*CSR_UARTFLG & 0x20); + *CSR_UARTDR = s[i]; + if (s[i] == '\n') { + while (*CSR_UARTFLG & 0x20); + *CSR_UARTDR = '\r'; + } + } + enable_irq(IRQ_CONTX); +} + +static int rs285_console_wait_key(struct console *co) +{ + int c; + + disable_irq(IRQ_CONRX); + while (*CSR_UARTFLG & 0x10); + c = *CSR_UARTDR; + enable_irq(IRQ_CONRX); + return c; +} + +static kdev_t rs285_console_device(struct console *c) +{ + return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); +} + +static int __init rs285_console_setup(struct console *co, char *options) +{ + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + + if (machine_is_personal_server()) + baud = 57600; + + if (options) { + char *s = options; + baud = simple_strtoul(options, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + if (*s) + parity = *s++; + if (*s) + bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch (baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + default: + cflag |= B9600; + break; + } + switch (bits) { + case 7: + cflag |= CS7; + break; + default: + cflag |= CS8; + break; + } + switch (parity) { + case 'o': + case 'O': + cflag |= PARODD; + break; + case 'e': + case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + rs285_set_cflag(cflag); + rs285_console_write(NULL, "\e[2J\e[Hboot ", 12); + if (options) + rs285_console_write(NULL, options, strlen(options)); + else + rs285_console_write(NULL, "no options", 10); + rs285_console_write(NULL, "\n", 1); + + return 0; +} + +static struct console rs285_cons = +{ + SERIAL_21285_NAME, + rs285_console_write, + NULL, + rs285_console_device, + rs285_console_wait_key, + NULL, + rs285_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +void __init rs285_console_init(void) +{ + register_console(&rs285_cons); +} + +#endif /* CONFIG_SERIAL_21285_CONSOLE */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.4.0-test6/linux/drivers/char/stallion.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/stallion.c Wed Dec 31 16:00:00 1969 @@ -1,5329 +0,0 @@ -/*****************************************************************************/ - -/* - * stallion.c -- stallion multiport serial driver. - * - * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This code is loosely based on the Linux serial driver, written by - * Linus Torvalds, Theodore T'so and others. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -/*****************************************************************************/ - -#include -#include -#include /* for linux/stallion.h */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_PCI -#include -#endif - -/*****************************************************************************/ - -/* - * Define different board types. Use the standard Stallion "assigned" - * board numbers. Boards supported in this driver are abbreviated as - * EIO = EasyIO and ECH = EasyConnection 8/32. - */ -#define BRD_EASYIO 20 -#define BRD_ECH 21 -#define BRD_ECHMC 22 -#define BRD_ECHPCI 26 -#define BRD_ECH64PCI 27 -#define BRD_EASYIOPCI 28 - -/* - * Define a configuration structure to hold the board configuration. - * Need to set this up in the code (for now) with the boards that are - * to be configured into the system. This is what needs to be modified - * when adding/removing/modifying boards. Each line entry in the - * stl_brdconf[] array is a board. Each line contains io/irq/memory - * ranges for that board (as well as what type of board it is). - * Some examples: - * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, - * This line would configure an EasyIO board (4 or 8, no difference), - * at io address 2a0 and irq 10. - * Another example: - * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 }, - * This line will configure an EasyConnection 8/32 board at primary io - * address 2a8, secondary io address 280 and irq 12. - * Enter as many lines into this array as you want (only the first 4 - * will actually be used!). Any combination of EasyIO and EasyConnection - * boards can be specified. EasyConnection 8/32 boards can share their - * secondary io addresses between each other. - * - * NOTE: there is no need to put any entries in this table for PCI - * boards. They will be found automatically by the driver - provided - * PCI BIOS32 support is compiled into the kernel. - */ - -typedef struct { - int brdtype; - int ioaddr1; - int ioaddr2; - unsigned long memaddr; - int irq; - int irqtype; -} stlconf_t; - -static stlconf_t stl_brdconf[] = { - /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ -}; - -static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); - -/*****************************************************************************/ - -/* - * Define some important driver characteristics. Device major numbers - * allocated as per Linux Device Registry. - */ -#ifndef STL_SIOMEMMAJOR -#define STL_SIOMEMMAJOR 28 -#endif -#ifndef STL_SERIALMAJOR -#define STL_SERIALMAJOR 24 -#endif -#ifndef STL_CALLOUTMAJOR -#define STL_CALLOUTMAJOR 25 -#endif - -#define STL_DRVTYPSERIAL 1 -#define STL_DRVTYPCALLOUT 2 - -/* - * Set the TX buffer size. Bigger is better, but we don't want - * to chew too much memory with buffers! - */ -#define STL_TXBUFLOW 512 -#define STL_TXBUFSIZE 4096 - -/*****************************************************************************/ - -/* - * Define our local driver identity first. Set up stuff to deal with - * all the local structures required by a serial tty driver. - */ -static char *stl_drvtitle = "Stallion Multiport Serial Driver"; -static char *stl_drvname = "stallion"; -static char *stl_drvversion = "5.6.0"; -static char *stl_serialname = "ttyE"; -static char *stl_calloutname = "cue"; - -static struct tty_driver stl_serial; -static struct tty_driver stl_callout; -static struct tty_struct *stl_ttys[STL_MAXDEVS]; -static struct termios *stl_termios[STL_MAXDEVS]; -static struct termios *stl_termioslocked[STL_MAXDEVS]; -static int stl_refcount = 0; - -/* - * We will need to allocate a temporary write buffer for chars that - * come direct from user space. The problem is that a copy from user - * space might cause a page fault (typically on a system that is - * swapping!). All ports will share one buffer - since if the system - * is already swapping a shared buffer won't make things any worse. - */ -static char *stl_tmpwritebuf; -static DECLARE_MUTEX(stl_tmpwritesem); - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. Basically all it defines is a raw port - * at 9600, 8 data bits, 1 stop bit. - */ -static struct termios stl_deftermios = { - 0, - 0, - (B9600 | CS8 | CREAD | HUPCL | CLOCAL), - 0, - 0, - INIT_C_CC -}; - -/* - * Define global stats structures. Not used often, and can be - * re-used for each stats call. - */ -static comstats_t stl_comstats; -static combrd_t stl_brdstats; -static stlbrd_t stl_dummybrd; -static stlport_t stl_dummyport; - -/* - * Define global place to put buffer overflow characters. - */ -static char stl_unwanted[SC26198_RXFIFOSIZE]; - -/* - * Keep track of what interrupts we have requested for us. - * We don't need to request an interrupt twice if it is being - * shared with another Stallion board. - */ -static int stl_gotintrs[STL_MAXBRDS]; -static int stl_numintrs = 0; - -/*****************************************************************************/ - -static stlbrd_t *stl_brds[STL_MAXBRDS]; - -/* - * Per board state flags. Used with the state field of the board struct. - * Not really much here! - */ -#define BRD_FOUND 0x1 - -/* - * Define the port structure istate flags. These set of flags are - * modified at interrupt time - so setting and reseting them needs - * to be atomic. Use the bit clear/setting routines for this. - */ -#define ASYI_TXBUSY 1 -#define ASYI_TXLOW 2 -#define ASYI_DCDCHANGE 3 -#define ASYI_TXFLOWED 4 - -/* - * Define an array of board names as printable strings. Handy for - * referencing boards when printing trace and stuff. - */ -static char *stl_brdnames[] = { - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EasyIO", - "EC8/32-AT", - "EC8/32-MC", - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EC8/32-PCI", - "EC8/64-PCI", - "EasyIO-PCI", -}; - -/*****************************************************************************/ - -#ifdef MODULE -/* - * Define some string labels for arguments passed from the module - * load line. These allow for easy board definitions, and easy - * modification of the io, memory and irq resoucres. - */ - -static char *board0[4]; -static char *board1[4]; -static char *board2[4]; -static char *board3[4]; - -static char **stl_brdsp[] = { - (char **) &board0, - (char **) &board1, - (char **) &board2, - (char **) &board3 -}; - -/* - * Define a set of common board names, and types. This is used to - * parse any module arguments. - */ - -typedef struct stlbrdtype { - char *name; - int type; -} stlbrdtype_t; - -static stlbrdtype_t stl_brdstr[] = { - { "easyio", BRD_EASYIO }, - { "eio", BRD_EASYIO }, - { "20", BRD_EASYIO }, - { "ec8/32", BRD_ECH }, - { "ec8/32-at", BRD_ECH }, - { "ec8/32-isa", BRD_ECH }, - { "ech", BRD_ECH }, - { "echat", BRD_ECH }, - { "21", BRD_ECH }, - { "ec8/32-mc", BRD_ECHMC }, - { "ec8/32-mca", BRD_ECHMC }, - { "echmc", BRD_ECHMC }, - { "echmca", BRD_ECHMC }, - { "22", BRD_ECHMC }, - { "ec8/32-pc", BRD_ECHPCI }, - { "ec8/32-pci", BRD_ECHPCI }, - { "26", BRD_ECHPCI }, - { "ec8/64-pc", BRD_ECH64PCI }, - { "ec8/64-pci", BRD_ECH64PCI }, - { "ech-pci", BRD_ECH64PCI }, - { "echpci", BRD_ECH64PCI }, - { "echpc", BRD_ECH64PCI }, - { "27", BRD_ECH64PCI }, - { "easyio-pc", BRD_EASYIOPCI }, - { "easyio-pci", BRD_EASYIOPCI }, - { "eio-pci", BRD_EASYIOPCI }, - { "eiopci", BRD_EASYIOPCI }, - { "28", BRD_EASYIOPCI }, -}; - -/* - * Define the module agruments. - */ -MODULE_AUTHOR("Greg Ungerer"); -MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); - -MODULE_PARM(board0, "1-4s"); -MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board1, "1-4s"); -MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board2, "1-4s"); -MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]"); -MODULE_PARM(board3, "1-4s"); -MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]"); - -#endif - -/*****************************************************************************/ - -/* - * Hardware ID bits for the EasyIO and ECH boards. These defines apply - * to the directly accessible io ports of these boards (not the uarts - - * they are in cd1400.h and sc26198.h). - */ -#define EIO_8PORTRS 0x04 -#define EIO_4PORTRS 0x05 -#define EIO_8PORTDI 0x00 -#define EIO_8PORTM 0x06 -#define EIO_MK3 0x03 -#define EIO_IDBITMASK 0x07 - -#define EIO_BRDMASK 0xf0 -#define ID_BRD4 0x10 -#define ID_BRD8 0x20 -#define ID_BRD16 0x30 - -#define EIO_INTRPEND 0x08 -#define EIO_INTEDGE 0x00 -#define EIO_INTLEVEL 0x08 -#define EIO_0WS 0x10 - -#define ECH_ID 0xa0 -#define ECH_IDBITMASK 0xe0 -#define ECH_BRDENABLE 0x08 -#define ECH_BRDDISABLE 0x00 -#define ECH_INTENABLE 0x01 -#define ECH_INTDISABLE 0x00 -#define ECH_INTLEVEL 0x02 -#define ECH_INTEDGE 0x00 -#define ECH_INTRPEND 0x01 -#define ECH_BRDRESET 0x01 - -#define ECHMC_INTENABLE 0x01 -#define ECHMC_BRDRESET 0x02 - -#define ECH_PNLSTATUS 2 -#define ECH_PNL16PORT 0x20 -#define ECH_PNLIDMASK 0x07 -#define ECH_PNLXPID 0x40 -#define ECH_PNLINTRPEND 0x80 - -#define ECH_ADDR2MASK 0x1e0 - -/* - * Define the vector mapping bits for the programmable interrupt board - * hardware. These bits encode the interrupt for the board to use - it - * is software selectable (except the EIO-8M). - */ -static unsigned char stl_vecmap[] = { - 0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07, - 0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03 -}; - -/* - * Set up enable and disable macros for the ECH boards. They require - * the secondary io address space to be activated and deactivated. - * This way all ECH boards can share their secondary io region. - * If this is an ECH-PCI board then also need to set the page pointer - * to point to the correct page. - */ -#define BRDENABLE(brdnr,pagenr) \ - if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ - outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE), \ - stl_brds[(brdnr)]->ioctrl); \ - else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI) \ - outb((pagenr), stl_brds[(brdnr)]->ioctrl); - -#define BRDDISABLE(brdnr) \ - if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ - outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \ - stl_brds[(brdnr)]->ioctrl); - -#define STL_CD1400MAXBAUD 230400 -#define STL_SC26198MAXBAUD 460800 - -#define STL_BAUDBASE 115200 -#define STL_CLOSEDELAY (5 * HZ / 10) - -/*****************************************************************************/ - -#ifdef CONFIG_PCI - -/* - * Define the Stallion PCI vendor and device IDs. - */ -#ifndef PCI_VENDOR_ID_STALLION -#define PCI_VENDOR_ID_STALLION 0x124d -#endif -#ifndef PCI_DEVICE_ID_ECHPCI832 -#define PCI_DEVICE_ID_ECHPCI832 0x0000 -#endif -#ifndef PCI_DEVICE_ID_ECHPCI864 -#define PCI_DEVICE_ID_ECHPCI864 0x0002 -#endif -#ifndef PCI_DEVICE_ID_EIOPCI -#define PCI_DEVICE_ID_EIOPCI 0x0003 -#endif - -/* - * Define structure to hold all Stallion PCI boards. - */ -typedef struct stlpcibrd { - unsigned short vendid; - unsigned short devid; - int brdtype; -} stlpcibrd_t; - -static stlpcibrd_t stl_pcibrds[] = { - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI }, - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI }, - { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI }, - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI }, -}; - -static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t); - -#endif - -/*****************************************************************************/ - -/* - * Define macros to extract a brd/port number from a minor number. - */ -#define MINOR2BRD(min) (((min) & 0xc0) >> 6) -#define MINOR2PORT(min) ((min) & 0x3f) - -/* - * Define a baud rate table that converts termios baud rate selector - * into the actual baud rate value. All baud rate calculations are - * based on the actual baud rate required. - */ -static unsigned int stl_baudrates[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 -}; - -/* - * Define some handy local macros... - */ -#undef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) - -#undef TOLOWER -#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) - -/*****************************************************************************/ - -/* - * Declare all those functions in this driver! - */ - -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -static void stl_argbrds(void); -static int stl_parsebrd(stlconf_t *confp, char **argp); - -static unsigned long stl_atol(char *str); -#endif - -int stl_init(void); -static int stl_open(struct tty_struct *tty, struct file *filp); -static void stl_close(struct tty_struct *tty, struct file *filp); -static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void stl_putchar(struct tty_struct *tty, unsigned char ch); -static void stl_flushchars(struct tty_struct *tty); -static int stl_writeroom(struct tty_struct *tty); -static int stl_charsinbuffer(struct tty_struct *tty); -static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void stl_settermios(struct tty_struct *tty, struct termios *old); -static void stl_throttle(struct tty_struct *tty); -static void stl_unthrottle(struct tty_struct *tty); -static void stl_stop(struct tty_struct *tty); -static void stl_start(struct tty_struct *tty); -static void stl_flushbuffer(struct tty_struct *tty); -static void stl_breakctl(struct tty_struct *tty, int state); -static void stl_waituntilsent(struct tty_struct *tty, int timeout); -static void stl_sendxchar(struct tty_struct *tty, char ch); -static void stl_hangup(struct tty_struct *tty); -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); -static int stl_portinfo(stlport_t *portp, int portnr, char *pos); -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); - -static int stl_brdinit(stlbrd_t *brdp); -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static int stl_mapirq(int irq, char *name); -static void stl_getserial(stlport_t *portp, struct serial_struct *sp); -static int stl_setserial(stlport_t *portp, struct serial_struct *sp); -static int stl_getbrdstats(combrd_t *bp); -static int stl_getportstats(stlport_t *portp, comstats_t *cp); -static int stl_clrportstats(stlport_t *portp, comstats_t *cp); -static int stl_getportstruct(unsigned long arg); -static int stl_getbrdstruct(unsigned long arg); -static int stl_waitcarrier(stlport_t *portp, struct file *filp); -static void stl_delay(int len); -static void stl_intr(int irq, void *dev_id, struct pt_regs *regs); -static void stl_eiointr(stlbrd_t *brdp); -static void stl_echatintr(stlbrd_t *brdp); -static void stl_echmcaintr(stlbrd_t *brdp); -static void stl_echpciintr(stlbrd_t *brdp); -static void stl_echpci64intr(stlbrd_t *brdp); -static void stl_offintr(void *private); -static void *stl_memalloc(int len); -static stlbrd_t *stl_allocbrd(void); -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); - -static inline int stl_initbrds(void); -static inline int stl_initeio(stlbrd_t *brdp); -static inline int stl_initech(stlbrd_t *brdp); -static inline int stl_getbrdnr(void); - -#ifdef CONFIG_PCI -static inline int stl_findpcibrds(void); -static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); -#endif - -/* - * CD1400 uart specific handling functions. - */ -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value); -static int stl_cd1400getreg(stlport_t *portp, int regnr); -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); -static int stl_cd1400getsignals(stlport_t *portp); -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); -static void stl_cd1400ccrwait(stlport_t *portp); -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); -static void stl_cd1400disableintrs(stlport_t *portp); -static void stl_cd1400sendbreak(stlport_t *portp, int len); -static void stl_cd1400flowctrl(stlport_t *portp, int state); -static void stl_cd1400sendflow(stlport_t *portp, int state); -static void stl_cd1400flush(stlport_t *portp); -static int stl_cd1400datastate(stlport_t *portp); -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase); -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); - -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr); - -/* - * SC26198 uart specific handling functions. - */ -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getreg(stlport_t *portp, int regnr); -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); -static int stl_sc26198getglobreg(stlport_t *portp, int regnr); -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); -static int stl_sc26198getsignals(stlport_t *portp); -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); -static void stl_sc26198disableintrs(stlport_t *portp); -static void stl_sc26198sendbreak(stlport_t *portp, int len); -static void stl_sc26198flowctrl(stlport_t *portp, int state); -static void stl_sc26198sendflow(stlport_t *portp, int state); -static void stl_sc26198flush(stlport_t *portp); -static int stl_sc26198datastate(stlport_t *portp); -static void stl_sc26198wait(stlport_t *portp); -static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); -static void stl_sc26198txisr(stlport_t *port); -static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); -static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); -static void stl_sc26198rxbadchars(stlport_t *portp); -static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); - -/*****************************************************************************/ - -/* - * Generic UART support structure. - */ -typedef struct uart { - int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); - void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); - void (*setport)(stlport_t *portp, struct termios *tiosp); - int (*getsignals)(stlport_t *portp); - void (*setsignals)(stlport_t *portp, int dtr, int rts); - void (*enablerxtx)(stlport_t *portp, int rx, int tx); - void (*startrxtx)(stlport_t *portp, int rx, int tx); - void (*disableintrs)(stlport_t *portp); - void (*sendbreak)(stlport_t *portp, int len); - void (*flowctrl)(stlport_t *portp, int state); - void (*sendflow)(stlport_t *portp, int state); - void (*flush)(stlport_t *portp); - int (*datastate)(stlport_t *portp); - void (*intr)(stlpanel_t *panelp, unsigned int iobase); -} uart_t; - -/* - * Define some macros to make calling these functions nice and clean. - */ -#define stl_panelinit (* ((uart_t *) panelp->uartp)->panelinit) -#define stl_portinit (* ((uart_t *) portp->uartp)->portinit) -#define stl_setport (* ((uart_t *) portp->uartp)->setport) -#define stl_getsignals (* ((uart_t *) portp->uartp)->getsignals) -#define stl_setsignals (* ((uart_t *) portp->uartp)->setsignals) -#define stl_enablerxtx (* ((uart_t *) portp->uartp)->enablerxtx) -#define stl_startrxtx (* ((uart_t *) portp->uartp)->startrxtx) -#define stl_disableintrs (* ((uart_t *) portp->uartp)->disableintrs) -#define stl_sendbreak (* ((uart_t *) portp->uartp)->sendbreak) -#define stl_flowctrl (* ((uart_t *) portp->uartp)->flowctrl) -#define stl_sendflow (* ((uart_t *) portp->uartp)->sendflow) -#define stl_flush (* ((uart_t *) portp->uartp)->flush) -#define stl_datastate (* ((uart_t *) portp->uartp)->datastate) - -/*****************************************************************************/ - -/* - * CD1400 UART specific data initialization. - */ -static uart_t stl_cd1400uart = { - stl_cd1400panelinit, - stl_cd1400portinit, - stl_cd1400setport, - stl_cd1400getsignals, - stl_cd1400setsignals, - stl_cd1400enablerxtx, - stl_cd1400startrxtx, - stl_cd1400disableintrs, - stl_cd1400sendbreak, - stl_cd1400flowctrl, - stl_cd1400sendflow, - stl_cd1400flush, - stl_cd1400datastate, - stl_cd1400eiointr -}; - -/* - * Define the offsets within the register bank of a cd1400 based panel. - * These io address offsets are common to the EasyIO board as well. - */ -#define EREG_ADDR 0 -#define EREG_DATA 4 -#define EREG_RXACK 5 -#define EREG_TXACK 6 -#define EREG_MDACK 7 - -#define EREG_BANKSIZE 8 - -#define CD1400_CLK 25000000 -#define CD1400_CLK8M 20000000 - -/* - * Define the cd1400 baud rate clocks. These are used when calculating - * what clock and divisor to use for the required baud rate. Also - * define the maximum baud rate allowed, and the default base baud. - */ -static int stl_cd1400clkdivs[] = { - CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 -}; - -/*****************************************************************************/ - -/* - * SC26198 UART specific data initization. - */ -static uart_t stl_sc26198uart = { - stl_sc26198panelinit, - stl_sc26198portinit, - stl_sc26198setport, - stl_sc26198getsignals, - stl_sc26198setsignals, - stl_sc26198enablerxtx, - stl_sc26198startrxtx, - stl_sc26198disableintrs, - stl_sc26198sendbreak, - stl_sc26198flowctrl, - stl_sc26198sendflow, - stl_sc26198flush, - stl_sc26198datastate, - stl_sc26198intr -}; - -/* - * Define the offsets within the register bank of a sc26198 based panel. - */ -#define XP_DATA 0 -#define XP_ADDR 1 -#define XP_MODID 2 -#define XP_STATUS 2 -#define XP_IACK 3 - -#define XP_BANKSIZE 4 - -/* - * Define the sc26198 baud rate table. Offsets within the table - * represent the actual baud rate selector of sc26198 registers. - */ -static unsigned int sc26198_baudtable[] = { - 50, 75, 150, 200, 300, 450, 600, 900, 1200, 1800, 2400, 3600, - 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, - 230400, 460800, 921600 -}; - -#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int)) - -/*****************************************************************************/ - -/* - * Define the driver info for a user level control device. Used mainly - * to get at port stats - only not using the port device itself. - */ -static struct file_operations stl_fsiomem = { - owner: THIS_MODULE, - ioctl: stl_memioctl, -}; - -/*****************************************************************************/ - -static devfs_handle_t devfs_handle = NULL; - -#ifdef MODULE - -/* - * Loadable module initialization stuff. - */ - -int init_module() -{ - unsigned long flags; - -#if DEBUG - printk("init_module()\n"); -#endif - - save_flags(flags); - cli(); - stl_init(); - restore_flags(flags); - - return(0); -} - -/*****************************************************************************/ - -void cleanup_module() -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; - unsigned long flags; - int i, j, k; - -#if DEBUG - printk("cleanup_module()\n"); -#endif - - printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, - stl_drvversion); - - save_flags(flags); - cli(); - -/* - * Free up all allocated resources used by the ports. This includes - * memory and interrupts. As part of this process we will also do - * a hangup on every open port - to try to flush out any processes - * hanging onto ports. - */ - i = tty_unregister_driver(&stl_serial); - j = tty_unregister_driver(&stl_callout); - if (i || j) { - printk("STALLION: failed to un-register tty driver, " - "errno=%d,%d\n", -i, -j); - restore_flags(flags); - return; - } - devfs_unregister (devfs_handle); - if ((i = devfs_unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) - printk("STALLION: failed to un-register serial memory device, " - "errno=%d\n", -i); - - if (stl_tmpwritebuf != (char *) NULL) - kfree(stl_tmpwritebuf); - - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - for (j = 0; (j < STL_MAXPANELS); j++) { - panelp = brdp->panels[j]; - if (panelp == (stlpanel_t *) NULL) - continue; - for (k = 0; (k < STL_PORTSPERPANEL); k++) { - portp = panelp->ports[k]; - if (portp == (stlport_t *) NULL) - continue; - if (portp->tty != (struct tty_struct *) NULL) - stl_hangup(portp->tty); - if (portp->tx.buf != (char *) NULL) - kfree(portp->tx.buf); - kfree(portp); - } - kfree(panelp); - } - - release_region(brdp->ioaddr1, brdp->iosize1); - if (brdp->iosize2 > 0) - release_region(brdp->ioaddr2, brdp->iosize2); - - kfree(brdp); - stl_brds[i] = (stlbrd_t *) NULL; - } - - for (i = 0; (i < stl_numintrs); i++) - free_irq(stl_gotintrs[i], NULL); - - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Check for any arguments passed in on the module load command line. - */ - -static void stl_argbrds() -{ - stlconf_t conf; - stlbrd_t *brdp; - int nrargs, i; - -#if DEBUG - printk("stl_argbrds()\n"); -#endif - - nrargs = sizeof(stl_brdsp) / sizeof(char **); - - for (i = stl_nrbrds; (i < nrargs); i++) { - memset(&conf, 0, sizeof(conf)); - if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) - continue; - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - continue; - stl_nrbrds = i + 1; - brdp->brdnr = i; - brdp->brdtype = conf.brdtype; - brdp->ioaddr1 = conf.ioaddr1; - brdp->ioaddr2 = conf.ioaddr2; - brdp->irq = conf.irq; - brdp->irqtype = conf.irqtype; - stl_brdinit(brdp); - } -} - -/*****************************************************************************/ - -/* - * Convert an ascii string number into an unsigned long. - */ - -static unsigned long stl_atol(char *str) -{ - unsigned long val; - int base, c; - char *sp; - - val = 0; - sp = str; - if ((*sp == '0') && (*(sp+1) == 'x')) { - base = 16; - sp += 2; - } else if (*sp == '0') { - base = 8; - sp++; - } else { - base = 10; - } - - for (; (*sp != 0); sp++) { - c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); - if ((c < 0) || (c >= base)) { - printk("STALLION: invalid argument %s\n", str); - val = 0; - break; - } - val = (val * base) + c; - } - return(val); -} - -/*****************************************************************************/ - -/* - * Parse the supplied argument string, into the board conf struct. - */ - -static int stl_parsebrd(stlconf_t *confp, char **argp) -{ - char *sp; - int nrbrdnames, i; - -#if DEBUG - printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); -#endif - - if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) - return(0); - - for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) - *sp = TOLOWER(*sp); - - nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t); - for (i = 0; (i < nrbrdnames); i++) { - if (strcmp(stl_brdstr[i].name, argp[0]) == 0) - break; - } - if (i >= nrbrdnames) { - printk("STALLION: unknown board name, %s?\n", argp[0]); - return(0); - } - - confp->brdtype = stl_brdstr[i].type; - - i = 1; - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->ioaddr1 = stl_atol(argp[i]); - i++; - if (confp->brdtype == BRD_ECH) { - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->ioaddr2 = stl_atol(argp[i]); - i++; - } - if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) - confp->irq = stl_atol(argp[i]); - return(1); -} - -#endif - -/*****************************************************************************/ - -/* - * Local driver kernel memory allocation routine. - */ - -static void *stl_memalloc(int len) -{ - return((void *) kmalloc(len, GFP_KERNEL)); -} - -/*****************************************************************************/ - -/* - * Allocate a new board structure. Fill out the basic info in it. - */ - -static stlbrd_t *stl_allocbrd() -{ - stlbrd_t *brdp; - - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlbrd_t)); - return((stlbrd_t *) NULL); - } - - memset(brdp, 0, sizeof(stlbrd_t)); - brdp->magic = STL_BOARDMAGIC; - return(brdp); -} - -/*****************************************************************************/ - -static int stl_open(struct tty_struct *tty, struct file *filp) -{ - stlport_t *portp; - stlbrd_t *brdp; - unsigned int minordev; - int brdnr, panelnr, portnr, rc; - -#if DEBUG - printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, - (int) filp, tty->device); -#endif - - minordev = MINOR(tty->device); - brdnr = MINOR2BRD(minordev); - if (brdnr >= stl_nrbrds) - return(-ENODEV); - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - minordev = MINOR2PORT(minordev); - for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) { - if (brdp->panels[panelnr] == (stlpanel_t *) NULL) - break; - if (minordev < brdp->panels[panelnr]->nrports) { - portnr = minordev; - break; - } - minordev -= brdp->panels[panelnr]->nrports; - } - if (portnr < 0) - return(-ENODEV); - - portp = brdp->panels[panelnr]->ports[portnr]; - if (portp == (stlport_t *) NULL) - return(-ENODEV); - - MOD_INC_USE_COUNT; - -/* - * On the first open of the device setup the port hardware, and - * initialize the per port data structure. - */ - portp->tty = tty; - tty->driver_data = portp; - portp->refcount++; - - if ((portp->flags & ASYNC_INITIALIZED) == 0) { - if (portp->tx.buf == (char *) NULL) { - portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (portp->tx.buf == (char *) NULL) - return(-ENOMEM); - portp->tx.head = portp->tx.buf; - portp->tx.tail = portp->tx.buf; - } - stl_setport(portp, tty->termios); - portp->sigs = stl_getsignals(portp); - stl_setsignals(portp, 1, 1); - stl_enablerxtx(portp, 1, 1); - stl_startrxtx(portp, 1, 0); - clear_bit(TTY_IO_ERROR, &tty->flags); - portp->flags |= ASYNC_INITIALIZED; - } - -/* - * Check if this port is in the middle of closing. If so then wait - * until it is closed then return error status, based on flag settings. - * The sleep here does not need interrupt protection since the wakeup - * for it is done with the same context. - */ - if (portp->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&portp->close_wait); - if (portp->flags & ASYNC_HUP_NOTIFY) - return(-EAGAIN); - return(-ERESTARTSYS); - } - -/* - * Based on type of open being done check if it can overlap with any - * previous opens still in effect. If we are a normal serial device - * then also we might have to wait for carrier. - */ - if (tty->driver.subtype == STL_DRVTYPCALLOUT) { - if (portp->flags & ASYNC_NORMAL_ACTIVE) - return(-EBUSY); - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if ((portp->flags & ASYNC_SESSION_LOCKOUT) && - (portp->session != current->session)) - return(-EBUSY); - if ((portp->flags & ASYNC_PGRP_LOCKOUT) && - (portp->pgrp != current->pgrp)) - return(-EBUSY); - } - portp->flags |= ASYNC_CALLOUT_ACTIVE; - } else { - if (filp->f_flags & O_NONBLOCK) { - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - return(-EBUSY); - } else { - if ((rc = stl_waitcarrier(portp, filp)) != 0) - return(rc); - } - portp->flags |= ASYNC_NORMAL_ACTIVE; - } - - if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == STL_DRVTYPSERIAL) - *tty->termios = portp->normaltermios; - else - *tty->termios = portp->callouttermios; - stl_setport(portp, tty->termios); - } - - portp->session = current->session; - portp->pgrp = current->pgrp; - return(0); -} - -/*****************************************************************************/ - -/* - * Possibly need to wait for carrier (DCD signal) to come high. Say - * maybe because if we are clocal then we don't need to wait... - */ - -static int stl_waitcarrier(stlport_t *portp, struct file *filp) -{ - unsigned long flags; - int rc, doclocal; - -#if DEBUG - printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp); -#endif - - rc = 0; - doclocal = 0; - - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if (portp->normaltermios.c_cflag & CLOCAL) - doclocal++; - } else { - if (portp->tty->termios->c_cflag & CLOCAL) - doclocal++; - } - - save_flags(flags); - cli(); - portp->openwaitcnt++; - if (! tty_hung_up_p(filp)) - portp->refcount--; - - for (;;) { - if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) - stl_setsignals(portp, 1, 1); - if (tty_hung_up_p(filp) || - ((portp->flags & ASYNC_INITIALIZED) == 0)) { - if (portp->flags & ASYNC_HUP_NOTIFY) - rc = -EBUSY; - else - rc = -ERESTARTSYS; - break; - } - if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) && - ((portp->flags & ASYNC_CLOSING) == 0) && - (doclocal || (portp->sigs & TIOCM_CD))) { - break; - } - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - interruptible_sleep_on(&portp->open_wait); - } - - if (! tty_hung_up_p(filp)) - portp->refcount++; - portp->openwaitcnt--; - restore_flags(flags); - - return(rc); -} - -/*****************************************************************************/ - -static void stl_close(struct tty_struct *tty, struct file *filp) -{ - stlport_t *portp; - unsigned long flags; - -#if DEBUG - printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp); -#endif - - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - save_flags(flags); - cli(); - if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - if ((tty->count == 1) && (portp->refcount != 1)) - portp->refcount = 1; - if (portp->refcount-- > 1) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - - portp->refcount = 0; - portp->flags |= ASYNC_CLOSING; - - if (portp->flags & ASYNC_NORMAL_ACTIVE) - portp->normaltermios = *tty->termios; - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - portp->callouttermios = *tty->termios; - -/* - * May want to wait for any data to drain before closing. The BUSY - * flag keeps track of whether we are still sending or not - it is - * very accurate for the cd1400, not quite so for the sc26198. - * (The sc26198 has no "end-of-data" interrupt only empty FIFO) - */ - tty->closing = 1; - if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, portp->closing_wait); - stl_waituntilsent(tty, (HZ / 2)); - - portp->flags &= ~ASYNC_INITIALIZED; - stl_disableintrs(portp); - if (tty->termios->c_cflag & HUPCL) - stl_setsignals(portp, 0, 0); - stl_enablerxtx(portp, 0, 0); - stl_flushbuffer(tty); - portp->istate = 0; - if (portp->tx.buf != (char *) NULL) { - kfree(portp->tx.buf); - portp->tx.buf = (char *) NULL; - portp->tx.head = (char *) NULL; - portp->tx.tail = (char *) NULL; - } - set_bit(TTY_IO_ERROR, &tty->flags); - if (tty->ldisc.flush_buffer) - (tty->ldisc.flush_buffer)(tty); - - tty->closing = 0; - portp->tty = (struct tty_struct *) NULL; - - if (portp->openwaitcnt) { - if (portp->close_delay) - stl_delay(portp->close_delay); - wake_up_interruptible(&portp->open_wait); - } - - portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | - ASYNC_CLOSING); - wake_up_interruptible(&portp->close_wait); - MOD_DEC_USE_COUNT; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Wait for a specified delay period, this is not a busy-loop. It will - * give up the processor while waiting. Unfortunately this has some - * rather intimate knowledge of the process management stuff. - */ - -static void stl_delay(int len) -{ -#if DEBUG - printk("stl_delay(len=%d)\n", len); -#endif - if (len > 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(len); - current->state = TASK_RUNNING; - } -} - -/*****************************************************************************/ - -/* - * Write routine. Take data and stuff it in to the TX ring queue. - * If transmit interrupts are not running then start them. - */ - -static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) -{ - stlport_t *portp; - unsigned int len, stlen; - unsigned char *chbuf; - char *head, *tail; - -#if DEBUG - printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", - (int) tty, from_user, (int) buf, count); -#endif - - if ((tty == (struct tty_struct *) NULL) || - (stl_tmpwritebuf == (char *) NULL)) - return(0); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); - -/* - * If copying direct from user space we must cater for page faults, - * causing us to "sleep" here for a while. To handle this copy in all - * the data we need now, into a local buffer. Then when we got it all - * copy it into the TX buffer. - */ - chbuf = (unsigned char *) buf; - if (from_user) { - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : - (tail - head - 1); - count = MIN(len, count); - - down(&stl_tmpwritesem); - copy_from_user(stl_tmpwritebuf, chbuf, count); - chbuf = &stl_tmpwritebuf[0]; - } - - head = portp->tx.head; - tail = portp->tx.tail; - if (head >= tail) { - len = STL_TXBUFSIZE - (head - tail) - 1; - stlen = STL_TXBUFSIZE - (head - portp->tx.buf); - } else { - len = tail - head - 1; - stlen = len; - } - - len = MIN(len, count); - count = 0; - while (len > 0) { - stlen = MIN(len, stlen); - memcpy(head, chbuf, stlen); - len -= stlen; - chbuf += stlen; - count += stlen; - head += stlen; - if (head >= (portp->tx.buf + STL_TXBUFSIZE)) { - head = portp->tx.buf; - stlen = tail - head; - } - } - portp->tx.head = head; - - clear_bit(ASYI_TXLOW, &portp->istate); - stl_startrxtx(portp, -1, 1); - - if (from_user) - up(&stl_tmpwritesem); - - return(count); -} - -/*****************************************************************************/ - -static void stl_putchar(struct tty_struct *tty, unsigned char ch) -{ - stlport_t *portp; - unsigned int len; - char *head, *tail; - -#if DEBUG - printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - if (portp->tx.buf == (char *) NULL) - return; - - head = portp->tx.head; - tail = portp->tx.tail; - - len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail)) : (tail - head); - len--; - - if (len > 0) { - *head++ = ch; - if (head >= (portp->tx.buf + STL_TXBUFSIZE)) - head = portp->tx.buf; - } - portp->tx.head = head; -} - -/*****************************************************************************/ - -/* - * If there are any characters in the buffer then make sure that TX - * interrupts are on and get'em out. Normally used after the putchar - * routine has been called. - */ - -static void stl_flushchars(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_flushchars(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - if (portp->tx.buf == (char *) NULL) - return; - -#if 0 - if (tty->stopped || tty->hw_stopped || - (portp->tx.head == portp->tx.tail)) - return; -#endif - stl_startrxtx(portp, -1, 1); -} - -/*****************************************************************************/ - -static int stl_writeroom(struct tty_struct *tty) -{ - stlport_t *portp; - char *head, *tail; - -#if DEBUG - printk("stl_writeroom(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return(0); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); - - head = portp->tx.head; - tail = portp->tx.tail; - return((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1)); -} - -/*****************************************************************************/ - -/* - * Return number of chars in the TX buffer. Normally we would just - * calculate the number of chars in the buffer and return that, but if - * the buffer is empty and TX interrupts are still on then we return - * that the buffer still has 1 char in it. This way whoever called us - * will not think that ALL chars have drained - since the UART still - * must have some chars in it (we are busy after all). - */ - -static int stl_charsinbuffer(struct tty_struct *tty) -{ - stlport_t *portp; - unsigned int size; - char *head, *tail; - -#if DEBUG - printk("stl_charsinbuffer(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return(0); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(0); - if (portp->tx.buf == (char *) NULL) - return(0); - - head = portp->tx.head; - tail = portp->tx.tail; - size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate)) - size = 1; - return(size); -} - -/*****************************************************************************/ - -/* - * Generate the serial struct info. - */ - -static void stl_getserial(stlport_t *portp, struct serial_struct *sp) -{ - struct serial_struct sio; - stlbrd_t *brdp; - -#if DEBUG - printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); -#endif - - memset(&sio, 0, sizeof(struct serial_struct)); - sio.line = portp->portnr; - sio.port = portp->ioaddr; - sio.flags = portp->flags; - sio.baud_base = portp->baud_base; - sio.close_delay = portp->close_delay; - sio.closing_wait = portp->closing_wait; - sio.custom_divisor = portp->custom_divisor; - sio.hub6 = 0; - if (portp->uartp == &stl_cd1400uart) { - sio.type = PORT_CIRRUS; - sio.xmit_fifo_size = CD1400_TXFIFOSIZE; - } else { - sio.type = PORT_UNKNOWN; - sio.xmit_fifo_size = SC26198_TXFIFOSIZE; - } - - brdp = stl_brds[portp->brdnr]; - if (brdp != (stlbrd_t *) NULL) - sio.irq = brdp->irq; - - copy_to_user(sp, &sio, sizeof(struct serial_struct)); -} - -/*****************************************************************************/ - -/* - * Set port according to the serial struct info. - * At this point we do not do any auto-configure stuff, so we will - * just quietly ignore any requests to change irq, etc. - */ - -static int stl_setserial(stlport_t *portp, struct serial_struct *sp) -{ - struct serial_struct sio; - -#if DEBUG - printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); -#endif - - copy_from_user(&sio, sp, sizeof(struct serial_struct)); - if (!capable(CAP_SYS_ADMIN)) { - if ((sio.baud_base != portp->baud_base) || - (sio.close_delay != portp->close_delay) || - ((sio.flags & ~ASYNC_USR_MASK) != - (portp->flags & ~ASYNC_USR_MASK))) - return(-EPERM); - } - - portp->flags = (portp->flags & ~ASYNC_USR_MASK) | - (sio.flags & ASYNC_USR_MASK); - portp->baud_base = sio.baud_base; - portp->close_delay = sio.close_delay; - portp->closing_wait = sio.closing_wait; - portp->custom_divisor = sio.custom_divisor; - stl_setport(portp, portp->tty->termios); - return(0); -} - -/*****************************************************************************/ - -static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) -{ - stlport_t *portp; - unsigned int ival; - int rc; - -#if DEBUG - printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", - (int) tty, (int) file, cmd, (int) arg); -#endif - - if (tty == (struct tty_struct *) NULL) - return(-ENODEV); - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return(-ENODEV); - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return(-EIO); - } - - rc = 0; - - switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned int *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(int))) == 0) { - get_user(ival, (unsigned int *) arg); - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - } - break; - case TIOCMGET: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int))) == 0) { - ival = stl_getsignals(portp); - put_user(ival, (unsigned int *) arg); - } - break; - case TIOCMBIS: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); - stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1), - ((ival & TIOCM_RTS) ? 1 : -1)); - } - break; - case TIOCMBIC: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); - stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1), - ((ival & TIOCM_RTS) ? 0 : -1)); - } - break; - case TIOCMSET: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); - stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0), - ((ival & TIOCM_RTS) ? 1 : 0)); - } - break; - case TIOCGSERIAL: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) == 0) - stl_getserial(portp, (struct serial_struct *) arg); - break; - case TIOCSSERIAL: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = stl_setserial(portp, (struct serial_struct *) arg); - break; - case COM_GETPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_getportstats(portp, (comstats_t *) arg); - break; - case COM_CLRPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_clrportstats(portp, (comstats_t *) arg); - break; - case TIOCSERCONFIG: - case TIOCSERGWILD: - case TIOCSERSWILD: - case TIOCSERGETLSR: - case TIOCSERGSTRUCT: - case TIOCSERGETMULTI: - case TIOCSERSETMULTI: - default: - rc = -ENOIOCTLCMD; - break; - } - - return(rc); -} - -/*****************************************************************************/ - -static void stl_settermios(struct tty_struct *tty, struct termios *old) -{ - stlport_t *portp; - struct termios *tiosp; - -#if DEBUG - printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - tiosp = tty->termios; - if ((tiosp->c_cflag == old->c_cflag) && - (tiosp->c_iflag == old->c_iflag)) - return; - - stl_setport(portp, tiosp); - stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), - -1); - if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) { - tty->hw_stopped = 0; - stl_start(tty); - } - if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) - wake_up_interruptible(&portp->open_wait); -} - -/*****************************************************************************/ - -/* - * Attempt to flow control who ever is sending us data. Based on termios - * settings use software or/and hardware flow control. - */ - -static void stl_throttle(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_throttle(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_flowctrl(portp, 0); -} - -/*****************************************************************************/ - -/* - * Unflow control the device sending us data... - */ - -static void stl_unthrottle(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_unthrottle(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_flowctrl(portp, 1); -} - -/*****************************************************************************/ - -/* - * Stop the transmitter. Basically to do this we will just turn TX - * interrupts off. - */ - -static void stl_stop(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_stop(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_startrxtx(portp, -1, 0); -} - -/*****************************************************************************/ - -/* - * Start the transmitter again. Just turn TX interrupts back on. - */ - -static void stl_start(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_start(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - stl_startrxtx(portp, -1, 1); -} - -/*****************************************************************************/ - -/* - * Hangup this port. This is pretty much like closing the port, only - * a little more brutal. No waiting for data to drain. Shutdown the - * port and maybe drop signals. - */ - -static void stl_hangup(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_hangup(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - portp->flags &= ~ASYNC_INITIALIZED; - stl_disableintrs(portp); - if (tty->termios->c_cflag & HUPCL) - stl_setsignals(portp, 0, 0); - stl_enablerxtx(portp, 0, 0); - stl_flushbuffer(tty); - portp->istate = 0; - set_bit(TTY_IO_ERROR, &tty->flags); - if (portp->tx.buf != (char *) NULL) { - kfree(portp->tx.buf); - portp->tx.buf = (char *) NULL; - portp->tx.head = (char *) NULL; - portp->tx.tail = (char *) NULL; - } - portp->tty = (struct tty_struct *) NULL; - portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); - portp->refcount = 0; - wake_up_interruptible(&portp->open_wait); -} - -/*****************************************************************************/ - -static void stl_flushbuffer(struct tty_struct *tty) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_flushbuffer(tty=%x)\n", (int) tty); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - stl_flush(portp); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - -/*****************************************************************************/ - -static void stl_breakctl(struct tty_struct *tty, int state) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - stl_sendbreak(portp, ((state == -1) ? 1 : 2)); -} - -/*****************************************************************************/ - -static void stl_waituntilsent(struct tty_struct *tty, int timeout) -{ - stlport_t *portp; - unsigned long tend; - -#if DEBUG - printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - if (timeout == 0) - timeout = HZ; - tend = jiffies + timeout; - - while (stl_datastate(portp)) { - if (signal_pending(current)) - break; - stl_delay(2); - if (time_after_eq(jiffies, tend)) - break; - } -} - -/*****************************************************************************/ - -static void stl_sendxchar(struct tty_struct *tty, char ch) -{ - stlport_t *portp; - -#if DEBUG - printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); -#endif - - if (tty == (struct tty_struct *) NULL) - return; - portp = tty->driver_data; - if (portp == (stlport_t *) NULL) - return; - - if (ch == STOP_CHAR(tty)) - stl_sendflow(portp, 0); - else if (ch == START_CHAR(tty)) - stl_sendflow(portp, 1); - else - stl_putchar(tty, ch); -} - -/*****************************************************************************/ - -#define MAXLINE 80 - -/* - * Format info for a specified port. The line is deliberately limited - * to 80 characters. (If it is too long it will be truncated, if too - * short then padded with spaces). - */ - -static int stl_portinfo(stlport_t *portp, int portnr, char *pos) -{ - char *sp; - int sigs, cnt; - - sp = pos; - sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d", - portnr, (portp->hwid == 1) ? "SC26198" : "CD1400", - (int) portp->stats.txtotal, (int) portp->stats.rxtotal); - - if (portp->stats.rxframing) - sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing); - if (portp->stats.rxparity) - sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity); - if (portp->stats.rxbreaks) - sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks); - if (portp->stats.rxoverrun) - sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun); - - sigs = stl_getsignals(portp); - cnt = sprintf(sp, "%s%s%s%s%s ", - (sigs & TIOCM_RTS) ? "|RTS" : "", - (sigs & TIOCM_CTS) ? "|CTS" : "", - (sigs & TIOCM_DTR) ? "|DTR" : "", - (sigs & TIOCM_CD) ? "|DCD" : "", - (sigs & TIOCM_DSR) ? "|DSR" : ""); - *sp = ' '; - sp += cnt; - - for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) - *sp++ = ' '; - if (cnt >= MAXLINE) - pos[(MAXLINE - 2)] = '+'; - pos[(MAXLINE - 1)] = '\n'; - - return(MAXLINE); -} - -/*****************************************************************************/ - -/* - * Port info, read from the /proc file system. - */ - -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - stlport_t *portp; - int brdnr, panelnr, portnr, totalport; - int curoff, maxoff; - char *pos; - -#if DEBUG - printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," - "data=%x\n", (int) page, (int) start, (int) off, count, - (int) eof, (int) data); -#endif - - pos = page; - totalport = 0; - curoff = 0; - - if (off == 0) { - pos += sprintf(pos, "%s: version %s", stl_drvtitle, - stl_drvversion); - while (pos < (page + MAXLINE - 1)) - *pos++ = ' '; - *pos++ = '\n'; - } - curoff = MAXLINE; - -/* - * We scan through for each board, panel and port. The offset is - * calculated on the fly, and irrelevant ports are skipped. - */ - for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - - maxoff = curoff + (brdp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - continue; - } - - totalport = brdnr * STL_MAXPORTS; - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - continue; - - maxoff = curoff + (panelp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - totalport += panelp->nrports; - continue; - } - - for (portnr = 0; (portnr < panelp->nrports); portnr++, - totalport++) { - portp = panelp->ports[portnr]; - if (portp == (stlport_t *) NULL) - continue; - if (off >= (curoff += MAXLINE)) - continue; - if ((pos - page + MAXLINE) > count) - goto stl_readdone; - pos += stl_portinfo(portp, totalport, pos); - } - } - } - - *eof = 1; - -stl_readdone: - *start = page; - return(pos - page); -} - -/*****************************************************************************/ - -/* - * All board interrupts are vectored through here first. This code then - * calls off to the approrpriate board interrupt handlers. - */ - -static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - stlbrd_t *brdp; - int i; - -#if DEBUG - printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); -#endif - - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - (* brdp->isr)(brdp); - } -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for EasyIO board types. - */ - -static void stl_eiointr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int iobase; - - panelp = brdp->panels[0]; - iobase = panelp->iobase; - while (inb(brdp->iostatus) & EIO_INTRPEND) - (* panelp->isr)(panelp, iobase); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-AT board types. - */ - -static void stl_echatintr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; - - outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - - while (inb(brdp->iostatus) & ECH_INTRPEND) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - } - } - } - - outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-MCA board types. - */ - -static void stl_echmcaintr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; - - while (inb(brdp->iostatus) & ECH_INTRPEND) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - } - } - } -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-PCI board types. - */ - -static void stl_echpciintr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr, recheck; - - while (1) { - recheck = 0; - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - recheck++; - } - } - if (! recheck) - break; - } -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for ECH-8/64-PCI board types. - */ - -static void stl_echpci64intr(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int ioaddr; - int bnknr; - - while (inb(brdp->ioctrl) & 0x1) { - for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { - ioaddr = brdp->bnkstataddr[bnknr]; - if (inb(ioaddr) & ECH_PNLINTRPEND) { - panelp = brdp->bnk2panel[bnknr]; - (* panelp->isr)(panelp, (ioaddr & 0xfffc)); - } - } - } -} - -/*****************************************************************************/ - -/* - * Service an off-level request for some channel. - */ -static void stl_offintr(void *private) -{ - stlport_t *portp; - struct tty_struct *tty; - unsigned int oldsigs; - - portp = private; - -#if DEBUG - printk("stl_offintr(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - lock_kernel(); - if (test_bit(ASYI_TXLOW, &portp->istate)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } - if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { - clear_bit(ASYI_DCDCHANGE, &portp->istate); - oldsigs = portp->sigs; - portp->sigs = stl_getsignals(portp); - if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) - wake_up_interruptible(&portp->open_wait); - if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { - if (portp->flags & ASYNC_CHECK_CD) { - if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && - (portp->flags & ASYNC_CALLOUT_NOHUP))) { - tty_hangup(tty); - } - } - } - } - unlock_kernel(); -} - -/*****************************************************************************/ - -/* - * Map in interrupt vector to this driver. Check that we don't - * already have this vector mapped, we might be sharing this - * interrupt across multiple boards. - */ - -static int __init stl_mapirq(int irq, char *name) -{ - int rc, i; - -#if DEBUG - printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); -#endif - - rc = 0; - for (i = 0; (i < stl_numintrs); i++) { - if (stl_gotintrs[i] == irq) - break; - } - if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { - printk("STALLION: failed to register interrupt " - "routine for %s irq=%d\n", name, irq); - rc = -ENODEV; - } else { - stl_gotintrs[stl_numintrs++] = irq; - } - } - return(rc); -} - -/*****************************************************************************/ - -/* - * Initialize all the ports on a panel. - */ - -static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) -{ - stlport_t *portp; - int chipmask, i; - -#if DEBUG - printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); -#endif - - chipmask = stl_panelinit(brdp, panelp); - -/* - * All UART's are initialized (if found!). Now go through and setup - * each ports data structures. - */ - for (i = 0; (i < panelp->nrports); i++) { - portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); - if (portp == (stlport_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlport_t)); - break; - } - memset(portp, 0, sizeof(stlport_t)); - - portp->magic = STL_PORTMAGIC; - portp->portnr = i; - portp->brdnr = panelp->brdnr; - portp->panelnr = panelp->panelnr; - portp->uartp = panelp->uartp; - portp->clk = brdp->clk; - portp->baud_base = STL_BAUDBASE; - portp->close_delay = STL_CLOSEDELAY; - portp->closing_wait = 30 * HZ; - portp->normaltermios = stl_deftermios; - portp->callouttermios = stl_deftermios; - portp->tqueue.routine = stl_offintr; - portp->tqueue.data = portp; - init_waitqueue_head(&portp->open_wait); - init_waitqueue_head(&portp->close_wait); - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - panelp->ports[i] = portp; - stl_portinit(brdp, panelp, portp); - } - - return(0); -} - -/*****************************************************************************/ - -/* - * Try to find and initialize an EasyIO board. - */ - -static inline int stl_initeio(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status; - char *name; - int rc; - -#if DEBUG - printk("stl_initeio(brdp=%x)\n", (int) brdp); -#endif - - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 2; - - status = inb(brdp->iostatus); - if ((status & EIO_IDBITMASK) == EIO_MK3) - brdp->ioctrl++; - -/* - * Handle board specific stuff now. The real difference is PCI - * or not PCI. - */ - if (brdp->brdtype == BRD_EASYIOPCI) { - brdp->iosize1 = 0x80; - brdp->iosize2 = 0x80; - name = "serial(EIO-PCI)"; - outb(0x41, (brdp->ioaddr2 + 0x4c)); - } else { - brdp->iosize1 = 8; - name = "serial(EIO)"; - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(-EINVAL); - } - outb((stl_vecmap[brdp->irq] | EIO_0WS | - ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), - brdp->ioctrl); - } - - if (check_region(brdp->ioaddr1, brdp->iosize1)) { - printk("STALLION: Warning, board %d I/O address %x conflicts " - "with another device\n", brdp->brdnr, brdp->ioaddr1); - } - if (brdp->iosize2 > 0) { - if (check_region(brdp->ioaddr2, brdp->iosize2)) { - printk("STALLION: Warning, board %d I/O address %x " - "conflicts with another device\n", - brdp->brdnr, brdp->ioaddr2); - } - } - -/* - * Everything looks OK, so let's go ahead and probe for the hardware. - */ - brdp->clk = CD1400_CLK; - brdp->isr = stl_eiointr; - - switch (status & EIO_IDBITMASK) { - case EIO_8PORTM: - brdp->clk = CD1400_CLK8M; - /* fall thru */ - case EIO_8PORTRS: - case EIO_8PORTDI: - brdp->nrports = 8; - break; - case EIO_4PORTRS: - brdp->nrports = 4; - break; - case EIO_MK3: - switch (status & EIO_BRDMASK) { - case ID_BRD4: - brdp->nrports = 4; - break; - case ID_BRD8: - brdp->nrports = 8; - break; - case ID_BRD16: - brdp->nrports = 16; - break; - default: - return(-ENODEV); - } - break; - default: - return(-ENODEV); - } - -/* - * We have verfied that the board is actually present, so now we - * can complete the setup. - */ - request_region(brdp->ioaddr1, brdp->iosize1, name); - if (brdp->iosize2 > 0) - request_region(brdp->ioaddr2, brdp->iosize2, name); - - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlpanel_t)); - return(-ENOMEM); - } - memset(panelp, 0, sizeof(stlpanel_t)); - - panelp->magic = STL_PANELMAGIC; - panelp->brdnr = brdp->brdnr; - panelp->panelnr = 0; - panelp->nrports = brdp->nrports; - panelp->iobase = brdp->ioaddr1; - panelp->hwid = status; - if ((status & EIO_IDBITMASK) == EIO_MK3) { - panelp->uartp = (void *) &stl_sc26198uart; - panelp->isr = stl_sc26198intr; - } else { - panelp->uartp = (void *) &stl_cd1400uart; - panelp->isr = stl_cd1400eiointr; - } - - brdp->panels[0] = panelp; - brdp->nrpanels = 1; - brdp->state |= BRD_FOUND; - brdp->hwid = status; - rc = stl_mapirq(brdp->irq, name); - return(rc); -} - -/*****************************************************************************/ - -/* - * Try to find an ECH board and initialize it. This code is capable of - * dealing with all types of ECH board. - */ - -static int inline stl_initech(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status, nxtid, ioaddr, conflict; - int panelnr, banknr, i; - char *name; - -#if DEBUG - printk("stl_initech(brdp=%x)\n", (int) brdp); -#endif - - status = 0; - conflict = 0; - -/* - * Set up the initial board register contents for boards. This varies a - * bit between the different board types. So we need to handle each - * separately. Also do a check that the supplied IRQ is good. - */ - switch (brdp->brdtype) { - - case BRD_ECH: - brdp->isr = stl_echatintr; - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 1; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(-EINVAL); - } - status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); - status |= (stl_vecmap[brdp->irq] << 1); - outb((status | ECH_BRDRESET), brdp->ioaddr1); - brdp->ioctrlval = ECH_INTENABLE | - ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); - for (i = 0; (i < 10); i++) - outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - brdp->iosize1 = 2; - brdp->iosize2 = 32; - name = "serial(EC8/32)"; - outb(status, brdp->ioaddr1); - break; - - case BRD_ECHMC: - brdp->isr = stl_echmcaintr; - brdp->ioctrl = brdp->ioaddr1 + 0x20; - brdp->iostatus = brdp->ioctrl; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(-EINVAL); - } - outb(ECHMC_BRDRESET, brdp->ioctrl); - outb(ECHMC_INTENABLE, brdp->ioctrl); - brdp->iosize1 = 64; - name = "serial(EC8/32-MC)"; - break; - - case BRD_ECHPCI: - brdp->isr = stl_echpciintr; - brdp->ioctrl = brdp->ioaddr1 + 2; - brdp->iosize1 = 4; - brdp->iosize2 = 8; - name = "serial(EC8/32-PCI)"; - break; - - case BRD_ECH64PCI: - brdp->isr = stl_echpci64intr; - brdp->ioctrl = brdp->ioaddr2 + 0x40; - outb(0x43, (brdp->ioaddr1 + 0x4c)); - brdp->iosize1 = 0x80; - brdp->iosize2 = 0x80; - name = "serial(EC8/64-PCI)"; - break; - - default: - printk("STALLION: unknown board type=%d\n", brdp->brdtype); - return(-EINVAL); - break; - } - -/* - * Check boards for possible IO address conflicts. We won't actually - * do anything about it here, just issue a warning... - */ - conflict = check_region(brdp->ioaddr1, brdp->iosize1) ? - brdp->ioaddr1 : 0; - if ((conflict == 0) && (brdp->iosize2 > 0)) - conflict = check_region(brdp->ioaddr2, brdp->iosize2) ? - brdp->ioaddr2 : 0; - if (conflict) { - printk("STALLION: Warning, board %d I/O address %x conflicts " - "with another device\n", brdp->brdnr, conflict); - } - - request_region(brdp->ioaddr1, brdp->iosize1, name); - if (brdp->iosize2 > 0) - request_region(brdp->ioaddr2, brdp->iosize2, name); - -/* - * Scan through the secondary io address space looking for panels. - * As we find'em allocate and initialize panel structures for each. - */ - brdp->clk = CD1400_CLK; - brdp->hwid = status; - - ioaddr = brdp->ioaddr2; - banknr = 0; - panelnr = 0; - nxtid = 0; - - for (i = 0; (i < STL_MAXPANELS); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb(nxtid, brdp->ioctrl); - ioaddr = brdp->ioaddr2; - } - status = inb(ioaddr + ECH_PNLSTATUS); - if ((status & ECH_PNLIDMASK) != nxtid) - break; - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { - printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlpanel_t)); - break; - } - memset(panelp, 0, sizeof(stlpanel_t)); - panelp->magic = STL_PANELMAGIC; - panelp->brdnr = brdp->brdnr; - panelp->panelnr = panelnr; - panelp->iobase = ioaddr; - panelp->pagenr = nxtid; - panelp->hwid = status; - brdp->bnk2panel[banknr] = panelp; - brdp->bnkpageaddr[banknr] = nxtid; - brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; - - if (status & ECH_PNLXPID) { - panelp->uartp = (void *) &stl_sc26198uart; - panelp->isr = stl_sc26198intr; - if (status & ECH_PNL16PORT) { - panelp->nrports = 16; - brdp->bnk2panel[banknr] = panelp; - brdp->bnkpageaddr[banknr] = nxtid; - brdp->bnkstataddr[banknr++] = ioaddr + 4 + - ECH_PNLSTATUS; - } else { - panelp->nrports = 8; - } - } else { - panelp->uartp = (void *) &stl_cd1400uart; - panelp->isr = stl_cd1400echintr; - if (status & ECH_PNL16PORT) { - panelp->nrports = 16; - panelp->ackmask = 0x80; - if (brdp->brdtype != BRD_ECHPCI) - ioaddr += EREG_BANKSIZE; - brdp->bnk2panel[banknr] = panelp; - brdp->bnkpageaddr[banknr] = ++nxtid; - brdp->bnkstataddr[banknr++] = ioaddr + - ECH_PNLSTATUS; - } else { - panelp->nrports = 8; - panelp->ackmask = 0xc0; - } - } - - nxtid++; - ioaddr += EREG_BANKSIZE; - brdp->nrports += panelp->nrports; - brdp->panels[panelnr++] = panelp; - if ((brdp->brdtype != BRD_ECHPCI) && - (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) - break; - } - - brdp->nrpanels = panelnr; - brdp->nrbnks = banknr; - if (brdp->brdtype == BRD_ECH) - outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); - - brdp->state |= BRD_FOUND; - i = stl_mapirq(brdp->irq, name); - return(i); -} - -/*****************************************************************************/ - -/* - * Initialize and configure the specified board. - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is very different. - */ - -static int __init stl_brdinit(stlbrd_t *brdp) -{ - int i; - -#if DEBUG - printk("stl_brdinit(brdp=%x)\n", (int) brdp); -#endif - - switch (brdp->brdtype) { - case BRD_EASYIO: - case BRD_EASYIOPCI: - stl_initeio(brdp); - break; - case BRD_ECH: - case BRD_ECHMC: - case BRD_ECHPCI: - case BRD_ECH64PCI: - stl_initech(brdp); - break; - default: - printk("STALLION: board=%d is unknown board type=%d\n", - brdp->brdnr, brdp->brdtype); - return(ENODEV); - } - - stl_brds[brdp->brdnr] = brdp; - if ((brdp->state & BRD_FOUND) == 0) { - printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", - stl_brdnames[brdp->brdtype], brdp->brdnr, - brdp->ioaddr1, brdp->irq); - return(ENODEV); - } - - for (i = 0; (i < STL_MAXPANELS); i++) - if (brdp->panels[i] != (stlpanel_t *) NULL) - stl_initports(brdp, brdp->panels[i]); - - printk("STALLION: %s found, board=%d io=%x irq=%d " - "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], - brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, - brdp->nrports); - return(0); -} - -/*****************************************************************************/ - -/* - * Find the next available board number that is free. - */ - -static inline int stl_getbrdnr() -{ - int i; - - for (i = 0; (i < STL_MAXBRDS); i++) { - if (stl_brds[i] == (stlbrd_t *) NULL) { - if (i >= stl_nrbrds) - stl_nrbrds = i + 1; - return(i); - } - } - return(-1); -} - -/*****************************************************************************/ - -#ifdef CONFIG_PCI - -/* - * We have a Stallion board. Allocate a board structure and - * initialize it. Read its IO and IRQ resources from PCI - * configuration space. - */ - -static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) -{ - stlbrd_t *brdp; - -#if DEBUG - printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, - devp->bus->number, devp->devfn); -#endif - - if (pci_enable_device(devp)) - return(-EIO); - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - return(-ENOMEM); - if ((brdp->brdnr = stl_getbrdnr()) < 0) { - printk("STALLION: too many boards found, " - "maximum supported %d\n", STL_MAXBRDS); - return(0); - } - brdp->brdtype = brdtype; - -/* - * Different Stallion boards use the BAR registers in different ways, - * so set up io addresses based on board type. - */ -#if DEBUG - printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, - pci_resource_start(devp, 0), pci_resource_start(devp, 1), - pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); -#endif - -/* - * We have all resources from the board, so let's setup the actual - * board structure now. - */ - switch (brdtype) { - case BRD_ECHPCI: - brdp->ioaddr2 = pci_resource_start(devp, 0); - brdp->ioaddr1 = pci_resource_start(devp, 1); - break; - case BRD_ECH64PCI: - brdp->ioaddr2 = pci_resource_start(devp, 2); - brdp->ioaddr1 = pci_resource_start(devp, 1); - break; - case BRD_EASYIOPCI: - brdp->ioaddr1 = pci_resource_start(devp, 2); - brdp->ioaddr2 = pci_resource_start(devp, 1); - break; - default: - printk("STALLION: unknown PCI board type=%d\n", brdtype); - break; - } - - brdp->irq = devp->irq; - stl_brdinit(brdp); - - return(0); -} - -/*****************************************************************************/ - -/* - * Find all Stallion PCI boards that might be installed. Initialize each - * one as it is found. - */ - - -static inline int stl_findpcibrds() -{ - struct pci_dev *dev = NULL; - int i, rc; - -#if DEBUG - printk("stl_findpcibrds()\n"); -#endif - - if (! pci_present()) - return(0); - - for (i = 0; (i < stl_nrpcibrds); i++) - while ((dev = pci_find_device(stl_pcibrds[i].vendid, - stl_pcibrds[i].devid, dev))) { - -/* - * Found a device on the PCI bus that has our vendor and - * device ID. Need to check now that it is really us. - */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) - continue; - - rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev); - if (rc) - return(rc); - } - - return(0); -} - -#endif - -/*****************************************************************************/ - -/* - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is too different. - */ - -static inline int stl_initbrds() -{ - stlbrd_t *brdp; - stlconf_t *confp; - int i; - -#if DEBUG - printk("stl_initbrds()\n"); -#endif - - if (stl_nrbrds > STL_MAXBRDS) { - printk("STALLION: too many boards in configuration table, " - "truncating to %d\n", STL_MAXBRDS); - stl_nrbrds = STL_MAXBRDS; - } - -/* - * Firstly scan the list of static boards configured. Allocate - * resources and initialize the boards as found. - */ - for (i = 0; (i < stl_nrbrds); i++) { - confp = &stl_brdconf[i]; -#ifdef MODULE - stl_parsebrd(confp, stl_brdsp[i]); -#endif - if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) - return(-ENOMEM); - brdp->brdnr = i; - brdp->brdtype = confp->brdtype; - brdp->ioaddr1 = confp->ioaddr1; - brdp->ioaddr2 = confp->ioaddr2; - brdp->irq = confp->irq; - brdp->irqtype = confp->irqtype; - stl_brdinit(brdp); - } - -/* - * Find any dynamically supported boards. That is via module load - * line options or auto-detected on the PCI bus. - */ -#ifdef MODULE - stl_argbrds(); -#endif -#ifdef CONFIG_PCI - stl_findpcibrds(); -#endif - - return(0); -} - -/*****************************************************************************/ - -/* - * Return the board stats structure to user app. - */ - -static int stl_getbrdstats(combrd_t *bp) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - int i; - - copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)); - if (stl_brdstats.brd >= STL_MAXBRDS) - return(-ENODEV); - brdp = stl_brds[stl_brdstats.brd]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - - memset(&stl_brdstats, 0, sizeof(combrd_t)); - stl_brdstats.brd = brdp->brdnr; - stl_brdstats.type = brdp->brdtype; - stl_brdstats.hwid = brdp->hwid; - stl_brdstats.state = brdp->state; - stl_brdstats.ioaddr = brdp->ioaddr1; - stl_brdstats.ioaddr2 = brdp->ioaddr2; - stl_brdstats.irq = brdp->irq; - stl_brdstats.nrpanels = brdp->nrpanels; - stl_brdstats.nrports = brdp->nrports; - for (i = 0; (i < brdp->nrpanels); i++) { - panelp = brdp->panels[i]; - stl_brdstats.panels[i].panel = i; - stl_brdstats.panels[i].hwid = panelp->hwid; - stl_brdstats.panels[i].nrports = panelp->nrports; - } - - copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Resolve the referenced port number into a port struct pointer. - */ - -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - - if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) - return((stlport_t *) NULL); - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return((stlport_t *) NULL); - if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) - return((stlport_t *) NULL); - panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - return((stlport_t *) NULL); - if ((portnr < 0) || (portnr >= panelp->nrports)) - return((stlport_t *) NULL); - return(panelp->ports[portnr]); -} - -/*****************************************************************************/ - -/* - * Return the port stats structure to user app. A NULL port struct - * pointer passed in means that we need to find out from the app - * what port to get stats for (used through board control device). - */ - -static int stl_getportstats(stlport_t *portp, comstats_t *cp) -{ - unsigned char *head, *tail; - unsigned long flags; - - if (portp == (stlport_t *) NULL) { - copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, - stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - portp->stats.state = portp->istate; - portp->stats.flags = portp->flags; - portp->stats.hwid = portp->hwid; - - portp->stats.ttystate = 0; - portp->stats.cflags = 0; - portp->stats.iflags = 0; - portp->stats.oflags = 0; - portp->stats.lflags = 0; - portp->stats.rxbuffered = 0; - - save_flags(flags); - cli(); - if (portp->tty != (struct tty_struct *) NULL) { - if (portp->tty->driver_data == portp) { - portp->stats.ttystate = portp->tty->flags; - portp->stats.rxbuffered = portp->tty->flip.count; - if (portp->tty->termios != (struct termios *) NULL) { - portp->stats.cflags = portp->tty->termios->c_cflag; - portp->stats.iflags = portp->tty->termios->c_iflag; - portp->stats.oflags = portp->tty->termios->c_oflag; - portp->stats.lflags = portp->tty->termios->c_lflag; - } - } - } - restore_flags(flags); - - head = portp->tx.head; - tail = portp->tx.tail; - portp->stats.txbuffered = ((head >= tail) ? (head - tail) : - (STL_TXBUFSIZE - (tail - head))); - - portp->stats.signals = (unsigned long) stl_getsignals(portp); - - copy_to_user(cp, &portp->stats, sizeof(comstats_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Clear the port stats structure. We also return it zeroed out... - */ - -static int stl_clrportstats(stlport_t *portp, comstats_t *cp) -{ - if (portp == (stlport_t *) NULL) { - copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, - stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - memset(&portp->stats, 0, sizeof(comstats_t)); - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - copy_to_user(cp, &portp->stats, sizeof(comstats_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Return the entire driver ports structure to a user app. - */ - -static int stl_getportstruct(unsigned long arg) -{ - stlport_t *portp; - - copy_from_user(&stl_dummyport, (void *) arg, sizeof(stlport_t)); - portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, - stl_dummyport.portnr); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - copy_to_user((void *) arg, portp, sizeof(stlport_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * Return the entire driver board structure to a user app. - */ - -static int stl_getbrdstruct(unsigned long arg) -{ - stlbrd_t *brdp; - - copy_from_user(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t)); - if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) - return(-ENODEV); - brdp = stl_brds[stl_dummybrd.brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - copy_to_user((void *) arg, brdp, sizeof(stlbrd_t)); - return(0); -} - -/*****************************************************************************/ - -/* - * The "staliomem" device is also required to do some special operations - * on the board and/or ports. In this driver it is mostly used for stats - * collection. - */ - -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) -{ - int brdnr, rc; - -#if DEBUG - printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, - (int) fp, cmd, (int) arg); -#endif - - brdnr = MINOR(ip->i_rdev); - if (brdnr >= STL_MAXBRDS) - return(-ENODEV); - rc = 0; - - switch (cmd) { - case COM_GETPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_getportstats((stlport_t *) NULL, - (comstats_t *) arg); - break; - case COM_CLRPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stl_clrportstats((stlport_t *) NULL, - (comstats_t *) arg); - break; - case COM_GETBRDSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(combrd_t))) == 0) - rc = stl_getbrdstats((combrd_t *) arg); - break; - case COM_READPORT: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(stlport_t))) == 0) - rc = stl_getportstruct(arg); - break; - case COM_READBOARD: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(stlbrd_t))) == 0) - rc = stl_getbrdstruct(arg); - break; - default: - rc = -ENOIOCTLCMD; - break; - } - - return(rc); -} - -/*****************************************************************************/ - -int __init stl_init(void) -{ - printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); - - stl_initbrds(); - -/* - * Allocate a temporary write buffer. - */ - stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (stl_tmpwritebuf == (char *) NULL) - printk("STALLION: failed to allocate memory (size=%d)\n", - STL_TXBUFSIZE); - -/* - * Set up a character driver for per board stuff. This is mainly used - * to do stats ioctls on the ports. - */ - if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) - printk("STALLION: failed to register serial board device\n"); - devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL); - devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, - STL_SIOMEMMAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &stl_fsiomem, NULL); - -/* - * Set up the tty driver structure and register us as a driver. - * Also setup the callout tty device. - */ - memset(&stl_serial, 0, sizeof(struct tty_driver)); - stl_serial.magic = TTY_DRIVER_MAGIC; - stl_serial.driver_name = stl_drvname; - stl_serial.name = stl_serialname; - stl_serial.major = STL_SERIALMAJOR; - stl_serial.minor_start = 0; - stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; - stl_serial.type = TTY_DRIVER_TYPE_SERIAL; - stl_serial.subtype = STL_DRVTYPSERIAL; - stl_serial.init_termios = stl_deftermios; - stl_serial.flags = TTY_DRIVER_REAL_RAW; - stl_serial.refcount = &stl_refcount; - stl_serial.table = stl_ttys; - stl_serial.termios = stl_termios; - stl_serial.termios_locked = stl_termioslocked; - - stl_serial.open = stl_open; - stl_serial.close = stl_close; - stl_serial.write = stl_write; - stl_serial.put_char = stl_putchar; - stl_serial.flush_chars = stl_flushchars; - stl_serial.write_room = stl_writeroom; - stl_serial.chars_in_buffer = stl_charsinbuffer; - stl_serial.ioctl = stl_ioctl; - stl_serial.set_termios = stl_settermios; - stl_serial.throttle = stl_throttle; - stl_serial.unthrottle = stl_unthrottle; - stl_serial.stop = stl_stop; - stl_serial.start = stl_start; - stl_serial.hangup = stl_hangup; - stl_serial.flush_buffer = stl_flushbuffer; - stl_serial.break_ctl = stl_breakctl; - stl_serial.wait_until_sent = stl_waituntilsent; - stl_serial.send_xchar = stl_sendxchar; - stl_serial.read_proc = stl_readproc; - - stl_callout = stl_serial; - stl_callout.name = stl_calloutname; - stl_callout.major = STL_CALLOUTMAJOR; - stl_callout.subtype = STL_DRVTYPCALLOUT; - stl_callout.read_proc = 0; - - if (tty_register_driver(&stl_serial)) - printk("STALLION: failed to register serial driver\n"); - if (tty_register_driver(&stl_callout)) - printk("STALLION: failed to register callout driver\n"); - - return(0); -} - -/*****************************************************************************/ -/* CD1400 HARDWARE FUNCTIONS */ -/*****************************************************************************/ - -/* - * These functions get/set/update the registers of the cd1400 UARTs. - * Access to the cd1400 registers is via an address/data io port pair. - * (Maybe should make this inline...) - */ - -static int stl_cd1400getreg(stlport_t *portp, int regnr) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - return(inb(portp->ioaddr + EREG_DATA)); -} - -static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - outb(value, portp->ioaddr + EREG_DATA); -} - -static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - if (inb(portp->ioaddr + EREG_DATA) != value) { - outb(value, portp->ioaddr + EREG_DATA); - return(1); - } - return(0); -} - -/*****************************************************************************/ - -/* - * Inbitialize the UARTs in a panel. We don't care what sort of board - * these ports are on - since the port io registers are almost - * identical when dealing with ports. - */ - -static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) -{ - unsigned int gfrcr; - int chipmask, i, j; - int nrchips, uartaddr, ioaddr; - -#if DEBUG - printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); -#endif - - BRDENABLE(panelp->brdnr, panelp->pagenr); - -/* - * Check that each chip is present and started up OK. - */ - chipmask = 0; - nrchips = panelp->nrports / CD1400_PORTS; - for (i = 0; (i < nrchips); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); - ioaddr = panelp->iobase; - } else { - ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); - } - uartaddr = (i & 0x01) ? 0x080 : 0; - outb((GFRCR + uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); - outb((CCR + uartaddr), ioaddr); - outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); - outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); - outb((GFRCR + uartaddr), ioaddr); - for (j = 0; (j < CCR_MAXWAIT); j++) { - if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) - break; - } - if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { - printk("STALLION: cd1400 not responding, " - "brd=%d panel=%d chip=%d\n", - panelp->brdnr, panelp->panelnr, i); - continue; - } - chipmask |= (0x1 << i); - outb((PPR + uartaddr), ioaddr); - outb(PPR_SCALAR, (ioaddr + EREG_DATA)); - } - - BRDDISABLE(panelp->brdnr); - return(chipmask); -} - -/*****************************************************************************/ - -/* - * Initialize hardware specific port registers. - */ - -static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) -{ -#if DEBUG - printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", - (int) brdp, (int) panelp, (int) portp); -#endif - - if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || - (portp == (stlport_t *) NULL)) - return; - - portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || - (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); - portp->uartaddr = (portp->portnr & 0x04) << 5; - portp->pagenr = panelp->pagenr + (portp->portnr >> 3); - - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); - portp->hwid = stl_cd1400getreg(portp, GFRCR); - BRDDISABLE(portp->brdnr); -} - -/*****************************************************************************/ - -/* - * Wait for the command register to be ready. We will poll this, - * since it won't usually take too long to be ready. - */ - -static void stl_cd1400ccrwait(stlport_t *portp) -{ - int i; - - for (i = 0; (i < CCR_MAXWAIT); i++) { - if (stl_cd1400getreg(portp, CCR) == 0) { - return; - } - } - - printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n", - portp->portnr, portp->panelnr, portp->brdnr); -} - -/*****************************************************************************/ - -/* - * Set up the cd1400 registers for a port based on the termios port - * settings. - */ - -static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) -{ - stlbrd_t *brdp; - unsigned long flags; - unsigned int clkdiv, baudrate; - unsigned char cor1, cor2, cor3; - unsigned char cor4, cor5, ccr; - unsigned char srer, sreron, sreroff; - unsigned char mcor1, mcor2, rtpr; - unsigned char clk, div; - - cor1 = 0; - cor2 = 0; - cor3 = 0; - cor4 = 0; - cor5 = 0; - ccr = 0; - rtpr = 0; - clk = 0; - div = 0; - mcor1 = 0; - mcor2 = 0; - sreron = 0; - sreroff = 0; - - brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) - return; - -/* - * Set up the RX char ignore mask with those RX error types we - * can ignore. We can get the cd1400 to help us out a little here, - * it will ignore parity errors and breaks for us. - */ - portp->rxignoremsk = 0; - if (tiosp->c_iflag & IGNPAR) { - portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); - cor1 |= COR1_PARIGNORE; - } - if (tiosp->c_iflag & IGNBRK) { - portp->rxignoremsk |= ST_BREAK; - cor4 |= COR4_IGNBRK; - } - - portp->rxmarkmsk = ST_OVERRUN; - if (tiosp->c_iflag & (INPCK | PARMRK)) - portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); - if (tiosp->c_iflag & BRKINT) - portp->rxmarkmsk |= ST_BREAK; - -/* - * Go through the char size, parity and stop bits and set all the - * option register appropriately. - */ - switch (tiosp->c_cflag & CSIZE) { - case CS5: - cor1 |= COR1_CHL5; - break; - case CS6: - cor1 |= COR1_CHL6; - break; - case CS7: - cor1 |= COR1_CHL7; - break; - default: - cor1 |= COR1_CHL8; - break; - } - - if (tiosp->c_cflag & CSTOPB) - cor1 |= COR1_STOP2; - else - cor1 |= COR1_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - cor1 |= (COR1_PARENB | COR1_PARODD); - else - cor1 |= (COR1_PARENB | COR1_PAREVEN); - } else { - cor1 |= COR1_PARNONE; - } - -/* - * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing - * space for hardware flow control and the like. This should be set to - * VMIN. Also here we will set the RX data timeout to 10ms - this should - * really be based on VTIME. - */ - cor3 |= FIFO_RXTHRESHOLD; - rtpr = 2; - -/* - * Calculate the baud rate timers. For now we will just assume that - * the input and output baud are the same. Could have used a baud - * table here, but this way we can generate virtually any baud rate - * we like! - */ - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; - if ((baudrate < 1) || (baudrate > 4)) - tiosp->c_cflag &= ~CBAUDEX; - else - baudrate += 15; - } - baudrate = stl_baudrates[baudrate]; - if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) - baudrate = (portp->baud_base / portp->custom_divisor); - } - if (baudrate > STL_CD1400MAXBAUD) - baudrate = STL_CD1400MAXBAUD; - - if (baudrate > 0) { - for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { - clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); - if (clkdiv < 0x100) - break; - } - div = (unsigned char) clkdiv; - } - -/* - * Check what form of modem signaling is required and set it up. - */ - if ((tiosp->c_cflag & CLOCAL) == 0) { - mcor1 |= MCOR1_DCD; - mcor2 |= MCOR2_DCD; - sreron |= SRER_MODEM; - portp->flags |= ASYNC_CHECK_CD; - } else { - portp->flags &= ~ASYNC_CHECK_CD; - } - -/* - * Setup cd1400 enhanced modes if we can. In particular we want to - * handle as much of the flow control as possible automatically. As - * well as saving a few CPU cycles it will also greatly improve flow - * control reliability. - */ - if (tiosp->c_iflag & IXON) { - cor2 |= COR2_TXIBE; - cor3 |= COR3_SCD12; - if (tiosp->c_iflag & IXANY) - cor2 |= COR2_IXM; - } - - if (tiosp->c_cflag & CRTSCTS) { - cor2 |= COR2_CTSAE; - mcor1 |= FIFO_RTSTHRESHOLD; - } - -/* - * All cd1400 register values calculated so go through and set - * them all up. - */ - -#if DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", - portp->portnr, portp->panelnr, portp->brdnr); - printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", - cor1, cor2, cor3, cor4, cor5); - printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", - mcor1, mcor2, rtpr, sreron, sreroff); - printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); - srer = stl_cd1400getreg(portp, SRER); - stl_cd1400setreg(portp, SRER, 0); - if (stl_cd1400updatereg(portp, COR1, cor1)) - ccr = 1; - if (stl_cd1400updatereg(portp, COR2, cor2)) - ccr = 1; - if (stl_cd1400updatereg(portp, COR3, cor3)) - ccr = 1; - if (ccr) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_CORCHANGE); - } - stl_cd1400setreg(portp, COR4, cor4); - stl_cd1400setreg(portp, COR5, cor5); - stl_cd1400setreg(portp, MCOR1, mcor1); - stl_cd1400setreg(portp, MCOR2, mcor2); - if (baudrate > 0) { - stl_cd1400setreg(portp, TCOR, clk); - stl_cd1400setreg(portp, TBPR, div); - stl_cd1400setreg(portp, RCOR, clk); - stl_cd1400setreg(portp, RBPR, div); - } - stl_cd1400setreg(portp, SCHR1, tiosp->c_cc[VSTART]); - stl_cd1400setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); - stl_cd1400setreg(portp, SCHR3, tiosp->c_cc[VSTART]); - stl_cd1400setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); - stl_cd1400setreg(portp, RTPR, rtpr); - mcor1 = stl_cd1400getreg(portp, MSVR1); - if (mcor1 & MSVR1_DCD) - portp->sigs |= TIOCM_CD; - else - portp->sigs &= ~TIOCM_CD; - stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Set the state of the DTR and RTS signals. - */ - -static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) -{ - unsigned char msvr1, msvr2; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", - (int) portp, dtr, rts); -#endif - - msvr1 = 0; - msvr2 = 0; - if (dtr > 0) - msvr1 = MSVR1_DTR; - if (rts > 0) - msvr2 = MSVR2_RTS; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - if (rts >= 0) - stl_cd1400setreg(portp, MSVR2, msvr2); - if (dtr >= 0) - stl_cd1400setreg(portp, MSVR1, msvr1); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the state of the signals. - */ - -static int stl_cd1400getsignals(stlport_t *portp) -{ - unsigned char msvr1, msvr2; - unsigned long flags; - int sigs; - -#if DEBUG - printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - msvr1 = stl_cd1400getreg(portp, MSVR1); - msvr2 = stl_cd1400getreg(portp, MSVR2); - BRDDISABLE(portp->brdnr); - restore_flags(flags); - - sigs = 0; - sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; - sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; - sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; - sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; -#if 0 - sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; - sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; -#else - sigs |= TIOCM_DSR; -#endif - return(sigs); -} - -/*****************************************************************************/ - -/* - * Enable/Disable the Transmitter and/or Receiver. - */ - -static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char ccr; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - ccr = 0; - - if (tx == 0) - ccr |= CCR_TXDISABLE; - else if (tx > 0) - ccr |= CCR_TXENABLE; - if (rx == 0) - ccr |= CCR_RXDISABLE; - else if (rx > 0) - ccr |= CCR_RXENABLE; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, ccr); - stl_cd1400ccrwait(portp); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Start/stop the Transmitter and/or Receiver. - */ - -static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char sreron, sreroff; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - - sreron = 0; - sreroff = 0; - if (tx == 0) - sreroff |= (SRER_TXDATA | SRER_TXEMPTY); - else if (tx == 1) - sreron |= SRER_TXDATA; - else if (tx >= 2) - sreron |= SRER_TXEMPTY; - if (rx == 0) - sreroff |= SRER_RXDATA; - else if (rx > 0) - sreron |= SRER_RXDATA; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, SRER, - ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - if (tx > 0) - set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Disable all interrupts from this port. - */ - -static void stl_cd1400disableintrs(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); -#endif - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, SRER, 0); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_cd1400sendbreak(stlport_t *portp, int len) -{ - unsigned long flags; - -#if DEBUG - printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400setreg(portp, SRER, - ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | - SRER_TXEMPTY)); - BRDDISABLE(portp->brdnr); - portp->brklen = len; - if (len == 1) - portp->stats.txbreaks++; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Take flow control actions... - */ - -static void stl_cd1400flowctrl(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - - if (state) { - if (tty->termios->c_iflag & IXOFF) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); - portp->stats.rxxon++; - stl_cd1400ccrwait(portp); - } -/* - * Question: should we return RTS to what it was before? It may - * have been set by an ioctl... Suppose not, since if you have - * hardware flow control set then it is pretty silly to go and - * set the RTS line by hand. - */ - if (tty->termios->c_cflag & CRTSCTS) { - stl_cd1400setreg(portp, MCOR1, - (stl_cd1400getreg(portp, MCOR1) | - FIFO_RTSTHRESHOLD)); - stl_cd1400setreg(portp, MSVR2, MSVR2_RTS); - portp->stats.rxrtson++; - } - } else { - if (tty->termios->c_iflag & IXOFF) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); - portp->stats.rxxoff++; - stl_cd1400ccrwait(portp); - } - if (tty->termios->c_cflag & CRTSCTS) { - stl_cd1400setreg(portp, MCOR1, - (stl_cd1400getreg(portp, MCOR1) & 0xf0)); - stl_cd1400setreg(portp, MSVR2, 0); - portp->stats.rxrtsoff++; - } - } - - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Send a flow control character... - */ - -static void stl_cd1400sendflow(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - -#if DEBUG - printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - if (state) { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); - portp->stats.rxxon++; - stl_cd1400ccrwait(portp); - } else { - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); - portp->stats.rxxoff++; - stl_cd1400ccrwait(portp); - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_cd1400flush(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_cd1400flush(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); - stl_cd1400ccrwait(portp); - stl_cd1400setreg(portp, CCR, CCR_TXFLUSHFIFO); - stl_cd1400ccrwait(portp); - portp->tx.tail = portp->tx.head; - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the current state of data flow on this port. This is only - * really interresting when determining if data has fully completed - * transmission or not... This is easy for the cd1400, it accurately - * maintains the busy port flag. - */ - -static int stl_cd1400datastate(stlport_t *portp) -{ -#if DEBUG - printk("stl_cd1400datastate(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return(0); - - return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for cd1400 EasyIO boards. - */ - -static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) -{ - unsigned char svrtype; - -#if DEBUG - printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", - (int) panelp, iobase); -#endif - - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - if (panelp->nrports > 4) { - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - } - - if (svrtype & SVRR_RX) - stl_cd1400rxisr(panelp, iobase); - else if (svrtype & SVRR_TX) - stl_cd1400txisr(panelp, iobase); - else if (svrtype & SVRR_MDM) - stl_cd1400mdmisr(panelp, iobase); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for cd1400 panels. - */ - -static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) -{ - unsigned char svrtype; - -#if DEBUG - printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, - iobase); -#endif - - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - if (svrtype & SVRR_RX) - stl_cd1400rxisr(panelp, iobase); - else if (svrtype & SVRR_TX) - stl_cd1400txisr(panelp, iobase); - else if (svrtype & SVRR_MDM) - stl_cd1400mdmisr(panelp, iobase); -} - - -/*****************************************************************************/ - -/* - * Unfortunately we need to handle breaks in the TX data stream, since - * this is the only way to generate them on the cd1400. - */ - -static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) -{ - if (portp->brklen == 1) { - outb((COR2 + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) | COR2_ETC), - (ioaddr + EREG_DATA)); - outb((TDR + portp->uartaddr), ioaddr); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_STARTBREAK, (ioaddr + EREG_DATA)); - outb((SRER + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) & ~(SRER_TXDATA | SRER_TXEMPTY)), - (ioaddr + EREG_DATA)); - return(1); - } else if (portp->brklen > 1) { - outb((TDR + portp->uartaddr), ioaddr); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); - portp->brklen = -1; - return(1); - } else { - outb((COR2 + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), - (ioaddr + EREG_DATA)); - portp->brklen = 0; - } - return(0); -} - -/*****************************************************************************/ - -/* - * Transmit interrupt handler. This has gotta be fast! Handling TX - * chars is pretty simple, stuff as many as possible from the TX buffer - * into the cd1400 FIFO. Must also handle TX breaks here, since they - * are embedded as commands in the data stream. Oh no, had to use a goto! - * This could be optimized more, will do when I get time... - * In practice it is possible that interrupts are enabled but that the - * port has been hung up. Need to handle not having any TX buffer here, - * this is done by using the side effect that head and tail will also - * be NULL if the buffer has been freed. - */ - -static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - int len, stlen; - char *head, *tail; - unsigned char ioack, srer; - -#if DEBUG - printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_TXACK); - if (((ioack & panelp->ackmask) != 0) || - ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { - printk("STALLION: bad TX interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - -/* - * Unfortunately we need to handle breaks in the data stream, since - * this is the only way to generate them on the cd1400. Do it now if - * a break is to be sent. - */ - if (portp->brklen != 0) - if (stl_cd1400breakisr(portp, ioaddr)) - goto stl_txalldone; - - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((len == 0) || ((len < STL_TXBUFLOW) && - (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { - set_bit(ASYI_TXLOW, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - } - - if (len == 0) { - outb((SRER + portp->uartaddr), ioaddr); - srer = inb(ioaddr + EREG_DATA); - if (srer & SRER_TXDATA) { - srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; - } else { - srer &= ~(SRER_TXDATA | SRER_TXEMPTY); - clear_bit(ASYI_TXBUSY, &portp->istate); - } - outb(srer, (ioaddr + EREG_DATA)); - } else { - len = MIN(len, CD1400_TXFIFOSIZE); - portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); - outb((TDR + portp->uartaddr), ioaddr); - outsb((ioaddr + EREG_DATA), tail, stlen); - len -= stlen; - tail += stlen; - if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) - tail = portp->tx.buf; - if (len > 0) { - outsb((ioaddr + EREG_DATA), tail, len); - tail += len; - } - portp->tx.tail = tail; - } - -stl_txalldone: - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ - -/* - * Receive character interrupt handler. Determine if we have good chars - * or bad chars and then process appropriately. Good chars are easy - * just shove the lot into the RX buffer and set all status byte to 0. - * If a bad RX char then process as required. This routine needs to be - * fast! In practice it is possible that we get an interrupt on a port - * that is closed. This can happen on hangups - since they completely - * shutdown a port not in user context. Need to handle this case. - */ - -static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - struct tty_struct *tty; - unsigned int ioack, len, buflen; - unsigned char status; - char ch; - -#if DEBUG - printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_RXACK); - if ((ioack & panelp->ackmask) != 0) { - printk("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - tty = portp->tty; - - if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { - outb((RDCR + portp->uartaddr), ioaddr); - len = inb(ioaddr + EREG_DATA); - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - len = MIN(len, sizeof(stl_unwanted)); - outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); - portp->stats.rxlost += len; - portp->stats.rxtotal += len; - } else { - len = MIN(len, buflen); - if (len > 0) { - outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; - tty_schedule_flip(tty); - portp->stats.rxtotal += len; - } - } - } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { - outb((RDSR + portp->uartaddr), ioaddr); - status = inb(ioaddr + EREG_DATA); - ch = inb(ioaddr + EREG_DATA); - if (status & ST_PARITY) - portp->stats.rxparity++; - if (status & ST_FRAMING) - portp->stats.rxframing++; - if (status & ST_OVERRUN) - portp->stats.rxoverrun++; - if (status & ST_BREAK) - portp->stats.rxbreaks++; - if (status & ST_SCHARMASK) { - if ((status & ST_SCHARMASK) == ST_SCHAR1) - portp->stats.txxon++; - if ((status & ST_SCHARMASK) == ST_SCHAR2) - portp->stats.txxoff++; - goto stl_rxalldone; - } - if ((tty != (struct tty_struct *) NULL) && - ((portp->rxignoremsk & status) == 0)) { - if (portp->rxmarkmsk & status) { - if (status & ST_BREAK) { - status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { - do_SAK(tty); - BRDENABLE(portp->brdnr, portp->pagenr); - } - } else if (status & ST_PARITY) { - status = TTY_PARITY; - } else if (status & ST_FRAMING) { - status = TTY_FRAME; - } else if(status & ST_OVERRUN) { - status = TTY_OVERRUN; - } else { - status = 0; - } - } else { - status = 0; - } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } - } - } else { - printk("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; - } - -stl_rxalldone: - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ - -/* - * Modem interrupt handler. The is called when the modem signal line - * (DCD) has changed state. Leave most of the work to the off-level - * processing routine. - */ - -static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - unsigned int ioack; - unsigned char misr; - -#if DEBUG - printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp); -#endif - - ioack = inb(ioaddr + EREG_MDACK); - if (((ioack & panelp->ackmask) != 0) || - ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { - printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - - outb((MISR + portp->uartaddr), ioaddr); - misr = inb(ioaddr + EREG_DATA); - if (misr & MISR_DCD) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - portp->stats.modem++; - } - - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ -/* SC26198 HARDWARE FUNCTIONS */ -/*****************************************************************************/ - -/* - * These functions get/set/update the registers of the sc26198 UARTs. - * Access to the sc26198 registers is via an address/data io port pair. - * (Maybe should make this inline...) - */ - -static int stl_sc26198getreg(stlport_t *portp, int regnr) -{ - outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - return(inb(portp->ioaddr + XP_DATA)); -} - -static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) -{ - outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - outb(value, (portp->ioaddr + XP_DATA)); -} - -static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) -{ - outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); - if (inb(portp->ioaddr + XP_DATA) != value) { - outb(value, (portp->ioaddr + XP_DATA)); - return(1); - } - return(0); -} - -/*****************************************************************************/ - -/* - * Functions to get and set the sc26198 global registers. - */ - -static int stl_sc26198getglobreg(stlport_t *portp, int regnr) -{ - outb(regnr, (portp->ioaddr + XP_ADDR)); - return(inb(portp->ioaddr + XP_DATA)); -} - -#if 0 -static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) -{ - outb(regnr, (portp->ioaddr + XP_ADDR)); - outb(value, (portp->ioaddr + XP_DATA)); -} -#endif - -/*****************************************************************************/ - -/* - * Inbitialize the UARTs in a panel. We don't care what sort of board - * these ports are on - since the port io registers are almost - * identical when dealing with ports. - */ - -static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) -{ - int chipmask, i; - int nrchips, ioaddr; - -#if DEBUG - printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", - (int) brdp, (int) panelp); -#endif - - BRDENABLE(panelp->brdnr, panelp->pagenr); - -/* - * Check that each chip is present and started up OK. - */ - chipmask = 0; - nrchips = (panelp->nrports + 4) / SC26198_PORTS; - if (brdp->brdtype == BRD_ECHPCI) - outb(panelp->pagenr, brdp->ioctrl); - - for (i = 0; (i < nrchips); i++) { - ioaddr = panelp->iobase + (i * 4); - outb(SCCR, (ioaddr + XP_ADDR)); - outb(CR_RESETALL, (ioaddr + XP_DATA)); - outb(TSTR, (ioaddr + XP_ADDR)); - if (inb(ioaddr + XP_DATA) != 0) { - printk("STALLION: sc26198 not responding, " - "brd=%d panel=%d chip=%d\n", - panelp->brdnr, panelp->panelnr, i); - continue; - } - chipmask |= (0x1 << i); - outb(GCCR, (ioaddr + XP_ADDR)); - outb(GCCR_IVRTYPCHANACK, (ioaddr + XP_DATA)); - outb(WDTRCR, (ioaddr + XP_ADDR)); - outb(0xff, (ioaddr + XP_DATA)); - } - - BRDDISABLE(panelp->brdnr); - return(chipmask); -} - -/*****************************************************************************/ - -/* - * Initialize hardware specific port registers. - */ - -static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) -{ -#if DEBUG - printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n", - (int) brdp, (int) panelp, (int) portp); -#endif - - if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || - (portp == (stlport_t *) NULL)) - return; - - portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4); - portp->uartaddr = (portp->portnr & 0x07) << 4; - portp->pagenr = panelp->pagenr; - portp->hwid = 0x1; - - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IOPCR, IOPCR_SETSIGS); - BRDDISABLE(portp->brdnr); -} - -/*****************************************************************************/ - -/* - * Set up the sc26198 registers for a port based on the termios port - * settings. - */ - -static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) -{ - stlbrd_t *brdp; - unsigned long flags; - unsigned int baudrate; - unsigned char mr0, mr1, mr2, clk; - unsigned char imron, imroff, iopr, ipr; - - mr0 = 0; - mr1 = 0; - mr2 = 0; - clk = 0; - iopr = 0; - imron = 0; - imroff = 0; - - brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) - return; - -/* - * Set up the RX char ignore mask with those RX error types we - * can ignore. - */ - portp->rxignoremsk = 0; - if (tiosp->c_iflag & IGNPAR) - portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING | - SR_RXOVERRUN); - if (tiosp->c_iflag & IGNBRK) - portp->rxignoremsk |= SR_RXBREAK; - - portp->rxmarkmsk = SR_RXOVERRUN; - if (tiosp->c_iflag & (INPCK | PARMRK)) - portp->rxmarkmsk |= (SR_RXPARITY | SR_RXFRAMING); - if (tiosp->c_iflag & BRKINT) - portp->rxmarkmsk |= SR_RXBREAK; - -/* - * Go through the char size, parity and stop bits and set all the - * option register appropriately. - */ - switch (tiosp->c_cflag & CSIZE) { - case CS5: - mr1 |= MR1_CS5; - break; - case CS6: - mr1 |= MR1_CS6; - break; - case CS7: - mr1 |= MR1_CS7; - break; - default: - mr1 |= MR1_CS8; - break; - } - - if (tiosp->c_cflag & CSTOPB) - mr2 |= MR2_STOP2; - else - mr2 |= MR2_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - mr1 |= (MR1_PARENB | MR1_PARODD); - else - mr1 |= (MR1_PARENB | MR1_PAREVEN); - } else { - mr1 |= MR1_PARNONE; - } - - mr1 |= MR1_ERRBLOCK; - -/* - * Set the RX FIFO threshold at 8 chars. This gives a bit of breathing - * space for hardware flow control and the like. This should be set to - * VMIN. - */ - mr2 |= MR2_RXFIFOHALF; - -/* - * Calculate the baud rate timers. For now we will just assume that - * the input and output baud are the same. The sc26198 has a fixed - * baud rate table, so only discrete baud rates possible. - */ - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; - if ((baudrate < 1) || (baudrate > 4)) - tiosp->c_cflag &= ~CBAUDEX; - else - baudrate += 15; - } - baudrate = stl_baudrates[baudrate]; - if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - baudrate = 230400; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - baudrate = 460800; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) - baudrate = (portp->baud_base / portp->custom_divisor); - } - if (baudrate > STL_SC26198MAXBAUD) - baudrate = STL_SC26198MAXBAUD; - - if (baudrate > 0) { - for (clk = 0; (clk < SC26198_NRBAUDS); clk++) { - if (baudrate <= sc26198_baudtable[clk]) - break; - } - } - -/* - * Check what form of modem signaling is required and set it up. - */ - if (tiosp->c_cflag & CLOCAL) { - portp->flags &= ~ASYNC_CHECK_CD; - } else { - iopr |= IOPR_DCDCOS; - imron |= IR_IOPORT; - portp->flags |= ASYNC_CHECK_CD; - } - -/* - * Setup sc26198 enhanced modes if we can. In particular we want to - * handle as much of the flow control as possible automatically. As - * well as saving a few CPU cycles it will also greatly improve flow - * control reliability. - */ - if (tiosp->c_iflag & IXON) { - mr0 |= MR0_SWFTX | MR0_SWFT; - imron |= IR_XONXOFF; - } else { - imroff |= IR_XONXOFF; - } - if (tiosp->c_iflag & IXOFF) - mr0 |= MR0_SWFRX; - - if (tiosp->c_cflag & CRTSCTS) { - mr2 |= MR2_AUTOCTS; - mr1 |= MR1_AUTORTS; - } - -/* - * All sc26198 register values calculated so go through and set - * them all up. - */ - -#if DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", - portp->portnr, portp->panelnr, portp->brdnr); - printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); - printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IMR, 0); - stl_sc26198updatereg(portp, MR0, mr0); - stl_sc26198updatereg(portp, MR1, mr1); - stl_sc26198setreg(portp, SCCR, CR_RXERRBLOCK); - stl_sc26198updatereg(portp, MR2, mr2); - stl_sc26198updatereg(portp, IOPIOR, - ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr)); - - if (baudrate > 0) { - stl_sc26198setreg(portp, TXCSR, clk); - stl_sc26198setreg(portp, RXCSR, clk); - } - - stl_sc26198setreg(portp, XONCR, tiosp->c_cc[VSTART]); - stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]); - - ipr = stl_sc26198getreg(portp, IPR); - if (ipr & IPR_DCD) - portp->sigs &= ~TIOCM_CD; - else - portp->sigs |= TIOCM_CD; - - portp->imr = (portp->imr & ~imroff) | imron; - stl_sc26198setreg(portp, IMR, portp->imr); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Set the state of the DTR and RTS signals. - */ - -static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) -{ - unsigned char iopioron, iopioroff; - unsigned long flags; - -#if DEBUG - printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", - (int) portp, dtr, rts); -#endif - - iopioron = 0; - iopioroff = 0; - if (dtr == 0) - iopioroff |= IPR_DTR; - else if (dtr > 0) - iopioron |= IPR_DTR; - if (rts == 0) - iopioroff |= IPR_RTS; - else if (rts > 0) - iopioron |= IPR_RTS; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IOPIOR, - ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the state of the signals. - */ - -static int stl_sc26198getsignals(stlport_t *portp) -{ - unsigned char ipr; - unsigned long flags; - int sigs; - -#if DEBUG - printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - ipr = stl_sc26198getreg(portp, IPR); - BRDDISABLE(portp->brdnr); - restore_flags(flags); - - sigs = 0; - sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; - sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS; - sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR; - sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS; - sigs |= TIOCM_DSR; - return(sigs); -} - -/*****************************************************************************/ - -/* - * Enable/Disable the Transmitter and/or Receiver. - */ - -static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char ccr; - unsigned long flags; - -#if DEBUG - printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - - ccr = portp->crenable; - if (tx == 0) - ccr &= ~CR_TXENABLE; - else if (tx > 0) - ccr |= CR_TXENABLE; - if (rx == 0) - ccr &= ~CR_RXENABLE; - else if (rx > 0) - ccr |= CR_RXENABLE; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, SCCR, ccr); - BRDDISABLE(portp->brdnr); - portp->crenable = ccr; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Start/stop the Transmitter and/or Receiver. - */ - -static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char imr; - unsigned long flags; - -#if DEBUG - printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", - (int) portp, rx, tx); -#endif - - imr = portp->imr; - if (tx == 0) - imr &= ~IR_TXRDY; - else if (tx == 1) - imr |= IR_TXRDY; - if (rx == 0) - imr &= ~(IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG); - else if (rx > 0) - imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, IMR, imr); - BRDDISABLE(portp->brdnr); - portp->imr = imr; - if (tx > 0) - set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Disable all interrupts from this port. - */ - -static void stl_sc26198disableintrs(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - portp->imr = 0; - stl_sc26198setreg(portp, IMR, 0); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_sc26198sendbreak(stlport_t *portp, int len) -{ - unsigned long flags; - -#if DEBUG - printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); -#endif - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - if (len == 1) { - stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); - portp->stats.txbreaks++; - } else { - stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Take flow control actions... - */ - -static void stl_sc26198flowctrl(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - unsigned char mr0; - -#if DEBUG - printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - - if (state) { - if (tty->termios->c_iflag & IXOFF) { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); - mr0 |= MR0_SWFRX; - portp->stats.rxxon++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } -/* - * Question: should we return RTS to what it was before? It may - * have been set by an ioctl... Suppose not, since if you have - * hardware flow control set then it is pretty silly to go and - * set the RTS line by hand. - */ - if (tty->termios->c_cflag & CRTSCTS) { - stl_sc26198setreg(portp, MR1, - (stl_sc26198getreg(portp, MR1) | MR1_AUTORTS)); - stl_sc26198setreg(portp, IOPIOR, - (stl_sc26198getreg(portp, IOPIOR) | IOPR_RTS)); - portp->stats.rxrtson++; - } - } else { - if (tty->termios->c_iflag & IXOFF) { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); - mr0 &= ~MR0_SWFRX; - portp->stats.rxxoff++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } - if (tty->termios->c_cflag & CRTSCTS) { - stl_sc26198setreg(portp, MR1, - (stl_sc26198getreg(portp, MR1) & ~MR1_AUTORTS)); - stl_sc26198setreg(portp, IOPIOR, - (stl_sc26198getreg(portp, IOPIOR) & ~IOPR_RTS)); - portp->stats.rxrtsoff++; - } - } - - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Send a flow control character. - */ - -static void stl_sc26198sendflow(stlport_t *portp, int state) -{ - struct tty_struct *tty; - unsigned long flags; - unsigned char mr0; - -#if DEBUG - printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state); -#endif - - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - if (state) { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); - mr0 |= MR0_SWFRX; - portp->stats.rxxon++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } else { - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); - mr0 &= ~MR0_SWFRX; - portp->stats.rxxoff++; - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} - -/*****************************************************************************/ - -static void stl_sc26198flush(stlport_t *portp) -{ - unsigned long flags; - -#if DEBUG - printk("stl_sc26198flush(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_sc26198setreg(portp, SCCR, CR_TXRESET); - stl_sc26198setreg(portp, SCCR, portp->crenable); - BRDDISABLE(portp->brdnr); - portp->tx.tail = portp->tx.head; - restore_flags(flags); -} - -/*****************************************************************************/ - -/* - * Return the current state of data flow on this port. This is only - * really interresting when determining if data has fully completed - * transmission or not... The sc26198 interrupt scheme cannot - * determine when all data has actually drained, so we need to - * check the port statusy register to be sure. - */ - -static int stl_sc26198datastate(stlport_t *portp) -{ - unsigned long flags; - unsigned char sr; - -#if DEBUG - printk("stl_sc26198datastate(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return(0); - if (test_bit(ASYI_TXBUSY, &portp->istate)) - return(1); - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - sr = stl_sc26198getreg(portp, SR); - BRDDISABLE(portp->brdnr); - restore_flags(flags); - - return((sr & SR_TXEMPTY) ? 0 : 1); -} - -/*****************************************************************************/ - -/* - * Delay for a small amount of time, to give the sc26198 a chance - * to process a command... - */ - -static void stl_sc26198wait(stlport_t *portp) -{ - int i; - -#if DEBUG - printk("stl_sc26198wait(portp=%x)\n", (int) portp); -#endif - - if (portp == (stlport_t *) NULL) - return; - - for (i = 0; (i < 20); i++) - stl_sc26198getglobreg(portp, TSTR); -} - -/*****************************************************************************/ - -/* - * If we are TX flow controlled and in IXANY mode then we may - * need to unflow control here. We gotta do this because of the - * automatic flow control modes of the sc26198. - */ - -static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) -{ - unsigned char mr0; - - mr0 = stl_sc26198getreg(portp, MR0); - stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); - stl_sc26198setreg(portp, SCCR, CR_HOSTXON); - stl_sc26198wait(portp); - stl_sc26198setreg(portp, MR0, mr0); - clear_bit(ASYI_TXFLOWED, &portp->istate); -} - -/*****************************************************************************/ - -/* - * Interrupt service routine for sc26198 panels. - */ - -static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) -{ - stlport_t *portp; - unsigned int iack; - -/* - * Work around bug in sc26198 chip... Cannot have A6 address - * line of UART high, else iack will be returned as 0. - */ - outb(0, (iobase + 1)); - - iack = inb(iobase + XP_IACK); - portp = panelp->ports[(iack & IVR_CHANMASK) + ((iobase & 0x4) << 1)]; - - if (iack & IVR_RXDATA) - stl_sc26198rxisr(portp, iack); - else if (iack & IVR_TXDATA) - stl_sc26198txisr(portp); - else - stl_sc26198otherisr(portp, iack); -} - -/*****************************************************************************/ - -/* - * Transmit interrupt handler. This has gotta be fast! Handling TX - * chars is pretty simple, stuff as many as possible from the TX buffer - * into the sc26198 FIFO. - * In practice it is possible that interrupts are enabled but that the - * port has been hung up. Need to handle not having any TX buffer here, - * this is done by using the side effect that head and tail will also - * be NULL if the buffer has been freed. - */ - -static void stl_sc26198txisr(stlport_t *portp) -{ - unsigned int ioaddr; - unsigned char mr0; - int len, stlen; - char *head, *tail; - -#if DEBUG - printk("stl_sc26198txisr(portp=%x)\n", (int) portp); -#endif - - ioaddr = portp->ioaddr; - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((len == 0) || ((len < STL_TXBUFLOW) && - (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { - set_bit(ASYI_TXLOW, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - } - - if (len == 0) { - outb((MR0 | portp->uartaddr), (ioaddr + XP_ADDR)); - mr0 = inb(ioaddr + XP_DATA); - if ((mr0 & MR0_TXMASK) == MR0_TXEMPTY) { - portp->imr &= ~IR_TXRDY; - outb((IMR | portp->uartaddr), (ioaddr + XP_ADDR)); - outb(portp->imr, (ioaddr + XP_DATA)); - clear_bit(ASYI_TXBUSY, &portp->istate); - } else { - mr0 |= ((mr0 & ~MR0_TXMASK) | MR0_TXEMPTY); - outb(mr0, (ioaddr + XP_DATA)); - } - } else { - len = MIN(len, SC26198_TXFIFOSIZE); - portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); - outb(GTXFIFO, (ioaddr + XP_ADDR)); - outsb((ioaddr + XP_DATA), tail, stlen); - len -= stlen; - tail += stlen; - if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) - tail = portp->tx.buf; - if (len > 0) { - outsb((ioaddr + XP_DATA), tail, len); - tail += len; - } - portp->tx.tail = tail; - } -} - -/*****************************************************************************/ - -/* - * Receive character interrupt handler. Determine if we have good chars - * or bad chars and then process appropriately. Good chars are easy - * just shove the lot into the RX buffer and set all status byte to 0. - * If a bad RX char then process as required. This routine needs to be - * fast! In practice it is possible that we get an interrupt on a port - * that is closed. This can happen on hangups - since they completely - * shutdown a port not in user context. Need to handle this case. - */ - -static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) -{ - struct tty_struct *tty; - unsigned int len, buflen, ioaddr; - -#if DEBUG - printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack); -#endif - - tty = portp->tty; - ioaddr = portp->ioaddr; - outb(GIBCR, (ioaddr + XP_ADDR)); - len = inb(ioaddr + XP_DATA) + 1; - - if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { - if ((tty == (struct tty_struct *) NULL) || - (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - len = MIN(len, sizeof(stl_unwanted)); - outb(GRXFIFO, (ioaddr + XP_ADDR)); - insb((ioaddr + XP_DATA), &stl_unwanted[0], len); - portp->stats.rxlost += len; - portp->stats.rxtotal += len; - } else { - len = MIN(len, buflen); - if (len > 0) { - outb(GRXFIFO, (ioaddr + XP_ADDR)); - insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; - tty_schedule_flip(tty); - portp->stats.rxtotal += len; - } - } - } else { - stl_sc26198rxbadchars(portp); - } - -/* - * If we are TX flow controlled and in IXANY mode then we may need - * to unflow control here. We gotta do this because of the automatic - * flow control modes of the sc26198. - */ - if (test_bit(ASYI_TXFLOWED, &portp->istate)) { - if ((tty != (struct tty_struct *) NULL) && - (tty->termios != (struct termios *) NULL) && - (tty->termios->c_iflag & IXANY)) { - stl_sc26198txunflow(portp, tty); - } - } -} - -/*****************************************************************************/ - -/* - * Process an RX bad character. - */ - -static void inline stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) -{ - struct tty_struct *tty; - unsigned int ioaddr; - - tty = portp->tty; - ioaddr = portp->ioaddr; - - if (status & SR_RXPARITY) - portp->stats.rxparity++; - if (status & SR_RXFRAMING) - portp->stats.rxframing++; - if (status & SR_RXOVERRUN) - portp->stats.rxoverrun++; - if (status & SR_RXBREAK) - portp->stats.rxbreaks++; - - if ((tty != (struct tty_struct *) NULL) && - ((portp->rxignoremsk & status) == 0)) { - if (portp->rxmarkmsk & status) { - if (status & SR_RXBREAK) { - status = TTY_BREAK; - if (portp->flags & ASYNC_SAK) { - do_SAK(tty); - BRDENABLE(portp->brdnr, portp->pagenr); - } - } else if (status & SR_RXPARITY) { - status = TTY_PARITY; - } else if (status & SR_RXFRAMING) { - status = TTY_FRAME; - } else if(status & SR_RXOVERRUN) { - status = TTY_OVERRUN; - } else { - status = 0; - } - } else { - status = 0; - } - - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - } - tty_schedule_flip(tty); - } - - if (status == 0) - portp->stats.rxtotal++; - } -} - -/*****************************************************************************/ - -/* - * Process all characters in the RX FIFO of the UART. Check all char - * status bytes as well, and process as required. We need to check - * all bytes in the FIFO, in case some more enter the FIFO while we - * are here. To get the exact character error type we need to switch - * into CHAR error mode (that is why we need to make sure we empty - * the FIFO). - */ - -static void stl_sc26198rxbadchars(stlport_t *portp) -{ - unsigned char status, mr1; - char ch; - -/* - * To get the precise error type for each character we must switch - * back into CHAR error mode. - */ - mr1 = stl_sc26198getreg(portp, MR1); - stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK)); - - while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) { - stl_sc26198setreg(portp, SCCR, CR_CLEARRXERR); - ch = stl_sc26198getreg(portp, RXFIFO); - stl_sc26198rxbadch(portp, status, ch); - } - -/* - * To get correct interrupt class we must switch back into BLOCK - * error mode. - */ - stl_sc26198setreg(portp, MR1, mr1); -} - -/*****************************************************************************/ - -/* - * Other interrupt handler. This includes modem signals, flow - * control actions, etc. Most stuff is left to off-level interrupt - * processing time. - */ - -static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) -{ - unsigned char cir, ipr, xisr; - -#if DEBUG - printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack); -#endif - - cir = stl_sc26198getglobreg(portp, CIR); - - switch (cir & CIR_SUBTYPEMASK) { - case CIR_SUBCOS: - ipr = stl_sc26198getreg(portp, IPR); - if (ipr & IPR_DCDCHANGE) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task(&portp->tqueue, &tq_scheduler); - portp->stats.modem++; - } - break; - case CIR_SUBXONXOFF: - xisr = stl_sc26198getreg(portp, XISR); - if (xisr & XISR_RXXONGOT) { - set_bit(ASYI_TXFLOWED, &portp->istate); - portp->stats.txxoff++; - } - if (xisr & XISR_RXXOFFGOT) { - clear_bit(ASYI_TXFLOWED, &portp->istate); - portp->stats.txxon++; - } - break; - case CIR_SUBBREAK: - stl_sc26198setreg(portp, SCCR, CR_BREAKRESET); - stl_sc26198rxbadchars(portp); - break; - default: - break; - } -} - -/*****************************************************************************/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/stradis.c linux/drivers/char/stradis.c --- v2.4.0-test6/linux/drivers/char/stradis.c Mon Jul 10 16:47:22 2000 +++ linux/drivers/char/stradis.c Wed Dec 31 16:00:00 1969 @@ -1,2287 +0,0 @@ -/* - * stradis.c - stradis 4:2:2 mpeg decoder driver - * - * Stradis 4:2:2 MPEG-2 Decoder Driver - * Copyright (C) 1999 Nathan Laredo - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7146.h" -#include "saa7146reg.h" -#include "ibmmpeg2.h" -#include "saa7121.h" -#include "cs8420.h" - -#define DEBUG(x) /* debug driver */ -#undef IDEBUG(x) /* debug irq handler */ -#undef MDEBUG(x) /* debug memory management */ - -#define SAA7146_MAX 6 - -static struct saa7146 saa7146s[SAA7146_MAX]; - -static int saa_num = 0; /* number of SAA7146s in use */ - -#define nDebNormal 0x00480000 -#define nDebNoInc 0x00480000 -#define nDebVideo 0xd0480000 -#define nDebAudio 0xd0400000 -#define nDebDMA 0x02c80000 - -#define oDebNormal 0x13c80000 -#define oDebNoInc 0x13c80000 -#define oDebVideo 0xd1080000 -#define oDebAudio 0xd1080000 -#define oDebDMA 0x03080000 - -#define NewCard (saa->boardcfg[3]) -#define ChipControl (saa->boardcfg[1]) -#define NTSCFirstActive (saa->boardcfg[4]) -#define PALFirstActive (saa->boardcfg[5]) -#define NTSCLastActive (saa->boardcfg[54]) -#define PALLastActive (saa->boardcfg[55]) -#define Have2MB (saa->boardcfg[18] & 0x40) -#define HaveCS8420 (saa->boardcfg[18] & 0x04) -#define IBMMPEGCD20 (saa->boardcfg[18] & 0x20) -#define HaveCS3310 (saa->boardcfg[18] & 0x01) -#define CS3310MaxLvl ((saa->boardcfg[30] << 8) | saa->boardcfg[31]) -#define HaveCS4341 (saa->boardcfg[40] == 2) -#define SDIType (saa->boardcfg[27]) -#define CurrentMode (saa->boardcfg[2]) - -#define debNormal (NewCard ? nDebNormal : oDebNormal) -#define debNoInc (NewCard ? nDebNoInc : oDebNoInc) -#define debVideo (NewCard ? nDebVideo : oDebVideo) -#define debAudio (NewCard ? nDebAudio : oDebAudio) -#define debDMA (NewCard ? nDebDMA : oDebDMA) - -#ifdef DEBUG -int stradis_driver(void) /* for the benefit of ksymoops */ -{ - return 1; -} -#endif - -#ifdef USE_RESCUE_EEPROM_SDM275 -static unsigned char rescue_eeprom[64] = { -0x00,0x01,0x04,0x13,0x26,0x0f,0x10,0x00,0x00,0x00,0x43,0x63,0x22,0x01,0x29,0x15,0x73,0x00,0x1f, 'd', 'e', 'c', 'x', 'l', 'd', 'v', 'a',0x02,0x00,0x01,0x00,0xcc,0xa4,0x63,0x09,0xe2,0x10,0x00,0x0a,0x00,0x02,0x02, 'd', 'e', 'c', 'x', 'l', 'a',0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -}; -#endif - -/* ----------------------------------------------------------------------- */ -/* Hardware I2C functions */ -static void I2CWipe(struct saa7146 *saa) -{ - int i; - /* set i2c to ~=100kHz, abort transfer, clear busy */ - saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS); - saawrite((SAA7146_MC2_UPLD_I2C << 16) | - SAA7146_MC2_UPLD_I2C, SAA7146_MC2); - /* wait for i2c registers to be programmed */ - for (i = 0; i < 1000 && - !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) - schedule(); - saawrite(0x600, SAA7146_I2C_STATUS); - saawrite((SAA7146_MC2_UPLD_I2C << 16) | - SAA7146_MC2_UPLD_I2C, SAA7146_MC2); - /* wait for i2c registers to be programmed */ - for (i = 0; i < 1000 && - !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) - schedule(); - saawrite(0x600, SAA7146_I2C_STATUS); - saawrite((SAA7146_MC2_UPLD_I2C << 16) | - SAA7146_MC2_UPLD_I2C, SAA7146_MC2); - /* wait for i2c registers to be programmed */ - for (i = 0; i < 1000 && - !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) - schedule(); -} -/* read I2C */ -static int I2CRead(struct i2c_bus *bus, unsigned char addr, - unsigned char subaddr, int dosub) -{ - struct saa7146 *saa = (struct saa7146 *) bus->data; - int i; - - - if (saaread(SAA7146_I2C_STATUS) & 0x3c) - I2CWipe(saa); - for (i = 0; i < 1000 && - (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++) - schedule(); - if (i == 1000) - I2CWipe(saa); - if (dosub) - saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) | - ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER); - else - saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) | - 0xf1, SAA7146_I2C_TRANSFER); - saawrite((SAA7146_MC2_UPLD_I2C << 16) | - SAA7146_MC2_UPLD_I2C, SAA7146_MC2); - /* wait for i2c registers to be programmed */ - for (i = 0; i < 1000 && - !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) - schedule(); - /* wait for valid data */ - for (i = 0; i < 1000 && - (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++) - schedule(); - if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR) - return -1; - if (i == 1000) - printk("i2c setup read timeout\n"); - saawrite(0x41, SAA7146_I2C_TRANSFER); - saawrite((SAA7146_MC2_UPLD_I2C << 16) | - SAA7146_MC2_UPLD_I2C, SAA7146_MC2); - /* wait for i2c registers to be programmed */ - for (i = 0; i < 1000 && - !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) - schedule(); - /* wait for valid data */ - for (i = 0; i < 1000 && - (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++) - schedule(); - if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR) - return -1; - if (i == 1000) - printk("i2c read timeout\n"); - return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff); -} -static int I2CReadOld(struct i2c_bus *bus, unsigned char addr) -{ - return I2CRead(bus, addr, 0, 0); -} - -/* set both to write both bytes, reset it to write only b1 */ - -static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1, - unsigned char b2, int both) -{ - struct saa7146 *saa = (struct saa7146 *) bus->data; - int i; - u32 data; - - if (saaread(SAA7146_I2C_STATUS) & 0x3c) - I2CWipe(saa); - for (i = 0; i < 1000 && - (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++) - schedule(); - if (i == 1000) - I2CWipe(saa); - data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16); - if (both) - data |= ((b2 & 0xff) << 8) | 0xe5; - else - data |= 0xd1; - saawrite(data, SAA7146_I2C_TRANSFER); - saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C, - SAA7146_MC2); - return 0; -} - -static void attach_inform(struct i2c_bus *bus, int id) -{ - struct saa7146 *saa = (struct saa7146 *) bus->data; - int i; - - DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr, id)); - if (id == 0xa0) { /* we have rev2 or later board, fill in info */ - for (i = 0; i < 64; i++) - saa->boardcfg[i] = I2CRead(bus, 0xa0, i, 1); -#ifdef USE_RESCUE_EEPROM_SDM275 - if (saa->boardcfg[0] != 0) { - printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE BEEN IGNORED\n", saa->nr); - for (i = 0; i < 64; i++) - saa->boardcfg[i] = rescue_eeprom[i]; - } -#endif - printk("stradis%d: config =", saa->nr); - for (i = 0; i < 51; i++) { - printk(" %02x",saa->boardcfg[i]); - } - printk("\n"); - } -} - -static void detach_inform(struct i2c_bus *bus, int id) -{ - struct saa7146 *saa = (struct saa7146 *) bus->data; - int i; - i = saa->nr; -} - -static void I2CBusScan(struct i2c_bus *bus) -{ - int i; - for (i = 0; i < 0xff; i += 2) - if ((I2CRead(bus, i, 0, 0)) >= 0) - attach_inform(bus, i); -} - -static struct i2c_bus saa7146_i2c_bus_template = -{ - "saa7146", - I2C_BUSID_BT848, - NULL, - SPIN_LOCK_UNLOCKED, - attach_inform, - detach_inform, - NULL, - NULL, - I2CReadOld, - I2CWrite, -}; - -static int debiwait_maxwait = 0; - -static int wait_for_debi_done(struct saa7146 *saa) -{ - int i; - - /* wait for registers to be programmed */ - for (i = 0; i < 100000 && - !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++) - saaread(SAA7146_MC2); - /* wait for transfer to complete */ - for (i = 0; i < 500000 && - (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++) - saaread(SAA7146_MC2); - if (i > debiwait_maxwait) - printk("wait-for-debi-done maxwait: %d\n", - debiwait_maxwait = i); - - if (i == 500000) - return -1; - return 0; -} - -static int debiwrite(struct saa7146 *saa, u32 config, int addr, - u32 val, int count) -{ - u32 cmd; - if (count <= 0 || count > 32764) - return -1; - if (wait_for_debi_done(saa) < 0) - return -1; - saawrite(config, SAA7146_DEBI_CONFIG); - if (count <= 4) /* immediate transfer */ - saawrite(val, SAA7146_DEBI_AD); - else /* block transfer */ - saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD); - saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND); - saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI, - SAA7146_MC2); - return 0; -} - -static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count) -{ - u32 result = 0; - - if (count > 32764 || count <= 0) - return 0; - if (wait_for_debi_done(saa) < 0) - return 0; - saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD); - saawrite((count << 17) | 0x10000 | (addr & 0xffff), - SAA7146_DEBI_COMMAND); - saawrite(config, SAA7146_DEBI_CONFIG); - saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI, - SAA7146_MC2); - if (count > 4) /* not an immediate transfer */ - return count; - wait_for_debi_done(saa); - result = saaread(SAA7146_DEBI_AD); - if (count == 1) - result &= 0xff; - if (count == 2) - result &= 0xffff; - if (count == 3) - result &= 0xffffff; - return result; -} - -#if 0 /* unused */ -/* MUST be a multiple of 8 bytes and 8-byte aligned and < 32768 bytes */ -/* data copied into saa->dmadebi buffer, caller must re-enable interrupts */ -static void ibm_block_dram_read(struct saa7146 *saa, int address, int bytes) -{ - int i, j; - u32 *buf; - buf = (u32 *) saa->dmadebi; - if (bytes > 0x7000) - bytes = 0x7000; - saawrite(0, SAA7146_IER); /* disable interrupts */ - for (i=0; i < 10000 && - (debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2) - & 0x8000); i++) - saaread(SAA7146_MC2); - if (i == 10000) - printk(KERN_ERR "stradis%d: dram_busy never cleared\n", - saa->nr); - debiwrite(saa, debNormal, IBM_MP2_SRC_ADDR, (address<<16) | - (address>>16), 4); - debiwrite(saa, debNormal, IBM_MP2_BLOCK_SIZE, bytes, 2); - debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 0x8a10, 2); - for (j = 0; j < bytes/4; j++) { - for (i = 0; i < 10000 && - (!(debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2) - & 0x4000)); i++) - saaread(SAA7146_MC2); - if (i == 10000) - printk(KERN_ERR "stradis%d: dram_ready never set\n", - saa->nr); - buf[j] = debiread(saa, debNormal, IBM_MP2_DRAM_DATA, 4); - } -} -#endif /* unused */ - -static void do_irq_send_data(struct saa7146 *saa) -{ - int split, audbytes, vidbytes; - - saawrite(SAA7146_PSR_PIN1, SAA7146_IER); - /* if special feature mode in effect, disable audio sending */ - if (saa->playmode != VID_PLAY_NORMAL) - saa->audtail = saa->audhead = 0; - if (saa->audhead <= saa->audtail) - audbytes = saa->audtail - saa->audhead; - else - audbytes = 65536 - (saa->audhead - saa->audtail); - if (saa->vidhead <= saa->vidtail) - vidbytes = saa->vidtail - saa->vidhead; - else - vidbytes = 524288 - (saa->vidhead - saa->vidtail); - if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) { - saawrite(0, SAA7146_IER); - return; - } - /* if at least 1 block audio waiting and audio fifo isn't full */ - if (audbytes >= 2048 && (debiread(saa, debNormal, - IBM_MP2_AUD_FIFO, 2) & 0xff) < 60) { - if (saa->audhead > saa->audtail) - split = 65536 - saa->audhead; - else - split = 0; - audbytes = 2048; - if (split > 0 && split < 2048) { - memcpy(saa->dmadebi, saa->audbuf + saa->audhead, - split); - saa->audhead = 0; - audbytes -= split; - } else - split = 0; - memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead, - audbytes); - saa->audhead += audbytes; - saa->audhead &= 0xffff; - debiwrite(saa, debAudio, (NewCard? IBM_MP2_AUD_FIFO : - IBM_MP2_AUD_FIFOW), 0, 2048); - wake_up_interruptible(&saa->audq); - /* if at least 1 block video waiting and video fifo isn't full */ - } else if (vidbytes >= 30720 && (debiread(saa, debNormal, - IBM_MP2_FIFO, 2)) < 16384) { - if (saa->vidhead > saa->vidtail) - split = 524288 - saa->vidhead; - else - split = 0; - vidbytes = 30720; - if (split > 0 && split < 30720) { - memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, - split); - saa->vidhead = 0; - vidbytes -= split; - } else - split = 0; - memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead, - vidbytes); - saa->vidhead += vidbytes; - saa->vidhead &= 0x7ffff; - debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO : - IBM_MP2_FIFOW), 0, 30720); - wake_up_interruptible(&saa->vidq); - } - saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER); -} - -static void send_osd_data(struct saa7146 *saa) -{ - int size = saa->osdtail - saa->osdhead; - if (size > 30720) - size = 30720; - /* ensure some multiple of 8 bytes is transferred */ - size = 8 * ((size + 8)>>3); - if (size) { - debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, - (saa->osdhead>>3), 2); - memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size); - saa->osdhead += size; - /* block transfer of next 8 bytes to ~32k bytes */ - debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size); - } - if (saa->osdhead >= saa->osdtail) { - saa->osdhead = saa->osdtail = 0; - debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2); - } -} - -static void saa7146_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - struct saa7146 *saa = (struct saa7146 *) dev_id; - u32 stat, astat; - int count; - - count = 0; - while (1) { - /* get/clear interrupt status bits */ - stat = saaread(SAA7146_ISR); - astat = stat & saaread(SAA7146_IER); - if (!astat) - return; - saawrite(astat, SAA7146_ISR); - if (astat & SAA7146_PSR_DEBI_S) { - do_irq_send_data(saa); - } - if (astat & SAA7146_PSR_PIN1) { - int istat; - /* the following read will trigger DEBI_S */ - istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2); - if (istat & 1) { - saawrite(0, SAA7146_IER); - send_osd_data(saa); - saawrite(SAA7146_PSR_DEBI_S | - SAA7146_PSR_PIN1, SAA7146_IER); - } - if (istat & 0x20) { /* Video Start */ - saa->vidinfo.frame_count++; - } - if (istat & 0x400) { /* Picture Start */ - /* update temporal reference */ - } - if (istat & 0x200) { /* Picture Resolution Change */ - /* read new resolution */ - } - if (istat & 0x100) { /* New User Data found */ - /* read new user data */ - } - if (istat & 0x1000) { /* new GOP/SMPTE */ - /* read new SMPTE */ - } - if (istat & 0x8000) { /* Sequence Start Code */ - /* reset frame counter, load sizes */ - saa->vidinfo.frame_count = 0; - saa->vidinfo.h_size = 704; - saa->vidinfo.v_size = 480; -#if 0 - if (saa->endmarkhead != saa->endmarktail) { - saa->audhead = - saa->endmark[saa->endmarkhead]; - saa->endmarkhead++; - if (saa->endmarkhead >= MAX_MARKS) - saa->endmarkhead = 0; - } -#endif - } - if (istat & 0x4000) { /* Sequence Error Code */ - if (saa->endmarkhead != saa->endmarktail) { - saa->audhead = - saa->endmark[saa->endmarkhead]; - saa->endmarkhead++; - if (saa->endmarkhead >= MAX_MARKS) - saa->endmarkhead = 0; - } - } - } -#ifdef IDEBUG - if (astat & SAA7146_PSR_PPEF) { - IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr)); - } - if (astat & SAA7146_PSR_PABO) { - IDEBUG(printk("stradis%d irq: PABO\n", saa->nr)); - } - if (astat & SAA7146_PSR_PPED) { - IDEBUG(printk("stradis%d irq: PPED\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_I1) { - IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_I0) { - IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_LATE1) { - IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_LATE0) { - IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_E1) { - IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_E0) { - IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_TO1) { - IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr)); - } - if (astat & SAA7146_PSR_RPS_TO0) { - IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr)); - } - if (astat & SAA7146_PSR_UPLD) { - IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr)); - } - if (astat & SAA7146_PSR_DEBI_E) { - IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr)); - } - if (astat & SAA7146_PSR_I2C_S) { - IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr)); - } - if (astat & SAA7146_PSR_I2C_E) { - IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr)); - } - if (astat & SAA7146_PSR_A2_IN) { - IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr)); - } - if (astat & SAA7146_PSR_A2_OUT) { - IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr)); - } - if (astat & SAA7146_PSR_A1_IN) { - IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr)); - } - if (astat & SAA7146_PSR_A1_OUT) { - IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr)); - } - if (astat & SAA7146_PSR_AFOU) { - IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr)); - } - if (astat & SAA7146_PSR_V_PE) { - IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr)); - } - if (astat & SAA7146_PSR_VFOU) { - IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr)); - } - if (astat & SAA7146_PSR_FIDA) { - IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr)); - } - if (astat & SAA7146_PSR_FIDB) { - IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr)); - } - if (astat & SAA7146_PSR_PIN3) { - IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr)); - } - if (astat & SAA7146_PSR_PIN2) { - IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr)); - } - if (astat & SAA7146_PSR_PIN0) { - IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr)); - } - if (astat & SAA7146_PSR_ECS) { - IDEBUG(printk("stradis%d irq: ECS\n", saa->nr)); - } - if (astat & SAA7146_PSR_EC3S) { - IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr)); - } - if (astat & SAA7146_PSR_EC0S) { - IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr)); - } -#endif - count++; - if (count > 15) - printk(KERN_WARNING "stradis%d: irq loop %d\n", - saa->nr, count); - if (count > 20) { - saawrite(0, SAA7146_IER); - printk(KERN_ERR - "stradis%d: IRQ loop cleared\n", saa->nr); - } - } -} - -static int ibm_send_command(struct saa7146 *saa, - int command, int data, int chain) -{ - int i; - - if (chain) - debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1) | 1, 2); - else - debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2); - debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2); - debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2); - for (i = 0; i < 100 && - (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++) - schedule(); - if (i == 100) - return -1; - return 0; -} - -static void cs4341_setlevel(struct saa7146 *saa, int left, int right) -{ - I2CWrite(&(saa->i2c), 0x22, 0x03, - left > 94 ? 94 : left, 2); - I2CWrite(&(saa->i2c), 0x22, 0x04, - right > 94 ? 94 : right, 2); -} - -static void initialize_cs4341(struct saa7146 *saa) -{ - int i; - for (i = 0; i < 200; i++) { - /* auto mute off, power on, no de-emphasis */ - /* I2S data up to 24-bit 64xFs internal SCLK */ - I2CWrite(&(saa->i2c), 0x22, 0x01, 0x11, 2); - /* ATAPI mixer setings */ - I2CWrite(&(saa->i2c), 0x22, 0x02, 0x49, 2); - /* attenuation left 3db */ - I2CWrite(&(saa->i2c), 0x22, 0x03, 0x00, 2); - /* attenuation right 3db */ - I2CWrite(&(saa->i2c), 0x22, 0x04, 0x00, 2); - I2CWrite(&(saa->i2c), 0x22, 0x01, 0x10, 2); - if (I2CRead(&(saa->i2c), 0x22, 0x02, 1) == 0x49) - break; - schedule(); - } - printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i); - return; -} - -static void initialize_cs8420(struct saa7146 *saa, int pro) -{ - int i; - u8 *sequence; - if (pro) - sequence = mode8420pro; - else - sequence = mode8420con; - for (i = 0; i < INIT8420LEN; i++) - I2CWrite(&(saa->i2c), 0x20, init8420[i * 2], - init8420[i * 2 + 1], 2); - for (i = 0; i < MODE8420LEN; i++) - I2CWrite(&(saa->i2c), 0x20, sequence[i * 2], - sequence[i * 2 + 1], 2); - printk("stradis%d: CS8420 initialized\n", saa->nr); -} - -static void initialize_saa7121(struct saa7146 *saa, int dopal) -{ - int i, mod; - u8 *sequence; - if (dopal) - sequence = init7121pal; - else - sequence = init7121ntsc; - mod = saaread(SAA7146_PSR) & 0x08; - /* initialize PAL/NTSC video encoder */ - for (i = 0; i < INIT7121LEN; i++) { - if (NewCard) { /* handle new card encoder differences */ - if (sequence[i*2] == 0x3a) - I2CWrite(&(saa->i2c), 0x88, 0x3a, 0x13, 2); - else if (sequence[i*2] == 0x6b) - I2CWrite(&(saa->i2c), 0x88, 0x6b, 0x20, 2); - else if (sequence[i*2] == 0x6c) - I2CWrite(&(saa->i2c), 0x88, 0x6c, - dopal ? 0x09 : 0xf5, 2); - else if (sequence[i*2] == 0x6d) - I2CWrite(&(saa->i2c), 0x88, 0x6d, - dopal ? 0x20 : 0x00, 2); - else if (sequence[i*2] == 0x7a) - I2CWrite(&(saa->i2c), 0x88, 0x7a, - dopal ? (PALFirstActive - 1) : - (NTSCFirstActive - 4), 2); - else if (sequence[i*2] == 0x7b) - I2CWrite(&(saa->i2c), 0x88, 0x7b, - dopal ? PALLastActive : - NTSCLastActive, 2); - else I2CWrite(&(saa->i2c), 0x88, sequence[i * 2], - sequence[i * 2 + 1], 2); - } else { - if (sequence[i*2] == 0x6b && mod) - I2CWrite(&(saa->i2c), 0x88, 0x6b, - (sequence[i * 2 + 1] ^ 0x09), 2); - else if (sequence[i*2] == 0x7a) - I2CWrite(&(saa->i2c), 0x88, 0x7a, - dopal ? (PALFirstActive - 1) : - (NTSCFirstActive - 4), 2); - else if (sequence[i*2] == 0x7b) - I2CWrite(&(saa->i2c), 0x88, 0x7b, - dopal ? PALLastActive : - NTSCLastActive, 2); - else - I2CWrite(&(saa->i2c), 0x88, sequence[i * 2], - sequence[i * 2 + 1], 2); - } - } -} - -static void set_genlock_offset(struct saa7146 *saa, int noffset) -{ - int nCode; - int PixelsPerLine = 858; - if (CurrentMode == VIDEO_MODE_PAL) - PixelsPerLine = 864; - if (noffset > 500) - noffset = 500; - else if (noffset < -500) - noffset = -500; - nCode = noffset + 0x100; - if (nCode == 1) - nCode = 0x401; - else if (nCode < 1) nCode = 0x400 + PixelsPerLine + nCode; - debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2); -} - -static void set_out_format(struct saa7146 *saa, int mode) -{ - initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1)); - saa->boardcfg[2] = mode; - /* do not adjust analog video parameters here, use saa7121 init */ - /* you will affect the SDI output on the new card */ - if (mode == VIDEO_MODE_PAL) { /* PAL */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2); - mdelay(50); - saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1); - if (NewCard) { - debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, - 0xe100, 2); - mdelay(50); - } - debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, - NewCard ? 0xe500: 0x6500, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_DLY, - (1 << 8) | - (NewCard ? PALFirstActive : PALFirstActive-6), 2); - } else { /* NTSC */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2); - mdelay(50); - saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1); - debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, - NewCard ? 0xe100: 0x6100, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_DLY, - (1 << 8) | - (NewCard ? NTSCFirstActive : NTSCFirstActive-6), 2); - } -} - - -/* Intialize bitmangler to map from a byte value to the mangled word that - * must be output to program the Xilinx part through the DEBI port. - * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0 - * transfer FPGA code, init IBM chip, transfer IBM microcode - * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0 - */ -static u16 bitmangler[256]; - -static int initialize_fpga(struct video_code *bitdata) -{ - int i, num, startindex, failure = 0, loadtwo, loadfile = 0; - u16 *dmabuf; - u8 *newdma; - struct saa7146 *saa; - - /* verify fpga code */ - for (startindex = 0; startindex < bitdata->datasize; startindex++) - if (bitdata->data[startindex] == 255) - break; - if (startindex == bitdata->datasize) { - printk(KERN_INFO "stradis: bad fpga code\n"); - return -1; - } - /* initialize all detected cards */ - for (num = 0; num < saa_num; num++) { - saa = &saa7146s[num]; - if (saa->boardcfg[0] > 20) - continue; /* card was programmed */ - loadtwo = (saa->boardcfg[18] & 0x10); - if (!NewCard) /* we have an old board */ - for (i = 0; i < 256; i++) - bitmangler[i] = ((i & 0x01) << 15) | - ((i & 0x02) << 6) | ((i & 0x04) << 4) | - ((i & 0x08) << 9) | ((i & 0x10) << 7) | - ((i & 0x20) >> 3) | ((i & 0x40) >> 5) | - ((i & 0x80) >> 7); - else /* else we have a new board */ - for (i = 0; i < 256; i++) - bitmangler[i] = ((i & 0x01) << 7) | - ((i & 0x02) << 5) | ((i & 0x04) << 3) | - ((i & 0x08) << 1) | ((i & 0x10) >> 1) | - ((i & 0x20) >> 3) | ((i & 0x40) >> 5) | - ((i & 0x80) >> 7); - - dmabuf = (u16 *) saa->dmadebi; - newdma = (u8 *) saa->dmadebi; - if (NewCard) { /* SDM2xxx */ - if (!strncmp(bitdata->loadwhat, "decoder2", 8)) - continue; /* fpga not for this card */ - if (!strncmp(&saa->boardcfg[42], - bitdata->loadwhat, 8)) { - loadfile = 1; - } else if (loadtwo && !strncmp(&saa->boardcfg[19], - bitdata->loadwhat, 8)) { - loadfile = 2; - } else if (!saa->boardcfg[42] && /* special */ - !strncmp("decxl", bitdata->loadwhat, 8)) { - loadfile = 1; - } else - continue; /* fpga not for this card */ - if (loadfile != 1 && loadfile != 2) { - continue; /* skip to next card */ - } - if (saa->boardcfg[0] && loadfile == 1 ) - continue; /* skip to next card */ - if (saa->boardcfg[0] != 1 && loadfile == 2) - continue; /* skip to next card */ - saa->boardcfg[0]++; /* mark fpga handled */ - printk("stradis%d: loading %s\n", saa->nr, - bitdata->loadwhat); - if (loadtwo && loadfile == 2) - goto send_fpga_stuff; - /* turn on the Audio interface to set PROG low */ - saawrite(0x00400040, SAA7146_GPIO_CTRL); - saaread(SAA7146_PSR); /* ensure posted write */ - /* wait for everyone to reset */ - mdelay(10); - saawrite(0x00400000, SAA7146_GPIO_CTRL); - } else { /* original card */ - if (strncmp(bitdata->loadwhat, "decoder2", 8)) - continue; /* fpga not for this card */ - /* Pull the Xilinx PROG signal WS3 low */ - saawrite(0x02000200, SAA7146_MC1); - /* Turn on the Audio interface so can set PROG low */ - saawrite(0x000000c0, SAA7146_ACON1); - /* Pull the Xilinx INIT signal (GPIO2) low */ - saawrite(0x00400000, SAA7146_GPIO_CTRL); - /* Make sure everybody resets */ - saaread(SAA7146_PSR); /* ensure posted write */ - mdelay(10); - /* Release the Xilinx PROG signal */ - saawrite(0x00000000, SAA7146_ACON1); - /* Turn off the Audio interface */ - saawrite(0x02000000, SAA7146_MC1); - } - /* Release Xilinx INIT signal (WS2) */ - saawrite(0x00000000, SAA7146_GPIO_CTRL); - /* Wait for the INIT to go High */ - for (i = 0; i < 10000 && - !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++) - schedule(); - if (i == 1000) { - printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr); - return -1; - } -send_fpga_stuff: - if (NewCard) { - for (i = startindex; i < bitdata->datasize; i++) - newdma[i - startindex] = - bitmangler[bitdata->data[i]]; - debiwrite(saa, 0x01420000, 0, 0, - ((bitdata->datasize - startindex) + 5)); - if (loadtwo) { - if (loadfile == 1) { - printk("stradis%d: " - "awaiting 2nd FPGA bitfile\n", - saa->nr); - continue; /* skip to next card */ - } - - } - } else { - for (i = startindex; i < bitdata->datasize; i++) - dmabuf[i - startindex] = - bitmangler[bitdata->data[i]]; - debiwrite(saa, 0x014a0000, 0, 0, - ((bitdata->datasize - startindex) + 5) * 2); - } - for (i = 0; i < 1000 && - !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++) - schedule(); - if (i == 1000) { - printk(KERN_INFO "stradis%d: FPGA load failed\n", - saa->nr); - failure++; - continue; - } - if (!NewCard) { - /* Pull the Xilinx INIT signal (GPIO2) low */ - saawrite(0x00400000, SAA7146_GPIO_CTRL); - saaread(SAA7146_PSR); /* ensure posted write */ - mdelay(2); - saawrite(0x00000000, SAA7146_GPIO_CTRL); - mdelay(2); - } - printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr); - saa->boardcfg[0] = 26; /* mark fpga programmed */ - /* set VXCO to its lowest frequency */ - debiwrite(saa, debNormal, XILINX_PWM, 0, 2); - if (NewCard) { - /* mute CS3310 */ - if (HaveCS3310) - debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, - 0, 2); - /* set VXCO to PWM mode, release reset, blank on */ - debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2); - mdelay(10); - /* unmute CS3310 */ - if (HaveCS3310) - debiwrite(saa, debNormal, XILINX_CTL0, - 0x2020, 2); - } - /* set source Black */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2); - saa->boardcfg[4] = 22; /* set NTSC First Active Line */ - saa->boardcfg[5] = 23; /* set PAL First Active Line */ - saa->boardcfg[54] = 2; /* set NTSC Last Active Line - 256 */ - saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */ - set_out_format(saa, VIDEO_MODE_NTSC); - mdelay(50); - /* begin IBM chip init */ - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2); - saaread(SAA7146_PSR); /* wait for reset */ - mdelay(5); - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2); - debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2); - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2); - debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2); - if (NewCard) { - mdelay(5); - /* set i2s rate converter to 48KHz */ - debiwrite(saa, debNormal, 0x80c0, 6, 2); - /* we must init CS8420 first since rev b pulls i2s */ - /* master clock low and CS4341 needs i2s master to */ - /* run the i2c port. */ - if (HaveCS8420) { - /* 0=consumer, 1=pro */ - initialize_cs8420(saa, 0); - } - mdelay(5); - if (HaveCS4341) - initialize_cs4341(saa); - } - debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2); - debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2); - if (NewCard) - set_genlock_offset(saa, 0); - debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2); -#if 0 - /* enable genlock */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2); -#else - /* disable genlock */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2); -#endif - } - return failure; -} - -static int do_ibm_reset(struct saa7146 *saa) -{ - /* failure if decoder not previously programmed */ - if (saa->boardcfg[0] < 37) - return -EIO; - /* mute CS3310 */ - if (HaveCS3310) - debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2); - /* disable interrupts */ - saawrite(0, SAA7146_IER); - saa->audhead = saa->audtail = 0; - saa->vidhead = saa->vidtail = 0; - /* tristate debi bus, disable debi transfers */ - saawrite(0x00880000, SAA7146_MC1); - /* ensure posted write */ - saaread(SAA7146_MC1); - mdelay(50); - /* re-enable debi transfers */ - saawrite(0x00880088, SAA7146_MC1); - /* set source Black */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2); - /* begin IBM chip init */ - set_out_format(saa, CurrentMode); - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2); - saaread(SAA7146_PSR); /* wait for reset */ - mdelay(5); - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2); - debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2); - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2); - debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2); - if (NewCard) { - mdelay(5); - /* set i2s rate converter to 48KHz */ - debiwrite(saa, debNormal, 0x80c0, 6, 2); - /* we must init CS8420 first since rev b pulls i2s */ - /* master clock low and CS4341 needs i2s master to */ - /* run the i2c port. */ - if (HaveCS8420) { - /* 0=consumer, 1=pro */ - initialize_cs8420(saa, 1); - } - mdelay(5); - if (HaveCS4341) - initialize_cs4341(saa); - } - debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2); - debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2); - if (NewCard) - set_genlock_offset(saa, 0); - debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2); - debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2); - if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER, - (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) { - printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr); - } - if (HaveCS3310) { - int i = CS3310MaxLvl; - debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i<<8)|i), 2); - } - /* start video decoder */ - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2); - /* 256k vid, 3520 bytes aud */ - debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2); - debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2); - ibm_send_command(saa, IBM_MP2_PLAY, 0, 0); - /* enable buffer threshold irq */ - debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2); - /* clear pending interrupts */ - debiread(saa, debNormal, IBM_MP2_HOST_INT, 2); - debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2); - return 0; -} - -/* load the decoder microcode */ -static int initialize_ibmmpeg2(struct video_code *microcode) -{ - int i, num; - struct saa7146 *saa; - - for (num = 0; num < saa_num; num++) { - saa = &saa7146s[num]; - /* check that FPGA is loaded */ - debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2); - if ((i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2)) != - 0xa55a) { - printk(KERN_INFO "stradis%d: %04x != 0xa55a\n", - saa->nr, i); -#if 0 - return -1; -#endif - } - if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) { - if (saa->boardcfg[0] > 27) - continue; /* skip to next card */ - /* load video control store */ - saa->boardcfg[1] = 0x13; /* no-sync default */ - debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2); - debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2); - for (i = 0; i < microcode->datasize / 2; i++) - debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA, - (microcode->data[i * 2] << 8) | - microcode->data[i * 2 + 1], 2); - debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - saa->boardcfg[0] = 28; - } - if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) { - if (saa->boardcfg[0] > 35) - continue; /* skip to next card */ - /* load audio control store */ - debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2); - debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2); - for (i = 0; i < microcode->datasize; i++) - debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA, - microcode->data[i], 1); - debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2); - debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2); - if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER, - 0xe000, 1)) { - printk(KERN_ERR - "stradis%d: IBM config failed\n", - saa->nr); - return -1; - } - /* set PWM to center value */ - if (NewCard) { - debiwrite(saa, debNormal, XILINX_PWM, - saa->boardcfg[14] + - (saa->boardcfg[13]<<8), 2); - } else - debiwrite(saa, debNormal, XILINX_PWM, - 0x46, 2); - if (HaveCS3310) { - i = CS3310MaxLvl; - debiwrite(saa, debNormal, - XILINX_CS3310_CMPLT, ((i<<8)|i), 2); - } - printk(KERN_INFO - "stradis%d: IBM MPEGCD%d Initialized\n", - saa->nr, 18 + (debiread(saa, debNormal, - IBM_MP2_CHIP_CONTROL, 2) >> 12)); - /* start video decoder */ - debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, - 0x4037, 2); /* 256k vid, 3520 bytes aud */ - debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2); - ibm_send_command(saa, IBM_MP2_PLAY, 0, 0); - /* enable buffer threshold irq */ - debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2); - debiread(saa, debNormal, IBM_MP2_HOST_INT, 2); - /* enable gpio irq */ - saawrite(0x00002000, SAA7146_GPIO_CTRL); - /* enable decoder output to HPS */ - debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2); - saa->boardcfg[0] = 37; - } - } - return 0; -} - -static u32 palette2fmt[] = -{ /* some of these YUV translations are wrong */ - 0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000, - 0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000, - 0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000 -}; -static int bpp2fmt[4] = -{ - VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24, - VIDEO_PALETTE_RGB32 -}; - -/* I wish I could find a formula to calculate these... */ -static u32 h_prescale[64] = -{ - 0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808, - 0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460, - 0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f, - 0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000, - 0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000, - 0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000, - 0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000, - 0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000, - 0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000, - 0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000, - 0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000, -}; -static u32 v_gain[64] = -{ - 0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff, - 0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, - 0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, - 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, -}; - - -static void saa7146_set_winsize(struct saa7146 *saa) -{ - u32 format; - int offset, yacl, ysci; - saa->win.color_fmt = format = - (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] : - palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]]; - offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl; - saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1); - saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1); - saawrite(saa->win.bpl * 2, SAA7146_PITCH1); - saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight, - SAA7146_PROT_ADDR1); - saawrite(0, SAA7146_PAGE1); - saawrite(format|0x60, SAA7146_CLIP_FORMAT_CTRL); - offset = (704 / (saa->win.width - 1)) & 0x3f; - saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE); - offset = (720896 / saa->win.width) / (offset + 1); - saawrite((offset<<12)|0x0c, SAA7146_HPS_H_SCALE); - if (CurrentMode == VIDEO_MODE_NTSC) { - yacl = /*(480 / saa->win.height - 1) & 0x3f*/ 0; - ysci = 1024 - (saa->win.height * 1024 / 480); - } else { - yacl = /*(576 / saa->win.height - 1) & 0x3f*/ 0; - ysci = 1024 - (saa->win.height * 1024 / 576); - } - saawrite((1<<31)|(ysci<<21)|(yacl<<15), SAA7146_HPS_V_SCALE); - saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN); - saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V | - SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 | - SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), - SAA7146_MC2); -} - -/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area - * bitmap is fixed width, 128 bytes (1024 pixels represented) - * arranged most-sigificant-bit-left in 32-bit words - * based on saa7146 clipping hardware, it swaps bytes if LE - * much of this makes up for egcs brain damage -- so if you - * are wondering "why did he do this?" it is because the C - * was adjusted to generate the optimal asm output without - * writing non-portable __asm__ directives. - */ - -static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h) -{ - register int startword, endword; - register u32 bitsleft, bitsright; - u32 *temp; - if (x < 0) { - w += x; - x = 0; - } - if (y < 0) { - h += y; - y = 0; - } - if (w <= 0 || h <= 0 || x > 1023 || y > 639) - return; /* throw away bad clips */ - if (x + w > 1024) - w = 1024 - x; - if (y + h > 640) - h = 640 - y; - startword = (x >> 5); - endword = ((x + w) >> 5); - bitsleft = (0xffffffff >> (x & 31)); - bitsright = (0xffffffff << (~((x + w) - (endword<<5)))); - temp = &clipmap[(y<<5) + startword]; - w = endword - startword; - if (!w) { - bitsleft |= bitsright; - for (y = 0; y < h; y++) { - *temp |= bitsleft; - temp += 32; - } - } else { - for (y = 0; y < h; y++) { - *temp++ |= bitsleft; - for (x = 1; x < w; x++) - *temp++ = 0xffffffff; - *temp |= bitsright; - temp += (32 - w); - } - } -} - -static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr) -{ - int i, width, height; - u32 *clipmap; - - clipmap = saa->dmavid2; - if((width=saa->win.width)>1023) - width = 1023; /* sanity check */ - if((height=saa->win.height)>640) - height = 639; /* sanity check */ - if (ncr > 0) { /* rectangles pased */ - /* convert rectangular clips to a bitmap */ - memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ - for (i = 0; i < ncr; i++) - clip_draw_rectangle(clipmap, cr[i].x, cr[i].y, - cr[i].width, cr[i].height); - } - /* clip against viewing window AND screen - so we do not have to rely on the user program - */ - clip_draw_rectangle(clipmap,(saa->win.x+width>saa->win.swidth) ? - (saa->win.swidth-saa->win.x) : width, 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(saa->win.y+height>saa->win.sheight) ? - (saa->win.sheight-saa->win.y) : height,1024,768); - if (saa->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(saa->win.x), 768); - if (saa->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(saa->win.y)); -} - -static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct saa7146 *saa = (struct saa7146 *) dev; - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name, saa->video_dev.name); - b.type = VID_TYPE_CAPTURE | - VID_TYPE_OVERLAY | - VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | - VID_TYPE_SCALES; - b.channels = 1; - b.audios = 1; - 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 VIDIOCGPICT: - { - struct video_picture p = saa->picture; - if (saa->win.depth == 8) - p.palette = VIDEO_PALETTE_HI240; - if (saa->win.depth == 15) - p.palette = VIDEO_PALETTE_RGB555; - if (saa->win.depth == 16) - p.palette = VIDEO_PALETTE_RGB565; - if (saa->win.depth == 24) - p.palette = VIDEO_PALETTE_RGB24; - if (saa->win.depth == 32) - p.palette = VIDEO_PALETTE_RGB32; - if (copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture p; - u32 format; - if (copy_from_user(&p, arg, sizeof(p))) - return -EFAULT; - if (p.palette < sizeof(palette2fmt) / sizeof(u32)) { - format = palette2fmt[p.palette]; - saa->win.color_fmt = format; - saawrite(format|0x60, SAA7146_CLIP_FORMAT_CTRL); - } - saawrite(((p.brightness & 0xff00) << 16) | - ((p.contrast & 0xfe00) << 7) | - ((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL); - saa->picture = p; - /* upload changed registers */ - saawrite(((SAA7146_MC2_UPLD_HPS_H | - SAA7146_MC2_UPLD_HPS_V) << 16) | - SAA7146_MC2_UPLD_HPS_H | SAA7146_MC2_UPLD_HPS_V, - SAA7146_MC2); - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp = NULL; - - if (copy_from_user(&vw, arg, sizeof(vw))) - return -EFAULT; - - if (vw.flags || vw.width < 16 || vw.height < 16) { /* stop capture */ - saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1); - return -EINVAL; - } - if (saa->win.bpp < 4) { /* 32-bit align start and adjust width */ - int i = vw.x; - vw.x = (vw.x + 3) & ~3; - i = vw.x - i; - vw.width -= i; - } - saa->win.x = vw.x; - saa->win.y = vw.y; - saa->win.width = vw.width; - if (saa->win.width > 768) - saa->win.width = 768; - saa->win.height = vw.height; - if (CurrentMode == VIDEO_MODE_NTSC) { - if (saa->win.height > 480) - saa->win.height = 480; - } else { - if (saa->win.height > 576) - saa->win.height = 576; - } - - /* stop capture */ - saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1); - saa7146_set_winsize(saa); - - /* - * Do any clips. - */ - if (vw.clipcount < 0) { - if (copy_from_user(saa->dmavid2, vw.clips, - VIDEO_CLIPMAP_SIZE)) - return -EFAULT; - } else if (vw.clipcount > 0) { - if ((vcp = vmalloc(sizeof(struct video_clip) * - (vw.clipcount))) == NULL) - return -ENOMEM; - if (copy_from_user(vcp, vw.clips, - sizeof(struct video_clip) * - vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - } else /* nothing clipped */ - memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE); - make_clip_tab(saa, vcp, vw.clipcount); - if (vw.clipcount > 0) - vfree(vcp); - - /* start capture & clip dma if we have an address */ - if ((saa->cap & 3) && saa->win.vidadr != 0) - saawrite(((SAA7146_MC1_TR_E_1 | - SAA7146_MC1_TR_E_2) << 16) | 0xffff, - SAA7146_MC1); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - vw.x = saa->win.x; - vw.y = saa->win.y; - vw.width = saa->win.width; - vw.height = saa->win.height; - vw.chromakey = 0; - vw.flags = 0; - 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 (v == 0) { - saa->cap &= ~1; - saawrite((SAA7146_MC1_TR_E_1 << 16), - SAA7146_MC1); - } else { - if (saa->win.vidadr == 0 || saa->win.width == 0 - || saa->win.height == 0) - return -EINVAL; - saa->cap |= 1; - saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff, - SAA7146_MC1); - } - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer v; - v.base = (void *) saa->win.vidadr; - v.height = saa->win.sheight; - v.width = saa->win.swidth; - v.depth = saa->win.depth; - v.bytesperline = saa->win.bpl; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - - } - case VIDIOCSFBUF: - { - struct video_buffer v; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - if (v.depth != 8 && v.depth != 15 && v.depth != 16 && - v.depth != 24 && v.depth != 32 && v.width > 16 && - v.height > 16 && v.bytesperline > 16) - return -EINVAL; - if (v.base) - saa->win.vidadr = (unsigned long) v.base; - saa->win.sheight = v.height; - saa->win.swidth = v.width; - saa->win.bpp = ((v.depth + 7) & 0x38) / 8; - saa->win.depth = v.depth; - saa->win.bpl = v.bytesperline; - - DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", - v.base, v.width, v.height, saa->win.bpp, saa->win.bpl)); - saa7146_set_winsize(saa); - return 0; - } - case VIDIOCKEY: - { - /* Will be handled higher up .. */ - return 0; - } - - case VIDIOCGAUDIO: - { - struct video_audio v; - v = saa->audio_dev; - v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE); - v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; - strcpy(v.name, "MPEG"); - v.mode = VIDEO_SOUND_STEREO; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - int i; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - i = (~(v.volume>>8))&0xff; - if (!HaveCS4341) { - if (v.flags & VIDEO_AUDIO_MUTE) { - debiwrite(saa, debNormal, - IBM_MP2_FRNT_ATTEN, - 0xffff, 2); - } - if (!(v.flags & VIDEO_AUDIO_MUTE)) - debiwrite(saa, debNormal, - IBM_MP2_FRNT_ATTEN, - 0x0000, 2); - if (v.flags & VIDEO_AUDIO_VOLUME) - debiwrite(saa, debNormal, - IBM_MP2_FRNT_ATTEN, - (i<<8)|i, 2); - } else { - if (v.flags & VIDEO_AUDIO_MUTE) - cs4341_setlevel(saa, 0xff, 0xff); - if (!(v.flags & VIDEO_AUDIO_MUTE)) - cs4341_setlevel(saa, 0, 0); - if (v.flags & VIDEO_AUDIO_VOLUME) - cs4341_setlevel(saa, i, i); - } - saa->audio_dev = v; - return 0; - } - - case VIDIOCGUNIT: - { - struct video_unit vu; - vu.video = saa->video_dev.minor; - vu.vbi = VIDEO_NO_UNIT; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; - if (copy_to_user((void *) arg, (void *) &vu, sizeof(vu))) - return -EFAULT; - return 0; - } - case VIDIOCSPLAYMODE: - { - struct video_play_mode pmode; - if (copy_from_user((void *) &pmode, arg, - sizeof(struct video_play_mode))) - return -EFAULT; - switch (pmode.mode) { - case VID_PLAY_VID_OUT_MODE: - if (pmode.p1 != VIDEO_MODE_NTSC && - pmode.p1 != VIDEO_MODE_PAL) - return -EINVAL; - set_out_format(saa, pmode.p1); - return 0; - case VID_PLAY_GENLOCK: - debiwrite(saa, debNormal, - XILINX_CTL0, - (pmode.p1 ? 0x8000 : 0x8080), - 2); - if (NewCard) - set_genlock_offset(saa, - pmode.p2); - return 0; - case VID_PLAY_NORMAL: - debiwrite(saa, debNormal, - IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - ibm_send_command(saa, - IBM_MP2_PLAY, 0, 0); - saa->playmode = pmode.mode; - return 0; - case VID_PLAY_PAUSE: - /* IBM removed the PAUSE command */ - /* they say use SINGLE_FRAME now */ - case VID_PLAY_SINGLE_FRAME: - ibm_send_command(saa, - IBM_MP2_SINGLE_FRAME, - 0, 0); - if (saa->playmode == pmode.mode) { - debiwrite(saa, debNormal, - IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - } - saa->playmode = pmode.mode; - return 0; - case VID_PLAY_FAST_FORWARD: - ibm_send_command(saa, - IBM_MP2_FAST_FORWARD, 0, 0); - saa->playmode = pmode.mode; - return 0; - case VID_PLAY_SLOW_MOTION: - ibm_send_command(saa, - IBM_MP2_SLOW_MOTION, - pmode.p1, 0); - saa->playmode = pmode.mode; - return 0; - case VID_PLAY_IMMEDIATE_NORMAL: - /* ensure transfers resume */ - debiwrite(saa, debNormal, - IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - ibm_send_command(saa, - IBM_MP2_IMED_NORM_PLAY, 0, 0); - saa->playmode = VID_PLAY_NORMAL; - return 0; - case VID_PLAY_SWITCH_CHANNELS: - saa->audhead = saa->audtail = 0; - saa->vidhead = saa->vidtail = 0; - ibm_send_command(saa, - IBM_MP2_FREEZE_FRAME, 0, 1); - ibm_send_command(saa, - IBM_MP2_RESET_AUD_RATE, 0, 1); - debiwrite(saa, debNormal, - IBM_MP2_CHIP_CONTROL, 0, 2); - ibm_send_command(saa, - IBM_MP2_CHANNEL_SWITCH, 0, 1); - debiwrite(saa, debNormal, - IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - ibm_send_command(saa, - IBM_MP2_PLAY, 0, 0); - saa->playmode = VID_PLAY_NORMAL; - return 0; - case VID_PLAY_FREEZE_FRAME: - ibm_send_command(saa, - IBM_MP2_FREEZE_FRAME, 0, 0); - saa->playmode = pmode.mode; - return 0; - case VID_PLAY_STILL_MODE: - ibm_send_command(saa, - IBM_MP2_SET_STILL_MODE, 0, 0); - saa->playmode = pmode.mode; - return 0; - case VID_PLAY_MASTER_MODE: - if (pmode.p1 == VID_PLAY_MASTER_NONE) - saa->boardcfg[1] = 0x13; - else if (pmode.p1 == - VID_PLAY_MASTER_VIDEO) - saa->boardcfg[1] = 0x23; - else if (pmode.p1 == - VID_PLAY_MASTER_AUDIO) - saa->boardcfg[1] = 0x43; - else - return -EINVAL; - debiwrite(saa, debNormal, - IBM_MP2_CHIP_CONTROL, - ChipControl, 2); - return 0; - case VID_PLAY_ACTIVE_SCANLINES: - if (CurrentMode == VIDEO_MODE_PAL) { - if (pmode.p1 < 1 || - pmode.p2 > 625) - return -EINVAL; - saa->boardcfg[5] = pmode.p1; - saa->boardcfg[55] = (pmode.p1 + - (pmode.p2/2) - 1) & - 0xff; - } else { - if (pmode.p1 < 4 || - pmode.p2 > 525) - return -EINVAL; - saa->boardcfg[4] = pmode.p1; - saa->boardcfg[54] = (pmode.p1 + - (pmode.p2/2) - 4) & - 0xff; - } - set_out_format(saa, CurrentMode); - case VID_PLAY_RESET: - return do_ibm_reset(saa); - case VID_PLAY_END_MARK: - if (saa->endmarktail < - saa->endmarkhead) { - if (saa->endmarkhead - - saa->endmarktail < 2) - return -ENOSPC; - } else if (saa->endmarkhead <= - saa->endmarktail) { - if (saa->endmarktail - - saa->endmarkhead > - (MAX_MARKS - 2)) - return -ENOSPC; - } else - return -ENOSPC; - saa->endmark[saa->endmarktail] = - saa->audtail; - saa->endmarktail++; - if (saa->endmarktail >= MAX_MARKS) - saa->endmarktail = 0; - } - return -EINVAL; - } - case VIDIOCSWRITEMODE: - { - int mode; - if (copy_from_user((void *) &mode, arg, sizeof(int))) - return -EFAULT; - if (mode == VID_WRITE_MPEG_AUD || - mode == VID_WRITE_MPEG_VID || - mode == VID_WRITE_CC || - mode == VID_WRITE_TTX || - mode == VID_WRITE_OSD) { - saa->writemode = mode; - return 0; - } - return -EINVAL; - } - case VIDIOCSMICROCODE: - { - struct video_code ucode; - __u8 *udata; - int i; - if (copy_from_user((void *) &ucode, arg, - sizeof(ucode))) - return -EFAULT; - if (ucode.datasize > 65536 || ucode.datasize < 1024 || - strncmp(ucode.loadwhat, "dec", 3)) - return -EINVAL; - if ((udata = vmalloc(ucode.datasize)) == NULL) - return -ENOMEM; - if (copy_from_user((void *) udata, ucode.data, - ucode.datasize)) { - vfree(udata); - return -EFAULT; - } - ucode.data = udata; - if (!strncmp(ucode.loadwhat, "decoder.aud", 11) - || !strncmp(ucode.loadwhat, "decoder.vid", 11)) - i = initialize_ibmmpeg2(&ucode); - else - i = initialize_fpga(&ucode); - vfree(udata); - if (i) - return -EINVAL; - return 0; - - } - case VIDIOCGCHAN: /* this makes xawtv happy */ - { - struct video_channel v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - v.flags = VIDEO_VC_AUDIO; - v.tuners = 0; - v.type = VID_TYPE_MPEG_DECODER; - v.norm = CurrentMode; - strcpy(v.name, "MPEG2"); - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSCHAN: /* this makes xawtv happy */ - { - struct video_channel v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - /* do nothing */ - return 0; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int saa_init_done(struct video_device *dev) -{ - return 0; -} - -static int saa_mmap(struct video_device *dev, const char *adr, - unsigned long size) -{ - struct saa7146 *saa = (struct saa7146 *) dev; - printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr); - return -EINVAL; -} - -static long saa_read(struct video_device *dev, char *buf, - unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static long saa_write(struct video_device *dev, const char *buf, - unsigned long count, int nonblock) -{ - struct saa7146 *saa = (struct saa7146 *) dev; - unsigned long todo = count; - int blocksize, split; - unsigned long flags; - - while (todo > 0) { - if (saa->writemode == VID_WRITE_MPEG_AUD) { - spin_lock_irqsave(&saa->lock, flags); - if (saa->audhead <= saa->audtail) - blocksize = 65536-(saa->audtail - saa->audhead); - else - blocksize = saa->audhead - saa->audtail; - spin_unlock_irqrestore(&saa->lock, flags); - if (blocksize < 16384) { - saawrite(SAA7146_PSR_DEBI_S | - SAA7146_PSR_PIN1, SAA7146_IER); - saawrite(SAA7146_PSR_PIN1, SAA7146_PSR); - /* wait for buffer space to open */ - interruptible_sleep_on(&saa->audq); - } - spin_lock_irqsave(&saa->lock, flags); - if (saa->audhead <= saa->audtail) { - blocksize = 65536-(saa->audtail - saa->audhead); - split = 65536 - saa->audtail; - } else { - blocksize = saa->audhead - saa->audtail; - split = 65536; - } - spin_unlock_irqrestore(&saa->lock, flags); - blocksize--; - if (blocksize > todo) - blocksize = todo; - /* double check that we really have space */ - if (!blocksize) - return -ENOSPC; - if (split < blocksize) { - if (copy_from_user(saa->audbuf + - saa->audtail, buf, split)) - return -EFAULT; - buf += split; - todo -= split; - blocksize -= split; - saa->audtail = 0; - } - if (copy_from_user(saa->audbuf + saa->audtail, buf, - blocksize)) - return -EFAULT; - saa->audtail += blocksize; - todo -= blocksize; - buf += blocksize; - saa->audtail &= 0xffff; - } else if (saa->writemode == VID_WRITE_MPEG_VID) { - spin_lock_irqsave(&saa->lock, flags); - if (saa->vidhead <= saa->vidtail) - blocksize=524288-(saa->vidtail - saa->vidhead); - else - blocksize = saa->vidhead - saa->vidtail; - spin_unlock_irqrestore(&saa->lock, flags); - if (blocksize < 65536) { - saawrite(SAA7146_PSR_DEBI_S | - SAA7146_PSR_PIN1, SAA7146_IER); - saawrite(SAA7146_PSR_PIN1, SAA7146_PSR); - /* wait for buffer space to open */ - interruptible_sleep_on(&saa->vidq); - } - spin_lock_irqsave(&saa->lock, flags); - if (saa->vidhead <= saa->vidtail) { - blocksize=524288-(saa->vidtail - saa->vidhead); - split = 524288 - saa->vidtail; - } else { - blocksize = saa->vidhead - saa->vidtail; - split = 524288; - } - spin_unlock_irqrestore(&saa->lock, flags); - blocksize--; - if (blocksize > todo) - blocksize = todo; - /* double check that we really have space */ - if (!blocksize) - return -ENOSPC; - if (split < blocksize) { - if (copy_from_user(saa->vidbuf + - saa->vidtail, buf, split)) - return -EFAULT; - buf += split; - todo -= split; - blocksize -= split; - saa->vidtail = 0; - } - if (copy_from_user(saa->vidbuf + saa->vidtail, buf, - blocksize)) - return -EFAULT; - saa->vidtail += blocksize; - todo -= blocksize; - buf += blocksize; - saa->vidtail &= 0x7ffff; - } else if (saa->writemode == VID_WRITE_OSD) { - if (count > 131072) - return -ENOSPC; - if (copy_from_user(saa->osdbuf, buf, count)) - return -EFAULT; - buf += count; - saa->osdhead = 0; - saa->osdtail = count; - debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2); - debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2); - debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, - debiread(saa, debNormal, - IBM_MP2_DISP_MODE, 2) | 1, 2); - /* trigger osd data transfer */ - saawrite(SAA7146_PSR_DEBI_S | - SAA7146_PSR_PIN1, SAA7146_IER); - saawrite(SAA7146_PSR_PIN1, SAA7146_PSR); - } - } - return count; -} - -static int saa_open(struct video_device *dev, int flags) -{ - struct saa7146 *saa = (struct saa7146 *) dev; - - saa->video_dev.busy = 0; - saa->user++; - if (saa->user > 1) - return 0; /* device open already, don't reset */ - saa->writemode = VID_WRITE_MPEG_VID; /* default to video */ - return 0; -} - -static void saa_close(struct video_device *dev) -{ - struct saa7146 *saa = (struct saa7146 *) dev; - saa->user--; - saa->video_dev.busy = 0; - if (saa->user > 0) /* still someone using device */ - return; - saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */ -} - -/* template for video_device-structure */ -static struct video_device saa_template = -{ - "SAA7146A", - VID_TYPE_CAPTURE | VID_TYPE_OVERLAY, - VID_HARDWARE_SAA7146, - saa_open, - saa_close, - saa_read, - saa_write, - NULL, /* poll */ - saa_ioctl, - saa_mmap, - saa_init_done, - NULL, - 0, - 0 -}; - -static int configure_saa7146(struct pci_dev *dev, int num) -{ - int result; - struct saa7146 *saa; - - saa = &saa7146s[num]; - - saa->endmarkhead = saa->endmarktail = 0; - saa->win.x = saa->win.y = 0; - saa->win.width = saa->win.cropwidth = 720; - saa->win.height = saa->win.cropheight = 480; - saa->win.cropx = saa->win.cropy = 0; - saa->win.bpp = 2; - saa->win.depth = 16; - saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565]; - saa->win.bpl = 1024 * saa->win.bpp; - saa->win.swidth = 1024; - saa->win.sheight = 768; - saa->picture.brightness = 32768; - saa->picture.contrast = 38768; - saa->picture.colour = 32768; - saa->cap = 0; - saa->dev = dev; - saa->nr = num; - saa->playmode = VID_PLAY_NORMAL; - memset(saa->boardcfg, 0, 64); /* clear board config area */ - saa->saa7146_mem = NULL; - saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in = - saa->dmaa1out = saa->dmaa2in = saa->dmaa2out = - saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in = - saa->pagea1out = saa->pagea2in = saa->pagea2out = - saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 = - saa->pageRPS2 = NULL; - saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL; - saa->audhead = saa->vidtail = 0; - - init_waitqueue_head(&saa->i2cq); - init_waitqueue_head(&saa->audq); - init_waitqueue_head(&saa->debiq); - init_waitqueue_head(&saa->vidq); - spin_lock_init(&saa->lock); - - if (pci_enable_device(dev)) - return -EIO; - - saa->id = dev->device; - saa->irq = dev->irq; - saa->video_dev.minor = -1; - saa->saa7146_adr = pci_resource_start(dev, 0); - pci_read_config_byte(dev, PCI_CLASS_REVISION, &saa->revision); - - saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200); - if (!saa->saa7146_mem) - return -EIO; - - memcpy(&(saa->i2c), &saa7146_i2c_bus_template, sizeof(struct i2c_bus)); - memcpy(&saa->video_dev, &saa_template, sizeof(saa_template)); - sprintf(saa->i2c.name, "stradis%d", num); - saa->i2c.data = saa; - saawrite(0, SAA7146_IER); /* turn off all interrupts */ - result = request_irq(saa->irq, saa7146_irq, - SA_SHIRQ | SA_INTERRUPT, "stradis", (void *) saa); - if (result == -EINVAL) - printk(KERN_ERR "stradis%d: Bad irq number or handler\n", - num); - if (result == -EBUSY) - printk(KERN_ERR "stradis%d: IRQ %ld busy, change your PnP" - " config in BIOS\n", num, saa->irq); - if (result < 0) - return result; - pci_set_master(dev); - if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER) < 0) - return -1; -#if 0 - /* i2c generic interface is currently BROKEN */ - i2c_register_bus(&saa->i2c); -#endif - return 0; -} - -static int init_saa7146(int i) -{ - struct saa7146 *saa = &saa7146s[i]; - - saa->user = 0; - /* reset the saa7146 */ - saawrite(0xffff0000, SAA7146_MC1); - mdelay(5); - /* enable debi and i2c transfers and pins */ - saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C | - SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1); - /* ensure proper state of chip */ - saawrite(0x00000000, SAA7146_PAGE1); - saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1); - saawrite(0x00000000, SAA7146_PAGE2); - saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2); - saawrite(0x00000000, SAA7146_DD1_INIT); - saawrite(0x00000000, SAA7146_DD1_STREAM_B); - saawrite(0x00000000, SAA7146_DD1_STREAM_A); - saawrite(0x00000000, SAA7146_BRS_CTRL); - saawrite(0x80400040, SAA7146_BCS_CTRL); - saawrite(0x0000e000 /*| (1<<29)*/, SAA7146_HPS_CTRL); - saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL); - saawrite(0x00000000, SAA7146_ACON1); - saawrite(0x00000000, SAA7146_ACON2); - saawrite(0x00000600, SAA7146_I2C_STATUS); - saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A | - SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H | - SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 | - SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff, - SAA7146_MC2); - /* setup arbitration control registers */ - saawrite(0x1412121a, SAA7146_PCI_BT_V1); - - /* allocate 32k dma buffer + 4k for page table */ - if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) { - printk(KERN_ERR "stradis%d: debi kmalloc failed\n", i); - return -1; - } -#if 0 - saa->pagedebi = saa->dmadebi + 32768; /* top 4k is for mmu */ - saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE); - for (i = 0; i < 12; i++) /* setup mmu page table */ - saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096)); -#endif - saa->audhead = saa->vidhead = saa->osdhead = 0; - saa->audtail = saa->vidtail = saa->osdtail = 0; - if (saa->vidbuf == NULL) - if ((saa->vidbuf = vmalloc(524288)) == NULL) { - printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr); - return -ENOMEM; - } - if (saa->audbuf == NULL) - if ((saa->audbuf = vmalloc(65536)) == NULL) { - printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr); - vfree(saa->vidbuf); - saa->vidbuf = NULL; - return -ENOMEM; - } - if (saa->osdbuf == NULL) - if ((saa->osdbuf = vmalloc(131072)) == NULL) { - printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr); - vfree(saa->vidbuf); - vfree(saa->audbuf); - saa->vidbuf = saa->audbuf = NULL; - return -ENOMEM; - } - /* allocate 81920 byte buffer for clipping */ - if ((saa->dmavid2 = kmalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) { - printk(KERN_ERR "stradis%d: clip kmalloc failed\n", saa->nr); - vfree(saa->vidbuf); - vfree(saa->audbuf); - vfree(saa->osdbuf); - saa->vidbuf = saa->audbuf = saa->osdbuf = NULL; - saa->dmavid2 = NULL; - return -1; - } - memset(saa->dmavid2, 0x00, VIDEO_CLIPMAP_SIZE); /* clip everything */ - /* setup clipping registers */ - saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2); - saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2); - saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE, - SAA7146_PROT_ADDR2); - saawrite(256, SAA7146_PITCH2); - saawrite(4, SAA7146_PAGE2); /* dma direction: read, no byteswap */ - saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2, - SAA7146_MC2); - I2CBusScan(&(saa->i2c)); - return 0; -} - -static void release_saa(void) -{ - u8 command; - int i; - struct saa7146 *saa; - - for (i = 0; i < saa_num; i++) { - saa = &saa7146s[i]; - - /* turn off all capturing, DMA and IRQs */ - saawrite(0xffff0000, SAA7146_MC1); /* reset chip */ - saawrite(0, SAA7146_MC2); - saawrite(0, SAA7146_IER); - saawrite(0xffffffffUL, SAA7146_ISR); -#if 0 - /* unregister i2c_bus */ - i2c_unregister_bus((&saa->i2c)); -#endif - - /* disable PCI bus-mastering */ - pci_read_config_byte(saa->dev, PCI_COMMAND, &command); - /* Should this be &=~ ?? */ - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte(saa->dev, PCI_COMMAND, command); - /* unmap and free memory */ - saa->audhead = saa->audtail = saa->osdhead = 0; - saa->vidhead = saa->vidtail = saa->osdtail = 0; - if (saa->vidbuf) - vfree(saa->vidbuf); - if (saa->audbuf) - vfree(saa->audbuf); - if (saa->osdbuf) - vfree(saa->osdbuf); - if (saa->dmavid2) - kfree((void *) saa->dmavid2); - saa->audbuf = saa->vidbuf = saa->osdbuf = NULL; - saa->dmavid2 = NULL; - if (saa->dmadebi) - kfree((void *) saa->dmadebi); - if (saa->dmavid1) - kfree((void *) saa->dmavid1); - if (saa->dmavid2) - kfree((void *) saa->dmavid2); - if (saa->dmavid3) - kfree((void *) saa->dmavid3); - if (saa->dmaa1in) - kfree((void *) saa->dmaa1in); - if (saa->dmaa1out) - kfree((void *) saa->dmaa1out); - if (saa->dmaa2in) - kfree((void *) saa->dmaa2in); - if (saa->dmaa2out) - kfree((void *) saa->dmaa2out); - if (saa->dmaRPS1) - kfree((void *) saa->dmaRPS1); - if (saa->dmaRPS2) - kfree((void *) saa->dmaRPS2); - free_irq(saa->irq, saa); - if (saa->saa7146_mem) - iounmap(saa->saa7146_mem); - if (saa->video_dev.minor != -1) - video_unregister_device(&saa->video_dev); - } -} - - -static int __init stradis_init (void) -{ - struct pci_dev *dev = NULL; - int result = 0, i; - - saa_num = 0; - - while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) { - if (!dev->subsystem_vendor) - printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num); - else - printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); - result = configure_saa7146(dev, saa_num++); - if (result) - return result; - } - if (saa_num) - printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num); - else - return -EINVAL; - for (i = 0; i < saa_num; i++) - if (init_saa7146(i) < 0) { - release_saa(); - return -EIO; - } - return 0; -} - - -static void __exit stradis_exit (void) -{ - release_saa(); - printk(KERN_INFO "stradis: module cleanup complete\n"); -} - - -module_init(stradis_init); -module_exit(stradis_exit); - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.4.0-test6/linux/drivers/char/sx.c Fri Jun 23 21:55:08 2000 +++ linux/drivers/char/sx.c Fri Aug 11 14:51:33 2000 @@ -1518,9 +1518,14 @@ exit minicom. I expect an "oops". -- REW */ static void sx_hungup (void *ptr) { + /* struct sx_port *port = ptr; + */ func_enter (); + /* Don't force the SX card to close. mgetty doesn't like it !!!!!! -- pvdl */ + /* For some reson we added this code. Don't know why anymore ;-( -- pvdl */ + /* sx_setsignals (port, 0, 0); sx_reconfigure_port(port); sx_send_command (port, HS_CLOSE, 0, 0); @@ -1532,7 +1537,7 @@ } else sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); } - + */ MOD_DEC_USE_COUNT; func_exit (); } @@ -2368,7 +2373,7 @@ return 0; } - +#ifdef MODULE static void sx_release_drivers(void) { func_enter(); @@ -2376,6 +2381,7 @@ tty_unregister_driver(&sx_callout_driver); func_exit(); } +#endif #ifdef TWO_ZERO #define PDEV unsigned char pci_bus, unsigned pci_fun diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tda7432.c linux/drivers/char/tda7432.c --- v2.4.0-test6/linux/drivers/char/tda7432.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/tda7432.c Wed Dec 31 16:00:00 1969 @@ -1,505 +0,0 @@ -/* - * For the STS-Thompson TDA7432 audio processor chip - * - * Handles audio functions: volume, balance, tone, loudness - * This driver will not complain if used with any - * other i2c device with the same address. - * - * Copyright (c) 2000 Eric Sandeen - * This code is placed under the terms of the GNU General Public License - * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * Which was based on tda8425.c by Greg Alexander (c) 1998 - * - * OPTIONS: - * debug - set to 1 if you'd like to see debug messages - * set to 2 if you'd like to be inundated with debug messages - * - * loudness - set between 0 and 15 for varying degrees of loudness effect - * - * TODO: - * Implement tone controls - * - * Revision: 0.3 - Fixed silly reversed volume controls. :) - * Revision: 0.2 - Cleaned up #defines - * fixed volume control - * Added I2C_DRIVERID_TDA7432 - * added loudness insmod control - * Revision: 0.1 - initial version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - -/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */ -#ifndef I2C_DRIVERID_TDA7432 - #define I2C_DRIVERID_TDA7432 27 -#endif - - -MODULE_AUTHOR("Eric Sandeen "); -MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip"); - -MODULE_PARM(debug,"i"); -MODULE_PARM(loudness,"i"); -static int loudness = 0; /* disable loudness by default */ -static int debug = 0; /* insmod parameter */ - - -/* Address to scan (I2C address of this chip) */ -static unsigned short normal_i2c[] = { - I2C_TDA7432 >> 1, - I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -/* Structure of address and subaddresses for the tda7432 */ - -struct tda7432 { - int addr; - int input; - int volume; - int tone; - int lf, lr, rf, rr; - int loud; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - -#define dprintk if (debug) printk -#define d2printk if (debug > 1) printk - -/* The TDA7432 is made by STS-Thompson - * http://www.st.com - * http://us.st.com/stonline/books/pdf/docs/4056.pdf - * - * TDA7432: I2C-bus controlled basic audio processor - * - * The TDA7432 controls basic audio functions like volume, balance, - * and tone control (including loudness). It also has four channel - * output (for front and rear). Since most vidcap cards probably - * don't have 4 channel output, this driver will set front & rear - * together (no independent control). - */ - - /* Subaddresses for TDA7432 */ - -#define TDA7432_IN 0x00 /* Input select */ -#define TDA7432_VL 0x01 /* Volume */ -#define TDA7432_TN 0x02 /* Bass, Treble (Tone) */ -#define TDA7432_LF 0x03 /* Attenuation LF (Left Front) */ -#define TDA7432_LR 0x04 /* Attenuation LR (Left Rear) */ -#define TDA7432_RF 0x05 /* Attenuation RF (Right Front) */ -#define TDA7432_RR 0x06 /* Attenuation RR (Right Rear) */ -#define TDA7432_LD 0x07 /* Loudness */ - - - /* Masks for bits in TDA7432 subaddresses */ - -/* Many of these not used - just for documentation */ - -/* Subaddress 0x00 - Input selection and bass control */ - -/* Bits 0,1,2 control input: - * 0x00 - Stereo input - * 0x02 - Mono input - * 0x03 - Mute - * Mono probably isn't used - I'm guessing only the stereo - * input is connected on most cards, so we'll set it to stereo. - * - * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut - * Bit 4 controls bass range: 0/1 is extended/standard bass range - * - * Highest 3 bits not used - */ - -#define TDA7432_STEREO_IN 0 -#define TDA7432_MONO_IN 2 /* Probably won't be used */ -#define TDA7432_MUTE 3 /* Probably won't be used */ -#define TDA7432_BASS_SYM 1 << 3 -#define TDA7432_BASS_NORM 1 << 4 - -/* Subaddress 0x01 - Volume */ - -/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps - * Recommended maximum is +20 dB - * - * +32dB: 0x00 - * +20dB: 0x0c - * 0dB: 0x20 - * -79dB: 0x6f - * - * MSB (bit 7) controls loudness: 1/0 is loudness on/off - */ - -#define TDA7432_VOL_0DB 0x20 -#define TDA7432_LD_ON 1 << 7 - - -/* Subaddress 0x02 - Tone control */ - -/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB - * 0x0 is 14dB, 0x7 is 0dB - * - * Bit 3 controls treble attenuation/gain (sign) - * 1 = gain (+) - * 0 = attenuation (-) - * - * Bits 4,5,6 control absolute bass gain from 0dB to 14dB - * (This is only true for normal base range, set in 0x00) - * 0x0 << 4 is 14dB, 0x7 is 0dB - * - * Bit 7 controls bass attenuation/gain (sign) - * 1 << 7 = gain (+) - * 0 << 7 = attenuation (-) - * - * Example: - * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble - */ - -#define TDA7432_TREBLE_0DB 0xf -#define TDA7432_TREBLE 7 -#define TDA7432_TREBLE_GAIN 1 << 3 -#define TDA7432_BASS_0DB 0xf << 4 -#define TDA7432_BASS 7 << 4 -#define TDA7432_BASS_GAIN 1 << 7 - - -/* Subaddress 0x03 - Left Front attenuation */ -/* Subaddress 0x04 - Left Rear attenuation */ -/* Subaddress 0x05 - Right Front attenuation */ -/* Subaddress 0x06 - Right Rear attenuation */ - -/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB - * in 1.5dB steps. - * - * 0x00 is 0dB - * 0x1f is -37.5dB - * - * Bit 5 mutes that channel when set (1 = mute, 0 = unmute) - * We'll use the mute on the input, though (above) - * Bits 6,7 unused - */ - -#define TDA7432_ATTEN_0DB 0x00 - - -/* Subaddress 0x07 - Loudness Control */ - -/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps - * when bit 4 is NOT set - * - * 0x0 is 0dB - * 0xf is -15dB - * - * If bit 4 is set, then there is a flat attenuation according to - * the lower 4 bits, as above. - * - * Bits 5,6,7 unused - */ - - - -/* Begin code */ - -static int tda7432_write(struct i2c_client *client, int subaddr, int val) -{ - unsigned char buffer[2]; - d2printk("tda7432: In tda7432_write\n"); - dprintk("tda7432: Writing %d 0x%x\n", subaddr, val); - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -/* I don't think we ever actually _read_ the chip... */ -#if 0 -static int tda7432_read(struct i2c_client *client) -{ - unsigned char buffer; - d2printk("tda7432: In tda7432_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda7432: I/O error, trying (read)\n"); - return -1; - } - dprintk("tda7432: Read 0x%02x\n", buffer); - return buffer; -} -#endif - -static int tda7432_set(struct i2c_client *client) -{ - struct tda7432 *t = client->data; - unsigned char buf[16]; - d2printk("tda7432: In tda7432_set\n"); - - dprintk(KERN_INFO - "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", - t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud); - buf[0] = TDA7432_IN; - buf[1] = t->input; - buf[2] = t->volume; - buf[3] = t->tone; - buf[4] = t->lf; - buf[5] = t->lr; - buf[6] = t->rf; - buf[7] = t->rr; - buf[8] = t->loud; - if (9 != i2c_master_send(client,buf,9)) { - printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n"); - return -1; - } - - return 0; -} - -static void do_tda7432_init(struct i2c_client *client) -{ - struct tda7432 *t = client->data; - d2printk("tda7432: In tda7432_init\n"); - - t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ - TDA7432_BASS_SYM | /* Symmetric bass cut */ - TDA7432_BASS_NORM; /* Normal bass range */ - t->volume = TDA7432_VOL_0DB; /* 0dB Volume */ - if (loudness) /* Turn loudness on? */ - t->volume |= TDA7432_LD_ON; - t->tone = TDA7432_TREBLE_0DB | /* 0dB Treble */ - TDA7432_BASS_0DB; /* 0dB Bass */ - t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->loud = loudness; /* insmod parameter */ - - tda7432_set(client); -} - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda7432_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda7432 *t; - struct i2c_client *client; - d2printk("tda7432: In tda7432_attach\n"); - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = t = kmalloc(sizeof *t,GFP_KERNEL); - if (!t) - return -ENOMEM; - memset(t,0,sizeof *t); - do_tda7432_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA7432"); - printk(KERN_INFO "tda7432: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda7432_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda7432_attach); - return 0; -} - -static int tda7432_detach(struct i2c_client *client) -{ - struct tda7432 *t = client->data; - - do_tda7432_init(client); - i2c_detach_client(client); - - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda7432_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda7432 *t = client->data; - d2printk("tda7432: In tda7432_command\n"); -#if 0 - __u16 *sarg = arg; -#endif - - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - - /* Query card - scale from TDA7432 settings to V4L settings */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - dprintk("tda7432: VIDIOCGAUDIO\n"); - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - - /* Master volume control - * V4L volume is min 0, max 65535 - * TDA7432 Volume: - * Min (-79dB) is 0x6f - * Max (+20dB) is 0x07 - * (Mask out bit 7 of vol - it's for the loudness setting) - */ - - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; - - /* Balance depends on L,R attenuation - * V4L balance is 0 to 65535, middle is 32768 - * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f - * to scale up to V4L numbers, mult by 1057 - * attenuation exists for lf, lr, rf, rr - * we use only lf and rf (front channels) - */ - - if ( (t->lf) < (t->rf) ) - /* right is attenuated, balance shifted left */ - va->balance = (32768 - 1057*(t->rf)); - else - /* left is attenuated, balance shifted right */ - va->balance = (32768 + 1057*(t->lf)); - - /* Bass/treble */ - va->bass = 32768; /* brain hurts... set to middle for now */ - va->treble = 32768; /* brain hurts... set to middle for now */ - - break; /* VIDIOCGAUDIO case */ - } - - /* Set card - scale from V4L settings to TDA7432 settings */ - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - dprintk("tda7432: VIDEOCSAUDIO\n"); - - t->volume = 0x6f - ( (va->volume)/630 ); - - if (loudness) /* Turn on the loudness bit */ - t->volume |= TDA7432_LD_ON; - - if (va->balance < 32768) { - /* shifted to left, attenuate right */ - t->rr = (32768 - va->balance)/1057; - t->rf = t->rr; - } - else { - /* shifted to right, attenuate left */ - t->lf = (va->balance - 32768)/1057; - t->lr = t->lf; - } - - /* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */ - - tda7432_write(client,TDA7432_VL, t->volume); - /* tda7432_write(client,TDA7432_TN, t->tone); */ - tda7432_write(client,TDA7432_LF, t->lf); - tda7432_write(client,TDA7432_LR, t->lr); - tda7432_write(client,TDA7432_RF, t->rf); - tda7432_write(client,TDA7432_RR, t->rr); - - break; - - } /* end of VIDEOCSAUDIO case */ - - default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ - - /* nothing */ - d2printk("tda7432: Default\n"); - - } /* end of (cmd) switch */ - - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda7432 driver", - I2C_DRIVERID_TDA7432, - I2C_DF_NOTIFY, - tda7432_probe, - tda7432_detach, - tda7432_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda7432_init(void) -#endif -{ - - if ( (loudness < 0) || (loudness > 15) ) - { - printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n"); - return -EINVAL; - } - - - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tda8425.c linux/drivers/char/tda8425.c --- v2.4.0-test6/linux/drivers/char/tda8425.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/tda8425.c Wed Dec 31 16:00:00 1969 @@ -1,324 +0,0 @@ -/* - * for the TDA8425 chip (I don't know which cards have this) - * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT - * CHIP IS AT ADDRESS 0x82 (it relies on i2c to make sure that there is a - * device acknowledging that address) - * - * Copyright (c) 1998 Greg Alexander - * This code is placed under the terms of the GNU General Public License - * Code liberally copied from msp3400.c, which is by Gerd Knorr - * - * All of this should work, though it would be nice to eventually support - * balance (different left,right values). Also, the chip seems (?) to have - * two stereo inputs, so if someone has this card, could they tell me if the - * second one can be used for anything (i.e., does it have an external input - * that you can't hear even if you set input to composite?) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { - I2C_TDA8425 >> 1, - I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -MODULE_PARM(debug,"i"); -static int debug = 0; /* insmod parameter */ -#define dprintk if (debug) printk - - -struct tda8425 { - int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ - int stereo; - __u16 left,right; - __u16 bass,treble; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - - -#define TDA8425_VL 0x00 /* volume left */ -#define TDA8425_VR 0x01 /* volume right */ -#define TDA8425_BA 0x02 /* bass */ -#define TDA8425_TR 0x03 /* treble */ -#define TDA8425_S1 0x08 /* switch functions */ - /* values for those registers: */ -#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ -#define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */ - - -/* ******************************** * - * functions for talking to TDA8425 * - * ******************************** */ - -static int tda8425_write(struct i2c_client *client, int addr, int val) -{ - unsigned char buffer[2]; - - buffer[0] = addr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda8425: I/O error, trying (write %d 0x%x)\n", - addr, val); - return -1; - } - return 0; -} - -static void tda8425_set(struct i2c_client *client) -{ - struct tda8425 *tda = client->data; - - /* mode is ignored today */ - dprintk(KERN_DEBUG "tda8425_set(%04x,%04x,%04x,%04x)\n",tda->left>>10,tda->right>>10,tda->bass>>12,tda->treble>>12); - tda8425_write(client, TDA8425_VL, tda->left>>10 |0xC0); - tda8425_write(client, TDA8425_VR, tda->right>>10 |0xC0); - tda8425_write(client, TDA8425_BA, tda->bass>>12 |0xF0); - tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0); -} - -static void do_tda8425_init(struct i2c_client *client) -{ - struct tda8425 *tda = client->data; - - tda->left=tda->right =61440; /* 0dB */ - tda->bass=tda->treble=24576; /* 0dB */ - tda->mode=AUDIO_OFF; - tda->stereo=1; - /* left=right=0x27<<10, bass=treble=0x07<<12 */ - tda8425_write(client, TDA8425_S1, TDA8425_S1_OFF); /* mute */ - tda8425_set(client); -} - -static void tda8425_audio(struct i2c_client *client, int mode) -{ - struct tda8425 *tda = client->data; - - /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ - dprintk(KERN_DEBUG "tda8425_audio:%d (T,R,E,I,O)\n",mode); - tda->mode=mode; - tda8425_write(client, TDA8425_S1, - (mode==AUDIO_OFF)?TDA8425_S1_OFF:TDA8425_S1_ON); - /* this is the function we'll need to change if it turns out the - * input-selecting capabilities should be used. */ -} - - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda8425_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda8425 *tda; - struct i2c_client *client; - - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = tda = kmalloc(sizeof *tda,GFP_KERNEL); - if (!tda) - return -ENOMEM; - memset(tda,0,sizeof *tda); - do_tda8425_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA8425"); - printk(KERN_INFO "tda8425: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda8425_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda8425_attach); - return 0; -} - - -static int tda8425_detach(struct i2c_client *client) -{ - struct tda8425 *tda = client->data; - - do_tda8425_init(client); - i2c_detach_client(client); - - kfree(tda); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda8425_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda8425 *tda = client->data; - __u16 *sarg = arg; - - switch (cmd) { - case AUDC_SET_RADIO: - tda8425_audio(client,AUDIO_RADIO); - break; - case AUDC_SET_INPUT: - tda8425_audio(client,*sarg); - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - va->volume=MAX(tda->left,tda->right); - va->balance=(32768*MIN(tda->left,tda->right))/ - (va->volume ? va->volume : 1); - va->balance=(tda->leftright)? - (65535-va->balance) : va->balance; - va->bass = tda->bass; - va->treble = tda->treble; - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - - tda->left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - tda->right = (MIN(va->balance,32768) * - va->volume) / 32768; - tda->bass = va->bass; - tda->treble = va->treble; - tda8425_set(client); - break; - } - -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_GET_VOLUME_LEFT: - *sarg = tda->left; - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = tda->right; - break; - case AUDC_SET_VOLUME_LEFT: - tda->left = *sarg; - tda8425_set(client); - break; - case AUDC_SET_VOLUME_RIGHT: - tda->right = *sarg; - tda8425_set(client); - break; - - case AUDC_GET_BASS: - *sarg = tda->bass; - break; - case AUDC_SET_BASS: - tda->bass = *sarg; - tda8425_set(client); - break; - - case AUDC_GET_TREBLE: - *sarg = tda->treble; - break; - case AUDC_SET_TREBLE: - tda->treble = *sarg; - tda8425_set(client); - break; - - case AUDC_GET_STEREO: - *sarg = tda->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; - break; - case AUDC_SET_STEREO: - tda->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; - /* TODO: make this write to the TDA9850? */ - break; - -/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to - case AUDC_NEWCHANNEL: it and it would require preserving state - case AUDC_GET_DC: huh?? (not used by bttv.c) -*/ -#endif - default: - /* nothing */ - } - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda8424 driver", - I2C_DRIVERID_TDA8425, - I2C_DF_NOTIFY, - tda8425_probe, - tda8425_detach, - tda8425_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda8425_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tda985x.c linux/drivers/char/tda985x.c --- v2.4.0-test6/linux/drivers/char/tda985x.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/tda985x.c Wed Dec 31 16:00:00 1969 @@ -1,536 +0,0 @@ -/* - * For the TDA9850 and TDA9855 chips - * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used - * on STB cards. Other cards probably use these chips as well.) - * This driver will not complain if used with any - * other i2c device with the same address. - * - * Copyright (c) 1999 Gerd Knorr - * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) - * This code is placed under the terms of the GNU General Public License - * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * Which was based on tda8425.c by Greg Alexander (c) 1998 - * - * OPTIONS: - * debug - set to 1 if you'd like to see debug messages - * - set to 2 if you'd like to be flooded with debug messages - * chip - set to 9850 or 9855 to select your chip (default 9855) - * - * TODO: - * Fix channel change bug - sound goes out when changeing channels, mute - * and unmote to fix. - Is this still here? - * Fine tune sound - * Get rest of capabilities into video_audio struct... - * - * Revision 0.5 - cleaned up debugging messages, added debug level=2 - * Revision: 0.4 - check for correct chip= insmod value - * also cleaned up comments a bit - * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command - * Revision: 0.2 - added insmod option chip= - * Revision: 0.1 - original version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - -MODULE_PARM(debug,"i"); -MODULE_PARM(chip,"i"); -MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855"); - -static int debug = 0; /* insmod parameter */ -static int chip = 9855; /* insmod parameter */ - -/* Addresses to scan */ -#define I2C_TDA985x_L 0xb4 -#define I2C_TDA985x_H 0xb6 -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = { - I2C_TDA985x_L >> 1, - I2C_TDA985x_H >> 1, - I2C_CLIENT_END -}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -/* This is a superset of the TDA9850 and TDA9855 members */ - -struct tda985x { - int addr; - int rvol, lvol; - int bass, treble, sub; - int c4, c5, c6, c7; - int a1, a2, a3; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - -#define dprintk if (debug) printk -#define d2printk if (debug == 2) printk - -/* The TDA9850 and TDA9855 are both made by Philips Semiconductor - * http://www.semiconductors.philips.com - * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder - * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor - * - * The TDA9850 has more or less a subset of the functions that the TDA9855 - * has. As a result, we can re-use many of these defines. Anything with - * TDA9855 is specific to that chip, anything with TDA9850 is specific - * to that chip, and anything with TDA985x is valid for either. - * - * To complicate things further, the TDA9850 uses labels C1 through C4 - * for subaddresses 0x04 through 0x07, while the TDA9855 uses - * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing. - * To help keep things straight, I have renamed the various C[1,4] labels - * to C[4,7] so that the numerical label matches the hex value of the - * subaddress for both chips. At least the A[1,3] labels line up. :) - */ - - /* subaddresses for TDA9855 */ -#define TDA9855_VR 0x00 /* Volume, right */ -#define TDA9855_VL 0x01 /* Volume, left */ -#define TDA9855_BA 0x02 /* Bass */ -#define TDA9855_TR 0x03 /* Treble */ -#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ - - /* subaddresses for TDA9850 */ -#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */ - - /* subaddesses for both chips */ -#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */ -#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */ -#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */ -#define TDA985x_A1 0x08 /* Alignment 1 for both chips */ -#define TDA985x_A2 0x09 /* Alignment 2 for both chips */ -#define TDA985x_A3 0x0a /* Alignment 3 for both chips */ - - /* Masks for bits in TDA9855 subaddresses */ -/* 0x00 - VR in TDA9855 */ -/* 0x01 - VL in TDA9855 */ -/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) - * in 1dB steps - mute is 0x27 */ - - -/* 0x02 - BA in TDA9855 */ -/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) - * in .5dB steps - 0 is 0x0E */ - - -/* 0x03 - TR in TDA9855 */ -/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) - * in 3dB steps - 0 is 0x7 */ - - /* Masks for bits in both chips' subaddresses */ -/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */ -/* Unique to TDA9855: */ -/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf) - * in 3dB steps - mute is 0x0 */ - -/* Unique to TDA9850: */ -/* lower 4 bits control stereo noise threshold, over which stereo turns off - * set to values of 0x00 through 0x0f for Ster1 through Ster16 */ - - -/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/ -/* Unique to TDA9855: */ -#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ -#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ -#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ -#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ - /* Bits 0 to 3 select various combinations - * of line in and line out, only the - * interesting ones are defined */ -#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ -#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ - -/* Unique to TDA9850: */ -/* lower 4 bits contol SAP noise threshold, over which SAP turns off - * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ - - -/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ -/* Common to TDA9855 and TDA9850: */ -#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ -#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ -#define TDA985x_MONO 0 /* Forces Mono output */ -#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ - -/* Unique to TDA9855: */ -#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ -#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ -#define TDA9855_LINEAR 0 /* Linear Stereo */ -#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ -#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ -#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ -#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ - - -/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */ -/* Common to both TDA9855 and TDA9850: */ -/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) - * in .5dB steps - 0dB is 0x7 */ - - -/* 0x08, 0x09 - A1 and A2 (read/write) */ -/* Common to both TDA9855 and TDA9850: */ -/* lower 5 bites are wideband and spectral expander alignment - * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ -#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */ -#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ -#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ - - -/* 0x0a - A3 */ -/* Common to both TDA9855 and TDA9850: */ -/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), - * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ -#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ - -/* Unique to TDA9855: */ -/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), - * 1200ohm (0x1), 2100ohm (0x3) */ - - -/* Begin code */ - -static int tda985x_write(struct i2c_client *client, int subaddr, int val) -{ - unsigned char buffer[2]; - d2printk("tda985x: In tda985x_write\n"); - dprintk("tda985x: Writing %d 0x%x\n", subaddr, val); - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -static int tda985x_read(struct i2c_client *client) -{ - unsigned char buffer; - d2printk("tda985x: In tda985x_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda985x: I/O error, trying (read)\n"); - return -1; - } - dprintk("tda985x: Read 0x%02x\n", buffer); - return buffer; -} - -static int tda985x_set(struct i2c_client *client) -{ - struct tda985x *t = client->data; - unsigned char buf[16]; - d2printk("tda985x: In tda985x_set\n"); - - if (chip == 9855) - { - dprintk(KERN_INFO - "tda985x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", - t->rvol,t->lvol,t->bass,t->treble,t->sub, - t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); - buf[0] = TDA9855_VR; - buf[1] = t->rvol; - buf[2] = t->lvol; - buf[3] = t->bass; - buf[4] = t->treble; - buf[5] = t->sub; - buf[6] = t->c5; - buf[7] = t->c6; - buf[8] = t->c7; - buf[9] = t->a1; - buf[10] = t->a2; - buf[11] = t->a3; - if (12 != i2c_master_send(client,buf,12)) { - printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n"); - return -1; - } - } - - else if (chip == 9850) - { - dprintk(KERN_INFO - "tda986x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", - t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); - buf[0] = TDA9850_C4; - buf[1] = t->c4; - buf[2] = t->c5; - buf[3] = t->c6; - buf[4] = t->c7; - buf[5] = t->a1; - buf[6] = t->a2; - buf[7] = t->a3; - if (8 != i2c_master_send(client,buf,8)) { - printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n"); - return -1; - } - } - - return 0; -} - -static void do_tda985x_init(struct i2c_client *client) -{ - struct tda985x *t = client->data; - d2printk("tda985x: In tda985x_init\n"); - - if (chip == 9855) - { - printk("tda985x: Using tda9855 options\n"); - t->rvol = 0x6f; /* 0dB */ - t->lvol = 0x6f; /* 0dB */ - t->bass = 0x0e; /* 0dB */ - t->treble = (0x07 << 1); /* 0dB */ - t->sub = 0x8 << 2; /* 0dB */ - t->c5 = TDA9855_MUTE | TDA9855_AVL | - TDA9855_LOUD | TDA9855_INT; - /* Set Mute, AVL, Loudness off, Internal sound */ - t->c6 = TDA985x_STEREO | TDA9855_LINEAR | - TDA9855_TZCM | TDA9855_VZCM; - /* Stereo linear mode, also wait til zero crossings */ - t->c7 = 0x07; /* 0dB input gain */ - } - - else if (chip == 9850) - { - printk("tda985x: Using tda9850 options\n"); - t->c4 = 0x08; /* Set stereo noise thresh to nominal */ - t->c5 = 0x08; /* Set SAP noise threshold to nominal */ - t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */ - t->c7 = 0x07; /* 0dB input gain */ - } - - /* The following is valid for both chip types */ - t->a1 = 0x10; /* Select nominal wideband expander */ - t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */ - t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */ - - tda985x_set(client); -} - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda985x_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda985x *t; - struct i2c_client *client; - d2printk("tda985x: In tda985x_attach\n"); - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = t = kmalloc(sizeof *t,GFP_KERNEL); - if (!t) - return -ENOMEM; - memset(t,0,sizeof *t); - do_tda985x_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA985x"); - printk(KERN_INFO "tda985x: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda985x_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda985x_attach); - return 0; -} - -static int tda985x_detach(struct i2c_client *client) -{ - struct tda985x *t = client->data; - - do_tda985x_init(client); - i2c_detach_client(client); - - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda985x_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda985x *t = client->data; - d2printk("tda985x: In tda985x_command\n"); -#if 0 - __u16 *sarg = arg; -#endif - - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - dprintk("tda985x: VIDIOCGAUDIO\n"); - if (chip == 9855) - { - int left,right; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - - /* min is 0x27 max is 0x7f, vstep is 2e8 */ - left = (t->lvol-0x27)*0x2e8; - right = (t->rvol-0x27)*0x2e8; - va->volume=MAX(left,right); - va->balance=(32768*MIN(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(leftbalance) : va->balance; - va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */ - va->treble = ((t->treble>>1)-0x3)*0x1c71; - } - - /* Valid for both chips: */ - { - va->mode = ((TDA985x_STP | TDA985x_SAPP) & - tda985x_read(client)) >> 4; - /* Add mono mode regardless of SAP and stereo */ - /* Allows forced mono */ - va->mode |= VIDEO_SOUND_MONO; - } - - break; /* VIDIOCGAUDIO case */ - } - - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - dprintk("tda985x: VIDEOCSAUDIO\n"); - if (chip == 9855) - { - int left,right; - - left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - right = (MIN(va->balance,32768) * - va->volume) / 32768; - t->lvol = left/0x2e8+0x27; - t->rvol = right/0x2e8+0x27; - t->bass = va->bass/0xccc+0x6; - t->treble = (va->treble/0x1c71+0x3)<<1; - tda985x_write(client,TDA9855_VL,t->lvol); - tda985x_write(client,TDA9855_VR,t->rvol); - tda985x_write(client,TDA9855_BA, t->bass); - tda985x_write(client,TDA9855_TR,t->treble); - } - - /* The following is valid for both chips */ - - switch (va->mode) { - case VIDEO_SOUND_MONO: - dprintk("tda985x: VIDEO_SOUND_MONO\n"); - t->c6= TDA985x_MONO | (t->c6 & 0x3f); - tda985x_write(client,TDA985x_C6,t->c6); - break; - case VIDEO_SOUND_STEREO: - dprintk("tda985x: VIDEO_SOUND_STEREO\n"); - t->c6= TDA985x_STEREO | (t->c6 & 0x3f); - tda985x_write(client,TDA985x_C6,t->c6); - break; - case VIDEO_SOUND_LANG1: - dprintk("tda985x: VIDEO_SOUND_LANG1\n"); - t->c6= TDA985x_SAP | (t->c6 & 0x3f); - tda985x_write(client,TDA985x_C6,t->c6); - break; - } /* End of (va->mode) switch */ - - break; - - } /* end of VIDEOCSAUDIO case */ - - default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ - - /* nothing */ - d2printk("tda985x: Default\n"); - - } /* end of (cmd) switch */ - - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda985x driver", - I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */ - I2C_DF_NOTIFY, - tda985x_probe, - tda985x_detach, - tda985x_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda985x_init(void) -#endif -{ - if ( (chip != 9850) && (chip != 9855) ) - { - printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n"); - return -EINVAL; - } - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tda9875.c linux/drivers/char/tda9875.c --- v2.4.0-test6/linux/drivers/char/tda9875.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/tda9875.c Wed Dec 31 16:00:00 1969 @@ -1,403 +0,0 @@ -/* - * For the TDA9875 chip - * (The TDA9875 is used on the Diamond DTV2000 french version - * Other cards probably use these chips as well.) - * This driver will not complain if used with any - * other i2c device with the same address. - * - * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and - * Eric Sandeen - * This code is placed under the terms of the GNU General Public License - * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * Which was based on tda8425.c by Greg Alexander (c) 1998 - * - * OPTIONS: - * debug - set to 1 if you'd like to see debug messages - * - * Revision: 0.1 - original version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - -/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */ -#ifndef I2C_DRIVERID_TDA9875 - #define I2C_DRIVERID_TDA9875 28 -#endif - - -MODULE_PARM(debug,"i"); - -static int debug = 0; /* insmod parameter */ - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { - I2C_TDA9875 >> 1, - I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -/* This is a superset of the TDA9875 */ -struct tda9875 { - int mode; - int rvol, lvol; - int bass, treble; -}; - - -static struct i2c_driver driver; -static struct i2c_client client_template; - -#define dprintk if (debug) printk - -/* The TDA9875 is made by Philips Semiconductor - * http://www.semiconductors.philips.com - * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator - * - */ - - /* subaddresses for TDA9875 */ -#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/ -#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */ -#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ -#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ - -#define TDA9875_CH1V 0x0c /*Chanel 1 volume (mute)*/ -#define TDA9875_CH2V 0x0d /*Chanel 2 volume (mute)*/ -#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ -#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ - -#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/ -#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/ -#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/ -#define TDA9875_MVL 0x1a /* Main volume gauche */ -#define TDA9875_MVR 0x1b /* Main volume droite */ -#define TDA9875_MBA 0x1d /* Main Basse */ -#define TDA9875_MTR 0x1e /* Main treble */ -#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/ -#define TDA9875_AVL 0x20 /* Auxilary volume gauche */ -#define TDA9875_AVR 0x21 /* Auxilary volume droite */ -#define TDA9875_ABA 0x22 /* Auxilary Basse */ -#define TDA9875_ATR 0x23 /* Auxilary treble */ - -#define TDA9875_MSR 0x02 /* Monitor select register */ -#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */ -#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */ -#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */ -#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */ -#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */ -#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */ -#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/ -#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/ -#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/ - -/* values */ -#define TDA9875_MUTE_ON 0xff /* general mute */ -#define TDA9875_MUTE_OFF 0xcc /* general no mute */ - - - -/* Begin code */ - -static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char val) -{ - unsigned char buffer[2]; - dprintk("In tda9875_write\n"); - dprintk("Writing %d 0x%x\n", subaddr, val); - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda9875: I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -#if 0 -static int tda9875_read(struct i2c_client *client) -{ - unsigned char buffer; - dprintk("In tda9875_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda9875: I/O error, trying (read)\n"); - return -1; - } - dprintk("Read 0x%02x\n", buffer); - return buffer; -} -#endif - -static void tda9875_set(struct i2c_client *client) -{ - struct tda9875 *tda = client->data; - unsigned char a; - - dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",tda->lvol,tda->rvol,tda->bass,tda->treble); - - - a = tda->lvol & 0xff; - tda9875_write(client, TDA9875_MVL, a); - a =tda->rvol & 0xff; - tda9875_write(client, TDA9875_MVR, a); - a =tda->bass & 0xff; - tda9875_write(client, TDA9875_MBA, a); - a =tda->treble & 0xff; - tda9875_write(client, TDA9875_MTR, a); -} - -static void do_tda9875_init(struct i2c_client *client) -{ - struct tda9875 *t = client->data; - dprintk("In tda9875_init\n"); - tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/ - tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/ - tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/ - tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/ - tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/ - tda9875_write(client, TDA9875_C2MSB, 0x00 ); /*Car2(NICAM) MSB XMHz*/ - tda9875_write(client, TDA9875_C2MIB, 0x00 ); /*Car2(NICAM) MIB XMHz*/ - tda9875_write(client, TDA9875_C2LSB, 0x00 ); /*Car2(NICAM) LSB XMHz*/ - tda9875_write(client, TDA9875_DCR, 0x00 ); /*Demod config 0x00*/ - tda9875_write(client, TDA9875_DEEM, 0x44 ); /*DE-Emph 0b0100 0100*/ - tda9875_write(client, TDA9875_FMAT, 0x00 ); /*FM Matrix reg 0x00*/ - tda9875_write(client, TDA9875_SC1, 0x00 ); /* SCART 1 (SC1)*/ - tda9875_write(client, TDA9875_SC2, 0x01 ); /* SCART 2 (sc2)*/ - - tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Chanel volume 1 mute*/ - tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Chanel volume 2 mute */ - tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/ - tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/ - tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/ - tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */ - tda9875_write(client, TDA9875_MCS, 0x44 ); /* Main ch select (DAC) */ - tda9875_write(client, TDA9875_MVL, 0x03 ); /* Vol Main left 10dB */ - tda9875_write(client, TDA9875_MVR, 0x03 ); /* Vol Main right 10dB*/ - tda9875_write(client, TDA9875_MBA, 0x00 ); /* Main Bass Main 0dB*/ - tda9875_write(client, TDA9875_MTR, 0x00 ); /* Main Treble Main 0dB*/ - tda9875_write(client, TDA9875_ACS, 0x44 ); /* Aux chan select (dac)*/ - tda9875_write(client, TDA9875_AVL, 0x00 ); /* Vol Aux left 0dB*/ - tda9875_write(client, TDA9875_AVR, 0x00 ); /* Vol Aux right 0dB*/ - tda9875_write(client, TDA9875_ABA, 0x00 ); /* Aux Bass Main 0dB*/ - tda9875_write(client, TDA9875_ATR, 0x00 ); /* Aux Aigus Main 0dB*/ - - tda9875_write(client, TDA9875_MUT, 0xcc ); /* General mute */ - - t->mode=AUDIO_UNMUTE; - t->lvol=t->rvol =0; /* 0dB */ - t->bass=0; /* 0dB */ - t->treble=0; /* 0dB */ - tda9875_set(client); - -} - - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda9875_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda9875 *t; - struct i2c_client *client; - dprintk("In tda9875_attach\n"); - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = t = kmalloc(sizeof *t,GFP_KERNEL); - if (!t) - return -ENOMEM; - memset(t,0,sizeof *t); - do_tda9875_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA9875"); - printk(KERN_INFO "tda9875: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda9875_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda9875_attach); - return 0; -} - -static int tda9875_detach(struct i2c_client *client) -{ - struct tda9875 *t = client->data; - - do_tda9875_init(client); - i2c_detach_client(client); - - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda9875_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda9875 *t = client->data; - - dprintk("In tda9875_command...\n"); - - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - int left,right; - - dprintk("VIDIOCGAUDIO\n"); - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - - /* min is -84 max is 24 */ - left = (t->lvol+84)*606; - right = (t->rvol+84)*606; - va->volume=MAX(left,right); - va->balance=(32768*MIN(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(leftbalance) : va->balance; - va->bass = (t->bass+12)*2427; /* min -12 max +15 */ - va->treble = (t->treble+12)*2730;/* min -12 max +12 */ - - va->mode |= VIDEO_SOUND_MONO; - - - break; /* VIDIOCGAUDIO case */ - } - - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - dprintk("VIDEOCSAUDIO...\n"); - left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - right = (MIN(va->balance,32768) * - va->volume) / 32768; - t->lvol = ((left/606)-84) & 0xff; - if (t->lvol > 24) - t->lvol = 24; - if (t->lvol < -84) - t->lvol = -84 & 0xff; - - t->rvol = ((right/606)-84) & 0xff; - if (t->rvol > 24) - t->rvol = 24; - if (t->rvol < -84) - t->rvol = -84 & 0xff; - - t->bass = ((va->bass/2400)-12) & 0xff; - if (t->bass > 15) - t->bass = 15; - if (t->bass < -12) - t->bass = -12 & 0xff; - - t->treble = ((va->treble/2700)-12) & 0xff; - if (t->treble > 12) - t->treble = 12; - if (t->treble < -12) - t->treble = -12 & 0xff; - - - -//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); - - - tda9875_set(client); - - break; - - } /* end of VIDEOCSAUDIO case */ - - default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ - - /* nothing */ - dprintk("Default\n"); - - } /* end of (cmd) switch */ - - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda9875 driver", - I2C_DRIVERID_TDA9875, /* Get new one for TDA9875 */ - I2C_DF_NOTIFY, - tda9875_probe, - tda9875_detach, - tda9875_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda9875_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tea6300.c linux/drivers/char/tea6300.c --- v2.4.0-test6/linux/drivers/char/tea6300.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/char/tea6300.c Wed Dec 31 16:00:00 1969 @@ -1,344 +0,0 @@ -/* - * for the TEA6300 chip (only found on Gateway STB TV/FM cards tho the best - * of my knowledge) - * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF THE WRONG - * CHIP (i.e., an MSP3400) IS ON I2C ADDRESS 0x80 (it relies on i2c to - * make sure that there is a device acknowledging that address). This - * is a potential problem because the MSP3400 is very popular and does - * use this address! You have been warned! - * - * Copyright (c) 1998 Greg Alexander - * This code is placed under the terms of the GNU General Public License - * Code liberally copied from msp3400.c, which is by Gerd Knorr - * - * All of this should work, though it would be nice to eventually support - * balance (different left,right values) and, if someone ever finds a card - * with the support (or if you're careful with a soldering iron), fade - * (front/back). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - - -/* Addresses to scan */ -#define I2C_TEA6300 0x80 -static unsigned short normal_i2c[] = { - I2C_TEA6300 >> 1, - I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - - -MODULE_PARM(debug,"i"); -static int debug = 0; /* insmod parameter */ - -#define dprintk if (debug) printk - - -struct tea6300 { - int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ - int stereo; - __u16 left,right; - __u16 bass,treble; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - -#define TEA6300_VL 0x00 /* volume left */ -#define TEA6300_VR 0x01 /* volume right */ -#define TEA6300_BA 0x02 /* bass */ -#define TEA6300_TR 0x03 /* treble */ -#define TEA6300_FA 0x04 /* fader control */ -#define TEA6300_S 0x05 /* switch register */ - /* values for those registers: */ -#define TEA6300_S_SA 0x01 /* stereo A input */ -#define TEA6300_S_SB 0x02 /* stereo B */ -#define TEA6300_S_SC 0x04 /* stereo C */ -#define TEA6300_S_GMU 0x80 /* general mute */ - - -/* ******************************** * - * functions for talking to TEA6300 * - * ******************************** */ - -static int tea6300_write(struct i2c_client *client, int addr, int val) -{ - unsigned char buffer[2]; - - buffer[0] = addr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tea6300: I/O error, trying (write %d 0x%x)\n", - addr, val); - return -1; - } - return 0; -} - -static void tea6300_set(struct i2c_client *client) -{ - struct tea6300 *tea = client->data; - - /* mode is ignored today */ - dprintk(KERN_DEBUG "tea6300_set(%04x,%04x,%04x,%04x)\n",tea->left>>10,tea->right>>10,tea->bass>>12,tea->treble>>12); - tea6300_write(client, TEA6300_VL, tea->left>>10 ); - tea6300_write(client, TEA6300_VR, tea->right>>10 ); - tea6300_write(client, TEA6300_BA, tea->bass>>12 ); - tea6300_write(client, TEA6300_TR, tea->treble>>12); -} - -static void do_tea6300_init(struct i2c_client *client) -{ - struct tea6300 *tea = client->data; - - tea->left=tea->right =49152; /* -10dB (loud enough, but not beyond - normal line levels - so as to avoid - clipping */ - tea->bass=tea->treble=28672; /* 0dB */ - tea->mode=AUDIO_OFF; - tea->stereo=1; - /* left=right=0x27<<10, bass=treble=0x07<<12 */ - tea6300_write(client, TEA6300_FA, 0x3f ); /* fader off */ - tea6300_write(client, TEA6300_S , TEA6300_S_GMU); /* mute */ - tea6300_set(client); -} - -static void tea6300_audio(struct i2c_client *client, int mode) -{ - struct tea6300 *tea = client->data; - - /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ - dprintk(KERN_DEBUG "tea6300_audio:%d (T,R,E,I,O)\n",mode); - tea->mode=mode; - if (mode==AUDIO_OFF) { /* just mute it */ - tea6300_write(client, TEA6300_S, TEA6300_S_GMU); - return; - } - switch(mode) { - case AUDIO_TUNER: - tea6300_write(client, TEA6300_S, TEA6300_S_SA); - break; - case AUDIO_RADIO: - tea6300_write(client, TEA6300_S, TEA6300_S_SB); - break; - case AUDIO_EXTERN: - tea6300_write(client, TEA6300_S, TEA6300_S_SC); - break; - } -} - - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tea6300_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tea6300 *tea; - struct i2c_client *client; - - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); - if (!tea) - return -ENOMEM; - memset(tea,0,sizeof *tea); - do_tea6300_init(client); - - MOD_INC_USE_COUNT; - strcpy(client->name,"TEA6300T"); - printk(KERN_INFO "tea6300: initialized\n"); - - i2c_attach_client(client); - return 0; -} - -static int tea6300_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tea6300_attach); - return 0; -} - -static int tea6300_detach(struct i2c_client *client) -{ - struct tea6300 *tea = client->data; - - do_tea6300_init(client); - i2c_detach_client(client); - - kfree(tea); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int -tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct tea6300 *tea = client->data; - __u16 *sarg = arg; - - switch (cmd) { - case AUDC_SET_RADIO: - tea6300_audio(client,AUDIO_RADIO); - break; - case AUDC_SET_INPUT: - tea6300_audio(client,*sarg); - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - va->volume=MAX(tea->left,tea->right); - va->balance=(32768*MIN(tea->left,tea->right))/ - (va->volume ? va->volume : 1); - va->balance=(tea->leftright)? - (65535-va->balance) : va->balance; - va->bass = tea->bass; - va->treble = tea->treble; - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - - tea->left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - tea->right = (MIN(va->balance,32768) * - va->volume) / 32768; - tea->bass = va->bass; - tea->treble = va->treble; - tea6300_set(client); - break; - } -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_GET_VOLUME_LEFT: - *sarg = tea->left; - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = tea->right; - break; - case AUDC_SET_VOLUME_LEFT: - tea->left = *sarg; - tea6300_set(client); - break; - case AUDC_SET_VOLUME_RIGHT: - tea->right = *sarg; - tea6300_set(client); - break; - - case AUDC_GET_BASS: - *sarg = tea->bass; - break; - case AUDC_SET_BASS: - tea->bass = *sarg; - tea6300_set(client); - break; - - case AUDC_GET_TREBLE: - *sarg = tea->treble; - break; - case AUDC_SET_TREBLE: - tea->treble = *sarg; - tea6300_set(client); - break; - - case AUDC_GET_STEREO: - *sarg = tea->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; - break; - case AUDC_SET_STEREO: - tea->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; - /* TODO: make this write to the TDA9850? */ - break; - -/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to - case AUDC_NEWCHANNEL: it and it would require preserving state - case AUDC_GET_DC: huh?? (not used by bttv.c) -*/ -#endif - default: - /* nothing */ - } - return 0; -} - -static struct i2c_driver driver = { - "i2c tea6300 driver", - I2C_DRIVERID_TEA6300, - I2C_DF_NOTIFY, - tea6300_probe, - tea6300_detach, - tea6300_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tea6300_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tea6420.c linux/drivers/char/tea6420.c --- v2.4.0-test6/linux/drivers/char/tea6420.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/tea6420.c Wed Dec 31 16:00:00 1969 @@ -1,268 +0,0 @@ -/* - * for the TEA6420 chip (only found on 3DFX (STB) TV/FM cards to the best - * of my knowledge) - * Copyright (C) 2000 Dave Stuart - * This code is placed under the terms of the GNU General Public License - * Code liberally copied from tea6300 by . . . - * - * Copyright (c) 1998 Greg Alexander - * This code is placed under the terms of the GNU General Public License - * Code liberally copied from msp3400.c, which is by Gerd Knorr - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - - -/* Addresses to scan */ -#define I2C_TEA6420 0x98 -static unsigned short normal_i2c[] = { - I2C_TEA6420 >> 1, - I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - - -MODULE_PARM(debug,"i"); -static int debug = 0; /* insmod parameter */ - -#define dprintk if (debug) printk - - -struct tea6420 { - int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ - int stereo; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - -#define TEA6420_S_SA 0x00 /* stereo A input */ -#define TEA6420_S_SB 0x01 /* stereo B */ -#define TEA6420_S_SC 0x02 /* stereo C */ -#define TEA6420_S_SD 0x03 /* stereo D */ -#define TEA6420_S_SE 0x04 /* stereo E */ -#define TEA6420_S_GMU 0x05 /* general mute */ - - -/* ******************************** * - * functions for talking to TEA6420 * - * ******************************** */ - -static int tea6420_write(struct i2c_client *client, int val) -{ - unsigned char buffer[2]; - int result; - -/* buffer[0] = addr; */ - buffer[0] = val; - result = i2c_master_send(client,buffer,1); - if (1 != result) { - printk(KERN_WARNING "tea6420: I/O error, trying (write -0x%x) result = %d\n", val, result); - return -1; - } - return 0; -} - - -static void do_tea6420_init(struct i2c_client *client) -{ - struct tea6420 *tea = client->data; - - tea->mode=AUDIO_OFF; - tea->stereo=1; - tea6420_write(client, TEA6420_S_GMU); /* mute */ -} - -static void tea6420_audio(struct i2c_client *client, int mode) -{ - struct tea6420 *tea = client->data; - - /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ - dprintk(KERN_DEBUG "tea6420_audio:%d (T,R,E,I,O)\n",mode); - tea->mode=mode; - if (mode==AUDIO_OFF) { /* just mute it */ - tea6420_write(client, TEA6420_S_GMU); - return; - } - switch(mode) { - case AUDIO_TUNER: - tea6420_write(client, TEA6420_S_SA); - break; - case AUDIO_RADIO: - tea6420_write(client, TEA6420_S_SB); - break; - case AUDIO_EXTERN: - tea6420_write(client, TEA6420_S_SC); - break; - } -} - - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tea6420_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tea6420 *tea; - struct i2c_client *client; - - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); - if (!tea) - return -ENOMEM; - memset(tea,0,sizeof *tea); - do_tea6420_init(client); - - MOD_INC_USE_COUNT; - strcpy(client->name,"TEA6420"); - printk(KERN_INFO "tea6420: initialized\n"); - - i2c_attach_client(client); - return 0; -} - -static int tea6420_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tea6420_attach); - return 0; -} - -static int tea6420_detach(struct i2c_client *client) -{ - struct tea6420 *tea = client->data; - - do_tea6420_init(client); - i2c_detach_client(client); - - kfree(tea); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int -tea6420_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - __u16 *sarg = arg; - - switch (cmd) { - case AUDC_SET_RADIO: - tea6420_audio(client,AUDIO_RADIO); - break; - case AUDC_SET_INPUT: - tea6420_audio(client,*sarg); - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; -/* va->volume=MAX(tea->left,tea->right); - va->balance=(32768*MIN(tea->left,tea->right))/ - (va->volume ? va->volume : 1); - va->balance=(tea->leftright)? - (65535-va->balance) : va->balance; - va->bass = tea->bass; - va->treble = tea->treble; -*/ break; - } - case VIDIOCSAUDIO: - { - -/* tea->left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - tea->right = (MIN(va->balance,32768) * - va->volume) / 32768; - tea->bass = va->bass; - tea->treble = va->treble; - tea6420_set(client); -*/ break; - } - -default: - /* nothing */ - } - return 0; -} - -static struct i2c_driver driver = { - "i2c tea6420 driver", - I2C_DRIVERID_TEA6420, - I2C_DF_NOTIFY, - tea6420_probe, - tea6420_detach, - tea6420_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tea6420_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.4.0-test6/linux/drivers/char/tty_io.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/tty_io.c Sat Aug 12 19:48:04 2000 @@ -1839,9 +1839,12 @@ read_lock(&tasklist_lock); for_each_task(p) { if ((p->tty == tty) || - ((session > 0) && (p->session == session))) + ((session > 0) && (p->session == session))) { send_sig(SIGKILL, p, 1); - else if (p->files) { + continue; + } + task_lock(p); + if (p->files) { read_lock(&p->files->file_lock); /* FIXME: p->files could change */ for (i=0; i < p->files->max_fds; i++) { @@ -1854,6 +1857,7 @@ } read_unlock(&p->files->file_lock); } + task_unlock(p); } read_unlock(&tasklist_lock); #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tuner-3036.c linux/drivers/char/tuner-3036.c --- v2.4.0-test6/linux/drivers/char/tuner-3036.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/tuner-3036.c Wed Dec 31 16:00:00 1969 @@ -1,227 +0,0 @@ -/* - * Driver for Philips SAB3036 "CITAC" tuner control chip. - * - * Author: Phil Blundell - * - * The SAB3036 is just about different enough from the chips that - * tuner.c copes with to make it not worth the effort to crowbar - * the support into that file. So instead we have a separate driver. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "tuner.h" - -static int debug; /* insmod parameter */ -static int this_adap; - -static struct i2c_client client_template; - -/* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x60, 0x61, I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -/* ---------------------------------------------------------------------- */ - -static unsigned char -tuner_getstatus (struct i2c_client *c) -{ - unsigned char byte; - if (i2c_master_recv(c, &byte, 1) != 1) - printk(KERN_ERR "tuner-3036: I/O error.\n"); - return byte; -} - -#define TUNER_FL 0x80 - -static int -tuner_islocked (struct i2c_client *c) -{ - return (tuner_getstatus(c) & TUNER_FL); -} - -/* ---------------------------------------------------------------------- */ - -static void -set_tv_freq(struct i2c_client *c, int freq) -{ - u16 div = ((freq * 20) / 16); - unsigned long give_up = jiffies + HZ; - unsigned char buffer[2]; - - if (debug) - printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div); - - /* Select high tuning current */ - buffer[0] = 0x29; - buffer[1] = 0x3e; - - if (i2c_master_send(c, buffer, 2) != 2) - printk("tuner: i2c i/o error 1\n"); - - buffer[0] = 0x80 | ((div>>8) & 0x7f); - buffer[1] = div & 0xff; - - if (i2c_master_send(c, buffer, 2) != 2) - printk("tuner: i2c i/o error 2\n"); - - while (!tuner_islocked(c) && time_before(jiffies, give_up)) - schedule(); - - if (!tuner_islocked(c)) - printk(KERN_WARNING "tuner: failed to achieve PLL lock\n"); - - /* Select low tuning current and engage AFC */ - buffer[0] = 0x29; - buffer[1] = 0xb2; - - if (i2c_master_send(c, buffer, 2) != 2) - printk("tuner: i2c i/o error 3\n"); - - if (debug) - printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c)); -} - -/* ---------------------------------------------------------------------- */ - -static int -tuner_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 }; - - struct i2c_client *client; - - if (this_adap > 0) - return -1; - this_adap++; - - client_template.adapter = adap; - client_template.addr = addr; - - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) - return -ENOMEM; - memcpy(client, &client_template, sizeof(struct i2c_client)); - - printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client)); - - i2c_attach_client(client); - MOD_INC_USE_COUNT; - - if (i2c_master_send(client, buffer, 2) != 2) - printk("tuner: i2c i/o error 1\n"); - if (i2c_master_send(client, buffer+2, 2) != 2) - printk("tuner: i2c i/o error 2\n"); - if (i2c_master_send(client, buffer+4, 2) != 2) - printk("tuner: i2c i/o error 3\n"); - return 0; -} - -static int -tuner_detach(struct i2c_client *c) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -static int -tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - int *iarg = (int*)arg; - - switch (cmd) - { - case TUNER_SET_TVFREQ: - set_tv_freq(client, *iarg); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int -tuner_probe(struct i2c_adapter *adap) -{ - this_adap = 0; - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_LP)) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver -i2c_driver_tuner = -{ - "sab3036", /* name */ - I2C_DRIVERID_SAB3036, /* ID */ - I2C_DF_NOTIFY, - tuner_probe, - tuner_detach, - tuner_command -}; - -static struct i2c_client client_template = -{ - "SAB3036", /* name */ - -1, - 0, - 0, - NULL, - &i2c_driver_tuner -}; - -EXPORT_NO_SYMBOLS; - -int __init -tuner3036_init(void) -{ - i2c_add_driver(&i2c_driver_tuner); - return 0; -} - -void __exit -tuner3036_exit(void) -{ - i2c_del_driver(&i2c_driver_tuner); -} - -MODULE_DESCRIPTION("SAB3036 tuner driver"); -MODULE_AUTHOR("Philip Blundell "); -MODULE_PARM(debug,"i"); -MODULE_PARM_DESC(debug,"Enable debugging output"); - -module_init(tuner3036_init); -module_exit(tuner3036_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tuner.c linux/drivers/char/tuner.c --- v2.4.0-test6/linux/drivers/char/tuner.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/tuner.c Wed Dec 31 16:00:00 1969 @@ -1,451 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tuner.h" -#include "audiochip.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -static int debug = 0; /* insmod parameter */ -static int type = -1; /* insmod parameter */ - -static int addr = 0; -static int this_adap; - -#define dprintk if (debug) printk - -MODULE_PARM(debug,"i"); -MODULE_PARM(type,"i"); -MODULE_PARM(addr,"i"); - -struct tuner -{ - int type; /* chip type */ - int freq; /* keep track of the current settings */ - int std; - - int radio; - int mode; /* PAL(0)/SECAM(1) mode (PHILIPS_SECAM only) */ -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - -/* ---------------------------------------------------------------------- */ - -struct tunertype -{ - char *name; - unsigned char Vendor; - unsigned char Type; - - unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */ - unsigned short thresh2; - unsigned char VHF_L; - unsigned char VHF_H; - unsigned char UHF; - unsigned char config; - unsigned short IFPCoff; - unsigned char mode; /* mode change value (tested PHILIPS_SECAM only) */ - /* 0x01 -> ??? no change ??? */ - /* 0x02 -> PAL BDGHI / SECAM L */ - /* 0x04 -> ??? PAL others / SECAM others ??? */ - int capability; -}; - -/* - * 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,623}, - { "Philips PAL_I", Philips, PAL_I, - 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, - { "Philips SECAM", Philips, SECAM, - 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623,0x02}, - { "NoTuner", NoTuner, NOTUNER, - 0,0,0x00,0x00,0x00,0x00,0x00,000}, - { "Philips PAL", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, - { "Temic NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, - { "Temic PAL_I", TEMIC, PAL_I, - 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, - { "Temic 4036 FY5 NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, - { "Alps HSBH1", TEMIC, NTSC, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBE1",TEMIC,PAL, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, - { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, - { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, - { "Temic 4006FH5", TEMIC, PAL_I, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, -}; -#define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) - -/* ---------------------------------------------------------------------- */ - -static int tuner_getstatus(struct i2c_client *c) -{ - unsigned char byte; - - if (1 != i2c_master_recv(c,&byte,1)) - return 0; - return byte; -} - -#define TUNER_POR 0x80 -#define TUNER_FL 0x40 -#define TUNER_MODE 0x38 -#define TUNER_AFC 0x07 - -static int tuner_islocked (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_FL); -} - -static int tuner_afcstatus (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_AFC) - 2; -} - -#if 0 /* unused */ -static int tuner_mode (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_MODE) >> 3; -} -#endif - -static void set_tv_freq(struct i2c_client *c, int freq) -{ - u8 config; - u16 div; - struct tunertype *tun; - struct tuner *t = c->data; - unsigned char buffer[4]; - int rc; - - if (t->type == -1) { - printk("tuner: tuner type not set\n"); - return; - } - - tun=&tuners[t->type]; - if (freq < tun->thresh1) - config = tun->VHF_L; - else if (freq < tun->thresh2) - config = tun->VHF_H; - else - config = tun->UHF; - -#if 1 // Fix colorstandard mode change - if (t->type == TUNER_PHILIPS_SECAM && t->mode) - config |= tun->mode; - else - config &= ~tun->mode; -#else - config &= ~tun->mode; -#endif - - div=freq + tun->IFPCoff; - - /* - * Philips FI1216MK2 remark from specification : - * for channel selection involving band switching, and to ensure - * smooth tuning to the desired channel without causing - * unnecessary charge pump action, it is recommended to consider - * the difference between wanted channel frequency and the - * current channel frequency. Unnecessary charge pump action - * will result in very low tuning voltage which may drive the - * oscillator to extreme conditions. - */ - /* - * Progfou: specification says to send config data before - * frequency in case (wanted frequency < current frequency). - */ - - if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { - buffer[0] = tun->config; - buffer[1] = config; - buffer[2] = (div>>8) & 0x7f; - buffer[3] = div & 0xff; - } else { - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = tun->config; - buffer[3] = config; - } - - if (4 != (rc = i2c_master_send(c,buffer,4))) - printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); - -} - -static void set_radio_freq(struct i2c_client *c, int freq) -{ - u8 config; - u16 div; - struct tunertype *tun; - struct tuner *t = (struct tuner*)c->data; - unsigned char buffer[4]; - int rc; - - if (t->type == -1) { - printk("tuner: tuner type not set\n"); - return; - } - - tun=&tuners[t->type]; - config = 0xa5; - div=freq + (int)(16*10.7); - div&=0x7fff; - - buffer[0] = (div>>8) & 0x7f; - buffer[1] = div & 0xff; - buffer[2] = tun->config; - buffer[3] = config; - if (4 != (rc = i2c_master_send(c,buffer,4))) - printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); - - if (debug) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); - - if (tuner_islocked (c)) - printk ("tuner: PLL locked\n"); - else - printk ("tuner: PLL not locked\n"); - - printk ("tuner: AFC: %d\n", tuner_afcstatus (c)); - } -} -/* ---------------------------------------------------------------------- */ - - -static int tuner_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tuner *t; - struct i2c_client *client; - - if (this_adap > 0) - return -1; - this_adap++; - - client_template.adapter = adap; - client_template.addr = addr; - - printk("tuner: chip found @ 0x%x\n",addr); - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); - if (NULL == t) { - kfree(client); - return -ENOMEM; - } - memset(t,0,sizeof(struct tuner)); - if (type >= 0 && type < TUNERS) { - t->type = type; - strncpy(client->name, tuners[t->type].name, sizeof(client->name)); - } else { - t->type = -1; - } - i2c_attach_client(client); - MOD_INC_USE_COUNT; - - return 0; -} - -static int tuner_probe(struct i2c_adapter *adap) -{ - if (0 != addr) { - normal_i2c_range[0] = addr; - normal_i2c_range[1] = addr; - } - this_adap = 0; - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; -} - -static int tuner_detach(struct i2c_client *client) -{ - struct tuner *t = (struct tuner*)client->data; - - i2c_detach_client(client); - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int -tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct tuner *t = (struct tuner*)client->data; - int *iarg = (int*)arg; -#if 0 - __u16 *sarg = (__u16*)arg; -#endif - - switch (cmd) { - - /* --- configuration --- */ - case TUNER_SET_TYPE: - if (t->type != -1) - return 0; - if (*iarg < 0 || *iarg >= TUNERS) - return 0; - t->type = *iarg; - dprintk("tuner: type set to %d (%s)\n", - t->type,tuners[t->type].name); - strncpy(client->name, tuners[t->type].name, sizeof(client->name)); - break; - case AUDC_SET_RADIO: - t->radio = 1; - break; - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCSCHAN: - { - struct video_channel *vc = arg; - - t->radio = 0; - if (t->type == TUNER_PHILIPS_SECAM) { - t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; - set_tv_freq(client,t->freq); - } - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *v = arg; - - t->freq = *v; - if (t->radio) { - dprintk("tuner: radio freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); - set_radio_freq(client,t->freq); - } else { - dprintk("tuner: tv freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); - set_tv_freq(client,t->freq); - } - return 0; - } -#if 0 - /* --- old, obsolete interface --- */ - case TUNER_SET_TVFREQ: - dprintk("tuner: tv freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); - set_tv_freq(client,*iarg); - t->radio = 0; - t->freq = *iarg; - break; - - case TUNER_SET_RADIOFREQ: - dprintk("tuner: radio freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); - set_radio_freq(client,*iarg); - t->radio = 1; - t->freq = *iarg; - break; - case TUNER_SET_MODE: - if (t->type != TUNER_PHILIPS_SECAM) { - dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); - } else { - int mode=(*sarg==VIDEO_MODE_SECAM)?1:0; - dprintk("tuner: mode set to %d\n", *sarg); - t->mode = mode; - set_tv_freq(client,t->freq); - } - break; -#endif - default: - /* nothing */ - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver driver = { - "i2c TV tuner driver", - I2C_DRIVERID_TUNER, - I2C_DF_NOTIFY, - tuner_probe, - tuner_detach, - tuner_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -EXPORT_NO_SYMBOLS; - -int tuner_init_module(void) -{ - i2c_add_driver(&driver); - return 0; -} - -void tuner_cleanup_module(void) -{ - i2c_del_driver(&driver); -} - -module_init(tuner_init_module); -module_exit(tuner_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tuner.h linux/drivers/char/tuner.h --- v2.4.0-test6/linux/drivers/char/tuner.h Tue Nov 23 22:42:20 1999 +++ linux/drivers/char/tuner.h Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -/* - 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 TUNER_TEMIC_4036FY5_NTSC 8 -#define TUNER_ALPS_TSBH1_NTSC 9 -#define TUNER_ALPS_TSBE1_PAL 10 -#define TUNER_ALPS_TSBB5_PAL_I 11 -#define TUNER_ALPS_TSBE5_PAL 12 -#define TUNER_ALPS_TSBC5_PAL 13 - -#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 -#define Alps 4 - -#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ -#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ -#define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */ -#define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */ - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/tvmixer.c linux/drivers/char/tvmixer.c --- v2.4.0-test6/linux/drivers/char/tvmixer.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/tvmixer.c Wed Dec 31 16:00:00 1969 @@ -1,353 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "audiochip.h" - -#define DEV_MAX 4 - -static int debug = 0; -static int devnr = -1; - -MODULE_PARM(debug,"i"); -MODULE_PARM(devnr,"i"); - -/* ----------------------------------------------------------------------- */ - -struct TVMIXER { - struct i2c_client *dev; - int minor; - int count; -}; - -static struct TVMIXER devices[DEV_MAX]; - -static int tvmixer_adapters(struct i2c_adapter *adap); -static int tvmixer_clients(struct i2c_client *client); - -static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int tvmixer_open(struct inode *inode, struct file *file); -static int tvmixer_release(struct inode *inode, struct file *file); -static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin); - - -static struct i2c_driver driver = { - "tv card mixer driver", - 42 /* I2C_DRIVERID_FIXME */, - I2C_DF_DUMMY, - tvmixer_adapters, - tvmixer_clients, -}; - -static struct file_operations tvmixer_fops = { - owner: THIS_MODULE, - llseek: tvmixer_llseek, - ioctl: tvmixer_ioctl, - open: tvmixer_open, - release: tvmixer_release, -}; - -/* ----------------------------------------------------------------------- */ - -static int mix_to_v4l(int i) -{ - int r; - - r = ((i & 0xff) * 65536 + 50) / 100; - if (r > 65535) r = 65535; - if (r < 0) r = 0; - return r; -} - -static int v4l_to_mix(int i) -{ - int r; - - r = (i * 100 + 32768) / 65536; - if (r > 100) r = 100; - if (r < 0) r = 0; - return r | (r << 8); -} - -static int v4l_to_mix2(int l, int r) -{ - r = (r * 100 + 32768) / 65536; - if (r > 100) r = 100; - if (r < 0) r = 0; - l = (l * 100 + 32768) / 65536; - if (l > 100) l = 100; - if (l < 0) l = 0; - return (r << 8) | l; -} - -static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct video_audio va; - int left,right,ret,val = 0; - struct TVMIXER *mix = file->private_data; - struct i2c_client *client = mix->dev; - - if (NULL == client) - return -ENODEV; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strncpy(info.id, "tv card", sizeof(info.id)); - strncpy(info.name, client->name, sizeof(info.name)); - info.modify_counter = 42 /* FIXME */; - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strncpy(info.id, "tv card", sizeof(info.id)); - strncpy(info.name, client->name, sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *)arg); - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (get_user(val, (int *)arg)) - return -EFAULT; - - /* read state */ - memset(&va,0,sizeof(va)); - client->driver->command(client,VIDIOCGAUDIO,&va); - - switch (cmd) { - case MIXER_READ(SOUND_MIXER_RECMASK): - case MIXER_READ(SOUND_MIXER_CAPS): - case MIXER_READ(SOUND_MIXER_RECSRC): - case MIXER_WRITE(SOUND_MIXER_RECSRC): - ret = 0; - break; - - case MIXER_READ(SOUND_MIXER_STEREODEVS): - ret = SOUND_MASK_VOLUME; - break; - case MIXER_READ(SOUND_MIXER_DEVMASK): - ret = SOUND_MASK_VOLUME; - if (va.flags & VIDEO_AUDIO_BASS) - ret |= SOUND_MASK_BASS; - if (va.flags & VIDEO_AUDIO_TREBLE) - ret |= SOUND_MASK_TREBLE; - break; - - case MIXER_WRITE(SOUND_MIXER_VOLUME): - left = mix_to_v4l(val); - right = mix_to_v4l(val >> 8); - va.volume = MAX(left,right); - va.balance = (32768*MIN(left,right)) / (va.volume ? va.volume : 1); - va.balance = (leftdriver->command(client,VIDIOCSAUDIO,&va); - client->driver->command(client,VIDIOCGAUDIO,&va); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_VOLUME): - left = (MIN(65536 - va.balance,32768) * - va.volume) / 32768; - right = (MIN(va.balance,32768) * - va.volume) / 32768; - ret = v4l_to_mix2(left,right); - break; - - case MIXER_WRITE(SOUND_MIXER_BASS): - va.bass = mix_to_v4l(val); - client->driver->command(client,VIDIOCSAUDIO,&va); - client->driver->command(client,VIDIOCGAUDIO,&va); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_BASS): - ret = v4l_to_mix(va.bass); - break; - - case MIXER_WRITE(SOUND_MIXER_TREBLE): - va.treble = mix_to_v4l(val); - client->driver->command(client,VIDIOCSAUDIO,&va); - client->driver->command(client,VIDIOCGAUDIO,&va); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_TREBLE): - ret = v4l_to_mix(va.treble); - break; - - default: - return -EINVAL; - } - if (put_user(ret, (int *)arg)) - return -EFAULT; - return 0; -} - -static int tvmixer_open(struct inode *inode, struct file *file) -{ - int i, minor = MINOR(inode->i_rdev); - struct TVMIXER *mix = NULL; - struct i2c_client *client = NULL; - - for (i = 0; i < DEV_MAX; i++) { - if (devices[i].minor == minor) { - mix = devices+i; - client = mix->dev; - break; - } - } - - if (NULL == client) - return -ENODEV; - - /* lock bttv in memory while the mixer is in use */ - file->private_data = mix; - if (client->adapter->inc_use) - client->adapter->inc_use(client->adapter); - return 0; -} - -static int tvmixer_release(struct inode *inode, struct file *file) -{ - struct TVMIXER *mix = file->private_data; - struct i2c_client *client; - - client = mix->dev; - if (NULL == client) { - return -ENODEV; - } - - if (client->adapter->dec_use) - client->adapter->dec_use(client->adapter); - return 0; -} - -static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - -/* ----------------------------------------------------------------------- */ - -static int tvmixer_adapters(struct i2c_adapter *adap) -{ - return 0; -} - -static int tvmixer_clients(struct i2c_client *client) -{ - struct video_audio va; - int i,minor; - - /* TV card ??? */ - if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) { - if (debug) - printk("tvmixer: %s is not a tv card\n", - client->adapter->name); - return -1; - } - printk("tvmixer: debug: %s\n",client->name); - - /* unregister ?? */ - for (i = 0; i < DEV_MAX; i++) { - if (devices[i].dev == client) { - /* unregister */ - unregister_sound_mixer(devices[i].minor); - devices[i].dev = NULL; - devices[i].minor = -1; - printk("tvmixer: %s unregistered (#1)\n",client->name); - return 0; - } - } - - /* look for a free slot */ - for (i = 0; i < DEV_MAX; i++) - if (NULL == devices[i].dev) - break; - if (i == DEV_MAX) { - printk(KERN_WARNING "tvmixer: DEV_MAX too small\n"); - return -1; - } - - /* audio chip with mixer ??? */ - if (NULL == client->driver->command) { - if (debug) - printk("tvmixer: %s: driver->command is NULL\n", - client->driver->name); - return -1; - } - memset(&va,0,sizeof(va)); - if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) { - if (debug) - printk("tvmixer: %s: VIDIOCGAUDIO failed\n", - client->name); - return -1; - } - if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) { - if (debug) - printk("tvmixer: %s: has no volume control\n", - client->name); - return -1; - } - - /* everything is fine, register */ - if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) { - printk(KERN_ERR "tvmixer: cannot allocate mixer device\n"); - return -1; - } - - devices[i].minor = minor; - devices[i].count = 0; - devices[i].dev = client; - printk("tvmixer: %s (%s) registered with minor %d\n", - client->name,client->adapter->name,minor); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -int tvmixer_init_module(void) -{ - int i; - - for (i = 0; i < DEV_MAX; i++) - devices[i].minor = -1; - i2c_add_driver(&driver); - return 0; -} - -void tvmixer_cleanup_module(void) -{ - int i; - - i2c_del_driver(&driver); - for (i = 0; i < DEV_MAX; i++) { - if (devices[i].minor != -1) { - unregister_sound_mixer(devices[i].minor); - printk("tvmixer: %s unregistered (#2)\n", - devices[i].dev->name); - } - } -} - -module_init(tvmixer_init_module); -module_exit(tvmixer_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.4.0-test6/linux/drivers/char/videodev.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/char/videodev.c Wed Dec 31 16:00:00 1969 @@ -1,581 +0,0 @@ -/* - * 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: 20000516 Claudio Matsuoka - * - Added procfs support - */ - -#include -#include -#include -#include -#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]; - - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - -#include - -struct videodev_proc_data { - struct list_head proc_list; - char name[16]; - struct video_device *vdev; - struct proc_dir_entry *proc_entry; -}; - -static struct proc_dir_entry *video_dev_proc_entry = NULL; -struct proc_dir_entry *video_proc_entry = NULL; -EXPORT_SYMBOL(video_proc_entry); -LIST_HEAD(videodev_proc_list); - -#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ - - -#ifdef CONFIG_VIDEO_BWQCAM -extern int init_bw_qcams(struct video_init *); -#endif -#ifdef CONFIG_VIDEO_CPIA -extern int cpia_init(struct video_init *); -#endif -#ifdef CONFIG_VIDEO_PLANB -extern int init_planbs(struct video_init *); -#endif -#ifdef CONFIG_VIDEO_ZORAN -extern int init_zoran_cards(struct video_init *); -#endif - -static struct video_init video_init_list[]={ -#ifdef CONFIG_VIDEO_BWQCAM - {"bw-qcam", init_bw_qcams}, -#endif -#ifdef CONFIG_VIDEO_CPIA - {"cpia", cpia_init}, -#endif -#ifdef CONFIG_VIDEO_PLANB - {"planb", init_planbs}, -#endif -#ifdef CONFIG_VIDEO_ZORAN - {"zoran", init_zoran_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) -{ - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; - if(vfl->read) - return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); - else - return -EINVAL; -} - - -/* - * 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) -{ - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; - if(vfl->write) - return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); - else - return 0; -} - -/* - * Poll to see if we're readable, can probably be used for timing on incoming - * frames, etc.. - */ - -static unsigned int video_poll(struct file *file, poll_table * wait) -{ - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; - if(vfl->poll) - return vfl->poll(vfl, file, wait); - else - return 0; -} - - -/* - * 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) { - char modname[20]; - - sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor); - request_module(modname); - 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; - lock_kernel(); - vfl=video_device[MINOR(inode->i_rdev)]; - if(vfl->close) - vfl->close(vfl); - vfl->busy=0; - unlock_kernel(); - 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 - */ - - -int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - int ret = -EINVAL; - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; - if(vfl->mmap) { - lock_kernel(); - ret = vfl->mmap(vfl, (char *)vma->vm_start, - (unsigned long)(vma->vm_end-vma->vm_start)); - unlock_kernel(); - } - return ret; -} - -/* - * /proc support - */ - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - -/* Hmm... i'd like to see video_capability information here, but - * how can I access it (without changing the other drivers? -claudio - */ -static int videodev_proc_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *out = page; - struct video_device *vfd = data; - struct videodev_proc_data *d; - struct list_head *tmp; - int len; - char c = ' '; - - list_for_each (tmp, &videodev_proc_list) { - d = list_entry(tmp, struct videodev_proc_data, proc_list); - if (vfd == d->vdev) - break; - } - - /* Sanity check */ - if (tmp == &videodev_proc_list) - goto skip; - -#define PRINT_VID_TYPE(x) do { if (vfd->type & x) \ - out += sprintf (out, "%c%s", c, #x); c='|';} while (0) - - out += sprintf (out, "name : %s\n", vfd->name); - out += sprintf (out, "type :"); - PRINT_VID_TYPE(VID_TYPE_CAPTURE); - PRINT_VID_TYPE(VID_TYPE_TUNER); - PRINT_VID_TYPE(VID_TYPE_TELETEXT); - PRINT_VID_TYPE(VID_TYPE_OVERLAY); - PRINT_VID_TYPE(VID_TYPE_CHROMAKEY); - PRINT_VID_TYPE(VID_TYPE_CLIPPING); - PRINT_VID_TYPE(VID_TYPE_FRAMERAM); - PRINT_VID_TYPE(VID_TYPE_SCALES); - PRINT_VID_TYPE(VID_TYPE_MONOCHROME); - PRINT_VID_TYPE(VID_TYPE_SUBCAPTURE); - PRINT_VID_TYPE(VID_TYPE_MPEG_DECODER); - PRINT_VID_TYPE(VID_TYPE_MPEG_ENCODER); - PRINT_VID_TYPE(VID_TYPE_MJPEG_DECODER); - PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER); - out += sprintf (out, "\n"); - out += sprintf (out, "hardware : 0x%x\n", vfd->hardware); -#if 0 - out += sprintf (out, "channels : %d\n", d->vcap.channels); - out += sprintf (out, "audios : %d\n", d->vcap.audios); - out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth); - out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight); - out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth); - out += sprintf (out, "minheight : %d\n", d->vcap.minheight); -#endif - -skip: - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - - *start = page + off; - - return len; -} - -static void videodev_proc_create(void) -{ - video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root); - - if (video_proc_entry == NULL) { - printk("video_dev: unable to initialise /proc/video\n"); - return; - } - - video_proc_entry->owner = THIS_MODULE; - video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry); - - if (video_dev_proc_entry == NULL) { - printk("video_dev: unable to initialise /proc/video/dev\n"); - return; - } - - video_dev_proc_entry->owner = THIS_MODULE; -} - -#ifdef MODULE -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) -static void videodev_proc_destroy(void) -{ - if (video_dev_proc_entry != NULL) - remove_proc_entry("dev", video_proc_entry); - - if (video_proc_entry != NULL) - remove_proc_entry("video", &proc_root); -} -#endif -#endif - -static void videodev_proc_create_dev (struct video_device *vfd, char *name) -{ - struct videodev_proc_data *d; - struct proc_dir_entry *p; - - if (video_dev_proc_entry == NULL) - return; - - d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL); - if (!d) - return; - - p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry); - p->data = vfd; - p->read_proc = videodev_proc_read; - - d->proc_entry = p; - d->vdev = vfd; - strcpy (d->name, name); - - /* How can I get capability information ? */ - - list_add (&d->proc_list, &videodev_proc_list); -} - -static void videodev_proc_destroy_dev (struct video_device *vfd) -{ - struct list_head *tmp; - struct videodev_proc_data *d; - - list_for_each (tmp, &videodev_proc_list) { - d = list_entry(tmp, struct videodev_proc_data, proc_list); - if (vfd == d->vdev) { - remove_proc_entry(d->name, video_dev_proc_entry); - list_del (&d->proc_list); - kfree (d); - break; - } - } -} - -#endif /* CONFIG_VIDEO_PROC_FS */ - -extern struct file_operations video_fops; - -/** - * video_register_device - register video4linux devices - * @vfd: video device structure we want to register - * @type: type of device to register - * FIXME: needs a semaphore on 2.3.x - * - * The registration code assigns minor numbers based on the type - * requested. -ENFILE is returned in all the device slots for this - * category are full. If not then the minor field is set and the - * driver initialize function is called (if non %NULL). - * - * Zero is returned on success. - * - * Valid types are - * - * %VFL_TYPE_GRABBER - A frame grabber - * - * %VFL_TYPE_VTX - A teletext device - * - * %VFL_TYPE_VBI - Vertical blank data (undecoded) - * - * %VFL_TYPE_RADIO - A radio card - */ - -int video_register_device(struct video_device *vfd, int type) -{ - int i=0; - int base; - int err; - int end; - char *name_base; - - switch(type) - { - case VFL_TYPE_GRABBER: - base=0; - end=64; - name_base = "video"; - break; - case VFL_TYPE_VTX: - base=192; - end=224; - name_base = "vtx"; - break; - case VFL_TYPE_VBI: - base=224; - end=240; - name_base = "vbi"; - break; - case VFL_TYPE_RADIO: - base=64; - end=128; - name_base = "radio"; - break; - default: - return -1; - } - - for(i=base;iminor=i; - /* The init call may sleep so we book the slot out - then call */ - MOD_INC_USE_COUNT; - if(vfd->initialize) - { - err=vfd->initialize(vfd); - if(err<0) - { - video_device[i]=NULL; - MOD_DEC_USE_COUNT; - return err; - } - } - sprintf (name, "v4l/%s%d", name_base, i - base); - /* - * Start the device root only. Anything else - * has serious privacy issues. - */ - vfd->devfs_handle = - devfs_register (NULL, name, DEVFS_FL_DEFAULT, - VIDEO_MAJOR, vfd->minor, - S_IFCHR | S_IRUSR | S_IWUSR, - &video_fops, NULL); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - sprintf (name, "%s%d", name_base, i - base); - videodev_proc_create_dev (vfd, name); -#endif - - - return 0; - } - } - return -ENFILE; -} - -/** - * video_unregister_device - unregister a video4linux device - * @vfd: the device to unregister - * - * This unregisters the passed device and deassigns the minor - * number. Future open calls will be met with errors. - */ - -void video_unregister_device(struct video_device *vfd) -{ - if(video_device[vfd->minor]!=vfd) - panic("vfd: bad unregister"); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - videodev_proc_destroy_dev (vfd); -#endif - - devfs_unregister (vfd->devfs_handle); - video_device[vfd->minor]=NULL; - MOD_DEC_USE_COUNT; -} - - -static struct file_operations video_fops= -{ - owner: THIS_MODULE, - llseek: video_lseek, - read: video_read, - write: video_write, - ioctl: video_ioctl, - mmap: video_mmap, - open: video_open, - release: video_release, - poll: video_poll, -}; - -/* - * Initialise video for linux - */ - -int __init videodev_init(void) -{ - struct video_init *vfli = video_init_list; - - printk(KERN_INFO "Linux video capture interface: v1.00\n"); - if(devfs_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 - */ - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - videodev_proc_create (); -#endif - - while(vfli->init!=NULL) - { - vfli->init(vfli); - vfli++; - } - return 0; -} - -#ifdef MODULE -int init_module(void) -{ - return videodev_init(); -} - -void cleanup_module(void) -{ -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - videodev_proc_destroy (); -#endif - - devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture"); -} - -#endif - -EXPORT_SYMBOL(video_register_device); -EXPORT_SYMBOL(video_unregister_device); - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/vino.c linux/drivers/char/vino.c --- v2.4.0-test6/linux/drivers/char/vino.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/char/vino.c Wed Dec 31 16:00:00 1969 @@ -1,275 +0,0 @@ -/* $Id: vino.c,v 1.5 1999/10/09 00:01:14 ralf Exp $ - * drivers/char/vino.c - * - * (incomplete) Driver for the Vino Video input system found in SGI Indys. - * - * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) - * - * This isn't complete yet, please don't expect any video until I've written - * some more code. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "vino.h" - -struct vino_device { - struct video_device vdev; - - unsigned long chan; -#define VINO_CHAN_A 0 -#define VINO_CHAN_B 1 - - unsigned long flags; -#define VINO_DMA_ACTIVE (1<<0) -}; - -/* We can actually receive TV and IndyCam input at the same time. Believe it or - * not.. - */ -static struct vino_device vino[2]; - -/* Those registers have to be accessed by either *one* 64 bit write or *one* 64 - * bit read. We need some asm to fix this. We can't use mips3 as standard - * because we just save 32 bits at context switch. - */ - -static __inline__ unsigned long long vino_reg_read(unsigned long addr) -{ - unsigned long long ret __attribute__ ((aligned (64))); - unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; - - save_and_cli(flags); - __asm__ __volatile__( - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "sd\t$1,(%1)\n\t" - ".set\tat\n\t" - ".set\tmips0" - : - :"r" (virt_addr), - "r" (&ret) - :"$1"); - restore_flags(flags); - - return ret; -} - -static __inline__ void vino_reg_write(unsigned long long value, - unsigned long addr) -{ - unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; - - /* we might lose the upper parts of the registers which are not saved - * if there comes an interrupt in our way, play safe */ - - save_and_cli(flags); - __asm__ __volatile__( - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "sd\t$1,(%1)\n\t" - ".set\tat\n\t" - ".set\tmips0" - : - :"r" (&value), - "r" (virt_addr) - :"$1"); - restore_flags(flags); -} - -static __inline__ void vino_reg_and(unsigned long long value, - unsigned long addr) -{ - unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; - - save_and_cli(flags); - __asm__ __volatile__( - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "and\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" - ".set\tat\n\t" - ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); - restore_flags(flags); -} - -static __inline__ void vino_reg_or(unsigned long long value, - unsigned long addr) -{ - unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; - - save_and_cli(flags); - __asm__ __volatile__( - ".set\tmips3\n\t" - ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "or\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" - ".set\tat\n\t" - ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); - restore_flags(flags); -} - -static int vino_dma_setup(void) -{ - return 0; -} - -static void vino_dma_stop(void) -{ - -} - -static int vino_init(void) -{ - unsigned long ret; - unsigned short rev, id; - unsigned long long foo; - unsigned long *bar; - - bar = (unsigned long *) &foo; - - ret = vino_reg_read(VINO_REVID); - - rev = (ret & VINO_REVID_REV_MASK); - id = (ret & VINO_REVID_ID_MASK) >> 4; - - printk("Vino: ID:%02hx Rev:%02hx\n", id, rev); - - foo = vino_reg_read(VINO_A_DESC_DATA0); - printk("0x%lx", bar[0]); - printk("%lx ", bar[1]); - foo = vino_reg_read(VINO_A_DESC_DATA1); - printk("0x%lx", bar[0]); - printk("%lx ", bar[1]); - foo = vino_reg_read(VINO_A_DESC_DATA2); - printk("0x%lx", bar[0]); - printk("%lx ", bar[1]); - foo = vino_reg_read(VINO_A_DESC_DATA3); - printk("0x%lx", bar[0]); - printk("%lx\n", bar[1]); - foo = vino_reg_read(VINO_B_DESC_DATA0); - printk("0x%lx", bar[0]); - printk("%lx ", bar[1]); - foo = vino_reg_read(VINO_B_DESC_DATA1); - printk("0x%lx", bar[0]); - printk("%lx ", bar[1]); - foo = vino_reg_read(VINO_B_DESC_DATA2); - printk("0x%lx", bar[0]); - printk("%lx ", bar[1]); - foo = vino_reg_read(VINO_B_DESC_DATA3); - printk("0x%lx", bar[0]); - printk("%lx\n", bar[1]); - - return 0; -} - -static void vino_dma_go(struct vino_device *v) -{ - -} - -/* Reset the vino back to default state */ - -static void vino_setup(struct vino_device *v) -{ - -} - -static int vino_open(struct video_device *dev, int flags) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static void vino_close(struct video_device *dev) -{ - MOD_DEC_USE_COUNT; -} - -static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - return 0; -} - -static int vino_mmap(struct video_device *dev, const char *adr, - unsigned long size) -{ - return 0; -} - -static struct video_device vino_dev = { - "Vino IndyCam/TV", - VID_TYPE_CAPTURE, - VID_HARDWARE_VINO, - vino_open, - vino_close, - NULL, /* vino_read */ - NULL, /* vino_write */ - NULL, /* vino_poll */ - vino_ioctl, - vino_mmap, - NULL, /* vino_init */ - NULL, - 0, - 0 -}; - -int __init init_vino(struct video_device *dev) -{ - int err; - - err = vino_init(); - if (err) - return err; - -#if 0 - if (video_register_device(&vinodev, VFL_TYPE_GRABBER) == -1) { - return -ENODEV; - } -#endif - - return 0; -} - -#ifdef MODULE -int init_module(void) -{ - int err; - - err = vino_init(); - if (err) - return err; - - return 0; -} - -void cleanup_module(void) -{ -} -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/wdt285.c linux/drivers/char/wdt285.c --- v2.4.0-test6/linux/drivers/char/wdt285.c Fri Jul 14 12:12:09 2000 +++ linux/drivers/char/wdt285.c Sun Aug 13 09:54:15 2000 @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include /* diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/zr36057.h linux/drivers/char/zr36057.h --- v2.4.0-test6/linux/drivers/char/zr36057.h Mon Jul 5 20:09:40 1999 +++ linux/drivers/char/zr36057.h Wed Dec 31 16:00:00 1969 @@ -1,168 +0,0 @@ -/* - zr36057.h - zr36057 register offsets - - Copyright (C) 1998 Dave Perks - - 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 _ZR36057_H_ -#define _ZR36057_H_ - - -/* Zoran ZR36057 registers */ - -#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ -#define ZR36057_VFEHCR_HSPol (1<<30) -#define ZR36057_VFEHCR_HStart 10 -#define ZR36057_VFEHCR_HEnd 0 -#define ZR36057_VFEHCR_Hmask 0x3ff - -#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ -#define ZR36057_VFEVCR_VSPol (1<<30) -#define ZR36057_VFEVCR_VStart 10 -#define ZR36057_VFEVCR_VEnd 0 -#define ZR36057_VFEVCR_Vmask 0x3ff - -#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ -#define ZR36057_VFESPFR_ExtFl (1<<26) -#define ZR36057_VFESPFR_TopField (1<<25) -#define ZR36057_VFESPFR_VCLKPol (1<<24) -#define ZR36057_VFESPFR_HFilter 21 -#define ZR36057_VFESPFR_HorDcm 14 -#define ZR36057_VFESPFR_VerDcm 8 -#define ZR36057_VFESPFR_DispMode 6 -#define ZR36057_VFESPFR_YUV422 (0<<3) -#define ZR36057_VFESPFR_RGB888 (1<<3) -#define ZR36057_VFESPFR_RGB565 (2<<3) -#define ZR36057_VFESPFR_RGB555 (3<<3) -#define ZR36057_VFESPFR_ErrDif (1<<2) -#define ZR36057_VFESPFR_Pack24 (1<<1) -#define ZR36057_VFESPFR_LittleEndian (1<<0) - -#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ - -#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ - -#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ -#define ZR36057_VSSFGR_DispStride 16 -#define ZR36057_VSSFGR_VidOvf (1<<8) -#define ZR36057_VSSFGR_SnapShot (1<<1) -#define ZR36057_VSSFGR_FrameGrab (1<<0) - -#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ -#define ZR36057_VDCR_VidEn (1<<31) -#define ZR36057_VDCR_MinPix 24 -#define ZR36057_VDCR_Triton (1<<24) -#define ZR36057_VDCR_VidWinHt 12 -#define ZR36057_VDCR_VidWinWid 0 - -#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ - -#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ - -#define ZR36057_OCR 0x024 /* Overlay Control Register */ -#define ZR36057_OCR_OvlEnable (1 << 15) -#define ZR36057_OCR_MaskStride 0 - -#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ -#define ZR36057_SPGPPCR_SoftReset (1<<24) - -#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ - -#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ - -#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ -#define ZR36057_MCTCR_CodTime (1 << 30) -#define ZR36057_MCTCR_CEmpty (1 << 29) -#define ZR36057_MCTCR_CFlush (1 << 28) -#define ZR36057_MCTCR_CodGuestID 20 -#define ZR36057_MCTCR_CodGuestReg 16 - -#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ - -#define ZR36057_ISR 0x03c /* Interrupt Status Register */ -#define ZR36057_ISR_GIRQ1 (1<<30) -#define ZR36057_ISR_GIRQ0 (1<<29) -#define ZR36057_ISR_CodRepIRQ (1<<28) -#define ZR36057_ISR_JPEGRepIRQ (1<<27) - -#define ZR36057_ICR 0x040 /* Interrupt Control Register */ -#define ZR36057_ICR_GIRQ1 (1<<30) -#define ZR36057_ICR_GIRQ0 (1<<29) -#define ZR36057_ICR_CodRepIRQ (1<<28) -#define ZR36057_ICR_JPEGRepIRQ (1<<27) -#define ZR36057_ICR_IntPinEn (1<<24) - -#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ -#define ZR36057_I2CBR_SDA (1<<1) -#define ZR36057_I2CBR_SCL (1<<0) - -#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ -#define ZR36057_JMC_JPG (1 << 31) -#define ZR36057_JMC_JPGExpMode (0 << 29) -#define ZR36057_JMC_JPGCmpMode (1 << 29) -#define ZR36057_JMC_MJPGExpMode (2 << 29) -#define ZR36057_JMC_MJPGCmpMode (3 << 29) -#define ZR36057_JMC_RTBUSY_FB (1 << 6) -#define ZR36057_JMC_Go_en (1 << 5) -#define ZR36057_JMC_SyncMstr (1 << 4) -#define ZR36057_JMC_Fld_per_buff (1 << 3) -#define ZR36057_JMC_VFIFO_FB (1 << 2) -#define ZR36057_JMC_CFIFO_FB (1 << 1) -#define ZR36057_JMC_Stll_LitEndian (1 << 0) - -#define ZR36057_JPC 0x104 /* JPEG Process Control */ -#define ZR36057_JPC_P_Reset (1 << 7) -#define ZR36057_JPC_CodTrnsEn (1 << 5) -#define ZR36057_JPC_Active (1 << 0) - -#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ -#define ZR36057_VSP_VsyncSize 16 -#define ZR36057_VSP_FrmTot 0 - -#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ -#define ZR36057_HSP_HsyncStart 16 -#define ZR36057_HSP_LineTot 0 - -#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ -#define ZR36057_FHAP_NAX 16 -#define ZR36057_FHAP_PAX 0 - -#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ -#define ZR36057_FVAP_NAY 16 -#define ZR36057_FVAP_PAY 0 - -#define ZR36057_FPP 0x118 /* Field Process Parameters */ -#define ZR36057_FPP_Odd_Even (1 << 0) - -#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ - -#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ - -#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ -#define ZR36057_JCGI_JPEGuestID 4 -#define ZR36057_JCGI_JPEGuestReg 0 - -#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ - -#define ZR36057_POR 0x200 /* Post Office Register */ -#define ZR36057_POR_POPen (1<<25) -#define ZR36057_POR_POTime (1<<24) -#define ZR36057_POR_PODir (1<<23) - -#define ZR36057_STR 0x300 /* "Still" Transfer Register */ - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/zr36060.h linux/drivers/char/zr36060.h --- v2.4.0-test6/linux/drivers/char/zr36060.h Mon Jul 5 20:09:40 1999 +++ linux/drivers/char/zr36060.h Wed Dec 31 16:00:00 1969 @@ -1,35 +0,0 @@ -/* - zr36060.h - zr36060 register offsets - - Copyright (C) 1998 Dave Perks - - 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 _ZR36060_H_ -#define _ZR36060_H_ - - -/* Zoran ZR36060 registers */ - -#define ZR36060_LoadParameters 0x000 -#define ZR36060_Load (1<<7) -#define ZR36060_SyncRst (1<<0) - -#define ZR36060_CodeFifoStatus 0x001 -#define ZR36060_Load (1<<7) -#define ZR36060_SyncRst (1<<0) - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/zr36120.c linux/drivers/char/zr36120.c --- v2.4.0-test6/linux/drivers/char/zr36120.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/char/zr36120.c Wed Dec 31 16:00:00 1969 @@ -1,2086 +0,0 @@ -/* - zr36120.c - Zoran 36120/36125 based framegrabbers - - Copyright (C) 1998-1999 Pauline Middelink - - 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. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "tuner.h" -#include "zr36120.h" -#include "zr36120_mem.h" - -/* mark an required function argument unused - lintism */ -#define UNUSED(x) (void)(x) - -/* sensible default */ -#ifndef CARDTYPE -#define CARDTYPE 0 -#endif - -/* Anybody who uses more than four? */ -#define ZORAN_MAX 4 - -static unsigned int triton1=0; /* triton1 chipset? */ -static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; - -MODULE_AUTHOR("Pauline Middelink "); -MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); -MODULE_PARM(triton1,"i"); -MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i"); - -static int zoran_cards; -static struct zoran zorans[ZORAN_MAX]; - -/* - * the meaning of each element can be found in zr36120.h - * Determining the value of gpdir/gpval can be tricky. The - * best way is to run the card under the original software - * and read the values from the general purpose registers - * 0x28 and 0x2C. How you do that is left as an exercise - * to the impatient reader :) - */ -#define T 1 /* to seperate the bools from the ints */ -#define F 0 -static struct tvcard tvcards[] = { - /* reported working by */ -/*0*/ { "Trust Victor II", - 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, - /* reported working by */ -/*1*/ { "Aitech WaveWatcher TV-PCI", - 3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } }, - /* reported working by ? */ -/*2*/ { "Genius Video Wonder PCI Video Capture Card", - 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, - /* reported working by */ -/*3*/ { "Guillemot Maxi-TV PCI", - 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, - /* reported working by "Craig Whitmore */ -/*4*/ { "Quadrant Buster", - 3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } }, - /* a debug entry which has all inputs mapped */ -/*5*/ { "ZR36120 based framegrabber (all inputs enabled)", - 6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } } -}; -#undef T -#undef F -#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0])) - -#ifdef __sparc__ -#define ENDIANESS 0 -#else -#define ENDIANESS ZORAN_VFEC_LE -#endif - -static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = { -/* n/a */ { "n/a", 0, 0 }, -/* GREY */ { "GRAY", 0, 0 }, -/* HI240 */ { "HI240", 0, 0 }, -/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 }, -/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 }, -/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 }, -/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 }, -/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 }, -/* YUYV */ { "YUYV", 0, 0 }, -/* UYVY */ { "UYVY", 0, 0 }, -/* YUV420 */ { "YUV420", 0, 0 }, -/* YUV411 */ { "YUV411", 0, 0 }, -/* RAW */ { "RAW", 0, 0 }, -/* YUV422P */ { "YUV422P", 0, 0 }, -/* YUV411P */ { "YUV411P", 0, 0 }}; -#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0])) -#undef ENDIANESS - -/* ----------------------------------------------------------------------- */ -/* ZORAN chipset detector */ -/* shamelessly stolen from bttv.c */ -/* Reason for beeing here: we need to detect if we are running on a */ -/* Triton based chipset, and if so, enable a certain bit */ -/* ----------------------------------------------------------------------- */ -static -void __init handle_chipset(void) -{ - struct pci_dev *dev = NULL; - - /* Just in case some nut set this to something dangerous */ - if (triton1) - triton1 = ZORAN_VDC_TRICOM; - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) - { - printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n"); - triton1 = ZORAN_VDC_TRICOM; - } -} - -/* ----------------------------------------------------------------------- */ -/* ZORAN functions */ -/* ----------------------------------------------------------------------- */ - -static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i); - -#if 0 /* unused */ -static -void zoran_dump(struct zoran *ztv) -{ - char str[256]; - char *p=str; /* shut up, gcc! */ - int i; - - for (i=0; i<0x60; i+=4) { - if ((i % 16) == 0) { - if (i) printk("%s\n",str); - p = str; - p+= sprintf(str, KERN_DEBUG " %04x: ",i); - } - p += sprintf(p, "%08x ",zrread(i)); - } -} -#endif /* unused */ - -static -void reap_states(struct zoran* ztv) -{ - /* count frames */ - ztv->fieldnr++; - - /* - * Are we busy at all? - * This depends on if there is a workqueue AND the - * videotransfer is enabled on the chip... - */ - if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) - { - struct vidinfo* newitem; - - /* did we get a complete frame? */ - if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) - return; - -DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); - - /* we are done with this buffer, tell everyone */ - ztv->workqueue->status = FBUFFER_DONE; - ztv->workqueue->fieldnr = ztv->fieldnr; - /* not good, here for BTTV_FIELDNR reasons */ - ztv->lastfieldnr = ztv->fieldnr; - - switch (ztv->workqueue->kindof) { - case FBUFFER_GRAB: - wake_up_interruptible(&ztv->grabq); - break; - case FBUFFER_VBI: - wake_up_interruptible(&ztv->vbiq); - break; - default: - printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof); - } - - /* item completed, skip to next item in queue */ - write_lock(&ztv->lock); - newitem = ztv->workqueue->next; - ztv->workqueue->next = 0; /* mark completed */ - ztv->workqueue = newitem; - write_unlock(&ztv->lock); - } - - /* - * ok, so it seems we have nothing in progress right now. - * Lets see if we can find some work. - */ - if (ztv->workqueue) - { - struct vidinfo* newitem; -again: - -DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); - - /* loadup the frame settings */ - read_lock(&ztv->lock); - zoran_set_geo(ztv,ztv->workqueue); - read_unlock(&ztv->lock); - - switch (ztv->workqueue->kindof) { - case FBUFFER_GRAB: - case FBUFFER_VBI: - zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); - zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); - zror(ZORAN_VDC_VIDEN,ZORAN_VDC); - - /* start single-shot grab */ - zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); - break; - default: - printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof); - write_lock(&ztv->lock); - newitem = ztv->workqueue->next; - ztv->workqueue->next = 0; - ztv->workqueue = newitem; - write_unlock(&ztv->lock); - if (newitem) - goto again; /* yeah, sure.. */ - } - /* bye for now */ - return; - } -DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD)); - - /* - * What? Even the workqueue is empty? Am i really here - * for nothing? Did i come all that way to... do nothing? - */ - - /* do we need to overlay? */ - if (test_bit(STATE_OVERLAY, &ztv->state)) - { - /* are we already overlaying? */ - if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) || - !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) - { -DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD)); - - read_lock(&ztv->lock); - zoran_set_geo(ztv,&ztv->overinfo); - read_unlock(&ztv->lock); - - zror(ZORAN_OCR_OVLEN, ZORAN_OCR); - zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); - zror(ZORAN_VDC_VIDEN,ZORAN_VDC); - } - - /* - * leave overlaying on, but turn interrupts off. - */ - zrand(~ZORAN_ICR_EN,ZORAN_ICR); - return; - } - - /* do we have any VBI idle time processing? */ - if (test_bit(STATE_VBI, &ztv->state)) - { - struct vidinfo* item; - struct vidinfo* lastitem; - - /* protect the workqueue */ - write_lock(&ztv->lock); - lastitem = ztv->workqueue; - if (lastitem) - while (lastitem->next) lastitem = lastitem->next; - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - if (item->next == 0 && item->status == FBUFFER_FREE) - { -DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item)); - item->status = FBUFFER_BUSY; - if (!lastitem) - ztv->workqueue = item; - else - lastitem->next = item; - lastitem = item; - } - write_unlock(&ztv->lock); - if (ztv->workqueue) - goto again; /* hey, _i_ graduated :) */ - } - - /* - * Then we must be realy IDLE - */ -DEBUG(printk(CARD_DEBUG "turning off\n",CARD)); - /* nothing further to do, disable DMA and further IRQs */ - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - zrand(~ZORAN_ICR_EN,ZORAN_ICR); -} - -static -void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) -{ - u32 stat,estat; - int count = 0; - struct zoran *ztv = (struct zoran *)dev_id; - - UNUSED(irq); UNUSED(regs); - for (;;) { - /* get/clear interrupt status bits */ - stat=zrread(ZORAN_ISR); - estat=stat & zrread(ZORAN_ICR); - if (!estat) - return; - zrwrite(estat,ZORAN_ISR); - IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat)); - IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat)); - - if (estat & ZORAN_ISR_CODE) - { - IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD)); - } - if (estat & ZORAN_ISR_GIRQ0) - { - IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD)); - if (!ztv->card->usegirq1) - reap_states(ztv); - } - if (estat & ZORAN_ISR_GIRQ1) - { - IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD)); - if (ztv->card->usegirq1) - reap_states(ztv); - } - - count++; - if (count > 10) - printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat); - if (count > 20) - { - zrwrite(0, ZORAN_ICR); - printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD); - } - } -} - -static -int zoran_muxsel(struct zoran* ztv, int channel, int norm) -{ - int rv; - - /* set the new video norm */ - rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); - if (rv) - return rv; - ztv->norm = norm; - - /* map the given channel to the cards decoder's channel */ - channel = ztv->card->video_mux[channel] & CHANNEL_MASK; - - /* set the new channel */ - rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel); - return rv; -} - -/* Tell the interrupt handler what to to. */ -static -void zoran_cap(struct zoran* ztv, int on) -{ -DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state)); - - if (on) { - ztv->running = 1; - - /* - * turn interrupts (back) on. The DMA will be enabled - * inside the irq handler when it detects a restart. - */ - zror(ZORAN_ICR_EN,ZORAN_ICR); - } - else { - /* - * turn both interrupts and DMA off - */ - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - zrand(~ZORAN_ICR_EN,ZORAN_ICR); - - ztv->running = 0; - } -} - -static ulong dmask[] = { - 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, - 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, - 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, - 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, - 0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000, - 0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000, - 0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000, - 0xF0000000, 0xE0000000, 0xC0000000, 0x80000000 -}; - -static -void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp) -{ - ulong* mtop; - int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */ - int i; - -DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); - - for (i=0; ix,vp->y,vp->width,vp->height)); - } - - /* - * activate the visible portion of the screen - * Note we take some shortcuts here, because we - * know the width can never be < 32. (I.e. a DWORD) - * We also assume the overlay starts somewhere in - * the FIRST dword. - */ - { - int start = ztv->vidXshift; - ulong firstd = dmask[start]; - ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31]; - mtop = ztv->overinfo.overlay; - for (i=0; ioverinfo.h; i++) { - int w = ztv->vidWidth; - ulong* line = mtop; - if (start & 31) { - *line++ = firstd; - w -= 32-(start&31); - } - memset(line, ~0, w/8); - if (w & 31) - line[w/32] = lastd; - mtop += ystep; - } - } - - /* process clipping regions */ - for (i=0; ix < 0 || (uint)vcp->x > ztv->overinfo.w || - vcp->y < 0 || vcp->y > ztv->overinfo.h || - vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w || - vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h) - { - DEBUG(printk(CARD_DEBUG "illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); - if (vcp->x < 0) vcp->x = 0; - if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; - if (vcp->y < 0) vcp->y = 0; - if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h; - if (vcp->width < 0) vcp->width = 0; - if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; - if (vcp->height < 0) vcp->height = 0; - if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y; -// continue; - } - - mtop = &ztv->overinfo.overlay[vcp->y*ystep]; - for (h=0; h<=vcp->height; h++) { - int w; - int x = ztv->vidXshift + vcp->x; - for (w=0; w<=vcp->width; w++) { - clear_bit(x&31, &mtop[x/32]); - x++; - } - mtop += ystep; - } - ++vcp; - } - - mtop = ztv->overinfo.overlay; - zrwrite(virt_to_bus(mtop), ZORAN_MTOP); - zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT); - zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); -} - -struct tvnorm -{ - u16 Wt, Wa, Ht, Ha, HStart, VStart; -}; - -static struct tvnorm tvnorms[] = { - /* PAL-BDGHI */ -/* { 864, 720, 625, 576, 131, 21 },*/ -/*00*/ { 864, 768, 625, 576, 81, 17 }, - /* NTSC */ -/*01*/ { 858, 720, 525, 480, 121, 10 }, - /* SECAM */ -/*02*/ { 864, 720, 625, 576, 131, 21 }, - /* BW50 */ -/*03*/ { 864, 720, 625, 576, 131, 21 }, - /* BW60 */ -/*04*/ { 858, 720, 525, 480, 121, 10 } -}; -#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) - -/* - * Program the chip for a setup as described in the vidinfo struct. - * - * Side-effects: calculates vidXshift, vidInterlace, - * vidHeight, vidWidth which are used in a later stage - * to calculate the overlay mask - * - * This is an internal function, as such it does not check the - * validity of the struct members... Spectaculair crashes will - * follow /very/ quick when you're wrong and the chip right :) - */ -static -void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) -{ - ulong top, bot; - int stride; - int winWidth, winHeight; - int maxWidth, maxHeight, maxXOffset, maxYOffset; - long vfec; - -DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay)); - - /* - * make sure the DMA transfers are inhibited during our - * reprogramming of the chip - */ - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - - maxWidth = tvnorms[ztv->norm].Wa; - maxHeight = tvnorms[ztv->norm].Ha/2; - maxXOffset = tvnorms[ztv->norm].HStart; - maxYOffset = tvnorms[ztv->norm].VStart; - - /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */ - vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) | - (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24)); - - /* - * Set top, bottom ptrs. Since these must be DWORD aligned, - * possible adjust the x and the width of the window. - * so the endposition stay the same. The vidXshift will make - * sure we are not writing pixels before the requested x. - */ - ztv->vidXshift = 0; - winWidth = i->w; - if (winWidth < 0) - winWidth = -winWidth; - top = i->busadr + i->x*i->bpp + i->y*i->bpl; - if (top & 3) { - ztv->vidXshift = (top & 3) / i->bpp; - winWidth += ztv->vidXshift; - DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift)); - top &= ~3; - } - - /* - * bottom points to next frame but in interleaved mode we want - * to 'mix' the 2 frames to one capture, so 'bot' points to one - * (physical) line below the top line. - */ - bot = top + i->bpl; - zrwrite(top,ZORAN_VTOP); - zrwrite(bot,ZORAN_VBOT); - - /* - * Make sure the winWidth is DWORD aligned too, - * thereby automaticly making sure the stride to the - * next line is DWORD aligned too (as required by spec). - */ - if ((winWidth*i->bpp) & 3) { -DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); - winWidth += (winWidth*i->bpp) & 3; - } - - /* determine the DispMode and stride */ - if (i->h >= 0 && i->h <= maxHeight) { - /* single frame grab suffices for this height. */ - vfec |= ZORAN_VFEC_DISPMOD; - ztv->vidInterlace = 0; - stride = i->bpl - (winWidth*i->bpp); - winHeight = i->h; - } - else { - /* interleaving needed for this height */ - ztv->vidInterlace = 1; - stride = i->bpl*2 - (winWidth*i->bpp); - winHeight = i->h/2; - } - if (winHeight < 0) /* can happen for VBI! */ - winHeight = -winHeight; - - /* safety net, sometimes bpl is too short??? */ - if (stride<0) { -DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride)); - stride = 0; - } - - zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC); - zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR); - - /* remember vidWidth, vidHeight for overlay calculations */ - ztv->vidWidth = winWidth; - ztv->vidHeight = winHeight; -DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot)); -DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight)); -DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight)); -DEBUG(printk(KERN_DEBUG " stride=%d\n",stride)); - - /* - * determine horizontal scales and crops - */ - if (i->w < 0) { - int Hstart = 1; - int Hend = Hstart + winWidth; -DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend)); - zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); - } - else { - int Wa = maxWidth; - int X = (winWidth*64+Wa-1)/Wa; - int We = winWidth*64/X; - int HorDcm = 64-X; - int hcrop1 = 2*(Wa-We)/4; - /* - * BUGFIX: Juha Nurmela - * found the solution to the color phase shift. - * See ChangeLog for the full explanation) - */ - int Hstart = (maxXOffset + hcrop1) | 1; - int Hend = Hstart + We - 1; - -DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); - - zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); - vfec |= HorDcm<<14; - - if (HorDcm<16) - vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */ - else if (HorDcm<32) - vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ - else if (HorDcm<48) - vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ - else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ - } - - /* - * Determine vertical scales and crops - * - * when height is negative, we want to read starting at line 0 - * One day someone might need access to these lines... - */ - if (i->h < 0) { - int Vstart = 0; - int Vend = Vstart + winHeight; -DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend)); - zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); - } - else { - int Ha = maxHeight; - int Y = (winHeight*64+Ha-1)/Ha; - int He = winHeight*64/Y; - int VerDcm = 64-Y; - int vcrop1 = 2*(Ha-He)/4; - int Vstart = maxYOffset + vcrop1; - int Vend = Vstart + He - 1; - -DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); - zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); - vfec |= VerDcm<<8; - } - -DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); - - /* setup the requested format */ - zrwrite(vfec, ZORAN_VFEC); -} - -static -void zoran_common_open(struct zoran* ztv, int flags) -{ - UNUSED(flags); - - /* already opened? */ - if (ztv->users++ != 0) - return; - - /* unmute audio */ - /* /what/ audio? */ - - ztv->state = 0; - - /* setup the encoder to the initial values */ - ztv->picture.colour=254<<7; - ztv->picture.brightness=128<<8; - ztv->picture.hue=128<<8; - ztv->picture.contrast=216<<7; - i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); - - /* default to the composite input since my camera is there */ - zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); -} - -static -void zoran_common_close(struct zoran* ztv) -{ - if (--ztv->users != 0) - return; - - /* mute audio */ - /* /what/ audio? */ - - /* stop the chip */ - zoran_cap(ztv, 0); -} - -/* - * Open a zoran card. Right now the flags are just a hack - */ -static int zoran_open(struct video_device *dev, int flags) -{ - struct zoran *ztv = (struct zoran*)dev; - struct vidinfo* item; - char* pos; - - DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags)); - - /********************************************* - * We really should be doing lazy allocing... - *********************************************/ - /* allocate a frame buffer */ - if (!ztv->fbuffer) - ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); - if (!ztv->fbuffer) { - /* could not get a buffer, bail out */ - return -ENOBUFS; - } - /* at this time we _always_ have a framebuffer */ - memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); - - if (!ztv->overinfo.overlay) - ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); - if (!ztv->overinfo.overlay) { - /* could not get an overlay buffer, bail out */ - bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); - return -ENOBUFS; - } - /* at this time we _always_ have a overlay */ - - /* clear buffer status, and give them a DMAable address */ - pos = ztv->fbuffer; - for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) - { - item->status = FBUFFER_FREE; - item->memadr = pos; - item->busadr = virt_to_bus(pos); - pos += ZORAN_MAX_FBUFFER; - } - - /* do the common part of all open's */ - zoran_common_open(ztv, flags); - - MOD_INC_USE_COUNT; - return 0; -} - -static -void zoran_close(struct video_device* dev) -{ - struct zoran *ztv = (struct zoran*)dev; - - DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD)); - - /* driver specific closure */ - clear_bit(STATE_OVERLAY, &ztv->state); - - zoran_common_close(ztv); - - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); /* Wait 1/10th of a second */ - - /* free the allocated framebuffer */ - if (ztv->fbuffer) - bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE ); - ztv->fbuffer = 0; - if (ztv->overinfo.overlay) - kfree( ztv->overinfo.overlay ); - ztv->overinfo.overlay = 0; - - MOD_DEC_USE_COUNT; -} - -/* - * This read function could be used reentrant in a SMP situation. - * - * This is made possible by the spinlock which is kept till we - * found and marked a buffer for our own use. The lock must - * be released as soon as possible to prevent lock contention. - */ -static -long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) -{ - struct zoran *ztv = (struct zoran*)dev; - unsigned long max; - struct vidinfo* unused = 0; - struct vidinfo* done = 0; - - DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock)); - - /* find ourself a free or completed buffer */ - for (;;) { - struct vidinfo* item; - - write_lock_irq(&ztv->lock); - for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) - { - if (!unused && item->status == FBUFFER_FREE) - unused = item; - if (!done && item->status == FBUFFER_DONE) - done = item; - } - if (done || unused) - break; - - /* no more free buffers, wait for them. */ - write_unlock_irq(&ztv->lock); - if (nonblock) - return -EWOULDBLOCK; - interruptible_sleep_on(&ztv->grabq); - if (signal_pending(current)) - return -EINTR; - } - - /* Do we have 'ready' data? */ - if (!done) { - /* no? than this will take a while... */ - if (nonblock) { - write_unlock_irq(&ztv->lock); - return -EWOULDBLOCK; - } - - /* mark the unused buffer as wanted */ - unused->status = FBUFFER_BUSY; - unused->w = 320; - unused->h = 240; - unused->format = VIDEO_PALETTE_RGB24; - unused->bpp = palette2fmt[unused->format].bpp; - unused->bpl = unused->w * unused->bpp; - unused->next = 0; - { /* add to tail of queue */ - struct vidinfo* oldframe = ztv->workqueue; - if (!oldframe) ztv->workqueue = unused; - else { - while (oldframe->next) oldframe = oldframe->next; - oldframe->next = unused; - } - } - write_unlock_irq(&ztv->lock); - - /* tell the state machine we want it filled /NOW/ */ - zoran_cap(ztv, 1); - - /* wait till this buffer gets grabbed */ - while (unused->status == FBUFFER_BUSY) { - interruptible_sleep_on(&ztv->grabq); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - } - done = unused; - } - else - write_unlock_irq(&ztv->lock); - - /* Yes! we got data! */ - max = done->bpl * done->h; - if (count > max) - count = max; - if (copy_to_user((void*)buf, done->memadr, count)) - count = -EFAULT; - - /* keep the engine running */ - done->status = FBUFFER_FREE; -// zoran_cap(ztv,1); - - /* tell listeners this buffer became free */ - wake_up_interruptible(&ztv->grabq); - - /* goodbye */ - DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count)); - return count; -} - -static -long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) -{ - struct zoran *ztv = (struct zoran *)dev; - UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock); - DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD)); - return -EINVAL; -} - -#if LINUX_VERSION_CODE >= 0x020100 -static -unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) -{ - struct zoran *ztv = (struct zoran *)dev; - struct vidinfo* item; - unsigned int mask = 0; - - poll_wait(file, &ztv->grabq, wait); - - for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) - if (item->status == FBUFFER_DONE) - { - mask |= (POLLIN | POLLRDNORM); - break; - } - - DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask)); - - return mask; -} -#endif - -/* append a new clipregion to the vector of video_clips */ -static -void new_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++; -} - -static -int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) -{ - struct zoran* ztv = (struct zoran*)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability c; - DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD)); - - strcpy(c.name,ztv->video_dev.name); - c.type = VID_TYPE_CAPTURE| - VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING| - VID_TYPE_FRAMERAM| - VID_TYPE_SCALES; - if (ztv->have_tuner) - c.type |= VID_TYPE_TUNER; - if (ztv->have_decoder) { - c.channels = ztv->card->video_inputs; - c.audios = ztv->card->audio_inputs; - } else - /* no decoder -> no channels */ - c.channels = c.audios = 0; - c.maxwidth = 768; - c.maxheight = 576; - c.minwidth = 32; - c.minheight = 32; - if (copy_to_user(arg,&c,sizeof(c))) - return -EFAULT; - break; - } - - case VIDIOCGCHAN: - { - struct video_channel v; - int mux; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel)); - v.flags=VIDEO_VC_AUDIO -#ifdef VIDEO_VC_NORM - |VIDEO_VC_NORM -#endif - ; - v.tuners=0; - v.type=VIDEO_TYPE_CAMERA; -#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API - v.norm=VIDEO_MODE_PAL| - VIDEO_MODE_NTSC| - VIDEO_MODE_SECAM; -#else - v.norm=VIDEO_MODE_PAL; -#endif - /* too many inputs? no decoder -> no channels */ - if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) - return -EINVAL; - - /* now determine the name of the channel */ - mux = ztv->card->video_mux[v.channel]; - if (mux & IS_TUNER) { - /* lets assume only one tuner, yes? */ - strcpy(v.name,"Television"); - v.type = VIDEO_TYPE_TV; - if (ztv->have_tuner) { - v.flags |= VIDEO_VC_TUNER; - v.tuners = 1; - } - } - else if (mux & IS_SVHS) - sprintf(v.name,"S-Video-%d",v.channel); - else - sprintf(v.name,"CVBS-%d",v.channel); - - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - break; - } - case VIDIOCSCHAN: - { /* set video channel */ - struct video_channel v; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm)); - - /* too many inputs? no decoder -> no channels */ - if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) - return -EINVAL; - - if (v.norm != VIDEO_MODE_PAL && - v.norm != VIDEO_MODE_NTSC && - v.norm != VIDEO_MODE_SECAM && - v.norm != VIDEO_MODE_AUTO) - return -EOPNOTSUPP; - - /* make it happen, nr1! */ - return zoran_muxsel(ztv,v.channel,v.norm); - } - - case VIDIOCGTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner)); - - /* Only no or one tuner for now */ - if (!ztv->have_tuner || v.tuner) - return -EINVAL; - - strcpy(v.name,"Television"); - v.rangelow = 0; - v.rangehigh = ~0; - v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v.mode = ztv->norm; - v.signal = 0xFFFF; /* unknown */ - - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - break; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode)); - - /* Only no or one tuner for now */ - if (!ztv->have_tuner || v.tuner) - return -EINVAL; - - /* and it only has certain valid modes */ - if( v.mode != VIDEO_MODE_PAL && - v.mode != VIDEO_MODE_NTSC && - v.mode != VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - - /* engage! */ - return zoran_muxsel(ztv,v.tuner,v.mode); - } - - case VIDIOCGPICT: - { - struct video_picture p = ztv->picture; - DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD)); - p.depth = ztv->depth; - switch (p.depth) { - case 8: p.palette=VIDEO_PALETTE_YUV422; - break; - case 15: p.palette=VIDEO_PALETTE_RGB555; - break; - case 16: p.palette=VIDEO_PALETTE_RGB565; - break; - case 24: p.palette=VIDEO_PALETTE_RGB24; - break; - case 32: p.palette=VIDEO_PALETTE_RGB32; - break; - } - if (copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - break; - } - case VIDIOCSPICT: - { - struct video_picture p; - if (copy_from_user(&p, arg,sizeof(p))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette)); - - /* depth must match with framebuffer */ - if (p.depth != ztv->depth) - return -EINVAL; - - /* check if palette matches this bpp */ - if (p.palette>NRPALETTES || - palette2fmt[p.palette].bpp != ztv->overinfo.bpp) - return -EINVAL; - - write_lock_irq(&ztv->lock); - ztv->overinfo.format = p.palette; - ztv->picture = p; - write_unlock_irq(&ztv->lock); - - /* tell the decoder */ - i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); - break; - } - - case VIDIOCGWIN: - { - struct video_window vw; - DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD)); - read_lock(&ztv->lock); - vw.x = ztv->overinfo.x; - vw.y = ztv->overinfo.y; - vw.width = ztv->overinfo.w; - vw.height = ztv->overinfo.h; - vw.chromakey= 0; - vw.flags = 0; - if (ztv->vidInterlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - read_unlock(&ztv->lock); - if (copy_to_user(arg,&vw,sizeof(vw))) - return -EFAULT; - break; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp; - int on; - if (copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); - - if (vw.flags) - return -EINVAL; - - 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; - - on = ztv->running; - if (on) - zoran_cap(ztv, 0); - - /* - * strange, it seems xawtv sometimes calls us with 0 - * width and/or height. Ignore these values - */ - if (vw.x == 0) - vw.x = ztv->overinfo.x; - if (vw.y == 0) - vw.y = ztv->overinfo.y; - - /* by now we are committed to the new data... */ - write_lock_irq(&ztv->lock); - ztv->overinfo.x = vw.x; - ztv->overinfo.y = vw.y; - ztv->overinfo.w = vw.width; - ztv->overinfo.h = vw.height; - write_unlock_irq(&ztv->lock); - - /* - * Impose display clips - */ - if (vw.x+vw.width > ztv->swidth) - new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); - if (vw.y+vw.height > ztv->sheight) - new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1); - - /* built the requested clipping zones */ - zoran_set_geo(ztv, &ztv->overinfo); - zoran_built_overlay(ztv, vw.clipcount, vcp); - vfree(vcp); - - /* if we were on, restart the video engine */ - if (on) - zoran_cap(ztv, 1); - break; - } - - case VIDIOCCAPTURE: - { - int v; - get_user_ret(v,(int*)arg, -EFAULT); - DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); - - if (v==0) { - clear_bit(STATE_OVERLAY, &ztv->state); - zoran_cap(ztv, 1); - } - else { - /* is VIDIOCSFBUF, VIDIOCSWIN done? */ - if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) - return -EINVAL; - - set_bit(STATE_OVERLAY, &ztv->state); - zoran_cap(ztv, 1); - } - break; - } - - case VIDIOCGFBUF: - { - struct video_buffer v; - DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD)); - read_lock(&ztv->lock); - v.base = (void *)ztv->overinfo.busadr; - v.height = ztv->sheight; - v.width = ztv->swidth; - v.depth = ztv->depth; - v.bytesperline = ztv->overinfo.bpl; - read_unlock(&ztv->lock); - if(copy_to_user(arg, &v,sizeof(v))) - return -EFAULT; - break; - } - case VIDIOCSFBUF: - { - struct video_buffer v; -#if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) -#else - if(!suser()) -#endif - return -EPERM; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline)); - - if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) - return -EINVAL; - if (v.bytesperline<1) - return -EINVAL; - if (ztv->running) - return -EBUSY; - write_lock_irq(&ztv->lock); - ztv->overinfo.busadr = (ulong)v.base; - ztv->sheight = v.height; - ztv->swidth = v.width; - ztv->depth = v.depth; /* bits per pixel */ - ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ - ztv->overinfo.bpl = v.bytesperline; /* bytes per line */ - write_unlock_irq(&ztv->lock); - break; - } - - case VIDIOCKEY: - { - /* Will be handled higher up .. */ - break; - } - - case VIDIOCSYNC: - { - int i; - get_user_ret(i,(int*)arg, -EFAULT); - DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); - if (i<0 || i>ZORAN_MAX_FBUFFERS) - return -EINVAL; - switch (ztv->grabinfo[i].status) { - case FBUFFER_FREE: - return -EINVAL; - case FBUFFER_BUSY: - /* wait till this buffer gets grabbed */ - while (ztv->grabinfo[i].status == FBUFFER_BUSY) { - interruptible_sleep_on(&ztv->grabq); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - } - /* don't fall through; a DONE buffer is not UNUSED */ - break; - case FBUFFER_DONE: - ztv->grabinfo[i].status = FBUFFER_FREE; - /* tell ppl we have a spare buffer */ - wake_up_interruptible(&ztv->grabq); - break; - } - DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i)); - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - struct vidinfo* frame; - if (copy_from_user(&vm,arg,sizeof(vm))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format)); - if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || - vm.width<32 || vm.width>768 || - vm.height<32 || vm.height>576 || - vm.format>NRPALETTES || - palette2fmt[vm.format].mode == 0) - return -EINVAL; - - /* we are allowed to take over UNUSED and DONE buffers */ - frame = &ztv->grabinfo[vm.frame]; - if (frame->status == FBUFFER_BUSY) - return -EBUSY; - - /* setup the other parameters if they are given */ - write_lock_irq(&ztv->lock); - frame->w = vm.width; - frame->h = vm.height; - frame->format = vm.format; - frame->bpp = palette2fmt[frame->format].bpp; - frame->bpl = frame->w*frame->bpp; - frame->status = FBUFFER_BUSY; - frame->next = 0; - { /* add to tail of queue */ - struct vidinfo* oldframe = ztv->workqueue; - if (!oldframe) ztv->workqueue = frame; - else { - while (oldframe->next) oldframe = oldframe->next; - oldframe->next = frame; - } - } - write_unlock_irq(&ztv->lock); - zoran_cap(ztv, 1); - break; - } - - case VIDIOCGMBUF: - { - struct video_mbuf mb; - int i; - DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD)); - mb.size = ZORAN_MAX_FBUFSIZE; - mb.frames = ZORAN_MAX_FBUFFERS; - for (i=0; ivideo_dev.minor; - vu.vbi = ztv->vbi_dev.minor; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; - if(copy_to_user(arg, &vu,sizeof(vu))) - return -EFAULT; - break; - } - - case VIDIOCGFREQ: - { - unsigned long v = ztv->tuner_freq; - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD)); - break; - } - case VIDIOCSFREQ: - { - unsigned long v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD)); - - if (ztv->have_tuner) { - int fixme = v; - if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0) - return -EAGAIN; - } - ztv->tuner_freq = v; - break; - } - - /* Why isn't this in the API? - * And why doesn't it take a buffer number? - case BTTV_FIELDNR: - { - unsigned long v = ztv->lastfieldnr; - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD)); - break; - } - */ - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static -int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) -{ - struct zoran* ztv = (struct zoran*)dev; - unsigned long start = (unsigned long)adr; - unsigned long pos; - - DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size)); - - /* sanity checks */ - if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) - return -EINVAL; - - /* start mapping the whole shabang to user memory */ - pos = (unsigned long)ztv->fbuffer; - while (size>0) { - unsigned long page = virt_to_phys((void*)pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - -static struct video_device zr36120_template= -{ - "UNSET", - VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, - VID_HARDWARE_ZR36120, - - zoran_open, - zoran_close, - zoran_read, - zoran_write, -#if LINUX_VERSION_CODE >= 0x020100 - zoran_poll, /* poll */ -#endif - zoran_ioctl, - zoran_mmap, - NULL, /* initialize */ - NULL, - 0, - -1 -}; - -static -int vbi_open(struct video_device *dev, int flags) -{ - struct zoran *ztv = (struct zoran*)dev->priv; - struct vidinfo* item; - - DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags)); - - /* - * During VBI device open, we continiously grab VBI-like - * data in the vbi buffer when we have nothing to do. - * Only when there is an explicit request for VBI data - * (read call) we /force/ a read. - */ - - /* allocate buffers */ - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - { - item->status = FBUFFER_FREE; - - /* alloc */ - if (!item->memadr) { - item->memadr = bmalloc(ZORAN_VBI_BUFSIZE); - if (!item->memadr) { - /* could not get a buffer, bail out */ - while (item != ztv->readinfo) { - item--; - bfree(item->memadr, ZORAN_VBI_BUFSIZE); - item->memadr = 0; - item->busadr = 0; - } - return -ENOBUFS; - } - } - - /* determine the DMAable address */ - item->busadr = virt_to_bus(item->memadr); - } - - /* do the common part of all open's */ - zoran_common_open(ztv, flags); - - set_bit(STATE_VBI, &ztv->state); - /* start read-ahead */ - zoran_cap(ztv, 1); - - MOD_INC_USE_COUNT; - return 0; -} - -static -void vbi_close(struct video_device *dev) -{ - struct zoran *ztv = (struct zoran*)dev->priv; - struct vidinfo* item; - - DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD)); - - /* driver specific closure */ - clear_bit(STATE_VBI, &ztv->state); - - zoran_common_close(ztv); - - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); /* Wait 1/10th of a second */ - - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - { - if (item->memadr) - bfree(item->memadr, ZORAN_VBI_BUFSIZE); - item->memadr = 0; - } - - MOD_DEC_USE_COUNT; -} - -/* - * This read function could be used reentrant in a SMP situation. - * - * This is made possible by the spinlock which is kept till we - * found and marked a buffer for our own use. The lock must - * be released as soon as possible to prevent lock contention. - */ -static -long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) -{ - struct zoran *ztv = (struct zoran*)dev->priv; - unsigned long max; - struct vidinfo* unused = 0; - struct vidinfo* done = 0; - - DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock)); - - /* find ourself a free or completed buffer */ - for (;;) { - struct vidinfo* item; - - write_lock_irq(&ztv->lock); - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { - if (!unused && item->status == FBUFFER_FREE) - unused = item; - if (!done && item->status == FBUFFER_DONE) - done = item; - } - if (done || unused) - break; - - /* no more free buffers, wait for them. */ - write_unlock_irq(&ztv->lock); - if (nonblock) - return -EWOULDBLOCK; - interruptible_sleep_on(&ztv->vbiq); - if (signal_pending(current)) - return -EINTR; - } - - /* Do we have 'ready' data? */ - if (!done) { - /* no? than this will take a while... */ - if (nonblock) { - write_unlock_irq(&ztv->lock); - return -EWOULDBLOCK; - } - - /* mark the unused buffer as wanted */ - unused->status = FBUFFER_BUSY; - unused->next = 0; - { /* add to tail of queue */ - struct vidinfo* oldframe = ztv->workqueue; - if (!oldframe) ztv->workqueue = unused; - else { - while (oldframe->next) oldframe = oldframe->next; - oldframe->next = unused; - } - } - write_unlock_irq(&ztv->lock); - - /* tell the state machine we want it filled /NOW/ */ - zoran_cap(ztv, 1); - - /* wait till this buffer gets grabbed */ - while (unused->status == FBUFFER_BUSY) { - interruptible_sleep_on(&ztv->vbiq); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - } - done = unused; - } - else - write_unlock_irq(&ztv->lock); - - /* Yes! we got data! */ - max = done->bpl * -done->h; - if (count > max) - count = max; - - /* check if the user gave us enough room to write the data */ - if (!access_ok(VERIFY_WRITE, buf, count)) { - count = -EFAULT; - goto out; - } - - /* - * Now transform/strip the data from YUV to Y-only - * NB. Assume the Y is in the LSB of the YUV data. - */ - { - unsigned char* optr = buf; - unsigned char* eptr = buf+count; - - /* are we beeing accessed from an old driver? */ - if (count == 2*19*2048) { - /* - * Extreme HACK, old VBI programs expect 2048 points - * of data, and we only got 864 orso. Double each - * datapoint and clear the rest of the line. - * This way we have appear to have a - * sample_frequency of 29.5 Mc. - */ - int x,y; - unsigned char* iptr = done->memadr+1; - for (y=done->h; optrw; x++) - { - unsigned char a = iptr[x*2]; - *optr++ = a; - *optr++ = a; - } - /* and clear the rest of the line */ - for (x*=2; optrbpl; x++) - *optr++ = 0; - /* next line */ - iptr += done->bpl; - } - } - else { - /* - * Other (probably newer) programs asked - * us what geometry we are using, and are - * reading the correct size. - */ - int x,y; - unsigned char* iptr = done->memadr+1; - for (y=done->h; optrw; x++) - *optr++ = iptr[x*2]; - /* and clear the rest of the line */ - for (;optrbpl; x++) - *optr++ = 0; - /* next line */ - iptr += done->bpl; - } - } - - /* API compliance: - * place the framenumber (half fieldnr) in the last long - */ - ((ulong*)eptr)[-1] = done->fieldnr/2; - } - - /* keep the engine running */ - done->status = FBUFFER_FREE; - zoran_cap(ztv, 1); - - /* tell listeners this buffer just became free */ - wake_up_interruptible(&ztv->vbiq); - - /* goodbye */ -out: - DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count)); - return count; -} - -#if LINUX_VERSION_CODE >= 0x020100 -static -unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait) -{ - struct zoran *ztv = (struct zoran*)dev->priv; - struct vidinfo* item; - unsigned int mask = 0; - - poll_wait(file, &ztv->vbiq, wait); - - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - if (item->status == FBUFFER_DONE) - { - mask |= (POLLIN | POLLRDNORM); - break; - } - - DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask)); - - return mask; -} -#endif - -static -int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct zoran* ztv = (struct zoran*)dev->priv; - - switch (cmd) { - case VIDIOCGVBIFMT: - { - struct vbi_format f; - DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD)); - f.sampling_rate = 14750000UL; - f.samples_per_line = -ztv->readinfo[0].w; - f.sample_format = VIDEO_PALETTE_RAW; - f.start[0] = f.start[1] = ztv->readinfo[0].y; - f.start[1] += 312; - f.count[0] = f.count[1] = -ztv->readinfo[0].h; - f.flags = VBI_INTERLACED; - if (copy_to_user(arg,&f,sizeof(f))) - return -EFAULT; - break; - } - case VIDIOCSVBIFMT: - { - struct vbi_format f; - int i; - if (copy_from_user(&f, arg,sizeof(f))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags)); - - /* lots of parameters are fixed... (PAL) */ - if (f.sampling_rate != 14750000UL || - f.samples_per_line > 864 || - f.sample_format != VIDEO_PALETTE_RAW || - f.start[0] < 0 || - f.start[0] != f.start[1]-312 || - f.count[0] != f.count[1] || - f.start[0]+f.count[0] >= 288 || - f.flags != VBI_INTERLACED) - return -EINVAL; - - write_lock_irq(&ztv->lock); - ztv->readinfo[0].y = f.start[0]; - ztv->readinfo[0].w = -f.samples_per_line; - ztv->readinfo[0].h = -f.count[0]; - ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp; - for (i=1; ireadinfo[i] = ztv->readinfo[i]; - write_unlock_irq(&ztv->lock); - break; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static struct video_device vbi_template= -{ - "UNSET", - VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, - VID_HARDWARE_ZR36120, - - vbi_open, - vbi_close, - vbi_read, - zoran_write, -#if LINUX_VERSION_CODE >= 0x020100 - vbi_poll, /* poll */ -#endif - vbi_ioctl, - NULL, /* no mmap */ - NULL, /* no initialize */ - NULL, /* priv */ - 0, /* busy */ - -1 /* minor */ -}; - -/* - * Scan for a Zoran chip, request the irq and map the io memory - */ -static -int __init find_zoran(void) -{ - int result; - struct zoran *ztv; - struct pci_dev *dev = NULL; - unsigned char revision; - int zoran_num=0; - - while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) - { - /* Ok, a ZR36120/ZR36125 found! */ - ztv = &zorans[zoran_num]; - ztv->dev = dev; - - if (pci_enable_device(dev)) - return -EIO; - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); - printk(KERN_INFO "zoran: Zoran %x (rev %d) ", - dev->device, revision); - printk("bus: %d, devfn: %d, irq: %d, ", - dev->bus->number, dev->devfn, dev->irq); - printk("memory: 0x%08lx.\n", ztv->zoran_adr); - - ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); - DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); - - result = request_irq(dev->irq, zoran_irq, - SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); - if (result==-EINVAL) - { - printk(KERN_ERR "zoran: Bad irq number or handler\n"); - return -EINVAL; - } - if (result==-EBUSY) - printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); - if (result < 0) - return result; - - /* Enable bus-mastering */ - pci_set_master(dev); - - zoran_num++; - } - if(zoran_num) - printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); - return zoran_num; -} - -static -int __init init_zoran(int card) -{ - struct zoran *ztv = &zorans[card]; - int i; - - /* if the given cardtype valid? */ - if (cardtype[card]>=NRTVCARDS) { - printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); - return -1; - } - - /* reset the zoran */ - zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); - udelay(10); - zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); - udelay(10); - - /* zoran chip specific details */ - ztv->card = tvcards+cardtype[card]; /* point to the selected card */ - ztv->norm = 0; /* PAL */ - ztv->tuner_freq = 0; - - /* videocard details */ - ztv->swidth = 800; - ztv->sheight = 600; - ztv->depth = 16; - - /* State details */ - ztv->fbuffer = 0; - ztv->overinfo.kindof = FBUFFER_OVERLAY; - ztv->overinfo.status = FBUFFER_FREE; - ztv->overinfo.x = 0; - ztv->overinfo.y = 0; - ztv->overinfo.w = 768; /* 640 */ - ztv->overinfo.h = 576; /* 480 */ - ztv->overinfo.format = VIDEO_PALETTE_RGB565; - ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; - ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; - ztv->overinfo.busadr = 0; - ztv->overinfo.memadr = 0; - ztv->overinfo.overlay = 0; - for (i=0; igrabinfo[i] = ztv->overinfo; - ztv->grabinfo[i].kindof = FBUFFER_GRAB; - } - init_waitqueue_head(&ztv->grabq); - - /* VBI details */ - ztv->readinfo[0] = ztv->overinfo; - ztv->readinfo[0].kindof = FBUFFER_VBI; - ztv->readinfo[0].w = -864; - ztv->readinfo[0].h = -38; - ztv->readinfo[0].format = VIDEO_PALETTE_YUV422; - ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp; - ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp; - for (i=1; ireadinfo[i] = ztv->readinfo[0]; - init_waitqueue_head(&ztv->vbiq); - - /* maintenance data */ - ztv->have_decoder = 0; - ztv->have_tuner = 0; - ztv->tuner_type = 0; - ztv->running = 0; - ztv->users = 0; - ztv->lock = RW_LOCK_UNLOCKED; - ztv->workqueue = 0; - ztv->fieldnr = 0; - ztv->lastfieldnr = 0; - - if (triton1) - zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); - - /* external FL determines TOP frame */ - zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); - - /* set HSpol */ - if (ztv->card->hsync_pos) - zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH); - /* set VSpol */ - if (ztv->card->vsync_pos) - zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV); - - /* Set the proper General Purpuse register bits */ - /* implicit: no softreset, 0 waitstates */ - zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); - /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ - zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); - - /* clear interrupt status */ - zrwrite(~0, ZORAN_ISR); - - /* - * i2c template - */ - ztv->i2c = zoran_i2c_bus_template; - sprintf(ztv->i2c.name,"zoran-%d",card); - ztv->i2c.data = ztv; - - /* - * Now add the template and register the device unit - */ - ztv->video_dev = zr36120_template; - strcpy(ztv->video_dev.name, ztv->i2c.name); - ztv->video_dev.priv = ztv; - if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0) - return -1; - - ztv->vbi_dev = vbi_template; - strcpy(ztv->vbi_dev.name, ztv->i2c.name); - ztv->vbi_dev.priv = ztv; - if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) { - video_unregister_device(&ztv->video_dev); - return -1; - } - i2c_register_bus(&ztv->i2c); - - /* set interrupt mask - the PIN enable will be set later */ - zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); - - printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name); - return 0; -} - -static -void __exit release_zoran(int max) -{ - struct zoran *ztv; - int i; - - for (i=0;idev->irq,ztv); - - /* unregister i2c_bus */ - i2c_unregister_bus((&ztv->i2c)); - - /* unmap and free memory */ - if (ztv->zoran_mem) - iounmap(ztv->zoran_mem); - - video_unregister_device(&ztv->video_dev); - video_unregister_device(&ztv->vbi_dev); - } -} - -void __exit zr36120_exit(void) -{ - release_zoran(zoran_cards); -} - -int __init zr36120_init(void) -{ - int card; - - handle_chipset(); - zoran_cards = find_zoran(); - if (zoran_cards<0) - /* no cards found, no need for a driver */ - return -EIO; - - /* initialize Zorans */ - for (card=0; card -#include - -#include -#include - -#include - -/* - * Debug macro's, place an x behind the ) for actual debug-compilation - * E.g. #define DEBUG(x...) x - */ -#define DEBUG(x...) /* Debug driver */ -#define IDEBUG(x...) /* Debug interrupt handler */ -#define PDEBUG 0 /* Debug PCI writes */ - -/* defined in zr36120_i2c */ -extern struct i2c_bus zoran_i2c_bus_template; - -#define ZORAN_MAX_FBUFFERS 2 -#define ZORAN_MAX_FBUFFER (768*576*2) -#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) - -#define ZORAN_VBI_BUFFERS 2 -#define ZORAN_VBI_BUFSIZE (22*1024*2) - -struct tvcard { - char* name; /* name of the cardtype */ - int video_inputs; /* number of channels defined in video_mux */ - int audio_inputs; /* number of channels defined in audio_mux */ - __u32 swapi2c:1, /* need to swap i2c wires SDA/SCL? */ - usegirq1:1, /* VSYNC at GIRQ1 instead of GIRQ0? */ - vsync_pos:1, /* positive VSYNC signal? */ - hsync_pos:1, /* positive HSYNC signal? */ - gpdir:8, /* General Purpose Direction register */ - gpval:8; /* General Purpose Value register */ - int video_mux[6]; /* mapping channel number to physical input */ -#define IS_TUNER 0x80 -#define IS_SVHS 0x40 -#define CHANNEL_MASK 0x3F - int audio_mux[6]; /* mapping channel number to physical input */ -}; -#define TUNER(x) ((x)|IS_TUNER) -#define SVHS(x) ((x)|IS_SVHS) - -struct vidinfo { - struct vidinfo* next; /* next active buffer */ - uint kindof; -#define FBUFFER_OVERLAY 0 -#define FBUFFER_GRAB 1 -#define FBUFFER_VBI 2 - uint status; -#define FBUFFER_FREE 0 -#define FBUFFER_BUSY 1 -#define FBUFFER_DONE 2 - ulong fieldnr; /* # of field, not framer! */ - uint x,y; - int w,h; /* w,h can be negative! */ - uint format; /* index in palette2fmt[] */ - uint bpp; /* lookup from palette2fmt[] */ - uint bpl; /* calc: width * bpp */ - ulong busadr; /* bus addr for DMA engine */ - char* memadr; /* kernel addr for making copies */ - ulong* overlay; /* kernel addr of overlay mask */ -}; - -struct zoran -{ - struct video_device video_dev; -#define CARD_DEBUG KERN_DEBUG "%s(%lu): " -#define CARD_INFO KERN_INFO "%s(%lu): " -#define CARD_ERR KERN_ERR "%s(%lu): " -#define CARD ztv->video_dev.name,ztv->fieldnr - - /* zoran chip specific details */ - struct i2c_bus i2c; /* i2c registration data */ - struct pci_dev* dev; /* ptr to PCI device */ - ulong zoran_adr; /* bus address of IO memory */ - char* zoran_mem; /* kernel address of IO memory */ - struct tvcard* card; /* the cardtype */ - uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */ - uint tuner_freq; /* Current freq in kHz */ - struct video_picture picture; /* Current picture params */ - - /* videocard details */ - uint swidth; /* screen width */ - uint sheight; /* screen height */ - uint depth; /* depth in bits */ - - /* State details */ - char* fbuffer; /* framebuffers for mmap */ - struct vidinfo overinfo; /* overlay data */ - struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/ - wait_queue_head_t grabq; /* grabbers queue */ - - /* VBI details */ - struct video_device vbi_dev; - struct vidinfo readinfo[2]; /* VBI data - flip buffers */ - wait_queue_head_t vbiq; /* vbi queue */ - - /* maintenance data */ - int have_decoder; /* did we detect a mux? */ - int have_tuner; /* did we detect a tuner? */ - int users; /* howmany video/vbi open? */ - int tuner_type; /* tuner type, when found */ - int running; /* are we rolling? */ - rwlock_t lock; - int state; /* what is requested of us? */ -#define STATE_OVERLAY 0 -#define STATE_VBI 1 - struct vidinfo* workqueue; /* buffers to grab, head is active */ - ulong fieldnr; /* #field, ticked every VSYNC */ - ulong lastfieldnr; /* #field, ticked every GRAB */ - - int vidInterlace; /* calculated */ - int vidXshift; /* calculated */ - uint vidWidth; /* calculated */ - uint vidHeight; /* calculated */ -}; - -#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr))) -#define zrread(adr) readl(ztv->zoran_mem+(adr)) - -#if PDEBUG == 0 -#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr) -#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr) -#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr) -#else -#define zrand(dat, adr) \ -do { \ - ulong data = (dat) & zrread((adr)); \ - zrwrite(data, (adr)); \ - if (0 != (~(dat) & zrread((adr)))) \ - printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \ -} while(0) - -#define zror(dat, adr) \ -do { \ - ulong data = (dat) | zrread((adr)); \ - zrwrite(data, (adr)); \ - if ((dat) != ((dat) & zrread(adr))) \ - printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \ -} while(0) - -#define zraor(dat, mask, adr) \ -do { \ - ulong data; \ - if ((dat) & (mask)) \ - printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ - data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \ - zrwrite(data,(adr)); \ - if ( (dat) != (~(mask) & zrread((adr))) ) \ - printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ -} while(0) -#endif - -#endif - -/* zoran PCI address space */ -#define ZORAN_VFEH 0x000 /* Video Front End Horizontal Conf. */ -#define ZORAN_VFEH_HSPOL (1<<30) -#define ZORAN_VFEH_HSTART (0x3FF<<10) -#define ZORAN_VFEH_HEND (0x3FF<<0) - -#define ZORAN_VFEV 0x004 /* Video Front End Vertical Conf. */ -#define ZORAN_VFEV_VSPOL (1<<30) -#define ZORAN_VFEV_VSTART (0x3FF<<10) -#define ZORAN_VFEV_VEND (0x3FF<<0) - -#define ZORAN_VFEC 0x008 /* Video Front End Scaler and Pixel */ -#define ZORAN_VFEC_EXTFL (1<<26) -#define ZORAN_VFEC_TOPFIELD (1<<25) -#define ZORAN_VFEC_VCLKPOL (1<<24) -#define ZORAN_VFEC_HFILTER (7<<21) -#define ZORAN_VFEC_HFILTER_1 (0<<21) /* no lumi, 3-tap chromo */ -#define ZORAN_VFEC_HFILTER_2 (1<<21) /* 3-tap lumi, 3-tap chromo */ -#define ZORAN_VFEC_HFILTER_3 (2<<21) /* 4-tap lumi, 4-tap chromo */ -#define ZORAN_VFEC_HFILTER_4 (3<<21) /* 5-tap lumi, 4-tap chromo */ -#define ZORAN_VFEC_HFILTER_5 (4<<21) /* 4-tap lumi, 4-tap chromo */ -#define ZORAN_VFEC_DUPFLD (1<<20) -#define ZORAN_VFEC_HORDCM (63<<14) -#define ZORAN_VFEC_VERDCM (63<<8) -#define ZORAN_VFEC_DISPMOD (1<<6) -#define ZORAN_VFEC_RGB (3<<3) -#define ZORAN_VFEC_RGB_YUV422 (0<<3) -#define ZORAN_VFEC_RGB_RGB888 (1<<3) -#define ZORAN_VFEC_RGB_RGB565 (2<<3) -#define ZORAN_VFEC_RGB_RGB555 (3<<3) -#define ZORAN_VFEC_ERRDIF (1<<2) -#define ZORAN_VFEC_PACK24 (1<<1) -#define ZORAN_VFEC_LE (1<<0) - -#define ZORAN_VTOP 0x00C /* Video Display "Top" */ - -#define ZORAN_VBOT 0x010 /* Video Display "Bottom" */ - -#define ZORAN_VSTR 0x014 /* Video Display Stride */ -#define ZORAN_VSTR_DISPSTRIDE (0xFFFF<<16) -#define ZORAN_VSTR_VIDOVF (1<<8) -#define ZORAN_VSTR_SNAPSHOT (1<<1) -#define ZORAN_VSTR_GRAB (1<<0) - -#define ZORAN_VDC 0x018 /* Video Display Conf. */ -#define ZORAN_VDC_VIDEN (1<<31) -#define ZORAN_VDC_MINPIX (0x1F<<25) -#define ZORAN_VDC_TRICOM (1<<24) -#define ZORAN_VDC_VIDWINHT (0x3FF<<12) -#define ZORAN_VDC_VIDWINWID (0x3FF<<0) - -#define ZORAN_MTOP 0x01C /* Masking Map "Top" */ - -#define ZORAN_MBOT 0x020 /* Masking Map "Bottom" */ - -#define ZORAN_OCR 0x024 /* Overlay Control */ -#define ZORAN_OCR_OVLEN (1<<15) -#define ZORAN_OCR_MASKSTRIDE (0xFF<<0) - -#define ZORAN_PCI 0x028 /* System, PCI and GPP Control */ -#define ZORAN_PCI_SOFTRESET (1<<24) -#define ZORAN_PCI_WAITSTATE (3<<16) -#define ZORAN_PCI_GENPURDIR (0xFF<<0) - -#define ZORAN_GUEST 0x02C /* GuestBus Control */ - -#define ZORAN_CSOURCE 0x030 /* Code Source Address */ - -#define ZORAN_CTRANS 0x034 /* Code Transfer Control */ - -#define ZORAN_CMEM 0x038 /* Code Memory Pointer */ - -#define ZORAN_ISR 0x03C /* Interrupt Status Register */ -#define ZORAN_ISR_CODE (1<<28) -#define ZORAN_ISR_GIRQ0 (1<<29) -#define ZORAN_ISR_GIRQ1 (1<<30) - -#define ZORAN_ICR 0x040 /* Interrupt Control Register */ -#define ZORAN_ICR_EN (1<<24) -#define ZORAN_ICR_CODE (1<<28) -#define ZORAN_ICR_GIRQ0 (1<<29) -#define ZORAN_ICR_GIRQ1 (1<<30) - -#define ZORAN_I2C 0x044 /* I2C-Bus */ -#define ZORAN_I2C_SCL (1<<1) -#define ZORAN_I2C_SDA (1<<0) - -#define ZORAN_POST 0x48 /* PostOffice */ -#define ZORAN_POST_PEN (1<<25) -#define ZORAN_POST_TIME (1<<24) -#define ZORAN_POST_DIR (1<<23) -#define ZORAN_POST_GUESTID (3<<20) -#define ZORAN_POST_GUEST (7<<16) -#define ZORAN_POST_DATA (0xFF<<0) - -#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/zr36120_i2c.c linux/drivers/char/zr36120_i2c.c --- v2.4.0-test6/linux/drivers/char/zr36120_i2c.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/char/zr36120_i2c.c Wed Dec 31 16:00:00 1969 @@ -1,133 +0,0 @@ -/* - zr36120_i2c.c - Zoran 36120/36125 based framegrabbers - - Copyright (C) 1998-1999 Pauline Middelink - - 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. -*/ - -#include -#include -#include - -#include -#include -#include - -#include "tuner.h" -#include "zr36120.h" - -/* ----------------------------------------------------------------------- */ -/* I2C functions */ -/* ----------------------------------------------------------------------- */ - -/* software I2C functions */ - -#define I2C_DELAY 10 - -static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) -{ - struct zoran *ztv = (struct zoran*)bus->data; - unsigned int b = 0; - if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA; - if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL; - zrwrite(b, ZORAN_I2C); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct zoran *ztv = (struct zoran*)bus->data; - if (ztv->card->swapi2c) - return zrread(ZORAN_I2C) & ZORAN_I2C_SCL; - return zrread(ZORAN_I2C) & ZORAN_I2C_SDA; -} - -static -void attach_inform(struct i2c_bus *bus, int id) -{ - struct zoran *ztv = (struct zoran*)bus->data; - struct video_decoder_capability dc; - int rv; - - switch (id) { - case I2C_DRIVERID_VIDEODECODER: - DEBUG(printk(CARD_INFO "decoder attached\n",CARD)); - - /* fetch the capabilites of the decoder */ - rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); - if (rv) { - DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD)); - break; - } - DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); - - /* Test if the decoder can de VBI transfers */ - if (dc.flags & 16 /*VIDEO_DECODER_VBI*/) - ztv->have_decoder = 2; - else - ztv->have_decoder = 1; - break; - case I2C_DRIVERID_TUNER: - ztv->have_tuner = 1; - DEBUG(printk(CARD_INFO "tuner attached\n",CARD)); - if (ztv->tuner_type >= 0) - { - if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0) - DEBUG(printk(CARD_INFO "attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type)); - } - break; - default: - DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id)); - break; - } -} - -static -void detach_inform(struct i2c_bus *bus, int id) -{ - struct zoran *ztv = (struct zoran*)bus->data; - - switch (id) { - case I2C_DRIVERID_VIDEODECODER: - ztv->have_decoder = 0; - DEBUG(printk(CARD_INFO "decoder detached\n",CARD)); - break; - case I2C_DRIVERID_TUNER: - ztv->have_tuner = 0; - DEBUG(printk(CARD_INFO "tuner detached\n",CARD)); - break; - default: - DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id)); - break; - } -} - -struct i2c_bus zoran_i2c_bus_template = -{ - "ZR36120", - I2C_BUSID_ZORAN, - NULL, - - SPIN_LOCK_UNLOCKED, - - attach_inform, - detach_inform, - - i2c_setlines, - i2c_getdataline, - NULL, - NULL -}; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/zr36120_mem.c linux/drivers/char/zr36120_mem.c --- v2.4.0-test6/linux/drivers/char/zr36120_mem.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/char/zr36120_mem.c Wed Dec 31 16:00:00 1969 @@ -1,77 +0,0 @@ -/* - zr36120_mem.c - Zoran 36120/36125 based framegrabbers - - Copyright (C) 1998-1999 Pauline Middelink - - 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. -*/ - -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BIGPHYS_AREA -#include -#endif - -#include "zr36120.h" -#include "zr36120_mem.h" - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -void* bmalloc(unsigned long size) -{ - void* mem; -#ifdef CONFIG_BIGPHYS_AREA - mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL); -#else - /* - * The following function got a lot of memory at boottime, - * so we know its always there... - */ - mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size)); -#endif - if (mem) { - unsigned long adr = (unsigned long)mem; - while (size > 0) { - mem_map_reserve(virt_to_page(phys_to_virt(adr))); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - return mem; -} - -void bfree(void* mem, unsigned long size) -{ - if (mem) { - unsigned long adr = (unsigned long)mem; - unsigned long siz = size; - while (siz > 0) { - mem_map_unreserve(virt_to_page(phys_to_virt(adr))); - adr += PAGE_SIZE; - siz -= PAGE_SIZE; - } -#ifdef CONFIG_BIGPHYS_AREA - bigphysarea_free_pages(mem); -#else - free_pages((unsigned long)mem,get_order(size)); -#endif - } -} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/char/zr36120_mem.h linux/drivers/char/zr36120_mem.h --- v2.4.0-test6/linux/drivers/char/zr36120_mem.h Tue Jan 4 13:57:17 2000 +++ linux/drivers/char/zr36120_mem.h Wed Dec 31 16:00:00 1969 @@ -1,3 +0,0 @@ -/* either kmalloc() or bigphysarea() alloced memory - continuous */ -void* bmalloc(unsigned long size); -void bfree(void* mem, unsigned long size); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/Config.in linux/drivers/input/Config.in --- v2.4.0-test6/linux/drivers/input/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/Config.in Tue Aug 22 11:41:14 2000 @@ -0,0 +1,20 @@ +# +# Input core configuration +# + +mainmenu_option next_comment +comment 'Input core support' + +tristate 'Input core support' CONFIG_INPUT +if [ "$CONFIG_INPUT" != "n" ]; then + dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT + if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then + int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 + int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 + fi + dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT + dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT +fi + +endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/Makefile linux/drivers/input/Makefile --- v2.4.0-test6/linux/drivers/input/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/Makefile Tue Aug 22 11:41:14 2000 @@ -0,0 +1,51 @@ +# +# Makefile for the input core drivers. +# + +# Subdirs. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +# The target object and module list name. + +O_TARGET := inputdrv.o +M_OBJS := +O_OBJS := + +# Objects that export symbols. + +export-objs := input.o + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +# Each configuration option enables a list of files. + +obj-$(CONFIG_INPUT) += input.o +obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o +obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o +obj-$(CONFIG_INPUT_JOYDEV) += joydev.o +obj-$(CONFIG_INPUT_EVDEV) += evdev.o + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/evdev.c linux/drivers/input/evdev.c --- v2.4.0-test6/linux/drivers/input/evdev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/evdev.c Thu Jul 27 18:36:54 2000 @@ -0,0 +1,356 @@ +/* + * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Event char devices, giving access to raw input device events. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#define EVDEV_MINOR_BASE 64 +#define EVDEV_MINORS 32 +#define EVDEV_BUFFER_SIZE 64 + +#include +#include +#include +#include +#include +#include + +struct evdev { + int exist; + int open; + int minor; + struct input_handle handle; + wait_queue_head_t wait; + devfs_handle_t devfs; + struct evdev_list *list; +}; + +struct evdev_list { + struct input_event buffer[EVDEV_BUFFER_SIZE]; + int head; + int tail; + struct fasync_struct *fasync; + struct evdev *evdev; + struct evdev_list *next; +}; + +static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ }; + +static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct evdev *evdev = handle->private; + struct evdev_list *list = evdev->list; + + while (list) { + + get_fast_time(&list->buffer[list->head].time); + list->buffer[list->head].type = type; + list->buffer[list->head].code = code; + list->buffer[list->head].value = value; + list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); + + kill_fasync(&list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&evdev->wait); +} + +static int evdev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct evdev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int evdev_release(struct inode * inode, struct file * file) +{ + struct evdev_list *list = file->private_data; + struct evdev_list **listptr; + + lock_kernel(); + listptr = &list->evdev->list; + evdev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->evdev->open) { + if (list->evdev->exist) { + input_close_device(&list->evdev->handle); + } else { + input_unregister_minor(list->evdev->devfs); + evdev_table[list->evdev->minor] = NULL; + kfree(list->evdev); + } + } + + kfree(list); + unlock_kernel(); + + return 0; +} + +static int evdev_open(struct inode * inode, struct file * file) +{ + struct evdev_list *list; + int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; + + if (i > EVDEV_MINORS || !evdev_table[i]) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) + return -ENOMEM; + memset(list, 0, sizeof(struct evdev_list)); + + list->evdev = evdev_table[i]; + list->next = evdev_table[i]->list; + evdev_table[i]->list = list; + + file->private_data = list; + + if (!list->evdev->open++) + if (list->evdev->exist) + input_open_device(&list->evdev->handle); + + return 0; +} + +static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct evdev_list *list = file->private_data; + int retval = 0; + + if (list->head == list->tail) { + + add_wait_queue(&list->evdev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (list->head == list->tail) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->evdev->wait, &wait); + } + + if (retval) + return retval; + + while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { + if (copy_to_user(buffer + retval, list->buffer + list->tail, + sizeof(struct input_event))) return -EFAULT; + list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); + retval += sizeof(struct input_event); + } + + return retval; +} + +/* No kernel lock - fine */ +static unsigned int evdev_poll(struct file *file, poll_table *wait) +{ + struct evdev_list *list = file->private_data; + poll_wait(file, &list->evdev->wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + return 0; +} + +static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct evdev_list *list = file->private_data; + struct evdev *evdev = list->evdev; + struct input_dev *dev = evdev->handle.dev; + int retval; + + switch (cmd) { + + case EVIOCGVERSION: + return put_user(EV_VERSION, (int *) arg); + + case EVIOCGID: + if ((retval = put_user(dev->idbus, ((short *) arg) + 0))) return retval; + if ((retval = put_user(dev->idvendor, ((short *) arg) + 1))) return retval; + if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval; + if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval; + return 0; + + default: + + if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) + return -EINVAL; + + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { + + long *bits; + int len; + + switch (_IOC_NR(cmd) & EV_MAX) { + case 0: bits = dev->evbit; len = EV_MAX; break; + case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; + case EV_REL: bits = dev->relbit; len = REL_MAX; break; + case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; + case EV_LED: bits = dev->ledbit; len = LED_MAX; break; + case EV_SND: bits = dev->sndbit; len = SND_MAX; break; + default: return -EINVAL; + } + len = NBITS(len) * sizeof(long); + if (len > _IOC_SIZE(cmd)) { + printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n", + len, _IOC_SIZE(cmd)); + len = _IOC_SIZE(cmd); + } + return copy_to_user((char *) arg, bits, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { + int len; + if (!dev->name) return 0; + len = strlen(dev->name) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len; + } + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { + + int t = _IOC_NR(cmd) & ABS_MAX; + + if ((retval = put_user(dev->abs[t], ((int *) arg) + 0))) return retval; + if ((retval = put_user(dev->absmin[t], ((int *) arg) + 1))) return retval; + if ((retval = put_user(dev->absmax[t], ((int *) arg) + 2))) return retval; + if ((retval = put_user(dev->absfuzz[t], ((int *) arg) + 3))) return retval; + if ((retval = put_user(dev->absflat[t], ((int *) arg) + 4))) return retval; + + return 0; + } + } + return -EINVAL; +} + +static struct file_operations evdev_fops = { + owner: THIS_MODULE, + read: evdev_read, + write: evdev_write, + poll: evdev_poll, + open: evdev_open, + release: evdev_release, + ioctl: evdev_ioctl, + fasync: evdev_fasync, +}; + +static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct evdev *evdev; + int minor; + + for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); + if (evdev_table[minor]) { + printk(KERN_ERR "evdev: no more free evdev devices\n"); + return NULL; + } + + if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) + return NULL; + memset(evdev, 0, sizeof(struct evdev)); + + init_waitqueue_head(&evdev->wait); + + evdev->minor = minor; + evdev_table[minor] = evdev; + + evdev->handle.dev = dev; + evdev->handle.handler = handler; + evdev->handle.private = evdev; + + evdev->exist = 1; + + evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE); + + printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); + + return &evdev->handle; +} + +static void evdev_disconnect(struct input_handle *handle) +{ + struct evdev *evdev = handle->private; + + evdev->exist = 0; + + if (evdev->open) { + input_close_device(handle); + } else { + input_unregister_minor(evdev->devfs); + evdev_table[evdev->minor] = NULL; + kfree(evdev); + } +} + +static struct input_handler evdev_handler = { + event: evdev_event, + connect: evdev_connect, + disconnect: evdev_disconnect, + fops: &evdev_fops, + minor: EVDEV_MINOR_BASE, +}; + +static int __init evdev_init(void) +{ + input_register_handler(&evdev_handler); + return 0; +} + +static void __exit evdev_exit(void) +{ + input_unregister_handler(&evdev_handler); +} + +module_init(evdev_init); +module_exit(evdev_exit); + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Event character device driver"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/input.c linux/drivers/input/input.c --- v2.4.0-test6/linux/drivers/input/input.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/input.c Mon Aug 21 21:50:32 2000 @@ -0,0 +1,426 @@ +/* + * $Id: input.c,v 1.7 2000/05/28 17:31:36 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * The input layer module itself + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input layer module"); + +EXPORT_SYMBOL(input_register_device); +EXPORT_SYMBOL(input_unregister_device); +EXPORT_SYMBOL(input_register_handler); +EXPORT_SYMBOL(input_unregister_handler); +EXPORT_SYMBOL(input_register_minor); +EXPORT_SYMBOL(input_unregister_minor); +EXPORT_SYMBOL(input_open_device); +EXPORT_SYMBOL(input_close_device); +EXPORT_SYMBOL(input_event); + +#define INPUT_MAJOR 13 +#define INPUT_DEVICES 256 + +static struct input_dev *input_dev = NULL; +static struct input_handler *input_handler = NULL; +static struct input_handler *input_table[8] = { NULL, /* ... */ }; +static devfs_handle_t input_devfs_handle = NULL; +static int input_number = 0; +static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ }; + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct input_handle *handle = dev->handle; + +/* + * Filter non-events, and bad input values out. + */ + + if (type > EV_MAX || !test_bit(type, dev->evbit)) + return; + + switch (type) { + + case EV_KEY: + + if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) + return; + + if (value == 2) break; + + change_bit(code, dev->key); + + if (test_bit(EV_REP, dev->evbit) && dev->timer.function) { + if (value) { + mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]); + dev->repeat_key = code; + break; + } + if (dev->repeat_key == code) + del_timer(&dev->timer); + } + + break; + + case EV_ABS: + + if (code > ABS_MAX || !test_bit(code, dev->absbit)) + return; + + if (dev->absfuzz[code]) { + if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) && + (value < dev->abs[code] + (dev->absfuzz[code] >> 1))) + return; + + if ((value > dev->abs[code] - dev->absfuzz[code]) && + (value < dev->abs[code] + dev->absfuzz[code])) + value = (dev->abs[code] * 3 + value) >> 2; + + if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) && + (value < dev->abs[code] + (dev->absfuzz[code] << 1))) + value = (dev->abs[code] + value) >> 1; + } + + if (dev->abs[code] == value) + return; + + dev->abs[code] = value; + break; + + case EV_REL: + + if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) + return; + + break; + + case EV_LED: + + if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) + return; + + change_bit(code, dev->led); + if (dev->event) dev->event(dev, type, code, value); + + break; + + case EV_SND: + + if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value) + return; + + change_bit(code, dev->snd); + if (dev->event) dev->event(dev, type, code, value); + + break; + + case EV_REP: + + if (code > REP_MAX || dev->rep[code] == value) return; + + dev->rep[code] = value; + if (dev->event) dev->event(dev, type, code, value); + + break; + } +/* + * Add randomness. + */ + +#if 0 /* BUG */ + add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value); +#endif + +/* + * Distribute the event to handler modules. + */ + + while (handle) { + if (handle->open) + handle->handler->event(handle, type, code, value); + handle = handle->dnext; + } +} + +static void input_repeat_key(unsigned long data) +{ + struct input_dev *dev = (void *) data; + input_event(dev, EV_KEY, dev->repeat_key, 2); + mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); +} + +int input_open_device(struct input_handle *handle) +{ + handle->open++; + if (handle->dev->open) + return handle->dev->open(handle->dev); + return 0; +} + +void input_close_device(struct input_handle *handle) +{ + if (handle->dev->close) + handle->dev->close(handle->dev); + handle->open--; +} + +static void input_link_handle(struct input_handle *handle) +{ + handle->dnext = handle->dev->handle; + handle->hnext = handle->handler->handle; + handle->dev->handle = handle; + handle->handler->handle = handle; +} + +static void input_unlink_handle(struct input_handle *handle) +{ + struct input_handle **handleptr; + + handleptr = &handle->dev->handle; + while (*handleptr && (*handleptr != handle)) + handleptr = &((*handleptr)->dnext); + *handleptr = (*handleptr)->dnext; + + handleptr = &handle->handler->handle; + while (*handleptr && (*handleptr != handle)) + handleptr = &((*handleptr)->hnext); + *handleptr = (*handleptr)->hnext; +} + +void input_register_device(struct input_dev *dev) +{ + struct input_handler *handler = input_handler; + struct input_handle *handle; + +/* + * Initialize repeat timer to default values. + */ + + init_timer(&dev->timer); + dev->timer.data = (long) dev; + dev->timer.function = input_repeat_key; + dev->rep[REP_DELAY] = HZ/4; + dev->rep[REP_PERIOD] = HZ/33; + +/* + * Add the device. + */ + + if (input_number >= INPUT_DEVICES) { + printk(KERN_WARNING "input: ran out of input device numbers!\n"); + dev->number = input_number; + } else { + dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES); + set_bit(dev->number, input_devices); + } + + dev->next = input_dev; + input_dev = dev; + input_number++; + +/* + * Notify handlers. + */ + + while (handler) { + if ((handle = handler->connect(handler, dev))) + input_link_handle(handle); + handler = handler->next; + } +} + +void input_unregister_device(struct input_dev *dev) +{ + struct input_handle *handle = dev->handle; + struct input_dev **devptr = &input_dev; + struct input_handle *dnext; + +/* + * Kill any pending repeat timers. + */ + + del_timer(&dev->timer); + +/* + * Notify handlers. + */ + + while (handle) { + dnext = handle->dnext; + input_unlink_handle(handle); + handle->handler->disconnect(handle); + handle = dnext; + } + +/* + * Remove the device. + */ + + while (*devptr && (*devptr != dev)) + devptr = &((*devptr)->next); + *devptr = (*devptr)->next; + + input_number--; + + if (dev->number < INPUT_DEVICES) + clear_bit(dev->number, input_devices); +} + +void input_register_handler(struct input_handler *handler) +{ + struct input_dev *dev = input_dev; + struct input_handle *handle; + +/* + * Add minors if needed. + */ + + if (handler->fops != NULL) + input_table[handler->minor >> 5] = handler; + +/* + * Add the handler. + */ + + handler->next = input_handler; + input_handler = handler; + +/* + * Notify it about all existing devices. + */ + + while (dev) { + if ((handle = handler->connect(handler, dev))) + input_link_handle(handle); + dev = dev->next; + } +} + +void input_unregister_handler(struct input_handler *handler) +{ + struct input_handler **handlerptr = &input_handler; + struct input_handle *handle = handler->handle; + struct input_handle *hnext; + +/* + * Tell the handler to disconnect from all devices it keeps open. + */ + + while (handle) { + hnext = handle->hnext; + input_unlink_handle(handle); + handler->disconnect(handle); + handle = hnext; + } + +/* + * Remove it. + */ + + while (*handlerptr && (*handlerptr != handler)) + handlerptr = &((*handlerptr)->next); + + *handlerptr = (*handlerptr)->next; + +/* + * Remove minors. + */ + + if (handler->fops != NULL) + input_table[handler->minor >> 5] = NULL; +} + +static int input_open_file(struct inode *inode, struct file *file) +{ + struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5]; + struct file_operations *old_fops, *new_fops = NULL; + int err; + + /* No load-on-demand here? */ + if (!handler || !(new_fops = fops_get(handler->fops))) + return -ENODEV; + + /* + * That's _really_ odd. Usually NULL ->open means "nothing special", + * not "no device". Oh, well... + */ + if (!new_fops->open) { + fops_put(new_fops); + return -ENODEV; + } + old_fops = file->f_op; + file->f_op = new_fops; + err = new_fops->open(inode, file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + return err; +} + +static struct file_operations input_fops = { + owner: THIS_MODULE, + open: input_open_file, +}; + +devfs_handle_t input_register_minor(char *name, int minor, int minor_base) +{ + char devfs_name[16]; + sprintf(devfs_name, name, minor); + return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base, + S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL); +} + +void input_unregister_minor(devfs_handle_t handle) +{ + devfs_unregister(handle); +} + +static int __init input_init(void) +{ + if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) { + printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); + return -EBUSY; + } + input_devfs_handle = devfs_mk_dir(NULL, "input", NULL); + return 0; +} + +static void __exit input_exit(void) +{ + devfs_unregister(input_devfs_handle); + if (devfs_unregister_chrdev(INPUT_MAJOR, "input")) + printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR); +} + +module_init(input_init); +module_exit(input_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/joydev.c linux/drivers/input/joydev.c --- v2.4.0-test6/linux/drivers/input/joydev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/joydev.c Tue Aug 22 09:06:31 2000 @@ -0,0 +1,497 @@ +/* + * $Id: joydev.c,v 1.13 2000/08/14 21:05:26 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999 Colin Van Dyke + * + * Joystick device driver for the input driver suite. + * + * Sponsored by SuSE and Intel + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JOYDEV_MINOR_BASE 0 +#define JOYDEV_MINORS 32 +#define JOYDEV_BUFFER_SIZE 64 + +struct joydev { + int exist; + int open; + int minor; + struct input_handle handle; + wait_queue_head_t wait; + devfs_handle_t devfs; + struct joydev *next; + struct joydev_list *list; + struct js_corr corr[ABS_MAX]; + struct JS_DATA_SAVE_TYPE glue; + int nabs; + int nkey; + __u16 keymap[KEY_MAX - BTN_MISC]; + __u16 keypam[KEY_MAX - BTN_MISC]; + __u8 absmap[ABS_MAX]; + __u8 abspam[ABS_MAX]; + __s16 abs[ABS_MAX]; +}; + +struct joydev_list { + struct js_event buffer[JOYDEV_BUFFER_SIZE]; + int head; + int tail; + int startup; + struct fasync_struct *fasync; + struct joydev *joydev; + struct joydev_list *next; +}; + +static struct joydev *joydev_table[JOYDEV_MINORS]; + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Joystick device driver"); +MODULE_SUPPORTED_DEVICE("input/js"); + +static int joydev_correct(int value, struct js_corr *corr) +{ + switch (corr->type) { + case JS_CORR_NONE: + break; + case JS_CORR_BROKEN: + value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : + ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : + ((corr->coef[2] * (value - corr->coef[0])) >> 14); + break; + default: + return 0; + } + + if (value < -32767) return -32767; + if (value > 32767) return 32767; + + return value; +} + +static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct joydev *joydev = handle->private; + struct joydev_list *list = joydev->list; + struct js_event event; + + switch (type) { + + case EV_KEY: + if (code < BTN_MISC || value == 2) return; + event.type = JS_EVENT_BUTTON; + event.number = joydev->keymap[code - BTN_MISC]; + event.value = value; + break; + + case EV_ABS: + event.type = JS_EVENT_AXIS; + event.number = joydev->absmap[code]; + event.value = joydev_correct(value, joydev->corr + event.number); + if (event.value == joydev->abs[event.number]) return; + joydev->abs[event.number] = event.value; + break; + + default: + return; + } + + event.time = jiffies * (1000 / HZ); + + while (list) { + + memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); + + if (list->startup == joydev->nabs + joydev->nkey) + if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) + list->startup = 0; + + kill_fasync(&list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&joydev->wait); +} + +static int joydev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct joydev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int joydev_release(struct inode * inode, struct file * file) +{ + struct joydev_list *list = file->private_data; + struct joydev_list **listptr; + + lock_kernel(); + listptr = &list->joydev->list; + joydev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->joydev->open) { + if (list->joydev->exist) { + input_close_device(&list->joydev->handle); + } else { + input_unregister_minor(list->joydev->devfs); + joydev_table[list->joydev->minor] = NULL; + kfree(list->joydev); + } + } + + kfree(list); + unlock_kernel(); + + return 0; +} + +static int joydev_open(struct inode *inode, struct file *file) +{ + struct joydev_list *list; + int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE; + + if (i > JOYDEV_MINORS || !joydev_table[i]) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) + return -ENOMEM; + memset(list, 0, sizeof(struct joydev_list)); + + list->joydev = joydev_table[i]; + list->next = joydev_table[i]->list; + joydev_table[i]->list = list; + + file->private_data = list; + + if (!list->joydev->open++) + if (list->joydev->exist) + input_open_device(&list->joydev->handle); + + return 0; +} + +static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + struct input_dev *input = joydev->handle.dev; + int retval = 0; + + if (count < sizeof(struct js_event)) + return -EINVAL; + + if (count == sizeof(struct JS_DATA_TYPE)) { + + struct JS_DATA_TYPE data; + + data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) | + ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0); + data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; + data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; + + if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) + return -EFAULT; + + list->startup = 0; + list->tail = list->head; + + return sizeof(struct JS_DATA_TYPE); + } + + if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) { + + add_wait_queue(&list->joydev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (list->head == list->tail) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->joydev->wait, &wait); + } + + if (retval) + return retval; + + while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { + + struct js_event event; + + event.time = jiffies * (1000/HZ); + + if (list->startup < joydev->nkey) { + event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; + event.number = list->startup; + event.value = !!test_bit(joydev->keypam[event.number], input->key); + } else { + event.type = JS_EVENT_AXIS | JS_EVENT_INIT; + event.number = list->startup - joydev->nkey; + event.value = joydev->abs[event.number]; + } + + if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) + return -EFAULT; + + list->startup++; + retval += sizeof(struct js_event); + } + + while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { + + if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) + return -EFAULT; + + list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); + retval += sizeof(struct js_event); + } + + return retval; +} + +/* No kernel lock - fine */ +static unsigned int joydev_poll(struct file *file, poll_table *wait) +{ + struct joydev_list *list = file->private_data; + poll_wait(file, &list->joydev->wait, wait); + if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) + return POLLIN | POLLRDNORM; + return 0; +} + +static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + struct input_dev *dev = joydev->handle.dev; + + + switch (cmd) { + + case JS_SET_CAL: + return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg, + sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + case JS_GET_CAL: + return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR, + sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + case JS_SET_TIMEOUT: + return get_user(joydev->glue.JS_TIMEOUT, (int *) arg); + case JS_GET_TIMEOUT: + return put_user(joydev->glue.JS_TIMEOUT, (int *) arg); + case JS_SET_TIMELIMIT: + return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg); + case JS_GET_TIMELIMIT: + return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg); + case JS_SET_ALL: + return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg, + sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + case JS_GET_ALL: + return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue, + sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + + case JSIOCGVERSION: + return put_user(JS_VERSION, (__u32 *) arg); + case JSIOCGAXES: + return put_user(joydev->nabs, (__u8 *) arg); + case JSIOCGBUTTONS: + return put_user(joydev->nkey, (__u8 *) arg); + case JSIOCSCORR: + return copy_from_user(joydev->corr, (struct js_corr *) arg, + sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + case JSIOCGCORR: + return copy_to_user((struct js_corr *) arg, joydev->corr, + sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + default: + if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { + int len; + if (!dev->name) return 0; + len = strlen(dev->name) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT; + return len; + } + } + return -EINVAL; +} + +static struct file_operations joydev_fops = { + owner: THIS_MODULE, + read: joydev_read, + write: joydev_write, + poll: joydev_poll, + open: joydev_open, + release: joydev_release, + ioctl: joydev_ioctl, + fasync: joydev_fasync, +}; + +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct joydev *joydev; + int i, j, minor; + + if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && + (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) && + (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) + || test_bit(BTN_1, dev->keybit)))) return NULL; + + for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); + if (joydev_table[minor]) { + printk(KERN_ERR "joydev: no more free joydev devices\n"); + return NULL; + } + + if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) + return NULL; + memset(joydev, 0, sizeof(struct joydev)); + + init_waitqueue_head(&joydev->wait); + + joydev->minor = minor; + joydev_table[minor] = joydev; + + joydev->handle.dev = dev; + joydev->handle.handler = handler; + joydev->handle.private = joydev; + + joydev->exist = 1; + + for (i = 0; i < ABS_MAX; i++) + if (test_bit(i, dev->absbit)) { + joydev->absmap[i] = joydev->nabs; + joydev->abspam[joydev->nabs] = i; + joydev->nabs++; + } + + for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++) + if (test_bit(i + BTN_MISC, dev->keybit)) { + joydev->keymap[i] = joydev->nkey; + joydev->keypam[joydev->nkey] = i + BTN_MISC; + joydev->nkey++; + } + + for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) + if (test_bit(i + BTN_MISC, dev->keybit)) { + joydev->keymap[i] = joydev->nkey; + joydev->keypam[joydev->nkey] = i + BTN_MISC; + joydev->nkey++; + } + + for (i = 0; i < joydev->nabs; i++) { + j = joydev->abspam[i]; + if (dev->absmax[j] == dev->absmin[j]) { + joydev->corr[i].type = JS_CORR_NONE; + continue; + } + joydev->corr[i].type = JS_CORR_BROKEN; + joydev->corr[i].prec = dev->absfuzz[j]; + joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; + joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; + joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + + joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); + } + + joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); + + printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); + + return &joydev->handle; +} + +static void joydev_disconnect(struct input_handle *handle) +{ + struct joydev *joydev = handle->private; + + joydev->exist = 0; + + if (joydev->open) { + input_close_device(handle); + } else { + input_unregister_minor(joydev->devfs); + joydev_table[joydev->minor] = NULL; + kfree(joydev); + } +} + +static struct input_handler joydev_handler = { + event: joydev_event, + connect: joydev_connect, + disconnect: joydev_disconnect, + fops: &joydev_fops, + minor: JOYDEV_MINOR_BASE, +}; + +static int __init joydev_init(void) +{ + input_register_handler(&joydev_handler); + return 0; +} + +static void __exit joydev_exit(void) +{ + input_unregister_handler(&joydev_handler); +} + +module_init(joydev_init); +module_exit(joydev_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/keybdev.c linux/drivers/input/keybdev.c --- v2.4.0-test6/linux/drivers/input/keybdev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/keybdev.c Thu Jul 27 18:36:54 2000 @@ -0,0 +1,200 @@ +/* + * $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Input driver to keyboard driver binding. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) + +static int x86_sysrq_alt = 0; + +static unsigned short x86_keycodes[256] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90, + 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339, + 367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349, + 360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355, + 103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361, + 291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114, + 118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269, + 271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307, + 308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330, + 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 }; + +static int emulate_raw(unsigned int keycode, int down) +{ + if (keycode > 255 || !x86_keycodes[keycode]) + return -1; + + if (keycode == KEY_PAUSE) { + handle_scancode(0xe1, 1); + handle_scancode(0x1d, down); + handle_scancode(0x45, down); + return 0; + } + + if (keycode == KEY_SYSRQ && x86_sysrq_alt) { + handle_scancode(0x54, down); + return 0; + } + + if (x86_keycodes[keycode] & 0x100) + handle_scancode(0xe0, 1); + + handle_scancode(x86_keycodes[keycode] & 0x7f, down); + + if (keycode == KEY_SYSRQ) { + handle_scancode(0xe0, 1); + handle_scancode(0x37, down); + } + + if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) + x86_sysrq_alt = down; + + return 0; +} + +#elif defined(CONFIG_ADB_KEYBOARD) + +static unsigned char mac_keycodes[128] = + { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, + 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, + 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 }; + +static int emulate_raw(unsigned int keycode, int down) +{ + if (keycode > 127 || !mac_keycodes[keycode]) + return -1; + + handle_scancode(mac_keycodes[keycode] & 0x7f, down); + + return 0; +} + +#endif + +static struct input_handler keybdev_handler; + +void keybdev_ledfunc(unsigned int led) +{ + struct input_handle *handle; + + for (handle = keybdev_handler.handle; handle; handle = handle->hnext) { + + input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01)); + input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02)); + input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04)); + + } +} + +void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) +{ + if (type != EV_KEY) return; + + if (emulate_raw(code, down)) + printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code); + + tasklet_schedule(&keyboard_tasklet); +} + +static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct input_handle *handle; + int i; + + if (!test_bit(EV_KEY, dev->evbit)) + return NULL; + + for (i = KEY_RESERVED; i < BTN_MISC; i++) + if (test_bit(i, dev->keybit)) break; + + if (i == BTN_MISC) + return NULL; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number); + + return handle; +} + +static void keybdev_disconnect(struct input_handle *handle) +{ + printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number); + input_close_device(handle); + kfree(handle); +} + +static struct input_handler keybdev_handler = { + event: keybdev_event, + connect: keybdev_connect, + disconnect: keybdev_disconnect, +}; + +static int __init keybdev_init(void) +{ + input_register_handler(&keybdev_handler); + kbd_ledfunc = keybdev_ledfunc; + return 0; +} + +static void __exit keybdev_exit(void) +{ + kbd_ledfunc = NULL; + input_unregister_handler(&keybdev_handler); +} + +module_init(keybdev_init); +module_exit(keybdev_exit); + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input driver to keyboard driver binding"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/input/mousedev.c linux/drivers/input/mousedev.c --- v2.4.0-test6/linux/drivers/input/mousedev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/input/mousedev.c Tue Aug 22 09:06:31 2000 @@ -0,0 +1,489 @@ +/* + * $Id: mousedev.c,v 1.15 2000/08/14 21:05:26 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Input driver to PS/2 or ImPS/2 device driver module. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#define MOUSEDEV_MINOR_BASE 32 +#define MOUSEDEV_MINORS 32 +#define MOUSEDEV_MIX 31 + +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X +#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 +#endif +#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y +#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 +#endif + +struct mousedev { + int exist; + int open; + int minor; + wait_queue_head_t wait; + struct mousedev_list *list; + struct input_handle handle; + devfs_handle_t devfs; +}; + +struct mousedev_list { + struct fasync_struct *fasync; + struct mousedev *mousedev; + struct mousedev_list *next; + int dx, dy, dz, oldx, oldy; + signed char ps2[6]; + unsigned long buttons; + unsigned char ready, buffer, bufsiz; + unsigned char mode, genseq, impseq; +}; + +#define MOUSEDEV_GENIUS_LEN 5 +#define MOUSEDEV_IMPS_LEN 6 + +static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 }; +static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; + +static struct input_handler mousedev_handler; + +static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; +static struct mousedev mousedev_mix; + +static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; + struct mousedev **mousedev = mousedevs; + struct mousedev_list *list; + int index, size; + + while (*mousedev) { + list = (*mousedev)->list; + while (list) { + switch (type) { + case EV_ABS: + if (test_bit(BTN_TRIGGER, handle->dev->keybit)) + break; + switch (code) { + case ABS_X: + size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; + list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size; + list->oldx += list->dx * size; + break; + case ABS_Y: + size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; + list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size; + list->oldy -= list->dy * size; + break; + } + break; + + case EV_REL: + switch (code) { + case REL_X: list->dx += value; break; + case REL_Y: list->dy -= value; break; + case REL_WHEEL: if (list->mode) list->dz -= value; break; + } + break; + + case EV_KEY: + switch (code) { + case BTN_0: + case BTN_TOUCH: + case BTN_LEFT: index = 0; break; + case BTN_4: + case BTN_EXTRA: if (list->mode > 1) { index = 4; break; } + case BTN_STYLUS: + case BTN_1: + case BTN_RIGHT: index = 1; break; + case BTN_3: + case BTN_SIDE: if (list->mode > 1) { index = 3; break; } + case BTN_2: + case BTN_STYLUS2: + case BTN_MIDDLE: index = 2; break; + default: return; + } + switch (value) { + case 0: clear_bit(index, &list->buttons); break; + case 1: set_bit(index, &list->buttons); break; + case 2: return; + } + break; + } + + list->ready = 1; + + kill_fasync(&list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&((*mousedev)->wait)); + mousedev++; + } +} + +static int mousedev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct mousedev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int mousedev_release(struct inode * inode, struct file * file) +{ + struct mousedev_list *list = file->private_data; + struct mousedev_list **listptr; + + lock_kernel(); + listptr = &list->mousedev->list; + mousedev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->mousedev->open) { + if (list->mousedev->minor == MOUSEDEV_MIX) { + struct input_handle *handle = mousedev_handler.handle; + while (handle) { + struct mousedev *mousedev = handle->private; + if (!mousedev->open) { + if (mousedev->exist) { + input_close_device(&mousedev->handle); + } else { + input_unregister_minor(mousedev->devfs); + mousedev_table[mousedev->minor] = NULL; + kfree(mousedev); + } + } + handle = handle->hnext; + } + } else { + if (!mousedev_mix.open) { + if (list->mousedev->exist) { + input_close_device(&list->mousedev->handle); + } else { + input_unregister_minor(list->mousedev->devfs); + mousedev_table[list->mousedev->minor] = NULL; + kfree(list->mousedev); + } + } + } + } + + kfree(list); + unlock_kernel(); + + return 0; +} + +static int mousedev_open(struct inode * inode, struct file * file) +{ + struct mousedev_list *list; + int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; + + if (i > MOUSEDEV_MINORS || !mousedev_table[i]) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) + return -ENOMEM; + memset(list, 0, sizeof(struct mousedev_list)); + + list->mousedev = mousedev_table[i]; + list->next = mousedev_table[i]->list; + mousedev_table[i]->list = list; + file->private_data = list; + + if (!list->mousedev->open++) { + if (list->mousedev->minor == MOUSEDEV_MIX) { + struct input_handle *handle = mousedev_handler.handle; + while (handle) { + struct mousedev *mousedev = handle->private; + if (!mousedev->open) + if (mousedev->exist) + input_open_device(handle); + handle = handle->hnext; + } + } else { + if (!mousedev_mix.open) + if (list->mousedev->exist) + input_open_device(&list->mousedev->handle); + } + } + + return 0; +} + +static void mousedev_packet(struct mousedev_list *list, unsigned char off) +{ + list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); + list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); + list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); + list->dx -= list->ps2[off + 1]; + list->dy -= list->ps2[off + 2]; + list->bufsiz = off + 3; + + if (list->mode > 1) + list->ps2[off] |= ((list->buttons & 0x18) << 3); + + if (list->mode) { + list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); + list->bufsiz++; + list->dz -= list->ps2[off + 3]; + } + if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; + list->buffer = list->bufsiz; +} + + +static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + struct mousedev_list *list = file->private_data; + unsigned char c; + int i; + + for (i = 0; i < count; i++) { + + c = buffer[i]; + + if (c == mousedev_genius_seq[list->genseq]) { + if (++list->genseq == MOUSEDEV_GENIUS_LEN) { + list->genseq = 0; + list->ready = 1; + list->mode = 2; + } + } else list->genseq = 0; + + if (c == mousedev_imps_seq[list->impseq]) { + if (++list->impseq == MOUSEDEV_IMPS_LEN) { + list->impseq = 0; + list->ready = 1; + list->mode = 1; + } + } else list->impseq = 0; + + list->ps2[0] = 0xfa; + list->bufsiz = 1; + + switch (c) { + + case 0xeb: /* Poll */ + mousedev_packet(list, 1); + break; + + case 0xf2: /* Get ID */ + list->ps2[1] = (list->mode == 1) ? 3 : 0; + list->bufsiz = 2; + break; + + case 0xe9: /* Get info */ + if (list->mode == 2) { + list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55; + } else { + list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; + } + list->bufsiz = 4; + break; + } + + list->buffer = list->bufsiz; + } + + kill_fasync(&list->fasync, SIGIO, POLL_IN); + + wake_up_interruptible(&list->mousedev->wait); + + return count; +} + +static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct mousedev_list *list = file->private_data; + int retval = 0; + + if (!list->ready && !list->buffer) { + + add_wait_queue(&list->mousedev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!list->ready) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->mousedev->wait, &wait); + } + + if (retval) + return retval; + + if (!list->buffer) + mousedev_packet(list, 0); + + if (count > list->buffer) + count = list->buffer; + + if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count)) + return -EFAULT; + + list->buffer -= count; + + return count; +} + +/* No kernel lock - fine */ +static unsigned int mousedev_poll(struct file *file, poll_table *wait) +{ + struct mousedev_list *list = file->private_data; + poll_wait(file, &list->mousedev->wait, wait); + if (list->ready || list->buffer) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations mousedev_fops = { + owner: THIS_MODULE, + read: mousedev_read, + write: mousedev_write, + poll: mousedev_poll, + open: mousedev_open, + release: mousedev_release, + fasync: mousedev_fasync, +}; + +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct mousedev *mousedev; + int minor = 0; + + if (!test_bit(EV_KEY, dev->evbit) || + (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit))) + return NULL; + + if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) && + (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit))) + return NULL; + + for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); + if (mousedev_table[minor]) { + printk(KERN_ERR "mousedev: no more free mousedev devices\n"); + return NULL; + } + + if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) + return NULL; + memset(mousedev, 0, sizeof(struct mousedev)); + init_waitqueue_head(&mousedev->wait); + + mousedev->exist = 1; + mousedev->minor = minor; + mousedev_table[minor] = mousedev; + + mousedev->handle.dev = dev; + mousedev->handle.handler = handler; + mousedev->handle.private = mousedev; + + mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE); + + if (mousedev_mix.open) + input_open_device(&mousedev->handle); + + printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); + + return &mousedev->handle; +} + +static void mousedev_disconnect(struct input_handle *handle) +{ + struct mousedev *mousedev = handle->private; + + mousedev->exist = 0; + + if (mousedev->open) { + input_close_device(handle); + } else { + if (mousedev_mix.open) + input_close_device(handle); + input_unregister_minor(mousedev->devfs); + mousedev_table[mousedev->minor] = NULL; + kfree(mousedev); + } +} + +static struct input_handler mousedev_handler = { + event: mousedev_event, + connect: mousedev_connect, + disconnect: mousedev_disconnect, + fops: &mousedev_fops, + minor: MOUSEDEV_MINOR_BASE, +}; + +static int __init mousedev_init(void) +{ + input_register_handler(&mousedev_handler); + + memset(&mousedev_mix, 0, sizeof(struct mousedev)); + init_waitqueue_head(&mousedev_mix.wait); + mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; + mousedev_mix.exist = 1; + mousedev_mix.minor = MOUSEDEV_MIX; + mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE); + + printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); + + return 0; +} + +static void __exit mousedev_exit(void) +{ + input_unregister_minor(mousedev_mix.devfs); + input_unregister_handler(&mousedev_handler); +} + +module_init(mousedev_init); +module_exit(mousedev_exit); + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.4.0-test6/linux/drivers/isdn/Config.in Mon Mar 27 08:08:24 2000 +++ linux/drivers/isdn/Config.in Mon Aug 21 07:49:02 2000 @@ -37,6 +37,7 @@ bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD fi bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 + bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1 comment ' HiSax supported cards' bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0 bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 @@ -55,6 +56,7 @@ bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER bool ' MIC card' CONFIG_HISAX_MIC bool ' NETjet card' CONFIG_HISAX_NETJET + bool ' NETspider U card' CONFIG_HISAX_NETJET_U bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR @@ -83,7 +85,15 @@ fi dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then - bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + if [ "$CONFIG_ISDN_DRV_EICON_STANDALONE" != "y" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI + fi + bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + fi + if [ "$CONFIG_PCI" = "y" ]; then + bool ' build eicon driver type standalone' CONFIG_ISDN_DRV_EICON_STANDALONE + fi fi dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then @@ -109,8 +119,13 @@ bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON fi if [ "$CONFIG_PROC_FS" != "n" ]; then -if [ "$CONFIG_MODULES" != "n" ]; then - bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN + if [ "$CONFIG_MODULES" != "n" ]; then + bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN + fi fi +if [ "$CONFIG_HYSDN" != "n" ]; then + if [ "$CONFIG_ISDN_CAPI" != "n" ]; then + bool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI + fi fi endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/b1.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/isdn/avmb1/b1.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,17 @@ /* - * $Id: b1.c,v 1.14 2000/06/19 16:51:53 keil Exp $ + * $Id: b1.c,v 1.16 2000/08/04 15:36:31 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.16 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.15 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.14 2000/06/19 16:51:53 keil * don't free skb in irq context * @@ -95,7 +101,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.14 $"; +static char *revision = "$Revision: 1.16 $"; /* ------------------------------------------------------------- */ @@ -597,25 +603,29 @@ ctrl->ready(ctrl); break; - case RECEIVE_TASK_READY: + case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; - case RECEIVE_DEBUGMSG: + case RECEIVE_DEBUGMSG: MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/b1dma.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.6 2000/06/29 13:59:06 calle Exp $ + * $Id: b1dma.c,v 1.7 2000/08/04 12:20:08 calle Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.7 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.6 2000/06/29 13:59:06 calle * Bugfix: reinit txdma without interrupt will confuse some AMCC chips. * @@ -44,7 +47,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -561,22 +564,26 @@ case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/b1pci.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/isdn/avmb1/b1pci.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,14 @@ /* - * $Id: b1pci.c,v 1.26 2000/07/20 10:21:21 calle Exp $ + * $Id: b1pci.c,v 1.27 2000/08/08 09:24:19 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.27 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * * Revision 1.26 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -91,13 +94,12 @@ #include #include #include -#include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.26 $"; +static char *revision = "$Revision: 1.27 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/c4.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/isdn/avmb1/c4.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,20 @@ /* - * $Id: c4.c,v 1.13 2000/07/20 10:21:21 calle Exp $ + * $Id: c4.c,v 1.16 2000/08/20 07:30:13 keil Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.16 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.15 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * + * Revision 1.14 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.13 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -63,15 +72,15 @@ #include #include #include -#include #include #include +#include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13 $"; +static char *revision = "$Revision: 1.16 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -682,22 +691,26 @@ case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/capi.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/isdn/avmb1/capi.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.38 2000/07/24 08:49:09 calle Exp $ + * $Id: capi.c,v 1.39 2000/07/24 13:42:50 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.39 2000/07/24 13:42:50 calle + * - lock_kernel/unlock_kernel for _release functions. (from 2.4) + * * Revision 1.38 2000/07/24 08:49:09 calle * - Bugfix: capiminor_del_all_ack completely wrong :-( * @@ -216,7 +219,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include -static char *revision = "$Revision: 1.38 $"; +static char *revision = "$Revision: 1.39 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -325,11 +328,11 @@ static struct capiminor *minors = 0; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -static kmem_cache_t *capidev_cachep = 0; -static kmem_cache_t *capincci_cachep = 0; +static kmem_cache_t *capidev_cachep = 0; +static kmem_cache_t *capincci_cachep = 0; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static kmem_cache_t *capiminor_cachep = 0; -static kmem_cache_t *capidh_cachep = 0; +static kmem_cache_t *capiminor_cachep = 0; +static kmem_cache_t *capidh_cachep = 0; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1239,7 +1242,7 @@ capincci_free(cdev, 0xffffffff); capidev_free(cdev); file->private_data = NULL; - + MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); @@ -1251,13 +1254,13 @@ static struct file_operations capi_fops = { owner: THIS_MODULE, - llseek: capi_llseek, - read: capi_read, - write: capi_write, - poll: capi_poll, - ioctl: capi_ioctl, - open: capi_open, - release: capi_release, + llseek: capi_llseek, + read: capi_read, + write: capi_write, + poll: capi_poll, + ioctl: capi_ioctl, + open: capi_open, + release: capi_release, }; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1980,9 +1983,9 @@ static int alloc_init(void) { - capidev_cachep = kmem_cache_create("capi20_dev", + capidev_cachep = kmem_cache_create("capi20_dev", sizeof(struct capidev), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidev_cachep) { @@ -1990,9 +1993,9 @@ return -ENOMEM; } - capincci_cachep = kmem_cache_create("capi20_ncci", + capincci_cachep = kmem_cache_create("capi20_ncci", sizeof(struct capincci), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capincci_cachep) { @@ -2000,18 +2003,18 @@ return -ENOMEM; } #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - capidh_cachep = kmem_cache_create("capi20_dh", + capidh_cachep = kmem_cache_create("capi20_dh", sizeof(struct datahandle_queue), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidh_cachep) { alloc_exit(); return -ENOMEM; } - capiminor_cachep = kmem_cache_create("capi20_minor", + capiminor_cachep = kmem_cache_create("capi20_minor", sizeof(struct capiminor), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capiminor_cachep) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/capidrv.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/isdn/avmb1/capidrv.c Mon Aug 21 07:49:02 2000 @@ -2183,50 +2183,6 @@ send_message(card, &cmdcmsg); } -static void disable_dchannel_trace(capidrv_contr *card) -{ - __u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - __u16 contr = card->contrnr; - __u16 errcode; - __u16 avmversion[3]; - - errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; - } - if (strstr(manufacturer, "AVM") == 0) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; - } - errcode = (*capifuncs->capi_get_version)(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; - } - avmversion[0] = (version.majormanuversion >> 4) & 0x0f; - avmversion[1] = (version.majormanuversion << 4) & 0xf0; - avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; - avmversion[2] |= version.minormanuversion & 0x0f; - - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { - printk(KERN_INFO "%s: D2 trace disabled\n", card->name); - } else { - printk(KERN_INFO "%s: D3 trace disabled\n", card->name); - } - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\000\000\000\000"); - send_message(card, &cmdcmsg); -} static void send_listen(capidrv_contr *card) { @@ -2288,15 +2244,15 @@ card->interface.writecmd = 0; card->interface.readstat = if_readstat; card->interface.features = ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_X75UI | ISDN_FEATURE_L2_X75BUI; if (profp->support1 & (1<<2)) card->interface.features |= ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038; if (profp->support1 & (1<<8)) card->interface.features |= ISDN_FEATURE_L2_MODEM; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/capifs.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/isdn/avmb1/capifs.c Tue Aug 22 09:06:31 2000 @@ -1,11 +1,20 @@ /* - * $Id: capifs.c,v 1.6 2000/04/03 13:29:25 calle Exp $ + * $Id: capifs.c,v 1.9 2000/08/20 07:30:13 keil Exp $ * * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) * * Heavily based on devpts filesystem from H. Peter Anvin * * $Log: capifs.c,v $ + * Revision 1.9 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.8 2000/07/20 10:23:13 calle + * Include isdn_compat.h for people that don't use -p option of std2kern. + * + * Revision 1.7 2000/06/18 16:09:54 keil + * more changes for 2.4 + * * Revision 1.6 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... @@ -60,7 +69,7 @@ MODULE_AUTHOR("Carsten Paeth "); -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.9 $"; struct capifs_ncci { struct inode *inode; @@ -130,12 +139,12 @@ switch(nr) { case 0: - if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ @@ -147,7 +156,7 @@ char *p = numbuf; if (np->type) *p++ = np->type; sprintf(p, "%u", np->num); - if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_UNKNOWN) < 0 ) return 0; } filp->f_pos = ++nr; @@ -228,9 +237,9 @@ for ( i = 0 ; i < sbi->max_ncci ; i++ ) { if ( (inode = sbi->nccis[i].inode) ) { - if ( atomic_read(&inode->i_count) != 1 ) + if (atomic_read(&inode->i_count) != 1 ) printk("capifs_put_super: badness: entry %d count %d\n", - i, atomic_read(&inode->i_count)); + i, (unsigned)atomic_read(&inode->i_count)); inode->i_nlink--; iput(inode); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/t1isa.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/avmb1/t1isa.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,17 @@ /* - * $Id: t1isa.c,v 1.11 2000/04/03 13:29:25 calle Exp $ + * $Id: t1isa.c,v 1.13 2000/08/04 15:36:31 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.13 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.12 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.11 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... @@ -85,7 +91,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.13 $"; /* ------------------------------------------------------------- */ @@ -282,24 +288,29 @@ case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; + case 0xff: printk(KERN_ERR "%s: card reseted ?\n", card->name); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- v2.4.0-test6/linux/drivers/isdn/avmb1/t1pci.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/isdn/avmb1/t1pci.c Mon Aug 21 07:49:02 2000 @@ -1,11 +1,14 @@ /* - * $Id: t1pci.c,v 1.10 2000/07/20 10:21:21 calle Exp $ + * $Id: t1pci.c,v 1.11 2000/08/08 09:24:19 calle Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.11 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * * Revision 1.10 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -60,13 +63,12 @@ #include #include #include -#include #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.11 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.4.0-test6/linux/drivers/isdn/divert/divert_procfs.c Fri Jul 14 12:12:09 2000 +++ linux/drivers/isdn/divert/divert_procfs.c Mon Aug 21 07:49:02 2000 @@ -1,5 +1,5 @@ /* - * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $ + * $Id: divert_procfs.c,v 1.9 2000/08/20 07:40:14 keil Exp $ * * Filesystem handling for the diversion supplementary services. * @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_procfs.c,v $ + * Revision 1.9 2000/08/20 07:40:14 keil + * changes from 2.4 + * * Revision 1.8 2000/03/03 16:37:11 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c --- v2.4.0-test6/linux/drivers/isdn/eicon/Divas_mod.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/Divas_mod.c Mon Aug 14 13:09:07 2000 @@ -0,0 +1,172 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.15 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#include +#include +#undef N_DATA + +#include + +#include +#include +#include +#include +#include + +#include "adapter.h" +#include "uxio.h" + +#ifdef MODULE +#include "idi.h" +void EtdM_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#define Divas_init init_module +#endif + +extern char *file_check(void); + +int DivasCardsDiscover(void); + +int +Divas_init(void) +{ + printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); + + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.12 (%s)\n",file_check()); + + +#if !defined(CONFIG_PCI) + printk(KERN_WARNING "CONFIG_PCI is not defined!\n"); + return -ENODEV; +#endif + + if (pci_present()) + { + if (DivasCardsDiscover() < 0) + { + printk(KERN_WARNING "Divas: Not loaded\n"); + return -ENODEV; + } + } + else + { + printk(KERN_WARNING "Divas: No PCI bus present\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void +cleanup_module(void) +{ + card_t *pCard; + word wCardIndex; + extern int Divas_major; + + printk(KERN_DEBUG "DIVA Server Driver - unloading\n"); + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + pCard++; + } + + unregister_chrdev(Divas_major, "Divas"); +} + +void mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +#else +Divas_setup(char *str, int *ints) +{ +} +#endif + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/Makefile linux/drivers/isdn/eicon/Makefile --- v2.4.0-test6/linux/drivers/isdn/eicon/Makefile Sun May 23 10:03:41 1999 +++ linux/drivers/isdn/eicon/Makefile Sun Aug 13 10:05:32 2000 @@ -1,8 +1,37 @@ L_OBJS := M_OBJS := -O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o +LX_OBJS := +MX_OBJS := +O_OBJS := +OX_OBJS := +L_TARGET := +O_TARGET := + +ifeq ($(CONFIG_ISDN_DRV_EICON_STANDALONE),y) + + ifeq ($(CONFIG_PCI),y) + O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o + O_OBJS += lincfg.o linchr.o linsys.o linio.o + O_OBJS += fcheck.o + OX_OBJS += Divas_mod.o + endif + +else + + OX_OBJS += eicon_mod.o + O_OBJS := eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o + O_OBJS += fcheck.o + ifeq ($(CONFIG_PCI),y) + ifeq ($(CONFIG_ISDN_DRV_EICON_PCI),y) + O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o + O_OBJS += lincfg.o linchr.o linsys.o linio.o + endif + endif + +endif O_TARGET := + ifeq ($(CONFIG_ISDN_DRV_EICON),y) O_TARGET += eicon.o else @@ -10,4 +39,14 @@ M_OBJS = eicon.o endif + include $(TOPDIR)/Rules.make + +MD5FILES += common.c idi.c bri.c pri.c log.c xlog.c kprintf.c fpga.c \ + fourbri.c fcheck.c + +FCHECK = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) + +fcheck.o: $(MD5FILES) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D FILECHECK=$(FCHECK) -c -o fcheck.o fcheck.c + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/adapter.h linux/drivers/isdn/eicon/adapter.h --- v2.4.0-test6/linux/drivers/isdn/eicon/adapter.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/adapter.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,265 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.7 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Main internal include file for Diva Server driver */ + +#if !defined(ADAPTER_H) +#define ADAPTER_H + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" + +#define XMOREC 0x1f +#define XMOREF 0x20 +#define XBUSY 0x40 +#define RMORE 0x80 + + /* structure for all information we have to keep on a per */ + /* adapater basis */ + +typedef struct adapter_s ADAPTER; + +struct adapter_s { + void * io; + + byte IdTable[256]; + byte ReadyInt; + + byte (* ram_in)(ADAPTER * a, void * adr); + word (* ram_inw)(ADAPTER * a, void * adr); + void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length); + void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e); + + void (* ram_out)(ADAPTER * a, void * adr, byte data); + void (* ram_outw)(ADAPTER * a, void * adr, word data); + void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length); + + void (* ram_inc)(ADAPTER * a, void * adr); +}; + +typedef struct card card_t; + +typedef int card_load_fn_t(card_t *card, dia_load_t *load); +typedef int card_config_fn_t(card_t *card, dia_config_t *config); +typedef int card_start_fn_t(card_t *card, byte *channels); +typedef int card_reset_fn_t(card_t *card); +typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block); + +#define MAX_PENTITIES 256 /* Number of entities primary adapter */ +#define MAX_ENTITIES 16 /* Number of entities standard adapter */ + +typedef struct e_info_s E_INFO; + +struct e_info_s +{ + ENTITY *e; /* entity pointer */ + byte next; /* chaining index */ + word assign_ref; /* assign reference */ +}; + +/* DIVA card info (details hidden from user) */ + +typedef struct ux_diva_card_s ux_diva_card_t; + +/* card info */ + +struct card +{ + ADAPTER a; /* per-adapter information */ + dia_card_t cfg; /* card configuration */ + int state; /* State of the adapter */ + dword serial_no; /* serial number */ + int test_int_pend; /* set for interrupt testing */ + ux_diva_card_t *hw; /* O/S-specific handle */ + card_reset_fn_t *card_reset; /* call this to reset card */ + card_load_fn_t *card_load; /* call this to load card */ + card_config_fn_t *card_config; /* call this to config card */ + card_start_fn_t *card_start; /* call this to start card */ + card_mem_get_fn_t *card_mem_get; /* call this to get card memory */ + E_INFO *e_tbl; /* table of ENTITY pointers */ + byte e_head; /* list of active ENTITIES */ + byte e_tail; /* list of active ENTITIES */ + int e_count; /* # of active ENTITIES */ + int e_max; /* total # of ENTITIES */ + byte assign; /* assign queue entry */ + PBUFFER RBuffer; /* Copy of receive lookahead buffer */ + int log_types; /* bit-mask of active logs */ + word xlog_offset; /* offset to XLOG buffer on card */ + void (*out)(ADAPTER *a); + byte (*dpc)(ADAPTER * a); + byte (*test_int)(ADAPTER * a); + void (*clear_int)(ADAPTER * a); + void (*reset_int)(card_t *c); + int is_live; + + int (*card_isr)(card_t *card); + + int int_pend; /* interrupt pending */ + long interrupt_reentered; + long dpc_reentered; + int set_xlog_request; + +} ; + +/* card information */ + +#define MAX_CARDS 20 /* max number of cards on a system */ + +extern +card_t DivasCards[]; + +extern +int DivasCardNext; + +extern +dia_config_t DivasCardConfigs[]; + +extern +byte DivasFlavourConfig[]; + +/*------------------------------------------------------------------*/ +/* public functions of IDI common code */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a); +byte DivasDpc(ADAPTER * a); +byte DivasTestInt(ADAPTER * a); +void DivasClearInt(ADAPTER * a); + +/*------------------------------------------------------------------*/ +/* public functions of configuration platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasConfigGet(dia_card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of LOG related code */ +/*------------------------------------------------------------------*/ + +void DivasXlogReq(int card_num); +int DivasXlogRetrieve(card_t *card); +void DivasLog(dia_log_t *log); +void DivasLogIdi(card_t *card, ENTITY *e, int request); + +/*------------------------------------------------------------------*/ +/* public functions to initialise cards for each type supported */ +/*------------------------------------------------------------------*/ + +int DivasPriInit(card_t *card, dia_card_t *cfg); + +int DivasBriInit(card_t *card, dia_card_t *cfg); +int Divas4BriInit(card_t *card, dia_card_t *cfg); +void DivasBriPatch(card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of log common code */ +/*------------------------------------------------------------------*/ + +extern char *DivasLogFifoRead(void); +extern void DivasLogFifoWrite(char *entry, int length); +extern int DivasLogFifoEmpty(void); +extern int DivasLogFifoFull(void); +extern void DivasLogAdd(void *buffer, int length); + +/*------------------------------------------------------------------*/ +/* public functions of misc. platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasDpcSchedule(void); +void DivasDoDpc(void *); +void DivasDoRequestDpc(void *pData); +int DivasScheduleRequestDpc(void); + +/* table of IDI request functions */ + +extern +IDI_CALL DivasIdiRequest[]; + +/* + * intialisation entry point + */ + +int DivasInit(void); + +/* + * Get information on the number and type of cards present + */ + +extern +int DivasCardsDiscover(void); + +/* + * initialise a new card + */ + +int DivasCardNew(dia_card_t *card); + +/* + * configure specified card + */ + +int DivasCardConfig(dia_config_t *config); + +/* + * load specified binary code onto card + */ + +int DivasCardLoad(dia_load_t *load); + +/* + * start specified card running + */ + +int DivasCardStart(int card_id); + +/* + * ISR for card + * Returns 0 if specified card was interrupting + */ + +int DivasIsr(void *arg); + +/* + * Get number of active cards + */ + +int DivasGetNum(void); + +/* + * Get list of active cards + */ + +int DivasGetList(dia_card_list_t *card_list); + +/* definitions common to several card types */ + +#define DIVAS_SHARED_OFFSET (0x1000) + +#endif /* ADAPTER_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c --- v2.4.0-test6/linux/drivers/isdn/eicon/bri.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/bri.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,717 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.8 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + +#include + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_BADDR0 0x10 +#define PCI_BADDR1 0x14 +#define PCI_BADDR2 0x18 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */ + +#define PROTCAP_TELINDUS 0x1 +#define PROTCAP_V90D 0x8 + +word GetProtFeatureValue(char *sw_id); +byte io_in(ADAPTER *a, void *adr); +word io_inw(ADAPTER *a, void *adr); +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void io_out(ADAPTER *a, void *adr, byte data); +void io_outw(ADAPTER *a, void *adr, word data); +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_inc(ADAPTER *a, void *adr); + +static int diva_server_bri_test_int(card_t *card); + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +#define REG_DATA 0x00 +#define REG_ADDRLO 0x04 +#define REG_ADDRHI 0x0C +#define REG_IOCTRL 0x10 + +#define M_PCI_RESET 0x10 + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg); +int bri_ISR (card_t* card); + +static +int diva_server_bri_reset(card_t *card) +{ + byte *DivasIOBase; + word i; + dword dwWait; + + UxCardLog(0); + + DPRINTF(("divas: resetting BRI adapter")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0); + + for (i=0; i < 50000; i++) + ; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000); + + for (i=0; i<0x8000; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + } + + for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++) + ; + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +void diva_server_bri_reset_int(card_t *card) +{ + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +int diva_server_bri_start(card_t *card, byte *channels) +{ + byte *DivasIOBase, *PLXIOBase; + word wSig = 0; + word i; + dword dwSerialNum; + byte bPLX9060 = FALSE; + + DPRINTF(("divas: starting Diva Server BRI card")); + + card->is_live = FALSE; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + /* wait for signature to indicate card has started */ + for (i = 0; i < 300; i++) + { + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + if (wSig == DIVAS_SIGNATURE) + { + DPRINTF(("divas: card started after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if (wSig != DIVAS_SIGNATURE) + { + DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig)); + UxCardMemDetach(card->hw, DivasIOBase); + return -1; + } + + card->is_live = TRUE; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6); + *channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + UxCardMemDetach(card->hw, DivasIOBase); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x22)); + DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum)); + } + else + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x26)); + DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum)); + } + + UxCardMemDetach(card->hw, PLXIOBase); + + card->serial_no = dwSerialNum; + + diva_server_bri_test_int(card); + + return 0; +} + +static +int diva_server_bri_load(card_t *card, dia_load_t *load) +{ + byte *DivasIOBase; + dword r3000_base; + dword dwAddr, dwLength, i; + word wTest, aWord; + + DPRINTF(("divas: loading Diva Server BRI card")); + + switch (load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: loading RISC %s", &load->code[0x80])); + + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + DPRINTF(("divas: features 0x%x", card->hw->features)); + if (card->hw->features == 0xFFFF) + { + DPRINTF(("divas: invalid feature string failed load\n")); + return -1; + } + + r3000_base = 0; + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code \"%s\"", load->code)); + + if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS))) + { + DPRINTF(("divas: only Telindus style binaries supported")); + return -1; + } + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: V.90 DSP binary")); + r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + else + { + DPRINTF(("divas: non-V.90 DSP binary")); + r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + DPRINTF(("divas: loading at 0x%x", r3000_base)); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000 + sizeof(dword); + } + else + { + r3000_base = 0xBF7A0000 + sizeof(dword); + } + + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000; + } + else + { + r3000_base = 0xBF7A0000; + } + break; + + default: + DPRINTF(("divas: unknown code type %d", load->code_type)); + return -1; + break; + } + + DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + DPRINTF(("divas: Attached to 0x%04X", DivasIOBase)); + + dwLength = load->length; + + for (i=0; i < dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]); + } + + DPRINTF(("divas: Verifying")); + + for (i=0; ihw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + + aWord = load->code[i]; + + if (wTest != aWord) + { + DPRINTF(("divas: load verify failed on byte %d", i)); + DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord)); + + UxCardMemDetach(card->hw, DivasIOBase); + + return -1; + } + } + + DPRINTF(("divas: Loaded and verified. Detaching from adapter")); + + UxCardMemDetach(card->hw, DivasIOBase); + + UxCardLog(0); + + return 0; +} + +static +int diva_server_bri_config(card_t *card, dia_config_t *config) +{ + byte *DivasIOBase, i; + + DPRINTF(("divas: configuring Diva Server BRI card")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4); + } + else + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + } + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21); + + for (i=0; i<32; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]); + + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +void DivasBriPatch(card_t *card) +{ + dword PLXIOBase = 0; + dword DivasIOBase = 0; + + PLXIOBase = card->cfg.reset_base; + DivasIOBase = card->cfg.io_base; + + if(card->hw == NULL) + { + DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null")); + return; + } + + if (PLXIOBase == 0) + { + DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may")); + DPRINTF(("Divas: not function properly. If you do encounter problems,")); + DPRINTF(("Divas: ensure that your machine is using the latest BIOS.")); + return; + } + + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + + if (PLXIOBase & 0x80) + { + dword dwSize, dwSerialNum, dwCmd; + boolean_t bPLX9060; + word wSerHi, wSerLo; + + DPRINTF(("Divas: Patch required")); + dwCmd = 0; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + PLXIOBase &= ~0x80; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase); + + dwSize = 0xFFFFFFFF; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize); + UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize); + + dwSize = (~ (dwSize & ~7)) + 1; + + DivasIOBase = PLXIOBase + dwSize; + + card->cfg.reset_base = PLXIOBase; + card->cfg.io_base = DivasIOBase; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base); + UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base); + + dwCmd = 5; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + } + else + { + word wSerHi, wSerLo; + boolean_t bPLX9060; + dword dwSerialNum; + + DPRINTF(("divas: No patch required")); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + } + DPRINTF(("Divas: After patching:")); + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + +} + +#define TEST_INT_DIVAS_BRI 0x12 +static +int diva_server_bri_test_int(card_t *card) +{ + boolean_t bPLX9060 = FALSE; + byte *PLXIOBase = NULL, *DivasIOBase = NULL; + + DPRINTF(("divas: test interrupt for Diva Server BRI card")); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { /* PLX9060 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09); + } + else + { /* PLX9050 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41); + } + + card->test_int_pend = TEST_INT_DIVAS_BRI; + + UxCardMemDetach(card->hw, PLXIOBase); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89); + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block) +{ + dword user_addr = mem_block->addr; + word length = 0; + dword addr; + word i; + byte *DivasIOBase; + + DPRINTF(("divas: Retrieving memory from 0x%x", user_addr)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + addr = user_addr; + + for (i=0; i < (16 * 8); i++) + { + addr = user_addr + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr); + + mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + length++; + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return length; +} + +int DivasBriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server BRI card")); + + if (DivasBRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_bri_reset; + card->card_start = diva_server_bri_start; + card->card_load = diva_server_bri_load; + card->card_config = diva_server_bri_config; + card->reset_int = diva_server_bri_reset_int; + card->card_mem_get = diva_server_bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = bri_ISR; + + card->a.ram_out = io_out; + card->a.ram_outw = io_outw; + card->a.ram_out_buffer = io_out_buffer; + card->a.ram_inc = io_inc; + + card->a.ram_in = io_in; + card->a.ram_inw = io_inw; + card->a.ram_in_buffer = io_in_buffer; + card->a.ram_look_ahead = io_look_ahead; + + return 0; +} + +word GetProtFeatureValue(char *sw_id) +{ + word features = 0; + + while ((*sw_id) && (sw_id[0] != '[')) + sw_id++; + + if (sw_id == NULL) + { + DPRINTF(("divas: no feature string present")); + features = -1; + } + else + { + byte i, shifter; + + sw_id += 3; + + for (i=0, shifter=12; i<4; i++, shifter-=4) + { + if ((sw_id[i] >= '0') && (sw_id[i] <= '9')) + { + features |= (sw_id[i] - '0') << shifter; + } + else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f')) + { + features |= (sw_id[i] - 'a' + 10) << shifter; + } + else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F')) + { + features |= (sw_id[i] - 'A' + 10) << shifter; + } + else + { + DPRINTF(("divas: invalid feature string")); + return -1; + } + } + } + + return features; +} + + +int bri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +} + + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c --- v2.4.0-test6/linux/drivers/isdn/eicon/common.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/common.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,896 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.15 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" + +#include "uxio.h" +#include + +#define MAX_ADDR_LEN + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_INTERRUPT 0x3C + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_SIGNATURE 0x4447 + +#define MP_PROTOCOL_ADDR 0xA0011000 + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +int DivasCardNext; +card_t DivasCards[MAX_CARDS]; + +dia_config_t *DivasConfig(card_t *, dia_config_t *); + +static +DESCRIPTOR DIDD_Table[16]; +static +int DIDD_Length = 0; + +void EtdM_DIDD_Read( DESCRIPTOR *table, int *tablelength ) +{ + int table_size = sizeof(DIDD_Table); + + bcopy((caddr_t)DIDD_Table, (caddr_t)table, table_size); + + *tablelength = DIDD_Length; + + return; +} + +static +void EtdM_DIDD_Write(DESCRIPTOR *table, int tablelength) +{ + int table_size = sizeof(DIDD_Table); + + bcopy((caddr_t)table, (caddr_t)DIDD_Table, table_size); + + DIDD_Length = tablelength; + + return; +} + +static +void init_idi_tab(void) +{ + int length = 0; + + DESCRIPTOR d[16]; + + EtdM_DIDD_Read(d, &length); + + d[length].type = IDI_DIMAINT; /* identify the DIMAINT entry */ + d[length].channels = 0; /* zero channels associated with dimaint*/ + d[length].features = 0; /* no features associated with dimaint */ + d[length].request = (IDI_CALL) DivasPrintf; + length++; + + EtdM_DIDD_Write(d, length); + + return; +} + +/* + * I/O routines for memory mapped cards + */ + +byte mem_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + byte value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemIn(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +word mem_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + word value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemInBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (dword) &RBuffer->length; + card->RBuffer.length = UxCardMemInW(card->hw, m); + + m = b; + m += (dword) &RBuffer->P; + UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOut(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutW(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + value++; + UxCardMemOutW(card->hw, m, value); + + UxCardMemDetach(card->hw, b); + + return; +} + +/* + * I/O routines for I/O mapped cards + */ + +byte io_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + byte value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoIn(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +word io_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + word value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer); + + UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length); + + UxCardMemDetach(card->hw, DivasIOBase); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + return; +} + +void io_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOut(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutW(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + byte *DivasIOBase; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + value++; + + UxCardIoOutW(card->hw, DivasIOBase, adr, value); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +void test_int(card_t *card) + +{ + byte *shared, *DivasIOBase; + + switch (card->test_int_pend) + { + case TEST_INT_DIVAS: + DPRINTF(("divas: test interrupt pending")); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + if (UxCardMemIn(card->hw, &shared[0x3FE])) + { + UxCardMemOut(card->hw, + &(((struct pr_ram *)shared)->RcOutput), 0); + UxCardMemDetach(card->hw, shared); + (*card->reset_int)(card); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + DPRINTF(("divas: test interrupt cleared")); + } + + UxCardMemDetach(card->hw, shared); + + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_BRI: + DPRINTF(("divas: BRI test interrupt pending")); + (*card->reset_int)(card); + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0); + UxCardMemDetach(card->hw, DivasIOBase); + DPRINTF(("divas: test interrupt cleared")); + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_Q: + DPRINTF(("divas: 4BRI test interrupt pending")); + (*card->reset_int)(card); + card->test_int_pend = 0; + break; + + default: + DPRINTF(("divas: unknown test interrupt pending")); + return; + } + return; +} + +void card_isr (void *dev_id) +{ + card_t *card = (card_t *) dev_id; + ADAPTER *a = &card->a; + int ipl; + + if (card->test_int_pend) + { + ipl = UxCardLock(card->hw); + card->int_pend=0; + test_int(card); + UxCardUnlock(card->hw,ipl); + return; + } + + if(card->card_isr) + { + (*(card->card_isr))(card); + } + else + { + ipl = UxCardLock(card->hw); + + if ((card->test_int)(a)) + { + (card->reset_int)(card); + } + + UxCardUnlock(card->hw,ipl); + + } + +} + +int DivasCardNew(dia_card_t *card_info) +{ + card_t *card; + byte b; + static boolean_t first_call = TRUE; + boolean_t NeedISRandReset = FALSE; + + DPRINTF(("divas: new card ")); + + if (first_call) + { + first_call = FALSE; + init_idi_tab(); + } + + DivasConfigGet(card_info); + + if (DivasCardNext == DIM(DivasCards)) + { + KDPRINTF((KERN_WARNING "Divas: no space available for new card")); + return -1; + } + + card = &DivasCards[DivasCardNext]; + + card->state = DIA_UNKNOWN; + + card->cfg = *card_info; + + card->a.io = card; + + if (UxCardHandleGet(&card->hw, card_info)) + { + KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card")); + return -1; + } + + if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + DivasBriPatch(card); + card_info->io_base = card->cfg.io_base; + } + + switch (card_info->card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + if (DivasPriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + if (DivasBriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_Q: + if (Divas4BriInit(card, card_info)) + { + return -1; + } + + if (card_info->name[6] == '0') + { + NeedISRandReset = TRUE; + } + else // Need to set paramater for ISR anyway + { + card->hw->user_isr_arg = card; + card->hw->user_isr = card_isr; + } + break; + + default: + KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type)); + return -1; + } + + if (NeedISRandReset) + { + if (UxIsrInstall(card->hw, card_isr, card)) + { + KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq)); + UxCardHandleFree(card->hw); + return -1; + } + + b = card->cfg.irq; + + UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b); + + if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) + { + if ((*card->card_reset)(card)) + { + KDPRINTF((KERN_WARNING "Divas: Adapter reset failed")); + return -1; + } + card->state = DIA_RESET; + } + + NeedISRandReset = FALSE; + } + + DivasCardNext++; + + return 0; +} + +void *get_card(int card_id) +{ + int i; + + for (i=0; i < DivasCardNext; i++) + { + if (DivasCards[i].cfg.card_id == card_id) + { + return(&DivasCards[i]); + } + } + + DPRINTF(("divas: get_card() : no such card id (%d)", card_id)); + + return NULL; +} + +int DivasCardConfig(dia_config_t *config) +{ + card_t *card; + int status; + + DPRINTF(("divas: configuring card")); + + card = get_card(config->card_id); + if (!card) + { + return -1; + } + + config = DivasConfig(card, config); + + status = (*card->card_config)(card, config); + + if (!status) + { + card->state = DIA_CONFIGURED; + } + return status; +} + +int DivasCardLoad(dia_load_t *load) +{ + card_t *card; + int status; + + card = get_card(load->card_id); + if (!card) + { + return -1; + } + + if (card->state == DIA_RUNNING) + { + (*card->card_reset)(card); + } + + status = (*card->card_load)(card, load); + if (!status) + { + card->state = DIA_LOADED; + } + return status; +} + +static int idi_register(card_t *card, byte channels) +{ + DESCRIPTOR d[16]; + int length, num_entities; + + DPRINTF(("divas: registering card with IDI")); + + num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES; + card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities); + + if (!card->e_tbl) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available")); + return -1; + } + + bzero(card->e_tbl, sizeof(E_INFO) * num_entities); + card->e_max = num_entities; + + EtdM_DIDD_Read(d, &length); + + if (length == DIM(d)) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); + return -1; + } + + switch (card->cfg.card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + d[length].type = IDI_ADAPTER_PR; + d[length].serial = card->serial_no; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + d[length].type = IDI_ADAPTER_MAESTRA; + d[length].serial = card->serial_no; + break; + + // 4BRI is treated as 4 BRI adapters + case DIA_CARD_TYPE_DIVA_SERVER_Q: + d[length].type = IDI_ADAPTER_MAESTRA; + d[length].serial = card->cfg.serial; + } + + d[length].features = 0; + d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120; + + if ( card->hw->features & PROTCAP_MANIF ) + { + d[length].features |= DI_MANAGE ; + } + if ( card->hw->features & PROTCAP_V_42 ) + { + d[length].features |= DI_V_42 ; + } + if ( card->hw->features & PROTCAP_EXTD_FAX ) + { + d[length].features |= DI_EXTD_FAX ; + } + + d[length].channels = channels; + d[length].request = DivasIdiRequest[card - DivasCards]; + + length++; + + EtdM_DIDD_Write(d, length); + + return 0; +} + +int DivasCardStart(int card_id) +{ + card_t *card; + byte channels; + int status; + + DPRINTF(("divas: starting card")); + + card = get_card(card_id); + if (!card) + { + return -1; + } + + status = (*card->card_start)(card, &channels); + if (status) + { + return status; + } + + /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */ + if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + int i; + card_t *FourBRISlave; + + for (i=3; i >= 0; i--) + { + FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */ + if (FourBRISlave) + { + idi_register(FourBRISlave, 2); + FourBRISlave->state = DIA_RUNNING; + } + } + card->serial_no = card->cfg.serial; + + DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", + card_id - 3, card->serial_no, (int) channels)); + } + else + { + status = idi_register(card, channels); + if (!status) + { + card->state = DIA_RUNNING; + DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", + card_id, card->serial_no, (int) channels)); + } + } + + return status; +} + +int DivasGetMem(mem_block_t *mem_block) +{ + card_t *card; + word card_id = mem_block->card_id; + + card = get_card(card_id); + if (!card) + { + return 0; + } + + return (*card->card_mem_get)(card, mem_block); +} + + +/* + * Deleyed Procedure Call for handling interrupts from card + */ + +void DivaDoCardDpc(card_t *card) +{ + ADAPTER *a; + + a = &card->a; + + if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1) + { + return; + } + + do{ + if((*(card->test_int))(a)) + { + (*(card->dpc))(a); + (*(card->clear_int))(a); + } + (*(card->out))(a); + }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered)); + +} + +void DivasDoDpc(void *pData) +{ + card_t *card = DivasCards; + int i = DivasCardNext; + + while(i--) + { + DivaDoCardDpc(card++); + } +} + +void DivasDoRequestDpc(void *pData) +{ + DivasDoDpc(pData); +} + +/* + * DivasGetNum + * Returns the number of active adapters + */ + +int DivasGetNum(void) +{ + return(DivasCardNext); +} + +/* + * DivasGetList + * Returns a list of active adapters + */ +int DivasGetList(dia_card_list_t *card_list) +{ + int i; + + bzero(card_list, sizeof(dia_card_list_t)); + + for(i = 0; i < DivasCardNext; i++) + { + card_list->card_type = DivasCards[i].cfg.card_type; + card_list->card_slot = DivasCards[i].cfg.slot; + card_list->state = DivasCards[i].state; + card_list++; + } + + return 0; + +} + +/* + * control logging for specified card + */ + +void DivasLog(dia_log_t *log) +{ + card_t *card; + + card = get_card(log->card_id); + if (!card) + { + return; + } + + card->log_types = log->log_types; + + return; +} + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/constant.h linux/drivers/isdn/eicon/constant.h --- v2.4.0-test6/linux/drivers/isdn/eicon/constant.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/constant.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,179 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + + +/*------------------------------------------------------------------*/ +/* Q.931 information elements maximum length */ +/* excluding the identifier, including the length field */ +/*------------------------------------------------------------------*/ + +#define MAX_LEN_BC 13 +#define MAX_LEN_LLC 19 /* ctr3 */ +#define MAX_LEN_HLC 6 /* ctr3 */ +#define MAX_LEN_UUI 200 /* Hicom USBS req */ +#define MAX_LEN_NUM 24 +#define MAX_LEN_DSP 83 /* ctr3 */ +#define MAX_LEN_NI 4 +#define MAX_LEN_PI 5 +#define MAX_LEN_SIN 3 +#define MAX_LEN_CST 4 +#define MAX_LEN_SIG 2 +#define MAX_LEN_SPID 32 +#define MAX_LEN_EID 3 +#define MAX_LEN_CHI 35 /* ctr3 */ +#define MAX_LEN_CAU 33 +#define MAX_LEN_FTY 130 +#define MAX_LEN_KEY 83 /* ctr3 */ +#define MAX_LEN_RSI 4 +#define MAX_LEN_CAI 11 +#define MAX_NUM_SPID 4 +#define MAX_LEN_USERID 9 +#define MAX_LEN_APPLID 5 +#define MAX_LEN_NTTCIF 15 + +/*------------------------------------------------------------------*/ +/* decision return values */ +/*------------------------------------------------------------------*/ + +#define YES 1 +#define NO 0 + + +/*-------------------------------------------------------------------*/ +/* w element coding */ +/*-------------------------------------------------------------------*/ + +#define NTTCIF 0x01 +#define BC 0x04 +#define CAU 0x08 +#define CAD 0x0c +#define CAI 0x10 +#define CST 0x14 +#define CHI 0x18 +#define LLI 0x19 +#define CHA 0x1a +#define FTY 0x1c +#define PI 0x1e +#define NFAC 0x20 +#define TC 0x24 +#define ATT_EID 0x26 +#define NI 0x27 +#define DSP 0x28 +#define DT 0x29 +#define KEY 0x2c +#define KP 0x2c +#define UID 0x2d +#define SIG 0x34 +#define FI 0x39 +#define SPID 0x3a +#define EID 0x3b +#define DSPF 0x3c +#define ECAD 0x4c +#define OAD 0x6c +#define OSA 0x6d +#define DAD 0x70 +#define CPN 0x70 +#define DSA 0x71 +#define RDX 0x73 +#define RAD 0x74 +#define RDN 0x74 +#define RSI 0x79 +#define SCR 0x7A /* internal unscreened CPN */ +#define MIE 0x7a /* internal management info element */ +#define LLC 0x7c +#define HLC 0x7d +#define UUI 0x7e +#define ESC 0x7f + +#define SHIFT 0x90 +#define MORE 0xa0 +#define CL 0xb0 + +/* information elements used on the spid interface */ +#define SPID_CMD 0xc0 +#define SPID_LINK 0x10 +#define SPID_DN 0x70 +#define SPID_BC 0x04 +#define SPID_SWITCH 0x11 + +/*------------------------------------------------------------------*/ +/* global configuration parameters, defined in exec.c */ +/* these parameters are configured with program loading */ +/*------------------------------------------------------------------*/ + +#define PROT_1TR6 0 +#define PROT_ETSI 1 +#define PROT_FRANC 2 +#define PROT_BELG 3 +#define PROT_SWED 4 +#define PROT_NI 5 +#define PROT_5ESS 6 +#define PROT_JAPAN 7 +#define PROT_ATEL 8 +#define PROT_US 9 +#define PROT_ITALY 10 +#define PROT_TWAN 11 +#define PROT_AUSTRAL 12 + +#define INIT_PROT_1TR6 0x80|PROT_1TR6 +#define INIT_PROT_ETSI 0x80|PROT_ETSI +#define INIT_PROT_FRANC 0x80|PROT_FRANC +#define INIT_PROT_BELG 0x80|PROT_BELG +#define INIT_PROT_SWED 0x80|PROT_SWED +#define INIT_PROT_NI 0x80|PROT_NI +#define INIT_PROT_5ESS 0x80|PROT_5ESS +#define INIT_PROT_JAPAN 0x80|PROT_JAPAN +#define INIT_PROT_ATEL 0x80|PROT_ATEL +#define INIT_PROT_ITALY 0x80|PROT_ITALY +#define INIT_PROT_TWAN 0x80|PROT_TWAN +#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL + + +/* -----------------------------------------------------------** +** The PROTOCOL_FEATURE_STRING in feature.h (included ** +** in prstart.sx and astart.sx) defines capabilities and ** +** features of the actual protocol code. It's used as a bit ** +** mask. ** +** The following Bits are defined: ** +** -----------------------------------------------------------*/ + +#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ +#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ +#define PROTCAP_V_42 0x0004 /* V42 implemented */ +#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ +#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ +#define PROTCAP_FREE4 0x0020 /* not used */ +#define PROTCAP_FREE5 0x0040 /* not used */ +#define PROTCAP_FREE6 0x0080 /* not used */ +#define PROTCAP_FREE7 0x0100 /* not used */ +#define PROTCAP_FREE8 0x0200 /* not used */ +#define PROTCAP_FREE9 0x0400 /* not used */ +#define PROTCAP_FREE10 0x0800 /* not used */ +#define PROTCAP_FREE11 0x1000 /* not used */ +#define PROTCAP_FREE12 0x2000 /* not used */ +#define PROTCAP_FREE13 0x4000 /* not used */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/divalog.h linux/drivers/isdn/eicon/divalog.h --- v2.4.0-test6/linux/drivers/isdn/eicon/divalog.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/divalog.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,57 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Include file for defining the kernel loggger messages + * These definitions are shared between the klog driver and the + * klogd daemon process + */ + +#if !defined(_KLOGMSG_H) +#define _KLOGMSG_H + +/* define a type for a log entry */ + +#define KLOG_TEXT_MSG (0) +#define KLOG_XLOG_MSG (1) +#define KLOG_XTXT_MSG (2) +#define KLOG_IDI_REQ (4) +#define KLOG_IDI_CALLBACK (5) +#define KLOG_CAPI_MSG (6) + +typedef struct +{ + unsigned long time_stamp; /* in ms since last system boot */ + int card; /* card number (-1 for all) */ + unsigned int type; /* type of log message (0 is text) */ + unsigned int length; /* message length (non-text messages only) */ + unsigned short code; /* message code (non-text messages only) */ + char buffer[110];/* text/data to log */ +} klog_t; + +void DivasLogAdd(void *buffer, int length); +#endif /* of _KLOGMSG_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/divas.h linux/drivers/isdn/eicon/divas.h --- v2.4.0-test6/linux/drivers/isdn/eicon/divas.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/divas.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,232 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* External Diva Server driver include file */ + +#if !defined(DIVAS_H) +#define DIVAS_H + +#include "sys.h" + + +/* IOCTL commands */ + +#define DIA_IOCTL_INIT (0) +#define DIA_IOCTL_LOAD (1) +#define DIA_IOCTL_CONFIG (2) +#define DIA_IOCTL_START (3) +#define DIA_IOCTL_GET_NUM (4) +#define DIA_IOCTL_GET_LIST (5) +#define DIA_IOCTL_LOG (6) +#define DIA_IOCTL_DETECT (7) +#define DIA_IOCTL_SPACE (8) +#define DIA_IOCTL_GET_MEM (9) +#define DIA_IOCTL_FLAVOUR (10) +#define DIA_IOCTL_XLOG_REQ (11) + +/* Error codes */ + +#define XLOG_ERR_CARD_NUM (13) +#define XLOG_ERR_DONE (14) +#define XLOG_ERR_CMD (15) +#define XLOG_ERR_TIMEOUT (16) +#define XLOG_ERR_CARD_STATE (17) +#define XLOG_ERR_UNKNOWN (18) +#define XLOG_OK (0) + +/* Adapter states */ + +#define DIA_UNKNOWN (0) +#define DIA_RESET (1) +#define DIA_LOADED (2) +#define DIA_CONFIGURED (3) +#define DIA_RUNNING (4) + +/* Stucture for getting card specific information from active cad driver */ + +typedef struct +{ + int card_type; + int card_slot; + int state; +} dia_card_list_t; + +/* use following to select which logging to have active */ + +#define DIVAS_LOG_DEBUG (1 << 0) +#define DIVAS_LOG_XLOG (1 << 1) +#define DIVAS_LOG_IDI (1 << 2) +#define DIVAS_LOG_CAPI (1 << 3) + +/* stucture for DIA_IOCTL_LOG to get information from adapter */ + +typedef struct +{ + int card_id; + int log_types; /* bit mask of log types: use DIVAS_LOG_XXX */ +} dia_log_t; + +/* list of cards supported by this driver */ + +#define DIA_CARD_TYPE_DIVA_SERVER (0) /* Diva Server PRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_B (1) /* Diva Server BRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_Q (2) /* Diva Server 4-BRI */ + +/* bus types */ + +#define DIA_BUS_TYPE_ISA (0) +#define DIA_BUS_TYPE_ISA_PNP (1) +#define DIA_BUS_TYPE_PCI (2) +#define DIA_BUS_TYPE_MCA (3) + +/* types of memory used (index for memory array below) */ + +#define DIVAS_RAM_MEMORY 0 +#define DIVAS_REG_MEMORY 1 +#define DIVAS_CFG_MEMORY 2 +#define DIVAS_SHARED_MEMORY 3 +#define DIVAS_CTL_MEMORY 4 +/* + * card config information + * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card + */ + +typedef struct +{ + int card_id; /* unique id assigned to this card */ + int card_type; /* use DIA_CARD_TYPE_xxx above */ + int bus_type; /* use DIA_BUS_TYPE_xxx above */ + int bus_num; /* bus number (instance number of bus type) */ + int func_num; /* adapter function number (PCI register) */ + int slot; /* slot number in bus */ + unsigned char irq; /* IRQ number */ + int reset_base; /* Reset register for I/O mapped cards */ + int io_base; /* I/O base for I/O mapped cards */ + void *memory[5]; /* memory base addresses for memory mapped cards */ + char name[9]; /* name of adapter */ + int serial; /* serial number */ + unsigned char int_priority; /* Interrupt priority */ +} dia_card_t; + +/* + * protocol configuration information + * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card + */ + +typedef struct +{ + int card_id; /* to identify particular card */ + unsigned char tei; + unsigned char nt2; + unsigned char watchdog; + unsigned char permanent; + unsigned char x_interface; + unsigned char stable_l2; + unsigned char no_order_check; + unsigned char handset_type; + unsigned char sig_flags; + unsigned char low_channel; + unsigned char prot_version; + unsigned char crc4; + struct + { + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + }terminal[2]; +} dia_config_t; + +/* + * code configuration + * passed as parameter to DIA_IOCTL_LOAD ioctl + * one of these ioctl per code file to load + */ + +typedef struct +{ + int card_id; /* card to load */ + enum + { + DIA_CPU_CODE, /* CPU code */ + DIA_DSP_CODE, /* DSP code */ + DIA_CONT_CODE, /* continuation of code */ + DIA_TABLE_CODE, /* code table */ + DIA_DLOAD_CNT, /* number of downloads*/ + DIA_FPGA_CODE + } code_type; /* code for CPU or DSP ? */ + int length; /* length of code */ + unsigned char *code; /* pointer (in user-space) to code */ +} dia_load_t; + +/* + * start configuration + * passed as parameter to DIA_IOCTL_START ioctl + */ + +typedef struct +{ + int card_id; /* card to start */ +} dia_start_t; + +/* used for retrieving memory from the card */ + +typedef struct { + word card_id; + dword addr; + byte data[16 * 8]; +} mem_block_t; + +/* DIVA Server specific addresses */ + +#define DIVAS_CPU_START_ADDR (0x0) +#define ORG_MAX_PROTOCOL_CODE_SIZE 0x000A0000 +#define ORG_MAX_DSP_CODE_SIZE (0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE) +#define ORG_DSP_CODE_BASE (0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE) +#define DIVAS_DSP_START_ADDR (0xBF7A0000) +#define DIVAS_SHARED_OFFSET (0x1000) +#define MP_DSP_CODE_BASE 0xa03a0000 +#define MQ_PROTCODE_OFFSET 0x100000 +#define MQ_SM_OFFSET 0X0f0000 + +#define V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 +#define V90D_MAX_DSP_CODE_SIZE (0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE) +#define V90D_DSP_CODE_BASE (0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE) + +#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ +#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code */ +#define MQ_ORG_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_ORG_MAX_DSP_CODE_SIZE) +#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 /* max 576K Protocol-Code */ +#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */ +#define MQ_MAX_DSP_DOWNLOAD_ADDR 0xa03f0000 +#define MQ_V90D_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_V90D_MAX_DSP_CODE_SIZE) + + +#define ALIGNMENT_MASK_MAESTRA 0xfffffffc + +#endif /* DIVAS_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/dsp_defs.h linux/drivers/isdn/eicon/dsp_defs.h --- v2.4.0-test6/linux/drivers/isdn/eicon/dsp_defs.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/dsp_defs.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,303 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 DSP_DEFS_H_ +#define DSP_DEFS_H_ + +#ifndef DSPDIDS_H_ +#include "dspdids.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif +#ifndef TRUE +#define TRUE (0 == 0) +#endif +#ifndef FALSE +#define FALSE (0 != 0) +#endif + + +/*---------------------------------------------------------------------------*/ + +#define DSP_MEMORY_TYPE_EXTERNAL_DM 0 +#define DSP_MEMORY_TYPE_EXTERNAL_PM 1 +#define DSP_MEMORY_TYPE_INTERNAL_DM 2 +#define DSP_MEMORY_TYPE_INTERNAL_PM 3 + +#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001 +#define DSP_DOWNLOAD_FLAG_2181 0x0002 +#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004 +#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008 + +#define DSP_MEMORY_BLOCK_COUNT 16 + +#define DSP_SEGMENT_PM_FLAG 0x0001 +#define DSP_SEGMENT_SHARED_FLAG 0x0002 + +#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM +#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM +#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM +#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM +#define DSP_SEGMENT_FIRST_RELOCATABLE 4 + +#define DSP_DATA_BLOCK_PM_FLAG 0x0001 +#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002 +#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004 + +#define DSP_RELOC_NONE 0x00 +#define DSP_RELOC_SEGMENT_MASK 0x3f +#define DSP_RELOC_TYPE_MASK 0xc0 +#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */ +#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */ +#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */ +#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */ + +#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 + +#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 + + +typedef struct tag_dsp_combifile_header +{ + char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word header_size; + word combifile_description_size; + word directory_entries; + word directory_size; + word download_count; + word usage_mask_size; +} t_dsp_combifile_header; + +typedef struct tag_dsp_combifile_directory_entry +{ + word card_type_number; + word file_set_number; +} t_dsp_combifile_directory_entry; + +typedef struct tag_dsp_file_header +{ + char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word header_size; + word download_description_size; + word memory_block_table_size; + word memory_block_count; + word segment_table_size; + word segment_count; + word symbol_table_size; + word symbol_count; + word total_data_size_dm; + word data_block_count_dm; + word total_data_size_pm; + word data_block_count_pm; +} t_dsp_file_header; + +typedef struct tag_dsp_memory_block_desc +{ + word alias_memory_block; + word memory_type; + word address; + word size; /* DSP words */ +} t_dsp_memory_block_desc; + +typedef struct tag_dsp_segment_desc +{ + word memory_block; + word attributes; + word base; + word size; + word alignment; /* ==0 -> no other legal start address than base */ +} t_dsp_segment_desc; + +typedef struct tag_dsp_symbol_desc +{ + word symbol_id; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_symbol_desc; + +typedef struct tag_dsp_data_block_header +{ + word attributes; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_data_block_header; + +typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ +{ + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word excess_header_size; + word memory_block_count; + word segment_count; + word symbol_count; + word data_block_count_dm; + word data_block_count_pm; + byte *p_excess_header_data; + char *p_download_description; + t_dsp_memory_block_desc *p_memory_block_table; + t_dsp_segment_desc *p_segment_table; + t_dsp_symbol_desc *p_symbol_table; + word *p_data_blocks_dm; + word *p_data_blocks_pm; +} t_dsp_download_desc; + +#define DSP_DOWNLOAD_INDEX_KERNEL 0 +#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1 +#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2 +#define DSP_MAX_DOWNLOAD_COUNT 35 + + +#define DSP_DOWNLOAD_MAX_SEGMENTS 16 + +#define DSP_UDATA_REQUEST_RECONFIGURE 0 +/* +parameters: + reconfigure delay (in 8kHz samples) + reconfigure code + reconfigure hdlc preamble flags +*/ + +#define DSP_RECONFIGURE_TX_FLAG 0x8000 +#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 +#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 +#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 +#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 +#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff +#define DSP_RECONFIGURE_IDLE 0 +#define DSP_RECONFIGURE_V25 1 +#define DSP_RECONFIGURE_V21_CH2 2 +#define DSP_RECONFIGURE_V27_2400 3 +#define DSP_RECONFIGURE_V27_4800 4 +#define DSP_RECONFIGURE_V29_7200 5 +#define DSP_RECONFIGURE_V29_9600 6 +#define DSP_RECONFIGURE_V33_12000 7 +#define DSP_RECONFIGURE_V33_14400 8 +#define DSP_RECONFIGURE_V17_7200 9 +#define DSP_RECONFIGURE_V17_9600 10 +#define DSP_RECONFIGURE_V17_12000 11 +#define DSP_RECONFIGURE_V17_14400 12 + +/* +data indications if transparent framer + data 0 + data 1 + ... + +data indications if HDLC framer + data 0 + data 1 + ... + CRC 0 + CRC 1 + preamble flags +*/ + +#define DSP_UDATA_INDICATION_SYNC 0 +/* +returns: + time of sync (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_OFF 1 +/* +returns: + time of DCD off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_ON 2 +/* +returns: + time of DCD on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s) +*/ + +#define DSP_UDATA_INDICATION_CTS_OFF 3 +/* +returns: + time of CTS off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_CTS_ON 4 +/* +returns: + time of CTS on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s) +*/ + +#define DSP_CONNECTED_NORM_UNSPECIFIED 0 +#define DSP_CONNECTED_NORM_V21 1 +#define DSP_CONNECTED_NORM_V23 2 +#define DSP_CONNECTED_NORM_V22 3 +#define DSP_CONNECTED_NORM_V22_BIS 4 +#define DSP_CONNECTED_NORM_V32_BIS 5 +#define DSP_CONNECTED_NORM_V34 6 +#define DSP_CONNECTED_NORM_V8 7 +#define DSP_CONNECTED_NORM_BELL_212A 8 +#define DSP_CONNECTED_NORM_BELL_103 9 +#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 +#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 +#define DSP_CONNECTED_NORM_TFAST 12 +#define DSP_CONNECTED_NORM_V21_CH2 13 +#define DSP_CONNECTED_NORM_V27_TER 14 +#define DSP_CONNECTED_NORM_V29 15 +#define DSP_CONNECTED_NORM_V33 16 +#define DSP_CONNECTED_NORM_V17 17 + +#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 + + +/*---------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif + +#endif + +/*---------------------------------------------------------------------------*/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/dspdids.h linux/drivers/isdn/eicon/dspdids.h --- v2.4.0-test6/linux/drivers/isdn/eicon/dspdids.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/dspdids.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,84 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 DSPDIDS_H_ +#define DSPDIDS_H_ + + +/*---------------------------------------------------------------------------*/ + +#define DSP_DID_INVALID 0 +#define DSP_DID_DIVA 1 +#define DSP_DID_DIVA_PRO 2 +#define DSP_DID_DIVA_PRO_20 3 +#define DSP_DID_DIVA_PRO_PCCARD 4 +#define DSP_DID_DIVA_SERVER_BRI_1M 5 +#define DSP_DID_DIVA_SERVER_BRI_2M 6 +#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7 +#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8 +#define DSP_DID_DIVA_SERVER_PRI_30M 9 +#define DSP_DID_TASK_HSCX 100 +#define DSP_DID_TASK_HSCX_PRI_2M_TX 101 +#define DSP_DID_TASK_HSCX_PRI_2M_RX 102 +#define DSP_DID_TASK_V110KRNL 200 +#define DSP_DID_OVERLAY_V1100 201 +#define DSP_DID_OVERLAY_V1101 202 +#define DSP_DID_OVERLAY_V1102 203 +#define DSP_DID_OVERLAY_V1103 204 +#define DSP_DID_OVERLAY_V1104 205 +#define DSP_DID_OVERLAY_V1105 206 +#define DSP_DID_OVERLAY_V1106 207 +#define DSP_DID_OVERLAY_V1107 208 +#define DSP_DID_OVERLAY_V1108 209 +#define DSP_DID_OVERLAY_V1109 210 +#define DSP_DID_TASK_V110_PRI_2M_TX 220 +#define DSP_DID_TASK_V110_PRI_2M_RX 221 +#define DSP_DID_TASK_MODEM 300 +#define DSP_DID_TASK_FAX05 400 +#define DSP_DID_TASK_VOICE 500 +#define DSP_DID_TASK_TIKRNL81 600 +#define DSP_DID_OVERLAY_DIAL 601 +#define DSP_DID_OVERLAY_V22 602 +#define DSP_DID_OVERLAY_V32 603 +#define DSP_DID_OVERLAY_FSK 604 +#define DSP_DID_OVERLAY_FAX 605 +#define DSP_DID_OVERLAY_VXX 606 +#define DSP_DID_OVERLAY_V8 607 +#define DSP_DID_OVERLAY_INFO 608 +#define DSP_DID_OVERLAY_V34 609 +#define DSP_DID_OVERLAY_DFX 610 +#define DSP_DID_PARTIAL_OVERLAY_DIAL 611 +#define DSP_DID_PARTIAL_OVERLAY_FSK 612 +#define DSP_DID_PARTIAL_OVERLAY_FAX 613 +#define DSP_DID_TASK_TIKRNL05 700 + + +/*---------------------------------------------------------------------------*/ + +#endif + +/*---------------------------------------------------------------------------*/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon.h Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,86 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon.h,v $ - * Revision 1.19 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.18 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.17 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.16 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.15 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.14 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.13 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.12 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.11 1999/08/29 17:23:44 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/22 20:26:41 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/18 20:16:57 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:01 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:23 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:24 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/03/29 11:19:41 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:42 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:07 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:04 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ @@ -124,6 +44,8 @@ #define EICON_IOCTL_TEST 98 #define EICON_IOCTL_DEBUGVAR 99 +#define EICON_IOCTL_DIA_OFFSET 100 + /* Bus types */ #define EICON_BUS_ISA 1 #define EICON_BUS_MCA 2 @@ -185,39 +107,10 @@ unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */ } eicon_isa_codebuf; -/* Struct for downloading protocol via ioctl for PCI cards */ -typedef struct { - /* start-up parameters */ - unsigned char tei; - unsigned char nt2; - unsigned char WatchDog; - unsigned char Permanent; - unsigned char XInterface; - unsigned char StableL2; - unsigned char NoOrderCheck; - unsigned char HandsetType; - unsigned char LowChannel; - unsigned char ProtVersion; - unsigned char Crc4; - unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */ - unsigned char Loopback; /* switch card into Loopback mode */ - struct q931_link_s - { - unsigned char oad[32]; - unsigned char osa[32]; - unsigned char spid[32]; - } l[2]; - unsigned long protocol_len; - unsigned int dsp_code_num; - unsigned long dsp_code_len[9]; - unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */ -} eicon_pci_codebuf; - /* Data for downloading protocol via ioctl */ typedef union { eicon_isa_codebuf isa; eicon_isa_codebuf mca; - eicon_pci_codebuf pci; } eicon_codebuf; /* Data for Management interface */ @@ -228,6 +121,7 @@ unsigned char data[700]; } eicon_manifbuf; +#define TRACE_OK (1) #ifdef __KERNEL__ @@ -265,206 +159,34 @@ #include "eicon_isa.h" +#include "idi.h" + +typedef struct { + __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ + __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ + __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ + __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ + __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ + __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ + __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ + __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ + __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ + __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ + __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ + __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ + __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ + __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ + __u8 B[1]; /* buffer space for Req,Ind and Rc */ +} eicon_pr_ram; + /* Macro for delay via schedule() */ #define SLEEP(j) { \ set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout(j); \ } -#endif /* KERNEL */ - -#define DIVAS_SHARED_OFFSET (0x1000) - -#define MIPS_BUFFER_SZ 128 -#define MIPS_MAINT_OFFS 0xff00 - -#define XLOG_ERR_CARD_NUM (13) -#define XLOG_ERR_DONE (14) -#define XLOG_ERR_CMD (15) -#define XLOG_ERR_TIMEOUT (16) -#define XLOG_ERR_CARD_STATE (17) -#define XLOG_ERR_UNKNOWN (18) -#define XLOG_OK (0) - -#define TRACE_OK (1) - -typedef struct { - __u8 Id __attribute__ ((packed)); - __u8 uX __attribute__ ((packed)); - __u8 listen __attribute__ ((packed)); - __u8 active __attribute__ ((packed)); - __u8 sin[3] __attribute__ ((packed)); - __u8 bc[6] __attribute__ ((packed)); - __u8 llc[6] __attribute__ ((packed)); - __u8 hlc[6] __attribute__ ((packed)); - __u8 oad[20] __attribute__ ((packed)); -}DSigStruc; - -typedef struct { - __u32 cx_b1 __attribute__ ((packed)); - __u32 cx_b2 __attribute__ ((packed)); - __u32 cr_b1 __attribute__ ((packed)); - __u32 cr_b2 __attribute__ ((packed)); - __u32 px_b1 __attribute__ ((packed)); - __u32 px_b2 __attribute__ ((packed)); - __u32 pr_b1 __attribute__ ((packed)); - __u32 pr_b2 __attribute__ ((packed)); - __u16 er_b1 __attribute__ ((packed)); - __u16 er_b2 __attribute__ ((packed)); -}BL1Struc; - -typedef struct { - __u32 XTotal __attribute__ ((packed)); - __u32 RTotal __attribute__ ((packed)); - __u16 XError __attribute__ ((packed)); - __u16 RError __attribute__ ((packed)); -}L2Struc; - -typedef struct { - __u16 free_n; -}OSStruc; - -typedef union -{ - DSigStruc DSigStats; - BL1Struc BL1Stats; - L2Struc L2Stats; - OSStruc OSStats; - __u8 b[MIPS_BUFFER_SZ]; - __u16 w[MIPS_BUFFER_SZ>>1]; - __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ - __u32 d[MIPS_BUFFER_SZ>>2]; -} MIPS_BUFFER; - -typedef struct -{ - __u8 req __attribute__ ((packed)); - __u8 rc __attribute__ ((packed)); - __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */ - __u8 *mem __attribute__ ((packed)); - __u16 length __attribute__ ((packed)); /* used to be short */ - __u16 port __attribute__ ((packed)); - __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */ - MIPS_BUFFER data __attribute__ ((packed)); -} mi_pc_maint_t; - -typedef struct -{ - __u16 command; - mi_pc_maint_t pcm; -}xlogreq_t; - -typedef struct{ - __u16 code __attribute__ ((packed)); /* used to be short */ - __u16 timeh __attribute__ ((packed)); - __u16 timel __attribute__ ((packed)); - char buffer[MIPS_BUFFER_SZ - 6]; -}xlog_entry_t; - - -#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 - -#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 - -typedef struct tag_dsp_combifile_header -{ - char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 combifile_description_size __attribute__ ((packed)); - __u16 directory_entries __attribute__ ((packed)); - __u16 directory_size __attribute__ ((packed)); - __u16 download_count __attribute__ ((packed)); - __u16 usage_mask_size __attribute__ ((packed)); -} t_dsp_combifile_header; - -typedef struct tag_dsp_combifile_directory_entry -{ - __u16 card_type_number __attribute__ ((packed)); - __u16 file_set_number __attribute__ ((packed)); -} t_dsp_combifile_directory_entry; - -typedef struct tag_dsp_file_header -{ - char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 download_id __attribute__ ((packed)); - __u16 download_flags __attribute__ ((packed)); - __u16 required_processing_power __attribute__ ((packed)); - __u16 interface_channel_count __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 download_description_size __attribute__ ((packed)); - __u16 memory_block_table_size __attribute__ ((packed)); - __u16 memory_block_count __attribute__ ((packed)); - __u16 segment_table_size __attribute__ ((packed)); - __u16 segment_count __attribute__ ((packed)); - __u16 symbol_table_size __attribute__ ((packed)); - __u16 symbol_count __attribute__ ((packed)); - __u16 total_data_size_dm __attribute__ ((packed)); - __u16 data_block_count_dm __attribute__ ((packed)); - __u16 total_data_size_pm __attribute__ ((packed)); - __u16 data_block_count_pm __attribute__ ((packed)); -} t_dsp_file_header; - -typedef struct tag_dsp_memory_block_desc -{ - __u16 alias_memory_block; - __u16 memory_type; - __u16 address; - __u16 size; /* DSP words */ -} t_dsp_memory_block_desc; - -typedef struct tag_dsp_segment_desc -{ - __u16 memory_block; - __u16 attributes; - __u16 base; - __u16 size; - __u16 alignment; /* ==0 -> no other legal start address than base */ -} t_dsp_segment_desc; - -typedef struct tag_dsp_symbol_desc -{ - __u16 symbol_id; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_symbol_desc; - -typedef struct tag_dsp_data_block_header -{ - __u16 attributes; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_data_block_header; - -typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ -{ - __u16 download_id; - __u16 download_flags; - __u16 required_processing_power; - __u16 interface_channel_count; - __u16 excess_header_size; - __u16 memory_block_count; - __u16 segment_count; - __u16 symbol_count; - __u16 data_block_count_dm; - __u16 data_block_count_pm; - __u8 * p_excess_header_data __attribute__ ((packed)); - char * p_download_description __attribute__ ((packed)); - t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed)); - t_dsp_segment_desc *p_segment_table __attribute__ ((packed)); - t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed)); - __u16 * p_data_blocks_dm __attribute__ ((packed)); - __u16 * p_data_blocks_pm __attribute__ ((packed)); -} t_dsp_download_desc; - - -#ifdef __KERNEL__ - typedef struct { __u8 Req; /* pending request */ __u8 Rc; /* return code received */ @@ -508,6 +230,7 @@ unsigned short statectrl; /* State controling bits */ unsigned short eazmask; /* EAZ-Mask for this Channel */ int queued; /* User-Data Bytes in TX queue */ + int pqueued; /* User-Data Packets in TX queue */ int waitq; /* User-Data Bytes in wait queue */ int waitpq; /* User-Data Bytes in packet queue */ struct sk_buff *tskb1; /* temp skb 1 */ @@ -518,7 +241,9 @@ T30_s *fax; /* pointer to fax data in LL */ eicon_ch_fax_buf fax2; /* fax related struct */ #endif - entity e; /* Entity */ + entity e; /* Native Entity */ + ENTITY de; /* Divas D Entity */ + ENTITY be; /* Divas B Entity */ char cpn[32]; /* remember cpn */ char oad[32]; /* remember oad */ char dsa[32]; /* remember dsa */ @@ -542,8 +267,6 @@ #define EICON_FLAGS_MVALID 8 /* Cards membase is valid */ #define EICON_FLAGS_LOADED 8 /* Firmware loaded */ -#define EICON_BCH 2 /* # of channels per card */ - /* D-Channel states */ #define EICON_STATE_NULL 0 #define EICON_STATE_ICALL 1 @@ -565,9 +288,6 @@ #define EICON_MAX_QUEUE 2138 -#define EICON_LOCK_TX 0 -#define EICON_LOCK_RX 1 - typedef union { eicon_isa_card isa; eicon_pci_card pci; @@ -593,17 +313,12 @@ __u8 more; } eicon_indhdr; -typedef struct msn_entry { - char eaz; - char msn[16]; - struct msn_entry * next; -} msn_entry; - /* * Per card driver data */ typedef struct eicon_card { eicon_hwif hwif; /* Hardware dependant interface */ + DESCRIPTOR *d; /* IDI Descriptor */ u_char ptype; /* Protocol type (1TR6 or Euro) */ u_char bus; /* Bustype (ISA, MCA, PCI) */ u_char type; /* Cardtype (EICON_CTYPE_...) */ @@ -621,49 +336,23 @@ struct tq_struct snd_tq; /* Task struct for xmit bh */ struct tq_struct rcv_tq; /* Task struct for rcv bh */ struct tq_struct ack_tq; /* Task struct for ack bh */ - msn_entry *msn_list; eicon_chan* IdTable[256]; /* Table to find entity */ __u16 ref_in; __u16 ref_out; int nchannels; /* Number of B-Channels */ int ReadyInt; /* Ready Interrupt */ eicon_chan *bch; /* B-Channel status/control */ - char status_buf[256]; /* Buffer for status messages */ - char *status_buf_read; - char *status_buf_write; - char *status_buf_end; + DBUFFER *dbuf; /* Dbuffer for Diva Server */ + BUFFERS *sbuf; /* Buffer for Diva Server */ + char *sbufp; /* Data Buffer for Diva Server */ isdn_if interface; /* Interface to upper layer */ - char regname[35]; /* Name used for request_region */ + char regname[35]; /* Drivers card name */ #ifdef CONFIG_MCA int mca_slot; /* # of cards MCA slot */ int mca_io; /* MCA cards IO port */ #endif /* CONFIG_MCA */ } eicon_card; -/* -----------------------------------------------------------** -** The PROTOCOL_FEATURE_STRING ** -** defines capabilities and ** -** features of the actual protocol code. It's used as a bit ** -** mask. ** -** The following Bits are defined: ** -** -----------------------------------------------------------*/ -#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ -#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ -#define PROTCAP_V_42 0x0004 /* V42 implemented */ -#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ -#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ -#define PROTCAP_FREE4 0x0020 /* not used */ -#define PROTCAP_FREE5 0x0040 /* not used */ -#define PROTCAP_FREE6 0x0080 /* not used */ -#define PROTCAP_FREE7 0x0100 /* not used */ -#define PROTCAP_FREE8 0x0200 /* not used */ -#define PROTCAP_FREE9 0x0400 /* not used */ -#define PROTCAP_FREE10 0x0800 /* not used */ -#define PROTCAP_FREE11 0x1000 /* not used */ -#define PROTCAP_FREE12 0x2000 /* not used */ -#define PROTCAP_FREE13 0x4000 /* not used */ -#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ - #include "eicon_idi.h" extern eicon_card *cards; @@ -688,13 +377,11 @@ mark_bh(IMMEDIATE_BH); } -extern char *eicon_find_eaz(eicon_card *, char); -extern int eicon_addcard(int, int, int, char *); +extern int eicon_addcard(int, int, int, char *, int); extern void eicon_io_transmit(eicon_card *card); extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); extern void eicon_io_rcv_dispatch(eicon_card *ccard); extern void eicon_io_ack_dispatch(eicon_card *ccard); -extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq); #ifdef CONFIG_MCA extern int eicon_mca_find_card(int, int, int, char *); extern int eicon_mca_probe(int, int, int, int, char *); @@ -704,6 +391,8 @@ extern ulong DebugVar; extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); extern void eicon_putstatus(eicon_card * card, char * buf); + +extern spinlock_t eicon_lock; #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_dsp.h linux/drivers/isdn/eicon/eicon_dsp.h --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_dsp.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_dsp.h Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * DSP definitions @@ -20,75 +20,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_dsp.h,v $ - * Revision 1.5 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.4 1999/07/25 15:12:02 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.3 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.2 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.1 1999/03/02 12:18:54 armin - * First checkin of DSP defines for audio features. - * * */ #ifndef DSP_H #define DSP_H -#define DSP_UDATA_REQUEST_RECONFIGURE 0 -/* -parameters: - reconfigure delay (in 8kHz samples) - reconfigure code - reconfigure hdlc preamble flags -*/ - -#define DSP_RECONFIGURE_TX_FLAG 0x8000 -#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 -#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 -#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 -#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 -#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff -#define DSP_RECONFIGURE_IDLE 0 -#define DSP_RECONFIGURE_V25 1 -#define DSP_RECONFIGURE_V21_CH2 2 -#define DSP_RECONFIGURE_V27_2400 3 -#define DSP_RECONFIGURE_V27_4800 4 -#define DSP_RECONFIGURE_V29_7200 5 -#define DSP_RECONFIGURE_V29_9600 6 -#define DSP_RECONFIGURE_V33_12000 7 -#define DSP_RECONFIGURE_V33_14400 8 -#define DSP_RECONFIGURE_V17_7200 9 -#define DSP_RECONFIGURE_V17_9600 10 -#define DSP_RECONFIGURE_V17_12000 11 -#define DSP_RECONFIGURE_V17_14400 12 +#include "dsp_defs.h" -/* -data indications if transparent framer - data 0 - data 1 - ... - -data indications if HDLC framer - data 0 - data 1 - ... - CRC 0 - CRC 1 - preamble flags -*/ #define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 /* @@ -122,49 +61,6 @@ - none - */ - -#define DSP_UDATA_INDICATION_SYNC 0 -/* -returns: - time of sync (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_OFF 1 -/* -returns: - time of DCD off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_ON 2 -/* -returns: - time of DCD on (sampled from counter at 8kHz) - connected norm - connected options - connected speed (bit/s, max of tx and rx speed) - roundtrip delay (ms) - connected speed tx (bit/s) - connected speed rx (bit/s) -*/ - -#define DSP_UDATA_INDICATION_CTS_OFF 3 -/* -returns: - time of CTS off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_CTS_ON 4 -/* -returns: - time of CTS on (sampled from counter at 8kHz) - connected norm - connected options - connected speed (bit/s, max of tx and rx speed) - roundtrip delay (ms) - connected speed tx (bit/s) - connected speed rx (bit/s) -*/ - typedef struct eicon_dsp_ind { __u16 time __attribute__ ((packed)); __u8 norm __attribute__ ((packed)); @@ -175,32 +71,11 @@ __u32 rxspeed __attribute__ ((packed)); } eicon_dsp_ind; -#define DSP_CONNECTED_NORM_UNSPECIFIED 0 -#define DSP_CONNECTED_NORM_V21 1 -#define DSP_CONNECTED_NORM_V23 2 -#define DSP_CONNECTED_NORM_V22 3 -#define DSP_CONNECTED_NORM_V22_BIS 4 -#define DSP_CONNECTED_NORM_V32_BIS 5 -#define DSP_CONNECTED_NORM_V34 6 -#define DSP_CONNECTED_NORM_V8 7 -#define DSP_CONNECTED_NORM_BELL_212A 8 -#define DSP_CONNECTED_NORM_BELL_103 9 -#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 -#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 -#define DSP_CONNECTED_NORM_V90 12 -#define DSP_CONNECTED_NORM_V21_CH2 13 -#define DSP_CONNECTED_NORM_V27_TER 14 -#define DSP_CONNECTED_NORM_V29 15 -#define DSP_CONNECTED_NORM_V33 16 -#define DSP_CONNECTED_NORM_V17 17 - -#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 #define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 #define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 #define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 - #define DSP_UDATA_INDICATION_DISCONNECT 5 /* returns: @@ -213,7 +88,6 @@ #define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY 0x03 #define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 - #define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 /* diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_idi.c Mon Mar 27 08:08:25 2000 +++ linux/drivers/isdn/eicon/eicon_idi.c Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $ +/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,135 +25,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.c,v $ - * Revision 1.33 2000/03/06 15:45:17 armin - * Fixed incomplete number handling with BRI PtP connection. - * - * Revision 1.32 2000/03/04 17:04:21 armin - * Fix of statemachine, B-connect before D-connect, - * thanks to Helmut Adams - * Minor change in send-data packet handling. - * - * Revision 1.31 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.30 2000/02/16 16:08:46 armin - * Fixed virtual channel handling of IDI. - * - * Revision 1.29 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.28 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.27 1999/11/29 13:12:03 armin - * Autoconnect on L2_TRANS doesn't work with link_level correctly, - * changed back to former mode. - * - * Revision 1.26 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.25 1999/11/18 20:30:55 armin - * removed old workaround for ISA cards. - * - * Revision 1.24 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.23 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.22 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.21 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.20 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.19 1999/09/21 20:06:40 armin - * Added pointer checks. - * - * Revision 1.18 1999/09/07 12:48:05 armin - * Prepared for sub-address usage. - * - * Revision 1.17 1999/09/07 12:35:39 armin - * Better checking and channel Id handling. - * - * Revision 1.16 1999/09/04 13:44:19 armin - * Fix of V.42 analog Modem negotiation handling. - * - * Revision 1.15 1999/08/28 21:32:50 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.14 1999/08/28 20:24:40 armin - * Corrected octet 3/3a in CPN/OAD information element. - * Thanks to John Simpson - * - * Revision 1.13 1999/08/22 20:26:44 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.12 1999/08/18 20:16:59 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.11 1999/07/25 15:12:03 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.10 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.9 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.8 1999/03/02 12:37:43 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.7 1999/02/03 18:34:35 armin - * Channel selection for outgoing calls w/o CHI. - * Added channel # in debug messages. - * L2 Transparent should work with 800 byte/packet now. - * - * Revision 1.6 1999/01/26 07:18:59 armin - * Bug with wrong added CPN fixed. - * - * Revision 1.5 1999/01/24 20:14:11 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.4 1999/01/10 18:46:05 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.3 1999/01/05 14:49:34 armin - * Added experimental usage of full BC and HLC for - * speech, 3.1kHz audio, fax gr.2/3 - * - * Revision 1.2 1999/01/04 13:19:29 armin - * Channel status with listen-request wrong - fixed. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -161,25 +32,14 @@ #include "eicon.h" #include "eicon_idi.h" #include "eicon_dsp.h" +#include "uxio.h" #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.33 $"; +char *eicon_idi_revision = "$Revision: 1.41 $"; eicon_manifbuf *manbuf; -static char BC_Speech[3] = { 0x80, 0x90, 0xa3 }; -static char BC_31khz[3] = { 0x90, 0x90, 0xa3 }; -static char BC_64k[2] = { 0x88, 0x90 }; -static char BC_video[3] = { 0x91, 0x90, 0xa5 }; - -#ifdef EICON_FULL_SERVICE_OKTETT -/* -static char HLC_telephony[2] = { 0x91, 0x81 }; -*/ -static char HLC_faxg3[2] = { 0x91, 0x84 }; -#endif - int eicon_idi_manage_assign(eicon_card *card); int eicon_idi_manage_remove(eicon_card *card); int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer); @@ -209,7 +69,7 @@ reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0; + reqbuf->ReqId = DSIG_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ } @@ -221,6 +81,9 @@ reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; @@ -262,7 +125,7 @@ reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0x20; + reqbuf->ReqId = NL_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 1; /* Net Entity */ } @@ -282,6 +145,21 @@ } int +idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan) +{ + reqbuf->Req = SUSPEND; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.P[0] = CAI; + reqbuf->XBuffer.P[1] = 1; + reqbuf->XBuffer.P[2] = chan->No; + reqbuf->XBuffer.P[3] = 0; + reqbuf->XBuffer.length = 4; + reqbuf->Reference = 0; /* Sig Entity */ + return(0); +} + +int idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) { int l = 9; @@ -295,7 +173,7 @@ reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 3; + reqbuf->XBuffer.P[7] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -391,6 +269,12 @@ case HANGUP: idi_put_req(reqbuf, HANGUP, 0, 0); break; + case SUSPEND: + idi_put_suspend_req(reqbuf, chan); + break; + case RESUME: + idi_put_req(reqbuf, RESUME, 0 ,0); + break; case REJECT: idi_put_req(reqbuf, REJECT, 0 ,0); break; @@ -400,17 +284,20 @@ case CALL_RES: idi_call_res_req(reqbuf, chan); break; - case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); + case CALL_HOLD: + idi_put_req(reqbuf, CALL_HOLD, 0, 0); + break; + case N_CONNECT|0x700: + idi_put_req(reqbuf, N_CONNECT, 1, 0); break; - case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); + case N_CONNECT_ACK|0x700: + idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); break; - case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); + case N_DISC|0x700: + idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); break; - case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); + case N_DISC_ACK|0x700: + idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -492,7 +379,7 @@ if ((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) { - if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1); + if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { @@ -508,6 +395,32 @@ } int +capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm) +{ + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return -1; + if (cm->para[2] < 3) + return -1; + if (cm->para[4] != 0) + return -1; + switch(cm->para[3]) { + case 4: /* Suspend */ + eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); + if (cm->para[5]) { + idi_do_req(card, chan, SUSPEND, 0); + } else { + idi_do_req(card, chan, CALL_HOLD, 0); + } + break; + case 5: /* Resume */ + eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); + idi_do_req(card, chan, RESUME, 0); + break; + } + return 0; +} + +int idi_connect_res(eicon_card *card, eicon_chan *chan) { if ((!card) || (!chan)) @@ -612,7 +525,14 @@ reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; } - if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { + if (si2 > 2) { + reqbuf->XBuffer.P[l++] = SHIFT|6; + reqbuf->XBuffer.P[l++] = SIN; + reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = si1; + reqbuf->XBuffer.P[l++] = si2; + } + else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { reqbuf->XBuffer.P[l++] = BC; reqbuf->XBuffer.P[l++] = tmp; for(i=0; iXBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 32; - reqbuf->XBuffer.P[l++] = 3; + reqbuf->XBuffer.P[l++] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -859,7 +779,7 @@ } for(i=0; i < wlen; i++) message->llc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0], + eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0], message->llc[1],message->llc[2],message->llc[3]); break; case HLC: @@ -869,7 +789,7 @@ } for(i=0; i < wlen; i++) message->hlc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No, + eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No, message->hlc[0], message->hlc[1], message->hlc[2], message->hlc[3], message->hlc[4]); break; @@ -1061,31 +981,55 @@ } void -idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2) +idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2) { - si1[0] = 0; - si2[0] = 0; - if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */ - si1[0] = 1; + si1[0] = 0; + si2[0] = 0; + + switch (bc[0] & 0x7f) { + case 0x00: /* Speech */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 1; + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */ - si1[0] = 1; + break; + case 0x10: /* 3.1 Khz audio */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 2; - if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */ - si1[0] = 2; - } + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */ - si1[0] = 7; - } - if (memcmp(bc, BC_video, 3) == 0) { /* video */ - si1[0] = 4; - } + break; + case 0x08: /* Unrestricted digital information */ + si1[0] = 7; + si2[0] = sin[1]; + break; + case 0x09: /* Restricted digital information */ + si1[0] = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + si1[0] = 3; + break; + case 0x18: /* Video */ + si1[0] = 4; + break; + } + switch (bc[1] & 0x7f) { + case 0x40: /* packed mode */ + si1[0] = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + /* moderate = bc[1] & 0x7f; */ + break; + } } /********************* FAX stuff ***************************/ @@ -1225,7 +1169,7 @@ reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_EDATA; + reqbuf->Req = N_EDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -1359,7 +1303,7 @@ eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength); break; } - idi_send_data(card, chan, 0, skb, 0); + idi_send_data(card, chan, 0, skb, 0, 0); } void @@ -1913,7 +1857,7 @@ OutBuf->Len = 0; OutBuf->Next = OutBuf->Data; - return(idi_send_data(ccard, chan, 0, skb, 1)); + return(idi_send_data(ccard, chan, 0, skb, 1, 0)); } int @@ -1958,6 +1902,8 @@ if (chan->queued + skb->len > 1200) return 0; + if (chan->pqueued > 1) + return 0; InBuf.Data = skb->data; InBuf.Size = skb->len; @@ -2183,6 +2129,7 @@ } if ((chan->fax->code > 1) && (chan->fax->code < 120)) chan->fax->code += 120; + eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code); chan->fax->r_code = ISDN_TTY_FAX_HNG; cmd.driver = ccard->myid; cmd.command = ISDN_STAT_FAXIND; @@ -2224,7 +2171,7 @@ reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_UDATA; + reqbuf->Req = N_UDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -2418,12 +2365,12 @@ while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (message.e_cau[0] & 0x7f) { cmd.driver = ccard->myid; cmd.arg = chan->No; @@ -2433,10 +2380,6 @@ ccard->interface.statcallb(&cmd); } chan->cause[0] = 0; -#ifdef CONFIG_ISDN_TTY_FAX - if (!chan->e.B2Id) - chan->fax = 0; -#endif if (((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) || ((chan->l2prot == ISDN_PROTO_L2_FAX) && @@ -2446,6 +2389,7 @@ if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); chan->statectrl &= ~WAITING_FOR_HANGUP; + chan->statectrl &= ~IN_HOLD; if (chan->statectrl & HAVE_CONN_REQ) { eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); chan->statectrl &= ~HAVE_CONN_REQ; @@ -2463,6 +2407,9 @@ cmd.command = ISDN_STAT_DHUP; ccard->interface.statcallb(&cmd); eicon_idi_listen_req(ccard, chan); +#ifdef CONFIG_ISDN_TTY_FAX + chan->fax = 0; +#endif } } break; @@ -2475,7 +2422,7 @@ break; } chan->fsm_state = EICON_STATE_ICALL; - idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2); + idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2); strcpy(chan->cpn, message.cpn + 1); strcpy(chan->oad, message.oad); strcpy(chan->dsa, message.dsa); @@ -2553,12 +2500,15 @@ case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); break; default: /* On most incoming calls we use automatic connect */ - /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ + /* idi_do_req(ccard, chan, N_CONNECT, 1); */ } } else { if (chan->fsm_state != EICON_STATE_ACTIVE) @@ -2568,33 +2518,50 @@ case CALL_CON: eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); if (chan->fsm_state == EICON_STATE_OCALL) { - chan->fsm_state = EICON_STATE_OBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - /* check if old NetID has been removed */ if (chan->e.B2Id) { eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n", chan->No, chan->e.B2Id); idi_do_req(ccard, chan, REMOVE, 1); } - - idi_do_req(ccard, chan, ASSIGN, 1); - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if (chan->fax) + if (chan->fax) { chan->fax->phase = ISDN_FAX_PHASE_A; + } else { + eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n"); + idi_hangup(ccard, chan); + break; + } } #endif + chan->fsm_state = EICON_STATE_OBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + + idi_do_req(ccard, chan, ASSIGN, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); } else - idi_hangup(ccard, chan); + idi_hangup(ccard, chan); break; case AOC_IND: eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No); break; + case CALL_HOLD_ACK: + chan->statectrl |= IN_HOLD; + eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No); + break; + case SUSPEND_REJ: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No); + break; + case SUSPEND: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No); + break; + case RESUME: + eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No); + break; default: eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); } @@ -2613,7 +2580,7 @@ } else switch(ind->Ind) { - case IDI_N_CONNECT_ACK: + case N_CONNECT_ACK: eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No); if (chan->l2prot == ISDN_PROTO_L2_MODEM) { chan->fsm_state = EICON_STATE_WMCONN; @@ -2634,7 +2601,7 @@ } } else { - eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n"); + eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n"); } #endif break; @@ -2646,10 +2613,10 @@ strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_CONNECT: + case N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); chan->e.IndCh = ind->IndCh; - if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); + if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; } @@ -2664,43 +2631,47 @@ strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_DISC: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No); + case N_DISC: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No); if (chan->e.B2Id) { while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1); + idi_do_req(ccard, chan, N_DISC_ACK, 1); idi_do_req(ccard, chan, REMOVE, 1); } #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); idi_fax_hangup(ccard, chan); } #endif chan->e.IndCh = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); - idi_do_req(ccard, chan, HANGUP, 0); + spin_unlock_irqrestore(&eicon_lock, flags); + if (!(chan->statectrl & IN_HOLD)) { + idi_do_req(ccard, chan, HANGUP, 0); + } if (chan->fsm_state == EICON_STATE_ACTIVE) { cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BHUP; cmd.arg = chan->No; ccard->interface.statcallb(&cmd); chan->fsm_state = EICON_STATE_NULL; - chan->statectrl |= WAITING_FOR_HANGUP; + if (!(chan->statectrl & IN_HOLD)) { + chan->statectrl |= WAITING_FOR_HANGUP; + } } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; #endif break; - case IDI_N_DISC_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No); + case N_DISC_ACK: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); @@ -2708,10 +2679,10 @@ } #endif break; - case IDI_N_DATA_ACK: - eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + case N_DATA_ACK: + eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No); break; - case IDI_N_DATA: + case N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); if (chan->l2prot == ISDN_PROTO_L2_FAX) { @@ -2723,11 +2694,11 @@ free_buff = 0; } break; - case IDI_N_UDATA: + case N_UDATA: idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #ifdef CONFIG_ISDN_TTY_FAX - case IDI_N_EDATA: + case N_EDATA: idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #endif @@ -2747,6 +2718,8 @@ { ulong flags; isdn_ctrl cmd; + int tqueued = 0; + int twaitpq = 0; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { /* I dont know why this happens, should not ! */ @@ -2770,16 +2743,15 @@ eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); ccard->IdTable[ack->RcId] = NULL; - eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, - ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); if (!chan->e.ReqCh) chan->e.D3Id = 0; else chan->e.B2Id = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, + ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); return 1; } @@ -2790,25 +2762,21 @@ } else { /* Network layer */ switch(chan->e.Req & 0x0f) { - case IDI_N_CONNECT: + case N_CONNECT: chan->e.IndCh = ack->RcCh; eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); break; - case IDI_N_MDATA: - case IDI_N_DATA: - if ((chan->e.Req & 0x0f) == IDI_N_DATA) { - if (chan->queued) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BSENT; - cmd.arg = chan->No; - cmd.parm.length = chan->waitpq; - ccard->interface.statcallb(&cmd); - } - save_flags(flags); - cli(); + case N_MDATA: + case N_DATA: + tqueued = chan->queued; + twaitpq = chan->waitpq; + if ((chan->e.Req & 0x0f) == N_DATA) { + spin_lock_irqsave(&eicon_lock, flags); chan->waitpq = 0; - restore_flags(flags); + if(chan->pqueued) + chan->pqueued--; + spin_unlock_irqrestore(&eicon_lock, flags); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { if (((chan->queued - chan->waitq) < 1) && @@ -2828,11 +2796,17 @@ } #endif } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued -= chan->waitq; if (chan->queued < 0) chan->queued = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BSENT; + cmd.arg = chan->No; + cmd.parm.length = twaitpq; + ccard->interface.statcallb(&cmd); + } break; default: eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, @@ -2858,11 +2832,10 @@ return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ack->RcId]) != NULL) dCh = chan->No; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); switch (ack->Rc) { case OK_FC: @@ -2890,8 +2863,7 @@ eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n", chan->No, chan->e.D3Id, chan->e.B2Id); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); for(j = 0; j < ccard->nchannels + 1; j++) { if ((ccard->bch[j].e.ref == ack->Reference) && (ccard->bch[j].e.Req == ASSIGN)) { @@ -2901,12 +2873,12 @@ ccard->bch[j].e.B2Id = ack->RcId; ccard->IdTable[ack->RcId] = &ccard->bch[j]; chan = &ccard->bch[j]; - eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, - ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); break; } - } - restore_flags(flags); + } + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, + ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); if (j > ccard->nchannels) { eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", ack->Reference, ack->RcId); @@ -2917,6 +2889,7 @@ case UNKNOWN_COMMAND: case WRONG_COMMAND: case WRONG_ID: + case ADAPTER_DEAD: case WRONG_CH: case UNKNOWN_IE: case WRONG_IE: @@ -2949,19 +2922,18 @@ ccard->interface.statcallb(&cmd); } } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if (chan) { chan->e.ref = 0; chan->e.busy = 0; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); dev_kfree_skb(skb); eicon_schedule_tx(ccard); } int -idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que) +idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk) { struct sk_buff *xmit_skb; struct sk_buff *skb2; @@ -2985,13 +2957,14 @@ return -1; if (!len) return 0; - if (chan->queued + len > EICON_MAX_QUEUE) + + if ((chk) && (chan->pqueued > 1)) return 0; - eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len); + eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n", + chan->No, len, chan->pqueued); - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while(offset < len) { plen = ((len - offset) > 270) ? 270 : len - offset; @@ -3000,7 +2973,7 @@ skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!xmit_skb) || (!skb2)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); if (xmit_skb) dev_kfree_skb(skb); @@ -3013,13 +2986,10 @@ chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); - if (((len - offset) > 270) && - (chan->l2prot != ISDN_PROTO_L2_MODEM) && - (chan->l2prot != ISDN_PROTO_L2_FAX) && - (chan->l2prot != ISDN_PROTO_L2_TRANS)) { - reqbuf->Req = IDI_N_MDATA; + if ((len - offset) > 270) { + reqbuf->Req = N_MDATA; } else { - reqbuf->Req = IDI_N_DATA; + reqbuf->Req = N_DATA; /* if (ack) reqbuf->Req |= N_D_BIT; */ } reqbuf->ReqCh = chan->e.IndCh; @@ -3033,9 +3003,11 @@ offset += plen; } - if (que) + if (que) { chan->queued += len; - restore_flags(flags); + chan->pqueued++; + } + spin_unlock_irqrestore(&eicon_lock, flags); eicon_schedule_tx(card); dev_kfree_skb(skb); return len; @@ -3073,7 +3045,7 @@ reqbuf->XBuffer.P[0] = 0; reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0xe0; + reqbuf->ReqId = MAN_ID; reqbuf->XBuffer.length = 1; reqbuf->Reference = 2; /* Man Entity */ @@ -3199,7 +3171,7 @@ reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; reqbuf->XBuffer.P[l++] = 0; - reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */ + reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.length = l; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_idi.h linux/drivers/isdn/eicon/eicon_idi.h --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_idi.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_idi.h Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface @@ -20,168 +20,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.h,v $ - * Revision 1.9 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.8 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.7 1999/08/22 20:26:46 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:04 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/07/11 17:16:26 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.4 1999/03/29 11:19:44 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:18 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:42 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * * */ -#ifndef IDI_H -#define IDI_H +#ifndef E_IDI_H +#define E_IDI_H #include -#define ASSIGN 0x01 -#define REMOVE 0xff - -#define CALL_REQ 1 /* call request */ -#define CALL_CON 1 /* call confirmation */ -#define CALL_IND 2 /* incoming call connected */ -#define LISTEN_REQ 2 /* listen request */ -#define HANGUP 3 /* hangup request/indication */ -#define SUSPEND 4 /* call suspend request/confirm */ -#define RESUME 5 /* call resume request/confirm */ -#define SUSPEND_REJ 6 /* suspend rejected indication */ -#define USER_DATA 8 /* user data for user to user signaling */ -#define CONGESTION 9 /* network congestion indication */ -#define INDICATE_REQ 10 /* request to indicate an incoming call */ -#define INDICATE_IND 10 /* indicates that there is an incoming call */ -#define CALL_RES 11 /* accept an incoming call */ -#define CALL_ALERT 12 /* send ALERT for incoming call */ -#define INFO_REQ 13 /* INFO request */ -#define INFO_IND 13 /* INFO indication */ -#define REJECT 14 /* reject an incoming call */ -#define RESOURCES 15 /* reserve B-Channel hardware resources */ -#define TEL_CTRL 16 /* Telephone control request/indication */ -#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ -#define FAC_REG_REQ 18 /* connection idependent fac registration */ -#define FAC_REG_ACK 19 /* fac registration acknowledge */ -#define FAC_REG_REJ 20 /* fac registration reject */ -#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ -#define AOC_IND 26/* Advice of Charge */ - -#define IDI_N_MDATA (0x01) -#define IDI_N_CONNECT (0x02) -#define IDI_N_CONNECT_ACK (0x03) -#define IDI_N_DISC (0x04) -#define IDI_N_DISC_ACK (0x05) -#define IDI_N_RESET (0x06) -#define IDI_N_RESET_ACK (0x07) -#define IDI_N_DATA (0x08) -#define IDI_N_EDATA (0x09) -#define IDI_N_UDATA (0x0a) -#define IDI_N_BDATA (0x0b) -#define IDI_N_DATA_ACK (0x0c) -#define IDI_N_EDATA_ACK (0x0d) - -#define N_Q_BIT 0x10 /* Q-bit for req/ind */ -#define N_M_BIT 0x20 /* M-bit for req/ind */ -#define N_D_BIT 0x40 /* D-bit for req/ind */ - - -#define SHIFT 0x90 /* codeset shift */ -#define MORE 0xa0 /* more data */ -#define CL 0xb0 /* congestion level */ - - /* codeset 0 */ - -#define BC 0x04 /* Bearer Capability */ -#define CAU 0x08 /* cause */ -#define CAD 0x0c /* Connected address */ -#define CAI 0x10 /* call identity */ -#define CHI 0x18 /* channel identification */ -#define LLI 0x19 /* logical link id */ -#define CHA 0x1a /* charge advice */ -#define FTY 0x1c -#define PI 0x1e /* Progress Indicator */ -#define NI 0x27 /* Notification Indicator */ -#define DT 0x29 /* ETSI date/time */ -#define KEY 0x2c /* keypad information element */ -#define DSP 0x28 /* display */ -#define OAD 0x6c /* origination address */ -#define OSA 0x6d /* origination sub-address */ -#define CPN 0x70 /* called party number */ -#define DSA 0x71 /* destination sub-address */ -#define RDN 0x74 /* redirecting number */ -#define LLC 0x7c /* low layer compatibility */ -#define HLC 0x7d /* high layer compatibility */ -#define UUI 0x7e /* user user information */ -#define ESC 0x7f /* escape extension */ - -#define DLC 0x20 /* data link layer configuration */ -#define NLC 0x21 /* network layer configuration */ - - /* codeset 6 */ - -#define SIN 0x01 /* service indicator */ -#define CIF 0x02 /* charging information */ -#define DATE 0x03 /* date */ -#define CPS 0x07 /* called party status */ - -/*------------------------------------------------------------------*/ -/* return code coding */ -/*------------------------------------------------------------------*/ - -#define UNKNOWN_COMMAND 0x01 /* unknown command */ -#define WRONG_COMMAND 0x02 /* wrong command */ -#define WRONG_ID 0x03 /* unknown task/entity id */ -#define WRONG_CH 0x04 /* wrong task/entity id */ -#define UNKNOWN_IE 0x05 /* unknown information el. */ -#define WRONG_IE 0x06 /* wrong information el. */ -#define OUT_OF_RESOURCES 0x07 /* card out of res. */ -#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ -#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ -#define ASSIGN_OK 0xef /* ASSIGN OK */ -#define OK_FC 0xfc /* Flow-Control RC */ -#define READY_INT 0xfd /* Ready interrupt */ -#define TIMER_INT 0xfe /* timer interrupt */ -#define OK 0xff /* command accepted */ +#undef N_DATA +#undef ID_MASK + +#include "pc.h" -/*------------------------------------------------------------------*/ +#define AOC_IND 26 /* Advice of Charge */ +#define PI 0x1e /* Progress Indicator */ +#define NI 0x27 /* Notification Indicator */ + +#define CALL_HOLD 0x22 +#define CALL_HOLD_ACK 0x24 /* defines for statectrl */ #define WAITING_FOR_HANGUP 0x01 #define HAVE_CONN_REQ 0x02 +#define IN_HOLD 0x04 typedef struct { char cpn[32]; @@ -242,26 +104,6 @@ } eicon_IND; typedef struct { - __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ - __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ - __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ - __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ - __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ - __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ - __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ - __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ - __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ - __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ - __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ - __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ - __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ - __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ - __u8 B[1]; /* buffer space for Req,Ind and Rc */ -} eicon_pr_ram; - -typedef struct { __u8 *Data; unsigned int Size; unsigned int Len; @@ -278,8 +120,9 @@ extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb); extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb); extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb); -extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que); +extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk); extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); +extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm); #ifdef CONFIG_ISDN_TTY_FAX extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan); extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_io.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_io.c Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. @@ -23,52 +23,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_io.c,v $ - * Revision 1.10 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.9 1999/11/18 20:55:25 armin - * Ready_Int fix of ISA cards. - * - * Revision 1.8 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.7 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.6 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.5 1999/08/31 11:20:11 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.4 1999/08/22 20:26:47 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.3 1999/08/18 20:17:01 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.2 1999/07/25 15:12:05 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.1 1999/03/29 11:19:45 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * */ #include #include "eicon.h" +#include "uxio.h" void eicon_io_rcv_dispatch(eicon_card *ccard) { @@ -85,12 +45,12 @@ while((skb = skb_dequeue(&ccard->rcvq))) { ind = (eicon_IND *)skb->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + spin_unlock_irqrestore(&eicon_lock, flags); if (DebugVar & 1) { switch(ind->Ind) { - case IDI_N_DISC_ACK: + case N_DISC_ACK: /* doesn't matter if this happens */ break; default: @@ -99,11 +59,10 @@ ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } } - restore_flags(flags); dev_kfree_skb(skb); continue; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (chan->e.complete) { /* check for rec-buffer chaining */ if (ind->MLength == ind->RBuffer.length) { @@ -119,12 +78,9 @@ } } else { - save_flags(flags); - cli(); if (!(skb2 = skb_dequeue(&chan->e.R))) { chan->e.complete = 1; eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n"); - restore_flags(flags); dev_kfree_skb(skb); continue; } @@ -133,7 +89,6 @@ GFP_ATOMIC); if (!skb_new) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n"); - restore_flags(flags); dev_kfree_skb(skb); dev_kfree_skb(skb2); continue; @@ -152,14 +107,12 @@ dev_kfree_skb(skb2); if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 2; - restore_flags(flags); idi_handle_ind(ccard, skb_new); continue; } else { chan->e.complete = 0; skb_queue_tail(&chan->e.R, skb_new); - restore_flags(flags); continue; } } @@ -181,242 +134,120 @@ /* - * IO-Functions for different card-types + * IO-Functions for ISA cards */ u8 ram_inb(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inb((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readb(addr)); - } - return(0); + return(readb(addr)); } u16 ram_inw(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inw((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readw(addr)); - } - return(0); + return(readw(addr)); } void ram_outb(eicon_card *card, void *adr, u8 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outb((u8)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writeb(data, addr); - break; - } + writeb(data, addr); } void ram_outw(eicon_card *card, void *adr , u16 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outw((u16)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writew(data, addr); - break; - } + writew(data, addr); } void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - writeb(ram_inb(card, adr + i), adrto + i); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_fromio(adrto, adr, len); - break; - } + memcpy_fromio(adrto, adr, len); } void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - ram_outb(card, adrto + i, readb(adr + i)); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_toio(adrto, adr, len); - break; - } + memcpy_toio(adrto, adr, len); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * XLOG + * IDI-Callback function */ -int -eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +void +eicon_idi_callback(ENTITY *de) { - int timeout, i; - int divas_shared_offset = 0; + eicon_card *ccard = (eicon_card *)de->R; + struct sk_buff *skb; + eicon_RC *ack; + eicon_IND *ind; int len = 0; - int stype = 0; - __u32 time = 0; - mi_pc_maint_t *pcm = &xlogreq->pcm; - eicon_pci_card *pci_card = &card->hwif.pci; - eicon_isa_card *isa_card = &card->hwif.isa; - eicon_pr_ram *prram = 0; - char *ram; - switch(card->type) { - case EICON_CTYPE_MAESTRAP: - ram = (char *)pci_card->PCIram; - prram = (eicon_pr_ram *)ram; - divas_shared_offset = DIVAS_SHARED_OFFSET; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_MAESTRA: - prram = 0; - divas_shared_offset = 0; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - case EICON_CTYPE_S2M: - prram = (eicon_pr_ram *)isa_card->shmem; - divas_shared_offset = 0xfb80; - len = sizeof(mi_pc_maint_t) - 78; - stype = 1; - break; - default: - return -ENODEV; - } - - memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t)); - - xlogreq->pcm.rc = 0; - xlogreq->pcm.req = 1; /* DO_LOG */ - - ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset; - - ram_outb(card, ram+1, pcm->rc); - ram_outb(card, ram+0, pcm->req); - - timeout = jiffies + 50; - while (timeout > jiffies) { - pcm->rc = ram_inb(card, ram+1); - pcm->req = ram_inb(card, ram+0); - if (!pcm->req) break; - SLEEP(10); - } - - if (pcm->req) { - return XLOG_ERR_TIMEOUT; - } - - if (pcm->rc != OK) { - return XLOG_ERR_DONE; - } - - ram_copyfromcard(card, pcm, ram, len); - - if (stype) { - for (i=0; i<8; i++) - ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i]; - time = (__u32)pcm->data.w[2] * 3600 * 1000 + - (__u32)pcm->data.w[1] * 1000 + - (__u32)pcm->data.b[1] * 20 + - (__u32)pcm->data.b[0] ; - pcm->data.w[1] = (__u16) (time >> 16); - pcm->data.w[2] = (__u16) (time & 0x0000ffff); - pcm->data.w[0] = 2; + if (de->complete == 255) { + /* Return Code */ + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = de->Rc; + if (de->Rc == ASSIGN_OK) { + ack->RcId = de->Id; + de->user[1] = de->Id; + } else { + ack->RcId = de->user[1]; + } + ack->RcCh = de->RcCh; + ack->Reference = de->user[0]; + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); + } + } else { + /* Indication */ + if (de->complete) { + len = de->RLength; + } else { + len = 270; + if (de->RLength <= 270) + eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n"); + } + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = de->Ind; + ind->IndId = de->user[1]; + ind->IndCh = de->IndCh; + ind->MInd = de->Ind; + ind->RBuffer.length = len; + ind->MLength = de->RLength; + memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); + } } - return XLOG_OK; + de->RNum = 0; + de->RNR = 0; + de->Rc = 0; + de->Ind = 0; } +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ /* * Transmit-Function */ void eicon_io_transmit(eicon_card *ccard) { - eicon_pci_card *pci_card; eicon_isa_card *isa_card; struct sk_buff *skb; struct sk_buff *skb2; unsigned long flags; - char *ram, *reg, *cfg; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_REQ *ReqOut = 0; @@ -426,10 +257,11 @@ int ReqCount; int scom = 0; int tmp = 0; + int tmpid = 0; int quloop = 1; int dlev = 0; + ENTITY *ep = 0; - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; if (!ccard) { @@ -451,20 +283,17 @@ prram = (eicon_pr_ram *)isa_card->shmem; break; #endif +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = (eicon_pr_ram *)ram; + scom = 2; + break; + case EICON_CTYPE_MAESTRAQ: + scom = 2; break; case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = 0; + scom = 2; break; +#endif default: eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n"); return; @@ -474,69 +303,91 @@ if (!(skb2 = skb_dequeue(&ccard->sndq))) quloop = 0; while(quloop) { - save_flags(flags); - cli(); - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + switch (scom) { + case 1: if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); ccard->ReadyInt++; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } - } else { + break; + case 0: if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } + break; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + chan2 = (eicon_chan_ptr *)skb2->data; chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); + reqbuf = (eicon_REQ *)skb->data; if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); } else { - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + + switch (scom) { + case 1: ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); - - } else { + break; + case 0: /* get address of next available request buffer */ ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); ram_outb(ccard, &ReqOut->Req, reqbuf->Req); + break; } + dlev = 160; + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ - if (scom) + switch (scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.D3Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); - + break; + case 2: + ep = &chan->de; + break; + } + tmpid = chan->e.D3Id; chan->e.ReqCh = 0; } else { /* Net Layer */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.B2Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); - + break; + case 2: + ep = &chan->be; + break; + } + tmpid = chan->e.B2Id; chan->e.ReqCh = 1; if (((reqbuf->Req & 0x0f) == 0x08) || ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ @@ -548,51 +399,106 @@ } else { /* It is an ASSIGN */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, reqbuf->ReqId); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + break; + case 2: + if (!reqbuf->Reference) + ep = &chan->de; + else + ep = &chan->be; + ep->Id = reqbuf->ReqId; + break; + } + tmpid = reqbuf->ReqId; if (!reqbuf->Reference) chan->e.ReqCh = 0; else chan->e.ReqCh = 1; } - if (scom) + + switch(scom) { + case 1: chan->e.ref = ccard->ref_out++; - else + break; + case 0: chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + break; + case 2: + chan->e.ref = chan->No; + break; + } chan->e.Req = reqbuf->Req; ReqCount++; - if (scom) + + switch (scom) { + case 1: ram_outb(ccard, &com->Req, reqbuf->Req); - else + break; + case 0: ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + break; + case 2: +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (!ep) break; + ep->callback = eicon_idi_callback; + ep->R = (BUFFERS *)ccard; + ep->user[0] = (word)chan->No; + ep->user[1] = (word)tmpid; + ep->XNum = 1; + ep->RNum = 0; + ep->RNR = 0; + ep->Rc = 0; + ep->Ind = 0; + ep->X->PLength = reqbuf->XBuffer.length; + memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ep->ReqCh = reqbuf->ReqCh; + ep->Req = reqbuf->Req; +#endif + break; + } chan->e.busy = 1; + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", - reqbuf->Req, - (scom) ? ram_inb(ccard, &com->ReqId) : - ram_inb(ccard, &ReqOut->ReqId), + reqbuf->Req, tmpid, reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (scom == 2) { + if (ep) { + ccard->d->request(ep); + if (ep->Rc) + eicon_idi_callback(ep); + } + } +#endif } - restore_flags(flags); dev_kfree_skb(skb); } dev_kfree_skb(skb2); } else { - skb_queue_tail(&ccard->sackq, skb2); - eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); + skb_queue_tail(&ccard->sackq, skb2); + eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); } - if (scom) - quloop = 0; - else - if (!(skb2 = skb_dequeue(&ccard->sndq))) + switch(scom) { + case 1: quloop = 0; + break; + case 0: + case 2: + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + break; + } } if (!scom) @@ -603,18 +509,14 @@ } } - +#ifdef CONFIG_ISDN_DRV_EICON_ISA /* * IRQ handler */ void eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { eicon_card *ccard = (eicon_card *)dev_id; - eicon_pci_card *pci_card; eicon_isa_card *isa_card; - char *ram = 0; - char *reg = 0; - char *cfg = 0; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_RC *RcIn; @@ -646,11 +548,9 @@ } } - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -664,23 +564,6 @@ prram = (eicon_pr_ram *)isa_card->shmem; irqprobe = &isa_card->irqprobe; break; -#endif - case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = (eicon_pr_ram *)ram; - break; - case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = 0; - break; default: eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n"); return; @@ -688,7 +571,6 @@ if (*irqprobe) { switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -706,26 +588,11 @@ } (*irqprobe)++; break; -#endif - case EICON_CTYPE_MAESTRAP: - if (readb(&ram[0x3fe])) { - writeb(0, &prram->RcOutput); - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - } - *irqprobe = 0; - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - *irqprobe = 0; - break; } return; } switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -736,20 +603,6 @@ return; } break; -#endif - case EICON_CTYPE_MAESTRAP: - if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; - case EICON_CTYPE_MAESTRA: - outw(0x3fe, pci_card->PCIreg + M_ADDR); - if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; } if (scom) { @@ -891,7 +744,6 @@ /* clear interrupt */ switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_QUADRO: writeb(0, isa_card->intack); writeb(0, &com[0x401]); @@ -902,19 +754,8 @@ case EICON_CTYPE_S2M: writeb(0, isa_card->intack); break; -#endif - case EICON_CTYPE_MAESTRAP: - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - outw(0x3fe, pci_card->PCIreg + M_ADDR); - outb(0, pci_card->PCIreg + M_DATA); - break; } return; } - +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_isa.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/eicon/eicon_isa.c Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -21,62 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.c,v $ - * Revision 1.14 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.13 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.12 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.11 1999/11/25 11:33:09 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * - * Revision 1.10 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.9 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.8 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.7 1999/08/22 20:26:48 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:06 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/04/01 12:48:33 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:46 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:19 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:43 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -87,7 +31,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.14 $"; +char *eicon_isa_revision = "$Revision: 1.16 $"; #undef EICON_MCA_DEBUG @@ -357,7 +301,7 @@ printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { tmp = eicon_addcard(card->type, card->physmem, card->irq, - ((eicon_card *)card->card)->regname); + ((eicon_card *)card->card)->regname, 0); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } return 0; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_isa.h linux/drivers/isdn/eicon/eicon_isa.h --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_isa.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_isa.h Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,38 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.h,v $ - * Revision 1.8 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.7 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.6 1999/11/15 19:37:04 keil - * need config.h - * - * Revision 1.5 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.4 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.3 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:46 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_isa_h @@ -138,7 +106,6 @@ unsigned char mvalid; /* Flag: Memory is valid */ unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card ist Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_isa_card; /* Offsets for special locations on standard cards */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_mod.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/eicon/eicon_mod.c Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_mod.c,v 1.35 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -9,8 +9,6 @@ * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. @@ -30,105 +28,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_mod.c,v $ - * Revision 1.25 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.24 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.23 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.22 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.21 1999/11/25 11:35:10 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * Minor cleanup. - * - * Revision 1.20 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.19 1999/11/12 13:21:44 armin - * Bugfix of undefined reference with CONFIG_MCA - * - * Revision 1.18 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.17 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.16 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.15 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.14 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.13 1999/09/04 17:37:59 armin - * Removed not used define, did not work and caused error - * in 2.3.16 - * - * Revision 1.12 1999/08/31 11:20:14 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.11 1999/08/29 17:23:45 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/28 21:32:53 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.9 1999/08/18 20:17:02 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:08 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:27 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:26 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/04/01 12:48:35 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:47 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:21 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ -#define DRIVERPATCH "" +#define DRIVERNAME "Eicon active ISDN driver" +#define DRIVERRELEASE "2.0" +#define DRIVERPATCH ".14" + #include #include @@ -139,17 +44,30 @@ #include "eicon.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ + +#undef N_DATA +#include "adapter.h" +#include "uxio.h" + #define INCLUDE_INLINE_FUNCS static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.25 $"; +static char *eicon_revision = "$Revision: 1.35 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; extern char *eicon_idi_revision; +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern void eicon_pci_init_conf(eicon_card *card); +void mod_inc_use_count(void); +void mod_dec_use_count(void); +extern char *file_check(void); + #ifdef MODULE #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif @@ -158,6 +76,11 @@ ulong DebugVar; +spinlock_t eicon_lock; + +DESCRIPTOR idi_d[16]; +int idi_dlength; + /* Parameters to be set by insmod */ #ifdef CONFIG_ISDN_DRV_EICON_ISA static int membase = -1; @@ -189,23 +112,6 @@ "DIVA Server PRI/PCI" }; -static int -getrel(char *p) -{ - int v = 0; - char *tmp = 0; - - if ((tmp = strchr(p, '.'))) - p = tmp + 1; - while (p[0] >= '0' && p[0] <= '9') { - v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0'); - p++; - } - return v; - - -} - static char * eicon_getrev(const char *revision) { @@ -229,68 +135,26 @@ return NULL; } +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * Free MSN list + * Find pcicard with given card number */ -static void -eicon_clear_msn(eicon_card *card) +static inline eicon_card * +eicon_findnpcicard(int driverid) { - struct msn_entry *p = card->msn_list; - struct msn_entry *q; - unsigned long flags; + eicon_card *p = cards; - save_flags(flags); - cli(); - card->msn_list = NULL; - restore_flags(flags); while (p) { - q = p->next; - kfree(p); - p = q; + if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) && + (p->bus == EICON_BUS_PCI)) + return p; + p = p->next; } + return (eicon_card *) 0; } - -/* - * Find an MSN entry in the list. - * If ia5 != 0, return IA5-encoded EAZ, else - * return a bitmask with corresponding bit set. - */ -static __u16 -eicon_find_msn(eicon_card *card, char *msn, int ia5) -{ - struct msn_entry *p = card->msn_list; - __u8 eaz = '0'; - - while (p) { - if (!strcmp(p->msn, msn)) { - eaz = p->eaz; - break; - } - p = p->next; - } - if (!ia5) - return (1 << (eaz - '0')); - else - return eaz; -} - -/* - * Find an EAZ entry in the list. - * return a string with corresponding msn. - */ -char * -eicon_find_eaz(eicon_card *card, char eaz) -{ - struct msn_entry *p = card->msn_list; - - while (p) { - if (p->eaz == eaz) - return(p->msn); - p = p->next; - } - return("\0"); -} - +#endif +#endif /* CONFIG_PCI */ static void eicon_rcv_dispatch(struct eicon_card *card) @@ -337,39 +201,18 @@ } } -static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq) -{ - xlogreq_t *xlr; - int ret_val; - - if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) { - eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n"); - return -ENOMEM; - } - if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - - ret_val = eicon_get_xlog(card, xlr); - - if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - kfree(xlr); - - return ret_val; -} - static int eicon_command(eicon_card * card, isdn_ctrl * c) { ulong a; eicon_chan *chan; eicon_cdef cdef; +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + dia_start_t dstart; +#endif +#endif isdn_ctrl cmd; - char tmp[17]; int ret = 0; unsigned long flags; @@ -383,16 +226,15 @@ case EICON_IOCTL_GETVER: return(EICON_CTRL_VERSION); case EICON_IOCTL_GETTYPE: + if (card->bus == EICON_BUS_PCI) { + copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int)); + } return(card->type); case EICON_IOCTL_GETMMIO: switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: return (int)card->hwif.isa.shmem; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.PCIram; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -433,10 +275,6 @@ case EICON_BUS_ISA: case EICON_BUS_MCA: return card->hwif.isa.irq; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.irq; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -514,7 +352,9 @@ case EICON_IOCTL_MANIF: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - if (!card->Feature & PROTCAP_MANIF) + if (!card->d) + return -ENODEV; + if (!card->d->features & DI_MANAGE) return -ENODEV; ret = eicon_idi_manage( card, @@ -522,49 +362,12 @@ return ret; case EICON_IOCTL_GETXLOG: - if (!card->flags & EICON_FLAGS_RUNNING) - return XLOG_ERR_CARD_STATE; - ret = eicon_xlog(card, (xlogreq_t *)a); - return ret; -#if CONFIG_PCI - case EICON_IOCTL_LOADPCI: - if (card->flags & EICON_FLAGS_RUNNING) - return -EBUSY; - if (card->bus == EICON_BUS_PCI) { - switch(card->type) { - case EICON_CTYPE_MAESTRA: - ret = eicon_pci_load_bri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - - case EICON_CTYPE_MAESTRAP: - ret = eicon_pci_load_pri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - } - if (!ret) { - card->flags |= EICON_FLAGS_LOADED; - card->flags |= EICON_FLAGS_RUNNING; - if (card->hwif.pci.channels > 1) { - cmd.command = ISDN_STAT_ADDCH; - cmd.driver = card->myid; - cmd.arg = card->hwif.pci.channels - 1; - card->interface.statcallb(&cmd); - } - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - return ret; - } else return -ENODEV; -#endif + return -ENODEV; + case EICON_IOCTL_ADDCARD: if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) return -EFAULT; - if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id))) + if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0))) return -EIO; return 0; case EICON_IOCTL_DEBUGVAR: @@ -574,11 +377,77 @@ #ifdef MODULE case EICON_IOCTL_FREEIT: while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT; - MOD_INC_USE_COUNT; + mod_inc_use_count(); return 0; #endif - default: + case EICON_IOCTL_LOADPCI: + eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n"); + eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n"); + eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n"); + return -EINVAL; + default: +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (c->arg < EICON_IOCTL_DIA_OFFSET) + return -EINVAL; + if (copy_from_user(&dstart, (char *)a, sizeof(dstart))) + return -1; + if (!(card = eicon_findnpcicard(dstart.card_id))) + return -EINVAL; + ret = do_ioctl(NULL, NULL, + c->arg - EICON_IOCTL_DIA_OFFSET, + (unsigned long) a); + if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { + if (card->type != EICON_CTYPE_MAESTRAQ) { + EtdM_DIDD_Read(idi_d, &idi_dlength); + card->d = &idi_d[idi_dlength - 1]; + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x, SerNo. %d)\n", + (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", + card->d->channels, card->d->features, card->d->serial); + } else { + int i; + EtdM_DIDD_Read(idi_d, &idi_dlength); + for(i = 3; i >= 0; i--) { + if (!(card = eicon_findnpcicard(dstart.card_id - i))) + return -EINVAL; + + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + card->d = &idi_d[idi_dlength - (i+1)]; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x, SerNo. %d)\n", + 4-i, card->d->channels, card->d->features, card->d->serial); + } + } + } + return ret; +#else return -EINVAL; +#endif +#endif /* CONFIG_PCI */ } break; case ISDN_CMD_DIAL: @@ -586,20 +455,15 @@ return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "Dial on channel %d with state %d\n", chan->No, chan->fsm_state); return -EBUSY; } - if (card->ptype == ISDN_PTYPE_EURO) - tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1); - else - tmp[0] = c->parm.setup.eazmsn[0]; chan->fsm_state = EICON_STATE_OCALL; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); ret = idi_connect_req(card, chan, c->parm.setup.phone, c->parm.setup.eazmsn, @@ -637,19 +501,7 @@ return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - if (strlen(c->parm.num)) { - if (card->ptype == ISDN_PTYPE_EURO) { - chan->eazmask = eicon_find_msn(card, c->parm.num, 0); - } - if (card->ptype == ISDN_PTYPE_1TR6) { - int i; - chan->eazmask = 0; - for (i = 0; i < strlen(c->parm.num); i++) - if (isdigit(c->parm.num[i])) - chan->eazmask |= (1 << (c->parm.num[i] - '0')); - } - } else - chan->eazmask = 0x3ff; + chan->eazmask = 0x3ff; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_CLREAZ: @@ -680,8 +532,10 @@ break; chan->l3prot = (c->arg >> 8); #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) + if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { chan->fax = c->parm.fax; + eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); + } #endif return 0; case ISDN_CMD_GETL3: @@ -706,10 +560,14 @@ eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n"); return 0; case ISDN_CMD_LOCK: - MOD_INC_USE_COUNT; +#ifdef MODULE + mod_inc_use_count(); +#endif return 0; case ISDN_CMD_UNLOCK: - MOD_DEC_USE_COUNT; +#ifdef MODULE + mod_dec_use_count(); +#endif return 0; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_CMD_FAXCMD: @@ -729,6 +587,23 @@ break; idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); return 0; + case CAPI_PUT_MESSAGE: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (c->parm.cmsg.Length < 8) + break; + switch(c->parm.cmsg.Command) { + case CAPI_FACILITY: + if (c->parm.cmsg.Subcommand == CAPI_REQ) + return(capipmsg(card, chan, &c->parm.cmsg)); + break; + case CAPI_MANUFACTURER: + default: + break; + } + return 0; } return -EINVAL; @@ -787,8 +662,7 @@ if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while((skb = skb_dequeue(&card->statq))) { if ((skb->len + count) > len) @@ -811,12 +685,12 @@ } else { skb_pull(skb, cnt); skb_queue_head(&card->statq, skb); - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } } card->statq_entries = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } printk(KERN_ERR @@ -848,7 +722,7 @@ } else #endif - ret = idi_send_data(card, chan, ack, skb, 1); + ret = idi_send_data(card, chan, ack, skb, 1, 1); return (ret); } else { return -ENODEV; @@ -895,12 +769,11 @@ return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); count = strlen(buf); skb = alloc_skb(count, GFP_ATOMIC); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); printk(KERN_ERR "eicon: could not alloc skb in putstatus\n"); return; } @@ -918,7 +791,7 @@ } else card->statq_entries++; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (count) { cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; @@ -967,7 +840,7 @@ * link it into cards-list. */ static void -eicon_alloccard(int Type, int membase, int irq, char *id) +eicon_alloccard(int Type, int membase, int irq, char *id, int card_id) { int i; int j; @@ -976,9 +849,6 @@ char qid[5]; #endif eicon_card *card; -#if CONFIG_PCI - eicon_pci_card *pcic; -#endif qloop = (Type == EICON_CTYPE_QUADRO)?2:0; for (i = 0; i <= qloop; i++) { @@ -1088,9 +958,9 @@ card->interface.channels = 1; break; #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRA: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1101,11 +971,26 @@ ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 2; + card->interface.channels = 1; + break; + + case EICON_CTYPE_MAESTRAQ: + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FCLASS2; + card->hwif.pci.card = (void *)card; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1114,7 +999,6 @@ break; case EICON_CTYPE_MAESTRAP: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1125,13 +1009,7 @@ ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIram = pcic->PCIram; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1139,6 +1017,7 @@ card->interface.channels = 1; break; #endif +#endif #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_ISABRI: if (membase == -1) @@ -1197,6 +1076,53 @@ skb_queue_head_init(&card->bch[j].e.X); skb_queue_head_init(&card->bch[j].e.R); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI + /* *** Diva Server *** */ + if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2 + , GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate DBUFFER-struct.\n", id); + kfree(card); + kfree(card->bch); + return; + } + if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERS-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + return; + } + if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + kfree(card->sbuf); + return; + } + for (j=0; j< (card->nchannels + 1); j++) { + memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER)); + card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j]; + memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS)); + card->bch[j].de.X = (BUFFERS *)&card->sbuf[j]; + memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbufp[j], 0, 270); + card->bch[j].de.X->P = (char *)&card->sbufp[j * 270]; + memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270); + card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270]; + } + /* *** */ +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ + card->next = cards; cards = card; } @@ -1220,10 +1146,7 @@ #endif /* CONFIG_MCA */ #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_printpar(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon_registercard: Illegal BUS type %d\n", @@ -1260,10 +1183,7 @@ break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_release(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon: Invalid BUS type %d\n", @@ -1295,13 +1215,17 @@ while((skb = skb_dequeue(&card->statq))) dev_kfree_skb(skb); - eicon_clear_msn(card); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + kfree(card->sbufp); + kfree(card->sbuf); + kfree(card->dbuf); +#endif kfree(card->bch); kfree(card); } int -eicon_addcard(int Type, int membase, int irq, char *id) +eicon_addcard(int Type, int membase, int irq, char *id, int card_id) { eicon_card *p; eicon_card *q = NULL; @@ -1314,7 +1238,7 @@ if ((Type = eicon_isa_find_card(membase, irq, id)) < 0) return 0; #endif - eicon_alloccard(Type, membase, irq, id); + eicon_alloccard(Type, membase, irq, id, card_id); p = cards; while (p) { registered = 0; @@ -1333,12 +1257,14 @@ break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI if (eicon_registercard(p)) break; registered = 1; break; #endif +#endif default: printk(KERN_ERR "eicon: addcard: Invalid BUS type %d\n", @@ -1371,8 +1297,6 @@ return (added - failed); } -#define DRIVERNAME "Eicon active ISDN driver" -#define DRIVERRELEASE "1" #ifdef MODULE #define eicon_init init_module @@ -1382,35 +1306,30 @@ eicon_init(void) { int card_count = 0; - int release = 0; char tmprev[50]; DebugVar = 1; + eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; printk(KERN_INFO "%s Rev: ", DRIVERNAME); strcpy(tmprev, eicon_revision); printk("%s/", eicon_getrev(tmprev)); - release += getrel(tmprev); strcpy(tmprev, eicon_pci_revision); -#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_isa_revision); #ifdef CONFIG_ISDN_DRV_EICON_ISA printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_idi_revision); printk("%s\n", eicon_getrev(tmprev)); - release += getrel(tmprev); - sprintf(tmprev,"%d", release); - printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev, DRIVERPATCH); + printk(KERN_INFO "%s Release: %s%s (%s)\n", DRIVERNAME, + DRIVERRELEASE, DRIVERPATCH, file_check()); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1427,18 +1346,23 @@ card_count++; }; #else - card_count = eicon_addcard(0, membase, irq, id); + card_count = eicon_addcard(0, membase, irq, id, 0); #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + DivasCardsDiscover(); card_count += eicon_pci_find_card(id); #endif +#endif + if (!cards) { #ifdef MODULE -#ifndef CONFIG_PCI +#ifndef CONFIG_ISDN_DRV_EICON_PCI #ifndef CONFIG_ISDN_DRV_EICON_ISA printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n"); + printk(KERN_INFO "Eicon: Driver not loaded !\n"); #else printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); #endif @@ -1451,17 +1375,47 @@ } else printk(KERN_INFO "Eicon: %d card%s added\n", card_count, (card_count>1)?"s":""); - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; return 0; } + #ifdef MODULE + +void mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +#ifdef CONFIG_ISDN_DRV_EICON_PCI +void EtdM_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#else +int DivasCardNext; +card_t DivasCards[1]; +#endif + void cleanup_module(void) { +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + card_t *pCard; + word wCardIndex; + extern int Divas_major; + int iTmp = 0; +#endif +#endif + eicon_card *card = cards; eicon_card *last; + while (card) { #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1481,6 +1435,54 @@ card = card->next; eicon_freecard(last); } + +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + for (iTmp = 0; iTmp < 3; iTmp++) + { + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + } + pCard++; + } + unregister_chrdev(Divas_major, "Divas"); +#endif +#endif /* CONFIG_PCI */ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } @@ -1675,7 +1677,7 @@ return ENODEV; }; /* matching membase & irq */ - if ( 1 == eicon_addcard(type, membase, irq, id)) { + if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_pci.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/isdn/eicon/eicon_pci.c Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -9,8 +9,6 @@ * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -25,53 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.c,v $ - * Revision 1.11 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.10 1999/08/22 20:26:49 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/11 21:01:11 keil - * new PCI codefix - * - * Revision 1.8 1999/08/10 16:02:20 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.7 1999/06/09 19:31:29 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.6 1999/04/01 12:48:37 armin - * Changed some log outputs. - * - * Revision 1.5 1999/03/29 11:19:49 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:48 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:24 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:06 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:45 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -80,896 +31,90 @@ #include "eicon.h" #include "eicon_pci.h" +#undef N_DATA +#include "adapter.h" +#include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.11 $"; +char *eicon_pci_revision = "$Revision: 1.15 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ - -#undef EICON_PCI_DEBUG +#ifdef CONFIG_ISDN_DRV_EICON_PCI int eicon_pci_find_card(char *ID) { - if (pci_present()) { - struct pci_dev *pdev = NULL; - int pci_nextindex=0, pci_cards=0, pci_akt=0; - int pci_type = PCI_MAESTRA; - int NoMorePCICards = FALSE; - char *ram, *reg, *cfg; - unsigned int pram=0, preg=0, pcfg=0; - char did[12]; - eicon_pci_card *aparms; - - if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) { - printk(KERN_WARNING - "eicon_pci: Could not allocate card-struct.\n"); - return 0; - } - - for (pci_cards = 0; pci_cards < 0x0f; pci_cards++) - { - do { - if ((pdev = pci_find_device(PCI_VENDOR_EICON, - pci_type, - pdev))) - { - pci_nextindex++; - break; - } - else { - pci_nextindex = 0; - switch (pci_type) /* switch to next card type */ - { - case PCI_MAESTRA: - pci_type = PCI_MAESTRAQ; break; - case PCI_MAESTRAQ: - pci_type = PCI_MAESTRAQ_U; break; - case PCI_MAESTRAQ_U: - pci_type = PCI_MAESTRAP; break; - default: - case PCI_MAESTRAP: - NoMorePCICards = TRUE; - } - } - } - while (!NoMorePCICards); - if (NoMorePCICards) - { - if (pci_cards < 1) { - printk(KERN_INFO "Eicon: No supported PCI cards found.\n"); - kfree(aparms); - return 0; - } - else - { - printk(KERN_INFO "Eicon: %d PCI card%s registered.\n", - pci_cards, (pci_cards > 1) ? "s":""); - kfree(aparms); - return (pci_cards); - } - } - - pci_enable_device(pdev); /* XXX handle error return */ - - pci_akt = 0; - switch(pci_type) - { - case PCI_MAESTRA: - printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRA; - - aparms->irq = pdev->irq; - preg = pci_resource_start(pdev, 2); - pcfg = pci_resource_start(pdev, 1); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg); -#endif - pci_akt = 1; - break; + int pci_cards = 0; + int card_id = 0; + int had_q = 0; + int ctype = 0; + char did[20]; + card_t *pCard; + word wCardIndex; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n"); - pci_cards--; - pci_akt = 0; - break; - - case PCI_MAESTRAP: - printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ - aparms->irq = pdev->irq; - pram = pci_resource_start(pdev, 0); - preg = pci_resource_start(pdev, 2); - pcfg = pci_resource_start(pdev, 4); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: ram=0x%x\n", - (pram)); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", - (preg)); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", - (pcfg)); -#endif - pci_akt = 1; - break; - default: - printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n"); - pci_cards--; - pci_akt = 0; - break; - } - - if (pci_akt) { - /* remapping memory */ - switch(pci_type) + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) { - case PCI_MAESTRA: - aparms->PCIreg = (unsigned int) preg; - aparms->PCIcfg = (unsigned int) pcfg; - if (check_region((aparms->PCIreg), 0x20)) { - printk(KERN_WARNING "eicon_pci: reg port already in use !\n"); - aparms->PCIreg = 0; - break; - } else { - request_region(aparms->PCIreg, 0x20, "eicon reg"); - } - if (check_region((aparms->PCIcfg), 0x80)) { - printk(KERN_WARNING "eicon_pci: cfg port already in use !\n"); - aparms->PCIcfg = 0; - release_region(aparms->PCIreg, 0x20); - break; - } else { - request_region(aparms->PCIcfg, 0x80, "eicon cfg"); + switch(pCard->hw->card_type) { + case DIA_CARD_TYPE_DIVA_SERVER: + ctype = EICON_CTYPE_MAESTRAP; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_B: + ctype = EICON_CTYPE_MAESTRA; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_Q: + ctype = EICON_CTYPE_MAESTRAQ; + if (!had_q) + card_id++; + if (++had_q >=4) + had_q = 0; + break; + default: + printk(KERN_ERR "eicon_pci: unknown card type %d !\n", + pCard->hw->card_type); + goto err; } - break; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - case PCI_MAESTRAP: - aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000); - ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET); - reg = ioremap(preg, 0x4000); - cfg = ioremap(pcfg, 0x1000); - aparms->PCIram = (unsigned int) ram; - aparms->PCIreg = (unsigned int) reg; - aparms->PCIcfg = (unsigned int) cfg; - break; - } - if ((!aparms->PCIreg) || (!aparms->PCIcfg)) { - printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; - } else { - aparms->mvalid = 1; - sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); - - printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did); - - if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) { + if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) { printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; + } else { + pci_cards++; + printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", + eicon_ctype_name[ctype], did, card_id); } +err: } + pCard++; } - - } - } else - printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n"); - return 0; -} - -/* - * Checks protocol file id for "F#xxxx" string fragment to - * extract the features, supported by this protocol version. - * binary representation of the feature string value is returned - * in *value. The function returns 0 if feature string was not - * found or has a wrong format, else 1. - */ -static int GetProtFeatureValue(char *sw_id, int *value) -{ - __u8 i, offset; - - while (*sw_id) - { - if ((sw_id[0] == 'F') && (sw_id[1] == '#')) - { - sw_id = &sw_id[2]; - for (i=0, *value=0; i<4; i++, sw_id++) - { - if ((*sw_id >= '0') && (*sw_id <= '9')) - { - offset = '0'; - } - else if ((*sw_id >= 'A') && (*sw_id <= 'F')) - { - offset = 'A' + 10; - } - else if ((*sw_id >= 'a') && (*sw_id <= 'f')) - { - offset = 'a' + 10; - } - else - { - return 0; - } - *value |= (*sw_id - offset) << (4*(3-i)); - } - return 1; - } - else - { - sw_id++; - } - } - return 0; -} - - -void -eicon_pci_printpar(eicon_pci_card *card) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->PCIreg, - (unsigned int)card->PCIcfg, - card->irq); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - printk(KERN_INFO "%s at 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->shmem, - card->irq); -#ifdef EICON_PCI_DEBUG - printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram); - printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg); - printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); -#endif - break; - } -} - - -static void -eicon_pci_release_shmem(eicon_pci_card *card) { - if (!card->master) - return; - if (card->mvalid) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - /* reset board */ - outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */ - outb(0, card->PCIreg + M_RESET); - SLEEP(20); - outb(0, card->PCIreg + M_ADDRH); - outw(0, card->PCIreg + M_ADDR); - outw(0, card->PCIreg + M_DATA); - - release_region(card->PCIreg, 0x20); - release_region(card->PCIcfg, 0x80); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - iounmap((void *)card->shmem); - iounmap((void *)card->PCIreg); - iounmap((void *)card->PCIcfg); - break; - } - } - card->mvalid = 0; -} - -static void -eicon_pci_release_irq(eicon_pci_card *card) { - if (!card->master) - return; - if (card->ivalid) - free_irq(card->irq, card); - card->ivalid = 0; + return pci_cards; } void -eicon_pci_release(eicon_pci_card *card) { - eicon_pci_release_irq(card); - eicon_pci_release_shmem(card); -} - -/* - * Upload buffer content to adapters shared memory - * on verify error, 1 is returned and a message is printed on screen - * else 0 is returned - * Can serve IO-Type and Memory type adapters - */ -int eicon_upload(t_dsp_download_space *p_para, - __u16 length, /* byte count */ - __u8 *buffer, - int verify) -{ - __u32 i, dwdata = 0, val = 0, timeout; - __u16 data; - eicon_pci_boot *boot = 0; - - switch (p_para->type) /* actions depend on type of union */ - { - case DL_PARA_IO_TYPE: - for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */ - outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); - } - if (verify) /* check written block */ - { - for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - data = inw(p_para->dat.io.ioDATA); - if (data != *(u16 *)&buffer[i]) - { - p_para->dat.io.r3addr += i; - p_para->dat.io.BadData = data; - p_para->dat.io.GoodData = *(u16 *)&buffer[i]; - return 1; - } - } - } - break; - - case DL_PARA_MEM_TYPE: - boot = p_para->dat.mem.boot; - writel(p_para->dat.mem.r3addr, &boot->addr); - for (i=0; i> 2], &boot->data[i]); - } - if (verify) /* check written block */ - { - for (i=0; idata[i]); - if (((u32 *)buffer)[i >> 2] != dwdata) - { - p_para->dat.mem.r3addr += i; - p_para->dat.mem.BadData = dwdata; - p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2]; - return 1; - } - } - } - writel(((length + 3) / 4), &boot->len); /* len in dwords */ - writel(2, &boot->cmd); - - timeout = jiffies + 20; - while (timeout > jiffies) { - val = readl(&boot->cmd); - if (!val) break; - SLEEP(2); - } - if (val) - { - p_para->dat.mem.timeout = 1; - return 1; - } - break; - } - return 0; -} - - -/* show header information of code file */ -static -int eicon_pci_print_hdr(unsigned char *code, int offset) +eicon_pci_init_conf(eicon_card *card) { - unsigned char hdr[80]; - int i, fvalue = 0; - - i = 0; - while ((i < (sizeof(hdr) -1)) - && (code[offset + i] != '\0') - && (code[offset + i] != '\r') - && (code[offset + i] != '\n')) - { - hdr[i] = code[offset + i]; - i++; - } - hdr[i] = '\0'; - printk(KERN_DEBUG "Eicon: loading %s\n", hdr); - if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue); - else return(0); -} - + int j; -/* - * Configure a card, download code into BRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - int i,j; - int timeout; - unsigned int offset, offp=0, size, length; - int signature = 0; - int FeatureValue = 0; - eicon_pci_codebuf cbuf; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - unsigned char *code; - unsigned int reg; - unsigned int cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - reg = card->PCIreg; - cfg = card->PCIcfg; - - /* reset board */ - outb(0, reg + M_RESET); - SLEEP(10); - outb(0, reg + M_ADDRH); - outw(0, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card\n"); -#endif + /* initializing some variables */ + card->ReadyInt = 0; - /* clear shared memory */ - outb(0xff, reg + M_ADDRH); - outw(0, reg + M_ADDR); - for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA); - SLEEP(10); + for(j = 0; j < 256; j++) + card->IdTable[j] = NULL; -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: clear shared memory\n"); -#endif - - /* download protocol and dsp file */ - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_IO_TYPE; - dl_para.dat.io.ioADDR = reg + M_ADDR; - dl_para.dat.io.ioADDRH = reg + M_ADDRH; - dl_para.dat.io.ioDATA = reg + M_DATA; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j == 0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - offset = 0; - - if (j == 0) dl_para.dat.io.r3addr = 0; - if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32); - - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - kfree(code); - return -EIO; - } - /* move onto next block */ - offset += length; - dl_para.dat.io.r3addr += length; - } while (offset < size); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset); -#endif - offp += size; + for(j = 0; j < (card->d->channels + 1); j++) { + card->bch[j].e.busy = 0; + card->bch[j].e.D3Id = 0; + card->bch[j].e.B2Id = 0; + card->bch[j].e.ref = 0; + card->bch[j].e.Req = 0; + card->bch[j].e.complete = 1; + card->bch[j].fsm_state = EICON_STATE_NULL; } - kfree(code); - - /* clear signature */ - outb(0xff, reg + M_ADDRH); - outw(0x1e, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* copy configuration data into shared memory */ - outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA); - outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA); - outw(10,reg + M_ADDR); outb(0, reg + M_DATA); - outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA); - outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA); - outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */ - outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA); - outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA); - outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */ - outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */ - outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA); - outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA); - outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA); - outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA); - - for (i=0;i<32;i++) - { - outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA); - outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA); - outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA); - outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA); - outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA); - outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA); - } - -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: starting CPU...\n"); -#endif - /* let the CPU run */ - outw(0x08, reg + M_RESET); - - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - outw(0x1e, reg + M_ADDR); - signature = inw(reg + M_DATA); - if (signature == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if (signature != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - outb(0xff, reg + M_ADDRH); - outw(0x3f6, reg + M_ADDR); - card->channels = inw(reg + M_DATA); - card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - /* Trigger an interrupt and check if it is delivered */ - outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */ - outb(0x89, reg + M_RESET); /* place int request */ - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(5); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; } - -/* - * Configure a card, download code into PRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - eicon_pci_boot *boot; - eicon_pr_ram *prram; - int i,j; - int timeout; - int FeatureValue = 0; - unsigned int offset, offp=0, size, length; - unsigned long int signature = 0; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - eicon_pci_codebuf cbuf; - unsigned char *code; - unsigned char req_int; - char *ram, *reg, *cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - boot = &card->shmem->boot; - ram = (char *)card->PCIram; - reg = (char *)card->PCIreg; - cfg = (char *)card->PCIcfg; - prram = (eicon_pr_ram *)ram; - - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - /* set command count to 0 */ - writel(0, &boot->reserved); - - /* check if CPU increments the life word */ - i = readw(&boot->live); - SLEEP(20); - if (i == readw(&boot->live)) { - printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n"); -#endif - - /* download firmware : DSP and Protocol */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); #endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_MEM_TYPE; - dl_para.dat.mem.boot = boot; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j==0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */ - - if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR; - if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32); - - offset = 0; - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - if (dl_para.dat.mem.timeout == 0) - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - else - printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n"); - kfree(code); - return -EIO; - } - - /* move onto next block */ - offset += length; - dl_para.dat.mem.r3addr += length; - } while (offset < size); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* initialize the adapter data structure */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* clear out config space */ - for (i = 0; i < 256; i++) writeb(0, &ram[i]); - - /* copy configuration down to the card */ - writeb(cbuf.tei, &ram[8]); - writeb(cbuf.nt2, &ram[9]); - writeb(0, &ram[10]); - writeb(cbuf.WatchDog, &ram[11]); - writeb(cbuf.Permanent, &ram[12]); - writeb(cbuf.XInterface, &ram[13]); - writeb(cbuf.StableL2, &ram[14]); - writeb(cbuf.NoOrderCheck, &ram[15]); - writeb(cbuf.HandsetType, &ram[16]); - writeb(0, &ram[17]); - writeb(cbuf.LowChannel, &ram[18]); - writeb(cbuf.ProtVersion, &ram[19]); - writeb(cbuf.Crc4, &ram[20]); - for (i = 0; i < 32; i++) - { - writeb(cbuf.l[0].oad[i], &ram[32 + i]); - writeb(cbuf.l[0].osa[i], &ram[64 + i]); - writeb(cbuf.l[0].spid[i], &ram[96 + i]); - writeb(cbuf.l[1].oad[i], &ram[128 + i]); - writeb(cbuf.l[1].osa[i], &ram[160 + i]); - writeb(cbuf.l[1].spid[i], &ram[192 + i]); - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: configured card OK\n"); -#endif - - /* start adapter */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: tell card to start...\n"); -#endif - writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */ - writel(3, &boot->cmd); /* DIVAS_START_CMD */ - - /* wait till card ACKs */ - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - signature = readl(&boot->signature); - if ((signature >> 16) == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if ((signature >> 16) != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - card->channels = readb(&ram[0x3f6]); - card->serial = readl(&ram[0x3f0]); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - readb(&ram[0x3fe]); - writeb(0, &ram[0x3fe]); /* reset any pending interrupt */ - readb(&ram[0x3fe]); - - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - - req_int = readb(&prram->ReadyInt); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - req_int++; - /* Trigger an interrupt and check if it is delivered */ - writeb(req_int, &prram->ReadyInt); - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(2); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; -} - #endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/eicon_pci.h linux/drivers/isdn/eicon/eicon_pci.h --- v2.4.0-test6/linux/drivers/isdn/eicon/eicon_pci.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_pci.h Sun Aug 13 10:05:32 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * @@ -19,26 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.h,v $ - * Revision 1.4 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.3 1999/03/29 11:19:51 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:50 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:46 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_pci_h @@ -46,147 +26,20 @@ #ifdef __KERNEL__ - -#define PCI_VENDOR_EICON 0x1133 -#define PCI_DIVA_PRO20 0xe001 /* Not supported */ -#define PCI_DIVA20 0xe002 /* Not supported */ -#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */ -#define PCI_DIVA20_U 0xe004 /* Not supported */ -#define PCI_MAESTRA 0xe010 -#define PCI_MAESTRAQ 0xe012 -#define PCI_MAESTRAQ_U 0xe013 -#define PCI_MAESTRAP 0xe014 - -#define DIVA_PRO20 1 -#define DIVA20 2 -#define DIVA_PRO20_U 3 -#define DIVA20_U 4 -#define MAESTRA 5 -#define MAESTRAQ 6 -#define MAESTRAQ_U 7 -#define MAESTRAP 8 - -#define TRUE 1 -#define FALSE 0 - -#define DIVAS_SIGNATURE 0x4447 - - -/* MAESTRA BRI PCI */ - -#define M_RESET 0x10 /* offset of reset register */ -#define M_DATA 0x00 /* offset of data register */ -#define M_ADDR 0x04 /* offset of address register */ -#define M_ADDRH 0x0c /* offset of high address register */ - -#define M_DSP_CODE_LEN 0xbf7d0000 -#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */ -#define M_DSP_CODE_BASE 0xbf7a0000 -#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */ - - - -/* MAESTRA PRI PCI */ - -#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */ - -#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */ -#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */ - -#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */ -#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */ -#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ -#define MP_DSP_CODE_BASE 0xa03a0000 -#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */ - -#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */ - -/* RESET register bits */ -#define _MP_S2M_RESET 0x10 /* active lo */ -#define _MP_LED2 0x08 /* 1 = on */ -#define _MP_LED1 0x04 /* 1 = on */ -#define _MP_DSP_RESET 0x02 /* active lo */ -#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */ - -/* boot interface structure */ -typedef struct { - __u32 cmd __attribute__ ((packed)); - __u32 addr __attribute__ ((packed)); - __u32 len __attribute__ ((packed)); - __u32 err __attribute__ ((packed)); - __u32 live __attribute__ ((packed)); - __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed)); - __u32 signature __attribute__ ((packed)); - __u8 data[1]; /* real interface description */ -} eicon_pci_boot; - - -#define DL_PARA_IO_TYPE 0 -#define DL_PARA_MEM_TYPE 1 - -typedef struct tag_dsp_download_space -{ - __u16 type; /* see definitions above to differ union elements */ - union - { - struct - { - __u32 r3addr; - __u16 ioADDR; - __u16 ioADDRH; - __u16 ioDATA; - __u16 BadData; /* in case of verify error */ - __u16 GoodData; - } io; /* for io based adapters */ - struct - { - __u32 r3addr; - eicon_pci_boot *boot; - __u32 BadData; /* in case of verify error */ - __u32 GoodData; - __u16 timeout; - } mem; /* for memory based adapters */ - } dat; -} t_dsp_download_space; - - -/* Shared memory */ -typedef union { - eicon_pci_boot boot; -} eicon_pci_shmem; - /* * card's description */ typedef struct { - int ramsize; int irq; /* IRQ */ - unsigned int PCIram; - unsigned int PCIreg; - unsigned int PCIcfg; - long int serial; /* Serial No. */ int channels; /* No. of supported channels */ void* card; - eicon_pci_shmem* shmem; /* Shared-memory area */ - unsigned char* intack; /* Int-Acknowledge */ - unsigned char* stopcpu; /* Writing here stops CPU */ - unsigned char* startcpu; /* Writing here starts CPU */ unsigned char type; /* card type */ - unsigned char irqprobe; /* Flag: IRQ-probing */ - unsigned char mvalid; /* Flag: Memory is valid */ - unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card is Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_pci_card; - - -extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern void eicon_pci_release(eicon_pci_card *card); -extern void eicon_pci_printpar(eicon_pci_card *card); extern int eicon_pci_find_card(char *ID); #endif /* __KERNEL__ */ #endif /* eicon_pci_h */ + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/fcheck.c linux/drivers/isdn/eicon/fcheck.c --- v2.4.0-test6/linux/drivers/isdn/eicon/fcheck.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/fcheck.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,31 @@ +/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $ + * + * (c) 2000 Cytronics & Melware + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/README.eicon + * + * + */ + +#include + +char * +file_check(void) { + +#ifdef FILECHECK +#if FILECHECK == 0 + return("verified"); +#endif +#if FILECHECK == 1 + return("modified"); +#endif +#if FILECHECK == 127 + return("verification failed"); +#endif +#else + return("not verified"); +#endif +} + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/fourbri.c linux/drivers/isdn/eicon/fourbri.c --- v2.4.0-test6/linux/drivers/isdn/eicon/fourbri.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/fourbri.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,583 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.7 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Diva Server 4BRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" +#include "constant.h" +#include "adapter.h" +#include "uxio.h" + +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for 4BRI card */ +#define MQ_BOARD_DSP_OFFSET 0x00a00000 +#define MQ_DSP1_ADDR_OFFSET 0x00000008 +#define MQ_DSP_JUNK_OFFSET 0x00000400 +#define MQ_DSP1_DATA_OFFSET 0x00000000 +#define MQ_BOARD_ISAC_DSP_RESET 0x00800028 +#define MQ_BREG_RISC 0x1200 /* RISC Reset */ +#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */ +#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */ +#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */ +#define MQ_IRQ_REQ_ON 0x1 +#define MQ_IRQ_REQ_OFF 0x0 +#define MQ_BREG_IRQ_TEST 0x0608 +#define PLX9054_INTCSR 0x69 +#define PLX9054_INT_ENA 0x09 + +#define DIVAS_IOBASE 0x01 +#define M_PCI_RESET 0x10 + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg); +int fourbri_ISR (card_t* card); + +int FPGA_Download(word, dword, byte *, byte *, int); +extern byte FPGA_Bytes[]; +extern void *get_card(int); + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +word GetProtFeatureValue(char *sw_id); + +void memcp(byte *dst, byte *src, dword dwLen); +int memcm(byte *dst, byte *src, dword dwLen); + +static int diva_server_4bri_reset(card_t *card) +{ + byte *ctl; + + DPRINTF(("divas: reset Diva Server 4BRI")); + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + /* stop RISC, DSP's and ISAC */ + UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0); + UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0); + + UxCardMemDetach(card->hw, ctl); + + return 0; +} + +static int diva_server_4bri_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server 4BRI")); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardMemOut(card->hw, &shared[22], 4); + } + else + { + UxCardMemOut(card->hw, &shared[22], 0); + } + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_4bri_reset_int(card_t *card) +{ + byte *ctl; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + + UxCardMemDetach(card->hw, ctl); + + return; +} + + +static int diva_server_4bri_test_int(card_t *card) +{ + byte *ctl, i; + byte *reg; + + DPRINTF(("divas: test interrupt for Diva Server 4BRI")); + + /* We get the last (dummy) adapter in so we need to go back to the first */ + + card = get_card(card->cfg.card_id - 3); + + /* Enable interrupts on PLX chip */ + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA); + + UxCardMemDetach(card->hw, reg); + + /* Set the test interrupt flag */ + card->test_int_pend = TEST_INT_DIVAS_Q; + + /* Now to trigger the interrupt */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON); + + UxCardMemDetach(card->hw, ctl); + + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + if (card->test_int_pend) + { + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_4bri_load(card_t *card, dia_load_t *load) +{ + byte *pRAM=NULL; + int download_offset=0; + card_t *FirstCard; + byte sw_id[80]; + + DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id)); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + download_offset = 0; // Protocol code written to offset 0 + pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC); + + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword); + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword); + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_FPGA_CODE: + DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length)); + if (FPGA_Download(IDI_ADAPTER_MAESTRAQ, + card->hw->io_base, + sw_id, + load->code, + load->length + ) == -1) + { + DPRINTF(("divas: FPGA download failed")); + return -1; + } + + /* NOW reset the 4BRI */ + diva_server_4bri_reset(card); + return 0; // No need for anything further loading + + default: + DPRINTF(("divas: unknown code type")); + return -1; + } + + memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length); + + { + int mism_off; + if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length))) + { + DPRINTF(("divas: memory mismatch at offset %d", mism_off)); + UxCardMemDetach(card->hw, pRAM); + return -1; + } + } + + UxCardMemDetach(card->hw, pRAM); + + return 0; +} + +static int diva_server_4bri_start(card_t *card, byte *channels) +{ + byte *ctl; + byte *shared, i; + int adapter_num; + + DPRINTF(("divas: start Diva Server 4BRI")); + *channels = 0; + card->is_live = FALSE; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK); + + UxPause(2); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK); + + UxPause(10); + + UxCardMemDetach(card->hw, ctl); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for ( i = 0 ; i < 300 ; ++i ) + { + UxPause (10) ; + + if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 ) + { + DPRINTF(("divas: Protocol startup time %d.%02d seconds", + (i / 100), (i % 100) )); + + break; + } + } + + if (i==300) + { + DPRINTF(("divas: Timeout starting card")); + DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E]))); + + UxCardMemDetach(card->hw, shared); + return -1; + } + + UxCardMemDetach(card->hw, shared); + + for (adapter_num=3; adapter_num >= 0; adapter_num--) + { + card_t *qbri_card; + + qbri_card = get_card(card->cfg.card_id - adapter_num); + + if (qbri_card) + { + qbri_card->is_live = TRUE; + shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY); + *channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]); + UxCardMemDetach(qbri_card->hw, shared); + } + else + { + DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id)); + } + } + + diva_server_4bri_test_int(card); + + return 0; +} + +static +int diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise 4BRI specific entry points + */ + +int Divas4BriInit(card_t *card, dia_card_t *cfg) +{ +// byte sw_id[80]; +// extern int FPGA_Done; + + DPRINTF(("divas: initialise Diva Server 4BRI")); + + if (Divas4BRIInitPCI(card, cfg) == -1) + { + return -1; + } + + /* Need to download the FPGA */ +/* if (!FPGA_Done) + { + int retVal; + + retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ, + cfg->io_base, + sw_id, + FPGA_Bytes + ); + if(retVal==-1) + { + + DPRINTF(("divas: FPGA Download Failed")); + return -1; + + } + FPGA_Done = 1; + } */ + + card->card_reset = diva_server_4bri_reset; + card->card_load = diva_server_4bri_load; + card->card_config = diva_server_4bri_config; + card->card_start = diva_server_4bri_start; + card->reset_int = diva_server_4bri_reset_int; + card->card_mem_get = diva_server_4bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = fourbri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + +void memcp(byte *dst, byte *src, dword dwLen) +{ + while (dwLen) + { + *dst = *src; + dst++; src++; + dwLen--; + } +} + +int memcm(byte *dst, byte *src, dword dwLen) +{ + int offset = 0; + + while (offset < dwLen) + { + if(*dst != *src) + return (offset+1); + + offset++; + src++; + dst++; + } + + return 0; +} + + + +/*int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +}*/ + + +int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *ctl; + byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + UxCardMemDetach(card->hw, ctl); + } + + UxCardMemDetach(card->hw, reg); + return (served != 0); +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/fpga.c linux/drivers/isdn/eicon/fpga.c --- v2.4.0-test6/linux/drivers/isdn/eicon/fpga.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/fpga.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,158 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "uxio.h" + +#define FPGA_PORT 0x6E +#define FPGA_DLOAD_BUFLEN 256 +#define NAME_OFFSET 0x10 +#define NAME_MAXLEN 12 +#define DATE_OFFSET 0x2c +#define DATE_MAXLEN 10 + +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); +void UxPause(long int); + +/*-------------------------------------------------------------------------*/ +/* Loads the FPGA configuration file onto the hardware. */ +/* Function returns 0 on success, else an error number. */ +/* On success, an identifier string is returned in the buffer */ +/* */ +/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream */ +/* file and a file read function has to be provided by the operating */ +/* system part. */ +/* ----------------------------------------------------------------------- */ +int FPGA_Download( word cardtype, + dword RegBase, + byte *strbuf, + byte FPGA_SRC[], + int FPGA_LEN + ) +{ + word i, j, k; + word baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN; + dword addr; + byte *pFPGA; + + //--- check for legal cardtype + switch (cardtype) + { + case IDI_ADAPTER_MAESTRAQ: + addr = RegBase ; // address where to access FPGA + Mask_PROGRAM = 0x0001; // FPGA pins at address + Mask_DONE = 0x0002; + Mask_CCLK = 0x0100; + Mask_DIN = 0x0400; + baseval = 0x000d; // PROGRAM hi, CCLK lo, DIN lo by default + break; + + default: + + DPRINTF(("divas: FPGA Download ,Illegal Card")); + return -1; // illegal card + } + + //--- generate id string from file content + for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k++] = ' '; + for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k] = 0; + + DPRINTF(("divas: FPGA Download - %s", strbuf)); + + //--- prepare download, Pulse PROGRAM pin down. + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM); // PROGRAM low pulse + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // release + UxPause(50); // wait until FPGA finised internal memory clear + + //--- check done pin, must be low + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL")); + return -1; + } + + pFPGA = FPGA_SRC; + + i = 0; + /* Move past the header */ + while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) + { + i++; + } + + // We've hit the 0xFF so move on to the next byte + // i++; + DPRINTF(("divas: FPGA Code starts at offset %d", i)); + + //--- put data onto the FPGA + for (;i>j)) baseval |= Mask_DIN; // write a hi + else baseval &=~Mask_DIN; // write a lo + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + } + + //--- add some additional startup clock cycles and check done pin + for (i=0; i<5; i++) + { + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + + UxPause(100); + + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA download successful")); + } + else + { + DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT))); + return -1; + } + +return 0; +} + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/idi.c linux/drivers/isdn/eicon/idi.c --- v2.4.0-test6/linux/drivers/isdn/eicon/idi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/idi.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,870 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.8 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Core driver for Diva Server cards + * Implements the IDI interface + */ + +#include "idi.h" +#include "adapter.h" +#include "pc.h" +#include "pr_pc.h" +#include "sys.h" +#include "uxio.h" + +/* IDI request functions */ + +static void request(card_t *card, ENTITY *e); + +static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); } +static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); } +static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); } +static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); } +static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); } +static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); } +static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); } +static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); } +static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); } +static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); } +static void req_10(ENTITY *e) { request(&DivasCards[10], e); } +static void req_11(ENTITY *e) { request(&DivasCards[11], e); } +static void req_12(ENTITY *e) { request(&DivasCards[12], e); } +static void req_13(ENTITY *e) { request(&DivasCards[13], e); } +static void req_14(ENTITY *e) { request(&DivasCards[14], e); } +static void req_15(ENTITY *e) { request(&DivasCards[15], e); } + +IDI_CALL DivasIdiRequest[16] = +{ + &req_0, &req_1, &req_2, &req_3, + &req_4, &req_5, &req_6, &req_7, + &req_8, &req_9, &req_10, &req_11, + &req_12, &req_13, &req_14, &req_15 +}; + +#define PR_RAM ((struct pr_ram *)0) +#define RAM ((struct dual *)0) + +/*------------------------------------------------------------------*/ +/* local function prototypes */ +/*------------------------------------------------------------------*/ + +static byte isdn_rc(ADAPTER *, byte, byte, byte, word); +static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word); + +/* + * IDI related functions + */ + +static +ENTITY *entity_ptr(ADAPTER *a, byte e_no) +{ + card_t *card; + + card = a->io; + + return card->e_tbl[e_no].e; +} + +static +void CALLBACK(ADAPTER *a, ENTITY *e) +{ + card_t *card = a->io; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, FALSE); + } + + (*e->callback)(e); +} + +static +void *PTR_P(ADAPTER *a, ENTITY *e, void *P) +{ + return(P); +} + +static +void *PTR_R(ADAPTER *a, ENTITY *e) +{ + return((void*)e->R); +} + +static +void *PTR_X(ADAPTER *a, ENTITY *e) +{ + return((void*)e->X); +} + +static +void free_entity(ADAPTER *a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].e = NULL; + card->e_count--; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +void assign_queue(ADAPTER * a, byte e_no, word ref) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].assign_ref = ref; + card->e_tbl[e_no].next = card->assign; + card->assign = e_no; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte get_assign(ADAPTER *a, word ref) +{ + card_t *card; + byte e_no; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + e_no = (byte)card->assign; + while (e_no) + { + if (card->e_tbl[e_no].assign_ref == ref) + { + break; + } + e_no = card->e_tbl[e_no].next; + } + + UxCardUnlock(card->hw, ipl); + + return e_no; +} + +static +void req_queue(ADAPTER * a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].next = 0; + + if (card->e_head) + { + card->e_tbl[card->e_tail].next = e_no; + card->e_tail = e_no; + } + else + { + card->e_head = e_no; + card->e_tail = e_no; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte look_req(ADAPTER * a) +{ + card_t *card; + + card = a->io; + + return(card->e_head); +} + +static +void next_req(ADAPTER * a) +{ + card_t *card; + int ipl; + + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_head = card->e_tbl[card->e_head].next; + if (!card->e_head) + { + card->e_tail = 0; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + + +/* + * IDI request function for active cards + */ + +static +void request(card_t *card, ENTITY *e) +{ + word *special_req; + int i; + int ipl; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, TRUE); + } + + if (!e->Req) + { + special_req = (word *) e; + + switch (*special_req) + { + case REQ_REMOVE: + return; + + case REQ_NAME: + for (i=0; i < DIM(card->cfg.name); i++) + { + ((struct get_name_s *) e)->name[i] = card->cfg.name[i]; + } + return; + + case REQ_SERIAL: + case REQ_XLOG: + DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG")); + return; + + default: + return; + } + } + + ipl = UxCardLock(card->hw); + + if (!(e->Id & 0x1f)) + { + DPRINTF(("IDI: ASSIGN req")); + + for (i = 1; i < card->e_max; i++) + { + if (!card->e_tbl[i].e) + { + break; + } + } + + if (i == card->e_max) + { + DPRINTF(("IDI: request all ids in use (IDI req ignored)")); + UxCardUnlock(card->hw, ipl); + e->Rc = OUT_OF_RESOURCES; + return; + } + + card->e_tbl[i].e = e; + card->e_count++; + + e->No = (byte) i; + e->More = 0; + e->RCurrent = 0xff; + } + else + { + i = e->No; + } + + if (e->More & XBUSY) + { + DPRINTF(("IDI: request - entity is busy")); + UxCardUnlock(card->hw, ipl); + return; + } + + e->More |= XBUSY; + e->More &= ~ XMOREF; + e->XCurrent = 0; + e->XOffset = 0; + + card->e_tbl[i].next = 0; + + if(card->e_head) + { + card->e_tbl[card->e_tail].next = i; + card->e_tail = i; + } + else + { + card->e_head = i; + card->e_tail = i; + } + + UxCardUnlock(card->hw, ipl); + + DivasScheduleRequestDpc(); + + return; +} + +static byte pr_ready(ADAPTER * a) +{ + byte ReadyCount; + + ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) - + a->ram_in(a, &PR_RAM->ReqInput)); + + if(!ReadyCount) { + if(!a->ReadyInt) { + a->ram_inc(a, &PR_RAM->ReadyInt); + a->ReadyInt++; + } + } + return ReadyCount; +} + +/*------------------------------------------------------------------*/ +/* output function */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a) +{ + byte e_no; + ENTITY * this = NULL; + BUFFERS *X; + word length; + word i; + word clength; + REQ * ReqOut; + byte more; + byte ReadyCount; + byte ReqCount; + byte Id; + + /* while a request is pending ... */ + e_no = look_req(a); + if(!e_no) + { + return; + } + + ReadyCount = pr_ready(a); + if(!ReadyCount) + { + DPRINTF(("IDI: card not ready for next request")); + return; + } + + ReqCount = 0; + while(e_no && ReadyCount) { + + next_req(a); + + this = entity_ptr(a, e_no); + +#ifdef USE_EXTENDED_DEBUGS + if ( !this ) + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum)) + e_no = look_req(a) ; + ReadyCount-- ; + continue ; + } + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req)) + } +#else + DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh)); +#endif + + /* get address of next available request buffer */ + ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)]; + + /* now copy the data from the current data buffer into the */ + /* adapters request buffer */ + length = 0; + i = this->XCurrent; + X = PTR_X(a,this); + while(iXNum && length<270) { + clength = MIN((word)(270-length),X[i].PLength-this->XOffset); + a->ram_out_buffer(a, + &ReqOut->XBuffer.P[length], + PTR_P(a,this,&X[i].P[this->XOffset]), + clength); + + length +=clength; + this->XOffset +=clength; + if(this->XOffset==X[i].PLength) { + this->XCurrent = (byte)++i; + this->XOffset = 0; + } + } + + a->ram_outw(a, &ReqOut->XBuffer.length, length); + a->ram_out(a, &ReqOut->ReqId, this->Id); + a->ram_out(a, &ReqOut->ReqCh, this->ReqCh); + + /* if its a specific request (no ASSIGN) ... */ + + if(this->Id &0x1f) { + + /* if buffers are left in the list of data buffers do */ + /* do chaining (LL_MDATA, N_MDATA) */ + + this->More++; + if(iXNum && this->MInd) { + a->ram_out(a, &ReqOut->Req, this->MInd); + more = TRUE; + } + else { + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + more = FALSE; + } + + /* if we did chaining, this entity is put back into the */ + /* request queue */ + + if(more) { + req_queue(a,this->No); + } + } + + /* else it's a ASSIGN */ + + else { + + /* save the request code used for buffer chaining */ + + this->MInd = 0; + if (this->Id==BLLC_ID) this->MInd = LL_MDATA; + if (this->Id==NL_ID || + this->Id==TASK_ID || + this->Id==MAN_ID + ) this->MInd = N_MDATA; + + /* send the ASSIGN */ + + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + + /* save the reference of the ASSIGN */ + + assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference)); + } + a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next)); + ReadyCount--; + ReqCount++; + + e_no = look_req(a); + } + + /* send the filled request buffers to the ISDN adapter */ + + a->ram_out(a, &PR_RAM->ReqInput, + (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount)); + + /* if it is a 'unreturncoded' UREMOVE request, remove the */ + /* Id from our table after sending the request */ + if(this->Req==UREMOVE && this->Id) { + Id = this->Id; + e_no = a->IdTable[Id]; + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + +} + +/*------------------------------------------------------------------*/ +/* isdn interrupt handler */ +/*------------------------------------------------------------------*/ + +byte DivasDpc(ADAPTER * a) +{ + byte Count; + RC * RcIn; + IND * IndIn; + byte c; + byte RNRId; + byte Rc; + byte Ind; + + /* if return codes are available ... */ + if((Count = a->ram_in(a, &PR_RAM->RcOutput))) { + + DPRINTF(("IDI: #Rc=%x",Count)); + + /* get the buffer address of the first return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)]; + + /* for all return codes do ... */ + while(Count--) { + + if((Rc=a->ram_in(a, &RcIn->Rc))) { + + /* call return code handler, if it is not our return code */ + /* the handler returns 2 */ + /* for all return codes we process, we clear the Rc field */ + isdn_rc(a, + Rc, + a->ram_in(a, &RcIn->RcId), + a->ram_in(a, &RcIn->RcCh), + a->ram_inw(a, &RcIn->Reference)); + + a->ram_out(a, &RcIn->Rc, 0); + } + + /* get buffer address of next return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)]; + } + + /* clear all return codes (no chaining!) */ + a->ram_out(a, &PR_RAM->RcOutput ,0); + + /* call output function */ + DivasOut(a); + } + + /* clear RNR flag */ + RNRId = 0; + + /* if indications are available ... */ + if((Count = a->ram_in(a, &PR_RAM->IndOutput))) { + + DPRINTF(("IDI: #Ind=%x",Count)); + + /* get the buffer address of the first indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)]; + + /* for all indications do ... */ + while(Count--) { + + /* if the application marks an indication as RNR, all */ + /* indications from the same Id delivered in this interrupt */ + /* are marked RNR */ + if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { + a->ram_out(a, &IndIn->Ind, 0); + a->ram_out(a, &IndIn->RNR, TRUE); + } + else { + Ind = a->ram_in(a, &IndIn->Ind); + if(Ind) { + RNRId = 0; + + /* call indication handler, a return value of 2 means chain */ + /* a return value of 1 means RNR */ + /* for all indications we process, we clear the Ind field */ + c = isdn_ind(a, + Ind, + a->ram_in(a, &IndIn->IndId), + a->ram_in(a, &IndIn->IndCh), + &IndIn->RBuffer, + a->ram_in(a, &IndIn->MInd), + a->ram_inw(a, &IndIn->MLength)); + + if(c==1) { + DPRINTF(("IDI: RNR")); + a->ram_out(a, &IndIn->Ind, 0); + RNRId = a->ram_in(a, &IndIn->IndId); + a->ram_out(a, &IndIn->RNR, TRUE); + } + } + } + + /* get buffer address of next indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)]; + } + + a->ram_out(a, &PR_RAM->IndOutput, 0); + } + return FALSE; +} + +byte DivasTestInt(ADAPTER * a) +{ + return a->ram_in(a,(void *)0x3fe); +} + +void DivasClearInt(ADAPTER * a) +{ + a->ram_out(a,(void *)0x3fe,0); +} + +/*------------------------------------------------------------------*/ +/* return code handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_rc(ADAPTER * a, + byte Rc, + byte Id, + byte Ch, + word Ref) +{ + ENTITY * this; + byte e_no; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: ANum, Id, Rc)) + } +#else + DPRINTF(("IDI: ReadyInt) { + a->ReadyInt--; + return 0; + } + return 2; + } + + /* if we know this Id ... */ + e_no = a->IdTable[Id]; + if(e_no) { + + this = entity_ptr(a,e_no); + + this->RcCh = Ch; + + /* if it is a return code to a REMOVE request, remove the */ + /* Id from our table */ + if(this->Req==REMOVE && Rc==OK) { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; +/**************************************************************/ + if ((this->More & XMOREC) > 1) { + this->More &= ~XMOREC; + this->More |= 1; + DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id)); + } + } + + if (Rc==OK_FC) { + this->Rc = Rc; + this->More = (this->More & (~XBUSY | XMOREC)) | 1; + this->complete = 0xFF; + CALLBACK(a, this); + return 0; + } + if(this->More &XMOREC) + this->More--; + + /* call the application callback function */ + if(this->More &XMOREF && !(this->More &XMOREC)) { + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + } + return 0; + } + + /* if it's an ASSIGN return code check if it's a return */ + /* code to an ASSIGN request from us */ + if((Rc &0xf0)==ASSIGN_RC) { + + e_no = get_assign(a, Ref); + + if(e_no) { + + this = entity_ptr(a,e_no); + + this->Id = Id; + + /* call the application callback function */ + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + + if(Rc==ASSIGN_OK) { + a->IdTable[Id] = e_no; + } + else + { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + return 1; + } + } + return 2; +} + +/*------------------------------------------------------------------*/ +/* indication handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_ind(ADAPTER * a, + byte Ind, + byte Id, + byte Ch, + PBUFFER * RBuffer, + byte MInd, + word MLength) +{ + ENTITY * this; + word clength; + word offset; + BUFFERS *R; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: ANum, Id, Ind)) + } +#else + DPRINTF(("IDI: IdTable[Id]) { + + this = entity_ptr(a,a->IdTable[Id]); + + this->IndCh = Ch; + + /* if the Receive More flag is not yet set, this is the */ + /* first buffer of the packet */ + if(this->RCurrent==0xff) { + + /* check for receive buffer chaining */ + if(Ind==this->MInd) { + this->complete = 0; + this->Ind = MInd; + } + else { + this->complete = 1; + this->Ind = Ind; + } + + /* call the application callback function for the receive */ + /* look ahead */ + this->RLength = MLength; + + a->ram_look_ahead(a, RBuffer, this); + + this->RNum = 0; + CALLBACK(a, this); + + /* map entity ptr, selector could be re-mapped by call to */ + /* IDI from within callback */ + this = entity_ptr(a,a->IdTable[Id]); + + /* check for RNR */ + if(this->RNR==1) { + this->RNR = 0; + return 1; + } + + /* if no buffers are provided by the application, the */ + /* application want to copy the data itself including */ + /* N_MDATA/LL_MDATA chaining */ + if(!this->RNR && !this->RNum) { + return 0; + } + + /* if there is no RNR, set the More flag */ + this->RCurrent = 0; + this->ROffset = 0; + } + + if(this->RNR==2) { + if(Ind!=this->MInd) { + this->RCurrent = 0xff; + this->RNR = 0; + } + return 0; + } + /* if we have received buffers from the application, copy */ + /* the data into these buffers */ + offset = 0; + R = PTR_R(a,this); + do { + if(this->ROffset==R[this->RCurrent].PLength) { + this->ROffset = 0; + this->RCurrent++; + } + clength = MIN(a->ram_inw(a, &RBuffer->length)-offset, + R[this->RCurrent].PLength-this->ROffset); + if(R[this->RCurrent].P) { + a->ram_in_buffer(a, + &RBuffer->P[offset], + PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), + clength); + } + offset +=clength; + this->ROffset +=clength; + } while(offset<(a->ram_inw(a, &RBuffer->length))); + + /* if it's the last buffer of the packet, call the */ + /* application callback function for the receive complete */ + /* call */ + if(Ind!=this->MInd) { + R[this->RCurrent].PLength = this->ROffset; + if(this->ROffset) this->RCurrent++; + this->RNum = this->RCurrent; + this->RCurrent = 0xff; + this->Ind = Ind; + this->complete = 2; + CALLBACK(a, this); + } + return 0; + } + return 2; +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/idi.h linux/drivers/isdn/eicon/idi.h --- v2.4.0-test6/linux/drivers/isdn/eicon/idi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/idi.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,146 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* External IDI interface */ + +#if !defined(IDI_H) +#define IDI_H + +#include "sys.h" + +/* typedefs for our data structures */ + +typedef struct get_name_s GET_NAME; +typedef struct entity_s ENTITY; +typedef struct buffers_s BUFFERS; + +/* IDI request/callback function pointer */ + +typedef void (* IDI_CALL)(ENTITY *); + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} DBUFFER; + +#define REQ_NAME 0x0100 +#define BOARD_NAME_LENGTH 9 +struct get_name_s { + word command; /* command = 0x0100 */ + byte name[BOARD_NAME_LENGTH]; +}; + +#define REQ_REMOVE 0x0000 /* pointer to word which is 0 */ +#define REQ_SERIAL 0x0200 +struct get_serial_s { + word command; /* command = 0x0200 */ + dword serial; /* serial number */ +}; + +#define REQ_POSTCALL 0x0300 +struct postcall_s { + word command; /* command = 0x0300 */ + word dummy; /* not used */ + IDI_CALL callback; /* routine adress to call back */ + ENTITY *contxt; /* ptr to entity to use */ +}; + +#define REQ_XLOG 0x0400 /* structure is card dependent/defined locally */ + +struct buffers_s { + word PLength; + byte *P; +}; + +struct entity_s { + byte Req; /* pending request */ + byte Rc; /* return code received */ + byte Ind; /* indication received */ + byte ReqCh; /* channel of current Req */ + byte RcCh; /* channel of current Rc */ + byte IndCh; /* channel of current Ind */ + byte Id; /* ID used by this entity */ + byte GlobalId; /* reserved field */ + byte XNum; /* number of X-buffers */ + byte RNum; /* number of R-buffers */ + BUFFERS *X; /* pointer to X-buffer list */ + BUFFERS *R; /* pointer to R-buffer list */ + word RLength; /* length of current R-data */ + DBUFFER *RBuffer; /* buffer of current R-data */ + byte RNR; /* receive not ready flag */ + byte complete; /* receive complete status */ + IDI_CALL callback; + + word user[2]; + + /* fields used by the driver internally */ + byte No; /* entity number */ + byte reserved2; /* reserved field */ + byte More; /* R/X More flags */ + byte MInd; /* MDATA coding for this ID */ + byte XCurrent; /* current transmit buffer */ + byte RCurrent; /* current receive buffer */ + word XOffset; /* offset in x-buffer */ + word ROffset; /* offset in r-buffer */ +}; + +typedef struct { + byte type; + byte channels; + word features; + dword serial; + IDI_CALL request; +} DESCRIPTOR; + +extern void EtdM_DIDD_Read(DESCRIPTOR *, int *); + + /* descriptor type field coding */ +#define IDI_ADAPTER_S 1 +#define IDI_ADAPTER_PR 2 +#define IDI_ADAPTER_DIVA 3 +#define IDI_ADAPTER_MAESTRA 4 +#define IDI_ADAPTER_MAESTRAQ 5 +#define IDI_ADAPTER_MAESTRAP 6 +#define IDI_VADAPTER 0x40 +#define IDI_DRIVER 0x80 +#define IDI_DIMAINT 0xff + +/* feature bit mask values */ + +#define DI_VOICE 0x0 /* obsolete define */ +#define DI_FAX3 0x1 +#define DI_MODEM 0x2 +#define DI_POST 0x4 +#define DI_V110 0x8 +#define DI_V120 0x10 +#define DI_POTS 0x20 +#define DI_CODEC 0x40 +#define DI_MANAGE 0x80 +#define DI_V_42 0x0100 +#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */ + +#endif /* IDI_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c --- v2.4.0-test6/linux/drivers/isdn/eicon/kprintf.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/kprintf.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,538 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.3 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Source file for kernel interface to kernel log facility + */ + + +#include "sys.h" +#include +#undef MAX +#undef MIN + +#include +#include + +#include "divas.h" +#include "divalog.h" +#include "uxio.h" + +/* + * Implementation of printf and sprintf for kernel + */ + +#define MAX_BUFF (80) /* limit size of temporary buffers */ + +#define WRITE_CHAR(BUFFER, SIZE, C) \ + if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C) + + +/* + * convert a number to decimal ASCII + */ + +static +void do_decimal( char *temp, + int temp_len, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i < temp_len; i++) + { + temp[i] = (char) ((value % 10) + (int) '0'); + value /= 10; + } + + for (i = (temp_len - 1); temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to octal ASCII + */ + +static +void do_octal( char *temp, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i <= 11; i++) + { + temp[i] = (char) ((value & 07) + (int) '0'); + value >>= 3; + } + temp[11] &= '3'; + + for (i = 11; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to hex ASCII + */ + +static +void do_hex( char *temp, + unsigned int value, + char *s) + +{ + int i; + static + char *dec_to_hex = "0123456789abcdef"; + + temp[0] = '\0'; + + for (i = 1; i <= 8; i++) + { + temp[i] = dec_to_hex[value & 0x0f]; + value >>= 4; + } + + for (i = 8; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a buffer to ASCII HEX + */ + +static +void do_buffer( char *buffer, + int length, + char *s) + +{ + static + char hex_char [] = "0123456789abcdef"; + char *b = buffer; + int hex_byte; + int nybble; + + length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length; + + while (length) + { + hex_byte = (int) *b++; + nybble = (hex_byte >> 4) & 0xf; + *s++ = hex_char[nybble]; + nybble = hex_byte & 0xf; + *s++ = hex_char[nybble]; + *s++ = ' '; + length--; + } + *s = '\0'; + + return; +} + +/* + * Body of sprintf function: behaves just like standard sprintf, except we + * have an extra argument (buffer size) which we use to ensure we don't + * overflow + */ + +void Divas_vsprintf( char *buffer, + int size, + char *fmt, + va_list argptr) + +{ + char c; /* single character buffer */ + int i; /* handy scratch counter */ + int f; /* format character (after %) */ + char *str; /* pointer into string */ + char temp[20]; /* temp buffer used in printing numbers */ + char string[MAX_BUFF]; /* output from number conversion */ + int length; /* length of string "str" */ + char fill; /* fill character ' ' or '0' */ + boolean_t leftjust; /* TRUE if left justified, else right justified */ + int fmax, fmin; /* field specifiers % MIN . MAX s */ + int leading; /* number of leading/trailing fill characters */ + char sign; /* set to '-' for negative decimals */ + int number; /* numeric argument */ + + char *buff_ptr; /* pointer to user's buffer of hex data */ + int buff_len; /* length of hex data */ + + /* make sure we have somthing to write into */ + + if ((!buffer) || (size <= 0)) + { + return; + } + + while (TRUE) + { + /* echo characters until end or '%' encountered */ + + while ((c = *fmt++) != '%') + { + if (!c) + { + *buffer = '\0'; + return; + } + WRITE_CHAR(buffer, size, c); + } + + /* echo %% as % */ + + if (*fmt == '%') + { + WRITE_CHAR(buffer, size, *fmt); + continue; + } + + /* %- turns on left-justify */ + + if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE))) + { + fmt++; + } + + /* %0 turns on zero filling */ + + if (*fmt == '0') + { + fill = '0'; + } + else + { + fill = ' '; + } + + /* minium field width specifier for %d, u, x, c, s */ + + fmin = 0; + + if (*fmt == '*') + { + fmin = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmin = (fmin * 10) + (*fmt++ - '0'); + } + } + + /* maximum string width specifier for %s */ + + fmax = 0; + + if (*fmt == '.') + { + if (*(++fmt) == '*') + { + fmax = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmax = (fmax * 10) + (*fmt++ - '0'); + } + } + } + + /* skip over 'l' option (ints are assumed same size as longs) */ + + if (*fmt == 'l') + { + fmt++; + } + + /* get the format chacater */ + + if (!(f = *fmt++)) + { + WRITE_CHAR(buffer, size, '%'); + *buffer = '\0'; + return; + } + + sign = '\0'; /* sign == '-' for negative decimal */ + + str = string; + + switch (f) + { + case 'c' : + string[0] = (char) va_arg(argptr, int); + string[1] = '\0'; + fmax = 0; + fill = ' '; + break; + + case 's' : + str = va_arg(argptr, char *); + fill = ' '; + break; + + case 'D' : + case 'd' : + number = va_arg(argptr, int); + if (number < 0) + { + sign = '-'; + number = -number; + } + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'U' : + case 'u' : + number = va_arg(argptr, int); + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'O' : + case 'o' : + number = va_arg(argptr, int); + do_octal(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'X' : + case 'x' : + number = va_arg(argptr, int); + do_hex(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'H' : + case 'h' : + buff_ptr = va_arg(argptr, char *); + buff_len = va_arg(argptr, int); + do_buffer(buff_ptr, buff_len, str); + fmax = 0; + break; + + default : + WRITE_CHAR(buffer, size, ((char) f)); + break; + } + + /* get the length of the string */ + + length = 0; + while (str[length]) + { + length++; + } + + /* make sure we have fmax and fmin values that are O.K. */ + + if (fmin > DIM(string) || fmin < 0) + { + fmin = 0; + } + + if (fmax > DIM(string) || fmax < 0) + { + fmax = 0; + } + + /* figure out how many leading characters thare are */ + + leading = 0; + + if (fmax || fmin) + { + if (fmax) + { + if (length > fmax) + { + length = fmax; + } + } + + if (fmin) + { + leading = fmin - length; + } + + if (sign == '-') + { + leading--; + } + } + + /* output sign now, if fill is numeric */ + + if (sign == '-' && fill == '0') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* if right justified, output fill characters */ + + if (!leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + + /* output sign now, if fill is spaces */ + + if (sign == '-' && fill == ' ') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* now the actual value */ + + for (i = 0; i < length; i++) + { + WRITE_CHAR(buffer, size, str[i]); + } + + /* if left justified, fill out with the fill character */ + + if (leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + } +} + +/* + * sprintf for kernel + * + * call our vsprintf assuming user has a big buffer.... + */ + +void DivasSprintf(char *buffer, char *fmt, ...) + +{ + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + Divas_vsprintf(buffer, 1024, fmt, argptr); + + va_end(argptr); + + return; +} + +void DivasPrintf(char *fmt, ...) + +{ + klog_t log; /* log entry buffer */ + + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + /* clear log entry */ + + bzero((caddr_t) &log, sizeof(klog_t)); + + log.card = -1; + log.type = KLOG_TEXT_MSG; + + /* time stamp the entry */ + + log.time_stamp = UxTimeGet(); + + /* call vsprintf to format the user's information */ + + Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr); + + va_end(argptr); + + /* send to the log streams driver and return */ + + DivasLogAdd(&log, sizeof(klog_t)); + + return; +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/lincfg.c linux/drivers/isdn/eicon/lincfg.c --- v2.4.0-test6/linux/drivers/isdn/eicon/lincfg.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/lincfg.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,410 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.9 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#include +#undef N_DATA /* Because we have our own definition */ + +#include +#include + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" +#include "pr_pc.h" + +#include "adapter.h" +#include "uxio.h" + +#include +#include +#include + +#define HW_ID_EICON_PCI 0x1133 +#define HW_ID_DIVA_SERVER_P 0xE014 +#define HW_ID_DIVA_SERVER_B_ST 0xE010 +#define HW_ID_DIVA_SERVER_B_U 0xE013 +#define HW_ID_DIVA_SERVER_Q 0xE012 + +struct file_operations Divas_fops; +int Divas_major; + +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable); +extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset); +extern int do_open(struct inode *, struct file *); +extern int do_release(struct inode *, struct file *); + +int FPGA_Done=0; + +int DivasCardsDiscover(void) +{ + word wNumCards = 0, wDeviceIndex = 0; + byte byBus, byFunc; + word wPCIConsultation, PCItmp; + dword j, i; + unsigned int PCIserial; + dia_card_t Card; + byte *b; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_Q, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + + dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM); + dwRAM &= 0xFFC00000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG); + dwCFG &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL); + dwCTL &= 0xFFFFE000; + + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + /* Retrieve the serial number */ + + pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC); + + for (j=0, PCItmp=0; j<10000 && !PCItmp; j++) + { + pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp); + PCItmp &= 0x8000; // extract done flag + } + + pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial); + + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000); + Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100); + Card.io_base=dwDivasIOBase; + + Card.irq = byIRQ; + + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q; + Card.bus_type = DIA_BUS_TYPE_PCI; + + FPGA_Done = 0; + + /* Create four virtual card structures as we want to treat + the 4Bri card as 4 Bri cards*/ + for(i=0;i<4;i++) + { + + b=Card.memory[DIVAS_RAM_MEMORY]; + b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); + DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET)); + Card.memory[DIVAS_RAM_MEMORY]=b; + + b = Card.memory[DIVAS_RAM_MEMORY]; + b += MQ_SM_OFFSET; + Card.memory[DIVAS_SHARED_MEMORY] = b; + + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + + + /* Fill in Name */ + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'Q'; + Card.name[6] = '0' + i; + Card.name[7] = '\0'; + + Card.serial = PCIserial; + + Card.card_id = wNumCards; + + if (DivasCardNew(&Card) != 0) + { + // Force for loop to terminate + i = 4; + continue; + } + wNumCards++; + + }//for + } + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_ST, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_U, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_P, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwRAM, dwREG, dwCFG; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM); + dwRAM &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG); + dwREG &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG); + dwCFG &= 0xFFFFF000; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000); + Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000); + Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET; + +/* pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFFFc; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF80; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); +*/ + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; +/* Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase;*/ + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'P'; + Card.name[6] = '\0'; + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + + printk(KERN_INFO "Divas: %d cards detected\n", wNumCards); + + if(wNumCards == 0) + { + return -1; + } + + Divas_fops.ioctl = do_ioctl; + Divas_fops.poll = do_poll; + Divas_fops.read = do_read; + Divas_fops.open = do_open; + Divas_fops.release = do_release; + + Divas_major = register_chrdev(0, "Divas", &Divas_fops); + + if (Divas_major < 0) + { + printk(KERN_WARNING "Divas: Unable to register character driver\n"); + return -1; + } + + return 0; +} + +/* Error return -1 */ +int DivasConfigGet(dia_card_t *card) +{ + /* Retrieve Config from O/S? Not in Linux */ + return 0; +} + +dia_config_t *DivasConfig(card_t *card, dia_config_t *config) +{ + /* If config retrieved from OS then copy the data into a dia_config_t structure here + and return the pointer here. If the config 'came from above' then just + + return config; + */ + + return config; +} + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c --- v2.4.0-test6/linux/drivers/isdn/eicon/linchr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/linchr.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,274 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.12 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#include +#include +#include +#include + +#undef N_DATA + +#include "adapter.h" +#include "divas.h" +#include "divalog.h" + +extern int DivasCardNext; +void UxPause(long ms); +void bcopy(void *pSource, void *pDest, dword dwLength); +int DivasGetMem(mem_block_t *); + +#define DIA_IOCTL_UNLOCK 12 +void UnlockDivas(void); + +int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg) +{ + dia_load_t *pDivaLoad; + dia_start_t *pDivaStart; + dia_config_t *pDivaConfig; + dia_log_t *pDivaLog; + byte *pUserCards, card_i; + word wCardNum; + mem_block_t *mem_block; + + switch (command) + { + case DIA_IOCTL_CONFIG: + pDivaConfig = (dia_config_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t))) + { + DivasCardConfig(pDivaConfig); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_DETECT: + pUserCards = (byte *) arg; + + if (!verify_area(VERIFY_WRITE, pUserCards, 20)) + { + put_user(DivasCardNext, pUserCards++); + + for (card_i=1; card_i < 20; card_i++) + { + put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++); + } + } + else + { + printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_START: + pDivaStart = (dia_start_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t))) + { + return DivasCardStart(pDivaStart->card_id); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n"); + return -1; + } + + + case DIA_IOCTL_FLAVOUR: + return 0; + + case DIA_IOCTL_LOAD: + pDivaLoad = (dia_load_t *) arg; + if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length)) + { + if (DivasCardLoad(pDivaLoad)) + { + printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n"); + return -EINVAL; + } + } + else + { + printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n"); + return -EINVAL; + } + return 0; + + case DIA_IOCTL_LOG: + pDivaLog = (dia_log_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t))) + { + DivasLog(pDivaLog); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_XLOG_REQ: + + if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word))) + { + wCardNum = * (word *) arg; + DivasXlogReq(wCardNum); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_NUM: + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) + { + * (int *) arg = DivasCardNext; + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_LIST: + DPRINTF(("divas: DIA_IOCTL_GET_LIST")); + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t))) + { + DivasGetList((dia_card_list_t *)arg); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_MEM: + mem_block = (mem_block_t *) arg; + + if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t))) + { + DivasGetMem(mem_block); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_UNLOCK: + UnlockDivas(); + return 0; + + default: + printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command); + return -EINVAL; + } + + return -EINVAL; +} + +unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable) +{ + word wMask = 0; + + if (!DivasLogFifoEmpty()) + { + wMask |= POLLIN | POLLRDNORM; + } + + return wMask; +} + +ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset) +{ + klog_t *pClientLogBuffer = (klog_t *) pUserBuffer; + klog_t *pHeadItem; + + if (BufferSize < sizeof(klog_t)) + { + printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n", + BufferSize, sizeof(klog_t)); + return 0; + } + + pHeadItem = (klog_t *) DivasLogFifoRead(); + + if (pHeadItem) + { + bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t)); + kfree(pHeadItem); + return sizeof(klog_t); + } + + return 0; +} +int private_usage_count; +extern void mod_inc_use_count(void); +extern void mod_dec_use_count(void); + +int do_open(struct inode *pInode, struct file *pFile) +{ +#if defined(MODULE) + mod_inc_use_count(); + private_usage_count++; +#endif + return 0; +} + +int do_release(struct inode *pInode, struct file *pFile) +{ +#if defined(MODULE) + mod_dec_use_count(); + private_usage_count--; +#endif + return 0; +} + +void UnlockDivas(void) +{ + while (private_usage_count > 0) + { + private_usage_count--; +#if defined(MODULE) + mod_dec_use_count(); +#endif + } +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/linio.c linux/drivers/isdn/eicon/linio.c --- v2.4.0-test6/linux/drivers/isdn/eicon/linio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/linio.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,750 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.16 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#define N_DATA + +#include +#include +#include +#include +#include +#undef N_DATA + +#include "uxio.h" + +static +int log_on=0; + +int Divasdevflag = 0; + +//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED; + +static +ux_diva_card_t card_pool[MAX_CARDS]; + +void UxPause(long int ms) +{ + int timeout = jiffies + ((ms * HZ) / 1000); + + while (time_before(jiffies, timeout)); +} + +int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg) +{ + int i; + ux_diva_card_t *c; + + if (cfg->bus_type != DIA_BUS_TYPE_PCI) + { + DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type)); + return -1; + } + + for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++) + { + ; + } + + if (i == DIM(card_pool)) + { + DPRINTF(("divas hw: card_pool exhausted")); + return -1; + } + + c = *card = &card_pool[i]; + + switch (cfg->bus_type) + { + case DIA_BUS_TYPE_PCI: + c->bus_num = cfg->bus_num; + c->func_num = cfg->func_num; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->card_type = cfg->card_type; + c->mapped = NULL; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + c->pCONTROL = cfg->memory[DIVAS_CTL_MEMORY]; + + /* c->bus_type = DIA_BUS_TYPE_PCI; + c->bus_num = cfg->bus_num & 0x3f; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->int_priority = (int) cfg->int_priority; + c->card_type = cfg->card_type; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM)); + DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED)); + DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG)); + c->cm_key = cm_getbrdkey("Divas", cfg->card_id);*/ + break; + default: + break; + } + + c->in_use = TRUE; + + return 0; +} + +void UxCardHandleFree(ux_diva_card_t *card) +{ + card->in_use = FALSE; +} + + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 +void *UxCardMemAttach(ux_diva_card_t *card, int id) +{ + if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = card->pDEVICES; + return card->pDEVICES; + break; + case DIVAS_CFG_MEMORY: + card->mapped = card->pCONFIG; + return card->pCONFIG; + break; + default: + ASSERT(FALSE); + card->mapped = NULL; + return (void *) 0; + } + } + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + switch (id) + { + case PLX_IOBASE: + return (void *) card->reset_base; + break; + case DIVAS_IOBASE: + return (void *) card->io_base; + break; + default: + ASSERT(FALSE); + return 0; + } + } + + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = (void *) card->io_base; + return (void *) card->io_base; + break; + case DIVAS_CTL_MEMORY: + card->mapped = card->pCONTROL; + return card->pCONTROL; + break; + default: + // ASSERT(FALSE); + DPRINTF(("divas: Trying to attach to mem %d", id)); + card->mapped = NULL; + return (void *) 0; + } + } else + DPRINTF(("divas: Tried to attach to unknown card")); + + /* Unknown card type */ + return NULL; +} + +void UxCardMemDetach(ux_diva_card_t *card, void *address) +{ + return; // Just a place holder. No un-mapping done. +} + +void UxCardLog(int turn_on) +{ + log_on = turn_on; +} + +/* + * Control Register I/O Routines to be performed on Attached I/O ports + */ + +void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outb(the_byte, base); +} + +void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outw(the_word, base); +} + +void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outl(the_dword, base); +} + +byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inb(base); +} + +word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inw(base); +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address) +{ + byte b; + volatile byte* t = (byte*)address; + + b = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a)); + } + + return(b); +} + +word UxCardMemInW(ux_diva_card_t *card, void *address) +{ + word w; + volatile word* t = (word*)address; + + w = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a)); + } + + return (w); +} + +dword UxCardMemInD(ux_diva_card_t *card, void *address) +{ + dword dw; + volatile dword* t = (dword*)address; + + dw = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a)); + } + + return (dw); +} + +void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + volatile byte *pSource = address; + byte *pDest = buffer; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data) +{ + volatile byte* t = (byte*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a)); + } + + *t = data; + + return; +} + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data) +{ + volatile word* t = (word*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a)); + } + + *t = data; + return; +} + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data) +{ + volatile dword* t = (dword*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a)); + } + + *t = data; + return; +} + +void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + byte *pSource = buffer; + byte *pDest = address; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + byte the_byte; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + + the_byte = inb(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", + the_byte & 0xff, address)); + } + + return the_byte; +} + +word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + word the_word; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_word = inw(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", + the_word & 0xffff, address)); + } + + return the_word; +} + +dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + dword the_dword; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_dword = inl(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", + the_dword, address)); + } + + return the_dword; +} + +void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = address; + byte *pDest = buffer; + + if ((word) (dword) address & 0x1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + *pDest = (byte) inb(card->io_base); + pDest++; + pSource++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +/* Output */ + +void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", + data & 0xff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outb((byte) data & 0xFF, card->io_base); + + return; +} + +void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", + data & 0xffff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outw((word) data & 0xFFFF, card->io_base); + + return; +} + +void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outl((dword) data & 0xFFFFFFFF, card->io_base); + + return; +} + +void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = buffer; + byte *pDest = address; + + if ((word) (dword) address & 1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outb(*pSource, card->io_base); + pSource++; + pDest++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +void Divasintr(int arg, void *unused, struct pt_regs *unused_regs) +{ + int i; + card_t *card = NULL; + ux_diva_card_t *ux_ref = NULL; + + for (i = 0; i < DivasCardNext; i++) + { + + if (arg == DivasCards[i].cfg.irq) + { + card = &DivasCards[i]; + ux_ref = card->hw; + + if ((ux_ref) && (card->is_live)) + { + (*ux_ref->user_isr)(ux_ref->user_isr_arg); + } + else + { + DPRINTF(("divas: ISR couldn't locate card")); + } + } + } + + return; +} + + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg) +{ + int result; + + card->user_isr = isr_fn; + card->user_isr_arg = isr_arg; + + result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg); + + return result; +} + +void UxIsrRemove(ux_diva_card_t *card, void *dev_id) +{ + free_irq(card->irq, card->user_isr_arg); +} + +void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value); + break; + case sizeof(word): + pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value); + break; + case sizeof(dword): + pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n"); + } +} + +void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value); + break; + case sizeof(word): + pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value); + break; + case sizeof(dword): + pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n"); + } +} + +void *UxAlloc(unsigned int size) +{ + void *m; + + m = kmalloc(size, GFP_ATOMIC); + + return m; +} + +void UxFree(void *ptr) +{ + kfree(ptr); +} + +int UxCardLock(ux_diva_card_t *card) +{ + unsigned long flags; + + //spin_lock_irqsave(&diva_lock, flags); + + save_flags(flags); + cli(); + return flags; + +} + +void UxCardUnlock(ux_diva_card_t *card, int ipl) +{ + //spin_unlock_irqrestore(&diva_lock, ipl); + + restore_flags(ipl); + +} + +dword UxTimeGet(void) +{ + return jiffies; +} + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p += 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} + +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p -= 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/linsys.c linux/drivers/isdn/eicon/linsys.c --- v2.4.0-test6/linux/drivers/isdn/eicon/linsys.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/linsys.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,170 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.10 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#include +#undef N_DATA +#include + +#include +struct pt_regs; +#include +#include + +#include "sys.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +#ifdef MODULE +void bcopy(void *pSource, void *pDest, dword dwLength) +{ + memcpy(pDest, pSource, dwLength); +} +#endif + +void bzero(void *pDataArea, dword dwLength) +{ + memset(pDataArea, 0, dwLength); +} + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); +*/ + return 0; +} + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/ + + return 0; +} + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Need to set these platform dependent values after patching */ + + card->hw->reset_base = card->cfg.reset_base; + card->hw->io_base = card->cfg.io_base; + + request_region(card->hw->reset_base,0x80,"Divas"); + request_region(card->hw->io_base,0x20,"Divas"); + + + /* Same as for PRI */ + return DivasPRIInitPCI(card, cfg); +} + +/* ######################### Stubs of routines that are not done yet ################## */ +/*void DivasLogIdi(card_t *card, ENTITY *e, int request) +{ +} +*/ + +int DivasDpcSchedule(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +int DivasScheduleRequestDpc(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoRequestDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +void DivasLogAdd(void *buffer, int length) +{ + static + boolean_t overflow = FALSE; + static + boolean_t busy = FALSE; + + /* make sure we're not interrupting ourselves */ + + if (busy) + { + printk(KERN_DEBUG "Divas: Logging interrupting self !\n"); + return; + } + busy = TRUE; + + /* ignore call if daemon isn't running and we've reached limit */ + + if (DivasLogFifoFull()) + { + if (!overflow) + { + printk(KERN_DEBUG "Divas: Trace buffer full\n"); + overflow = TRUE; + } + busy = FALSE; + return; + } + + DivasLogFifoWrite(buffer, length); + + busy = FALSE; + return; +} + +/* #################################################################################### */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/log.c linux/drivers/isdn/eicon/log.c --- v2.4.0-test6/linux/drivers/isdn/eicon/log.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/log.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,179 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Source file for diva log facility + */ + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +/*Counter to monitor number of messages */ +static int m_count; + +#define MAX_BUFFERED_MSGS (1000) + +/* Our Linked List Structure to hold message */ +typedef struct klog_link{ + klog_t klog; + struct klog_link *next; +}KNODE; + +/* First & Last structures in list*/ +KNODE *head; +KNODE *tail; + +/* + * retrieve message from FIFO buffer + * returns NULL if buffer empty + * otherwise returns pointer to entry + */ + +char *DivasLogFifoRead(void) + +{ + KNODE *old_head; + + if(head==NULL) + { + /* Buffer Empty - No Messages */ + return NULL; + } + + m_count--; + /* Keep track of message to be read & increment to next message*/ + old_head = head; + head = head->next; + /*Return ptr to Msg */ + return((char *)old_head); +} + +/* + * write message into FIFO buffer + */ + +void DivasLogFifoWrite(char *entry, int length) + +{ + KNODE *new_klog; + + if(head == NULL) + { + /* No Entries in Log */ + tail=NULL; + m_count=0; + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Set head & tail to point to the new Msg Struct */ + head=tail=new_klog; + tail->next=NULL; + } + else + { + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Let last Msg Struct point to new Msg Struct & inc tail */ + tail->next=new_klog; + tail=new_klog; + tail->next=NULL; + } + + if (length > sizeof(klog_t)) + { + length = sizeof(klog_t); + } + + bcopy(entry,&tail->klog,length); + + return; +} + +/* + * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE + */ +int DivasLogFifoEmpty(void) +{ + return (m_count == 0); +} + +/* + *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE + */ +int DivasLogFifoFull(void) +{ + return (m_count == MAX_BUFFERED_MSGS); +} + +/* + * generate an IDI log entry + */ + +void DivasLogIdi(card_t *card, ENTITY *e, int request) + +{ + klog_t klog; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = UxTimeGet(); + + klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ? + sizeof(klog.buffer) : sizeof(ENTITY); + + klog.card = (int) (card - DivasCards); + + klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK; + klog.code = 0; + bcopy(e, klog.buffer, klog.length); + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/md5sums.asc linux/drivers/isdn/eicon/md5sums.asc --- v2.4.0-test6/linux/drivers/isdn/eicon/md5sums.asc Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/md5sums.asc Sun Aug 13 10:05:32 2000 @@ -0,0 +1,16 @@ +# These are valid md5sums to detect modifications +# in eicon driver files provided by Eicon Technology. +# For changes and modifications in these files please +# read ../../../Documentation/isdn/README.eicon +# +9b0e381d4558af3a6eba66843e1ee5d9 common.c +dbb92cba52db31ff8325a252b3f595c3 idi.c +15687687ef82f099966ed42772001cd3 bri.c +c3e3b720c3351b66635bd548195e29e8 pri.c +b0a6d2ab49bcfcfd1825860f178a84b4 log.c +673746176316b72271a09c0a27287a01 xlog.c +07e1bbabdb4d69880db196ef31bfb241 kprintf.c +b60b40ad630f26b7923369df95b4d1b9 fpga.c +5013ecca0a38a8fcc4a61642754f2076 fourbri.c +1501ae468a0c5eaab1e60720fa723a67 fcheck.c +# end of md5sums diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/pc.h linux/drivers/isdn/eicon/pc.h --- v2.4.0-test6/linux/drivers/isdn/eicon/pc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/pc.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,320 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 PC_H_INCLUDED +#define PC_H_INCLUDED + + +#define byte unsigned char +#define word unsigned short +#define dword unsigned long +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/*------------------------------------------------------------------*/ +/* buffer definition */ +/*------------------------------------------------------------------*/ + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} PBUFFER; + +/*------------------------------------------------------------------*/ +/* dual port ram structure */ +/*------------------------------------------------------------------*/ + +struct dual +{ + byte Req; /* request register */ + byte ReqId; /* request task/entity identification */ + byte Rc; /* return code register */ + byte RcId; /* return code task/entity identification */ + byte Ind; /* Indication register */ + byte IndId; /* Indication task/entity identification */ + byte IMask; /* Interrupt Mask Flag */ + byte RNR; /* Receiver Not Ready (set by PC) */ + byte XLock; /* XBuffer locked Flag */ + byte Int; /* ISDN-S interrupt */ + byte ReqCh; /* Channel field for layer-3 Requests */ + byte RcCh; /* Channel field for layer-3 Returncodes */ + byte IndCh; /* Channel field for layer-3 Indications */ + byte MInd; /* more data indication field */ + word MLength; /* more data total packet length */ + byte ReadyInt; /* request field for ready interrupt */ + byte SWReg; /* Software register for special purposes */ + byte Reserved[11]; /* reserved space */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-S adapter Signature (GD) */ + PBUFFER XBuffer; /* Transmit Buffer */ + PBUFFER RBuffer; /* Receive Buffer */ +}; + +/*------------------------------------------------------------------*/ +/* SWReg Values (0 means no command) */ +/*------------------------------------------------------------------*/ +#define SWREG_DIE_WITH_LEDON 0x01 +#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */ + +/*------------------------------------------------------------------*/ +/* Id Fields Coding */ +/*------------------------------------------------------------------*/ + +#define ID_MASK 0xe0 /* Mask for the ID field */ +#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/ + +#define DSIG_ID 0x00 /* ID for D-channel signaling */ +#define NL_ID 0x20 /* ID for network-layer access (B or D) */ +#define BLLC_ID 0x60 /* ID for B-channel link level access */ +#define TASK_ID 0x80 /* ID for dynamic user tasks */ +#define TIMER_ID 0xa0 /* ID for timer task */ +#define TEL_ID 0xc0 /* ID for telephone support */ +#define MAN_ID 0xe0 /* ID for management */ + +/*------------------------------------------------------------------*/ +/* ASSIGN and REMOVE requests are the same for all entities */ +/*------------------------------------------------------------------*/ + +#define ASSIGN 0x01 +#define UREMOVE 0xfe /* without returncode */ +#define REMOVE 0xff + +/*------------------------------------------------------------------*/ +/* Timer Interrupt Task Interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TIM 0x01 +#define REMOVE_TIM 0xff + +/*------------------------------------------------------------------*/ +/* dynamic user task interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TSK 0x01 +#define REMOVE_TSK 0xff + +#define LOAD 0xf0 +#define RELOCATE 0xf1 +#define START 0xf2 +#define LOAD2 0xf3 +#define RELOCATE2 0xf4 + +/*------------------------------------------------------------------*/ +/* dynamic user task messages */ +/*------------------------------------------------------------------*/ + +#define TSK_B2 0x0000 +#define TSK_WAKEUP 0x2000 +#define TSK_TIMER 0x4000 +#define TSK_TSK 0x6000 +#define TSK_PC 0xe000 + +/*------------------------------------------------------------------*/ +/* LL management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_LL 1 /* assign logical link */ +#define REMOVE_LL 0xff /* remove logical link */ + +/*------------------------------------------------------------------*/ +/* LL service primitives */ +/*------------------------------------------------------------------*/ + +#define LL_UDATA 1 /* link unit data request/indication */ +#define LL_ESTABLISH 2 /* link establish request/indication */ +#define LL_RELEASE 3 /* link release request/indication */ +#define LL_DATA 4 /* data request/indication */ +#define LL_LOCAL 5 /* switch to local operation (COM only) */ +#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */ +#define LL_REMOTE 6 /* switch to remote operation (COM only) */ +#define LL_TEST 8 /* link test request */ +#define LL_MDATA 9 /* more data request/indication */ +#define LL_BUDATA 10 /* broadcast unit data request/indication */ +#define LL_XID 12 /* XID command request/indication */ +#define LL_XID_R 13 /* XID response request/indication */ + +/*------------------------------------------------------------------*/ +/* NL service primitives */ +/*------------------------------------------------------------------*/ + +#define N_MDATA 1 /* more data to come REQ/IND */ +#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */ +#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */ +#define N_DISC 4 /* OSI N-DISC REQ/IND */ +#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */ +#define N_RESET 6 /* OSI N-RESET REQ/IND */ +#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */ +#define N_DATA 8 /* OSI N-DATA REQ/IND */ +#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */ +#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */ +#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */ +#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ +#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ + +#define N_Q_BIT 0x10 /* Q-bit for req/ind */ +#define N_M_BIT 0x20 /* M-bit for req/ind */ +#define N_D_BIT 0x40 /* D-bit for req/ind */ + +/*------------------------------------------------------------------*/ +/* Signaling management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_SIG 1 /* assign signaling task */ +#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */ +#define REMOVE_SIG 0xff /* remove signaling task */ + +/*------------------------------------------------------------------*/ +/* Signaling service primitives */ +/*------------------------------------------------------------------*/ + +#define CALL_REQ 1 /* call request */ +#define CALL_CON 1 /* call confirmation */ +#define CALL_IND 2 /* incoming call connected */ +#define LISTEN_REQ 2 /* listen request */ +#define HANGUP 3 /* hangup request/indication */ +#define SUSPEND 4 /* call suspend request/confirm */ +#define RESUME 5 /* call resume request/confirm */ +#define SUSPEND_REJ 6 /* suspend rejected indication */ +#define USER_DATA 8 /* user data for user to user signaling */ +#define CONGESTION 9 /* network congestion indication */ +#define INDICATE_REQ 10 /* request to indicate an incoming call */ +#define INDICATE_IND 10 /* indicates that there is an incoming call */ +#define CALL_RES 11 /* accept an incoming call */ +#define CALL_ALERT 12 /* send ALERT for incoming call */ +#define INFO_REQ 13 /* INFO request */ +#define INFO_IND 13 /* INFO indication */ +#define REJECT 14 /* reject an incoming call */ +#define RESOURCES 15 /* reserve B-Channel hardware resources */ +#define TEL_CTRL 16 /* Telephone control request/indication */ +#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ +#define FAC_REG_REQ 18 /* connection idependent fac registration */ +#define FAC_REG_ACK 19 /* fac registration acknowledge */ +#define FAC_REG_REJ 20 /* fac registration reject */ +#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ +#define FACILITY_REQ 22 /* send a Facility Message type */ +#define FACILITY_IND 22 /* Facility Message type indication */ +#define SIG_CTRL 29 /* Control for signalling hardware */ +#define DSP_CTRL 30 /* Control for DSPs */ +#define LAW_REQ 31 /* Law config request for (returns info_i) */ + + +/*------------------------------------------------------------------*/ +/* management service primitives */ +/*------------------------------------------------------------------*/ + +#define MAN_READ 2 +#define MAN_WRITE 3 +#define MAN_EXECUTE 4 +#define MAN_EVENT_ON 5 +#define MAN_EVENT_OFF 6 +#define MAN_LOCK 7 +#define MAN_UNLOCK 8 + +#define MAN_INFO_IND 2 +#define MAN_EVENT_IND 3 +#define MAN_TRACE_IND 4 + +#define MAN_ESC 0x80 + +/*------------------------------------------------------------------*/ +/* return code coding */ +/*------------------------------------------------------------------*/ + +#define UNKNOWN_COMMAND 0x01 /* unknown command */ +#define WRONG_COMMAND 0x02 /* wrong command */ +#define WRONG_ID 0x03 /* unknown task/entity id */ +#define WRONG_CH 0x04 /* wrong task/entity id */ +#define UNKNOWN_IE 0x05 /* unknown information el. */ +#define WRONG_IE 0x06 /* wrong information el. */ +#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */ +#define ADAPTER_DEAD 0x08 /* ISDN card CPU halted */ +#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ +#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ +#define ASSIGN_OK 0xef /* ASSIGN OK */ +#define OK_FC 0xfc /* Flow-Control RC */ +#define READY_INT 0xfd /* Ready interrupt */ +#define TIMER_INT 0xfe /* timer interrupt */ +#define OK 0xff /* command accepted */ + +/*------------------------------------------------------------------*/ +/* information elements */ +/*------------------------------------------------------------------*/ + +#define SHIFT 0x90 /* codeset shift */ +#define MORE 0xa0 /* more data */ +#define CL 0xb0 /* congestion level */ + + /* codeset 0 */ + +#define BC 0x04 /* Bearer Capability */ +#define CAU 0x08 /* cause */ +#define CAD 0x0c /* Connected address */ +#define CAI 0x10 /* call identity */ +#define CHI 0x18 /* channel identification */ +#define LLI 0x19 /* logical link id */ +#define CHA 0x1a /* charge advice */ +#define DT 0x29 /* ETSI date/time */ +#define KEY 0x2c /* keypad information element */ +#define FTY 0x1c /* facility information element */ +#define DSP 0x28 /* display */ +#define OAD 0x6c /* origination address */ +#define OSA 0x6d /* origination sub-address */ +#define CPN 0x70 /* called party number */ +#define DSA 0x71 /* destination sub-address */ +#define RDX 0x73 /* redirected number extended */ +#define RDN 0x74 /* redirected number */ +#define LLC 0x7c /* low layer compatibility */ +#define HLC 0x7d /* high layer compatibility */ +#define UUI 0x7e /* user user information */ +#define ESC 0x7f /* escape extension */ + +#define DLC 0x20 /* data link layer configuration */ +#define NLC 0x21 /* network layer configuration */ + + /* codeset 6 */ + +#define SIN 0x01 /* service indicator */ +#define CIF 0x02 /* charging information */ +#define DATE 0x03 /* date */ +#define CPS 0x07 /* called party status */ + +/*------------------------------------------------------------------*/ +/* TEL_CTRL contents */ +/*------------------------------------------------------------------*/ + +#define RING_ON 0x01 +#define RING_OFF 0x02 +#define HANDS_FREE_ON 0x03 +#define HANDS_FREE_OFF 0x04 +#define ON_HOOK 0x80 +#define OFF_HOOK 0x90 + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/pc_maint.h linux/drivers/isdn/eicon/pc_maint.h --- v2.4.0-test6/linux/drivers/isdn/eicon/pc_maint.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/pc_maint.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,165 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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 PC_MAINT_H +#define PC_MAINT_H + +#if !defined(MIPS_SCOM) +#define BUFFER_SZ 48 +#define MAINT_OFFS 0x380 +#else +#define BUFFER_SZ 128 +#define MAINT_OFFS 0xff00 +#endif + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define DO_LOG 1 +#define MEMR 2 +#define MEMW 3 +#define IOR 4 +#define IOW 5 +#define B1TEST 6 +#define B2TEST 7 +#define BTESTOFF 8 +#define DSIG_STATS 9 +#define B_CH_STATS 10 +#define D_CH_STATS 11 +#define BL1_STATS 12 +#define BL1_STATS_C 13 +#define GET_VERSION 14 +#define OS_STATS 15 +#define XLOG_SET_MASK 16 +#define XLOG_GET_MASK 17 +#define DSP_READ 20 +#define DSP_WRITE 21 + +#define OK 0xff +#define MORE_EVENTS 0xfe +#define NO_EVENT 1 + +struct DSigStruc +{ + byte Id; + byte uX; + byte listen; + byte active; + byte sin[3]; + byte bc[6]; + byte llc[6]; + byte hlc[6]; + byte oad[20]; +}; + +struct BL1Struc { + dword cx_b1; + dword cx_b2; + dword cr_b1; + dword cr_b2; + dword px_b1; + dword px_b2; + dword pr_b1; + dword pr_b2; + word er_b1; + word er_b2; +}; + +struct L2Struc { + dword XTotal; + dword RTotal; + word XError; + word RError; +}; + +struct OSStruc { + word free_n; +}; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[BUFFER_SZ]; + word w[BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[BUFFER_SZ>>2]; +} BUFFER; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[MIPS_BUFFER_SZ]; + word w[MIPS_BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + + +#if !defined(MIPS_SCOM) +struct pc_maint +{ + byte req; + byte rc; + byte *mem; /*far*/ + short length; + word port; + byte fill[6]; + BUFFER data; +}; +#else +struct pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte far *mem; + short length; + word port; + byte fill[4]; /* data at offset 16 */ + BUFFER data; +}; +#endif + +struct mi_pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte *mem; /*far*/ + short length; + word port; + byte fill[4]; /* data at offset 16 */ + MIPS_BUFFER data; +}; + +#endif /* PC_MAINT_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/pr_pc.h linux/drivers/isdn/eicon/pr_pc.h --- v2.4.0-test6/linux/drivers/isdn/eicon/pr_pc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/pr_pc.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,86 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#if !defined(PR_PC_H) +#define PR_PC_H + +struct pr_ram { + word NextReq; /* pointer to next Req Buffer */ + word NextRc; /* pointer to next Rc Buffer */ + word NextInd; /* pointer to next Ind Buffer */ + byte ReqInput; /* number of Req Buffers sent */ + byte ReqOutput; /* number of Req Buffers returned */ + byte ReqReserved; /* number of Req Buffers reserved */ + byte Int; /* ISDN-P interrupt */ + byte XLock; /* Lock field for arbitration */ + byte RcOutput; /* number of Rc buffers received */ + byte IndOutput; /* number of Ind buffers received */ + byte IMask; /* Interrupt Mask Flag */ + byte Reserved1[2]; /* reserved field, do not use */ + byte ReadyInt; /* request field for ready interrupt */ + byte Reserved2[12]; /* reserved field, do not use */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-P initialized indication */ + byte B[1]; /* buffer space for Req,Ind and Rc */ +}; + +typedef struct { + word next; + byte Req; + byte ReqId; + byte ReqCh; + byte Reserved1; + word Reference; + byte Reserved[8]; + PBUFFER XBuffer; +} REQ; + +typedef struct { + word next; + byte Rc; + byte RcId; + byte RcCh; + byte Reserved1; + word Reference; + byte Reserved2[8]; +} RC; + +typedef struct { + word next; + byte Ind; + byte IndId; + byte IndCh; + byte MInd; + word MLength; + word Reference; + byte RNR; + byte Reserved; + dword Ack; + PBUFFER RBuffer; +} IND; + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/pri.c linux/drivers/isdn/eicon/pri.c --- v2.4.0-test6/linux/drivers/isdn/eicon/pri.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/pri.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,533 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Diva Server PRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_RESET_REG 0x20 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xef00 /* value for PRI card */ + +#define MP_PROTOCOL_ADDR 0xA0011000 +#define MP_DSP_CODE_BASE 0xa03a0000 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg); +int pri_ISR (card_t* card); + +static int diva_server_reset(card_t *card) +{ + byte *reg; + diva_server_boot_t *boot = NULL; + dword live = 0; + int i = 0; + dword dwWait; + + DPRINTF(("divas: reset Diva Server PRI")); + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], DIVAS_RESET | + DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], 0x00); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemDetach(card->hw, reg); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, boot->reserved, 0); + + live = UxCardMemInD(card->hw, &boot->live); + + for (i=0; i<5; i++) + { + if (live != UxCardMemInD(card->hw, &boot->live)) + { + break; + } + UxPause(10); + } + + if (i == 5) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card is reset but CPU not running")); + return -1; + } + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card reset after %d ms", i * 10)); + + return 0; +} + +static int diva_server_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardLog(0); + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_reset_int(card_t *card) +{ + byte *cfg; + + cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL); + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0); + UxCardMemDetach(card->hw, cfg); + + return; +} + + +static int diva_server_test_int(card_t *card) +{ + int i; + byte *shared; + byte req_int; + + DPRINTF(("divas: test interrupt for Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardMemIn(card->hw, &shared[0x3FE]); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + UxCardMemIn(card->hw, &shared[0x3FE]); + + UxCardMemDetach(card->hw, shared); + + diva_server_reset_int(card); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + card->test_int_pend = TEST_INT_DIVAS; + + req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt)); + + req_int++; + + UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int); + + UxCardMemDetach(card->hw, shared); + + UxCardLog(0); + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + + if (card->test_int_pend) + { + + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_load(card_t *card, dia_load_t *load) +{ + diva_server_boot_t *boot; + int i, offset, length; + dword cmd = 0; + + DPRINTF(("divas: loading Diva Server PRI")); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + (((sizeof(dword) + + (sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT)) + + ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA))); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + sizeof(dword))); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE); + break; + + default: + DPRINTF(("divas: unknown code type")); + UxCardMemDetach(card->hw, boot); + return -1; + } + + UxCardLog(0); + offset = 0; + + do + { + length = (load->length - offset >= 400) ? 400 : load->length - offset; + + for (i=0; ihw, &boot->data[i], load->code[offset+i]); + } + + for (i=0; icode[offset + i] != UxCardMemIn(card->hw, &boot->data[i])) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card code block verify failed")); + return -1; + } + } + + UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD); + + for (i=0; i<50000; i++) + { + cmd = UxCardMemInD(card->hw, &boot->cmd); + if (!cmd) + { + break; + } + /*UxPause(1);*/ + } + + if (cmd) + { + DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset)); + UxCardMemDetach(card->hw, boot); + return -1; + } + + offset += length; + + } while (offset < load->length); + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: DIVA Server card loaded")); + + return 0; +} + +static int diva_server_start(card_t *card, byte *channels) +{ + diva_server_boot_t *boot; + byte *ram; + int i; + dword signature = 0; + + DPRINTF(("divas: start Diva Server PRI")); + + card->is_live = FALSE; + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD); + + UxCardLog(0); + + for (i = 0; i < 300; i++) + { + signature = UxCardMemInD(card->hw, &boot->signature); + if ((signature >> 16) == DIVAS_SIGNATURE) + { + DPRINTF(("divas: started card after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if ((signature >> 16) != DIVAS_SIGNATURE) + { + UxCardMemDetach(card->hw, boot); + DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature)); + return -1; + } + + card->is_live = TRUE; + + ram = (byte *) boot; + ram += DIVAS_SHARED_OFFSET; + + *channels = UxCardMemIn(card->hw, &ram[0x3F6]); + card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]); + + UxCardMemDetach(card->hw, boot); + + if (diva_server_test_int(card)) + { + DPRINTF(("divas: interrupt test failed")); + return -1; + } + + DPRINTF(("divas: DIVA Server card started")); + + return 0; +} + +static +int diva_server_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise PRI specific entry points + */ + +int DivasPriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server PRI")); + + if (DivasPRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_reset; + card->card_load = diva_server_load; + card->card_config = diva_server_config; + card->card_start = diva_server_start; + card->reset_int = diva_server_reset_int; + card->card_mem_get = diva_server_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = pri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + + +int pri_ISR (card_t* card) +{ + int served = 0; + byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET]; + register unsigned long val = *isr; + + if (val & 0x80000000) /* our card had caused interrupt ??? */ + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + *isr = (unsigned long)~0x03E00000; /* Clear interrupt line */ + } + + UxCardMemDetach(card->hw, cfg); + + return (served != 0); +} + + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/sys.h linux/drivers/isdn/eicon/sys.h --- v2.4.0-test6/linux/drivers/isdn/eicon/sys.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/sys.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,119 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Environment provided by system and miscellaneous definitions */ + +#if !defined(SYS_H) +#define SYS_H + +/* abreviations for unsigned types */ +typedef int boolean_t; + +typedef unsigned char byte; + +typedef unsigned long dword; +typedef unsigned short word; + +/* abreviations for volatile types */ + +typedef volatile byte vbyte; +typedef volatile word vword; +typedef volatile dword vdword; + +/* Booleans */ + +#if !defined(TRUE) +#define TRUE (1) +#define FALSE (0) +#endif + +/* NULL pointer */ + +#if !defined(NULL) +#define NULL ((void *) 0) +#endif + +/* MIN and MAX */ + +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/* Return the dimension of an array */ + +#if !defined(DIM) +#define DIM(array) (sizeof (array)/sizeof ((array)[0])) +#endif + +/* + * Return the number of milliseconds since last boot + */ + +extern dword UxTimeGet(void); + +extern void DivasSprintf(char *buffer, char *format, ...); +extern void DivasPrintf(char *format, ...); + +/* fatal errors, asserts and tracing */ + +void HwFatalErrorFrom(char *file, int line); +void HwFatalError(void); +/* void HwAssert(char *file, int line, char *condition); */ + +#include +#define _PRINTK printk + +#define _PRINTF DivasPrintf +void _PRINTF(char *format, ...); +#define PRINTF(arg_list) _PRINTF arg_list +#if defined DTRACE +# define DPRINTF(arg_list) _PRINTF arg_list +# define KDPRINTF(arg_list) _PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n"); +#else +# define DPRINTF(arg_list) (void)0 +# define KDPRINTF(arg_list) _PRINTK arg_list ; _PRINTK("\n"); +#endif + +#if !defined(ASSERT) +#if defined DEBUG || defined DBG +# define HwFatalError() HwFatalErrorFrom(__FILE__, __LINE__) +# define ASSERT(cond) \ + if (!(cond)) \ + { \ +/* HwAssert(__FILE__, __LINE__, #cond);*/ \ + } +#else +# define ASSERT(cond) ((void)0) +#endif +#endif /* !defined(ASSERT) */ + +#define TRACE (_PRINTF(__FILE__"@%d\n", __LINE__)) + +#endif /* SYS_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/uxio.h linux/drivers/isdn/eicon/uxio.h --- v2.4.0-test6/linux/drivers/isdn/eicon/uxio.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/uxio.h Sun Aug 13 10:05:32 2000 @@ -0,0 +1,220 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.6 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Interface to Unix specific code for performing card I/O + */ + +#if !defined(UXIO_H) +#define UXIO_H + +#include "sys.h" +#include "adapter.h" + + +struct pt_regs; + +/* user callback, returns zero if interrupt was from this card */ +typedef void isr_fn_t(void *); +struct ux_diva_card_s +{ + word in_use; + int io_base; + int reset_base; + int card_type; + byte *mapped; + int bus_num; + int func_num; + int slot; + int irq; + byte *pDRAM; + byte *pDEVICES; + byte *pCONFIG; + byte *pSHARED; + byte *pCONTROL; + word features; + void *user_isr_arg; + isr_fn_t *user_isr; +}; + +void bcopy(void *pSource, void *pDest, dword dwLength); +void bzero(void *pDataArea, dword dwLength); + + +/* + * Get a card handle to enable card to be accessed + */ + +int UxCardHandleGet( ux_diva_card_t **card, + dia_card_t *cfg); + +/* + * Free a card handle as no longer needed + */ + +void UxCardHandleFree(ux_diva_card_t *card); + +/* + * Lock and unlock access to a card + */ + +int UxCardLock(ux_diva_card_t *card); +void UxCardUnlock(ux_diva_card_t *card, int ipl); + +/* + * Set the mapping address for PCI cards + */ + +int UxCardAddrMappingSet(ux_diva_card_t *card, + int id, + void *address, + int size); + +/* + * Attach card to memory to enable it to be accessed + * Returns the mapped address + */ + +void *UxCardMemAttach(ux_diva_card_t *card, int id); + +/* + * map card out of memory after completion of access + */ + +void UxCardMemDetach(ux_diva_card_t *card, void *address); + +/* + * input functions for memory-mapped cards + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address); + +word UxCardMemInW(ux_diva_card_t *card, void *address); + +dword UxCardMemInD(ux_diva_card_t *card, void *address); + +void UxCardMemInBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * output functions for memory-mapped cards + */ + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data); + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data); + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data); + +void UxCardMemOutBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * input functions for I/O-mapped cards + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *, void *address); + +word UxCardIoInW(ux_diva_card_t *card, void *, void *address); + +dword UxCardIoInD(ux_diva_card_t *card, void *, void *address); + +void UxCardIoInBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * output functions for I/O-mapped cards + */ + +void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data); + +void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data); + +void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data); + +void UxCardIoOutBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * Get specified PCI config + */ + +void UxPciConfigRead(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* + * Set specified PCI config + */ + +void UxPciConfigWrite(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* allocate memory, returning NULL if none available */ + +void *UxAlloc(unsigned int size); + +void UxFree(void *); + +/* + * Pause for specified number of milli-seconds + */ + +void UxPause(long ms); + +/* + * Install an ISR for the specified card + */ + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg); + +/* + * Remove an ISR for the specified card + */ +void UxIsrRemove(ux_diva_card_t *card, void *); + +/* + * DEBUG function to turn logging ON or OFF + */ + +void UxCardLog(int turn_on); + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst); +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst); + +#endif /* of UXIO_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/eicon/xlog.c linux/drivers/isdn/eicon/xlog.c --- v2.4.0-test6/linux/drivers/isdn/eicon/xlog.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/xlog.c Sun Aug 13 10:05:32 2000 @@ -0,0 +1,183 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Unix Eicon active card driver + * XLOG related functions + */ + +#include "sys.h" +#include "idi.h" +#include "pc.h" +#include "pc_maint.h" +#include "divalog.h" + +#include "adapter.h" +#include "uxio.h" + +/* + * convert/copy XLOG info into a KLOG entry + */ + +static +void xlog_to_klog(byte *b, int size, int card_num) + +{ + typedef struct + { + word code; + word time_hi; + word time_lo; + word xcode; + byte data[2]; + } card_xlog_t; + + card_xlog_t *x; + + klog_t klog; + + x = (card_xlog_t *) b; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = (dword) x->time_hi; + klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo; + + klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size; + + klog.card = card_num; + if (x->code == 1) + { + klog.type = KLOG_XTXT_MSG; + klog.code = 0; + bcopy(&x->xcode, klog.buffer, klog.length); + } + else if (x->code == 2) + { + klog.type = KLOG_XLOG_MSG; + klog.code = x->xcode; + bcopy(&x->data, klog.buffer, klog.length); + } + else + { + char *c; int i; + klog.type = KLOG_TEXT_MSG; + klog.code = 0; + c = "divas: invalid xlog message code from card"; + i = 0; + while (*c) + { + klog.buffer[i] = *c; + c++; + i++; + } + klog.buffer[i] = *c; + } + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} + +/* + * send an XLOG request down to specified card + * if response available from previous request then read it + * if not then just send down new request, ready for next time + */ + +void DivasXlogReq(int card_num) + +{ + card_t *card; + ADAPTER *a; + + if ((card_num < 0) || (card_num > DivasCardNext)) + { + DPRINTF(("xlog: invalid card number")); + return; + } + + card = &DivasCards[card_num]; + + if (DivasXlogRetrieve(card)) + { + return; + } + + /* send down request for next time */ + + a = &card->a; + + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return; +} + +/* + * retrieve XLOG request from specified card + * returns non-zero if new request sent to card + */ + +int DivasXlogRetrieve(card_t *card) + +{ + ADAPTER *a; + struct mi_pc_maint pcm; + + a = &card->a; + + /* get status of last request */ + + pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1)); + + /* if nothing there from previous request, send down a new one */ + + if (pcm.rc == OK) + { + /* read in response */ + + a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); + + xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), + (int) (card - DivasCards)); + } + + /* if any response received from card, re-send request */ + + if (pcm.rc) + { + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return 1; + } + + return 0; +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.4.0-test6/linux/drivers/isdn/hisax/Makefile Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/Makefile Mon Aug 21 07:49:02 2000 @@ -31,6 +31,8 @@ HFC_2BDS0 := JADE_OBJ := W6692_OBJ := +NETJ_OBJ := +ICC_OBJ := ifeq ($(CONFIG_HISAX_16_0),y) O_OBJS += teles0.o @@ -124,10 +126,17 @@ endif ifeq ($(CONFIG_HISAX_NETJET),y) - O_OBJS += netjet.o + O_OBJS += nj_s.o + NETJ_OBJ := netjet.o ISAC_OBJ := isac.o endif +ifeq ($(CONFIG_HISAX_NETJET_U),y) + O_OBJS += nj_u.o + NETJ_OBJ := netjet.o + ICC_OBJ := icc.o +endif + ifeq ($(CONFIG_HISAX_HFCS),y) O_OBJS += hfcscard.o HFC_2BDS0 := hfc_2bds0.o @@ -189,7 +198,7 @@ endif O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ) -O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) +O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) $(NETJ_OBJ) $(ICC_OBJ) OX_OBJS += config.o O_TARGET := @@ -208,10 +217,9 @@ MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ - elsa.c diva.c + elsa.c diva.c sedlbauer.c CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) cert.o: $(MD5FILES) md5sums.asc $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.4.0-test6/linux/drivers/isdn/hisax/avm_pci.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/avm_pci.c Mon Aug 21 07:49:02 2000 @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.17 2000/06/26 08:59:12 keil Exp $ +/* $Id: avm_pci.c,v 1.18 2000/08/20 07:34:04 keil Exp $ * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -17,13 +17,17 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.15 $"; +static const char *avm_pci_rev = "$Revision: 1.18 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 -#define PCI_VENDOR_AVM 0x1244 -#define PCI_FRITZPCI_ID 0xa00 +#ifndef PCI_VENDOR_ID_AVM +#define PCI_VENDOR_ID_AVM 0x1244 +#endif +#ifndef PCI_DEVICE_ID_AVM_FRITZ +#define PCI_DEVICE_ID_AVM_FRITZ 0xa00 +#endif #define HDLC_FIFO 0x0 #define HDLC_STATUS 0x4 @@ -293,7 +297,15 @@ if (cs->subtyp == AVM_FRITZ_PCI) { outl(idx, cs->hw.avm.cfg_reg + 4); while (cnt < count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#else + *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#endif /* CONFIG_APUS */ +#else *ptr++ = inl(cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -349,7 +361,15 @@ write_ctrl(bcs, 3); /* sets the correct index too */ if (cs->subtyp == AVM_FRITZ_PCI) { while (cnthw.avm.isac +_IO_BASE), *ptr++); +#else + out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); +#endif /* CONFIG_APUS */ +#else outl(*ptr++, cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -767,8 +787,8 @@ printk(KERN_ERR "FritzPCI: no PCI bus present\n"); return(0); } - if ((dev_avm = pci_find_device(PCI_VENDOR_AVM, - PCI_FRITZPCI_ID, dev_avm))) { + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_FRITZ, dev_avm))) { cs->irq = dev_avm->irq; if (!cs->irq) { printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); @@ -776,9 +796,9 @@ } if (pci_enable_device(dev_avm)) return(0); - cs->hw.avm.cfg_reg = pci_resource_start (dev_avm, 1); + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); if (!cs->hw.avm.cfg_reg) { - printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); return(0); } cs->subtyp = AVM_FRITZ_PCI; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.4.0-test6/linux/drivers/isdn/hisax/bkm_a4t.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/bkm_a4t.c Mon Aug 21 07:49:02 2000 @@ -18,12 +18,12 @@ #include "hscx.h" #include "jade.h" #include "isdnl1.h" -#include "bkm_ax.h" #include +#include "bkm_ax.h" extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.9 $"; +const char *bkm_a4t_revision = "$Revision: 1.11 $"; static inline u_char @@ -287,17 +287,20 @@ printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); return (0); } - if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) { - u_int sub_sys_id = 0; - - if (pci_enable_device(dev_a4t)) - return (0); - pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { + while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, + PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { + u16 sub_sys; + u16 sub_vendor; + + sub_vendor = dev_a4t->subsystem_vendor; + sub_sys = dev_a4t->subsystem_device; + if ((sub_sys == A4T_SUBSYS_ID) && (sub_vendor == A4T_SUBVEN_ID)) { + if (pci_enable_device(dev_a4t)) + return(0); found = 1; - pci_memaddr = pci_resource_start (dev_a4t, 0); + pci_memaddr = pci_resource_start(dev_a4t, 0); cs->irq = dev_a4t->irq; + break; } } if (!found) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.4.0-test6/linux/drivers/isdn/hisax/bkm_a8.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/bkm_a8.c Mon Aug 21 07:49:02 2000 @@ -17,29 +17,16 @@ #include "ipac.h" #include "hscx.h" #include "isdnl1.h" -#include "bkm_ax.h" #include +#include "bkm_ax.h" + +#if CONFIG_PCI #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.9 $"; - -/* To survive the startup phase */ -typedef struct { - u_int active; /* true/false */ - u_int base; /* ipac base address */ -} IPAC_STATE; - -static IPAC_STATE ipac_state[4 + 1] __initdata = -{ - {0, 0}, /* dummy */ - {0, 0}, /* SCT_1 */ - {0, 0}, /* SCT_2 */ - {0, 0}, /* SCT_3 */ - {0, 0} /* SCT_4 */ -}; +const char sct_quadro_revision[] = "$Revision: 1.12 $"; static const char *sct_quadro_subtypes[] = { @@ -138,19 +125,13 @@ writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); } -/* Check whether the specified ipac is already active or not */ -static int -is_ipac_active(u_int ipac_nr) -{ - return (ipac_state[ipac_nr].active); -} - /* Set the specific ipac to active */ static void -set_ipac_active(u_int ipac_nr, u_int active) +set_ipac_active(struct IsdnCardState *cs, u_int active) { - /* set activation state */ - ipac_state[ipac_nr].active = active; + /* set irq mask */ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, + active ? 0xc0 : 0xff); } /* @@ -173,13 +154,14 @@ { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; - int i; + if (!cs) { printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n"); return; } ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - + if (!(ista & 0x3f)) /* not this IPAC */ + return; Start_IPAC: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); @@ -216,30 +198,15 @@ sct_quadro_subtypes[cs->subtyp]); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); - - /* Read out all interrupt sources from currently not active ipacs */ - /* "Handle" all interrupts from currently not active ipac by reading the regs */ - for (i = SCT_1; i <= SCT_4; i++) - if (!is_ipac_active(i)) { - u_int base = ipac_state[i].base; - if (readreg(base, base + 4, 0xC1)) { - readreg(base, base + 4, 0xA0); - readreg(base, base + 4, 0xA4); - readreg(base, base + 4, 0x20); - readreg(base, base + 4, 0x24); - readreg(base, base + 4, 0x60); - readreg(base, base + 4, 0x64); - readreg(base, base + 4, 0xC1); - readreg(base, base + 4, ISAC_CIR0 + 0x80); - } - } } void release_io_sct_quadro(struct IsdnCardState *cs) { - /* ?? */ + release_region(cs->hw.ax.base & 0xffffffc0, 256); + if (cs->subtyp == SCT_1) + release_region(cs->hw.ax.plx_adr, 256); } static void @@ -249,11 +216,6 @@ if (bEnable) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); else - /* Issue general di only if no ipac is active */ - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); } } @@ -263,26 +225,17 @@ { long flags; - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) { - /* Issue total reset only if no ipac is active */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - - save_flags(flags); - sti(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - - /* Remove the soft reset */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - restore_flags(flags); - } + if (cs->subtyp == SCT_1) { + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); + save_flags(flags); + sti(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + /* Remove the soft reset */ + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); } } @@ -292,20 +245,19 @@ switch (mt) { case CARD_RESET: /* Disable ints */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); reset_bkm(cs); return (0); case CARD_RELEASE: /* Sanity */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); - reset_bkm(cs); release_io_sct_quadro(cs); return (0); case CARD_INIT: cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs->subtyp, 1); + set_ipac_active(cs, 1); inithscxisac(cs, 3); /* Enable ints */ enable_bkm_int(cs, 1); @@ -316,18 +268,38 @@ return (0); } +__initfunc(int +sct_alloc_io(u_int adr, u_int len)) +{ + if (check_region(adr, len)) { + printk(KERN_WARNING + "HiSax: Scitel port %#x-%#x already in use\n", + adr, adr + len); + return (1); + } else { + request_region(adr, len, "scitel"); + } + return(0); +} + static struct pci_dev *dev_a8 __initdata = NULL; +static u16 sub_vendor_id __initdata = 0; +static u16 sub_sys_id __initdata = 0; +static u_char pci_bus __initdata = 0; +static u_char pci_device_fn __initdata = 0; +static u_char pci_irq __initdata = 0; + +#endif /* CONFIG_PCI */ __initfunc(int - setup_sct_quadro(struct IsdnCard *card)) +setup_sct_quadro(struct IsdnCard *card)) { +#if CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI - u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id; + u_char pci_rev_id; u_int found = 0; u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; -#endif strcpy(tmp, sct_quadro_revision); printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); @@ -339,32 +311,61 @@ /* Identify subtype by para[0] */ if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) cs->subtyp = card->para[0]; - else + else { printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n", - CardType[card->typ]); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + CardType[card->typ]); return (0); } - if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) { - u_int sub_sys_id = 0; - - pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) { - found = 1; - pci_ioaddr1 = dev_a8->resource[ 1].start; - pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; - } - } - if (!found) { - printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); + if ((cs->subtyp != SCT_1) && ((sub_sys_id != SCT_SUBSYS_ID) || + (sub_vendor_id != SCT_SUBVEN_ID))) return (0); + if (cs->subtyp == SCT_1) { + if (!pci_present()) { + printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + return (0); + } + while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX, + PCI_DEVICE_ID_PLX_9050, dev_a8))) { + + sub_vendor_id = dev_a8->subsystem_vendor; + sub_sys_id = dev_a8->subsystem_device; + if ((sub_sys_id == SCT_SUBSYS_ID) && + (sub_vendor_id == SCT_SUBVEN_ID)) { + if (pci_enable_device(dev_a8)) + return(0); + pci_ioaddr1 = pci_resource_start(dev_a8, 1); + pci_irq = dev_a8->irq; + pci_bus = dev_a8->bus->number; + pci_device_fn = dev_a8->devfn; + found = 1; + break; + } + } + if (!found) { + printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } +#ifdef ATTEMPT_PCI_REMAPPING +/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_REVISION_ID, &pci_rev_id); + if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { + printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + /* Restart PCI negotiation */ + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, (u_int) - 1); + /* Move up by 0x80 byte */ + pci_ioaddr1 += 0x80; + pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, pci_ioaddr1); + dev_a8->resource[ 1].start = pci_ioaddr1; + } +#endif /* End HACK */ } if (!pci_irq) { /* IRQ range check ?? */ printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n", @@ -372,25 +373,6 @@ sct_quadro_subtypes[cs->subtyp]); return (0); } -#ifdef ATTEMPT_PCI_REMAPPING -/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id); - if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { - printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - /* Restart PCI negotiation */ - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, (u_int) - 1); - /* Move up by 0x80 byte */ - pci_ioaddr1 += 0x80; - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, pci_ioaddr1); - dev_a8->resource[ 1].start = pci_ioaddr1; - } -/* End HACK */ -#endif pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3); @@ -417,23 +399,42 @@ /* pci_ioaddr5 is for the first subdevice only */ cs->hw.ax.plx_adr = pci_ioaddr1; /* Enter all ipac_base addresses */ - ipac_state[SCT_1].base = pci_ioaddr5 + 0x00; - ipac_state[SCT_2].base = pci_ioaddr4 + 0x08; - ipac_state[SCT_3].base = pci_ioaddr3 + 0x10; - ipac_state[SCT_4].base = pci_ioaddr2 + 0x20; - /* For isac and hscx control path */ - cs->hw.ax.base = ipac_state[cs->subtyp].base; + switch(cs->subtyp) { + case 1: + cs->hw.ax.base = pci_ioaddr5 + 0x00; + if (sct_alloc_io(pci_ioaddr1, 256)) + return(0); + if (sct_alloc_io(pci_ioaddr5, 256)) + return(0); + /* disable all IPAC */ + writereg(pci_ioaddr5, pci_ioaddr5 + 4, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, + IPAC_MASK, 0xFF); + break; + case 2: + cs->hw.ax.base = pci_ioaddr4 + 0x08; + if (sct_alloc_io(pci_ioaddr4, 256)) + return(0); + break; + case 3: + cs->hw.ax.base = pci_ioaddr3 + 0x10; + if (sct_alloc_io(pci_ioaddr3, 256)) + return(0); + break; + case 4: + cs->hw.ax.base = pci_ioaddr2 + 0x20; + if (sct_alloc_io(pci_ioaddr2, 256)) + return(0); + break; + } /* For isac and hscx data path */ cs->hw.ax.data_adr = cs->hw.ax.base + 4; -#else - printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - return (0); -#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n", CardType[card->typ], sct_quadro_subtypes[cs->subtyp], @@ -444,19 +445,6 @@ test_and_set_bit(HW_IPAC, &cs->HW_Flags); - /* Disable all currently not active ipacs */ - if (!is_ipac_active(SCT_1)) - set_ipac_active(SCT_1, 0); - if (!is_ipac_active(SCT_2)) - set_ipac_active(SCT_2, 0); - if (!is_ipac_active(SCT_3)) - set_ipac_active(SCT_3, 0); - if (!is_ipac_active(SCT_4)) - set_ipac_active(SCT_4, 0); - - /* Perfom general reset (if possible) */ - reset_bkm(cs); - cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; @@ -473,4 +461,7 @@ sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); +#else + printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); +#endif /* CONFIG_PCI */ } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/bkm_ax.h linux/drivers/isdn/hisax/bkm_ax.h --- v2.4.0-test6/linux/drivers/isdn/hisax/bkm_ax.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/bkm_ax.h Mon Aug 21 07:49:02 2000 @@ -19,13 +19,21 @@ /* A4T */ -#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */ -#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */ +#ifndef PCI_VENDOR_ID_ZORAN +#define PCI_VENDOR_ID_ZORAN 0x11DE +#endif +#ifndef PCI_DEVICE_ID_ZORAN_36120 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 +#endif #define A4T_SUBVEN_ID 0x0871 #define A4T_SUBSYS_ID 0xFFA4 /* Scitel Quadro */ -#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */ -#define PLX_VENDOR_ID 0x10B5 +#ifndef PCI_VENDOR_ID_PLX +#define PCI_VENDOR_ID_PLX 0x10B5 +#endif +#ifndef PCI_DEVICE_ID_PLX_9050 +#define PCI_DEVICE_ID_PLX_9050 0x9050 +#endif #define SCT_SUBVEN_ID 0x0871 #define SCT_SUBSYS_ID 0xFFA8 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.4.0-test6/linux/drivers/isdn/hisax/callc.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/callc.c Mon Aug 21 07:49:02 2000 @@ -366,7 +366,7 @@ * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ - memcpy (&ic.parm.setup, &chanp->proc->para.setup, sizeof(ic.parm.setup)); + memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); @@ -383,12 +383,16 @@ FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { - memcpy (&chanp->setup, &ic.parm.setup, sizeof(chanp->setup)); + memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; case 2: /* Rejecting Call */ break; + case 3: /* incomplete number */ + FsmDelTimer(&chanp->drel_timer, 61); + chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); + break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); @@ -795,6 +799,8 @@ {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, + {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call}, + {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error}, {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, @@ -956,6 +962,9 @@ return; switch (pr) { + case (CC_MORE_INFO | INDICATION): + FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); + break; case (CC_DISCONNECT | INDICATION): FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); break; @@ -1103,7 +1112,7 @@ chanp->fi.printdebug = callc_debug; FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); - if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { + if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { init_d_st(chanp); } else { chanp->d_st = csta->channel->d_st; @@ -1176,9 +1185,12 @@ switch (pr) { case (DL_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lldata: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { + } else { + link_debug(chanp, 0, "lldata: channel not open"); dev_kfree_skb(skb); } break; @@ -1205,10 +1217,12 @@ switch (pr) { case (PH_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lltrans: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { - link_debug(chanp, 0, "channel not open"); + } else { + link_debug(chanp, 0, "lltrans: channel not open"); dev_kfree_skb(skb); } break; @@ -1233,6 +1247,8 @@ struct Channel *chanp = st->lli.userdata; isdn_ctrl ic; + if (chanp->debug & 0x800) + link_debug(chanp, 0, "llwakeup: %d", len); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BSENT; ic.arg = chanp->chan; @@ -1506,7 +1522,7 @@ link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", ic->parm.setup.eazmsn, ic->parm.setup.phone, ic->parm.setup.si1, ic->parm.setup.si2); - memcpy (&chanp->setup, &ic->parm.setup, sizeof (chanp->setup)); + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; /* this solution is dirty and may be change, if @@ -1526,6 +1542,7 @@ break; case (ISDN_CMD_ACCEPTD): chanp = csta->channel + ic->arg; + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (chanp->debug & 1) link_debug(chanp, 1, "ACCEPTD"); FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); @@ -1722,7 +1739,7 @@ chanp = csta->channel + ic->arg; if (chanp->debug & 1) link_debug(chanp, 1, "REDIR"); - memcpy (&chanp->setup, &ic->parm.setup, sizeof(chanp->setup)); + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); FsmEvent(&chanp->fi, EV_REDIR, NULL); break; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c --- v2.4.0-test6/linux/drivers/isdn/hisax/cert.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/cert.c Mon Aug 21 07:49:02 2000 @@ -17,11 +17,9 @@ #if CERTIFICATION == 0 if (output) { printk(KERN_INFO "HiSax: Approval certification valid\n"); - printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n"); - printk(KERN_INFO "HiSax: Approval registration numbers:\n"); - printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n"); - printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n"); + printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n"); printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n"); + printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n"); } return(0); #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.4.0-test6/linux/drivers/isdn/hisax/config.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/config.c Mon Aug 21 07:49:02 2000 @@ -47,7 +47,7 @@ * 17 MIC card p0=irq p1=iobase * 18 ELSA Quickstep 1000PCI no parameter * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 - * 20 Travers Technologies NETjet PCI card + * 20 Travers Technologies NETjet-S PCI card * 21 TELES PCI no parameter * 22 Sedlbauer Speed Star p0=irq p1=iobase * 23 reserved @@ -65,6 +65,7 @@ * 35 HFC 2BDS0 PCI none * 36 Winbond 6692 PCI none * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase + * 38 Travers Technologies NETspider-U PCI card * * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * @@ -76,11 +77,11 @@ "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", - "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", + "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", - "HFC 2BDS0 SX", + "HFC 2BDS0 SX", "NETspider-U", }; void HiSax_closecard(int cardnr); @@ -106,7 +107,6 @@ #define DEFAULT_CFG {11,0x170,0,0} int avm_a1_init_pcmcia(void*, int, int*, int); EXPORT_SYMBOL(avm_a1_init_pcmcia); -EXPORT_SYMBOL(HiSax_closecard); #endif /* CONFIG_HISAX_AVM_A1_PCMCIA */ #ifdef CONFIG_HISAX_FRITZPCI @@ -198,7 +198,7 @@ #ifdef CONFIG_HISAX_NETJET #undef DEFAULT_CARD #undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NETJET +#define DEFAULT_CARD ISDN_CTYPE_NETJET_S #define DEFAULT_CFG {0,0,0,0} #endif @@ -280,22 +280,29 @@ #define DEFAULT_CFG {0,0,0,0} #endif +#ifdef CONFIG_HISAX_NETJET_U +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NETJET_U +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_1TR6 #define DEFAULT_PROTO ISDN_PTYPE_1TR6 #define DEFAULT_PROTO_NAME "1TR6" #endif -#ifdef CONFIG_HISAX_EURO -#undef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_EURO -#undef DEFAULT_PROTO_NAME -#define DEFAULT_PROTO_NAME "EURO" -#endif #ifdef CONFIG_HISAX_NI1 #undef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_NI1 #undef DEFAULT_PROTO_NAME #define DEFAULT_PROTO_NAME "NI1" #endif +#ifdef CONFIG_HISAX_EURO +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_EURO +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "EURO" +#endif #ifndef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN #define DEFAULT_PROTO_NAME "UNKNOWN" @@ -304,6 +311,10 @@ #error "HiSax: No cards configured" #endif +int hisax_init_pcmcia(void *, int *, struct IsdnCard *); +EXPORT_SYMBOL(hisax_init_pcmcia); +EXPORT_SYMBOL(HiSax_closecard); + #define FIRST_CARD { \ DEFAULT_CARD, \ DEFAULT_PROTO, \ @@ -400,9 +411,9 @@ printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); @@ -546,8 +557,8 @@ extern int setup_mic(struct IsdnCard *card); #endif -#if CARD_NETJET -extern int setup_netjet(struct IsdnCard *card); +#if CARD_NETJET_S +extern int setup_netjet_s(struct IsdnCard *card); #endif #if CARD_HFCS @@ -598,6 +609,10 @@ extern int setup_w6692(struct IsdnCard *card); #endif +#if CARD_NETJET_U +extern int setup_netjet_u(struct IsdnCard *card); +#endif + /* * Find card with given driverId */ @@ -800,7 +815,7 @@ ic.command = ISDN_STAT_STOP; ic.driver = cs->myid; cs->iif.statcallb(&ic); - CallcFreeChan(cs); +// CallcFreeChan(cs); } static void @@ -923,6 +938,8 @@ cs->busy_flag = busy_flag; cs->irq_flags = I4L_IRQ_FLAG; #if TEI_PER_CARD + if (card->protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #else test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #endif @@ -1067,9 +1084,9 @@ ret = setup_mic(card); break; #endif -#if CARD_NETJET - case ISDN_CTYPE_NETJET: - ret = setup_netjet(card); +#if CARD_NETJET_S + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); break; #endif #if CARD_HFCS @@ -1133,6 +1150,11 @@ ret = setup_w6692(card); break; #endif +#if CARD_NETJET_U + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; +#endif default: printk(KERN_WARNING "HiSax: Support for %s Card not selected\n", @@ -1252,6 +1274,9 @@ if (cards[cardnr].cs) { ll_stop(cards[cardnr].cs); release_tei(cards[cardnr].cs); + + CallcFreeChan(cards[cardnr].cs); + closecard(cardnr); if (cards[cardnr].cs->irq) free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); @@ -1310,10 +1335,19 @@ __initfunc(int HiSax_init(void)) { - int i; + int i,j; #ifdef MODULE int nzproto = 0; + if (!type[0]) { + /* We 'll register drivers later, but init basic functions*/ + CallcNew(); + Isdnl3New(); + Isdnl2New(); + TeiNew(); + Isdnl1New(); + return 0; + } #ifdef CONFIG_HISAX_ELSA if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { /* we have exported and return in this case */ @@ -1338,41 +1372,41 @@ #ifdef MODULE if (id) /* If id= string used */ HiSax_id = id; - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].typ = type[i]; + for (i = j = 0; j < HISAX_MAX_CARDS; i++) { + cards[j].typ = type[i]; if (protocol[i]) { - cards[i].protocol = protocol[i]; + cards[j].protocol = protocol[i]; nzproto++; } switch (type[i]) { case ISDN_CTYPE_16_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; - cards[i].para[2] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; + cards[j].para[2] = io[i]; break; case ISDN_CTYPE_8_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; break; #ifdef IO0_IO1 case ISDN_CTYPE_PNP: case ISDN_CTYPE_NICCY: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; break; case ISDN_CTYPE_COMPAQ_ISA: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; - cards[i].para[3] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; + cards[j].para[3] = io[i]; break; #endif case ISDN_CTYPE_ELSA: case ISDN_CTYPE_HFC_PCI: - cards[i].para[0] = io[i]; + cards[j].para[0] = io[i]; break; case ISDN_CTYPE_16_3: case ISDN_CTYPE_TELESPCMCIA: @@ -1396,26 +1430,42 @@ case ISDN_CTYPE_HSTSAPHIR: case ISDN_CTYPE_GAZEL: case ISDN_CTYPE_HFC_SX: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; break; case ISDN_CTYPE_ISURF: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].para[2] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; + cards[j].para[2] = mem[i]; break; case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET: + case ISDN_CTYPE_NETJET_S: case ISDN_CTYPE_AMD7930: case ISDN_CTYPE_TELESPCI: case ISDN_CTYPE_W6692: + case ISDN_CTYPE_NETJET_U: break; case ISDN_CTYPE_BKM_A4T: - break; + break; case ISDN_CTYPE_SCT_QUADRO: - cards[i].para[0] = irq[i]; + if (irq[i]) { + cards[j].para[0] = irq[i]; + } else { + /* QUADRO is a 4 BRI card */ + cards[j++].para[0] = 1; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 2; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 3; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j].para[0] = 4; + } break; } + j++; } if (!nzproto) { printk(KERN_WARNING "HiSax: Warning - no protocol specified\n"); @@ -1620,3 +1670,21 @@ return (0); } #endif + +int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) +{ + u_char ids[16]; + int ret = -1; + + cards[nrcards] = *card; + if (nrcards) + sprintf(ids, "HiSax%d", nrcards); + else + sprintf(ids, "HiSax"); + if (!checkcard(nrcards, ids, busy_flag)) { + return(-1); + } + ret = nrcards; + nrcards++; + return (ret); +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.4.0-test6/linux/drivers/isdn/hisax/diva.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/diva.c Mon Aug 21 07:49:03 2000 @@ -47,12 +47,18 @@ #define DIVA_IPAC_PCI 4 /* PCI stuff */ -#define PCI_VENDOR_EICON_DIEHL 0x1133 -#define PCI_DIVA20PRO_ID 0xe001 -#define PCI_DIVA20_ID 0xe002 -#define PCI_DIVA20PRO_U_ID 0xe003 -#define PCI_DIVA20_U_ID 0xe004 -#define PCI_DIVA_201 0xe005 +#ifndef PCI_VENDOR_ID_EICON +#define PCI_VENDOR_ID_EICON 0x1133 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA20 +#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA20_U +#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA201 +#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 +#endif /* CTRL (Read) */ #define DIVA_IRQ_STAT 0x01 @@ -70,10 +76,16 @@ /* Siemens PITA */ #define PITA_MISC_REG 0x1c +#ifdef __BIG_ENDIAN +#define PITA_PARA_SOFTRESET 0x00000001 +#define PITA_PARA_MPX_MODE 0x00000004 +#define PITA_INT0_ENABLE 0x00000200 +#else #define PITA_PARA_SOFTRESET 0x01000000 #define PITA_PARA_MPX_MODE 0x04000000 #define PITA_INT0_ENABLE 0x00020000 -#define PITA_INT0_STATUS 0x00000002 +#endif +#define PITA_INT0_STATUS 0x02 static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -122,7 +134,7 @@ static inline u_char memreadreg(unsigned long adr, u_char off) { - return(0xff & *((unsigned int *) + return(*((unsigned char *) (((unsigned int *)adr) + off))); } @@ -870,24 +882,24 @@ } cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, dev_diva))) { + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { if (pci_enable_device(dev_diva)) - return (0); + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva->irq; cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_U_ID, dev_diva_u))) { + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { if (pci_enable_device(dev_diva_u)) - return (0); + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva_u->irq; cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA_201, dev_diva201))) { + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { if (pci_enable_device(dev_diva201)) - return (0); + return(0); cs->subtyp = DIVA_IPAC_PCI; cs->irq = dev_diva201->irq; cs->hw.diva.pci_cfg = diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.4.0-test6/linux/drivers/isdn/hisax/elsa.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/elsa.c Mon Aug 21 07:49:03 2000 @@ -29,10 +29,10 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.20 $"; +const char *Elsa_revision = "$Revision: 2.23 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", + "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", "PCMCIA-IPAC" }; const char *ITACVer[] = @@ -66,9 +66,15 @@ #define ELSA_PCMCIA_IPAC 11 /* PCI stuff */ -#define PCI_VENDOR_ELSA 0x1048 -#define PCI_QS1000_ID 0x1000 -#define PCI_QS3000_ID 0x3000 +#ifndef PCI_VENDOR_ID_ELSA +#define PCI_VENDOR_ID_ELSA 0x1048 +#endif +#ifndef PCI_DEVICE_ID_ELSA_MIRCOLINK +#define PCI_DEVICE_ID_ELSA_MIRCOLINK 0x1000 +#endif +#ifndef PCI_DEVICE_ID_ELSA_QS3000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 +#endif #define ELSA_PCI_IRQ_MASK 0x04 /* ITAC Registeradressen (only Microlink PC) */ @@ -723,7 +729,8 @@ cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", cs->hw.elsa.counter); - if (abs(cs->hw.elsa.counter - 13) < 3) { + if ((cs->hw.elsa.counter > 10) && + (cs->hw.elsa.counter < 16)) { printk(KERN_INFO "Elsa: timer and irq OK\n"); ret = 0; } else { @@ -982,18 +989,18 @@ return(0); } cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, - dev_qs1000))) { + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MIRCOLINK, dev_qs1000))) { if (pci_enable_device(dev_qs1000)) - return (0); + return(0); cs->subtyp = ELSA_QS1000PCI; cs->irq = dev_qs1000->irq; cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, - PCI_QS3000_ID, dev_qs3000))) { - if (pci_enable_device(dev_qs1000)) - return (0); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) + return(0); cs->subtyp = ELSA_QS3000PCI; cs->irq = dev_qs3000->irq; cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.4.0-test6/linux/drivers/isdn/hisax/gazel.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/gazel.c Mon Aug 21 07:49:03 2000 @@ -26,10 +26,18 @@ #define R742 4 /* Gazel R685 stuff */ -#define GAZEL_MANUFACTURER 0x10b5 -#define GAZEL_R685 0x1030 -#define GAZEL_R753 0x1152 -#define GAZEL_DJINN_ITOO 0x1151 +#ifndef PCI_VENDOR_ID_PLX +#define PCI_VENDOR_ID_PLX 0x10b5 +#endif +#ifndef PCI_DEVICE_ID_PLX_R685 +#define PCI_DEVICE_ID_PLX_R685 0x1030 +#endif +#ifndef PCI_DEVICE_ID_PLX_R753 +#define PCI_DEVICE_ID_PLX_R753 0x1152 +#endif +#ifndef PCI_DEVICE_ID_PLX_DJINN_ITOO +#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 +#endif #define PLX_CNTRL 0x50 /* registre de controle PLX */ #define RESET_GAZEL 0x4 @@ -565,25 +573,25 @@ printk(KERN_WARNING "Gazel: No PCI bus present\n"); return 1; } - seekcard = GAZEL_R685; + seekcard = PCI_DEVICE_ID_PLX_R685; for (nbseek = 0; nbseek < 3; nbseek++) { - if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) { + if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) { if (pci_enable_device(dev_tel)) return 1; pci_irq = dev_tel->irq; - pci_ioaddr0 = dev_tel->resource[ 1].start; - pci_ioaddr1 = dev_tel->resource[ 2].start; + pci_ioaddr0 = pci_resource_start(dev_tel, 1); + pci_ioaddr1 = pci_resource_start(dev_tel, 2); found = 1; } if (found) break; else { switch (seekcard) { - case GAZEL_R685: - seekcard = GAZEL_R753; + case PCI_DEVICE_ID_PLX_R685: + seekcard = PCI_DEVICE_ID_PLX_R753; break; - case GAZEL_R753: - seekcard = GAZEL_DJINN_ITOO; + case PCI_DEVICE_ID_PLX_R753: + seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; break; } } @@ -612,7 +620,7 @@ cs->irq_flags |= SA_SHIRQ; switch (seekcard) { - case GAZEL_R685: + case PCI_DEVICE_ID_PLX_R685: printk(KERN_INFO "Gazel: Card PCI R685 found\n"); cs->subtyp = R685; cs->dc.isac.adf2 = 0x87; @@ -623,8 +631,8 @@ "Gazel: hscx A:0x%X hscx B:0x%X\n", cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); break; - case GAZEL_R753: - case GAZEL_DJINN_ITOO: + case PCI_DEVICE_ID_PLX_R753: + case PCI_DEVICE_ID_PLX_DJINN_ITOO: printk(KERN_INFO "Gazel: Card PCI R753 found\n"); cs->subtyp = R753; test_and_set_bit(HW_IPAC, &cs->HW_Flags); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.4.0-test6/linux/drivers/isdn/hisax/hfc_2bs0.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.14 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.15 2000/07/26 20:46:47 keil Exp $ * * specific routines for CCD's HFC 2BS0 * @@ -203,7 +203,7 @@ ptr = skb_put(skb, count); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx < count - 3) && WaitNoBusy(cs)) { + while ((idx < count) && WaitNoBusy(cs)) { *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.4.0-test6/linux/drivers/isdn/hisax/hfc_pci.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/hfc_pci.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.30 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_pci.c,v 1.31 2000/08/20 07:32:55 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -34,7 +34,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.30 $"; +static const char *hfcpci_revision = "$Revision: 1.31 $"; /* table entry in the PCI devices list */ typedef struct { @@ -44,7 +44,9 @@ char *card_name; } PCI_ENTRY; -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ static const PCI_ENTRY id_list[] = { @@ -63,7 +65,10 @@ {0x1051, 0x0100, "Motorola MC145575", "MC145575"}, {0x1397, 0xB100, "Seyeon", "B100"}, {0x15B0, 0x2BD0, "Zoltrix", "2BD0"}, - {0x114f, 0x71, "Digi intl.","Digicom"}, + {0x114F, 0x70,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"}, + {0x114F, 0x71,"Digi International", "Digi DataFire Micro V (Europe)"}, + {0x114F, 0x72,"Digi International", "Digi DataFire Micro V IOM2 (North America)"}, + {0x114F, 0x73,"Digi International", "Digi DataFire Micro V (North America)"}, {0, 0, NULL, NULL}, }; @@ -130,7 +135,7 @@ cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */ cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ cs->hw.hfcpci.bswapped = 0; /* no exchange */ @@ -254,6 +259,9 @@ (*(bdata + (zp->z1 - B_SUB_VAL)))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); +#ifdef ERROR_STATISTIC + bcs->err_inv++; +#endif bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ skb = NULL; @@ -320,6 +328,9 @@ (df->data[zp->z1])) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); } else if ((skb = dev_alloc_skb(rcnt - 3))) { @@ -506,6 +517,9 @@ if (fcnt > (MAX_D_FRAMES - 1)) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif return; } /* now determine free bytes in FIFO buffer */ @@ -740,6 +754,7 @@ (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { save_flags(flags); cli(); + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT; @@ -1625,6 +1640,9 @@ int i; struct pci_dev *tmp_hfcpci = NULL; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); #if CONFIG_PCI @@ -1645,7 +1663,7 @@ if (tmp_hfcpci) { if (pci_enable_device(tmp_hfcpci)) continue; - if ((card->para[0]) && (card->para[0] != pci_resource_start(tmp_hfcpci, 0))) + if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; else break; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.4.0-test6/linux/drivers/isdn/hisax/hisax.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/hisax.h Mon Aug 21 07:49:03 2000 @@ -39,8 +39,11 @@ #define HW_POWERUP 0x0008 #define HW_ACTIVATE 0x0010 #define HW_DEACTIVATE 0x0018 + +#define HW_INFO1 0x0010 #define HW_INFO2 0x0020 #define HW_INFO3 0x0030 +#define HW_INFO4 0x0040 #define HW_INFO4_P8 0x0040 #define HW_INFO4_P10 0x0048 #define HW_RSYNC 0x0060 @@ -90,6 +93,7 @@ #define CC_SUSPEND 0x0370 #define CC_PROCEED_SEND 0x0374 #define CC_REDIR 0x0378 +#define CC_T302 0x0382 #define CC_T303 0x0383 #define CC_T304 0x0384 #define CC_T305 0x0385 @@ -100,6 +104,7 @@ #define CC_T313 0x0393 #define CC_T318 0x0398 #define CC_T319 0x0399 +#define CC_TSPID 0x03A0 #define CC_NOSETUP_RSP 0x03E0 #define CC_SETUP_ERR 0x03E1 #define CC_SUSPEND_ERR 0x03E2 @@ -108,6 +113,7 @@ #define CC_RELEASE_ERR 0x03E5 #define CC_RESTART 0x03F4 #define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ +#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */ /* define maximum number of possible waiting incoming calls */ #define MAX_WAITING_CALLS 2 @@ -115,13 +121,19 @@ #ifdef __KERNEL__ -/* include only l3dss1 specific process structures, but no other defines */ +/* include l3dss1 & ni1 specific process structures, but no other defines */ #ifdef CONFIG_HISAX_EURO #define l3dss1_process #include "l3dss1.h" #undef l3dss1_process #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + #define l3ni1_process + #include "l3ni1.h" + #undef l3ni1_process +#endif CONFIG_HISAX_NI1 + #define MAX_DFRAME_LEN 260 #define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096 @@ -184,6 +196,7 @@ #define FLG_L1_ACTTIMER 4 #define FLG_L1_T3RUN 5 #define FLG_L1_PULL_REQ 6 +#define FLG_L1_UINT 7 struct Layer1 { void *hardware; @@ -298,7 +311,7 @@ struct Layer3 l3; struct LLInterface lli; struct Management ma; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ /* protocol specific data fields */ union @@ -306,6 +319,9 @@ #ifdef CONFIG_HISAX_EURO dss1_stk_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_stk_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -327,6 +343,9 @@ #ifdef CONFIG_HISAX_EURO dss1_proc_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_proc_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -373,10 +392,17 @@ }; struct hdlc_stat_reg { +#ifdef __BIG_ENDIAN + u_char fill __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char cmd __attribute__((packed)); +#else u_char cmd __attribute__((packed)); u_char xml __attribute__((packed)); u_char mode __attribute__((packed)); u_char fill __attribute__((packed)); +#endif }; struct hdlc_hw { @@ -805,6 +831,22 @@ int ph_state; }; +struct icc_chip { + int ph_state; + u_char *mon_tx; + u_char *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; + wait_queue_head_t arcofi_wait; + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; +}; + #define HW_IOM1 0 #define HW_IPAC 1 #define HW_ISAR 2 @@ -815,6 +857,7 @@ #define FLG_LOCK_ATOMIC 7 #define FLG_ARCOFI_TIMER 8 #define FLG_ARCOFI_ERROR 9 +#define FLG_HW_L1_UINT 10 struct IsdnCardState { unsigned char typ; @@ -883,6 +926,7 @@ struct hfcpci_chip hfcpci; struct hfcsx_chip hfcsx; struct w6692_chip w6692; + struct icc_chip icc; } dc; u_char *rcvbuf; int rcvidx; @@ -924,7 +968,7 @@ #define ISDN_CTYPE_MIC 17 #define ISDN_CTYPE_ELSA_PCI 18 #define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET 20 +#define ISDN_CTYPE_NETJET_S 20 #define ISDN_CTYPE_TELESPCI 21 #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 @@ -942,7 +986,8 @@ #define ISDN_CTYPE_HFC_PCI 35 #define ISDN_CTYPE_W6692 36 #define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_COUNT 37 +#define ISDN_CTYPE_NETJET_U 38 +#define ISDN_CTYPE_COUNT 38 #ifdef ISDN_CHIP_ISAC @@ -1091,12 +1136,12 @@ #endif #ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET 1 +#define CARD_NETJET_S 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif #else -#define CARD_NETJET 0 +#define CARD_NETJET_S 0 #endif #ifdef CONFIG_HISAX_HFCS @@ -1204,17 +1249,19 @@ #define CARD_W6692 0 #endif -#define TEI_PER_CARD 0 - -#ifdef CONFIG_HISAX_1TR6 -#undef TEI_PER_CARD -#define TEI_PER_CARD 1 +#ifdef CONFIG_HISAX_NETJET_U +#define CARD_NETJET_U 1 +#ifndef ISDN_CHIP_ICC +#define ISDN_CHIP_ICC 1 +#endif +#ifndef HISAX_UINTERFACE +#define HISAX_UINTERFACE 1 +#endif +#else +#define CARD_NETJET_U 0 #endif -#ifdef CONFIG_HISAX_EURO -#undef TEI_PER_CARD #define TEI_PER_CARD 1 -#endif /* L1 Debug */ #define L1_DEB_WARN 0x01 @@ -1238,7 +1285,7 @@ struct IsdnCard { int typ; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ unsigned int para[4]; struct IsdnCardState *cs; }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c --- v2.4.0-test6/linux/drivers/isdn/hisax/icc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/icc.c Mon Aug 21 07:49:03 2000 @@ -0,0 +1,685 @@ +// $Id: icc.c,v 1.3 2000/08/20 07:34:04 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.6.25 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include "hisax.h" +#include "icc.h" +// #include "arcofi.h" +#include "isdnl1.h" +#include + +#define DBUSY_TIMER_VALUE 80 +#define ARCOFI_USE 0 + +static char *ICCVer[] HISAX_INITDATA = +{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; + +void +ICCVersion(struct IsdnCardState *cs, char *s) +{ + int val; + + val = cs->readisac(cs, ICC_RBCH); + printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); +} + +static void +ph_command(struct IsdnCardState *cs, unsigned int command) +{ + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_command %x", command); + cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); +} + + +static void +icc_new_ph(struct IsdnCardState *cs) +{ + switch (cs->dc.icc.ph_state) { + case (ICC_IND_EI1): + ph_command(cs, ICC_CMD_DI); + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + case (ICC_IND_DC): + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); + break; + case (ICC_IND_DR): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + case (ICC_IND_PU): + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + case (ICC_IND_FJ): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + case (ICC_IND_AR): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + case (ICC_IND_AI): + l1_msg(cs, HW_INFO4 | INDICATION, NULL); + break; + default: + break; + } +} + +static void +icc_bh(struct IsdnCardState *cs) +{ + struct PStack *stptr; + + if (!cs) + return; + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) + debugl1(cs, "D-Channel Busy cleared"); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr = stptr->next; + } + } + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) + icc_new_ph(cs); + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) + DChannel_proc_rcv(cs); + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) + DChannel_proc_xmt(cs); +#if ARCOFI_USE + if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) + return; + if (test_and_clear_bit(D_RX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_RX_END, NULL); + if (test_and_clear_bit(D_TX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_TX_END, NULL); +#endif +} + +void +icc_empty_fifo(struct IsdnCardState *cs, int count) +{ + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeisac(cs, ICC_CMDR, 0x80); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + save_flags(flags); + cli(); + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, 0x80); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +static void +icc_fill_fifo(struct IsdnCardState *cs) +{ + int count, more; + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_fill_fifo"); + + if (!cs->tx_skb) + return; + + count = cs->tx_skb->len; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + save_flags(flags); + cli(); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); + if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + debugl1(cs, "icc_fill_fifo dbusytimer running"); + del_timer(&cs->dbusytimer); + } + init_timer(&cs->dbusytimer); + cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dbusytimer); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +void +icc_sched_event(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + queue_task(&cs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +void +icc_interrupt(struct IsdnCardState *cs, u_char val) +{ + u_char exval, v1; + struct sk_buff *skb; + unsigned int count; + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC interrupt %x", val); + if (val & 0x80) { /* RME */ + exval = cs->readisac(cs, ICC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RDO"); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif + } + if (!(exval & 0x20)) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC CRC error"); +#ifdef ERROR_STATISTIC + cs->err_crc++; +#endif + } + cs->writeisac(cs, ICC_CMDR, 0x80); + } else { + count = cs->readisac(cs, ICC_RBCL) & 0x1f; + if (count == 0) + count = 32; + icc_empty_fifo(cs, count); + save_flags(flags); + cli(); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + restore_flags(flags); + } + cs->rcvidx = 0; + icc_sched_event(cs, D_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + icc_empty_fifo(cs, 32); + } + if (val & 0x20) { /* RSC */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + icc_fill_fifo(cs); + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else + icc_sched_event(cs, D_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + exval = cs->readisac(cs, ICC_CIR0); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR0 %02X", exval ); + if (exval & 2) { + cs->dc.icc.ph_state = (exval >> 2) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); + icc_sched_event(cs, D_L1STATECHANGE); + } + if (exval & 1) { + exval = cs->readisac(cs, ICC_CIR1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR1 %02X", exval ); + } + } + if (val & 0x02) { /* SIN */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = cs->readisac(cs, ICC_EXIR); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC EXIR %02x", exval); + if (exval & 0x80) { /* XMR */ + debugl1(cs, "ICC XMR"); + printk(KERN_WARNING "HiSax: ICC XMR\n"); + } + if (exval & 0x40) { /* XDU */ + debugl1(cs, "ICC XDU"); + printk(KERN_WARNING "HiSax: ICC XDU\n"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); + debugl1(cs, "ICC XDU no skb"); + } + } + if (exval & 0x04) { /* MOS */ + v1 = cs->readisac(cs, ICC_MOSR); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOSR %02x", v1); +#if ARCOFI_USE + if (v1 & 0x08) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR0; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR0; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + if (cs->dc.icc.mon_rxp == 1) { + cs->dc.icc.mocr |= 0x04; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + } + afterMONR0: + if (v1 & 0x80) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR1; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR1; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + cs->dc.icc.mocr |= 0x40; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + afterMONR1: + if (v1 & 0x04) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON0); + } + if (v1 & 0x40) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON1); + } + if (v1 & 0x02) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x08))) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + cs->writeisac(cs, ICC_MOX0, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX0: + if (v1 & 0x20) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x80))) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + cs->writeisac(cs, ICC_MOX1, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX1: +#endif + } + } +} + +static void +ICC_l1hw(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + int val; + + switch (pr) { + case (PH_DATA |REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + icc_fill_fifo(cs); + } + break; + case (PH_PULL |INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + icc_fill_fifo(cs); + break; + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (HW_RESET | REQUEST): + if ((cs->dc.icc.ph_state == ICC_IND_EI1) || + (cs->dc.icc.ph_state == ICC_IND_DR)) + ph_command(cs, ICC_CMD_DI); + else + ph_command(cs, ICC_CMD_RES); + break; + case (HW_ENABLE | REQUEST): + ph_command(cs, ICC_CMD_DI); + break; + case (HW_INFO1 | REQUEST): + ph_command(cs, ICC_CMD_AR); + break; + case (HW_INFO3 | REQUEST): + ph_command(cs, ICC_CMD_AI); + break; + case (HW_TESTLOOP | REQUEST): + val = 0; + if (1 & (long) arg) + val |= 0x0c; + if (2 & (long) arg) + val |= 0x3; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + if (!val) { + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + } else { + cs->writeisac(cs, ICC_SPCR, val); + cs->writeisac(cs, ICC_ADF1, 0xa); + } + } else { + /* IOM 2 Mode */ + cs->writeisac(cs, ICC_SPCR, val); + if (val) + cs->writeisac(cs, ICC_ADF1, 0x8); + else + cs->writeisac(cs, ICC_ADF1, 0x0); + } + break; + case (HW_DEACTIVATE | RESPONSE): + discard_queue(&cs->rq); + discard_queue(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_skb = NULL; + } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_l1hw unknown %04x", pr); + break; + } +} + +void +setstack_icc(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = ICC_l1hw; +} + +void +DC_Close_icc(struct IsdnCardState *cs) { + if (cs->dc.icc.mon_rx) { + kfree(cs->dc.icc.mon_rx); + cs->dc.icc.mon_rx = NULL; + } + if (cs->dc.icc.mon_tx) { + kfree(cs->dc.icc.mon_tx); + cs->dc.icc.mon_tx = NULL; + } +} + +static void +dbusy_timer_handler(struct IsdnCardState *cs) +{ + struct PStack *stptr; + int rbch, star; + + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + rbch = cs->readisac(cs, ICC_RBCH); + star = cs->readisac(cs, ICC_STAR); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", + rbch, star); + if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */ + test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr = stptr->next; + } + } else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); + } + } +} + +HISAX_INITFUNC(void +initicc(struct IsdnCardState *cs)) +{ + cs->tqueue.routine = (void *) (void *) icc_bh; + cs->setstack_d = setstack_icc; + cs->DC_Close = DC_Close_icc; + cs->dc.icc.mon_tx = NULL; + cs->dc.icc.mon_rx = NULL; + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + cs->writeisac(cs, ICC_MASK, 0xff); + cs->dc.icc.mocr = 0xaa; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + cs->writeisac(cs, ICC_ADF2, 0x0); + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xc9); + } else { + /* IOM 2 Mode */ + if (!cs->dc.icc.adf2) + cs->dc.icc.adf2 = 0x80; + cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); + cs->writeisac(cs, ICC_SQXR, 0xa0); + cs->writeisac(cs, ICC_SPCR, 0x20); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xca); + cs->writeisac(cs, ICC_TIMR, 0x00); + cs->writeisac(cs, ICC_ADF1, 0x20); + } + ph_command(cs, ICC_CMD_RES); + cs->writeisac(cs, ICC_MASK, 0x0); + ph_command(cs, ICC_CMD_DI); +} + +HISAX_INITFUNC(void +clear_pending_icc_ints(struct IsdnCardState *cs)) +{ + int val, eval; + + val = cs->readisac(cs, ICC_STAR); + debugl1(cs, "ICC STAR %x", val); + val = cs->readisac(cs, ICC_MODE); + debugl1(cs, "ICC MODE %x", val); + val = cs->readisac(cs, ICC_ADF2); + debugl1(cs, "ICC ADF2 %x", val); + val = cs->readisac(cs, ICC_ISTA); + debugl1(cs, "ICC ISTA %x", val); + if (val & 0x01) { + eval = cs->readisac(cs, ICC_EXIR); + debugl1(cs, "ICC EXIR %x", eval); + } + val = cs->readisac(cs, ICC_CIR0); + debugl1(cs, "ICC CIR0 %x", val); + cs->dc.icc.ph_state = (val >> 2) & 0xf; + icc_sched_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0xFF); +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/icc.h linux/drivers/isdn/hisax/icc.h --- v2.4.0-test6/linux/drivers/isdn/hisax/icc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/icc.h Mon Aug 21 07:49:03 2000 @@ -0,0 +1,73 @@ +// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.7.14 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + + +/* All Registers original Siemens Spec */ + +#define ICC_MASK 0x20 +#define ICC_ISTA 0x20 +#define ICC_STAR 0x21 +#define ICC_CMDR 0x21 +#define ICC_EXIR 0x24 +#define ICC_ADF2 0x39 +#define ICC_SPCR 0x30 +#define ICC_ADF1 0x38 +#define ICC_CIR0 0x31 +#define ICC_CIX0 0x31 +#define ICC_CIR1 0x33 +#define ICC_CIX1 0x33 +#define ICC_STCR 0x37 +#define ICC_MODE 0x22 +#define ICC_RSTA 0x27 +#define ICC_RBCL 0x25 +#define ICC_RBCH 0x2A +#define ICC_TIMR 0x23 +#define ICC_SQXR 0x3b +#define ICC_MOSR 0x3a +#define ICC_MOCR 0x3a +#define ICC_MOR0 0x32 +#define ICC_MOX0 0x32 +#define ICC_MOR1 0x34 +#define ICC_MOX1 0x34 + +#define ICC_RBCH_XAC 0x80 + +#define ICC_CMD_TIM 0x0 +#define ICC_CMD_RES 0x1 +#define ICC_CMD_DU 0x3 +#define ICC_CMD_EI1 0x4 +#define ICC_CMD_SSP 0x5 +#define ICC_CMD_DT 0x6 +#define ICC_CMD_AR 0x8 +#define ICC_CMD_ARL 0xA +#define ICC_CMD_AI 0xC +#define ICC_CMD_DI 0xF + +#define ICC_IND_DR 0x0 +#define ICC_IND_FJ 0x2 +#define ICC_IND_EI1 0x4 +#define ICC_IND_INT 0x6 +#define ICC_IND_PU 0x7 +#define ICC_IND_AR 0x8 +#define ICC_IND_ARL 0xA +#define ICC_IND_AI 0xC +#define ICC_IND_AIL 0xE +#define ICC_IND_DC 0xF + +extern void ICCVersion(struct IsdnCardState *cs, char *s); +extern void initicc(struct IsdnCardState *cs); +extern void icc_interrupt(struct IsdnCardState *cs, u_char val); +extern void clear_pending_icc_ints(struct IsdnCardState *cs); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.4.0-test6/linux/drivers/isdn/hisax/isar.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/isar.c Mon Aug 21 07:49:03 2000 @@ -243,6 +243,14 @@ printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); goto reterror; } +#ifdef __BIG_ENDIAN + sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256; + blk_head.sadr = sadr; + sadr = (blk_head.len & 0xff)*256 + blk_head.len/256; + blk_head.len = sadr; + sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256; + blk_head.d_key = sadr; +#endif /* __BIG_ENDIAN */ cnt += BLK_HEAD_SIZE; p += BLK_HEAD_SIZE; printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", @@ -284,8 +292,13 @@ #endif sadr += noc; while(noc) { +#ifdef __BIG_ENDIAN + *mp++ = *sp % 256; + *mp++ = *sp / 256; +#else *mp++ = *sp / 256; *mp++ = *sp % 256; +#endif /* __BIG_ENDIAN */ sp++; noc--; } @@ -528,8 +541,9 @@ rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { @@ -538,6 +552,7 @@ skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } + bcs->hw.isar.rcvidx = 0; } } break; @@ -606,13 +621,16 @@ bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { + int len = bcs->hw.isar.rcvidx + + dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { - memcpy(skb_put(skb, bcs->hw.isar.rcvidx), + insert_dle((u_char *)skb_put(skb, len), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); skb_queue_tail(&bcs->rqueue, skb); @@ -620,8 +638,20 @@ send_DLE_ETX(bcs); isar_sched_event(bcs, B_LL_OK); } + bcs->hw.isar.rcvidx = 0; } } + if (ireg->cmsb & SART_NMD) { /* ABORT */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: no more data"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + send_DLE_ETX(bcs); + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + bcs->hw.isar.state = STFAX_ESCAPE; + isar_sched_event(bcs, B_LL_NOCARRIER); + } break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); @@ -1044,6 +1074,9 @@ debugl1(cs, "pump stev RSP_DISC"); if (bcs->hw.isar.state == STFAX_ESCAPE) { switch(bcs->hw.isar.newcmd) { + case 0: + bcs->hw.isar.state = STFAX_READY; + break; case PCTRL_CMD_FTH: case PCTRL_CMD_FTM: p1 = 10; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h --- v2.4.0-test6/linux/drivers/isdn/hisax/isar.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/isar.h Mon Aug 21 07:49:03 2000 @@ -186,7 +186,7 @@ #define HDLC_ERROR 0x1c #define HDLC_ERR_FAD 0x10 #define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x01 +#define HDLC_ERR_CER 0x04 #define SART_NMD 0x01 #define BSTAT_RDM0 0x1 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.4.0-test6/linux/drivers/isdn/hisax/isdnl1.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/isdnl1.c Mon Aug 21 07:49:03 2000 @@ -28,7 +28,7 @@ {NULL, 0, 0, NULL, NULL}; static -struct Fsm l1fsm_d = +struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; enum { @@ -41,9 +41,9 @@ ST_L1_F8, }; -#define L1D_STATE_COUNT (ST_L1_F8+1) +#define L1S_STATE_COUNT (ST_L1_F8+1) -static char *strL1DState[] = +static char *strL1SState[] = { "ST_L1_F2", "ST_L1_F3", @@ -54,6 +54,29 @@ "ST_L1_F8", }; +#ifdef HISAX_UINTERFACE +static +struct Fsm l1fsm_u = +{NULL, 0, 0, NULL, NULL}; + +enum { + ST_L1_RESET, + ST_L1_DEACT, + ST_L1_SYNC2, + ST_L1_TRANS, +}; + +#define L1U_STATE_COUNT (ST_L1_TRANS+1) + +static char *strL1UState[] = +{ + "ST_L1_RESET", + "ST_L1_DEACT", + "ST_L1_SYNC2", + "ST_L1_TRANS", +}; +#endif + enum { ST_L1_NULL, ST_L1_WAIT_ACT, @@ -432,7 +455,7 @@ } static void -l1_deact_req(struct FsmInst *fi, int event, void *arg) +l1_deact_req_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -442,7 +465,7 @@ } static void -l1_power_up(struct FsmInst *fi, int event, void *arg) +l1_power_up_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -472,7 +495,12 @@ { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F6); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_SYNC2); + else +#endif + FsmChangeState(fi, ST_L1_F6); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); } @@ -481,7 +509,12 @@ { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F7); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_TRANS); + else +#endif + FsmChangeState(fi, ST_L1_F7); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 4); @@ -501,6 +534,10 @@ test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) L1deactivated(st->l1.hardware); + +#ifdef HISAX_UINTERFACE + if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) +#endif if (st->l1.l1m.state != ST_L1_F6) { FsmChangeState(fi, ST_L1_F3); st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); @@ -529,7 +566,7 @@ } static void -l1_activate(struct FsmInst *fi, int event, void *arg) +l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -547,9 +584,9 @@ } } -static struct FsmNode L1DFnList[] HISAX_INITDATA = +static struct FsmNode L1SFnList[] HISAX_INITDATA = { - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate}, + {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F3, EV_RESET_IND, l1_reset}, @@ -564,10 +601,10 @@ {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F3, EV_POWER_UP, l1_power_up}, + {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, @@ -595,7 +632,68 @@ {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode)) +#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) + +#ifdef HISAX_UINTERFACE +static void +l1_deact_req_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_RESET); + FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); + test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); +} + +static void +l1_power_up_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); +} + +static void +l1_info0_ind(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_DEACT); +} + +static void +l1_activate_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); +} + +static struct FsmNode L1UFnList[] HISAX_INITDATA = +{ + {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, + {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, + {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, + {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_DEACT, EV_TIMER3, l1_timer3}, + {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, + {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, + {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, +}; + +#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) + +#endif static void l1b_activate(struct FsmInst *fi, int event, void *arg) @@ -645,11 +743,18 @@ HISAX_INITFUNC(void Isdnl1New(void)) { - l1fsm_d.state_count = L1D_STATE_COUNT; - l1fsm_d.event_count = L1_EVENT_COUNT; - l1fsm_d.strEvent = strL1Event; - l1fsm_d.strState = strL1DState; - FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT); +#ifdef HISAX_UINTERFACE + l1fsm_u.state_count = L1U_STATE_COUNT; + l1fsm_u.event_count = L1_EVENT_COUNT; + l1fsm_u.strEvent = strL1Event; + l1fsm_u.strState = strL1UState; + FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); +#endif + l1fsm_s.state_count = L1S_STATE_COUNT; + l1fsm_s.event_count = L1_EVENT_COUNT; + l1fsm_s.strEvent = strL1Event; + l1fsm_s.strState = strL1SState; + FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); l1fsm_b.state_count = L1B_STATE_COUNT; l1fsm_b.event_count = L1_EVENT_COUNT; l1fsm_b.strEvent = strL1Event; @@ -659,7 +764,10 @@ void Isdnl1Free(void) { - FsmFree(&l1fsm_d); +#ifdef HISAX_UINTERFACE + FsmFree(&l1fsm_u); +#endif + FsmFree(&l1fsm_s); FsmFree(&l1fsm_b); } @@ -677,7 +785,7 @@ case (PH_ACTIVATE | REQUEST): if (cs->debug) debugl1(cs, "PH_ACTIVATE_REQ %s", - strL1DState[st->l1.l1m.state]); + st->l1.l1m.fsm->strState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { @@ -757,8 +865,16 @@ { st->l1.hardware = cs; st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm_d; + st->l1.l1m.fsm = &l1fsm_s; st->l1.l1m.state = ST_L1_F3; + st->l1.Flags = 0; +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { + st->l1.l1m.fsm = &l1fsm_u; + st->l1.l1m.state = ST_L1_RESET; + st->l1.Flags = FLG_L1_UINT; + } +#endif st->l1.l1m.debug = cs->debug; st->l1.l1m.userdata = st; st->l1.l1m.userint = 0; @@ -768,7 +884,6 @@ setstack_manager(st); st->l1.stlistp = &(cs->stlist); st->l2.l2l1 = dch_l2l1; - st->l1.Flags = 0; cs->setstack_d(st, cs); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.4.0-test6/linux/drivers/isdn/hisax/isdnl3.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/isdnl3.c Mon Aug 21 07:49:03 2000 @@ -234,7 +234,7 @@ extern void setstack_dss1(struct PStack *st); #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 extern void setstack_ni1(struct PStack *st); #endif @@ -356,7 +356,7 @@ setstack_dss1(st); } else #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 if (st->protocol == ISDN_PTYPE_NI1) { setstack_ni1(st); } else @@ -544,7 +544,6 @@ void l3_msg(struct PStack *st, int pr, void *arg) { - switch (pr) { case (DL_DATA | REQUEST): if (st->l3.l3m.state == ST_L3_LC_ESTAB) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c --- v2.4.0-test6/linux/drivers/isdn/hisax/l3_1tr6.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/l3_1tr6.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: l3_1tr6.c,v 2.11 2000/06/26 08:59:14 keil Exp $ +/* $Id: l3_1tr6.c,v 2.12 2000/08/20 07:31:30 keil Exp $ * * German 1TR6 D-channel protocol * @@ -17,7 +17,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.11 $"; +const char *l3_1tr6_revision = "$Revision: 2.12 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -883,7 +883,7 @@ } else { proc->chan = chan; chan->proc = proc; - memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.4.0-test6/linux/drivers/isdn/hisax/l3dss1.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/l3dss1.c Mon Aug 21 07:49:03 2000 @@ -721,6 +721,9 @@ u_char *p, ie; int l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; p = skb->data; /* skip cr */ @@ -729,20 +732,34 @@ p += l; mt = *p++; oldpos = 0; -/* shift codeset procedure not implemented in the moment */ while ((p - skb->data) < skb->len) { - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; else - oldpos = newpos; + err_ureg++; } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; } ie = *p++; if (ie & 0x80) { @@ -752,12 +769,19 @@ p += l; l += 2; } - if (l > getmax_ie_len(ie)) + if (!codeset && (l > getmax_ie_len(ie))) err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } } if (err_compr | err_ureg | err_len | err_seq) { if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d", + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", mt, err_compr, err_ureg, err_len, err_seq); if (err_compr) return(ERR_IE_COMPREHENSION); @@ -959,7 +983,7 @@ #if EXT_BEARER_CAPS -u_char * +static u_char * EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb @@ -1024,7 +1048,7 @@ return p + 3; } -u_char +static u_char EncodeSyncParams(u_char si2, u_char ai) { @@ -1889,6 +1913,16 @@ pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); } +static void +l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + /********************************************/ /* deliver a incoming display message to HL */ /********************************************/ @@ -1926,7 +1960,7 @@ if (p[1] != 2) { err = 1; pc->para.cause = 100; - } else if (p[2] & 0x60) { + } else if (!(p[2] & 0x70)) { switch (p[2]) { case 0x80: case 0x81: @@ -2030,9 +2064,22 @@ { int ret; struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; ret = check_infoelements(pc, skb, ie_INFORMATION); - l3dss1_std_ie_err(pc, ret); + if (ret) + l3dss1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } } /******************************/ @@ -2258,6 +2305,16 @@ } static void +l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3dss1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -2276,6 +2333,7 @@ l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2315,6 +2373,7 @@ l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2324,6 +2383,7 @@ l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); @@ -2713,32 +2773,36 @@ CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), CC_RESUME | REQUEST, l3dss1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, CC_RESTART | REQUEST, l3dss1_restart}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_IGNORE | REQUEST, l3dss1_reset}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_REJECT | REQUEST, l3dss1_reject_req}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(6) | SBIT(9), + {SBIT(6), + CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3dss1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), CC_ALERTING | REQUEST, l3dss1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9), + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), CC_SETUP | RESPONSE, l3dss1_setup_rsp}, {SBIT(10), CC_SUSPEND | REQUEST, l3dss1_suspend_req}, - {SBIT(6), - CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(7) | SBIT(9), + {SBIT(7) | SBIT(9) | SBIT(25), CC_REDIR | REQUEST, l3dss1_redir_req}, {SBIT(6), CC_REDIR | REQUEST, l3dss1_redir_req_early}, {SBIT(9) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, + {SBIT(25), + CC_T302, l3dss1_t302}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), @@ -3081,7 +3145,7 @@ if ((proc = dss1_new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; - memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/l3ni1.c linux/drivers/isdn/hisax/l3ni1.c --- v2.4.0-test6/linux/drivers/isdn/hisax/l3ni1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/l3ni1.c Tue Aug 22 09:06:31 2000 @@ -0,0 +1,3171 @@ +// $Id: l3ni1.c,v 2.3 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson and Will Scales. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl3.h" +#include "l3ni1.h" +#include + +extern char *HiSax_getrev(const char *revision); +const char *ni1_revision = "$Revision: 2.3 $"; + +#define EXT_BEARER_CAPS 1 + +#define MsgHead(ptr, cref, mty) \ + *ptr++ = 0x8; \ + if (cref == -1) { \ + *ptr++ = 0x0; \ + } else { \ + *ptr++ = 0x1; \ + *ptr++ = cref^0x80; \ + } \ + *ptr++ = mty + + +/**********************************************/ +/* get a new invoke id for remote operations. */ +/* Only a return value != 0 is valid */ +/**********************************************/ +static unsigned char new_invoke_id(struct PStack *p) +{ + unsigned char retval; + int flags,i; + + i = 32; /* maximum search depth */ + + save_flags(flags); + cli(); + + retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ + while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { + p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; + i--; + } + if (i) { + while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) + retval++; + } else + retval = 0; + p->prot.ni1.last_invoke_id = retval; + p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); + restore_flags(flags); + + return(retval); +} /* new_invoke_id */ + +/*************************/ +/* free a used invoke id */ +/*************************/ +static void free_invoke_id(struct PStack *p, unsigned char id) +{ int flags; + + if (!id) return; /* 0 = invalid value */ + + save_flags(flags); + cli(); + p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); + restore_flags(flags); +} /* free_invoke_id */ + + +/**********************************************************/ +/* create a new l3 process and fill in ni1 specific data */ +/**********************************************************/ +static struct l3_process +*ni1_new_l3_process(struct PStack *st, int cr) +{ struct l3_process *proc; + + if (!(proc = new_l3_process(st, cr))) + return(NULL); + + proc->prot.ni1.invoke_id = 0; + proc->prot.ni1.remote_operation = 0; + proc->prot.ni1.uus1_data[0] = '\0'; + + return(proc); +} /* ni1_new_l3_process */ + +/************************************************/ +/* free a l3 process and all ni1 specific data */ +/************************************************/ +static void +ni1_release_l3_process(struct l3_process *p) +{ + free_invoke_id(p->st,p->prot.ni1.invoke_id); + release_l3_process(p); +} /* ni1_release_l3_process */ + +/********************************************************/ +/* search a process with invoke id id and dummy callref */ +/********************************************************/ +static struct l3_process * +l3ni1_search_dummy_proc(struct PStack *st, int id) +{ struct l3_process *pc = st->l3.proc; /* start of processes */ + + if (!id) return(NULL); + + while (pc) + { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) + return(pc); + pc = pc->next; + } + return(NULL); +} /* l3ni1_search_dummy_proc */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return result is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_RES; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen); +} /* l3ni1_dummy_return_result */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return error is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= error; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error); +} /* l3ni1_error_return */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a invoke is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_invoke(struct PStack *st, int cr, int id, + int ident, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + + l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", + (cr == -1) ? "local" : "broadcast",id,ident,nlen); + if (cr >= -1) return; /* ignore local data */ + + cs = st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_BRD; + ic.parm.ni1_io.hl_id = id; + ic.parm.ni1_io.ll_id = 0; + ic.parm.ni1_io.proc = ident; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + + cs->iif.statcallb(&ic); +} /* l3ni1_dummy_invoke */ + +static void +l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, + int cr, u_char * p) +{ + int qd_len = 0; + unsigned char nlen = 0, ilen, cp_tag; + int ident, id; + ulong err_ret; + + if (pc) + st = pc->st; /* valid Stack */ + else + if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ + + p++; + qd_len = *p++; + if (qd_len == 0) { + l3_debug(st, "qd_len == 0"); + return; + } + if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ + l3_debug(st, "supplementary service != 0x11"); + return; + } + while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ + p++; + qd_len--; + } + if (qd_len < 2) { + l3_debug(st, "qd_len < 2"); + return; + } + p++; + qd_len--; + if ((*p & 0xE0) != 0xA0) { /* class and form */ + l3_debug(st, "class and form != 0xA0"); + return; + } + + cp_tag = *p & 0x1F; /* remember tag value */ + + p++; + qd_len--; + if (qd_len < 1) + { l3_debug(st, "qd_len < 1"); + return; + } + if (*p & 0x80) + { /* length format indefinite or limited */ + nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ + if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || + (nlen > 1)) + { l3_debug(st, "length format error or not implemented"); + return; + } + if (nlen == 1) + { nlen = *p++; /* complete length */ + qd_len--; + } + else + { qd_len -= 2; /* trailing null bytes */ + if ((*(p+qd_len)) || (*(p+qd_len+1))) + { l3_debug(st,"length format indefinite error"); + return; + } + nlen = qd_len; + } + } + else + { nlen = *p++; + qd_len--; + } + if (qd_len < nlen) + { l3_debug(st, "qd_len < nlen"); + return; + } + qd_len -= nlen; + + if (nlen < 2) + { l3_debug(st, "nlen < 2"); + return; + } + if (*p != 0x02) + { /* invoke identifier tag */ + l3_debug(st, "invoke identifier tag !=0x02"); + return; + } + p++; + nlen--; + if (*p & 0x80) + { /* length format */ + l3_debug(st, "invoke id length format 2"); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + id = 0; + while (ilen > 0) + { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ + ilen--; + } + + switch (cp_tag) { /* component tag */ + case 1: /* invoke */ + if (nlen < 2) { + l3_debug(st, "nlen < 2 22"); + return; + } + if (*p != 0x02) { /* operation value */ + l3_debug(st, "operation value !=0x02"); + return; + } + p++; + nlen--; + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(st, "ilen > nlen || ilen == 0 22"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); + ilen--; + } + + if (!pc) + { + l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); + return; + } + l3_debug(st, "invoke break"); + break; + case 2: /* return result */ + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_return_result(st, id, p, nlen); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Diversion successfull */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = 0; /* success */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + else + l3_debug(st,"return error unknown identifier"); + break; + case 3: /* return error */ + err_ret = 0; + if (nlen < 2) + { l3_debug(st, "return error nlen < 2"); + return; + } + if (*p != 0x02) + { /* result tag */ + l3_debug(st, "invoke error tag !=0x02"); + return; + } + p++; + nlen--; + if (*p > 4) + { /* length format */ + l3_debug(st, "invoke return errlen > 4 "); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "error return ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + while (ilen > 0) + { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ + ilen--; + } + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_error_return(st, id, err_ret); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Deflection error */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = err_ret; /* result */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); + } /* Deflection error */ + else + l3_debug(st,"return result unknown identifier"); + break; + default: + l3_debug(st, "facility default break tag=0x%02x",cp_tag); + break; + } +} + +static void +l3ni1_message(struct l3_process *pc, u_char mt) +{ + struct sk_buff *skb; + u_char *p; + + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); + MsgHead(p, pc->callref, mt); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, mt); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + MsgHead(p, pc->callref, MT_STATUS); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + + *p++ = IE_CALL_STATE; + *p++ = 0x1; + *p++ = pc->state & 0x3f; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) +{ + /* This routine is called if here was no SETUP made (checks in ni1up and in + * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code + * MT_STATUS_ENQUIRE in the NULL state is handled too + */ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + switch (pc->para.cause) { + case 81: /* invalid callreference */ + case 88: /* incomp destination */ + case 96: /* mandory IE missing */ + case 100: /* invalid IE contents */ + case 101: /* incompatible Callstate */ + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + break; + default: + printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", + pc->para.cause); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + ni1_release_l3_process(pc); +} + +static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, + IE_USER_USER, -1}; +static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; +static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, + IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, + IE_CALLED_PN, -1}; +static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | + IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; +static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, + IE_SIGNAL, IE_USER_USER, -1}; +/* a RELEASE_COMPLETE with errors don't require special actions +static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +*/ +static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, + IE_DISPLAY, -1}; +static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, + IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, + IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, + IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, + IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | + IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; +static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; +static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +/* not used + * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, + * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; + * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; + * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | + * IE_MANDATORY, -1}; + */ +static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; +static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1}; +static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1}; + +struct ie_len { + int ie; + int len; +}; + +static +struct ie_len max_ie_len[] = { + {IE_SEGMENT, 4}, + {IE_BEARER, 12}, + {IE_CAUSE, 32}, + {IE_CALL_ID, 10}, + {IE_CALL_STATE, 3}, + {IE_CHANNEL_ID, 34}, + {IE_FACILITY, 255}, + {IE_PROGRESS, 4}, + {IE_NET_FAC, 255}, + {IE_NOTIFY, 3}, + {IE_DISPLAY, 82}, + {IE_DATE, 8}, + {IE_KEYPAD, 34}, + {IE_SIGNAL, 3}, + {IE_INFORATE, 6}, + {IE_E2E_TDELAY, 11}, + {IE_TDELAY_SEL, 5}, + {IE_PACK_BINPARA, 3}, + {IE_PACK_WINSIZE, 4}, + {IE_PACK_SIZE, 4}, + {IE_CUG, 7}, + {IE_REV_CHARGE, 3}, + {IE_CALLING_PN, 24}, + {IE_CALLING_SUB, 23}, + {IE_CALLED_PN, 24}, + {IE_CALLED_SUB, 23}, + {IE_REDIR_NR, 255}, + {IE_TRANS_SEL, 255}, + {IE_RESTART_IND, 3}, + {IE_LLC, 18}, + {IE_HLC, 5}, + {IE_USER_USER, 131}, + {-1,0}, +}; + +static int +getmax_ie_len(u_char ie) { + int i = 0; + while (max_ie_len[i].ie != -1) { + if (max_ie_len[i].ie == ie) + return(max_ie_len[i].len); + i++; + } + return(255); +} + +static int +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { + int ret = 1; + + while (*checklist != -1) { + if ((*checklist & 0xff) == ie) { + if (ie & 0x80) + return(-ret); + else + return(ret); + } + ret++; + checklist++; + } + return(0); +} + +static int +check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) +{ + int *cl = checklist; + u_char mt; + u_char *p, ie; + int l, newpos, oldpos; + int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; + + p = skb->data; + /* skip cr */ + p++; + l = (*p++) & 0xf; + p += l; + mt = *p++; + oldpos = 0; + while ((p - skb->data) < skb->len) { + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; + else + err_ureg++; + } + } + ie = *p++; + if (ie & 0x80) { + l = 1; + } else { + l = *p++; + p += l; + l += 2; + } + if (!codeset && (l > getmax_ie_len(ie))) + err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } + } + if (err_compr | err_ureg | err_len | err_seq) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", + mt, err_compr, err_ureg, err_len, err_seq); + if (err_compr) + return(ERR_IE_COMPREHENSION); + if (err_ureg) + return(ERR_IE_UNRECOGNIZED); + if (err_len) + return(ERR_IE_LENGTH); + if (err_seq) + return(ERR_IE_SEQUENCE); + } + return(0); +} + +/* verify if a message type exists and contain no IE error */ +static int +l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) +{ + switch (mt) { + case MT_ALERTING: + case MT_CALL_PROCEEDING: + case MT_CONNECT: + case MT_CONNECT_ACKNOWLEDGE: + case MT_DISCONNECT: + case MT_INFORMATION: + case MT_FACILITY: + case MT_NOTIFY: + case MT_PROGRESS: + case MT_RELEASE: + case MT_RELEASE_COMPLETE: + case MT_SETUP: + case MT_SETUP_ACKNOWLEDGE: + case MT_RESUME_ACKNOWLEDGE: + case MT_RESUME_REJECT: + case MT_SUSPEND_ACKNOWLEDGE: + case MT_SUSPEND_REJECT: + case MT_USER_INFORMATION: + case MT_RESTART: + case MT_RESTART_ACKNOWLEDGE: + case MT_CONGESTION_CONTROL: + case MT_STATUS: + case MT_STATUS_ENQUIRY: + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); + break; + case MT_RESUME: /* RESUME only in user->net */ + case MT_SUSPEND: /* SUSPEND only in user->net */ + default: + if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); + pc->para.cause = 97; + l3ni1_status_send(pc, 0, NULL); + return(1); + } + return(0); +} + +static void +l3ni1_std_ie_err(struct l3_process *pc, int ret) { + + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check_infoelements ret %d", ret); + switch(ret) { + case 0: + break; + case ERR_IE_COMPREHENSION: + pc->para.cause = 96; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_UNRECOGNIZED: + pc->para.cause = 99; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_LENGTH: + pc->para.cause = 100; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_SEQUENCE: + default: + break; + } +} + +static int +l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { + u_char *p; + + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + p++; + if (*p != 1) { /* len for BRI = 1 */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid len %d", *p); + return (-2); + } + p++; + if (*p & 0x60) { /* only base rate interface */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid %x", *p); + return (-3); + } + return(*p & 0x3); + } else + return(-1); +} + +static int +l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { + u_char l, i=0; + u_char *p; + + p = skb->data; + pc->para.cause = 31; + pc->para.loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + l = *p++; + if (l>30) + return(1); + if (l) { + pc->para.loc = *p++; + l--; + } else { + return(2); + } + if (l && !(pc->para.loc & 0x80)) { + l--; + p++; /* skip recommendation */ + } + if (l) { + pc->para.cause = *p++; + l--; + if (!(pc->para.cause & 0x80)) + return(3); + } else + return(4); + while (l && (i<6)) { + pc->para.diag[i++] = *p++; + l--; + } + } else + return(-1); + return(0); +} + +static void +l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, cmd); + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_msg_with_uus */ + +static void +l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) +{ + StopAllL3Timer(pc); + newl3state(pc, 19); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_RELEASE); + else + l3ni1_msg_with_uus(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret); + } else if (ret < 0) + pc->para.cause = NO_CAUSE; + StopAllL3Timer(pc); + newl3state(pc, 0); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); + ni1_release_l3_process(pc); +} + +#if EXT_BEARER_CAPS + +static u_char * +EncodeASyncParams(u_char * p, u_char si2) +{ // 7c 06 88 90 21 42 00 bb + + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 + p[2] = 0x80; + if (si2 & 32) // 7 data bits + + p[2] += 16; + else // 8 data bits + + p[2] += 24; + + if (si2 & 16) // 2 stop bits + + p[2] += 96; + else // 1 stop bit + + p[2] += 32; + + if (si2 & 8) // even parity + + p[2] += 2; + else // no parity + + p[2] += 3; + + switch (si2 & 0x07) { + case 0: + p[0] = 66; // 1200 bit/s + + break; + case 1: + p[0] = 88; // 1200/75 bit/s + + break; + case 2: + p[0] = 87; // 75/1200 bit/s + + break; + case 3: + p[0] = 67; // 2400 bit/s + + break; + case 4: + p[0] = 69; // 4800 bit/s + + break; + case 5: + p[0] = 72; // 9600 bit/s + + break; + case 6: + p[0] = 73; // 14400 bit/s + + break; + case 7: + p[0] = 75; // 19200 bit/s + + break; + } + return p + 3; +} + +static u_char +EncodeSyncParams(u_char si2, u_char ai) +{ + + switch (si2) { + case 0: + return ai + 2; // 1200 bit/s + + case 1: + return ai + 24; // 1200/75 bit/s + + case 2: + return ai + 23; // 75/1200 bit/s + + case 3: + return ai + 3; // 2400 bit/s + + case 4: + return ai + 5; // 4800 bit/s + + case 5: + return ai + 8; // 9600 bit/s + + case 6: + return ai + 9; // 14400 bit/s + + case 7: + return ai + 11; // 19200 bit/s + + case 8: + return ai + 14; // 48000 bit/s + + case 9: + return ai + 15; // 56000 bit/s + + case 15: + return ai + 40; // negotiate bit/s + + default: + break; + } + return ai; +} + + +static u_char +DecodeASyncParams(u_char si2, u_char * p) +{ + u_char info; + + switch (p[5]) { + case 66: // 1200 bit/s + + break; // si2 don't change + + case 88: // 1200/75 bit/s + + si2 += 1; + break; + case 87: // 75/1200 bit/s + + si2 += 2; + break; + case 67: // 2400 bit/s + + si2 += 3; + break; + case 69: // 4800 bit/s + + si2 += 4; + break; + case 72: // 9600 bit/s + + si2 += 5; + break; + case 73: // 14400 bit/s + + si2 += 6; + break; + case 75: // 19200 bit/s + + si2 += 7; + break; + } + + info = p[7] & 0x7f; + if ((info & 16) && (!(info & 8))) // 7 data bits + + si2 += 32; // else 8 data bits + + if ((info & 96) == 96) // 2 stop bits + + si2 += 16; // else 1 stop bit + + if ((info & 2) && (!(info & 1))) // even parity + + si2 += 8; // else no parity + + return si2; +} + + +static u_char +DecodeSyncParams(u_char si2, u_char info) +{ + info &= 0x7f; + switch (info) { + case 40: // bit/s negotiation failed ai := 165 not 175! + + return si2 + 15; + case 15: // 56000 bit/s failed, ai := 0 not 169 ! + + return si2 + 9; + case 14: // 48000 bit/s + + return si2 + 8; + case 11: // 19200 bit/s + + return si2 + 7; + case 9: // 14400 bit/s + + return si2 + 6; + case 8: // 9600 bit/s + + return si2 + 5; + case 5: // 4800 bit/s + + return si2 + 4; + case 3: // 2400 bit/s + + return si2 + 3; + case 23: // 75/1200 bit/s + + return si2 + 2; + case 24: // 1200/75 bit/s + + return si2 + 1; + default: // 1200 bit/s + + return si2; + } +} + +static u_char +DecodeSI2(struct sk_buff *skb) +{ + u_char *p; //, *pend=skb->data + skb->len; + + if ((p = findie(skb->data, skb->len, 0x7c, 0))) { + switch (p[4] & 0x0f) { + case 0x01: + if (p[1] == 0x04) // sync. Bitratenadaption + + return DecodeSyncParams(160, p[5]); // V.110/X.30 + + else if (p[1] == 0x06) // async. Bitratenadaption + + return DecodeASyncParams(192, p); // V.110/X.30 + + break; + case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption + if (p[1] > 3) + return DecodeSyncParams(176, p[5]); // V.120 + break; + } + } + return 0; +} + +#endif + + +static void +l3ni1_setup_req(struct l3_process *pc, u_char pr, + void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + + u_char *teln; + u_char *sub; + u_char *sp; + int l; + + MsgHead(p, pc->callref, MT_SETUP); + + teln = pc->para.setup.phone; + + *p++ = 0xa1; /* complete indicator */ + /* + * Set Bearer Capability, Map info from 1TR6-convention to NI1 + */ + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_BEARER; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_BEARER; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + + sub = NULL; + sp = teln; + while (*sp) { + if ('.' == *sp) { + sub = sp; + *sp = 0; + } else + sp++; + } + + *p++ = IE_KEYPAD; + *p++ = strlen(teln); + while (*teln) + *p++ = (*teln++) & 0x7F; + + if (sub) + *sub++ = '.'; + +#if EXT_BEARER_CAPS + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x04; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); + } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 + + *p++ = IE_LLC; + *p++ = 0x05; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x28; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); + *p++ = 0x82; + } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x06; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + p = EncodeASyncParams(p, pc->para.setup.si2 - 192); + } else { + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_LLC; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_LLC; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + } +#endif + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) +{ + return; +} + memcpy(skb_put(skb, l), tmp, l); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T303, CC_T303); + newl3state(pc, 1); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 3); + L3AddTimer(&pc->timer, T310, CC_T310); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); +} + +static void +l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 2); + L3AddTimer(&pc->timer, T304, CC_T304); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); +} + +static void +l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret; + u_char cause = 0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "DISC get_cause ret(%d)", ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + ret = check_infoelements(pc, skb, ie_DISCONNECT); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) + cause = 99; + ret = pc->state; + newl3state(pc, 12); + if (cause) + newl3state(pc, 19); + if (11 != ret) + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); + else if (!cause) + l3ni1_release_req(pc, pr, NULL); + if (cause) { + l3ni1_message_cause(pc, MT_RELEASE, cause); + L3AddTimer(&pc->timer, T308, CC_T308_1); + } +} + +static void +l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T310 */ + newl3state(pc, 10); + pc->para.chargeinfo = 0; + /* here should inserted COLP handling KKe */ + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); +} + +static void +l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_ALERTING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T304 */ + newl3state(pc, 4); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); +} + +static void +l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + int bcfound = 0; + char tmp[80]; + struct sk_buff *skb = arg; + int id; + int err = 0; + + /* + * Bearer Capabilities + */ + p = skb->data; + /* only the first occurence 'll be detected ! */ + if ((p = findie(p, skb->len, 0x04, 0))) { + if ((p[1] < 2) || (p[1] > 11)) + err = 1; + else { + pc->para.setup.si2 = 0; + switch (p[2] & 0x7f) { + case 0x00: /* Speech */ + case 0x10: /* 3.1 Khz audio */ + pc->para.setup.si1 = 1; + break; + case 0x08: /* Unrestricted digital information */ + pc->para.setup.si1 = 7; +/* JIM, 05.11.97 I wanna set service indicator 2 */ +#if EXT_BEARER_CAPS + pc->para.setup.si2 = DecodeSI2(skb); +#endif + break; + case 0x09: /* Restricted digital information */ + pc->para.setup.si1 = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + pc->para.setup.si1 = 3; + break; + case 0x18: /* Video */ + pc->para.setup.si1 = 4; + break; + default: + err = 2; + break; + } + switch (p[3] & 0x7f) { + case 0x40: /* packed mode */ + pc->para.setup.si1 = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + pc->para.moderate = p[3] & 0x7f; + break; + default: + err = 3; + break; + } + } + if (pc->debug & L3_DEB_SI) + l3_debug(pc->st, "SI=%d, AI=%d", + pc->para.setup.si1, pc->para.setup.si2); + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", + p[1], p[2], p[3]); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bearer capabilities"); + /* ETS 300-104 1.3.3 */ + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* + * Channel Identification + */ + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((pc->para.bchannel = id)) { + if ((3 == id) && (0x10 == pc->para.moderate)) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid %x", + id); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + bcfound++; + } else + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bchannel, call waiting"); + bcfound++; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid ret %d", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_SETUP); + if (ERR_IE_COMPREHENSION == err) { + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) + iecpy(pc->para.setup.eazmsn, p, 1); + else + pc->para.setup.eazmsn[0] = 0; + + p = skb->data; + if ((p = findie(p, skb->len, 0x71, 0))) { + /* Called party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.eazmsn, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong called subaddress"); + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6c, 0))) { + pc->para.setup.plan = p[2]; + if (p[2] & 0x80) { + iecpy(pc->para.setup.phone, p, 1); + pc->para.setup.screen = 0; + } else { + iecpy(pc->para.setup.phone, p, 2); + pc->para.setup.screen = p[3]; + } + } else { + pc->para.setup.phone[0] = 0; + pc->para.setup.plan = 0; + pc->para.setup.screen = 0; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6d, 0))) { + /* Calling party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.phone, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong calling subaddress"); + } + newl3state(pc, 6); + if (err) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, err); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); +} + +static void +l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) +{ + ni1_release_l3_process(pc); +} + +static void +l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + u_char cause = 16; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + StopAllL3Timer(pc); + + MsgHead(p, pc->callref, MT_DISCONNECT); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 11); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T305, CC_T305); +} + +static void +l3ni1_setup_rsp(struct l3_process *pc, u_char pr, + void *arg) +{ + if (!pc->para.bchannel) + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "D-chan connect for waiting call"); + l3ni1_disconnect_req(pc, pr, arg); + return; + } + newl3state(pc, 8); + l3ni1_message(pc, MT_CONNECT); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T313, CC_T313); +} + +static void +l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + newl3state(pc, 10); + L3DelTimer(&pc->timer); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); +} + +static void +l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char cause = 21; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_release(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret, cause=0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "REL get_cause ret(%d)", ret); + } else if (ret<0) + pc->para.cause = NO_CAUSE; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } + if ((ret<0) && (pc->state != 11)) + cause = 96; + else if (ret>0) + cause = 100; + ret = check_infoelements(pc, skb, ie_RELEASE); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) + cause = 99; + if (cause) + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); + else + l3ni1_message(pc, MT_RELEASE_COMPLETE); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_alert_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 7); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_ALERTING); + else + l3ni1_msg_with_uus(pc, MT_ALERTING); +} + +static void +l3ni1_proceed_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 9); + l3ni1_message(pc, MT_CALL_PROCEEDING); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); +} + +static void +l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + +/********************************************/ +/* deliver a incoming display message to HL */ +/********************************************/ +static void +l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; + isdn_ctrl ic; + struct IsdnCardState *cs; + char *p; + + if (*infp++ != IE_DISPLAY) return; + if ((len = *infp++) > 80) return; /* total length <= 82 */ + if (!pc->chan) return; + + p = ic.parm.display; + while (len--) + *p++ = *infp++; + *p = '\0'; + ic.command = ISDN_STAT_DISPLAY; + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.arg = pc->chan->chan; + cs->iif.statcallb(&ic); +} /* l3ni1_deliver_display */ + + +static void +l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { + if (p[1] != 2) { + err = 1; + pc->para.cause = 100; + } else if (!(p[2] & 0x70)) { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x87: + case 0x8a: + switch (p[3]) { + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x88: + break; + default: + err = 2; + pc->para.cause = 100; + break; + } + break; + default: + err = 3; + pc->para.cause = 100; + break; + } + } + } else { + pc->para.cause = 96; + err = 4; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "progress error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_PROGRESS); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); +} + +static void +l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { + if (p[1] != 1) { + err = 1; + pc->para.cause = 100; + } else { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + break; + default: + pc->para.cause = 100; + err = 2; + break; + } + } + } else { + pc->para.cause = 96; + err = 3; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "notify error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_NOTIFY); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); +} + +static void +l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + + ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); + l3ni1_std_ie_err(pc, ret); + pc->para.cause = 30; /* response to STATUS_ENQUIRY */ + l3ni1_status_send(pc, pr, NULL); +} + +static void +l3ni1_information(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; + + ret = check_infoelements(pc, skb, ie_INFORMATION); + if (ret) + l3ni1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } +} + +/******************************/ +/* handle deflection requests */ +/******************************/ +static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; + int l; + + + strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */ + if (!pc->chan->setup.phone[0]) + { pc->para.cause = -1; + l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */ + return; + } /* only uus */ + + if (pc->prot.ni1.invoke_id) + free_invoke_id(pc->st,pc->prot.ni1.invoke_id); + + if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) + return; + + MsgHead(p, pc->callref, MT_FACILITY); + + for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + + *p++ = 0x1c; /* Facility info element */ + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ + *p++ = 0x91; /* remote operations protocol */ + *p++ = 0xa1; /* invoke component */ + + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ + *p++ = 0x02; /* invoke id tag, integer */ + *p++ = 0x01; /* length */ + *p++ = pc->prot.ni1.invoke_id; /* invoke id */ + *p++ = 0x02; /* operation value tag, integer */ + *p++ = 0x01; /* length */ + *p++ = 0x0D; /* Call Deflect */ + + *p++ = 0x30; /* sequence phone number */ + *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ + + *p++ = 0x30; /* Deflected to UserNumber */ + *p++ = len_phone+2+len_sub; /* length */ + *p++ = 0x80; /* NumberDigits */ + *p++ = len_phone; /* length */ + for (l = 0; l < len_phone; l++) + *p++ = pc->chan->setup.phone[l]; + + if (len_sub) + { *p++ = 0x04; /* called party subadress */ + *p++ = len_sub - 2; + while (*subp) *p++ = *subp++; + } + + *p++ = 0x01; /* screening identifier */ + *p++ = 0x01; + *p++ = pc->chan->setup.screen; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) return; + memcpy(skb_put(skb, l), tmp, l); + + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_redir_req */ + +/********************************************/ +/* handle deflection request in early state */ +/********************************************/ +static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) +{ + l3ni1_proceed_req(pc,pr,arg); + l3ni1_redir_req(pc,pr,arg); +} /* l3ni1_redir_req_early */ + +/***********************************************/ +/* handle special commands for this protocol. */ +/* Examples are call independant services like */ +/* remote operations with dummy callref. */ +/***********************************************/ +static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) +{ u_char id; + u_char temp[265]; + u_char *p = temp; + int i, l, proc_len; + struct sk_buff *skb; + struct l3_process *pc = NULL; + + switch (ic->arg) + { case NI1_CMD_INVOKE: + if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */ + + for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) + i = i >> 8; /* add one byte */ + l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ + if (l > 255) + return(-2); /* too long */ + + if (!(id = new_invoke_id(st))) + return(0); /* first get a invoke id -> return if no available */ + + i = -1; + MsgHead(p, i, MT_FACILITY); /* build message head */ + *p++ = 0x1C; /* Facility IE */ + *p++ = l; /* length of ie */ + *p++ = 0x91; /* remote operations */ + *p++ = 0xA1; /* invoke */ + *p++ = l - 3; /* length of invoke */ + *p++ = 0x02; /* invoke id tag */ + *p++ = 0x01; /* length is 1 */ + *p++ = id; /* invoke id */ + *p++ = 0x02; /* operation */ + *p++ = proc_len; /* length of operation */ + + for (i = proc_len; i; i--) + *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF; + memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ + l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */ + + if (ic->parm.ni1_io.timeout > 0) + if (!(pc = ni1_new_l3_process(st, -1))) + { free_invoke_id(st, id); + return(-2); + } + pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */ + pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */ + + if (!(skb = l3_alloc_skb(l))) + { free_invoke_id(st, id); + if (pc) ni1_release_l3_process(pc); + return(-2); + } + memcpy(skb_put(skb, l), temp, l); + + if (pc) + { pc->prot.ni1.invoke_id = id; /* remember id */ + L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); + } + + l3_msg(st, DL_DATA | REQUEST, skb); + ic->parm.ni1_io.hl_id = id; /* return id */ + return(0); + + case NI1_CMD_INVOKE_ABORT: + if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) + { L3DelTimer(&pc->timer); /* remove timer */ + ni1_release_l3_process(pc); + return(0); + } + else + { l3_debug(st, "l3ni1_cmd_global abort unknown id"); + return(-2); + } + break; + + default: + l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); + return(-1); + } /* switch ic-> arg */ + return(-1); +} /* l3ni1_cmd_global */ + +static void +l3ni1_io_timer(struct l3_process *pc) +{ isdn_ctrl ic; + struct IsdnCardState *cs = pc->st->l1.hardware; + + L3DelTimer(&pc->timer); /* remove timer */ + + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= -1; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + + ni1_release_l3_process(pc); +} /* l3ni1_io_timer */ + +static void +l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int callState = 0; + p = skb->data; + + if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) + callState = *p; + } + if (callState == 0) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 + * set down layer 3 without sending any message + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } else { + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); + } +} + +static void +l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) +{ +} + +static void +l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) +{ + if (pc->N303 > 0) { + pc->N303--; + L3DelTimer(&pc->timer); + l3ni1_setup_req(pc, pr, arg); + } else { + L3DelTimer(&pc->timer); + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); + +} + +static void +l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + u_char cause = 16; + + L3DelTimer(&pc->timer); + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 19); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); +} + +static void +l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 19); + L3DelTimer(&pc->timer); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_2); +} + +static void +l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 19); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); +} + +static void +l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_status(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int ret; + u_char cause = 0, callState = 0; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS get_cause ret(%d)",ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) { + callState = *p; + if (!ie_in_set(pc, *p, l3_valid_states)) + cause = 100; + } else + cause = 100; + } else + cause = 96; + if (!cause) { /* no error before */ + ret = check_infoelements(pc, skb, ie_STATUS); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if (ERR_IE_UNRECOGNIZED == ret) + cause = 99; + } + if (cause) { + u_char tmp; + + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); + tmp = pc->para.cause; + pc->para.cause = cause; + l3ni1_status_send(pc, 0, NULL); + if (cause == 99) + pc->para.cause = tmp; + else + return; + } + cause = pc->para.cause; + if (((cause & 0x7f) == 111) && (callState == 0)) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... + * if received MT_STATUS with cause == 111 and call + * state == 0, then we must set down layer 3 + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_FACILITY); + l3ni1_std_ie_err(pc, ret); + { + u_char *p; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } +} + +static void +l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; + + MsgHead(p, pc->callref, MT_SUSPEND); + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 15); + L3AddTimer(&pc->timer, T319, CC_T319); +} + +static void +l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + L3DelTimer(&pc->timer); + newl3state(pc, 0); + pc->para.cause = NO_CAUSE; + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); + /* We don't handle suspend_ack for IE errors now */ + if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSPACK check ie(%d)",ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; + + MsgHead(p, pc->callref, MT_RESUME); + + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "RES wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 17); + L3AddTimer(&pc->timer, T318, CC_T318); +} + +static void +l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack without chid (ret %d)", id); + pc->para.cause = 96; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 0); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[32]; + u_char *p; + u_char ri, ch = 0, chan = 0; + int l; + struct sk_buff *skb = arg; + struct l3_process *up; + + newl3state(pc, 2); + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { + ri = p[2]; + l3_debug(pc->st, "Restart %x", ri); + } else { + l3_debug(pc->st, "Restart without restart IE"); + ri = 0x86; + } + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + chan = p[2] & 3; + ch = p[2]; + if (pc->st->l3.debug) + l3_debug(pc->st, "Restart for channel %d", chan); + } + newl3state(pc, 2); + up = pc->st->l3.proc; + while (up) { + if ((ri & 7) == 7) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + else if (up->para.bchannel == chan) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + up = up->next; + } + p = tmp; + MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); + if (chan) { + *p++ = IE_CHANNEL_ID; + *p++ = 1; + *p++ = ch | 0x80; + } + *p++ = 0x79; /* RESTART Ind */ + *p++ = 1; + *p++ = ri; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 0); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) +{ + pc->para.cause = 0x29; /* Temporary failure */ + pc->para.loc = 0; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 0); + pc->para.cause = 0x1b; /* Destination out of order */ + pc->para.loc = 0; + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + release_l3_process(pc); +} + +static void +l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T309, CC_T309); + l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + + pc->para.cause = 0x1F; /* normal, unspecified */ + l3ni1_status_send(pc, 0, NULL); +} + +static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState ) +{ + u_char * p; + char * pSPID; + struct Channel * pChan = pc->st->lli.userdata; + int l; + + if ( skb ) + dev_kfree_skb( skb); + + if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) ) + { + printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + return; + } + + l = strlen( ++pSPID ); + if ( !( skb = l3_alloc_skb( 5+l ) ) ) + { + printk( KERN_ERR "HiSax can't get memory to send SPID\n" ); + return; + } + + p = skb_put( skb, 5 ); + *p++ = PROTO_DIS_EURO; + *p++ = 0; + *p++ = MT_INFORMATION; + *p++ = IE_SPID; + *p++ = l; + + memcpy( skb_put( skb, l ), pSPID, l ); + + newl3state( pc, iNewState ); + + L3DelTimer( &pc->timer ); + L3AddTimer( &pc->timer, TSPID, CC_TSPID ); + + pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb ); +} + +static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) +{ + l3ni1_SendSpid( pc, pr, arg, 20 ); +} + +void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) +{ + struct sk_buff *skb = arg; + + if ( skb->data[ 1 ] == 0 ) + if ( skb->data[ 3 ] == IE_ENDPOINT_ID ) + { + L3DelTimer( &pc->timer ); + newl3state( pc, 0 ); + l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL ); + } + dev_kfree_skb( skb); +} + +static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg ) +{ + if ( pc->state < 22 ) + l3ni1_SendSpid( pc, pr, arg, pc->state+1 ); + else + { + L3DelTimer( &pc->timer ); + dev_kfree_skb( arg); + + printk( KERN_ERR "SPID not accepted\n" ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + } +} + +/* *INDENT-OFF* */ +static struct stateentry downstatelist[] = +{ + {SBIT(0), + CC_SETUP | REQUEST, l3ni1_setup_req}, + {SBIT(0), + CC_RESUME | REQUEST, l3ni1_resume_req}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(12), + CC_RELEASE | REQUEST, l3ni1_release_req}, + {ALL_STATES, + CC_RESTART | REQUEST, l3ni1_restart}, + {SBIT(6) | SBIT(25), + CC_IGNORE | REQUEST, l3ni1_reset}, + {SBIT(6) | SBIT(25), + CC_REJECT | REQUEST, l3ni1_reject_req}, + {SBIT(6) | SBIT(25), + CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, + {SBIT(6), + CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3ni1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), + CC_ALERTING | REQUEST, l3ni1_alert_req}, + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), + CC_SETUP | RESPONSE, l3ni1_setup_rsp}, + {SBIT(10), + CC_SUSPEND | REQUEST, l3ni1_suspend_req}, + {SBIT(7) | SBIT(9) | SBIT(25), + CC_REDIR | REQUEST, l3ni1_redir_req}, + {SBIT(6), + CC_REDIR | REQUEST, l3ni1_redir_req_early}, + {SBIT(9) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(25), + CC_T302, l3ni1_t302}, + {SBIT(1), + CC_T303, l3ni1_t303}, + {SBIT(2), + CC_T304, l3ni1_t304}, + {SBIT(3), + CC_T310, l3ni1_t310}, + {SBIT(8), + CC_T313, l3ni1_t313}, + {SBIT(11), + CC_T305, l3ni1_t305}, + {SBIT(15), + CC_T319, l3ni1_t319}, + {SBIT(17), + CC_T318, l3ni1_t318}, + {SBIT(19), + CC_T308_1, l3ni1_t308_1}, + {SBIT(19), + CC_T308_2, l3ni1_t308_2}, + {SBIT(10), + CC_T309, l3ni1_dl_release}, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), + CC_TSPID, l3ni1_spid_tout }, +}; + +#define DOWNSLLEN \ + (sizeof(downstatelist) / sizeof(struct stateentry)) + +static struct stateentry datastatelist[] = +{ + {ALL_STATES, + MT_STATUS_ENQUIRY, l3ni1_status_enq}, + {ALL_STATES, + MT_FACILITY, l3ni1_facility}, + {SBIT(19), + MT_STATUS, l3ni1_release_ind}, + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_SETUP, l3ni1_setup}, + {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | + SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_SETUP, l3ni1_dummy}, + {SBIT(1) | SBIT(2), + MT_CALL_PROCEEDING, l3ni1_call_proc}, + {SBIT(1), + MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, + {SBIT(2) | SBIT(3), + MT_ALERTING, l3ni1_alerting}, + {SBIT(2) | SBIT(3), + MT_PROGRESS, l3ni1_progress}, + {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_INFORMATION, l3ni1_information}, + {SBIT(10) | SBIT(11) | SBIT(15), + MT_NOTIFY, l3ni1_notify}, + {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), + MT_RELEASE, l3ni1_release}, + {SBIT(19), MT_RELEASE, l3ni1_release_ind}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), + MT_DISCONNECT, l3ni1_disconnect}, + {SBIT(19), + MT_DISCONNECT, l3ni1_dummy}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), + MT_CONNECT, l3ni1_connect}, + {SBIT(8), + MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, + {SBIT(15), + MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, + {SBIT(15), + MT_SUSPEND_REJECT, l3ni1_suspend_rej}, + {SBIT(17), + MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, + {SBIT(17), + MT_RESUME_REJECT, l3ni1_resume_rej}, +}; + +#define DATASLLEN \ + (sizeof(datastatelist) / sizeof(struct stateentry)) + +static struct stateentry globalmes_list[] = +{ + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_RESTART, l3ni1_global_restart}, +/* {SBIT(1), + MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, +*/ + { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, +}; +#define GLOBALM_LEN \ + (sizeof(globalmes_list) / sizeof(struct stateentry)) + +static struct stateentry manstatelist[] = +{ + {SBIT(2), + DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, + {SBIT(10), + DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, + {SBIT(10), + DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, + {ALL_STATES, + DL_RELEASE | INDICATION, l3ni1_dl_release}, +}; + +#define MANSLLEN \ + (sizeof(manstatelist) / sizeof(struct stateentry)) +/* *INDENT-ON* */ + + +static void +global_handler(struct PStack *st, int mt, struct sk_buff *skb) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + int i; + struct l3_process *proc = st->l3.global; + + if ( skb ) + proc->callref = skb->data[2]; /* cr flag */ + else + proc->callref = 0; + for (i = 0; i < GLOBALM_LEN; i++) + if ((mt == globalmes_list[i].primitive) && + ((1 << proc->state) & globalmes_list[i].state)) + break; + if (i == GLOBALM_LEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global state %d mt %x unhandled", + proc->state, mt); + } + MsgHead(p, proc->callref, MT_STATUS); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 81 |0x80; /* invalid cr */ + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = proc->state & 0x3f; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(proc->st, DL_DATA | REQUEST, skb); + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global %d mt %x", + proc->state, mt); + } + globalmes_list[i].rout(proc, mt, skb); + } +} + +static void +ni1up(struct PStack *st, int pr, void *arg) +{ + int i, mt, cr, cause, callState; + char *ptr; + u_char *p; + struct sk_buff *skb = arg; + struct l3_process *proc; + + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + + case (DL_ESTABLISH | CONFIRM): + global_handler( st, MT_DL_ESTABLISHED, NULL ); + return; + + default: + printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); + return; + } + if (skb->len < 3) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + + if (skb->data[0] != PROTO_DIS_EURO) { + if (st->l3.debug & L3_DEB_PROTERR) { + l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + skb->data[0], skb->len); + } + dev_kfree_skb(skb); + return; + } + cr = getcallref(skb->data); + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + mt = skb->data[skb->data[1] + 2]; + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up cr %d", cr); + if (cr == -2) { /* wrong Callref */ + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up wrong Callref"); + dev_kfree_skb(skb); + return; + } else if (cr == -1) { /* Dummy Callref */ + if (mt == MT_FACILITY) + { + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(st, NULL, + (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); + dev_kfree_skb(skb); + return; + } + } + else + { + global_handler(st, mt, skb); + return; + } + + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); + dev_kfree_skb(skb); + return; + } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) || + (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up Global CallRef"); + global_handler(st, mt, skb); + dev_kfree_skb(skb); + return; + } else if (!(proc = getl3proc(st, cr))) { + /* No transaction process exist, that means no call with + * this callreference is active + */ + if (mt == MT_SETUP) { + /* Setup creates a new transaction process */ + if (skb->data[2] & 0x80) { + /* Setup with wrong CREF flag */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up wrong CRef flag"); + dev_kfree_skb(skb); + return; + } + if (!(proc = ni1_new_l3_process(st, cr))) { + /* May be to answer with RELEASE_COMPLETE and + * CAUSE 0x2f "Resource unavailable", but this + * need a new_l3_process too ... arghh + */ + dev_kfree_skb(skb); + return; + } + } else if (mt == MT_STATUS) { + cause = 0; + if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + cause = *ptr & 0x7f; + } + callState = 0; + if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + callState = *ptr; + } + /* ETS 300-104 part 2.4.1 + * if setup has not been made and a message type + * MT_STATUS is received with call state == 0, + * we must send nothing + */ + if (callState != 0) { + /* ETS 300-104 part 2.4.2 + * if setup has not been made and a message type + * MT_STATUS is received with call state != 0, + * we must send MT_RELEASE_COMPLETE cause 101 + */ + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 101; + l3ni1_msg_without_setup(proc, 0, NULL); + } + } + dev_kfree_skb(skb); + return; + } else if (mt == MT_RELEASE_COMPLETE) { + dev_kfree_skb(skb); + return; + } else { + /* ETS 300-104 part 2 + * if setup has not been made and a message type + * (except MT_SETUP and RELEASE_COMPLETE) is received, + * we must send MT_RELEASE_COMPLETE cause 81 */ + dev_kfree_skb(skb); + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 81; + l3ni1_msg_without_setup(proc, 0, NULL); + } + return; + } + } + if (l3ni1_check_messagetype_validity(proc, mt, skb)) { + dev_kfree_skb(skb); + return; + } + if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) + l3ni1_deliver_display(proc, pr, p); /* Display IE included */ + for (i = 0; i < DATASLLEN; i++) + if ((mt == datastatelist[i].primitive) && + ((1 << proc->state) & datastatelist[i].state)) + break; + if (i == DATASLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %#x unhandled", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { + proc->para.cause = 101; + l3ni1_status_send(proc, pr, skb); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %x", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + datastatelist[i].rout(proc, pr, skb); + } + dev_kfree_skb(skb); + return; +} + +static void +ni1down(struct PStack *st, int pr, void *arg) +{ + int i, cr; + struct l3_process *proc; + struct Channel *chan; + + if ((DL_ESTABLISH | REQUEST) == pr) { + l3_msg(st, pr, NULL); + return; + } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { + chan = arg; + cr = newcallref(); + cr |= 0x80; + if ((proc = ni1_new_l3_process(st, cr))) { + proc->chan = chan; + chan->proc = proc; + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); + proc->callref = cr; + } + } else { + proc = arg; + } + if (!proc) { + printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); + return; + } + + if ( pr == (CC_TNI1_IO | REQUEST)) { + l3ni1_io_timer(proc); /* timer expires */ + return; + } + + for (i = 0; i < DOWNSLLEN; i++) + if ((pr == downstatelist[i].primitive) && + ((1 << proc->state) & downstatelist[i].state)) + break; + if (i == DOWNSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x unhandled", + proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x", + proc->state, pr); + } + downstatelist[i].rout(proc, pr, arg); + } +} + +static void +ni1man(struct PStack *st, int pr, void *arg) +{ + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) + if ((pr == manstatelist[i].primitive) && + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } +} + +void +setstack_ni1(struct PStack *st) +{ + char tmp[64]; + int i; + + st->lli.l4l3 = ni1down; + st->lli.l4l3_proto = l3ni1_cmd_global; + st->l2.l2l3 = ni1up; + st->l3.l3ml3 = ni1man; + st->l3.N303 = 1; + st->prot.ni1.last_invoke_id = 0; + st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ + i = 1; + while (i < 32) + st->prot.ni1.invoke_used[i++] = 0; + + if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { + printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); + } else { + st->l3.global->state = 0; + st->l3.global->callref = 0; + st->l3.global->next = NULL; + st->l3.global->debug = L3_DEB_WARN; + st->l3.global->st = st; + st->l3.global->N303 = 1; + st->l3.global->prot.ni1.invoke_id = 0; + + L3InitTimer(st->l3.global, &st->l3.global->timer); + } + strcpy(tmp, ni1_revision); + printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/l3ni1.h linux/drivers/isdn/hisax/l3ni1.h --- v2.4.0-test6/linux/drivers/isdn/hisax/l3ni1.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/l3ni1.h Mon Aug 21 07:49:03 2000 @@ -0,0 +1,136 @@ +// $Id: l3ni1.h,v 2.2 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#ifndef l3ni1_process + +#define T302 15000 +#define T303 4000 +#define T304 30000 +#define T305 30000 +#define T308 4000 +/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ +/* This makes some tests easier and quicker */ +#define T309 40000 +#define T310 30000 +#define T313 4000 +#define T318 4000 +#define T319 4000 +#define TSPID 2000 + +/* + * Message-Types + */ + +#define MT_ALERTING 0x01 +#define MT_CALL_PROCEEDING 0x02 +#define MT_CONNECT 0x07 +#define MT_CONNECT_ACKNOWLEDGE 0x0f +#define MT_PROGRESS 0x03 +#define MT_SETUP 0x05 +#define MT_SETUP_ACKNOWLEDGE 0x0d +#define MT_RESUME 0x26 +#define MT_RESUME_ACKNOWLEDGE 0x2e +#define MT_RESUME_REJECT 0x22 +#define MT_SUSPEND 0x25 +#define MT_SUSPEND_ACKNOWLEDGE 0x2d +#define MT_SUSPEND_REJECT 0x21 +#define MT_USER_INFORMATION 0x20 +#define MT_DISCONNECT 0x45 +#define MT_RELEASE 0x4d +#define MT_RELEASE_COMPLETE 0x5a +#define MT_RESTART 0x46 +#define MT_RESTART_ACKNOWLEDGE 0x4e +#define MT_SEGMENT 0x60 +#define MT_CONGESTION_CONTROL 0x79 +#define MT_INFORMATION 0x7b +#define MT_FACILITY 0x62 +#define MT_NOTIFY 0x6e +#define MT_STATUS 0x7d +#define MT_STATUS_ENQUIRY 0x75 +#define MT_DL_ESTABLISHED 0xfe + +#define IE_SEGMENT 0x00 +#define IE_BEARER 0x04 +#define IE_CAUSE 0x08 +#define IE_CALL_ID 0x10 +#define IE_CALL_STATE 0x14 +#define IE_CHANNEL_ID 0x18 +#define IE_FACILITY 0x1c +#define IE_PROGRESS 0x1e +#define IE_NET_FAC 0x20 +#define IE_NOTIFY 0x27 +#define IE_DISPLAY 0x28 +#define IE_DATE 0x29 +#define IE_KEYPAD 0x2c +#define IE_SIGNAL 0x34 +#define IE_SPID 0x3a +#define IE_ENDPOINT_ID 0x3b +#define IE_INFORATE 0x40 +#define IE_E2E_TDELAY 0x42 +#define IE_TDELAY_SEL 0x43 +#define IE_PACK_BINPARA 0x44 +#define IE_PACK_WINSIZE 0x45 +#define IE_PACK_SIZE 0x46 +#define IE_CUG 0x47 +#define IE_REV_CHARGE 0x4a +#define IE_CONNECT_PN 0x4c +#define IE_CONNECT_SUB 0x4d +#define IE_CALLING_PN 0x6c +#define IE_CALLING_SUB 0x6d +#define IE_CALLED_PN 0x70 +#define IE_CALLED_SUB 0x71 +#define IE_REDIR_NR 0x74 +#define IE_TRANS_SEL 0x78 +#define IE_RESTART_IND 0x79 +#define IE_LLC 0x7c +#define IE_HLC 0x7d +#define IE_USER_USER 0x7e +#define IE_ESCAPE 0x7f +#define IE_SHIFT 0x90 +#define IE_MORE_DATA 0xa0 +#define IE_COMPLETE 0xa1 +#define IE_CONGESTION 0xb0 +#define IE_REPEAT 0xd0 + +#define IE_MANDATORY 0x0100 +/* mandatory not in every case */ +#define IE_MANDATORY_1 0x0200 + +#define ERR_IE_COMPREHENSION 1 +#define ERR_IE_UNRECOGNIZED -1 +#define ERR_IE_LENGTH -2 +#define ERR_IE_SEQUENCE -3 + +#else /* only l3ni1_process */ + +/* l3ni1 specific data in l3 process */ +typedef struct + { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ + ulong ll_id; /* remebered ll id */ + u_char remote_operation; /* handled remote operation, 0 = not active */ + int proc; /* rememered procedure */ + ulong remote_result; /* result of remote operation for statcallb */ + char uus1_data[35]; /* data send during alerting or disconnect */ + } ni1_proc_priv; + +/* l3dni1 specific data in protocol stack */ +typedef struct + { unsigned char last_invoke_id; /* last used value for invoking */ + unsigned char invoke_used[32]; /* 256 bits for 256 values */ + } ni1_stk_priv; + +#endif /* only l3dni1_process */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.4.0-test6/linux/drivers/isdn/hisax/md5sums.asc Wed Apr 26 16:34:07 2000 +++ linux/drivers/isdn/hisax/md5sums.asc Mon Aug 21 07:49:03 2000 @@ -2,30 +2,32 @@ # This are valid md5sums for certificated HiSax driver. # The certification is valid only if the md5sums of all files match. -# The certification is valid only for ELSA QuickStep cards and -# Eicon Technology Diva 2.01 PCI cards in the moment. +# The certification is valid only for ELSA Microlink PCI, +# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax + +# cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3fb9c99465857a4c136ae2881f4e30ba isac.c -dd3955847bbf680b41233478fe521d88 isdnl1.c -d362523462c424a8bce8b596ed5bdf2e isdnl2.c -92ea268891c222963a6ca70935bf1556 isdnl3.c -a23fbf8879c1432b04640b8b04bdf419 tei.c -838791b14269ec94c74ba4ae89c022e6 callc.c -bf9605b36429898f7be6630034e83230 cert.c -a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c -a3a570781f828b6d59e6b231653133de l3_1tr6.c -4aeba32c4c3480d2a6b9af34600b974f elsa.c -a296edc459b508bf0346c3132815a4db diva.c +f4573d10ffe38b49f6c94e4c966b7bab isac.c +a29f5270c0c89626d8d6fa5dd09e7005 isdnl1.c +fbe41751c8130a8c3c607bfe1b41cb4e isdnl2.c +7915b7e802b98f6f4f05b931c4736ad4 isdnl3.c +7c31c12b3c2cfde33596bd2c406f775c tei.c +f1fbd532016f005e01decf36e5197d8f callc.c +a1834e9b2ec068440cff2e899eff4710 cert.c +a1f908f8b4f225c5c2f2a13842549b72 l3dss1.c +5bcab52f9937beb352aa02093182e039 l3_1tr6.c +030d4600ee59a2b246410d6a73977412 elsa.c +9e800b8e05c24542d731721eb192f305 diva.c +f32fae58dd9b2b3a73b2e5028f68dc4c sedlbauer.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBOPT2aTpxHvX/mS9tAQFJyAQAj+eY8MhPxQ2TS3rtfjK7bv8jrOGeJYu6 -P0YPnkkc09pCA6UdmYP6VSFkhtDS43HEZiGMb1MV/Y4LQ4wVDNrFDk9AyUNhP2/0 -gY+nYON6hT9ilXYqsbqoqGmh5qLaxj64p9mKu+MIgZ69CS4g7aj/OAXWB06zh7li -MiC65PNo6k0= -=d7xA +iQCVAwUBOaARmDpxHvX/mS9tAQFT7wP/TEEhtP96uKKgzr2o3GpJ5rRik0Q1HbKY +dzeA3U79QCEYqyptU09Uz96Av3dt1lNxpQyaahX419NjHH53HCaZgFCxgRxFWBYS +M9s4aSXLPTCSNM/kWiZkzWQ2lZ7ISNk2/+fF73w4l3G+4zF5y+VotjZCPx7OJj6i +R/L1m4vZXys= +=6DzE -----END PGP SIGNATURE----- diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.4.0-test6/linux/drivers/isdn/hisax/netjet.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/netjet.c Tue Aug 22 09:06:31 2000 @@ -11,7 +11,6 @@ */ #define __NO_VERSION__ -#include #include "hisax.h" #include "isac.h" #include "hscx.h" @@ -19,6 +18,7 @@ #include #include #include +#include "netjet.h" #ifndef bus_to_virt #define bus_to_virt (u_int *) @@ -28,61 +28,12 @@ #define virt_to_bus (u_int) #endif -extern const char *CardType[]; - -const char *NETjet_revision = "$Revision: 1.18 $"; - -#define byteout(addr,val) outb(val,addr) -#define bytein(addr) inb(addr) - -/* PCI stuff */ -#define PCI_VENDOR_TRAVERSE_TECH 0xe159 -#define PCI_NETJET_ID 0x0001 - -#define NETJET_CTRL 0x00 -#define NETJET_DMACTRL 0x01 -#define NETJET_AUXCTRL 0x02 -#define NETJET_AUXDATA 0x03 -#define NETJET_IRQMASK0 0x04 -#define NETJET_IRQMASK1 0x05 -#define NETJET_IRQSTAT0 0x06 -#define NETJET_IRQSTAT1 0x07 -#define NETJET_DMA_READ_START 0x08 -#define NETJET_DMA_READ_IRQ 0x0c -#define NETJET_DMA_READ_END 0x10 -#define NETJET_DMA_READ_ADR 0x14 -#define NETJET_DMA_WRITE_START 0x18 -#define NETJET_DMA_WRITE_IRQ 0x1c -#define NETJET_DMA_WRITE_END 0x20 -#define NETJET_DMA_WRITE_ADR 0x24 -#define NETJET_PULSE_CNT 0x28 - -#define NETJET_ISAC_OFF 0xc0 -#define NETJET_ISACIRQ 0x10 -#define NETJET_IRQM0_READ 0x0c -#define NETJET_IRQM0_READ_1 0x04 -#define NETJET_IRQM0_READ_2 0x08 -#define NETJET_IRQM0_WRITE 0x03 -#define NETJET_IRQM0_WRITE_1 0x01 -#define NETJET_IRQM0_WRITE_2 0x02 - -#define NETJET_DMA_TXSIZE 512 -#define NETJET_DMA_RXSIZE 128 - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e +const char *NETjet_revision = "$Revision: 1.20 $"; /* Interface functions */ -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) +u_char +NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) { long flags; u_char ret; @@ -97,8 +48,8 @@ return(ret); } -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +void +NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) { long flags; @@ -111,8 +62,8 @@ restore_flags(flags); } -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -155,8 +106,8 @@ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -242,15 +193,6 @@ bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); } -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return(5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { char tmp[128]; char *t = tmp; @@ -541,7 +483,7 @@ bcs->hw.tiger.r_bitcnt = bitcnt; } -static void read_tiger(struct IsdnCardState *cs) { +void read_tiger(struct IsdnCardState *cs) { u_int *p; int cnt = NETJET_DMA_RXSIZE/2; @@ -572,7 +514,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt); -static void fill_dma(struct BCState *bcs) +void netjet_fill_dma(struct BCState *bcs) { register u_int *p, *sp; register int cnt; @@ -687,7 +629,7 @@ test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - fill_dma(bcs); + netjet_fill_dma(bcs); } else { mask ^= 0xffffffff; if (s_cnt < cnt) { @@ -719,7 +661,7 @@ } } -static void write_tiger(struct IsdnCardState *cs) { +void write_tiger(struct IsdnCardState *cs) { u_int *p, cnt = NETJET_DMA_TXSIZE/2; if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { @@ -935,88 +877,6 @@ } } -static void -netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - long flags; - - if (!cs) { - printk(KERN_WARNING "NETjet: Spurious interrupt!\n"); - return; - } - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { - val = ReadISAC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); - if (val) { - isac_interrupt(cs, val); - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - } - } - save_flags(flags); - cli(); - if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - restore_flags(flags); - return; - } - cs->hw.njet.irqstat0 = sval; - restore_flags(flags); -/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", - sval, - bytein(cs->hw.njet.base + NETJET_DMACTRL), - bytein(cs->hw.njet.base + NETJET_IRQMASK0), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); -*/ -/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; -*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); -/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); -*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) - read_tiger(cs); - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) - write_tiger(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - restore_flags(flags); - -/* if (!testcnt--) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } -*/ -} - -static void -reset_netjet(struct IsdnCardState *cs) -{ - long flags; - - save_flags(flags); - sti(); - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - restore_flags(flags); - cs->hw.njet.auxd = 0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - void release_io_netjet(struct IsdnCardState *cs) { @@ -1026,100 +886,3 @@ release_region(cs->hw.njet.base, 256); } - -static int -NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - reset_netjet(cs); - return(0); - case CARD_RELEASE: - release_io_netjet(cs); - return(0); - case CARD_INIT: - inittiger(cs); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - return(0); - case CARD_TEST: - return(0); - } - return(0); -} - -static struct pci_dev *dev_netjet __initdata = NULL; - -__initfunc(int -setup_netjet(struct IsdnCard *card)) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - char tmp[64]; -#if CONFIG_PCI -#endif - strcpy(tmp, NETjet_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET) - return(0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "Netjet: no PCI bus present\n"); - return(0); - } - if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, - PCI_NETJET_ID, dev_netjet))) { - if (pci_enable_device(dev_netjet)) - return (0); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); - return(0); - } - } else { - printk(KERN_WARNING "NETjet: No PCI card found\n"); - return(0); - } - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - bytecnt = 256; -#else - printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n"); - printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - printk(KERN_INFO - "NETjet: PCI card configured at 0x%x IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (check_region(cs->hw.njet.base, bytecnt)) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } else { - request_region(cs->hw.njet.base, bytecnt, "netjet isdn"); - } - reset_netjet(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &fill_dma; - cs->cardmsg = &NETjet_card_msg; - cs->irq_func = &netjet_interrupt; - cs->irq_flags |= SA_SHIRQ; - ISACVersion(cs, "NETjet:"); - return (1); -} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/netjet.h linux/drivers/isdn/hisax/netjet.h --- v2.4.0-test6/linux/drivers/isdn/hisax/netjet.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/netjet.h Mon Aug 21 07:49:03 2000 @@ -0,0 +1,77 @@ +// $Id: netjet.h,v 2.3 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NETjet common header file +// +// Author Kerstern Keil repackaged by +// Matt Henderson - Traverse Technologies P/L www.traverse.com.au +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +extern const char *CardType[]; + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +/* PCI stuff */ +#ifndef PCI_VENDOR_ID_TIGERJET +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#endif +#ifndef PCI_DEVICE_ID_TIGERJET_300 +#define PCI_DEVICE_ID_TIGERJET_300 0x0001 +#endif +#define NETJET_CTRL 0x00 +#define NETJET_DMACTRL 0x01 +#define NETJET_AUXCTRL 0x02 +#define NETJET_AUXDATA 0x03 +#define NETJET_IRQMASK0 0x04 +#define NETJET_IRQMASK1 0x05 +#define NETJET_IRQSTAT0 0x06 +#define NETJET_IRQSTAT1 0x07 +#define NETJET_DMA_READ_START 0x08 +#define NETJET_DMA_READ_IRQ 0x0c +#define NETJET_DMA_READ_END 0x10 +#define NETJET_DMA_READ_ADR 0x14 +#define NETJET_DMA_WRITE_START 0x18 +#define NETJET_DMA_WRITE_IRQ 0x1c +#define NETJET_DMA_WRITE_END 0x20 +#define NETJET_DMA_WRITE_ADR 0x24 +#define NETJET_PULSE_CNT 0x28 + +#define NETJET_ISAC_OFF 0xc0 +#define NETJET_ISACIRQ 0x10 +#define NETJET_IRQM0_READ 0x0c +#define NETJET_IRQM0_READ_1 0x04 +#define NETJET_IRQM0_READ_2 0x08 +#define NETJET_IRQM0_WRITE 0x03 +#define NETJET_IRQM0_WRITE_1 0x01 +#define NETJET_IRQM0_WRITE_2 0x02 + +#define NETJET_DMA_TXSIZE 512 +#define NETJET_DMA_RXSIZE 128 + +#define HDLC_ZERO_SEARCH 0 +#define HDLC_FLAG_SEARCH 1 +#define HDLC_FLAG_FOUND 2 +#define HDLC_FRAME_FOUND 3 +#define HDLC_NULL 4 +#define HDLC_PART 5 +#define HDLC_FULL 6 + +#define HDLC_FLAG_VALUE 0x7e + +u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); +void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); +void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); +void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); + +void read_tiger(struct IsdnCardState *cs); +void write_tiger(struct IsdnCardState *cs); + +void netjet_fill_dma(struct BCState *bcs); +void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs); +__initfunc(void inittiger(struct IsdnCardState *cs)); +void release_io_netjet(struct IsdnCardState *cs); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.4.0-test6/linux/drivers/isdn/hisax/niccy.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/niccy.c Mon Aug 21 07:49:03 2000 @@ -38,8 +38,12 @@ #define NICCY_PCI 2 /* PCI stuff */ -#define PCI_VENDOR_DR_NEUHAUS 0x1267 -#define PCI_NICCY_ID 0x1016 +#ifndef PCI_VENDOR_ID_SATSAGEM +#define PCI_VENDOR_ID_SATSAGEM 0x1267 +#endif +#ifndef PCI_DEVICE_ID_SATSAGEM_NICCY +#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 +#endif #define PCI_IRQ_CTRL_REG 0x38 #define PCI_IRQ_ENABLE 0x1f00 #define PCI_IRQ_DISABLE 0xff0000 @@ -284,26 +288,26 @@ return(0); } cs->subtyp = 0; - if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, - PCI_NICCY_ID, niccy_dev))) { + if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, + PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { if (pci_enable_device(niccy_dev)) - return (0); + return(0); /* get IRQ */ if (!niccy_dev->irq) { printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); return(0); } cs->irq = niccy_dev->irq; - if (!niccy_dev->resource[ 0].start) { + cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); + if (!cs->hw.niccy.cfg_reg) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); return(0); } - cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); - if (!niccy_dev->resource[ 1].start) { + pci_ioaddr = pci_resource_start(niccy_dev, 1); + if (!pci_ioaddr) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr = pci_resource_start(niccy_dev, 1); cs->subtyp = NICCY_PCI; } else { printk(KERN_WARNING "Niccy: No PCI card found\n"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c --- v2.4.0-test6/linux/drivers/isdn/hisax/nj_s.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/nj_s.c Mon Aug 21 07:49:03 2000 @@ -0,0 +1,257 @@ +// $Id: nj_s.c,v 2.3 2000/06/26 08:59:14 keil Exp $ +// +// This file is (c) under GNU PUBLIC LICENSE +// +#define __NO_VERSION__ +#include +#include "hisax.h" +#include "isac.h" +#include "isdnl1.h" +#include +#include +#include +#include "netjet.h" + +const char *NETjet_S_revision = "$Revision: 2.3 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ISAC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + isac_interrupt(cs, val); + NETjet_WriteIC(cs, ISAC_MASK, 0xFF); + NETjet_WriteIC(cs, ISAC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", + sval, + bytein(cs->hw.njet.base + NETJET_DMACTRL), + bytein(cs->hw.njet.base + NETJET_IRQMASK0), + inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), + inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), + bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); +*/ +/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; +*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); +/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) + read_tiger(cs); + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) + write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_s(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_s(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_isac_ints(cs); + initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +__initfunc(int +setup_netjet_s(struct IsdnCard *card)) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_S_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_S) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + +#if CONFIG_PCI + + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETjet-S: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) ) + { + case 0 : + break; + + case 3 : + printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETjet-S: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETjet-S: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn"); + } + reset_netjet_s(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_S_card_msg; + cs->irq_func = &netjet_s_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "NETjet-S:"); + return (1); +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c --- v2.4.0-test6/linux/drivers/isdn/hisax/nj_u.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/nj_u.c Mon Aug 21 07:49:03 2000 @@ -0,0 +1,260 @@ +/* $Id: nj_u.c,v 2.4 2000/06/26 11:42:16 keil Exp $ + * + * This file is (c) under GNU PUBLIC LICENSE + * + */ +#define __NO_VERSION__ +#include +#include "hisax.h" +#include "icc.h" +#include "isdnl1.h" +#include +#include +#include +#include "netjet.h" + +const char *NETjet_U_revision = "$Revision: 2.4 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ICC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + icc_interrupt(cs, val); + NETjet_WriteIC(cs, ICC_MASK, 0xFF); + NETjet_WriteIC(cs, ICC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", + sval, + bytein(cs->hw.njet.base + NETJET_DMACTRL), + bytein(cs->hw.njet.base + NETJET_IRQMASK0), + inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), + inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), + bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); +*/ +/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; +*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); +/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) + read_tiger(cs); + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) + write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_u(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_u(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_icc_ints(cs); + initicc(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +__initfunc(int +setup_netjet_u(struct IsdnCard *card)) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_U_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_U) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + +#if CONFIG_PCI + + if (!pci_present()) { + printk(KERN_ERR "NETspider-U: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETspider-U: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) ) + { + case 3 : + break; + + case 0 : + printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETspider-U: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETspider-U: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-u isdn"); + } + reset_netjet_u(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_U_card_msg; + cs->irq_func = &netjet_u_interrupt; + cs->irq_flags |= SA_SHIRQ; + ICCVersion(cs, "NETspider-U:"); + return (1); +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.4.0-test6/linux/drivers/isdn/hisax/q931.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/q931.c Mon Aug 21 07:49:03 2000 @@ -65,6 +65,24 @@ 0xd, "SETUP ACKNOWLEDGE" }, { + 0x24, "HOLD" + }, + { + 0x28, "HOLD ACKNOWLEDGE" + }, + { + 0x30, "HOLD REJECT" + }, + { + 0x31, "RETRIEVE" + }, + { + 0x33, "RETRIEVE ACKNOWLEDGE" + }, + { + 0x37, "RETRIEVE REJECT" + }, + { 0x26, "RESUME" }, { @@ -638,6 +656,65 @@ return (dp - dest); } + +static +int +prbearer_ni1(char *dest, u_char * p) +{ + char *dp = dest; + u_char len; + + p++; + len = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x80: + dp += sprintf(dp, " Speech"); + break; + case 0x88: + dp += sprintf(dp, " Unrestricted digital information"); + break; + case 0x90: + dp += sprintf(dp, " 3.1 kHz audio"); + break; + default: + dp += sprintf(dp, " Unknown information-transfer capability"); + } + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x90: + dp += sprintf(dp, " 64 kbps, circuit mode"); + break; + case 0xc0: + dp += sprintf(dp, " Packet mode"); + break; + default: + dp += sprintf(dp, " Unknown transfer mode"); + } + *dp++ = '\n'; + if (len > 2) { + dp += sprintf(dp, " octet 5 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x21: + dp += sprintf(dp, " Rate adaption\n"); + dp += sprintf(dp, " octet 5a "); + dp += prbits(dp, *p, 8, 8); + break; + case 0xa2: + dp += sprintf(dp, " u-law"); + break; + default: + dp += sprintf(dp, " Unknown UI layer 1 protocol"); + } + *dp++ = '\n'; + } + return (dp - dest); +} + static int general(char *dest, u_char * p) { @@ -666,6 +743,33 @@ } static int +general_ni1(char *dest, u_char * p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p++ & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int prcharge(char *dest, u_char * p) { char *dp = dest; @@ -697,6 +801,112 @@ *dp++ = '\n'; return (dp - dest); } + +static int +prfeatureind(char *dest, u_char * p) +{ + char *dp = dest; + + p += 2; /* skip id, len */ + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p++ & 80)) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + dp += sprintf(dp, " Status: "); + switch (*p) { + case 0: + dp += sprintf(dp, "Idle"); + break; + case 1: + dp += sprintf(dp, "Active"); + break; + case 2: + dp += sprintf(dp, "Prompt"); + break; + case 3: + dp += sprintf(dp, "Pending"); + break; + default: + dp += sprintf(dp, "(Reserved)"); + break; + } + *dp++ = '\n'; + return (dp - dest); +} + +static +struct DTag { /* Display tags */ + u_char nr; + char *descr; +} dtaglist[] = { + { 0x82, "Continuation" }, + { 0x83, "Called address" }, + { 0x84, "Cause" }, + { 0x85, "Progress indicator" }, + { 0x86, "Notification indicator" }, + { 0x87, "Prompt" }, + { 0x88, "Accumlated digits" }, + { 0x89, "Status" }, + { 0x8a, "Inband" }, + { 0x8b, "Calling address" }, + { 0x8c, "Reason" }, + { 0x8d, "Calling party name" }, + { 0x8e, "Called party name" }, + { 0x8f, "Orignal called name" }, + { 0x90, "Redirecting name" }, + { 0x91, "Connected name" }, + { 0x92, "Originating restrictions" }, + { 0x93, "Date & time of day" }, + { 0x94, "Call Appearance ID" }, + { 0x95, "Feature address" }, + { 0x96, "Redirection name" }, + { 0x9e, "Text" }, +}; +#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) + +static int +disptext_ni1(char *dest, u_char * p) +{ + char *dp = dest; + int l, tag, len, i; + + p++; + l = *p++ - 1; + if (*p++ != 0x80) { + dp += sprintf(dp, " Unknown display type\n"); + return (dp - dest); + } + /* Iterate over all tag,length,text fields */ + while (l > 0) { + tag = *p++; + len = *p++; + l -= len + 2; + /* Don't space or skip */ + if ((tag == 0x80) || (tag == 0x81)) p++; + else { + for (i = 0; i < DTAGSIZE; i++) + if (tag == dtaglist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != DTAGSIZE) { + dp += sprintf(dp, " %s: ", dtaglist[i].descr); + while (len--) + *dp++ = *p++; + } else { + dp += sprintf(dp, " (unknown display tag %2x): ", tag); + while (len--) + *dp++ = *p++; + } + dp += sprintf(dp, "\n"); + } + } + return (dp - dest); +} static int display(char *dest, u_char * p) { @@ -867,6 +1077,49 @@ #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) +static +struct InformationElement ielist_ni1[] = { + { 0x04, "Bearer Capability", prbearer_ni1 }, + { 0x08, "Cause", prcause }, + { 0x14, "Call State", general_ni1 }, + { 0x18, "Channel Identification", prchident }, + { 0x1e, "Progress Indicator", general_ni1 }, + { 0x27, "Notification Indicator", general_ni1 }, + { 0x2c, "Keypad Facility", prtext }, + { 0x32, "Information Request", general_ni1 }, + { 0x34, "Signal", general_ni1 }, + { 0x38, "Feature Activation", general_ni1 }, + { 0x39, "Feature Indication", prfeatureind }, + { 0x3a, "Service Profile Identification (SPID)", prtext }, + { 0x3b, "Endpoint Identifier", general_ni1 }, + { 0x6c, "Calling Party Number", prcalling }, + { 0x6d, "Calling Party Subaddress", general_ni1 }, + { 0x70, "Called Party Number", prcalled }, + { 0x71, "Called Party Subaddress", general_ni1 }, + { 0x74, "Redirecting Number", general_ni1 }, + { 0x78, "Transit Network Selection", general_ni1 }, + { 0x7c, "Low Layer Compatibility", general_ni1 }, + { 0x7d, "High Layer Compatibility", general_ni1 }, +}; + + +#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs5[] = { + { 0x1d, "Operator system access", general_ni1 }, + { 0x2a, "Display text", disptext_ni1 }, +}; + +#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs6[] = { + { 0x7b, "Call appearance", general_ni1 }, +}; + +#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) + static struct InformationElement we_0[] = { {WE0_cause, "Cause", prcause_1tr6}, @@ -1107,7 +1360,93 @@ } buf += buf[1] + 2; } - } else if (buf[0] == 8) { /* EURO */ + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cset; + cset = *buf & 7; + cs_fest = *buf & 8; + break; + default: + dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cset == 0) { + for (i = 0; i < IESIZE; i++) + if (*buf == ielist_ni1[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); + dp += ielist_ni1[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 5) { + for (i = 0; i < IESIZE_NI1_CS5; i++) + if (*buf == ielist_ni1_cs5[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS5) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); + dp += ielist_ni1_cs5[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < IESIZE_NI1_CS6; i++) + if (*buf == ielist_ni1_cs6[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS6) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); + dp += ielist_ni1_cs6[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + + /* Skip to next element */ + if (cs_fest == 8) { + cset = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ /* locate message type */ buf++; cr_l = *buf++; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.4.0-test6/linux/drivers/isdn/hisax/sedlbauer.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/sedlbauer.c Mon Aug 21 07:49:03 2000 @@ -39,8 +39,6 @@ * For example: hisaxctrl 9 ISAR.BIN */ -#define SEDLBAUER_PCI 1 - #define __NO_VERSION__ #include #include "hisax.h" @@ -53,19 +51,23 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.20 $"; +const char *Sedlbauer_revision = "$Revision: 1.23 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pci"}; + "speed fax+ pyramid", "speed fax+ pci"}; -#ifdef SEDLBAUER_PCI -#define PCI_VENDOR_SEDLBAUER 0xe159 -#define PCI_SPEEDPCI_ID 0x02 -#define PCI_SUBVENDOR_SEDLBAUER 0x51 -#define PCI_SUB_ID_SPEEDFAXP 0x01 +#ifndef PCI_VENDOR_ID_TIGERJET +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#endif +#ifndef PCI_DEVICE_ID_TIGERJET_100 +#define PCI_DEVICE_ID_TIGERJET_100 0x0002 #endif +#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 +#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 +#define PCI_SUB_ID_SEDLBAUER 0x01 #define SEDL_SPEED_CARD_WIN 1 #define SEDL_SPEED_STAR 2 @@ -73,7 +75,8 @@ #define SEDL_SPEED_WIN2_PC104 4 #define SEDL_SPEED_STAR2 5 #define SEDL_SPEED_PCI 6 -#define SEDL_SPEEDFAX_PCI 7 +#define SEDL_SPEEDFAX_PYRAMID 7 +#define SEDL_SPEEDFAX_PCI 8 #define SEDL_CHIP_TEST 0 #define SEDL_CHIP_ISAC_HSCX 1 @@ -285,10 +288,10 @@ } if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Sedlbauer: card not available!\n"); - return; + /* The card tends to generate interrupts while being removed + causing us to just crash the kernel. bad. */ + printk(KERN_WARNING "Sedlbauer: card not available!\n"); + return; } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); @@ -360,7 +363,8 @@ goto Start_IPAC; } if (!icnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); } @@ -398,7 +402,8 @@ goto Start_ISAC; } if (!cnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); @@ -508,7 +513,7 @@ case CARD_TEST: return(0); case MDL_INFO_CONN: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; @@ -517,7 +522,7 @@ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); break; case MDL_INFO_REL: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; @@ -529,9 +534,7 @@ return(0); } -#ifdef SEDLBAUER_PCI static struct pci_dev *dev_sedl __initdata = NULL; -#endif __initfunc(int setup_sedlbauer(struct IsdnCard *card)) @@ -569,16 +572,15 @@ } } else { /* Probe for Sedlbauer speed pci */ -#if SEDLBAUER_PCI #if CONFIG_PCI if (!pci_present()) { printk(KERN_ERR "Sedlbauer: no PCI bus present\n"); return(0); } - if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, - PCI_SPEEDPCI_ID, dev_sedl))) { + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { if (pci_enable_device(dev_sedl)) - return (0); + return(0); cs->irq = dev_sedl->irq; if (!cs->irq) { printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); @@ -597,13 +599,23 @@ sub_vendor_id, sub_id); printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", cs->hw.sedl.cfg_reg); - if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) && - (sub_id == PCI_SUB_ID_SPEEDFAXP)) { + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; cs->subtyp = SEDL_SPEEDFAX_PCI; - } else { + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { cs->hw.sedl.chip = SEDL_CHIP_IPAC; cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); } bytecnt = 256; cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; @@ -623,7 +635,6 @@ printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); return (0); #endif /* CONFIG_PCI */ -#endif /* SEDLBAUER_PCI */ } /* In case of the sedlbauer pcmcia card, this region is in use, @@ -683,7 +694,6 @@ if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - /* IPAC */ if (cs->hw.sedl.bus == SEDL_BUS_PCI) { cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c --- v2.4.0-test6/linux/drivers/isdn/hisax/tei.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/tei.c Mon Aug 21 07:49:03 2000 @@ -154,7 +154,7 @@ if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ + if ((ost = findtei(st, tei))) { /* same tei is in use */ if (ri != ost->ma.ri) { st->ma.tei_m.printdebug(&st->ma.tei_m, "possible duplicate assignment tei %d", tei); @@ -181,10 +181,12 @@ if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "foreign identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + if ((ost = findtei(st, tei))) { /* same tei is in use */ + if (ri != ost->ma.ri) { /* and it wasn't our request */ + st->ma.tei_m.printdebug(&st->ma.tei_m, + "possible duplicate assignment tei %d", tei); + FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + } } } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c --- v2.4.0-test6/linux/drivers/isdn/hisax/telespci.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/telespci.c Mon Aug 21 07:49:03 2000 @@ -27,6 +27,12 @@ #define ZORAN_PO_GREG1 0x00010000 #define ZORAN_PO_DMASK 0xFF +#ifndef PCI_VENDOR_ID_ZORAN +#define PCI_VENDOR_ID_ZORAN 0x11DE +#endif +#ifndef PCI_DEVICE_ID_ZORAN_36120 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 +#endif #define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) #define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) #define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) @@ -282,6 +288,9 @@ struct IsdnCardState *cs = card->cs; char tmp[64]; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) @@ -291,18 +300,18 @@ printk(KERN_ERR "TelesPCI: no PCI bus present\n"); return(0); } - if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) { + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) - return (0); + return(0); cs->irq = dev_tel->irq; if (!cs->irq) { printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); return(0); } - cs->hw.teles0.membase = (u_long) ioremap(dev_tel->resource[ 0].start, + cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0), PAGE_SIZE); printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", - dev_tel->resource[ 0].start, dev_tel->irq); + pci_resource_start(dev_tel, 0), dev_tel->irq); } else { printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c --- v2.4.0-test6/linux/drivers/isdn/hisax/w6692.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/hisax/w6692.c Mon Aug 21 07:49:03 2000 @@ -17,13 +17,18 @@ #include #include -#define PCI_VEND_ASUSCOM 0x675 -#define PCI_DEV_ASUSCOMPCI1 0x1702 +#ifndef PCI_VENDOR_ID_ASUSCOM +#define PCI_VENDOR_ID_ASUSCOM 0x675 +#endif +#ifndef PCI_DEVICE_ID_ASUSCOM_TA1 +#define PCI_DEVICE_ID_ASUSCOM_TA1 0x1702 +#endif #ifndef PCI_VENDOR_ID_WINBOND2 #define PCI_VENDOR_ID_WINBOND2 0x1050 #endif -#define PCI_DEVICE_W6692 0x6692 - +#ifndef PCI_DEVICE_ID_WINBOND_6692 +#define PCI_DEVICE_ID_WINBOND_6692 0x6692 +#endif /* table entry in the PCI devices list */ typedef struct { int vendor_id; @@ -34,14 +39,14 @@ static const PCI_ENTRY id_list[] = { - {PCI_VEND_ASUSCOM, PCI_DEV_ASUSCOMPCI1, "AsusCom", "TA XXX"}, - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_W6692, "Winbond", "W6692"}, + {PCI_VENDOR_ID_ASUSCOM, PCI_DEVICE_ID_ASUSCOM_TA1, "AsusCom", "TA XXX"}, + {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND_6692, "Winbond", "W6692"}, {0, 0, NULL, NULL} }; extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.4 $"; +const char *w6692_revision = "$Revision: 1.7 $"; #define DBUSY_TIMER_VALUE 80 @@ -239,7 +244,7 @@ if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); bcs->hw.w6692.rcvidx = 0; return; } @@ -247,14 +252,14 @@ bcs->hw.w6692.rcvidx += count; save_flags(flags); cli(); - READW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + READW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_empty_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -290,14 +295,14 @@ skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.w6692.count += count; - WRITEW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); + WRITEW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_fill_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -308,13 +313,11 @@ { u_char val; u_char r; - struct BCState *bcs = cs->bcs; + struct BCState *bcs; struct sk_buff *skb; int count; - if (bcs->channel != bchan) - bcs++; /* hardware bchan must match ! */ - + bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1); val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); @@ -401,7 +404,7 @@ bcs->tx_cnt += bcs->hw.w6692.count; bcs->hw.w6692.count = 0; } - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B EXIR %x Lost TX", val); } @@ -715,18 +718,16 @@ } static void -W6692Bmode(struct BCState *bcs, int mode, int bc) +W6692Bmode(struct BCState *bcs, int mode, int bchan) { struct IsdnCardState *cs = bcs->cs; - int bchan = bc; - - bcs->hw.w6692.bchan = bc; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "w6692 %c mode %d ichan %d", - '1' + bchan, mode, bc); + '1' + bchan, mode, bchan); bcs->mode = mode; - bcs->channel = bc; + bcs->channel = bchan; + bcs->hw.w6692.bchan = bchan; switch (mode) { case (L1_MODE_NULL): @@ -895,8 +896,6 @@ cs->bcs[1].BC_SetStack = setstack_w6692; cs->bcs[0].BC_Close = close_w6692state; cs->bcs[1].BC_Close = close_w6692state; - cs->bcs[0].hw.w6692.bchan = 0; - cs->bcs[1].hw.w6692.bchan = 1; W6692Bmode(cs->bcs, 0, 0); W6692Bmode(cs->bcs + 1, 0, 0); } @@ -979,6 +978,9 @@ u_char pci_irq = 0; u_int pci_ioaddr = 0; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, w6692_revision); printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/Makefile linux/drivers/isdn/hysdn/Makefile --- v2.4.0-test6/linux/drivers/isdn/hysdn/Makefile Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/Makefile Mon Aug 21 07:49:03 2000 @@ -16,6 +16,9 @@ M_OBJS += hysdn.o O_TARGET += hysdn.o O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o + ifeq ($(CONFIG_HYSDN_CAPI),y) + O_OBJS += hycapi.o + endif OX_OBJS += hysdn_init.o endif endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/boardergo.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/boardergo.c Tue Aug 22 09:06:31 2000 @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: boardergo.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, specific routines for ergo type boards. * @@ -25,6 +25,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: boardergo.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -33,6 +39,7 @@ */ #define __NO_VERSION__ +#include #include #include #include @@ -153,6 +160,9 @@ uchar val; hysdn_net_release(card); /* first release the net device if existing */ +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_stop(card); +#endif /* CONFIG_HYSDN_CAPI */ save_flags(flags); cli(); val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ @@ -238,7 +248,7 @@ uchar *dst; tErgDpram *dpram; int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ - + if (card->debug_flags & LOG_POF_CARD) hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); @@ -334,7 +344,6 @@ } /* while (nr_write) */ } /* while (len) */ - return (0); } /* ergo_writebootseq */ @@ -354,7 +363,6 @@ if (card->debug_flags & LOG_POF_CARD) hysdn_addlog(card, "ERGO: waiting for pof ready"); - while (timecnt--) { /* wait until timeout */ @@ -375,7 +383,6 @@ if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "ERGO: pof boot success"); - save_flags(flags); cli(); @@ -396,6 +403,11 @@ card->state = CARD_STATE_BOOTERR; return (i); } +#ifdef CONFIG_HYSDN_CAPI + if((i = hycapi_capi_create(card))) { + printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n"); + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* success */ } /* data has arrived */ sti(); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hycapi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hysdn/hycapi.c Tue Aug 22 09:06:31 2000 @@ -0,0 +1,859 @@ +/* $Id: hycapi.c,v 1.6 2000/07/25 08:07:42 ualbrecht Exp $ + * + * Linux driver for HYSDN cards, CAPI2.0-Interface. + * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH + * + * Copyright 2000 by Hypercope GmbH + * + * 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. + * + * $Log: hycapi.c,v $ + * Revision 1.6 2000/07/25 08:07:42 ualbrecht + * Fixed stupid re-registering bug resulting in system-freeze + * + * Revision 1.5 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.4 2000/06/13 09:13:06 ualbrecht + * Changed internal application handling: Registration is now deferred + * until a CAPI-message is actually sent to the controller (no good + * wasting memory on the card if it's never used anyways). + * Module will now unload more gracefully. + * + * Revision 1.2 2000/05/22 10:31:22 ualbrecht + * Parameter-checking for app-registration fixed + * + * Revision 1.1 2000/05/17 11:34:30 ualbrecht + * Initial release + * + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include + + +#define VER_DRIVER 0 +#define VER_CARDTYPE 1 +#define VER_HWID 2 +#define VER_SERIAL 3 +#define VER_OPTION 4 +#define VER_PROTO 5 +#define VER_PROFILE 6 +#define VER_CAPI 7 + +#include "hysdn_defs.h" +#include + +static char hycapi_revision[]="$Revision: 1.6 $"; + +typedef struct _hycapi_appl { + unsigned int ctrl_mask; + capi_register_params rp; + struct sk_buff *listen_req[CAPI_MAXCONTR]; +} hycapi_appl; + +static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; + +static inline int _hycapi_appCheck(int app_id, int ctrl_no) +{ + if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || + (app_id > CAPI_MAXAPPL)) + { + printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no); + return -1; + } + return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0); +} + +struct capi_driver_interface *hy_di = NULL; + +/****************************** +Kernel-Capi callback reset_ctr +******************************/ + +void +hycapi_reset_ctr(struct capi_ctr *ctrl) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); +#endif + ctrl->reseted(ctrl); +} + +/****************************** +Kernel-Capi callback remove_ctr +******************************/ + +void +hycapi_remove_ctr(struct capi_ctr *ctrl) +{ + int i; + hycapictrl_info *cinfo = NULL; + hysdn_card *card = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n"); +#endif + if(!hy_di) { + printk(KERN_ERR "No capi_driver_interface set!"); + return; + } + cinfo = (hycapictrl_info *)(ctrl->driverdata); + if(!cinfo) { + printk(KERN_ERR "No hycapictrl_info set!"); + return; + } + card = cinfo->card; + ctrl->suspend_output(ctrl); + for(i=0; icnr-1]) { + kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]); + hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL; + } + } + hy_di->detach_ctr(ctrl); + ctrl->driverdata = 0; + kfree(card->hyctrlinfo); + + + card->hyctrlinfo = NULL; +} + +/*********************************************************** + +Queue a CAPI-message to the controller. + +***********************************************************/ + +static void +hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + + spin_lock_irq(&cinfo->lock); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_send_message\n"); +#endif + cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */ + if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->in_idx = 0; /* wrap around */ + cinfo->sk_count++; /* adjust counter */ + if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) { + /* inform upper layers we're full */ + printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n", + card->myid); + ctrl->suspend_output(ctrl); + } + cinfo->tx_skb = skb; + spin_unlock_irq(&cinfo->lock); + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/*********************************************************** +hycapi_register_internal + +Send down the CAPI_REGISTER-Command to the controller. +This functions will also be used if the adapter has been rebooted to +re-register any applications in the private list. + +************************************************************/ + +static void +hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*"; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa0, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; + __u16 MessageBufferSize = 0; + int slen = strlen(ExtFeatureDefaults); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_register_appl\n"); +#endif + MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; + + len = CAPI_MSG_BASELEN + 8 + slen + 1; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16)); + memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen); + hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1)); + hycapi_send_message(ctrl, skb); +} + +/************************************************************ +hycapi_restart_internal + +After an adapter has been rebootet, re-register all applications and +send a LISTEN_REQ (if there has been such a thing ) + +*************************************************************/ + +static void hycapi_restart_internal(struct capi_ctr *ctrl) +{ + int i; + struct sk_buff *skb; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_WARNING "HYSDN: hycapi_restart_internal"); +#endif + for(i=0; icnr) == 1) { + hycapi_register_internal(ctrl, i+1, + &hycapi_applications[i].rp); + if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { + skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC); + hycapi_sendmsg_internal(ctrl, skb); + } + } + } +} + +/************************************************************* +Register an application. +Error-checking is done for CAPI-compliance. + +The application is recorded in the internal list. +*************************************************************/ + +void +hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk < 0) { + return; + } + if(chk == 1) { + printk(KERN_INFO "HYSDN: apl %d allready registered\n", appl); + return; + } + MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt; + rp->datablkcnt = MaxBDataBlocks; + MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ; + rp->datablklen = MaxBDataLen; + + MaxLogicalConnections = rp->level3cnt; + if (MaxLogicalConnections < 0) { + MaxLogicalConnections = card->bchans * -MaxLogicalConnections; + } + if (MaxLogicalConnections == 0) { + MaxLogicalConnections = card->bchans; + } + + rp->level3cnt = MaxLogicalConnections; + memcpy(&hycapi_applications[appl-1].rp, + rp, sizeof(capi_register_params)); + +/* MOD_INC_USE_COUNT; */ + ctrl->appl_registered(ctrl, appl); +} + +/********************************************************************* + +hycapi_release_internal + +Send down a CAPI_RELEASE to the controller. +*********************************************************************/ + +static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa1, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_release_appl\n"); +#endif + len = CAPI_MSG_BASELEN; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + hycapi_send_message(ctrl, skb); + hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1)); +} + +/****************************************************************** +hycapi_release_appl + +Release the application from the internal list an remove it's +registration at controller-level +******************************************************************/ + +void +hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + int chk; + + chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk<0) { + printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr); + return; + } + if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) { + kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL; + } + if(chk == 1) + { + hycapi_release_internal(ctrl, appl); + } + ctrl->appl_released(ctrl, appl); +/* MOD_DEC_USE_COUNT; */ +} + + +/************************************************************** +Kill a single controller. +**************************************************************/ + +int hycapi_capi_release(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_release\n"); +#endif + if(cinfo) { + ctrl = cinfo->capi_ctrl; + hycapi_remove_ctr(ctrl); + } + return 0; +} + +/************************************************************** +hycapi_capi_stop + +Stop CAPI-Output on a card. (e.g. during reboot) +***************************************************************/ + +int hycapi_capi_stop(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_stop\n"); +#endif + if(cinfo) { + if(cinfo->capi_ctrl) { + ctrl = cinfo->capi_ctrl; +/* ctrl->suspend_output(ctrl); */ + ctrl->reseted(ctrl); + + } else { + printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n"); + } + } + return 0; +} + +/*************************************************************** +hycapi_send_message + +Send a message to the controller. + +Messages are parsed for their Command/Subcommand-type, and appropriate +action's are performed. + +Note that we have to muck around with a 64Bit-DATA_REQ as there are +firmware-releases that do not check the MsgLen-Indication! + +***************************************************************/ + +void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + __u16 appl_id; + int _len, _len2; + __u8 msghead[64]; + + appl_id = CAPIMSG_APPID(skb->data); + switch(_hycapi_appCheck(appl_id, ctrl->cnr)) + { + case 0: +/* printk(KERN_INFO "Need to register\n"); */ + hycapi_register_internal(ctrl, + appl_id, + &(hycapi_applications[appl_id-1].rp)); + break; + case 1: + break; + default: + printk(KERN_ERR "HYCAPI: Controller mixup!\n"); + return; + } + switch(CAPIMSG_CMD(skb->data)) { + case CAPI_DISCONNECT_B3_RESP: + ctrl->free_ncci(ctrl, appl_id, + CAPIMSG_NCCI(skb->data)); + break; + case CAPI_DATA_B3_REQ: + _len = CAPIMSG_LEN(skb->data); + if (_len > 22) { + _len2 = _len - 22; + memcpy(msghead, skb->data, 22); + memcpy(skb->data + _len2, msghead, 22); + skb_pull(skb, _len2); + CAPIMSG_SETLEN(skb->data, 22); + } + break; + case CAPI_LISTEN_REQ: + if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]) + { + kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL; + } + if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC))) + { + printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n"); + } + break; + default: + break; + } + hycapi_sendmsg_internal(ctrl, skb); +} + +/********************************************************************* +hycapi_read_proc + +Informations provided in the /proc/capi-entries. + +*********************************************************************/ + +int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int len = 0; + char *s; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_read_proc\n"); +#endif + len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + + switch (card->brdtype) { + case BD_PCCARD: s = "HYSDN Hycard"; break; + case BD_ERGO: s = "HYSDN Ergo2"; break; + case BD_METRO: s = "HYSDN Metro4"; break; + case BD_CHAMP2: s = "HYSDN Champ2"; break; + case BD_PLEXUS: s = "HYSDN Plexus30"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/************************************************************** +hycapi_load_firmware + +This does NOT load any firmware, but the callback somehow is needed +on capi-interface registration. + +**************************************************************/ + +int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_load_firmware\n"); +#endif + return 0; +} + + +char *hycapi_procinfo(struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_proc_info\n"); +#endif + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d %s", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->iobase : 0x0, + cinfo->card ? cinfo->card->irq : 0, + hycapi_revision + ); + return cinfo->infobuf; +} + +/****************************************************************** +hycapi_rx_capipkt + +Recieve a capi-message. + +All B3_DATA_IND are converted to 64K-extension compatible format. +New nccis are created if neccessary. +*******************************************************************/ + +void +hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len) +{ + struct sk_buff *skb; + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; + __u16 ApplId; + __u16 MsgLen, info; + __u16 len2, CapiCmd; + __u32 CP64[2] = {0,0}; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_rx_capipkt\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n", + card->myid); + return; + } + ctrl = cinfo->capi_ctrl; + if(!ctrl) + { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n", + card->myid); + return; + } + if(len < CAPI_MSG_BASELEN) { + printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n", + card->myid, len); + return; + } + MsgLen = CAPIMSG_LEN(buf); + ApplId = CAPIMSG_APPID(buf); + CapiCmd = CAPIMSG_CMD(buf); + + if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) { + len2 = len + (30 - MsgLen); + if (!(skb = alloc_skb(len2, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, MsgLen), buf, MsgLen); + memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32)); + memcpy(skb_put(skb, len - MsgLen), buf + MsgLen, + len - MsgLen); + CAPIMSG_SETLEN(skb->data, 30); + } else { + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, len), buf, len); + } + switch(CAPIMSG_CMD(skb->data)) + { + case CAPI_CONNECT_B3_CONF: +/* Check info-field for error-indication: */ + info = CAPIMSG_U16(skb->data, 12); + switch(info) + { + case 0: + ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + + break; + case 0x0001: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current " + "protocol. NCPI ignored.\n", card->myid); + break; + case 0x2001: + printk(KERN_ERR "HYSDN Card%d: Message not supported in" + " current state\n", card->myid); + break; + case 0x2002: + printk(KERN_ERR "HYSDN Card%d: illegal PLCI\n", card->myid); + break; + case 0x2004: + printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid); + break; + case 0x3008: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", + card->myid); + break; + default: + printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", + card->myid, info); + break; + } + break; + case CAPI_CONNECT_B3_IND: + ctrl->new_ncci(ctrl, ApplId, + CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + break; + default: + break; + } + ctrl->handle_capimsg(ctrl, ApplId, skb); +} + +/****************************************************************** +hycapi_tx_capiack + +Internally acknowledge a msg sent. This will remove the msg from the +internal queue. + +*******************************************************************/ + +void hycapi_tx_capiack(hysdn_card * card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_tx_capiack\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n", + card->myid); + return; + } + spin_lock_irq(&cinfo->lock); + kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */ + cinfo->skbs[cinfo->out_idx++] = NULL; + if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->out_idx = 0; /* wrap around */ + + if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */ + cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl); + spin_unlock_irq(&cinfo->lock); +} + +/*************************************************************** +hycapi_tx_capiget(hysdn_card *card) + +This is called when polling for messages to SEND. + +****************************************************************/ + +struct sk_buff * +hycapi_tx_capiget(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n", + card->myid); + return (struct sk_buff *)NULL; + } + if (!cinfo->sk_count) + return (struct sk_buff *)NULL; /* nothing available */ + + return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */ +} + + +static struct capi_driver hycapi_driver = { + "hysdn", + "0.0", + hycapi_load_firmware, + hycapi_reset_ctr, + hycapi_remove_ctr, + hycapi_register_appl, + hycapi_release_appl, + hycapi_send_message, + hycapi_procinfo, + hycapi_read_proc, + 0, /* use standard driver_read_proc */ + 0, /* no add_card function */ +}; + + +/********************************************************** +int hycapi_init() + +attach the capi-driver to the kernel-capi. + +***********************************************************/ + +int hycapi_init() +{ + struct capi_driver *driver; + int i; + if(hy_di) { + printk(KERN_NOTICE "HyDI allready set\n"); + return 0; + } + driver = &hycapi_driver; + printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n"); + hy_di = attach_capi_driver(driver); + if (!hy_di) { + printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n"); + return(-1); + } + for(i=0;ihyctrlinfo; + if(!cinfo) return; + ctrl = cinfo->capi_ctrl; + if(!ctrl) return; + strcpy(ctrl->manu, "Hypercope"); + ctrl->version.majorversion = 2; + ctrl->version.minorversion = 0; + ctrl->version.majormanuversion = 3; + ctrl->version.minormanuversion = 2; + ctrl->profile.ncontroller = card->myid; + ctrl->profile.nbchannel = card->bchans; + ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER | + GLOBAL_OPTION_B_CHANNEL_OPERATION; + ctrl->profile.support1 = B1_PROT_64KBIT_HDLC | + (card->faxchans ? B1_PROT_T30 : 0) | + B1_PROT_64KBIT_TRANSPARENT; + ctrl->profile.support2 = B2_PROT_ISO7776 | + (card->faxchans ? B2_PROT_T30 : 0) | + B2_PROT_TRANSPARENT; + ctrl->profile.support3 = B3_PROT_TRANSPARENT | + B3_PROT_T90NL | + (card->faxchans ? B3_PROT_T30 : 0) | + (card->faxchans ? B3_PROT_T30EXT : 0) | + B3_PROT_ISO8208; +} + +int +hycapi_capi_create(hysdn_card *card) +{ + hycapictrl_info *cinfo = NULL; + struct capi_ctr *ctrl = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_create\n"); +#endif + if (!card->hyctrlinfo) { + cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n"); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(hycapictrl_info)); + card->hyctrlinfo = cinfo; + cinfo->card = card; + spin_lock_init(&cinfo->lock); + + switch (card->brdtype) { + case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break; + case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break; + case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break; + case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break; + case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break; + default: strcpy(cinfo->cardname,"HYSDN ???"); break; + } + + cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver, + cinfo->cardname, cinfo); + ctrl = cinfo->capi_ctrl; + if (!ctrl) { + printk(KERN_ERR "%s: attach controller failed.\n", + hycapi_driver.name); + return -EBUSY; + } + /* fill in the blanks: */ + hycapi_fill_profile(card); + ctrl->ready(ctrl); + } else { + /* resume output on stopped ctrl */ + ctrl = card->hyctrlinfo->capi_ctrl; + if(ctrl) { + hycapi_fill_profile(card); + ctrl->ready(ctrl); + hycapi_restart_internal(ctrl); +/* ctrl->resume_output(ctrl); */ + } else { + printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n"); + } + } + return 0; +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_boot.c linux/drivers/isdn/hysdn/hysdn_boot.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_boot.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_boot.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_boot.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, specific routines for booting and pof handling. * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_boot.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -260,7 +266,6 @@ } if ((boot->last_error = pof_handle_data(card, datlen)) < 0) return (boot->last_error); /* an error occured */ - boot->pof_recoffset += datlen; if (boot->pof_recoffset >= boot->pof_reclen) { boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_defs.h linux/drivers/isdn/hysdn/hysdn_defs.h --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_defs.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_defs.h Tue Aug 22 09:06:31 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $ +/* $Id: hysdn_defs.h,v 1.3 2000/06/13 09:14:26 ualbrecht Exp $ * Linux driver for HYSDN cards, global definitions and exported vars and functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_defs.h,v $ + * Revision 1.3 2000/06/13 09:14:26 ualbrecht + * Removed obsolete struct for CAPI-application tracking. + * + * Revision 1.2 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * * Revision 1.1 2000/02/10 19:44:30 werner * * Initial release @@ -27,6 +33,10 @@ * */ +#ifndef HYSDN_DEFS_H +#define HYSDN_DEFS_H + +#include #include #include #include @@ -42,6 +52,54 @@ #include "ince1pc.h" +#ifdef CONFIG_HYSDN_CAPI +#include +#include "../avmb1/capicmd.h" +#include "../avmb1/capiutil.h" +#include "../avmb1/capilli.h" + +/***************************/ +/* CAPI-Profile values. */ +/***************************/ + +#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001 +#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002 +#define GLOBAL_OPTION_HANDSET 0x0004 +#define GLOBAL_OPTION_DTMF 0x0008 +#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010 +#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020 +#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040 + +#define B1_PROT_64KBIT_HDLC 0x0001 +#define B1_PROT_64KBIT_TRANSPARENT 0x0002 +#define B1_PROT_V110_ASYNCH 0x0004 +#define B1_PROT_V110_SYNCH 0x0008 +#define B1_PROT_T30 0x0010 +#define B1_PROT_64KBIT_INV_HDLC 0x0020 +#define B1_PROT_56KBIT_TRANSPARENT 0x0040 + +#define B2_PROT_ISO7776 0x0001 +#define B2_PROT_TRANSPARENT 0x0002 +#define B2_PROT_SDLC 0x0004 +#define B2_PROT_LAPD 0x0008 +#define B2_PROT_T30 0x0010 +#define B2_PROT_PPP 0x0020 +#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040 + +#define B3_PROT_TRANSPARENT 0x0001 +#define B3_PROT_T90NL 0x0002 +#define B3_PROT_ISO8208 0x0004 +#define B3_PROT_X25_DCE 0x0008 +#define B3_PROT_T30 0x0010 +#define B3_PROT_T30EXT 0x0020 + +#define HYSDN_MAXVERSION 8 + +/* Number of sendbuffers in CAPI-queue */ +#define HYSDN_MAX_CAPI_SKB 20 + +#endif /* CONFIG_HYSDN_CAPI*/ + /************************************************/ /* constants and bits for debugging/log outputs */ /************************************************/ @@ -176,8 +234,30 @@ /* init and deinit stopcard for booting, too */ void (*stopcard) (struct HYSDN_CARD *); void (*releasehardware) (struct HYSDN_CARD *); +#ifdef CONFIG_HYSDN_CAPI + struct hycapictrl_info { + char cardname[32]; + spinlock_t lock; + int versionlen; + char versionbuf[1024]; + char *version[HYSDN_MAXVERSION]; + + char infobuf[128]; /* for function procinfo */ + + struct HYSDN_CARD *card; + struct capi_ctr *capi_ctrl; + struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB]; + int in_idx, out_idx; /* indexes to buffer ring */ + int sk_count; /* number of buffers currently in ring */ + struct sk_buff *tx_skb; /* buffer for tx operation */ + } *hyctrlinfo; +#endif /* CONFIG_HYSDN_CAPI */ } hysdn_card; +#ifdef CONFIG_HYSDN_CAPI +typedef struct hycapictrl_info hycapictrl_info; +#endif /* CONFIG_HYSDN_CAPI */ + /*****************/ /* exported vars */ @@ -227,3 +307,27 @@ extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ + +#ifdef CONFIG_HYSDN_CAPI +extern struct capi_driver_interface *hy_di; +extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ +extern int hycapi_capi_release(hysdn_card *); /* delete the device */ +extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ +extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); +extern void hycapi_reset_ctr(struct capi_ctr *); +extern void hycapi_remove_ctr(struct capi_ctr *); +extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, + capi_register_params *); +extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); +extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); +extern char *hycapi_procinfo(struct capi_ctr *); +extern int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *card); +extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); +extern void hycapi_tx_capiack(hysdn_card * card); +extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); +extern int hycapi_init(void); +extern void hycapi_cleanup(void); +#endif /* CONFIG_HYSDN_CAPI */ + +#endif /* HYSDN_DEFS_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_init.c linux/drivers/isdn/hysdn/hysdn_init.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_init.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/isdn/hysdn/hysdn_init.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_init.c,v 1.5 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, init functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_init.c,v $ + * Revision 1.5 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.4 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.3 2000/06/13 09:15:07 ualbrecht + * Module will now unload more gracefully. + * + * Revision 1.2 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -37,7 +49,7 @@ #include "hysdn_defs.h" -static char *hysdn_init_revision = "$Revision: 1.1 $"; +static char *hysdn_init_revision = "$Revision: 1.5 $"; int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ @@ -77,7 +89,6 @@ { struct pci_dev *akt_pcidev = NULL; hysdn_card *card, *card_last; - uchar irq; int i; card_root = NULL; @@ -218,6 +229,14 @@ free_resources(); /* proc file_sys not created */ return (-1); } +#ifdef CONFIG_HYSDN_CAPI + if(cardmax > 0) { + if(hycapi_init()) { + printk(KERN_ERR "HYCAPI: init failed\n"); + return(-1); + } + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* no error */ } /* init_module */ @@ -233,8 +252,18 @@ void cleanup_module(void) { - +#ifdef CONFIG_HYSDN_CAPI + hysdn_card *card; +#endif /* CONFIG_HYSDN_CAPI */ stop_cards(); +#ifdef CONFIG_HYSDN_CAPI + card = card_root; /* first in chain */ + while (card) { + hycapi_capi_release(card); + card = card->next; /* remove card from chain */ + } /* while card */ + hycapi_cleanup(); +#endif /* CONFIG_HYSDN_CAPI */ hysdn_procconf_release(); free_resources(); printk(KERN_NOTICE "HYSDN: module unloaded\n"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_net.c Thu May 11 15:30:07 2000 +++ linux/drivers/isdn/hysdn/hysdn_net.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $ +/* $Id: hysdn_net.c,v 1.7 2000/05/23 06:48:54 ualbrecht Exp $ * Linux driver for HYSDN cards, net (ethernet type) handling routines. * @@ -24,6 +24,19 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_net.c,v $ + * Revision 1.7 2000/05/23 06:48:54 ualbrecht + * Reverted last change in dev->name assignment (broken netdevice.h in 2.3.99pre6?) + * + * Revision 1.6 2000/05/17 11:43:03 ualbrecht + * Fixed a NULL-pointer kernel-oops assigning the device-name + * + * Revision 1.5 2000/05/06 00:52:38 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.4 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.3 2000/02/14 19:24:12 werner * * Removed superflous file @@ -52,7 +65,7 @@ #include "hysdn_defs.h" /* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.3 $"; +char *hysdn_net_revision = "$Revision: 1.7 $"; #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ @@ -308,7 +321,10 @@ { struct net_device *dev; int i; - + if(!card) { + printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); + return (-ENOMEM); + } hysdn_net_release(card); /* release an existing net device */ if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); @@ -323,6 +339,9 @@ dev->base_addr = card->iobase; /* IO address */ dev->irq = card->irq; /* irq */ dev->init = net_init; /* the init function of the device */ + if(dev->name) { + strcpy(dev->name, ((struct net_local *) dev)->dev_name); + } if ((i = register_netdev(dev))) { printk(KERN_WARNING "HYSDN: unable to create network device\n"); kfree(dev); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_procconf.c Fri Jul 14 12:12:10 2000 +++ linux/drivers/isdn/hysdn/hysdn_procconf.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $ +/* $Id: hysdn_procconf.c,v 1.7 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_procconf.c,v $ + * Revision 1.7 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.6 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.5 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.4 2000/03/03 16:37:12 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -49,7 +58,7 @@ #include "hysdn_defs.h" -static char *hysdn_procconf_revision = "$Revision: 1.4 $"; +static char *hysdn_procconf_revision = "$Revision: 1.7 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ @@ -335,7 +344,7 @@ *cp++ = '\n'; /* and now the data */ - sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s", + sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s", card->myid, card->bus, PCI_SLOT(card->devfn), diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_proclog.c linux/drivers/isdn/hysdn/hysdn_proclog.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_proclog.c Fri Jul 14 12:12:10 2000 +++ linux/drivers/isdn/hysdn/hysdn_proclog.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $ +/* $Id: hysdn_proclog.c,v 1.7 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem log functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_proclog.c,v $ + * Revision 1.7 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.6 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.5 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.4 2000/03/03 16:37:12 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -49,8 +58,6 @@ #include "hysdn_defs.h" -static char *hysdn_proclog_revision = "$Revision: 1.4 $"; - /* the proc subdir for the interface is defined in the procconf module */ extern struct proc_dir_entry *hysdn_proc_entry; @@ -456,7 +463,7 @@ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { pd->log->proc_fops = &log_fops; - pd->log->owner = THIS_MODULE; + pd->log->owner = THIS_MODULE; } init_waitqueue_head(&(pd->rd_queue)); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c --- v2.4.0-test6/linux/drivers/isdn/hysdn/hysdn_sched.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_sched.c Tue Aug 22 09:06:31 2000 @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_sched.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_sched.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -29,6 +35,7 @@ */ #define __NO_VERSION__ +#include #include #include #include @@ -60,7 +67,12 @@ if (card->err_log_state == ERRLOG_STATE_ON) card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ break; - +#ifdef CONFIG_HYSDN_CAPI + case CHAN_CAPI: +/* give packet to CAPI handler */ + hycapi_rx_capipkt(card, buf, len); + break; +#endif /* CONFIG_HYSDN_CAPI */ default: printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); break; @@ -125,6 +137,17 @@ } else hysdn_tx_netack(card); /* aknowledge packet -> throw away */ } /* send a network packet if available */ +#ifdef CONFIG_HYSDN_CAPI + if((skb = hycapi_tx_capiget(card)) != NULL) { + if (skb->len <= maxlen) { + memcpy(buf, skb->data, skb->len); + *len = skb->len; + *chan = CHAN_CAPI; + hycapi_tx_capiack(card); + return (1); /* go and send the data */ + } + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* nothing to send */ } /* hysdn_sched_tx */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/hysdn/ince1pc.h linux/drivers/isdn/hysdn/ince1pc.h --- v2.4.0-test6/linux/drivers/isdn/hysdn/ince1pc.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/ince1pc.h Mon Aug 21 07:49:03 2000 @@ -1,132 +1,132 @@ -#ifndef __INCE1PC_H__ -#define __INCE1PC_H__ - -/**************************************************************************** - - FILE: ince1pc.h - - AUTHOR: M.Steinkopf - - PURPOSE: common definitions for both sides of the bus: - - conventions both spoolers must know - - channel numbers agreed upon - -*****************************************************************************/ - -/* basic scalar definitions have same meanning, - * but their declaration location depends on environment - */ - -/*--------------------------------------channel numbers---------------------*/ -#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ -#define CHAN_ERRLOG 0x0005 /* error logger */ -#define CHAN_CAPI 0x0064 /* CAPI interface */ -#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ - -/*--------------------------------------POF ready msg-----------------------*/ - /* NOTE: after booting POF sends system ready message to PC: */ -#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ -#define RDY_MAGIC_SIZE 4 /* size in bytes */ - -#define MAX_N_TOK_BYTES 255 - -#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE -#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) - -#define SYSR_TOK_END 0 -#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ -#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ -#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ -#define SYSR_TOK_ESC 255 /* undefined data size yet */ - /* default values, if not corrected by token: */ -#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ -#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ - -/* syntax of new SYSR token stream: - * channel: CHAN_SYSTEM - * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE - * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) - * msg : 0 1 2 3 {4 5 6 ..} - * S Y S R MAX_N_TOK_BYTES bytes of TokenStream - * - * TokenStream := empty - * | {NonEndTokenChunk} EndToken RotlCRC - * NonEndTokenChunk:= NonEndTokenId DataLen [Data] - * NonEndTokenId := 0x01 .. 0xFE 1 BYTE - * DataLen := 0x00 .. 0xFF 1 BYTE - * Data := DataLen bytes - * EndToken := 0x00 - * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes - * s. RotlCRC algorithm - * - * RotlCRC algorithm: - * ucSum= 0 1 uchar - * for all NonEndTokenChunk bytes: - * ROTL(ucSum,1) rotate left by 1 - * ucSum += Char; add current byte with swap around - * RotlCRC= ~ucSum; invert all bits for result - * - * note: - * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! - */ - -/*--------------------------------------error logger------------------------*/ - /* note: pof needs final 0 ! */ -#define ERRLOG_CMD_REQ "ERRLOG ON" -#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ -#define ERRLOG_CMD_STOP "ERRLOG OFF" -#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ - -#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ - /* remaining text size = 55 */ -#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) - +#ifndef __INCE1PC_H__ +#define __INCE1PC_H__ + +/**************************************************************************** + + FILE: ince1pc.h + + AUTHOR: M.Steinkopf + + PURPOSE: common definitions for both sides of the bus: + - conventions both spoolers must know + - channel numbers agreed upon + +*****************************************************************************/ + +/* basic scalar definitions have same meanning, + * but their declaration location depends on environment + */ + +/*--------------------------------------channel numbers---------------------*/ +#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ +#define CHAN_ERRLOG 0x0005 /* error logger */ +#define CHAN_CAPI 0x0064 /* CAPI interface */ +#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ + +/*--------------------------------------POF ready msg-----------------------*/ + /* NOTE: after booting POF sends system ready message to PC: */ +#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ +#define RDY_MAGIC_SIZE 4 /* size in bytes */ + +#define MAX_N_TOK_BYTES 255 + +#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE +#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + +#define SYSR_TOK_END 0 +#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ +#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ +#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ +#define SYSR_TOK_ESC 255 /* undefined data size yet */ + /* default values, if not corrected by token: */ +#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ +#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ + +/* syntax of new SYSR token stream: + * channel: CHAN_SYSTEM + * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE + * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + * msg : 0 1 2 3 {4 5 6 ..} + * S Y S R MAX_N_TOK_BYTES bytes of TokenStream + * + * TokenStream := empty + * | {NonEndTokenChunk} EndToken RotlCRC + * NonEndTokenChunk:= NonEndTokenId DataLen [Data] + * NonEndTokenId := 0x01 .. 0xFE 1 BYTE + * DataLen := 0x00 .. 0xFF 1 BYTE + * Data := DataLen bytes + * EndToken := 0x00 + * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes + * s. RotlCRC algorithm + * + * RotlCRC algorithm: + * ucSum= 0 1 uchar + * for all NonEndTokenChunk bytes: + * ROTL(ucSum,1) rotate left by 1 + * ucSum += Char; add current byte with swap around + * RotlCRC= ~ucSum; invert all bits for result + * + * note: + * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! + */ + +/*--------------------------------------error logger------------------------*/ + /* note: pof needs final 0 ! */ +#define ERRLOG_CMD_REQ "ERRLOG ON" +#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ +#define ERRLOG_CMD_STOP "ERRLOG OFF" +#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ + +#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ + /* remaining text size = 55 */ +#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) + typedef struct ErrLogEntry_tag { - + /*00 */ ulong ulErrType; - + /*04 */ ulong ulErrSubtype; - + /*08 */ uchar ucTextSize; - + /*09 */ uchar ucText[ERRLOG_TEXT_SIZE]; /* ASCIIZ of len ucTextSize-1 */ - -/*40 */ + +/*40 */ } tErrLogEntry; - -#if defined(__TURBOC__) -#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE -#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE -#endif /* */ -#endif /* */ - -/*--------------------------------------DPRAM boot spooler------------------*/ - /* this is the struture used between pc and - * hyperstone to exchange boot data - */ -#define DPRAM_SPOOLER_DATA_SIZE 0x20 + +#if defined(__TURBOC__) +#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE +#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE +#endif /* */ +#endif /* */ + +/*--------------------------------------DPRAM boot spooler------------------*/ + /* this is the struture used between pc and + * hyperstone to exchange boot data + */ +#define DPRAM_SPOOLER_DATA_SIZE 0x20 typedef struct DpramBootSpooler_tag { - + /*00 */ uchar Len; - + /*01 */ volatile uchar RdPtr; - + /*02 */ uchar WrPtr; - + /*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE]; - -/*23 */ + +/*23 */ } tDpramBootSpooler; - -#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ -#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ - -/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ - /* at DPRAM offset 0x1C00: */ -#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ - - -#endif /* __INCE1PC_H__ */ + +#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ +#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ + +/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ + /* at DPRAM offset 0x1C00: */ +#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ + + +#endif /* __INCE1PC_H__ */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.4.0-test6/linux/drivers/isdn/icn/icn.c Thu May 11 15:30:07 2000 +++ linux/drivers/isdn/icn/icn.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.62 1999/09/06 07:29:35 fritz Exp $ +/* $Id: icn.c,v 1.63 2000/05/06 00:52:39 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.63 2000/05/06 00:52:39 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * * Revision 1.62 1999/09/06 07:29:35 fritz * Changed my mail-address. * @@ -247,7 +251,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.62 $"; +*revision = "$Revision: 1.63 $"; static int icn_addcard(int, char *, char *); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.4.0-test6/linux/drivers/isdn/isdn_common.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/isdn_common.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.108 2000/06/24 15:52:47 keil Exp $ +/* $Id: isdn_common.c,v 1.111 2000/08/20 07:40:14 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -48,7 +48,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.108 $"; +static char *isdn_revision = "$Revision: 1.111 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1660,6 +1660,8 @@ uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; + int retval = -ENODEV; + if (minor == ISDN_MINOR_STATUS) { infostruct *p; @@ -1670,41 +1672,47 @@ dev->infochain = p; /* At opening we allow a single update */ filep->private_data = (char *) 1; - return 0; - } else - return -ENOMEM; + retval = 0; + goto out; + } else { + retval = -ENOMEM; + goto out; + } } if (!dev->channels) - return -ENODEV; + goto out; if (minor < ISDN_MINOR_CTRL) { printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) - return -ENODEV; + goto out; chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + goto out; if (!(dev->drv[drvidx]->online & (1 << chidx))) - return -ENODEV; + goto out; isdn_lock_drivers(); - return 0; + retval = 0; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) - return -ENODEV; + goto out; isdn_lock_drivers(); - return 0; + retval = 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { - int ret; - if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) + retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); + if (retval == 0) isdn_lock_drivers(); - return ret; + goto out; } #endif - return -ENODEV; + out: + return retval; } static int @@ -1724,31 +1732,28 @@ else dev->infochain = (infostruct *) (p->next); kfree(p); - unlock_kernel(); - return 0; + goto out; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - unlock_kernel(); - return 0; + goto out; } isdn_unlock_drivers(); - if (minor < ISDN_MINOR_CTRL) { - unlock_kernel(); - return 0; - } + if (minor < ISDN_MINOR_CTRL) + goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) dev->profd = NULL; - unlock_kernel(); - return 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); #endif + + out: unlock_kernel(); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.4.0-test6/linux/drivers/isdn/isdn_net.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/isdn_net.c Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.134 2000/06/21 09:54:29 keil Exp $ +/* $Id: isdn_net.c,v 1.135 2000/08/10 22:52:46 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -181,7 +181,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -char *isdn_net_revision = "$Revision: 1.134 $"; +char *isdn_net_revision = "$Revision: 1.135 $"; /* * Code for raw-networking over ISDN diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- v2.4.0-test6/linux/drivers/isdn/isdn_ppp.h Wed Aug 9 19:19:50 2000 +++ linux/drivers/isdn/isdn_ppp.h Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.16 2000/05/18 23:14:18 keil Exp $ +/* $Id: isdn_ppp.h,v 1.17 2000/08/10 22:52:46 kai Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c --- v2.4.0-test6/linux/drivers/isdn/pcbit/capi.c Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/pcbit/capi.c Mon Aug 21 07:49:03 2000 @@ -304,7 +304,14 @@ data_len = skb->len; - skb_push(skb, 10); + if(skb_headroom(skb) < 10) + { + printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb); + } + else + { + skb_push(skb, 10); + } *((u16 *) (skb->data)) = chan->callref; skb->data[2] = chan->layer2link; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.4.0-test6/linux/drivers/isdn/pcbit/drv.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/isdn/pcbit/drv.c Mon Aug 21 07:49:03 2000 @@ -162,7 +162,7 @@ dev->send_seq = 0; dev->unack_seq = 0; - dev->hl_hdrlen = 10; + dev->hl_hdrlen = 16; dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL); @@ -186,7 +186,7 @@ ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS ); dev_if->writebuf_skb = pcbit_xmit; - dev_if->hl_hdrlen = 10; + dev_if->hl_hdrlen = 16; dev_if->maxbufsize = MAXBUFSIZE; dev_if->command = pcbit_command; @@ -518,9 +518,6 @@ struct callb_data cbdata; int complete, err; isdn_ctrl ictl; -#ifdef DEBUG - struct msg_fmt * fmsg; -#endif switch(msg) { @@ -734,9 +731,6 @@ default: printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n", msg); - fmsg = (struct msg_fmt *) &msg; - printk(KERN_DEBUG "cmd=%02x sub=%02x\n", - fmsg->cmd, fmsg->scmd); break; #endif } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c --- v2.4.0-test6/linux/drivers/isdn/pcbit/layer2.c Thu Nov 11 20:11:39 1999 +++ linux/drivers/isdn/pcbit/layer2.c Mon Aug 21 07:49:03 2000 @@ -8,6 +8,11 @@ */ /* + * 19991203 - Fernando Carvalho - takion@superbofh.org + * Hacked to compile with egcs and run with current version of isdn modules +*/ + +/* * PCBIT-D low-layer interface */ @@ -205,7 +210,7 @@ /* Type 0 frame */ - struct msg_fmt *msg; + ulong msg; if (frame->skb) totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; @@ -214,7 +219,7 @@ flen = MIN(totlen, free); - msg = (struct msg_fmt *) &(frame->msg); + msg = frame->msg; /* * Board level 2 header @@ -222,9 +227,9 @@ pcbit_writew(dev, flen - FRAME_HDR_LEN); - pcbit_writeb(dev, msg->cpu); + pcbit_writeb(dev, GET_MSG_CPU(msg)); - pcbit_writeb(dev, msg->proc); + pcbit_writeb(dev, GET_MSG_PROC(msg)); /* TH */ pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); @@ -244,8 +249,8 @@ pcbit_writew(dev, 0); /* C + S */ - pcbit_writeb(dev, msg->cmd); - pcbit_writeb(dev, msg->scmd); + pcbit_writeb(dev, GET_MSG_CMD(msg)); + pcbit_writeb(dev, GET_MSG_SCMD(msg)); /* NUM */ pcbit_writew(dev, frame->refnum); @@ -312,8 +317,7 @@ pcbit_deliver(void *data) { struct frame_buf *frame; - unsigned long flags; - struct msg_fmt msg; + unsigned long flags, msg; struct pcbit_dev *dev = (struct pcbit_dev *) data; save_flags(flags); @@ -323,10 +327,10 @@ dev->read_queue = frame->next; restore_flags(flags); - msg.cpu = 0; - msg.proc = 0; - msg.cmd = frame->skb->data[2]; - msg.scmd = frame->skb->data[3]; + SET_MSG_CPU(msg, 0); + SET_MSG_PROC(msg, 0); + SET_MSG_CMD(msg, frame->skb->data[2]); + SET_MSG_SCMD(msg, frame->skb->data[3]); frame->refnum = *((ushort *) frame->skb->data + 4); frame->msg = *((ulong *) & msg); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/pcbit/layer2.h linux/drivers/isdn/pcbit/layer2.h --- v2.4.0-test6/linux/drivers/isdn/pcbit/layer2.h Mon Nov 3 10:09:13 1997 +++ linux/drivers/isdn/pcbit/layer2.h Mon Aug 21 07:49:03 2000 @@ -7,6 +7,11 @@ * the GNU Public License, incorporated herein by reference. */ +/* + * 19991203 - Fernando Carvalho - takion@superbofh.org + * Hacked to compile with egcs and run with current version of isdn modules +*/ + /* * PCBIT-D low-layer interface definitions */ @@ -84,21 +89,20 @@ Intel 1 2 3 4 */ -struct msg_fmt { -#ifdef __LITTLE_ENDIAN /* Little Endian */ - u_char scmd; - u_char cmd; - u_char proc; - u_char cpu; +#ifdef __LITTLE_ENDIAN +#define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff))) +#define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8)) +#define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16)) +#define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24)) + +#define GET_MSG_SCMD(msg) ((msg) & 0xFF) +#define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF) +#define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF) +#define GET_MSG_CPU(msg) ((msg) >> 24) + #else #error "Non-Intel CPU" - u_char cpu; - u_char proc; - u_char cmd; - u_char scmd; #endif -}; - #define MAX_QUEUED 7 @@ -107,14 +111,13 @@ #define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */ - struct frame_buf { ulong msg; - unsigned short refnum; - unsigned short dt_len; - unsigned short hdr_len; + unsigned int refnum; + unsigned int dt_len; + unsigned int hdr_len; struct sk_buff *skb; - unsigned short copied; + unsigned int copied; struct frame_buf * next; }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v2.4.0-test6/linux/drivers/isdn/pcbit/module.c Thu Nov 11 20:11:39 1999 +++ linux/drivers/isdn/pcbit/module.c Mon Aug 21 07:49:03 2000 @@ -46,8 +46,8 @@ num_boards = 0; - printk(KERN_INFO - "PCBIT-D device driver v 0.5 - " + printk(KERN_NOTICE + "PCBIT-D device driver v 0.5-fjpc0 19991204 - " "Copyright (C) 1996 Universidade de Lisboa\n"); if (mem[0] || irq[0]) @@ -97,7 +97,7 @@ for (board = 0; board < num_boards; board++) pcbit_terminate(board); - printk(KERN_INFO + printk(KERN_NOTICE "PCBIT-D module unloaded\n"); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/isdn/sc/timer.c linux/drivers/isdn/sc/timer.c --- v2.4.0-test6/linux/drivers/isdn/sc/timer.c Thu May 11 15:30:07 2000 +++ linux/drivers/isdn/sc/timer.c Mon Aug 21 07:49:03 2000 @@ -1,5 +1,5 @@ /* - * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $ + * $Id: timer.c,v 1.3 2000/05/06 00:52:39 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/Config.in linux/drivers/media/Config.in --- v2.4.0-test6/linux/drivers/media/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/Config.in Wed Aug 23 14:59:55 2000 @@ -0,0 +1,13 @@ +# +# Multimedia device configuration +# +mainmenu_option next_comment +comment 'Multimedia devices' + +tristate 'Video For Linux' CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + source drivers/media/video/Config.in + source drivers/media/radio/Config.in +fi + +endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/Makefile linux/drivers/media/Makefile --- v2.4.0-test6/linux/drivers/media/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/Makefile Tue Aug 22 11:29:02 2000 @@ -0,0 +1,21 @@ +# +# Makefile for the kernel multimedia device 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.. +# + +MEDIAS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o)) + +SUB_DIRS := video radio +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := media.o +O_OBJS := $(MEDIAS) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in --- v2.4.0-test6/linux/drivers/media/radio/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/Config.in Wed Aug 23 14:59:55 2000 @@ -0,0 +1,52 @@ +# +# Multimedia Video device configuration +# +mainmenu_option next_comment +comment 'Radio Adapters' + +dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV +dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then + hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f +fi +dep_tristate ' AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then + hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c +fi +dep_tristate ' Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then + hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 +fi +dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then + hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c +fi +dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV +dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then + hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 +fi +dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then + hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 +fi +dep_tristate ' Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_TRUST" = "y" ]; then + hex ' Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350 +fi +dep_tristate ' Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV +if [ "$CONFIG_PROC_FS" = "y" ]; then + if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then + bool ' Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS + fi +fi +if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then + hex ' Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316 + int ' Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500 +fi +dep_tristate ' Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV +if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then + hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c +fi + +endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile --- v2.4.0-test6/linux/drivers/media/radio/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/Makefile Tue Aug 22 11:29:02 2000 @@ -0,0 +1,75 @@ +# +# Makefile for the kernel character device 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.. +# + +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := radio.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := + +list-multi := + +obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o +obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o +obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o +obj-$(CONFIG_RADIO_CADET) += radio-cadet.o +obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o +obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o +obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o +obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o +obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o +obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o +obj-$(CONFIG_RADIO_TRUST) += radio-trust.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-aimslab.c linux/drivers/media/radio/radio-aimslab.c --- v2.4.0-test6/linux/drivers/media/radio/radio-aimslab.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-aimslab.c Mon Jun 19 13:25:06 2000 @@ -0,0 +1,390 @@ +/* radiotrack (radioreveal) driver for Linux radio support + * (c) 1997 M. Kirkwood + * Coverted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Frequency range expanded to start at 87 MHz + * + * TODO: Allow for more than one of these foolish entities :-) + * + * Notes on the hardware (reverse engineered from other peoples' + * reverse engineering of AIMS' code :-) + * + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * + * The signal strength query is unsurprisingly inaccurate. And it seems + * to indicate that (on my card, at least) the frequency setting isn't + * too great. (I have to tune up .025MHz from what the freq should be + * to get a report that the thing is tuned.) + * + * Volume control is (ugh) analogue: + * out(port, start_increasing_volume); + * wait(a_wee_while); + * out(port, stop_changing_the_volume); + * + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_RTRACK_PORT */ +#include /* Lock for the I/O */ + +#ifndef CONFIG_RADIO_RTRACK_PORT +#define CONFIG_RADIO_RTRACK_PORT -1 +#endif + +static int io = CONFIG_RADIO_RTRACK_PORT; +static int users = 0; +static struct semaphore lock; + +struct rt_device +{ + int port; + int curvol; + unsigned long curfreq; + int muted; +}; + + +/* local things */ + +static void sleep_delay(long n) +{ + /* Sleep nicely for 'n' uS */ + int d=n/(1000000/HZ); + if(!d) + udelay(n); + else + { + /* Yield CPU time */ + unsigned long x=jiffies; + while((jiffies-x)<=d) + schedule(); + } +} + +static void rt_decvol(void) +{ + outb(0x58, io); /* volume down + sigstr + on */ + sleep_delay(100000); + outb(0xd8, io); /* volume steady + sigstr + on */ +} + +static void rt_incvol(void) +{ + outb(0x98, io); /* volume up + sigstr + on */ + sleep_delay(100000); + outb(0xd8, io); /* volume steady + sigstr + on */ +} + +static void rt_mute(struct rt_device *dev) +{ + dev->muted = 1; + down(&lock); + outb(0xd0, io); /* volume steady, off */ + up(&lock); +} + +static int rt_setvol(struct rt_device *dev, int vol) +{ + int i; + + down(&lock); + + if(vol == dev->curvol) { /* requested volume = current */ + if (dev->muted) { /* user is unmuting the card */ + dev->muted = 0; + outb (0xd8, io); /* enable card */ + } + up(&lock); + return 0; + } + + if(vol == 0) { /* volume = 0 means mute the card */ + outb(0x48, io); /* volume down but still "on" */ + sleep_delay(2000000); /* make sure it's totally down */ + outb(0xd0, io); /* volume steady, off */ + dev->curvol = 0; /* track the volume state! */ + up(&lock); + return 0; + } + + dev->muted = 0; + if(vol > dev->curvol) + for(i = dev->curvol; i < vol; i++) + rt_incvol(); + else + for(i = dev->curvol; i > vol; i--) + rt_decvol(); + + dev->curvol = vol; + up(&lock); + return 0; +} + +/* the 128+64 on these outb's is to keep the volume stable while tuning + * without them, the volume _will_ creep up with each frequency change + * and bit 4 (+16) is to keep the signal strength meter enabled + */ + +void send_0_byte(int port, struct rt_device *dev) +{ + if ((dev->curvol == 0) || (dev->muted)) { + outb_p(128+64+16+ 1, port); /* wr-enable + data low */ + outb_p(128+64+16+2+1, port); /* clock */ + } + else { + outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */ + outb_p(128+64+16+8+2+1, port); /* clock */ + } + sleep_delay(1000); +} + +void send_1_byte(int port, struct rt_device *dev) +{ + if ((dev->curvol == 0) || (dev->muted)) { + outb_p(128+64+16+4 +1, port); /* wr-enable+data high */ + outb_p(128+64+16+4+2+1, port); /* clock */ + } + else { + outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */ + outb_p(128+64+16+8+4+2+1, port); /* clock */ + } + + sleep_delay(1000); +} + +static int rt_setfreq(struct rt_device *dev, unsigned long freq) +{ + int i; + + /* adapted from radio-aztech.c */ + + /* now uses VIDEO_TUNER_LOW for fine tuning */ + + freq += 171200; /* Add 10.7 MHz IF */ + freq /= 800; /* Convert to 50 kHz units */ + + down(&lock); /* Stop other ops interfering */ + + send_0_byte (io, dev); /* 0: LSB of frequency */ + + for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ + if (freq & (1 << i)) + send_1_byte (io, dev); + else + send_0_byte (io, dev); + + send_0_byte (io, dev); /* 14: test bit - always 0 */ + send_0_byte (io, dev); /* 15: test bit - always 0 */ + + send_0_byte (io, dev); /* 16: band data 0 - always 0 */ + send_0_byte (io, dev); /* 17: band data 1 - always 0 */ + send_0_byte (io, dev); /* 18: band data 2 - always 0 */ + send_0_byte (io, dev); /* 19: time base - always 0 */ + + send_0_byte (io, dev); /* 20: spacing (0 = 25 kHz) */ + send_1_byte (io, dev); /* 21: spacing (1 = 25 kHz) */ + send_0_byte (io, dev); /* 22: spacing (0 = 25 kHz) */ + send_1_byte (io, dev); /* 23: AM/FM (FM = 1, always) */ + + if ((dev->curvol == 0) || (dev->muted)) + outb (0xd0, io); /* volume steady + sigstr */ + else + outb (0xd8, io); /* volume steady + sigstr + on */ + + up(&lock); + + return 0; +} + +static int rt_getsigstr(struct rt_device *dev) +{ + if (inb(io) & 2) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + +static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct rt_device *rt=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + strcpy(v.name, "RadioTrack"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; + v.mode=VIDEO_MODE_AUTO; + strcpy(v.name, "FM"); + v.signal=0xFFFF*rt_getsigstr(rt); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq))) + return -EFAULT; + rt_setfreq(rt, rt->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + v.volume=rt->curvol * 6554; + v.step=6554; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + if(v.flags&VIDEO_AUDIO_MUTE) + rt_mute(rt); + else + rt_setvol(rt,v.volume/6554); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int rt_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void rt_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct rt_device rtrack_unit; + +static struct video_device rtrack_radio= +{ + "RadioTrack radio", + VID_TYPE_TUNER, + VID_HARDWARE_RTRACK, + rt_open, + rt_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* No poll */ + rt_ioctl, + NULL, + NULL +}; + +static int __init rtrack_init(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + + if (check_region(io, 2)) + { + printk(KERN_ERR "rtrack: port 0x%x already in use\n", io); + return -EBUSY; + } + + rtrack_radio.priv=&rtrack_unit; + + if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 2, "rtrack"); + printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n"); + + /* Set up the I/O locking */ + + init_MUTEX(&lock); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + outb(0x48, io); /* volume down but still "on" */ + sleep_delay(2000000); /* make sure it's totally down */ + outb(0xc0, io); /* steady volume, mute card */ + rtrack_unit.curvol = 0; + + return 0; +} + +MODULE_AUTHOR("M.Kirkwood"); +MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); + +EXPORT_NO_SYMBOLS; + +static void __exit cleanup_rtrack_module(void) +{ + video_unregister_device(&rtrack_radio); + release_region(io,2); +} + +module_init(rtrack_init); +module_exit(cleanup_rtrack_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-aztech.c linux/drivers/media/radio/radio-aztech.c --- v2.4.0-test6/linux/drivers/media/radio/radio-aztech.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-aztech.c Wed Sep 29 14:02:59 1999 @@ -0,0 +1,330 @@ +/* radio-aztech.c - Aztech radio card driver for Linux 2.2 + * + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: + * + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * + * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ + * along with more information on the card itself. + * + * History: + * 1999-02-24 Russell Kroll + * Fine tuning/VIDEO_TUNER_LOW + * Range expanded to 87-108 MHz (from 87.9-107.8) + * + * Notable changes from the original source: + * - includes stripped down to the essentials + * - for loops used as delays replaced with udelay() + * - #defines removed, changed to static values + * - tuning structure changed - no more character arrays, other changes +*/ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_AZTECH_PORT */ + +/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ + +#ifndef CONFIG_RADIO_AZTECH_PORT +#define CONFIG_RADIO_AZTECH_PORT -1 +#endif + +static int io = CONFIG_RADIO_AZTECH_PORT; +static int radio_wait_time = 1000; +static int users = 0; +static struct semaphore lock; + +struct az_device +{ + int curvol; + unsigned long curfreq; + int stereo; +}; + +static int volconvert(int level) +{ + level>>=14; /* Map 16bits down to 2 bit */ + level&=3; + + /* convert to card-friendly values */ + switch (level) + { + case 0: + return 0; + case 1: + return 1; + case 2: + return 4; + case 3: + return 5; + } + return 0; /* Quieten gcc */ +} + +static void send_0_byte (struct az_device *dev) +{ + udelay(radio_wait_time); + outb_p(2+volconvert(dev->curvol), io); + outb_p(64+2+volconvert(dev->curvol), io); +} + +static void send_1_byte (struct az_device *dev) +{ + udelay (radio_wait_time); + outb_p(128+2+volconvert(dev->curvol), io); + outb_p(128+64+2+volconvert(dev->curvol), io); +} + +static int az_setvol(struct az_device *dev, int vol) +{ + down(&lock); + outb (volconvert(vol), io); + up(&lock); + return 0; +} + +/* thanks to Michael Dwyer for giving me a dose of clues in + * the signal strength department.. + * + * This card has a stereo bit - bit 0 set = mono, not set = stereo + * It also has a "signal" bit - bit 1 set = bad signal, not set = good + * + */ + +static int az_getsigstr(struct az_device *dev) +{ + if (inb(io) & 2) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + +static int az_getstereo(struct az_device *dev) +{ + if (inb(io) & 1) /* bit set = mono */ + return 0; + return 1; /* stereo */ +} + +static int az_setfreq(struct az_device *dev, unsigned long frequency) +{ + int i; + + frequency += 171200; /* Add 10.7 MHz IF */ + frequency /= 800; /* Convert to 50 kHz units */ + + down(&lock); + + send_0_byte (dev); /* 0: LSB of frequency */ + + for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ + if (frequency & (1 << i)) + send_1_byte (dev); + else + send_0_byte (dev); + + send_0_byte (dev); /* 14: test bit - always 0 */ + send_0_byte (dev); /* 15: test bit - always 0 */ + send_0_byte (dev); /* 16: band data 0 - always 0 */ + if (dev->stereo) /* 17: stereo (1 to enable) */ + send_1_byte (dev); + else + send_0_byte (dev); + + send_1_byte (dev); /* 18: band data 1 - unknown */ + send_0_byte (dev); /* 19: time base - always 0 */ + send_0_byte (dev); /* 20: spacing (0 = 25 kHz) */ + send_1_byte (dev); /* 21: spacing (1 = 25 kHz) */ + send_0_byte (dev); /* 22: spacing (0 = 25 kHz) */ + send_1_byte (dev); /* 23: AM/FM (FM = 1, always) */ + + /* latch frequency */ + + udelay (radio_wait_time); + outb_p(128+64+volconvert(dev->curvol), io); + + up(&lock); + + return 0; +} + +static int az_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct az_device *az=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + strcpy(v.name, "Aztech Radio"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; + v.mode=VIDEO_MODE_AUTO; + v.signal=0xFFFF*az_getsigstr(az); + if(az_getstereo(az)) + v.flags|=VIDEO_TUNER_STEREO_ON; + strcpy(v.name, "FM"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &az->curfreq, sizeof(az->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&az->curfreq, arg,sizeof(az->curfreq))) + return -EFAULT; + az_setfreq(az, az->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + if(az->stereo) + v.mode=VIDEO_SOUND_STEREO; + else + v.mode=VIDEO_SOUND_MONO; + v.volume=az->curvol; + v.step=16384; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + az->curvol=v.volume; + + az->stereo=(v.mode&VIDEO_SOUND_STEREO)?1:0; + if(v.flags&VIDEO_AUDIO_MUTE) + az_setvol(az,0); + else + az_setvol(az,az->curvol); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int az_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void az_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct az_device aztech_unit; + +static struct video_device aztech_radio= +{ + "Aztech radio", + VID_TYPE_TUNER, + VID_HARDWARE_AZTECH, + az_open, + az_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* No poll */ + az_ioctl, + NULL, + NULL +}; + +static int __init aztech_init(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + + if (check_region(io, 2)) + { + printk(KERN_ERR "aztech: port 0x%x already in use\n", io); + return -EBUSY; + } + + init_MUTEX(&lock); + aztech_radio.priv=&aztech_unit; + + if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 2, "aztech"); + printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); + /* mute card - prevents noisy bootups */ + outb (0, io); + return 0; +} + +MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the Aztech radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); + +EXPORT_NO_SYMBOLS; + +static void __exit aztech_cleanup(void) +{ + video_unregister_device(&aztech_radio); + release_region(io,2); +} + +module_init(aztech_init); +module_exit(aztech_cleanup); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-cadet.c linux/drivers/media/radio/radio-cadet.c --- v2.4.0-test6/linux/drivers/media/radio/radio-cadet.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-cadet.c Wed May 3 01:45:19 2000 @@ -0,0 +1,603 @@ +/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card + * + * by Fred Gleason + * Version 0.3.3 + * + * (Loosely) based on code for the Aztech radio card by + * + * Russell Kroll (rkroll@exploits.org) + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * +*/ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_CADET_PORT */ +#include + +#ifndef CONFIG_RADIO_CADET_PORT +#define CONFIG_RADIO_CADET_PORT 0x330 +#endif +#define RDS_BUFFER 256 + +static int io=CONFIG_RADIO_CADET_PORT; +static int users=0; +static int curtuner=0; +static int tunestat=0; +static int sigstrength=0; +static wait_queue_head_t tunerq,rdsq,readq; +struct timer_list tunertimer,rdstimer,readtimer; +static __u8 rdsin=0,rdsout=0,rdsstat=0; +static unsigned char rdsbuf[RDS_BUFFER]; +static int cadet_lock=0; + +/* + * Signal Strength Threshold Values + * The V4L API spec does not define any particular unit for the signal + * strength value. These values are in microvolts of RF at the tuner's input. + */ +static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; + + + +void cadet_wake(unsigned long qnum) +{ + switch(qnum) { + case 0: /* cadet_setfreq */ + wake_up(&tunerq); + break; + case 1: /* cadet_getrds */ + wake_up(&rdsq); + break; + } +} + + + +static int cadet_getrds(void) +{ + int rdsstat=0; + + cadet_lock++; + outb(3,io); /* Select Decoder Control/Status */ + outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */ + cadet_lock--; + init_timer(&rdstimer); + rdstimer.function=cadet_wake; + rdstimer.data=(unsigned long)1; + rdstimer.expires=jiffies+(HZ/10); + init_waitqueue_head(&rdsq); + add_timer(&rdstimer); + sleep_on(&rdsq); + + cadet_lock++; + outb(3,io); /* Select Decoder Control/Status */ + if((inb(io+1)&0x80)!=0) { + rdsstat|=VIDEO_TUNER_RDS_ON; + } + if((inb(io+1)&0x10)!=0) { + rdsstat|=VIDEO_TUNER_MBS_ON; + } + cadet_lock--; + return rdsstat; +} + + + + +static int cadet_getstereo(void) +{ + if(curtuner!=0) { /* Only FM has stereo capability! */ + return 0; + } + cadet_lock++; + outb(7,io); /* Select tuner control */ + if((inb(io+1)&0x40)==0) { + cadet_lock--; + return 1; /* Stereo pilot detected */ + } + else { + cadet_lock--; + return 0; /* Mono */ + } +} + + + +static unsigned cadet_gettune(void) +{ + int curvol,i; + unsigned fifo=0; + + /* + * Prepare for read + */ + cadet_lock++; + outb(7,io); /* Select tuner control */ + curvol=inb(io+1); /* Save current volume/mute setting */ + outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */ + tunestat=0xffff; + + /* + * Read the shift register + */ + for(i=0;i<25;i++) { + fifo=(fifo<<1)|((inb(io+1)>>7)&0x01); + if(i<24) { + outb(0x01,io+1); + tunestat&=inb(io+1); + outb(0x00,io+1); + } + } + + /* + * Restore volume/mute setting + */ + outb(curvol,io+1); + cadet_lock--; + + return fifo; +} + + + +static unsigned cadet_getfreq(void) +{ + int i; + unsigned freq=0,test,fifo=0; + + /* + * Read current tuning + */ + fifo=cadet_gettune(); + + /* + * Convert to actual frequency + */ + if(curtuner==0) { /* FM */ + test=12500; + for(i=0;i<14;i++) { + if((fifo&0x01)!=0) { + freq+=test; + } + test=test<<1; + fifo=fifo>>1; + } + freq-=10700000; /* IF frequency is 10.7 MHz */ + freq=(freq*16)/1000000; /* Make it 1/16 MHz */ + } + if(curtuner==1) { /* AM */ + freq=((fifo&0x7fff)-2010)*16; + } + + return freq; +} + + + +static void cadet_settune(unsigned fifo) +{ + int i; + unsigned test; + + cadet_lock++; + outb(7,io); /* Select tuner control */ + /* + * Write the shift register + */ + test=0; + test=(fifo>>23)&0x02; /* Align data for SDO */ + test|=0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ + outb(7,io); /* Select tuner control */ + outb(test,io+1); /* Initialize for write */ + for(i=0;i<25;i++) { + test|=0x01; /* Toggle SCK High */ + outb(test,io+1); + test&=0xfe; /* Toggle SCK Low */ + outb(test,io+1); + fifo=fifo<<1; /* Prepare the next bit */ + test=0x1c|((fifo>>23)&0x02); + outb(test,io+1); + } + cadet_lock--; +} + + + +static void cadet_setfreq(unsigned freq) +{ + unsigned fifo; + int i,j,test; + int curvol; + + /* + * Formulate a fifo command + */ + fifo=0; + if(curtuner==0) { /* FM */ + test=102400; + freq=(freq*1000)/16; /* Make it kHz */ + freq+=10700; /* IF is 10700 kHz */ + for(i=0;i<14;i++) { + fifo=fifo<<1; + if(freq>=test) { + fifo|=0x01; + freq-=test; + } + test=test>>1; + } + } + if(curtuner==1) { /* AM */ + fifo=(freq/16)+2010; /* Make it kHz */ + fifo|=0x100000; /* Select AM Band */ + } + + /* + * Save current volume/mute setting + */ + cadet_lock++; + outb(7,io); /* Select tuner control */ + curvol=inb(io+1); + + /* + * Tune the card + */ + for(j=3;j>-1;j--) { + cadet_settune(fifo|(j<<16)); + outb(7,io); /* Select tuner control */ + outb(curvol,io+1); + cadet_lock--; + init_timer(&tunertimer); + tunertimer.function=cadet_wake; + tunertimer.data=(unsigned long)0; + tunertimer.expires=jiffies+(HZ/10); + init_waitqueue_head(&tunerq); + add_timer(&tunertimer); + sleep_on(&tunerq); + cadet_gettune(); + if((tunestat&0x40)==0) { /* Tuned */ + sigstrength=sigtable[curtuner][j]; + return; + } + cadet_lock++; + } + cadet_lock--; + sigstrength=0; +} + + +static int cadet_getvol(void) +{ + cadet_lock++; + outb(7,io); /* Select tuner control */ + if((inb(io+1)&0x20)!=0) { + cadet_lock--; + return 0xffff; + } + else { + cadet_lock--; + return 0; + } +} + + +static void cadet_setvol(int vol) +{ + cadet_lock++; + outb(7,io); /* Select tuner control */ + if(vol>0) { + outb(0x20,io+1); + } + else { + outb(0x00,io+1); + } + cadet_lock--; +} + + + +void cadet_handler(unsigned long data) +{ + /* + * Service the RDS fifo + */ + if(cadet_lock==0) { + outb(0x3,io); /* Select RDS Decoder Control */ + if((inb(io+1)&0x20)!=0) { + printk(KERN_CRIT "cadet: RDS fifo overflow\n"); + } + outb(0x80,io); /* Select RDS fifo */ + while((inb(io)&0x80)!=0) { + rdsbuf[rdsin++]=inb(io+1); + if(rdsin==rdsout) { + printk(KERN_CRIT "cadet: RDS buffer overflow\n"); + } + } + } + + /* + * Service pending read + */ + if( rdsin!=rdsout) { + wake_up_interruptible(&readq); + } + + /* + * Clean up and exit + */ + init_timer(&readtimer); + readtimer.function=cadet_handler; + readtimer.data=(unsigned long)0; + readtimer.expires=jiffies+(HZ/20); + add_timer(&readtimer); +} + + + +static long cadet_read(struct video_device *v,char *buf,unsigned long count, + int nonblock) +{ + int i=0; + unsigned char readbuf[RDS_BUFFER]; + + if(rdsstat==0) { + cadet_lock++; + rdsstat=1; + outb(0x80,io); /* Select RDS fifo */ + cadet_lock--; + init_timer(&readtimer); + readtimer.function=cadet_handler; + readtimer.data=(unsigned long)0; + readtimer.expires=jiffies+(HZ/20); + add_timer(&readtimer); + } + if(rdsin==rdsout) { + if(nonblock) { + return -EWOULDBLOCK; + } + interruptible_sleep_on(&readq); + } + while((i1)) { + return -EINVAL; + } + switch(v.tuner) { + case 0: + strcpy(v.name,"FM"); + v.rangelow=1400; /* 87.5 MHz */ + v.rangehigh=1728; /* 108.0 MHz */ + v.flags=0; + v.mode=0; + v.mode|=VIDEO_MODE_AUTO; + v.signal=sigstrength; + if(cadet_getstereo()==1) { + v.flags|=VIDEO_TUNER_STEREO_ON; + } + v.flags|=cadet_getrds(); + if(copy_to_user(arg,&v, sizeof(v))) { + return -EFAULT; + } + break; + case 1: + strcpy(v.name,"AM"); + v.rangelow=8320; /* 520 kHz */ + v.rangehigh=26400; /* 1650 kHz */ + v.flags=0; + v.flags|=VIDEO_TUNER_LOW; + v.mode=0; + v.mode|=VIDEO_MODE_AUTO; + v.signal=sigstrength; + if(copy_to_user(arg,&v, sizeof(v))) { + return -EFAULT; + } + break; + } + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + if((v.tuner<0)||(v.tuner>1)) { + return -EINVAL; + } + curtuner=v.tuner; + return 0; + } + case VIDIOCGFREQ: + freq=cadet_getfreq(); + if(copy_to_user(arg, &freq, sizeof(freq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&freq, arg,sizeof(freq))) + return -EFAULT; + if((curtuner==0)&&((freq<1400)||(freq>1728))) { + return -EINVAL; + } + if((curtuner==1)&&((freq<8320)||(freq>26400))) { + return -EINVAL; + } + cadet_setfreq(freq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + if(cadet_getstereo()==0) { + v.mode=VIDEO_SOUND_MONO; + } + else { + v.mode=VIDEO_SOUND_STEREO; + } + v.volume=cadet_getvol(); + v.step=0xffff; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + cadet_setvol(v.volume); + if(v.flags&VIDEO_AUDIO_MUTE) + cadet_setvol(0); + else + cadet_setvol(0xffff); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + + +static int cadet_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + init_waitqueue_head(&readq); + return 0; +} + +static void cadet_close(struct video_device *dev) +{ + if(rdsstat==1) { + del_timer(&readtimer); + rdsstat=0; + } + users--; + MOD_DEC_USE_COUNT; +} + + +static struct video_device cadet_radio= +{ + "Cadet radio", + VID_TYPE_TUNER, + VID_HARDWARE_CADET, + cadet_open, + cadet_close, + cadet_read, + NULL, /* Can't write */ + NULL, /* No poll */ + cadet_ioctl, + NULL, + NULL +}; + +#ifndef MODULE +static int cadet_probe(void) +{ + static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e}; + int i; + + for(i=0;i<8;i++) { + io=iovals[i]; + if(check_region(io,2)>=0) { + cadet_setfreq(1410); + if(cadet_getfreq()==1410) { + return io; + } + } + } + return -1; +} +#endif + +static int __init cadet_init(void) +{ +#ifndef MODULE + io = cadet_probe (); +#endif + + if(io < 0) { +#ifdef MODULE + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); +#endif + return -EINVAL; + } + if (!request_region(io,2,"cadet")) + return -EBUSY; + if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) { + release_region(io,2); + return -EINVAL; + } + printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io); + return 0; +} + + + +MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); + +EXPORT_NO_SYMBOLS; + +static void __exit cadet_cleanup_module(void) +{ + video_unregister_device(&cadet_radio); + release_region(io,2); +} + +module_init(cadet_init); +module_exit(cadet_cleanup_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-gemtek.c linux/drivers/media/radio/radio-gemtek.c --- v2.4.0-test6/linux/drivers/media/radio/radio-gemtek.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-gemtek.c Mon Mar 13 09:43:36 2000 @@ -0,0 +1,319 @@ +/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin + * + * GemTek hasn't released any specs on the card, so the protocol had to + * be reverse engineered with dosemu. + * + * Besides the protocol changes, this is mostly a copy of: + * + * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff + * + * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood + * Coverted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * + * TODO: Allow for more than one of these foolish entities :-) + * + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_GEMTEK_PORT */ +#include + +#ifndef CONFIG_RADIO_GEMTEK_PORT +#define CONFIG_RADIO_GEMTEK_PORT -1 +#endif + +static int io = CONFIG_RADIO_GEMTEK_PORT; +static int users = 0; +static spinlock_t lock; + +struct gemtek_device +{ + int port; + unsigned long curfreq; + int muted; +}; + + +/* local things */ + +/* the correct way to mute the gemtek may be to write the last written + * frequency || 0x10, but just writing 0x10 once seems to do it as well + */ +static void gemtek_mute(struct gemtek_device *dev) +{ + if(dev->muted) + return; + spin_lock(&lock); + outb(0x10, io); + spin_unlock(&lock); + dev->muted = 1; +} + +static void gemtek_unmute(struct gemtek_device *dev) +{ + if(dev->muted == 0) + return; + spin_lock(&lock); + outb(0x20, io); + spin_unlock(&lock); + dev->muted = 0; +} + +static void zero(void) +{ + outb_p(0x04, io); + udelay(5); + outb_p(0x05, io); + udelay(5); +} + +static void one(void) +{ + outb_p(0x06, io); + udelay(5); + outb_p(0x07, io); + udelay(5); +} + +static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +{ + int i; + +/* freq = 78.25*((float)freq/16000.0 + 10.52); */ + + freq /= 16; + freq += 10520; + freq *= 7825; + freq /= 100000; + + spin_lock(&lock); + + /* 2 start bits */ + outb_p(0x03, io); + udelay(5); + outb_p(0x07, io); + udelay(5); + + /* 28 frequency bits (lsb first) */ + for (i = 0; i < 14; i++) + if (freq & (1 << i)) + one(); + else + zero(); + /* 36 unknown bits */ + for (i = 0; i < 11; i++) + zero(); + one(); + for (i = 0; i < 4; i++) + zero(); + one(); + zero(); + + /* 2 end bits */ + outb_p(0x03, io); + udelay(5); + outb_p(0x07, io); + udelay(5); + + spin_unlock(&lock); + + return 0; +} + +int gemtek_getsigstr(struct gemtek_device *dev) +{ + spin_lock(&lock); + inb(io); + udelay(5); + spin_unlock(&lock); + if (inb(io) & 8) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + +static int gemtek_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct gemtek_device *rt=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + strcpy(v.name, "GemTek"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=87*16000; + v.rangehigh=108*16000; + v.flags=VIDEO_TUNER_LOW; + v.mode=VIDEO_MODE_AUTO; + v.signal=0xFFFF*gemtek_getsigstr(rt); + strcpy(v.name, "FM"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq))) + return -EFAULT; + /* needs to be called twice in order for getsigstr to work */ + gemtek_setfreq(rt, rt->curfreq); + gemtek_setfreq(rt, rt->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE; + v.volume=1; + v.step=65535; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + if(v.flags&VIDEO_AUDIO_MUTE) + gemtek_mute(rt); + else + gemtek_unmute(rt); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int gemtek_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void gemtek_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct gemtek_device gemtek_unit; + +static struct video_device gemtek_radio= +{ + "GemTek radio", + VID_TYPE_TUNER, + VID_HARDWARE_GEMTEK, + gemtek_open, + gemtek_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + gemtek_ioctl, + NULL, + NULL +}; + +static int __init gemtek_init(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n"); + return -EINVAL; + } + + if (check_region(io, 4)) + { + printk(KERN_ERR "gemtek: port 0x%x already in use\n", io); + return -EBUSY; + } + + gemtek_radio.priv=&gemtek_unit; + + if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 4, "gemtek"); + printk(KERN_INFO "GemTek Radio Card driver.\n"); + + spin_lock_init(&lock); + /* mute card - prevents noisy bootups */ + outb(0x10, io); + udelay(5); + gemtek_unit.muted = 1; + + /* this is _maybe_ unnecessary */ + outb(0x01, io); + + return 0; +} + +MODULE_AUTHOR("Jonas Munsin"); +MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); + +EXPORT_NO_SYMBOLS; + +static void __exit gemtek_cleanup(void) +{ + video_unregister_device(&gemtek_radio); + release_region(io,4); +} + +module_init(gemtek_init); +module_exit(gemtek_cleanup); + +/* + Local variables: + compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" + End: +*/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c --- v2.4.0-test6/linux/drivers/media/radio/radio-miropcm20.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-miropcm20.c Tue Aug 22 11:29:02 2000 @@ -0,0 +1,239 @@ +/* Miro PCM20 radio driver for Linux radio support + * (c) 1998 Ruurd Reitsma + * Thanks to Norberto Pellici for the ACI device interface specification + * The API part is based on the radiotrack driver by M. Kirkwood + * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c) + * Look there for further info... + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include "../../sound/miroaci.h" /* ACI Control by acimixer */ + +static int users = 0; + +struct pcm20_device +{ + int port; + int curvol; + unsigned long curfreq; + int muted; +}; + + +/* local things */ + + +static void pcm20_mute(struct pcm20_device *dev) +{ + + dev->muted = 1; + aci_write_cmd(0xa3,0x01); + +} + +static int pcm20_setvol(struct pcm20_device *dev, int vol) +{ + + if(vol == dev->curvol) { /* requested volume = current */ + if (dev->muted) { /* user is unmuting the card */ + dev->muted = 0; + aci_write_cmd(0xa3,0x00); /* enable card */ + } + + return 0; + } + + if(vol == 0) { /* volume = 0 means mute the card */ + aci_write_cmd(0x3d, 0x20); + aci_write_cmd(0x35, 0x20); + return 0; + } + + dev->muted = 0; + aci_write_cmd(0x3d, 32-vol); /* Right Channel */ + aci_write_cmd(0x35, 32-vol); /* Left Channel */ + dev->curvol = vol; + + return 0; +} + +static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) +{ + unsigned char freql; + unsigned char freqh; + + freq = (freq * 10) / 16; + freql = freq & 0xff; + freqh = freq >> 8; + + + aci_write_cmd_d(0xa7, freql, freqh); /* Tune to frequency */ + + return 0; +} + +int pcm20_getsigstr(struct pcm20_device *dev) +{ + unsigned char buf; + aci_indexed_cmd(0xf0, 0x32, &buf); + if ((buf & 0x80) == 0x80) + return 0; + return 1; /* signal present */ +} + +static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct pcm20_device *pcm20=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + strcpy(v.name, "Miro PCM20"); + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=(int)(87.5*16); + v.rangehigh=(int)(108.0*16); + v.flags=0; + v.mode=VIDEO_MODE_AUTO; + v.signal=0xFFFF*pcm20_getsigstr(pcm20); + strcpy(v.name, "FM"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq))) + return -EFAULT; + pcm20_setfreq(pcm20, pcm20->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + v.volume=pcm20->curvol * 2048; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + if(v.flags&VIDEO_AUDIO_MUTE) + pcm20_mute(pcm20); + else + pcm20_setvol(pcm20,v.volume/2048); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int pcm20_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void pcm20_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct pcm20_device pcm20_unit; + +static struct video_device pcm20_radio= +{ + "Miro PCM 20 radio", + VID_TYPE_TUNER, + VID_HARDWARE_RTRACK, + pcm20_open, + pcm20_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + pcm20_ioctl, + NULL, + NULL +}; + +static int __init pcm20_init(void) +{ + + pcm20_radio.priv=&pcm20_unit; + + if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + printk(KERN_INFO "Miro PCM20 radio card driver.\n"); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + + pcm20_unit.curvol = 0; + + return 0; +} + +MODULE_AUTHOR("Ruurd Reitsma"); +MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); + +EXPORT_NO_SYMBOLS; + +static void __exit pcm20_cleanup(void) +{ + video_unregister_device(&pcm20_radio); +} + +module_init(pcm20_init); +module_exit(pcm20_cleanup); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-rtrack2.c linux/drivers/media/radio/radio-rtrack2.c --- v2.4.0-test6/linux/drivers/media/radio/radio-rtrack2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-rtrack2.c Thu Oct 28 16:12:56 1999 @@ -0,0 +1,280 @@ +/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff + * + * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood + * Coverted to new API by Alan Cox + * Various bugfixes and enhancements by Russell Kroll + * + * TODO: Allow for more than one of these foolish entities :-) + * + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_RTRACK2_PORT */ +#include + +#ifndef CONFIG_RADIO_RTRACK2_PORT +#define CONFIG_RADIO_RTRACK2_PORT -1 +#endif + +static int io = CONFIG_RADIO_RTRACK2_PORT; +static int users = 0; +static spinlock_t lock; + +struct rt_device +{ + int port; + unsigned long curfreq; + int muted; +}; + + +/* local things */ + +static void rt_mute(struct rt_device *dev) +{ + if(dev->muted) + return; + spin_lock(&lock); + outb(1, io); + spin_unlock(&lock); + dev->muted = 1; +} + +static void rt_unmute(struct rt_device *dev) +{ + if(dev->muted == 0) + return; + spin_lock(&lock); + outb(0, io); + spin_unlock(&lock); + dev->muted = 0; +} + +static void zero(void) +{ + outb_p(1, io); + outb_p(3, io); + outb_p(1, io); +} + +static void one(void) +{ + outb_p(5, io); + outb_p(7, io); + outb_p(5, io); +} + +static int rt_setfreq(struct rt_device *dev, unsigned long freq) +{ + int i; + + freq = freq / 200 + 856; + + spin_lock(&lock); + + outb_p(0xc8, io); + outb_p(0xc9, io); + outb_p(0xc9, io); + + for (i = 0; i < 10; i++) + zero (); + + for (i = 14; i >= 0; i--) + if (freq & (1 << i)) + one (); + else + zero (); + + outb_p(0xc8, io); + if (!dev->muted) + outb_p(0, io); + + spin_unlock(&lock); + return 0; +} + +static int rt_getsigstr(struct rt_device *dev) +{ + if (inb(io) & 2) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + +static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct rt_device *rt=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + strcpy(v.name, "RadioTrack II"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=88*16000; + v.rangehigh=108*16000; + v.flags=VIDEO_TUNER_LOW; + v.mode=VIDEO_MODE_AUTO; + v.signal=0xFFFF*rt_getsigstr(rt); + strcpy(v.name, "FM"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq))) + return -EFAULT; + rt_setfreq(rt, rt->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE; + v.volume=1; + v.step=65535; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + if(v.flags&VIDEO_AUDIO_MUTE) + rt_mute(rt); + else + rt_unmute(rt); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int rt_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void rt_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct rt_device rtrack2_unit; + +static struct video_device rtrack2_radio= +{ + "RadioTrack II radio", + VID_TYPE_TUNER, + VID_HARDWARE_RTRACK2, + rt_open, + rt_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + rt_ioctl, + NULL, + NULL +}; + +static int __init rtrack2_init(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n"); + return -EINVAL; + } + if (check_region(io, 4)) + { + printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io); + return -EBUSY; + } + + rtrack2_radio.priv=&rtrack2_unit; + + spin_lock_init(&lock); + if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 4, "rtrack2"); + printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n"); + + /* mute card - prevents noisy bootups */ + outb(1, io); + rtrack2_unit.muted = 1; + + return 0; +} + +MODULE_AUTHOR("Ben Pfaff"); +MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); + +EXPORT_NO_SYMBOLS; + +static void __exit rtrack2_cleanup_module(void) +{ + video_unregister_device(&rtrack2_radio); + release_region(io,4); +} + +module_init(rtrack2_init); +module_exit(rtrack2_cleanup_module); + +/* + Local variables: + compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" + End: +*/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c --- v2.4.0-test6/linux/drivers/media/radio/radio-sf16fmi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-sf16fmi.c Thu Oct 28 16:13:00 1999 @@ -0,0 +1,339 @@ +/* SF16FMI radio driver for Linux radio support + * heavily based on rtrack driver... + * (c) 1997 M. Kirkwood + * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz + * + * Fitted to new interface by Alan Cox + * Made working and cleaned up functions + * + * Notes on the hardware + * + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * No volume control - only mute/unmute - you have to use line volume + * control on SB-part of SF16FMI + * + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_SF16MI_PORT */ +#include + +struct fmi_device +{ + int port; + int curvol; /* 1 or 0 */ + unsigned long curfreq; /* freq in kHz */ + __u32 flags; +}; + +#ifndef CONFIG_RADIO_SF16FMI_PORT +#define CONFIG_RADIO_SF16FMI_PORT -1 +#endif + +static int io = CONFIG_RADIO_SF16FMI_PORT; +static int users = 0; +static struct semaphore lock; + +/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ +/* It is only usefull to give freq in intervall of 800 (=0.05Mhz), + * other bits will be truncated, e.g 92.7400016 -> 92.7, but + * 92.7400017 -> 92.75 + */ +#define RSF16_ENCODE(x) ((x)/800+214) +#define RSF16_MINFREQ 87*16000 +#define RSF16_MAXFREQ 108*16000 + +static void outbits(int bits, unsigned int data, int port) +{ + while(bits--) { + if(data & 1) { + outb(5, port); + udelay(6); + outb(7, port); + udelay(6); + } else { + outb(1, port); + udelay(6); + outb(3, port); + udelay(6); + } + data>>=1; + } +} + +static inline void fmi_mute(int port) +{ + down(&lock); + outb(0x00, port); + up(&lock); +} + +static inline void fmi_unmute(int port) +{ + down(&lock); + outb(0x08, port); + up(&lock); +} + +static inline int fmi_setfreq(struct fmi_device *dev) +{ + int myport = dev->port; + unsigned long freq = dev->curfreq; + int i; + + down(&lock); + + outbits(16, RSF16_ENCODE(freq), myport); + outbits(8, 0xC0, myport); + for(i=0; i< 100; i++) + { + udelay(1400); + if(current->need_resched) + schedule(); + } +/* If this becomes allowed use it ... + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/7); +*/ + + up(&lock); + if (dev->curvol) fmi_unmute(myport); + return 0; +} + +static inline int fmi_getsigstr(struct fmi_device *dev) +{ + int val; + int res; + int myport = dev->port; + int i; + + down(&lock); + val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ + outb(val, myport); + outb(val | 0x10, myport); + for(i=0; i< 100; i++) + { + udelay(1400); + if(current->need_resched) + schedule(); + } +/* If this becomes allowed use it ... + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/7); +*/ + res = (int)inb(myport+1); + outb(val, myport); + + up(&lock); + return (res & 2) ? 0 : 0xFFFF; +} + +static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct fmi_device *fmi=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + strcpy(v.name, "SF16-FMx radio"); + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + int mult; + + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + strcpy(v.name, "FM"); + mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000; + v.rangelow = RSF16_MINFREQ/mult; + v.rangehigh = RSF16_MAXFREQ/mult; + v.flags=fmi->flags; + v.mode=VIDEO_MODE_AUTO; + v.signal = fmi_getsigstr(fmi); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + fmi->flags = v.flags & VIDEO_TUNER_LOW; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + { + unsigned long tmp = fmi->curfreq; + if (!(fmi->flags & VIDEO_TUNER_LOW)) + tmp /= 1000; + if(copy_to_user(arg, &tmp, sizeof(tmp))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: + { + unsigned long tmp; + if(copy_from_user(&tmp, arg, sizeof(tmp))) + return -EFAULT; + if (!(fmi->flags & VIDEO_TUNER_LOW)) + tmp *= 1000; + if ( tmpRSF16_MAXFREQ ) + return -EINVAL; + /*rounding in steps of 800 to match th freq + that will be used */ + fmi->curfreq = (tmp/800)*800; + fmi_setfreq(fmi); + return 0; + } + case VIDIOCGAUDIO: + { + struct video_audio v; + v.audio=0; + v.volume=0; + v.bass=0; + v.treble=0; + v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE); + strcpy(v.name, "Radio"); + v.mode=VIDEO_SOUND_STEREO; + v.balance=0; + v.step=0; /* No volume, just (un)mute */ + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + fmi->curvol= v.flags&VIDEO_AUDIO_MUTE ? 0 : 1; + fmi->curvol ? + fmi_unmute(fmi->port) : fmi_mute(fmi->port); + return 0; + } + case VIDIOCGUNIT: + { + struct video_unit v; + v.video=VIDEO_NO_UNIT; + v.vbi=VIDEO_NO_UNIT; + v.radio=dev->minor; + v.audio=0; /* How do we find out this??? */ + v.teletext=VIDEO_NO_UNIT; + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int fmi_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void fmi_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct fmi_device fmi_unit; + +static struct video_device fmi_radio= +{ + "SF16FMx radio", + VID_TYPE_TUNER, + VID_HARDWARE_SF16MI, + fmi_open, + fmi_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + fmi_ioctl, + NULL, + NULL +}; + +static int __init fmi_init(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + if (check_region(io, 2)) + { + printk(KERN_ERR "fmi: port 0x%x already in use\n", io); + return -EBUSY; + } + + fmi_unit.port = io; + fmi_unit.curvol = 0; + fmi_unit.curfreq = 0; + fmi_unit.flags = VIDEO_TUNER_LOW; + fmi_radio.priv = &fmi_unit; + + init_MUTEX(&lock); + + if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 2, "fmi"); + printk(KERN_INFO "SF16FMx radio card driver at 0x%x.\n", io); + printk(KERN_INFO "(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n"); + /* mute card - prevents noisy bootups */ + fmi_mute(io); + return 0; +} + +MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); +MODULE_DESCRIPTION("A driver for the SF16MI radio."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); + +EXPORT_NO_SYMBOLS; + +static void __exit fmi_cleanup_module(void) +{ + video_unregister_device(&fmi_radio); + release_region(io,2); +} + +module_init(fmi_init); +module_exit(fmi_cleanup_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-terratec.c linux/drivers/media/radio/radio-terratec.c --- v2.4.0-test6/linux/drivers/media/radio/radio-terratec.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-terratec.c Thu Oct 28 16:13:03 1999 @@ -0,0 +1,358 @@ +/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support + * (c) 1999 R. Offermanns (rolf@offermanns.de) + * based on the aimslab radio driver from M. Kirkwood + * many thanks to Michael Becker and Friedhelm Birth (from TerraTec) + * + * + * History: + * 1999-05-21 First preview release + * + * Notes on the hardware: + * There are two "main" chips on the card: + * - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf) + * - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf) + * (you can get the datasheet at the above links) + * + * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); + * Volume Control is done digitally + * + * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday + * (as soon i have understand how to get started :) + * If you can help me out with that, please contact me!! + * + * + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_TERRATEC_PORT */ +#include + +#ifndef CONFIG_RADIO_TERRATEC_PORT +#define CONFIG_RADIO_TERRATEC_PORT 0x590 +#endif + +/**************** this ones are for the terratec *******************/ +#define BASEPORT 0x590 +#define VOLPORT 0x591 +#define WRT_DIS 0x00 +#define CLK_OFF 0x00 +#define IIC_DATA 0x01 +#define IIC_CLK 0x02 +#define DATA 0x04 +#define CLK_ON 0x08 +#define WRT_EN 0x10 +/*******************************************************************/ + +static int io = CONFIG_RADIO_TERRATEC_PORT; +static int users = 0; +static spinlock_t lock; + +struct tt_device +{ + int port; + int curvol; + unsigned long curfreq; + int muted; +}; + + +/* local things */ + +static void cardWriteVol(int volume) +{ + int i; + volume = volume+(volume * 32); // change both channels + spin_lock(&lock); + for (i=0;i<8;i++) + { + if (volume & (0x80>>i)) + outb(0x80, VOLPORT); + else outb(0x00, VOLPORT); + } + spin_unlock(&lock); +} + + + +static void tt_mute(struct tt_device *dev) +{ + dev->muted = 1; + cardWriteVol(0); +} + +static int tt_setvol(struct tt_device *dev, int vol) +{ + +// printk(KERN_ERR "setvol called, vol = %d\n", vol); + + if(vol == dev->curvol) { /* requested volume = current */ + if (dev->muted) { /* user is unmuting the card */ + dev->muted = 0; + cardWriteVol(vol); /* enable card */ + } + + return 0; + } + + if(vol == 0) { /* volume = 0 means mute the card */ + cardWriteVol(0); /* "turn off card" by setting vol to 0 */ + dev->curvol = vol; /* track the volume state! */ + return 0; + } + + dev->muted = 0; + + cardWriteVol(vol); + + dev->curvol = vol; + + return 0; + +} + + +/* this is the worst part in this driver */ +/* many more or less strange things are going on here, but hey, it works :) */ + +static int tt_setfreq(struct tt_device *dev, unsigned long freq1) +{ + int freq; + int i; + int p; + int temp; + long rest; + + unsigned char buffer[25]; /* we have to bit shift 25 registers */ + freq = freq1/160; /* convert the freq. to a nice to handel value */ + for(i=24;i>-1;i--) + buffer[i]=0; + + rest = freq*10+10700; /* i once had understood what is going on here */ + /* maybe some wise guy (friedhelm?) can comment this stuff */ + i=13; + p=10; + temp=102400; + while (rest!=0) + { + if (rest%temp == rest) + buffer[i] = 0; + else + { + buffer[i] = 1; + rest = rest-temp; + } + i--; + p--; + temp = temp/2; + } + + spin_lock(&lock); + + for (i=24;i>-1;i--) /* bit shift the values to the radiocard */ + { + if (buffer[i]==1) + { + outb(WRT_EN|DATA, BASEPORT); + outb(WRT_EN|DATA|CLK_ON , BASEPORT); + outb(WRT_EN|DATA, BASEPORT); + } + else + { + outb(WRT_EN|0x00, BASEPORT); + outb(WRT_EN|0x00|CLK_ON , BASEPORT); + } + } + outb(0x00, BASEPORT); + + spin_unlock(&lock); + + return 0; +} + +int tt_getsigstr(struct tt_device *dev) /* TODO */ +{ + if (inb(io) & 2) /* bit set = no signal present */ + return 0; + return 1; /* signal present */ +} + + +/* implement the video4linux api */ + +static int tt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct tt_device *tt=dev->priv; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + strcpy(v.name, "ActiveRadio"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags=VIDEO_TUNER_LOW; + v.mode=VIDEO_MODE_AUTO; + strcpy(v.name, "FM"); + v.signal=0xFFFF*tt_getsigstr(tt); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &tt->curfreq, sizeof(tt->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if(copy_from_user(&tt->curfreq, arg,sizeof(tt->curfreq))) + return -EFAULT; + tt_setfreq(tt, tt->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v,0, sizeof(v)); + v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; + v.volume=tt->curvol * 6554; + v.step=6554; + strcpy(v.name, "Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + if(v.flags&VIDEO_AUDIO_MUTE) + tt_mute(tt); + else + tt_setvol(tt,v.volume/6554); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int tt_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void tt_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct tt_device terratec_unit; + +static struct video_device terratec_radio= +{ + "TerraTec ActiveRadio", + VID_TYPE_TUNER, + VID_HARDWARE_TERRATEC, + tt_open, + tt_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* No poll */ + tt_ioctl, + NULL, + NULL +}; + +static int __init terratec_init(void) +{ + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + if (check_region(io, 2)) + { + printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io); + return -EBUSY; + } + + terratec_radio.priv=&terratec_unit; + + spin_lock_init(&lock); + + if(video_register_device(&terratec_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 2, "terratec"); + printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n"); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + cardWriteVol(0); + terratec_unit.curvol = 0; + + return 0; +} + +MODULE_AUTHOR("R.OFFERMANNS & others"); +MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); + +EXPORT_NO_SYMBOLS; + +static void __exit terratec_cleanup_module(void) +{ + video_unregister_device(&terratec_radio); + release_region(io,2); + printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); +} + +module_init(terratec_init); +module_exit(terratec_cleanup_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-trust.c linux/drivers/media/radio/radio-trust.c --- v2.4.0-test6/linux/drivers/media/radio/radio-trust.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-trust.c Thu Oct 28 16:13:07 1999 @@ -0,0 +1,350 @@ +/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 + * by Eric Lammerts + * + * Based on radio-aztech.c. Original notes: + * + * Adapted to support the Video for Linux API by + * Russell Kroll . Based on original tuner code by: + * + * Quay Ly + * Donald Song + * Jason Lewis (jlewis@twilight.vtc.vsc.edu) + * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) + * William McGrath (wmcgrath@twilight.vtc.vsc.edu) + * + * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* CONFIG_RADIO_TRUST_PORT */ + +/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ + +#ifndef CONFIG_RADIO_TRUST_PORT +#define CONFIG_RADIO_TRUST_PORT -1 +#endif + +static int io = CONFIG_RADIO_TRUST_PORT; +static int ioval = 0xf; +static int users = 0; +static __u16 curvol; +static __u16 curbass; +static __u16 curtreble; +static unsigned long curfreq; +static int curstereo; +static int curmute; + +/* i2c addresses */ +#define TDA7318_ADDR 0x88 +#define TSA6060T_ADDR 0xc4 + +#define TR_DELAY do { inb(io); inb(io); inb(io); } while(0) +#define TR_SET_SCL outb(ioval |= 2, io) +#define TR_CLR_SCL outb(ioval &= 0xfd, io) +#define TR_SET_SDA outb(ioval |= 1, io) +#define TR_CLR_SDA outb(ioval &= 0xfe, io) + +static void write_i2c(int n, ...) +{ + unsigned char val, mask; + va_list args; + + va_start(args, n); + + /* start condition */ + TR_SET_SDA; + TR_SET_SCL; + TR_DELAY; + TR_CLR_SDA; + TR_CLR_SCL; + TR_DELAY; + + for(; n; n--) { + val = va_arg(args, unsigned); + for(mask = 0x80; mask; mask >>= 1) { + if(val & mask) + TR_SET_SDA; + else + TR_CLR_SDA; + TR_SET_SCL; + TR_DELAY; + TR_CLR_SCL; + TR_DELAY; + } + /* acknowledge bit */ + TR_SET_SDA; + TR_SET_SCL; + TR_DELAY; + TR_CLR_SCL; + TR_DELAY; + } + + /* stop condition */ + TR_CLR_SDA; + TR_DELAY; + TR_SET_SCL; + TR_DELAY; + TR_SET_SDA; + TR_DELAY; + + va_end(args); +} + +static void tr_setvol(__u16 vol) +{ + curvol = vol / 2048; + write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f); +} + +static int basstreble2chip[15] = { + 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 +}; + +static void tr_setbass(__u16 bass) +{ + curbass = bass / 4370; + write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]); +} + +static void tr_settreble(__u16 treble) +{ + curtreble = treble / 4370; + write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]); +} + +static void tr_setstereo(int stereo) +{ + curstereo = !!stereo; + ioval = (ioval & 0xfb) | (!curstereo << 2); + outb(ioval, io); +} + +static void tr_setmute(int mute) +{ + curmute = !!mute; + ioval = (ioval & 0xf7) | (curmute << 3); + outb(ioval, io); +} + +static int tr_getsigstr(void) +{ + int i, v; + + for(i = 0, v = 0; i < 100; i++) v |= inb(io); + return (v & 1)? 0 : 0xffff; +} + +static int tr_getstereo(void) +{ + /* don't know how to determine it, just return the setting */ + return curstereo; +} + +static void tr_setfreq(unsigned long f) +{ + f /= 160; /* Convert to 10 kHz units */ + f += 1070; /* Add 10.7 MHz IF */ + + write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); +} + +static int tr_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + + v.type=VID_TYPE_TUNER; + v.channels=1; + v.audios=1; + + /* No we don't do pictures */ + v.maxwidth=0; + v.maxheight=0; + v.minwidth=0; + v.minheight=0; + + strcpy(v.name, "Trust FM Radio"); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + + if(v.tuner) /* Only 1 tuner */ + return -EINVAL; + + v.rangelow = 87500 * 16; + v.rangehigh = 108000 * 16; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + + v.signal = tr_getsigstr(); + if(tr_getstereo()) + v.flags |= VIDEO_TUNER_STEREO_ON; + + strcpy(v.name, "FM"); + + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner != 0) + return -EINVAL; + + return 0; + } + case VIDIOCGFREQ: + if(copy_to_user(arg, &curfreq, sizeof(curfreq))) + return -EFAULT; + return 0; + + case VIDIOCSFREQ: + { + unsigned long f; + + if(copy_from_user(&f, arg, sizeof(curfreq))) + return -EFAULT; + tr_setfreq(f); + return 0; + } + case VIDIOCGAUDIO: + { + struct video_audio v; + + memset(&v,0, sizeof(v)); + v.flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; + v.mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + v.volume = curvol * 2048; + v.step = 2048; + v.bass = curbass * 4370; + v.treble = curtreble * 4370; + + strcpy(v.name, "Trust FM Radio"); + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + + tr_setvol(v.volume); + tr_setbass(v.bass); + tr_settreble(v.treble); + tr_setstereo(v.mode & VIDEO_SOUND_STEREO); + tr_setmute(v.flags & VIDEO_AUDIO_MUTE); + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int tr_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void tr_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct video_device trust_radio= +{ + "Trust FM Radio", + VID_TYPE_TUNER, + VID_HARDWARE_TRUST, + tr_open, + tr_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* No poll */ + tr_ioctl, + NULL, + NULL +}; + +static int __init trust_init(void) +{ + if(io == -1) { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + if(check_region(io, 2)) { + printk(KERN_ERR "trust: port 0x%x already in use\n", io); + return -EBUSY; + } + if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io, 2, "Trust FM Radio"); + + printk(KERN_INFO "Trust FM Radio card driver v1.0.\n"); + + write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ + write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ + write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ + write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ + write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ + + tr_setvol(0x8000); + tr_setbass(0x8000); + tr_settreble(0x8000); + tr_setstereo(1); + + /* mute card - prevents noisy bootups */ + tr_setmute(1); + + return 0; +} + +MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); + +EXPORT_NO_SYMBOLS; + +static void __exit cleanup_trust_module(void) +{ + video_unregister_device(&trust_radio); + release_region(io, 2); +} + +module_init(trust_init); +module_exit(cleanup_trust_module); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-typhoon.c linux/drivers/media/radio/radio-typhoon.c --- v2.4.0-test6/linux/drivers/media/radio/radio-typhoon.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-typhoon.c Fri Aug 4 18:36:46 2000 @@ -0,0 +1,402 @@ +/* Typhoon Radio Card driver for radio support + * (c) 1999 Dr. Henrik Seidel + * + * Card manufacturer: + * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e + * + * Notes on the hardware + * + * This card has two output sockets, one for speakers and one for line. + * The speaker output has volume control, but only in four discrete + * steps. The line output has neither volume control nor mute. + * + * The card has auto-stereo according to its manual, although it all + * sounds mono to me (even with the Win/DOS drivers). Maybe it's my + * antenna - I really don't know for sure. + * + * Frequency control is done digitally. + * + * Volume control is done digitally, but there are only four different + * possible values. So you should better always turn the volume up and + * use line control. I got the best results by connecting line output + * to the sound card microphone input. For such a configuration the + * volume control has no effect, since volume control only influences + * the speaker output. + * + * There is no explicit mute/unmute. So I set the radio frequency to a + * value where I do expect just noise and turn the speaker volume down. + * The frequency change is necessary since the card never seems to be + * completely silent. + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* radio card status report */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_TYPHOON_* */ + +#define BANNER "Typhoon Radio Card driver v0.1\n" + +#ifndef CONFIG_RADIO_TYPHOON_PORT +#define CONFIG_RADIO_TYPHOON_PORT -1 +#endif + +#ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ +#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 +#endif + +#ifndef CONFIG_PROC_FS +#undef CONFIG_RADIO_TYPHOON_PROC_FS +#endif + +struct typhoon_device { + int users; + int iobase; + int curvol; + int muted; + unsigned long curfreq; + unsigned long mutefreq; +}; + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency); +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); +static void typhoon_mute(struct typhoon_device *dev); +static void typhoon_unmute(struct typhoon_device *dev); +static int typhoon_setvol(struct typhoon_device *dev, int vol); +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg); +static int typhoon_open(struct video_device *dev, int flags); +static void typhoon_close(struct video_device *dev); +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS +static int typhoon_get_info(char *buf, char **start, off_t offset, int len); +#endif + +static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) +{ + vol >>= 14; /* Map 16 bit to 2 bit */ + vol &= 3; + outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */ + outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */ +} + +static int typhoon_setfreq_generic(struct typhoon_device *dev, + unsigned long frequency) +{ + unsigned long outval; + unsigned long x; + + /* + * The frequency transfer curve is not linear. The best fit I could + * get is + * + * outval = -155 + exp((f + 15.55) * 0.057)) + * + * where frequency f is in MHz. Since we don't have exp in the kernel, + * I approximate this function by a third order polynomial. + * + */ + + x = frequency / 160; + outval = (x * x + 2500) / 5000; + outval = (outval * x + 5000) / 10000; + outval -= (10 * x * x + 10433) / 20866; + outval += 4 * x - 11505; + + outb_p((outval >> 8) & 0x01, dev->iobase + 4); + outb_p(outval >> 9, dev->iobase + 6); + outb_p(outval & 0xff, dev->iobase + 8); + + return 0; +} + +static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency) +{ + typhoon_setfreq_generic(dev, frequency); + dev->curfreq = frequency; + return 0; +} + +static void typhoon_mute(struct typhoon_device *dev) +{ + if (dev->muted == 1) + return; + typhoon_setvol_generic(dev, 0); + typhoon_setfreq_generic(dev, dev->mutefreq); + dev->muted = 1; +} + +static void typhoon_unmute(struct typhoon_device *dev) +{ + if (dev->muted == 0) + return; + typhoon_setfreq_generic(dev, dev->curfreq); + typhoon_setvol_generic(dev, dev->curvol); + dev->muted = 0; +} + +static int typhoon_setvol(struct typhoon_device *dev, int vol) +{ + if (dev->muted && vol != 0) { /* user is unmuting the card */ + dev->curvol = vol; + typhoon_unmute(dev); + return 0; + } + if (vol == dev->curvol) /* requested volume == current */ + return 0; + + if (vol == 0) { /* volume == 0 means mute the card */ + typhoon_mute(dev); + dev->curvol = vol; + return 0; + } + typhoon_setvol_generic(dev, vol); + dev->curvol = vol; + return 0; +} + + +static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct typhoon_device *typhoon = dev->priv; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v)) != 0) + return -EFAULT; + if (v.tuner) /* Only 1 tuner */ + return -EINVAL; + v.rangelow = 875 * 1600; + v.rangehigh = 1080 * 1600; + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; /* We can't get the signal strength */ + strcpy(v.name, "FM"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if (copy_to_user(arg, &typhoon->curfreq, + sizeof(typhoon->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if (copy_from_user(&typhoon->curfreq, arg, + sizeof(typhoon->curfreq))) + return -EFAULT; + typhoon_setfreq(typhoon, typhoon->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v, 0, sizeof(v)); + v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; + v.mode |= VIDEO_SOUND_MONO; + v.volume = typhoon->curvol; + v.step = 1 << 14; + strcpy(v.name, "Typhoon Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.audio) + return -EINVAL; + + if (v.flags & VIDEO_AUDIO_MUTE) + typhoon_mute(typhoon); + else + typhoon_unmute(typhoon); + + if (v.flags & VIDEO_AUDIO_VOLUME) + typhoon_setvol(typhoon, v.volume); + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int typhoon_open(struct video_device *dev, int flags) +{ + struct typhoon_device *typhoon = dev->priv; + if (typhoon->users) + return -EBUSY; + typhoon->users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void typhoon_close(struct video_device *dev) +{ + struct typhoon_device *typhoon = dev->priv; + typhoon->users--; + MOD_DEC_USE_COUNT; +} + +static struct typhoon_device typhoon_unit = +{ + 0, /* users */ + CONFIG_RADIO_TYPHOON_PORT, /* iobase */ + 0, /* curvol */ + 0, /* muted */ + CONFIG_RADIO_TYPHOON_MUTEFREQ, /* curfreq */ + CONFIG_RADIO_TYPHOON_MUTEFREQ /* mutefreq */ +}; + +static struct video_device typhoon_radio = +{ + "Typhoon Radio", + VID_TYPE_TUNER, + VID_HARDWARE_TYPHOON, + typhoon_open, + typhoon_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, /* Can't poll */ + typhoon_ioctl, + NULL, + NULL +}; + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + +static int typhoon_get_info(char *buf, char **start, off_t offset, int len) +{ + char *out = buf; + + #ifdef MODULE + #define MODULEPROCSTRING "Driver loaded as a module" + #else + #define MODULEPROCSTRING "Driver compiled into kernel" + #endif + + /* output must be kept under PAGE_SIZE */ + out += sprintf(out, BANNER); + out += sprintf(out, "Load type: " MODULEPROCSTRING "\n\n"); + out += sprintf(out, "frequency = %lu kHz\n", + typhoon_unit.curfreq >> 4); + out += sprintf(out, "volume = %d\n", typhoon_unit.curvol); + out += sprintf(out, "mute = %s\n", typhoon_unit.muted ? + "on" : "off"); + out += sprintf(out, "iobase = 0x%x\n", typhoon_unit.iobase); + out += sprintf(out, "mute frequency = %lu kHz\n", + typhoon_unit.mutefreq >> 4); + return out - buf; +} + +#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ + +MODULE_AUTHOR("Dr. Henrik Seidel"); +MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); +MODULE_PARM(mutefreq, "i"); +MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); + +EXPORT_NO_SYMBOLS; + +static int io = -1; + +#ifdef MODULE +static unsigned long mutefreq = 0; +#endif + +static int __init typhoon_init(void) +{ +#ifdef MODULE + if (io == -1) { + printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); + return -EINVAL; + } + typhoon_unit.iobase = io; + + if (mutefreq < 87000 || mutefreq > 108500) { + printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n"); + printk(KERN_ERR "radio-typhoon: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); + return -EINVAL; + } + typhoon_unit.mutefreq = mutefreq; +#endif /* MODULE */ + + printk(KERN_INFO BANNER); + io = typhoon_unit.iobase; + if (check_region(io, 8)) { + printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", + typhoon_unit.iobase); + return -EBUSY; + } + + typhoon_radio.priv = &typhoon_unit; + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) + return -EINVAL; + + request_region(typhoon_unit.iobase, 8, "typhoon"); + printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); + printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", + typhoon_unit.mutefreq); + typhoon_unit.mutefreq <<= 4; + + /* mute card - prevents noisy bootups */ + typhoon_mute(&typhoon_unit); + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL, + typhoon_get_info)) + printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n"); +#endif + + return 0; +} + +static void __exit typhoon_cleanup_module(void) +{ + +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + remove_proc_entry("driver/radio-typhoon", NULL); +#endif + + video_unregister_device(&typhoon_radio); + release_region(io, 8); +} + +module_init(typhoon_init); +module_exit(typhoon_cleanup_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/radio/radio-zoltrix.c linux/drivers/media/radio/radio-zoltrix.c --- v2.4.0-test6/linux/drivers/media/radio/radio-zoltrix.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-zoltrix.c Thu Oct 28 16:13:13 1999 @@ -0,0 +1,412 @@ +/* zoltrix radio plus driver for Linux radio support + * (c) 1998 C. van Schaik + * + * BUGS + * Due to the inconsistancy in reading from the signal flags + * it is difficult to get an accurate tuned signal. + * + * It seems that the card is not linear to 0 volume. It cuts off + * at a low volume, and it is not possible (at least I have not found) + * to get fine volume control over the low volume range. + * + * Some code derived from code by Romolo Manfredini + * romolo@bicnet.it + * + * 1999-05-06 - (C. van Schaik) + * - Make signal strength and stereo scans + * kinder to cpu while in delay + * 1999-01-05 - (C. van Schaik) + * - Changed tuning to 1/160Mhz accuracy + * - Added stereo support + * (card defaults to stereo) + * (can explicitly force mono on the card) + * (can detect if station is in stereo) + * - Added unmute function + * - Reworked ioctl functions + */ + +#include /* Modules */ +#include /* Initdata */ +#include /* check_region, request_region */ +#include /* udelay */ +#include /* outb, outb_p */ +#include /* copy to/from user */ +#include /* kernel radio structs */ +#include /* CONFIG_RADIO_ZOLTRIX_PORT */ + +#ifndef CONFIG_RADIO_ZOLTRIX_PORT +#define CONFIG_RADIO_ZOLTRIX_PORT -1 +#endif + +static int io = CONFIG_RADIO_ZOLTRIX_PORT; +static int users = 0; + +struct zol_device { + int port; + int curvol; + unsigned long curfreq; + int muted; + unsigned int stereo; + struct semaphore lock; +}; + + +/* local things */ + +static void sleep_delay(void) +{ + /* Sleep nicely for +/- 10 mS */ + schedule(); +} + +static int zol_setvol(struct zol_device *dev, int vol) +{ + dev->curvol = vol; + if (dev->muted) + return 0; + + down(&dev->lock); + if (vol == 0) { + outb(0, io); + outb(0, io); + inb(io + 3); /* Zoltrix needs to be read to confirm */ + up(&dev->lock); + return 0; + } + + outb(dev->curvol-1, io); + sleep_delay(); + inb(io + 2); + up(&dev->lock); + return 0; +} + +static void zol_mute(struct zol_device *dev) +{ + dev->muted = 1; + down(&dev->lock); + outb(0, io); + outb(0, io); + inb(io + 3); /* Zoltrix needs to be read to confirm */ + up(&dev->lock); +} + +static void zol_unmute(struct zol_device *dev) +{ + dev->muted = 0; + zol_setvol(dev, dev->curvol); +} + +static int zol_setfreq(struct zol_device *dev, unsigned long freq) +{ + /* tunes the radio to the desired frequency */ + unsigned long long bitmask, f, m; + unsigned int stereo = dev->stereo; + int i; + + if (freq == 0) + return 1; + m = (freq / 160 - 8800) * 2; + f = (unsigned long long) m + 0x4d1c; + + bitmask = 0xc480402c10080000ull; + i = 45; + + down(&dev->lock); + + outb(0, io); + outb(0, io); + inb(io + 3); /* Zoltrix needs to be read to confirm */ + + outb(0x40, io); + outb(0xc0, io); + + bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31)); + while (i--) { + if ((bitmask & 0x8000000000000000ull) != 0) { + outb(0x80, io); + udelay(50); + outb(0x00, io); + udelay(50); + outb(0x80, io); + udelay(50); + } else { + outb(0xc0, io); + udelay(50); + outb(0x40, io); + udelay(50); + outb(0xc0, io); + udelay(50); + } + bitmask *= 2; + } + /* termination sequence */ + outb(0x80, io); + outb(0xc0, io); + outb(0x40, io); + udelay(1000); + inb(io+2); + + udelay(1000); + + if (dev->muted) + { + outb(0, io); + outb(0, io); + inb(io + 3); + udelay(1000); + } + + up(&dev->lock); + + if(!dev->muted) + { + zol_setvol(dev, dev->curvol); + } + return 0; +} + +/* Get signal strength */ + +int zol_getsigstr(struct zol_device *dev) +{ + int a, b; + + down(&dev->lock); + outb(0x00, io); /* This stuff I found to do nothing */ + outb(dev->curvol, io); + sleep_delay(); + sleep_delay(); + + a = inb(io); + sleep_delay(); + b = inb(io); + + up(&dev->lock); + + if (a != b) + return (0); + + if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */ + || (a == 0xef)) /* with a binary scanner on the card io */ + return (1); + return (0); +} + +int zol_is_stereo (struct zol_device *dev) +{ + int x1, x2; + + down(&dev->lock); + + outb(0x00, io); + outb(dev->curvol, io); + sleep_delay(); + sleep_delay(); + + x1 = inb(io); + sleep_delay(); + x2 = inb(io); + + up(&dev->lock); + + if ((x1 == x2) && (x1 == 0xcf)) + return 1; + return 0; +} + +static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zol_device *zol = dev->priv; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_TUNER; + v.channels = 1 + zol->stereo; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + strcpy(v.name, "Zoltrix Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner) + return -EINVAL; + strcpy(v.name, "FM"); + v.rangelow = (int) (88.0 * 16000); + v.rangehigh = (int) (108.0 * 16000); + v.flags = zol_is_stereo(zol) + ? VIDEO_TUNER_STEREO_ON : 0; + v.flags |= VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF * zol_getsigstr(zol); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.tuner != 0) + return -EINVAL; + /* Only 1 tuner so no setting needed ! */ + return 0; + } + case VIDIOCGFREQ: + if (copy_to_user(arg, &zol->curfreq, sizeof(zol->curfreq))) + return -EFAULT; + return 0; + case VIDIOCSFREQ: + if (copy_from_user(&zol->curfreq, arg, sizeof(zol->curfreq))) + return -EFAULT; + zol_setfreq(zol, zol->curfreq); + return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + memset(&v, 0, sizeof(v)); + v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; + v.mode != zol_is_stereo(zol) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + v.volume = zol->curvol * 4096; + v.step = 4096; + strcpy(v.name, "Zoltrix Radio"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.audio) + return -EINVAL; + + if (v.flags & VIDEO_AUDIO_MUTE) + zol_mute(zol); + else + { + zol_unmute(zol); + zol_setvol(zol, v.volume / 4096); + } + + if (v.mode & VIDEO_SOUND_STEREO) + { + zol->stereo = 1; + zol_setfreq(zol, zol->curfreq); + } + if (v.mode & VIDEO_SOUND_MONO) + { + zol->stereo = 0; + zol_setfreq(zol, zol->curfreq); + } + + return 0; + } + default: + return -ENOIOCTLCMD; + } +} + +static int zol_open(struct video_device *dev, int flags) +{ + if (users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void zol_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + +static struct zol_device zoltrix_unit; + +static struct video_device zoltrix_radio = +{ + "Zoltrix Radio Plus", + VID_TYPE_TUNER, + VID_HARDWARE_ZOLTRIX, + zol_open, + zol_close, + NULL, /* Can't read (no capture ability) */ + NULL, /* Can't write */ + NULL, + zol_ioctl, + NULL, + NULL +}; + +static int __init zoltrix_init(void) +{ + if (io == -1) { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + if (check_region(io, 2)) { + printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); + return -EBUSY; + } + if ((io != 0x20c) && (io != 0x30c)) { + printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n"); + return -ENXIO; + } + zoltrix_radio.priv = &zoltrix_unit; + + if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1) + return -EINVAL; + + request_region(io, 2, "zoltrix"); + printk(KERN_INFO "Zoltrix Radio Plus card driver.\n"); + + init_MUTEX(&zoltrix_unit.lock); + + /* mute card - prevents noisy bootups */ + + /* this ensures that the volume is all the way down */ + + outb(0, io); + outb(0, io); + sleep_delay(); + sleep_delay(); + inb(io + 3); + + zoltrix_unit.curvol = 0; + zoltrix_unit.stereo = 1; + + return 0; +} + +MODULE_AUTHOR("C.van Schaik"); +MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); + +EXPORT_NO_SYMBOLS; + +static void __exit zoltrix_cleanup_module(void) +{ + video_unregister_device(&zoltrix_radio); + release_region(io, 2); +} + +module_init(zoltrix_init); +module_exit(zoltrix_cleanup_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/Config.in linux/drivers/media/video/Config.in --- v2.4.0-test6/linux/drivers/media/video/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/Config.in Wed Aug 23 14:59:55 2000 @@ -0,0 +1,45 @@ +# +# Multimedia Video device configuration +# +mainmenu_option next_comment +comment 'Video For Linux' + +bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS +dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C + +comment 'Video Adapters' +if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT +fi +dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV +if [ "$CONFIG_ALL_PPC" = "y" ]; then + dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV +fi +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + fi +fi +dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then + if [ "CONFIG_PARPORT_1284" != "n" ]; then + dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT + fi + if [ "$CONFIG_USB" != "n" ]; then + dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB + fi +fi +dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C +dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_SGI" = "y" ]; then + dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI + fi + dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI +fi +dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN +dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C + +endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/Makefile linux/drivers/media/video/Makefile --- v2.4.0-test6/linux/drivers/media/video/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/Makefile Tue Aug 22 11:29:02 2000 @@ -0,0 +1,96 @@ +# +# Makefile for the kernel character device 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.. +# + +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := video.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := i2c-old.o videodev.o bttv-if.o cpia.o + +list-multi := bttv.o zoran.o +bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o +zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o + +obj-$(CONFIG_VIDEO_DEV) += videodev.o + +obj-$(CONFIG_BUS_I2C) += i2c-old.o +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \ + tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o +obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o + +obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o +obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o +obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o +obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o +obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o +obj-$(CONFIG_VIDEO_PMS) += pms.o +obj-$(CONFIG_VIDEO_PLANB) += planb.o +obj-$(CONFIG_VIDEO_VINO) += vino.o +obj-$(CONFIG_VIDEO_STRADIS) += stradis.o +obj-$(CONFIG_VIDEO_CPIA) += cpia.o +obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o +obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o +obj-$(CONFIG_TUNER_3036) += tuner-3036.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make + +fastdep: + +zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o + $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o + +bttv.o: $(bttv-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(bttv-objs) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/audiochip.h linux/drivers/media/video/audiochip.h --- v2.4.0-test6/linux/drivers/media/video/audiochip.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/audiochip.h Thu Dec 16 13:59:38 1999 @@ -0,0 +1,60 @@ +#ifndef AUDIOCHIP_H +#define AUDIOCHIP_H + +/* ---------------------------------------------------------------------- */ + +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +/* v4l device was opened in Radio mode */ +#define AUDC_SET_RADIO _IO('m',2) +/* select from TV,radio,extern,MUTE */ +#define AUDC_SET_INPUT _IOW('m',17,int) + +/* all the stuff below is obsolete and just here for reference. I'll + * remove it once the driver is tested and works fine. + * + * Instead creating alot of tiny API's for all kinds of different + * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not + * yet...). It is a bit less flexible, but most/all used i2c chips + * make sense in v4l context only. So I think that's acceptable... + */ + +#if 0 + +/* TODO (if it is ever [to be] accessible in the V4L[2] spec): + * maybe fade? (back/front) + * notes: + * NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special + * routine to go through when it tunes in to a new channel before turning + * back on the sound. + * Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be + * implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for + * channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV, + * radio, external, or MUTE]). If both methods are implemented, you get a + * cookie for doing such a good job! :) + */ + +#define AUDC_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ +#define AUDC_NEWCHANNEL _IO('m',3) /* indicate new chan - off mute */ + +#define AUDC_GET_VOLUME_LEFT _IOR('m',4,__u16) +#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16) +#define AUDC_SET_VOLUME_LEFT _IOW('m',6,__u16) +#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16) + +#define AUDC_GET_STEREO _IOR('m',8,__u16) +#define AUDC_SET_STEREO _IOW('m',9,__u16) + +#define AUDC_GET_DC _IOR('m',10,__u16)/* ??? */ + +#define AUDC_GET_BASS _IOR('m',11,__u16) +#define AUDC_SET_BASS _IOW('m',12,__u16) +#define AUDC_GET_TREBLE _IOR('m',13,__u16) +#define AUDC_SET_TREBLE _IOW('m',14,__u16) + +#define AUDC_GET_UNIT _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */ +#define AUDC_SWITCH_MUTE _IO('m',16) /* turn on mute */ +#endif + +#endif /* AUDIOCHIP_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/bt848.h linux/drivers/media/video/bt848.h --- v2.4.0-test6/linux/drivers/media/video/bt848.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bt848.h Tue Jul 18 22:35:33 2000 @@ -0,0 +1,355 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 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 +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* 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_PLOCK (1<<2) +#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_NTSC_J 2 +#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_PAL_NC 7 +#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_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (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) + + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c --- v2.4.0-test6/linux/drivers/media/video/bttv-cards.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bttv-cards.c Sun Aug 6 12:45:28 2000 @@ -0,0 +1,835 @@ +/* + bttv-cards.c -- this file has card-specific stuff + + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999,2000 Gerd Knorr + + 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. + +*/ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include + +#include + +#include "bttv.h" +#include "tuner.h" + +/* fwd decl */ +static void hauppauge_eeprom(struct bttv *btv); +static void hauppauge_boot_msp34xx(struct bttv *btv); +static void init_PXC200(struct bttv *btv); +static void init_tea5757(struct bttv *btv); + +MODULE_PARM(card,"1-4i"); +MODULE_PARM(pll,"1-4i"); +MODULE_PARM(autoload,"i"); + +static unsigned int card[4] = { -1, -1, -1, -1 }; +static unsigned int pll[4] = { -1, -1, -1, -1 }; +#ifdef MODULE +static unsigned int autoload = 1; +#else +static unsigned int autoload = 0; +#endif + +/* ----------------------------------------------------------------------- */ +/* list of card IDs for bt878+ cards */ + +static struct CARD { + unsigned id; + int cardnr; + char *name; +} cards[] __devinitdata = { + { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, + { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00021461, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, + { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00041461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, + { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" }, + { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV/Radio+" }, + { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, + { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, + { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, + { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, + { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, + { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" }, + { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, + { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, + { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, + { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, + { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" }, +#if 0 /* probably wrong */ + { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, + { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, +#endif + { 0, -1, NULL } +}; + +/* ----------------------------------------------------------------------- */ +/* array with description for bt848 / bt878 tv/grabber cards */ + +struct tvcard bttv_tvcards[] = +{ + /* 0x00 */ + { " *** UNKNOWN *** ", + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "MIRO PCTV", + 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Hauppauge old", + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0,0,0,1, PLL_NONE, -1 }, + { "STB", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,1,0,0,1, PLL_NONE, -1 }, + + { "Intel", + 3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Diamond DTV2000", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "AVerMedia TVPhone", + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "MATRIX-Vision MV-Delta", + 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x08 */ + { "Fly Video II", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, + { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "TurboTV", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Hauppauge new (bt878)", + 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0,0,0,1, PLL_28, -1 }, + { "MIRO PCTV pro", + 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, + /* 3, 1, 0, 2, 0x3004F, { 2, 3, 1, 1}, {1, 0x10011, 5, 0,10}, 0x3004F, */ + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + { "ADS Technologies Channel Surfer TV", + 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "AVerMedia TVCapture 98", + 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Aimslab VHX", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Zoltrix TV-Max", + 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x10 */ + { "Pixelview PlayTV (bt878)", + 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1}, + { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Leadtek WinView 601", + 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, + { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "AVEC Intercapture", + 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "LifeView FlyKit w/o Tuner", + 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, + 0,0,0,0,0,0,0,1, PLL_NONE, -1 }, + + { "CEI Raffles Card", + 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Lucky Star Image World ConferenceTV", + 3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_28, TUNER_PHILIPS_PAL_I }, + { "Phoebe Tv Master + FM", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Modular Technology MM205 PCTV, bt878", + 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x18 */ + { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)", + 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Terratec/Vobis TV-Boostar", + 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Newer Hauppauge WinCam (bt878)", + 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "MAXI TV Video PCI2", + 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, + 1,1,1,1,0,0,0,1, PLL_NONE, TUNER_PHILIPS_SECAM }, + + { "Terratec TerraTV+", + 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, + { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Imagenation PXC200", + 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "FlyVideo 98", + 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, + { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "iProTV", + 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x20 */ + { "Intel Create and Share PCI", + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Terratec TerraTValue", + 3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1}, + { 0x500, 0, 0x300, 0x900, 0x900},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Leadtek WinFast 2000", + 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, + { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},0, + 1,1,1,1,1,0,0,1, PLL_28, -1 }, + { "Chronos Video Shuttle II", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + + { "Typhoon TView TV/FM Tuner", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "PixelView PlayTV pro", + 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, + { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0, + 0,0,0,0,0,0,0,1, PLL_28, -1 }, + { "TView99 CPH063", + 3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1}, + { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Pinnacle PCTV Rave", + 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + + /* 0x28 */ + { "STB2", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,0,1,1,1, PLL_NONE, -1 }, + { "AVerMedia TVPhone 98", + 3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, 5 }, + { "ProVideo PV951", /* pic16c54 */ + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 0,0,0,0,0,0,0,0, PLL_28, 1 }, + { "Little OnAir TV", + 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1}, + {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, + + { "Sigma TVII-FM", + 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, + { "MATRIX-Vision MV-Delta 2", + 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, + 0,0,0,0,0,0,0,0, PLL_28, -1 }, + { "Zoltrix Genie TV", + 3, 1, 0, 2, 0xbcf03f, { 2, 3, 1, 1}, + { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f}, 0, + 0,0,0,0,0,0,0,0, PLL_28, 5 }, + { "Terratec TV/Radio+", /* Radio ?? */ + 3, 1, 0, 2, 0x1f0000, { 2, 3, 1, 1}, + { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },0, + 0,0,0,0,0,0,0,0, PLL_35, 1 }, + + /* 0x30 */ + { "Dynalink Magic TView ", + 3, 1, 0, 2, 15, { 2, 3, 1, 1}, {2,0,0,0,1},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, +}; +const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); + +/* ----------------------------------------------------------------------- */ + +static unsigned char eeprom_data[256]; + +static void __devinit bttv_dump_eeprom(struct bttv *btv,int addr) +{ + int i; + + if (bttv_verbose < 2) + return; + /* for debugging: dump eeprom to syslog */ + printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); + for (i = 0; i < 256;) { + printk(KERN_DEBUG " %02x:",i); + do { + printk(" %02x",eeprom_data[i++]); + } while (i % 16); + printk("\n"); + } +} + +static int __devinit bttv_idcard_eeprom(struct bttv *btv) +{ + unsigned id; + int i,n; + + id = (eeprom_data[252] << 24) | + (eeprom_data[253] << 16) | + (eeprom_data[254] << 8) | + (eeprom_data[255]); + if (id == 0 || id == 0xffffffff) + return -1; + + /* look for the card */ + btv->cardid = id; + for (n = -1, i = 0; cards[i].id != 0; i++) + if (cards[i].id == id) + n = i; + + if (n != -1) { + /* found it */ + printk(KERN_INFO "bttv%d: card id: %s (0x%08x) => card=%d\n", + btv->nr,cards[n].name,id,cards[n].cardnr); + return cards[n].cardnr; + } else { + /* 404 */ + printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n", + btv->nr, id); + printk(KERN_INFO "please mail id, board name and " + "the correct card= insmod option to " + "kraxel@goldbach.in-berlin.de\n"); + return -1; + } +} + +#ifndef HAVE_TVAUDIO +/* can tda9855.c handle this too maybe? */ +static void __devinit init_tda9840(struct bttv *btv) +{ + /* Horrible Hack */ + bttv_I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ + /* 00 - mute + 10 - mono / averaged stereo + 2a - stereo + 12 - dual A + 1a - dual AB + 16 - dual BA + 1e - dual B + 7a - external */ +} +#endif + +void __devinit bttv_idcard(struct bttv *btv) +{ + int type,eeprom = 0; + + btwrite(0, BT848_GPIO_OUT_EN); + + /* try to autodetect the card */ + /* many bt878 cards have a eeprom @ 0xa0 => read ID + and try to identify it */ + if (bttv_I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { + eeprom = 0xa0; + bttv_readee(btv,eeprom_data,0xa0); + bttv_dump_eeprom(btv,0xa0); /* DEBUG */ + type = bttv_idcard_eeprom(btv); + if (-1 != type) { + btv->type = type; + } else if (btv->id <= 849) { + /* for unknown bt848, assume old Hauppauge */ + btv->type=BTTV_HAUPPAUGE; + } + + /* STB cards have a eeprom @ 0xae (old bt848) */ + } else if (bttv_I2CRead(btv, I2C_STBEE, "eeprom")>=0) { + btv->type=BTTV_STB; + } + + /* let the user override the autodetected type */ + if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) + btv->type=card[btv->nr]; + + /* print which card config we are using */ + sprintf(btv->video_dev.name,"BT%d%s(%.23s)", + btv->id, + (btv->id==848 && btv->revision==0x12) ? "A" : "", + bttv_tvcards[btv->type].name); + printk(KERN_INFO "bttv%d: model: %s [%s]\n",btv->nr,btv->video_dev.name, + (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ? + "insmod option" : "autodetected"); + + /* board specific initialisations */ + if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { + /* auto detect tuner for MIRO cards */ + btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; +#if 0 + if (btv->type == BTTV_MIROPRO) { + if (bttv_verbose) + printk(KERN_INFO "Initializing TEA5757...\n"); + init_tea5757(btv); + } +#endif + } + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { + /* pick up some config infos from the eeprom */ + if (0xa0 != eeprom) { + eeprom = 0xa0; + bttv_readee(btv,eeprom_data,0xa0); + } + hauppauge_eeprom(btv); + hauppauge_boot_msp34xx(btv); + } + if (btv->type == BTTV_PXC200) + init_PXC200(btv); + + /* pll configuration */ + if (!(btv->id==848 && btv->revision==0x11)) { + /* defaults from card list */ + if (PLL_28 == bttv_tvcards[btv->type].pll) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; + } + /* insmod options can override */ + switch (pll[btv->nr]) { + case 0: /* none */ + btv->pll.pll_crystal = 0; + btv->pll.pll_ifreq = 0; + btv->pll.pll_ofreq = 0; + break; + case 1: /* 28 MHz */ + btv->pll.pll_ifreq = 28636363; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal=BT848_IFORM_XT0; + break; + case 2: /* 35 MHz */ + btv->pll.pll_ifreq = 35468950; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal=BT848_IFORM_XT1; + break; + } + } + + + /* tuner configuration */ + if (-1 != bttv_tvcards[btv->type].tuner_type) + btv->tuner_type = bttv_tvcards[btv->type].tuner_type; + if (btv->tuner_type != -1) + bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + + /* try to detect audio/fader chips */ + if (bttv_tvcards[btv->type].msp34xx && + bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { + if (autoload) + request_module("msp3400"); + } + +#ifndef HAVE_TVAUDIO + if (bttv_tvcards[btv->type].tda8425 && + bttv_I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) { + if (autoload) + request_module("tda8425"); + } + + if (bttv_tvcards[btv->type].tda9840 && + bttv_I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) { + init_tda9840(btv); + btv->audio_chip = TDA9840; + /* move this to a module too? */ + init_tda9840(btv); + } + + if (bttv_tvcards[btv->type].tda985x && + bttv_I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { + if (autoload) + request_module("tda985x"); + } + if (bttv_tvcards[btv->type].tea63xx) { + if (autoload) + request_module("tea6300"); + } +#else + if (bttv_tvcards[btv->type].tda8425 || + bttv_tvcards[btv->type].tda9840 || + bttv_tvcards[btv->type].tda985x || + bttv_tvcards[btv->type].tea63xx) { + if (autoload) + request_module("tvaudio"); + } +#endif + + if (bttv_tvcards[btv->type].tda9875 && + bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { + if (autoload) + request_module("tda9875"); + } + + if (bttv_tvcards[btv->type].tda7432 && + bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { + if (autoload) + request_module("tda7432"); + } + + + if (bttv_tvcards[btv->type].tea64xx) { + if (autoload) + request_module("tea6420"); + } + + if (bttv_tvcards[btv->type].tuner != -1) { + if (autoload) + request_module("tuner"); + } +} + + +/* ----------------------------------------------------------------------- */ +/* some hauppauge specific stuff */ + +static struct HAUPPAUGE_TUNER +{ + int id; + char *name; +} +hauppauge_tuner[] __devinitdata = +{ + { TUNER_ABSENT, "" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_ABSENT, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_ABSENT, "Philips FI1246" }, + { TUNER_ABSENT, "Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_ABSENT, "Philips FI1256 MK2" }, + { TUNER_ABSENT, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_ABSENT, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + { TUNER_ABSENT, "Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_ABSENT, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_ABSENT, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_PAL, "Temic 4006FH5" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_ABSENT, "Temic 4039FR5" }, + { TUNER_ABSENT, "Philips FQ1216 ME" }, + { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, + { TUNER_ABSENT, "Philips TD1536" }, + { TUNER_ABSENT, "Philips TD1536D" }, + { TUNER_ABSENT, "Philips FMR1236" }, + { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Temic 4006FN5" }, + { TUNER_ABSENT, "Temic 4009FR5" }, + { TUNER_ABSENT, "Temic 4046FM5" }, +}; + +static void __devinit hauppauge_eeprom(struct bttv *btv) +{ + if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) + { + btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; + if (bttv_verbose) + printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, + hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); + } +} + +static void __devinit hauppauge_boot_msp34xx(struct bttv *btv) +{ + int i; + + /* reset/enable the MSP on some Hauppauge cards */ + /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ + btaor(32, ~32, BT848_GPIO_OUT_EN); + btaor(0, ~32, BT848_GPIO_DATA); + udelay(2500); + btaor(32, ~32, BT848_GPIO_DATA); + + if (bttv_verbose) + printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); + + /* look if the msp3400 driver is already registered */ + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] != NULL && + btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { + return; + } + } + + /* if not: look for the chip ... */ + if (bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx")) { + /* ... if found re-register to trigger a i2c bus rescan, */ + /* this time with the msp34xx chip activated */ + i2c_bit_del_bus(&btv->i2c_adap); + i2c_bit_add_bus(&btv->i2c_adap); + } +} + + +/* ----------------------------------------------------------------------- */ +/* Imagenation L-Model PXC200 Framegrabber */ +/* This is basically the same procedure as + * used by Alessandro Rubini in his pxc200 + * driver, but using BTTV functions */ + +static void __devinit init_PXC200(struct bttv *btv) +{ + static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x00 }; + int i,tmp; + + /* Initialise GPIO-connevted stuff */ + btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ + btwrite(0,BT848_GPIO_DATA); + udelay(3); + btwrite(1<<13,BT848_GPIO_DATA); + /* GPIO inputs are pulled up, so no need to drive + * reset pin any longer */ + btwrite(0,BT848_GPIO_OUT_EN); + + /* we could/should try and reset/control the AD pots? but + right now we simply turned off the crushing. Without + this the AGC drifts drifts + remember the EN is reverse logic --> + setting BT848_ADC_AGC_EN disable the AGC + tboult@eecs.lehigh.edu + */ + btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); + + /* Initialise MAX517 DAC */ + printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + bttv_I2CWrite(btv,0x5E,0,0x80,1); + + /* Initialise 12C508 PIC */ + /* The I2CWrite and I2CRead commmands are actually to the + * same chips - but the R/W bit is included in the address + * argument so the numbers are different */ + + printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + + for (i = 0; i < sizeof(vals)/sizeof(int); i++) { + tmp=bttv_I2CWrite(btv,0x1E,vals[i],0,1); + printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n", + tmp,bttv_I2CRead(btv,0x1F,NULL)); + } + printk(KERN_INFO "PXC200 Initialised.\n"); +} + +/* ----------------------------------------------------------------------- */ +/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */ +/* + * Copyright (c) 1999 Csaba Halasz + * This code is placed under the terms of the GNU General Public License + * + * Brutally hacked by Dan Sheridan djs52 8/3/00 + */ + +/* bus bits on the GPIO port */ +#define TEA_WE 6 +#define TEA_DATA 9 +#define TEA_CLK 8 +#define TEA_MOST 7 + +#define BUS_LOW(bit) btand(~(1<> TEA_##bit) & 1) + +/* TEA5757 register bits */ +#define TEA_FREQ 0:14 +#define TEA_BUFFER 15:15 + +#define TEA_SIGNAL_STRENGTH 16:17 + +#define TEA_PORT1 18:18 +#define TEA_PORT0 19:19 + +#define TEA_BAND 20:21 +#define TEA_BAND_FM 0 +#define TEA_BAND_MW 1 +#define TEA_BAND_LW 2 +#define TEA_BAND_SW 3 + +#define TEA_MONO 22:22 +#define TEA_ALLOW_STEREO 0 +#define TEA_FORCE_MONO 1 + +#define TEA_SEARCH_DIRECTION 23:23 +#define TEA_SEARCH_DOWN 0 +#define TEA_SEARCH_UP 1 + +#define TEA_STATUS 24:24 +#define TEA_STATUS_TUNED 0 +#define TEA_STATUS_SEARCHING 1 + +/* Low-level stuff */ +static int tea_read(struct bttv *btv) +{ + int value = 0; + long timeout; + int i; + + /* better safe than sorry */ + btaor((1<volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + data = btread(BT848_GPIO_DATA); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1< + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HACKING +# include +#endif + +#include "bttv.h" +#include "tuner.h" + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + + +static void bt848_set_risc_jmps(struct bttv *btv, int state); + +int bttv_num; /* number of Bt848s in use */ +struct bttv bttvs[BTTV_MAX]; + + +/* insmod args */ +MODULE_PARM(triton1,"i"); +MODULE_PARM(radio,"1-4i"); +MODULE_PARM(bigendian,"i"); +MODULE_PARM(fieldnr,"i"); +MODULE_PARM(bttv_verbose,"i"); +MODULE_PARM(bttv_debug,"i"); +MODULE_PARM(gbuffers,"i"); +MODULE_PARM(gbufsize,"i"); + +MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); + +#if defined(__sparc__) || defined(__powerpc__) +static unsigned int bigendian=1; +#else +static unsigned int bigendian=0; +#endif +static int triton1=0; +static unsigned int radio[BTTV_MAX]; +static unsigned int fieldnr = 0; +static unsigned int gbuffers = 2; +static unsigned int gbufsize = BTTV_MAX_FBUF; +unsigned int bttv_debug = 0; +unsigned int bttv_verbose = 1; + +#define I2C_TIMING (0x7<<4) +#define I2C_DELAY 10 + +#define I2C_SET(CTRL,DATA) \ + { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } +#define I2C_GET() (btread(BT848_I2C)&1) + +#define BURSTOFFSET 76 +#define BTTV_ERRORS 5 + + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + } + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void * rvmalloc(signed long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, signed long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + + + +/* + * Create the giant waste of buffer space we need for now + * until we get DMA to user space sorted out (probably 2.3.x) + * + * We only create this as and when someone uses mmap + */ + +static int fbuffer_alloc(struct bttv *btv) +{ + if(!btv->fbuffer) + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); + else + printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", + btv->nr); + if(!btv->fbuffer) + return -ENOBUFS; + return 0; +} + + +static int __devinit init_bttv_i2c(struct bttv *btv) +{ + /* i2c bit_adapter */ + memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter)); + memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); + memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client)); + + sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), + " #%d", btv->nr); + btv->i2c_algo.data = btv; + btv->i2c_adap.data = btv; + btv->i2c_adap.algo_data = &btv->i2c_algo; + btv->i2c_client.adapter = &btv->i2c_adap; + + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); + + btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap); + return btv->i2c_ok; +} + + +/* ----------------------------------------------------------------------- */ + +static void audio(struct bttv *btv, int mode, int no_irq_context) +{ + btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask, + BT848_GPIO_OUT_EN); + + switch (mode) + { + case AUDIO_MUTE: + btv->audio|=AUDIO_MUTE; + break; + 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 audio mute or not in H-lock, turn audio off */ + if ((btv->audio&AUDIO_MUTE)) + mode=AUDIO_OFF; + if ((mode == AUDIO_TUNER) && (btv->radio)) + mode = AUDIO_RADIO; + btaor(bttv_tvcards[btv->type].audiomux[mode], + ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); + if (no_irq_context) + bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); +} + + +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); +} + + +/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/ + +/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C + PLL_X = Reference pre-divider (0=1, 1=2) + PLL_C = Post divider (0=6, 1=4) + PLL_I = Integer input + PLL_F = Fractional input + + F_input = 28.636363 MHz: + PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0 +*/ + +static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout) +{ + unsigned char fl, fh, fi; + + /* prevent overflows */ + fin/=4; + fout/=4; + + fout*=12; + fi=fout/fin; + + fout=(fout%fin)*256; + fh=fout/fin; + + fout=(fout%fin)*256; + fl=fout/fin; + + /*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/ + btwrite(fl, BT848_PLL_F_LO); + btwrite(fh, BT848_PLL_F_HI); + btwrite(fi|BT848_PLL_X, BT848_PLL_XCI); +} + +static int set_pll(struct bttv *btv) +{ + int i; + unsigned long tv; + + if (!btv->pll.pll_crystal) + return 0; + + if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { + /* no PLL needed */ + if (btv->pll.pll_current == 0) { + /* printk ("bttv%d: PLL: is off\n",btv->nr); */ + return 0; + } + printk ("bttv%d: PLL: switching off\n",btv->nr); + btwrite(0x00,BT848_TGCTRL); + btwrite(0x00,BT848_PLL_XCI); + btv->pll.pll_current = 0; + return 0; + } + + if (btv->pll.pll_ofreq == btv->pll.pll_current) { + /* printk("bttv%d: PLL: no change required\n",btv->nr); */ + return 1; + } + + if (bttv_verbose) + printk("bttv%d: PLL: %d => %d ... ",btv->nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + /* Let other people run while the PLL stabilizes */ + tv=jiffies+HZ/10; /* .1 seconds */ + do + { + schedule(); + } + while(time_before(jiffies,tv)); + + for (i=0; i<100; i++) + { + if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK)) + btwrite(0,BT848_DSTATUS); + else + { + btwrite(0x08,BT848_TGCTRL); + btv->pll.pll_current = btv->pll.pll_ofreq; + if (bttv_verbose) + printk("ok\n"); + return 1; + } + mdelay(10); + } + btv->pll.pll_current = 0; + if (bttv_verbose) + printk("oops\n"); + return -1; +} + +static void bt848_muxsel(struct bttv *btv, unsigned int input) +{ + btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2, + BT848_GPIO_OUT_EN); + + /* This seems to get rid of some synchronization problems */ + btand(~(3<<5), BT848_IFORM); + mdelay(10); + + + input %= bttv_tvcards[btv->type].video_inputs; + if (input==bttv_tvcards[btv->type].svhs) + { + 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); + } + btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); + audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? + AUDIO_EXTERN : AUDIO_TUNER, 1); + btaor(bttv_tvcards[btv->type].muxsel[input]>>4, + ~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); +} + + +struct tvnorm +{ + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; +}; + +static struct tvnorm tvnorms[] = { + /* PAL-BDGHI */ + /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ + /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ + { 35468950, + 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + 1135, 186, 924, 0x20, 255}, + + /* NTSC */ + { 28636363, + 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), + 910, 128, 910, 0x1a, 144}, +#if 0 + /* SECAM EAST */ + { 35468950, + 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), + 944, 186, 922, 0x20, 255}, +#else + /* SECAM L */ + { 35468950, + 924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), + 1135, 186, 922, 0x20, 255}, +#endif + /* PAL-NC */ + { 28636363, + 640, 576, 910, 0x68, 0x5d, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), + 780, 130, 734, 0x1a, 144}, + /* PAL-M */ + { 28636363, + 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0), + 780, 135, 754, 0x1a, 144}, + /* PAL-N */ + { 35468950, + 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1), + 944, 186, 922, 0x20, 144}, + /* NTSC-Japan */ + { 28636363, + 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), + 780, 135, 754, 0x16, 144}, +}; +#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) +#define VBI_SPL 2044 + +/* RISC command to write one VBI data line */ +#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL + +static void make_vbitab(struct bttv *btv) +{ + int i; + unsigned int *po=(unsigned int *) btv->vbi_odd; + unsigned int *pe=(unsigned int *) btv->vbi_even; + + if (bttv_debug > 1) + printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); + + *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; + for (i=0; i<16; i++) + { + *(po++)=cpu_to_le32(VBI_RISC); + *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); + } + *(po++)=cpu_to_le32(BT848_RISC_JUMP); + *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + + *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0; + for (i=16; i<32; i++) + { + *(pe++)=cpu_to_le32(VBI_RISC); + *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); + } + *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); + *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + + if (bttv_debug > 1) + printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); +} + +static int fmtbppx2[16] = { + 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 +}; + +static int palette2fmt[] = { + 0, + BT848_COLOR_FMT_Y8, + BT848_COLOR_FMT_RGB8, + BT848_COLOR_FMT_RGB16, + BT848_COLOR_FMT_RGB24, + BT848_COLOR_FMT_RGB32, + BT848_COLOR_FMT_RGB15, + BT848_COLOR_FMT_YUY2, + BT848_COLOR_FMT_BtYUV, + -1, + -1, + -1, + BT848_COLOR_FMT_RAW, + BT848_COLOR_FMT_YCrCb422, + BT848_COLOR_FMT_YCrCb411, + BT848_COLOR_FMT_YCrCb422, + BT848_COLOR_FMT_YCrCb411, +}; +#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int)) + +static int make_rawrisctab(struct bttv *btv, unsigned int *ro, + unsigned int *re, unsigned int *vbuf) +{ + unsigned long line; + unsigned long bpl=1024; /* bytes per line */ + unsigned long vadr=(unsigned long) vbuf; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY + is 2 and without separate VBI grabbing. + We'll have to handle this inside the IRQ handler ... */ + + for (line=0; line < 640; line++) + { + *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); + *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); + vadr+=bpl; + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + return 0; +} + +static int make_prisctab(struct bttv *btv, unsigned int *ro, + unsigned int *re, + unsigned int *vbuf, unsigned short width, + unsigned short height, unsigned short fmt) +{ + unsigned long line, lmask; + unsigned long bl, blcr, blcb, rcmd; + unsigned long todo; + unsigned int **rp; + int inter; + unsigned long cbadr, cradr; + unsigned long vadr=(unsigned long) vbuf; + int shift, csize; + + if (bttv_debug > 1) + printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + switch(fmt) + { + case VIDEO_PALETTE_YUV422P: + csize=(width*height)>>1; + shift=1; + lmask=0; + break; + + case VIDEO_PALETTE_YUV411P: + csize=(width*height)>>2; + shift=2; + lmask=0; + break; + + case VIDEO_PALETTE_YUV420P: + csize=(width*height)>>2; + shift=1; + lmask=1; + break; + + case VIDEO_PALETTE_YUV410P: + csize=(width*height)>>4; + shift=2; + lmask=3; + break; + + default: + return -1; + } + cbadr=vadr+(width*height); + cradr=cbadr+csize; + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(re++)=0; + + for (line=0; line < (height<<(1^inter)); line++) + { + if(line==height) + { + vadr+=csize<<1; + cbadr=vadr+(width*height); + cradr=cbadr+csize; + } + if (inter) + rp= (line&1) ? &re : &ro; + else + rp= (line>=height) ? &ro : &re; + + + if(line&lmask) + rcmd=BT848_RISC_WRITE1S23|BT848_RISC_SOL; + else + rcmd=BT848_RISC_WRITE123|BT848_RISC_SOL; + + todo=width; + while(todo) + { + bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); + blcr=(PAGE_SIZE-((PAGE_SIZE-1)&cradr))<todo) ? todo : bl; + blcr=bl>>shift; + blcb=blcr; + /* bl now containts the longest row that can be written */ + todo-=bl; + if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */ + + *((*rp)++)=cpu_to_le32(rcmd|bl); + *((*rp)++)=cpu_to_le32(blcb|(blcr<<16)); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=bl; + if((rcmd&(15<<28))==BT848_RISC_WRITE123) + { + *((*rp)++)=(kvirt_to_bus(cbadr)); + cbadr+=blcb; + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); + cradr+=blcr; + } + + rcmd&=~BT848_RISC_SOL; /* only the first has SOL */ + } + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (bttv_debug > 1) + printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + return 0; +} + +static int make_vrisctab(struct bttv *btv, unsigned int *ro, + unsigned int *re, + unsigned int *vbuf, unsigned short width, + unsigned short height, unsigned short palette) +{ + unsigned long line; + unsigned long bpl; /* bytes per line */ + unsigned long bl; + unsigned long todo; + unsigned int **rp; + int inter; + unsigned long vadr=(unsigned long) vbuf; + + if (palette==VIDEO_PALETTE_RAW) + return make_rawrisctab(btv, ro, re, vbuf); + if (palette>=VIDEO_PALETTE_PLANAR) + return make_prisctab(btv, ro, re, vbuf, width, height, palette); + + if (bttv_debug > 1) + printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; + bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + for (line=0; line < (height<<(1^inter)); line++) + { + if (inter) + rp= (line&1) ? &re : &ro; + else + rp= (line>=height) ? &ro : &re; + + bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); + if (bpl<=bl) + { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=bpl; + } + else + { + todo=bpl; + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=bl; + todo-=bl; + while (todo>PAGE_SIZE) + { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=PAGE_SIZE; + todo-=PAGE_SIZE; + } + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=todo; + } + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (bttv_debug > 1) + printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + return 0; +} + +static unsigned char lmaskt[8] = +{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; +static unsigned char rmaskt[8] = +{ 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; + +static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h) +{ + unsigned char lmask, rmask, *p; + int W, l, r; + int i; + + if (bttv_debug > 1) + printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); + + /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ + if (x<0) + { + w+=x; + x=0; + } + if (y<0) + { + h+=y; + y=0; + } + if (w < 0 || h < 0) /* catch bad clips */ + return; + /* out of range data should just fall through */ + if (y+h>=625) + h=625-y; + if (x+w>=1024) + w=1024-x; + + l=x>>3; + r=(x+w-1)>>3; + W=r-l-1; + lmask=lmaskt[x&7]; + rmask=rmaskt[(x+w-1)&7]; + p=clipmap+128*y+l; + + if (W>0) + { + for (i=0; iwin.bpp is allowed here */ + bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; + bpl=btv->win.bpl; + adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; + inter=(btv->win.interlace&1)^1; + width=btv->win.width; + height=btv->win.height; + if (bttv_debug > 1) + printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); + if(width > 1023) + width = 1023; /* sanity check */ + if(height > 625) + height = 625; /* sanity check */ + ro=btv->risc_scr_odd; + re=btv->risc_scr_even; + + if (bttv_debug) + printk("bttv%d: clip: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { + /* can't clip, don't generate any risc code */ + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + } + if (ncr < 0) { /* bitmap was pased */ + memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); + } else { /* convert rectangular clips to a bitmap */ + memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ + for (i=0; iwin.x * btv->win.bpp) / bpp; + clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, + 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + /* translate bitmap to risc code */ + for (line=outofmem=0; line < (height<>inter; + rp= (line&1) ? &re : &ro; + clipline = clipmap + (y<<7); /* running pointers ... */ + lastbit = *clipline & 1; + for(x=dx=0,sx=0; x<=width && !outofmem;) { + if (0 == (x&7)) { + /* check bytes not bits if we can ... */ + if (lastbit) { + while (0xff==*clipline && xrisc_scr_odd>RISCMEM_LEN/2 - 16) + outofmem++; + if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) + outofmem++; + } + x++; + if (0 == (x&7)) + clipline++; + } + if ((!inter)||(line&1)) + adr+=bpl; + } + + vfree(clipmap); + /* outofmem flag relies on the following code to discard extra data */ + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (bttv_debug > 1) + printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); +} + +/* + * 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 inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn, + int odd, int width, int height) +{ + u16 vscale, hscale; + u32 xsf, sr; + u16 hdelay; + u8 crop, vtc; + int inter = (height>tvn->sheight/2) ? 0 : 1; + int off = odd ? 0x80 : 0x00; + + xsf = (width*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*width)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/height-512; + vscale=(0x10000UL-sr)&0x1fff; + crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)| + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= inter ? (BT848_VSCALE_INT<<8) : 0; + +#if 0 + /* Some people say interpolation looks bad ... */ + vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); + if (width < 767) + btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); + else + btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); +#else + vtc = 0; + btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); +#endif + + btwrite(vtc, BT848_E_VTC+off); + btwrite(hscale>>8, BT848_E_HSCALE_HI+off); + btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); + btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); + btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); + btwrite(width&0xff, BT848_E_HACTIVE_LO+off); + btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); + btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off); + btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off); + btwrite(crop, BT848_E_CROP+off); +} + + +static void bt848_set_geo(struct bttv *btv, + int no_irq_context) +{ + u16 ewidth, eheight, owidth, oheight; + u16 format, bswap; + struct tvnorm *tvn; + + tvn=&tvnorms[btv->win.norm]; + + btwrite(tvn->adelay, BT848_ADELAY); + btwrite(tvn->bdelay, BT848_BDELAY); + btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); + btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE); + btwrite(1, BT848_VBI_PACK_DEL); + + btv->pll.pll_ofreq = tvn->Fsc; + if (no_irq_context) + set_pll(btv); + + btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; + + if (0 == btv->risc_cap_odd && + 0 == btv->risc_cap_even) { + /* overlay only */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->win.width; + eheight = btv->win.height; + format = btv->win.color_fmt; + bswap = btv->fb_color_ctl; + } else if (-1 != btv->gq_grab && + 0 == btv->risc_cap_odd && + !btv->win.interlace && + btv->scr_on) { + /* odd field -> overlay, even field -> capture */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = (btv->win.color_fmt & 0xf0) | + (btv->gbuf[btv->gq_grab].fmt & 0x0f); + bswap = btv->fb_color_ctl & 0x0a; + } else { + /* capture only */ + owidth = btv->gbuf[btv->gq_grab].width; + oheight = btv->gbuf[btv->gq_grab].height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = btv->gbuf[btv->gq_grab].fmt; + bswap = 0; + } + + /* program odd + even fields */ + bt848_set_eogeo(btv, tvn, 1, owidth, oheight); + bt848_set_eogeo(btv, tvn, 0, ewidth, eheight); + + btwrite(format, BT848_COLOR_FMT); + btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); +} + + +static int bpp2fmt[4] = { + BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, + BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 +}; + +static void bt848_set_winsize(struct bttv *btv) +{ + unsigned short format; + + if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { + /* format set by VIDIOCSPICT */ + format = palette2fmt[btv->picture.palette]; + } else { + /* use default for the given color depth */ + format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : + bpp2fmt[(btv->win.bpp-1)&3]; + } + btv->win.color_fmt = format; + if (bigendian && + format == BT848_COLOR_FMT_RGB32) { + btv->fb_color_ctl = + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else if (bigendian && + (format == BT848_COLOR_FMT_RGB16 || + format == BT848_COLOR_FMT_RGB15)) { + btv->fb_color_ctl = + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else { + btv->fb_color_ctl = 0; + } + + /* RGB8 seems to be a 9x5x5 GRB color cube starting at + * color 16. Why the h... can't they even mention this in the + * data sheet? [AC - because it's a standard format so I guess + * it never occurred to them] + * Enable dithering in this mode. + */ + + if (format==BT848_COLOR_FMT_RGB8) + btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); + else + btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); + + bt848_set_geo(btv,1); +} + +#ifdef HACKING +/* playing with kiobufs and dma-to-userspace. 2.4.x only + Yes, I know: cut+paste programming is ugly. + will fix later, this is proof-of-concept right now. */ +static int make_vrisctab_kiobuf(struct bttv *btv, unsigned int *ro, + unsigned int *re, struct kiobuf *iobuf, + unsigned short width, unsigned short height, + unsigned short palette) +{ + unsigned long bpl; /* bytes per line */ + unsigned long bl; + unsigned long todo; + unsigned long pageaddr; + unsigned int **rp; + unsigned long line,inter,offset,page; + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; + bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + offset = iobuf->offset; + page = 0; + pageaddr = virt_to_bus(page_address(iobuf->maplist[page])); + for (line=0; line < (height<<(1^inter)); line++) + { + if (inter) + rp= (line&1) ? &re : &ro; + else + rp= (line>=height) ? &ro : &re; + + bl = PAGE_SIZE - offset; + if (bpl <= bl) { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *((*rp)++)=cpu_to_le32(pageaddr+offset); + offset+=bpl; + } else { + todo = bpl; + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); + *((*rp)++)=cpu_to_le32(pageaddr+offset); + todo -= bl; + offset = 0; + page++; + pageaddr = virt_to_bus(page_address(iobuf->maplist[page])); + while (todo>PAGE_SIZE) + { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); + *((*rp)++)=cpu_to_le32(pageaddr); + page++; + pageaddr = virt_to_bus(page_address(iobuf->maplist[page])); + } + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); + *((*rp)++)=cpu_to_le32(pageaddr); + offset += todo; + } + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + return 0; +} + +static int vgrab_kiobuf(struct bttv *btv, struct bttv_just_hacking *mp, + struct kiobuf *iobuf) +{ + unsigned int *ro, *re; + unsigned long flags; + + if(btv->gbuf[0].stat != GBUFFER_UNUSED) + return -EBUSY; + + if(mp->height < 32 || mp->width < 32) + return -EINVAL; + if (mp->format >= 12 /* more is'nt yet ... PALETTEFMT_MAX */) + return -EINVAL; + + if(-1 == palette2fmt[mp->format]) + return -EINVAL; + + /* + * Ok load up the BT848 + */ + + ro=btv->gbuf[0].risc; + re=ro+2048; + make_vrisctab_kiobuf(btv, ro, re, iobuf, mp->width, mp->height, mp->format); + + if (bttv_debug) + printk("bttv%d: cap vgrab_kiobuf: queue %d (%d:%dx%d)\n", + btv->nr,0,mp->format,mp->width,mp->height); + spin_lock_irqsave(&btv->s_lock, flags); + btv->gbuf[0].stat = GBUFFER_GRABBING; + btv->gbuf[0].fmt = palette2fmt[mp->format]; + btv->gbuf[0].width = mp->width; + btv->gbuf[0].height = mp->height; + btv->gbuf[0].ro = virt_to_bus(ro); + btv->gbuf[0].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[0].ro = 0; +#endif + + if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { + btv->gq_start = 1; + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } + btv->gqueue[btv->gq_in++] = 0; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + + btor(3, BT848_CAP_CTL); + btor(3, BT848_GPIO_DMA_CTL); + spin_unlock_irqrestore(&btv->s_lock, flags); + return 0; +} +#endif + +/* + * Grab into virtual memory. + */ + +static int vgrab(struct bttv *btv, struct video_mmap *mp) +{ + unsigned int *ro, *re; + unsigned int *vbuf; + unsigned long flags; + + if(btv->fbuffer==NULL) + { + if(fbuffer_alloc(btv)) + return -ENOBUFS; + } + + if(mp->frame >= gbuffers || mp->frame < 0) + return -EINVAL; + if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) + return -EBUSY; + + if(mp->height < 32 || mp->width < 32) + return -EINVAL; + if (mp->format >= PALETTEFMT_MAX) + return -EINVAL; + + if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 + > gbufsize) + return -EINVAL; + if(-1 == palette2fmt[mp->format]) + return -EINVAL; + + /* + * Ok load up the BT848 + */ + + vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); + ro=btv->gbuf[mp->frame].risc; + re=ro+2048; + make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); + + if (bttv_debug) + printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n", + btv->nr,mp->frame,mp->format,mp->width,mp->height); + spin_lock_irqsave(&btv->s_lock, flags); + btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; + btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; + btv->gbuf[mp->frame].width = mp->width; + btv->gbuf[mp->frame].height = mp->height; + btv->gbuf[mp->frame].ro = virt_to_bus(ro); + btv->gbuf[mp->frame].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[mp->frame].ro = 0; +#endif + + if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { + btv->gq_start = 1; + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } + btv->gqueue[btv->gq_in++] = mp->frame; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + + btor(3, BT848_CAP_CTL); + btor(3, BT848_GPIO_DMA_CTL); + spin_unlock_irqrestore(&btv->s_lock, flags); + return 0; +} + +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; + DECLARE_WAITQUEUE(wait, current); + + /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ + 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; + + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + schedule(); + if(signal_pending(current)) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +static inline void burst(int on) +{ + tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); + tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); + tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); + tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0); +} + +static void bt848_restart(struct bttv *btv) +{ + unsigned long irq_flags; + + if (bttv_verbose) + printk("bttv%d: resetting chip\n",btv->nr); + btwrite(0xfffffUL, BT848_INT_STAT); + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(0, BT848_SRESET); + btwrite(virt_to_bus(btv->risc_jmp+2), + BT848_RISC_STRT_ADD); + + /* enforce pll reprogramming */ + btv->pll.pll_current = 0; + set_pll(btv); + + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->errors = 0; + btv->needs_restart = 0; + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); +} + +/* + * 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 i,ret; + + ret = -EBUSY; + + MOD_INC_USE_COUNT; + down(&btv->lock); + if (btv->user) + goto out_unlock; + + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); + ret = -ENOMEM; + if (!btv->fbuffer) + goto out_unlock; + + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + btv->gbuf[i].stat = GBUFFER_UNUSED; + + if (btv->needs_restart) + bt848_restart(btv); + burst(0); + set_pll(btv); + btv->user++; + up(&btv->lock); + return 0; + + out_unlock: + up(&btv->lock); + MOD_DEC_USE_COUNT; + return ret; +} + +static void bttv_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; + + down(&btv->lock); + btv->user--; + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->scr_on = 0; + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + /* + * A word of warning. At this point the chip + * is still capturing because its FIFO hasn't emptied + * and the DMA control operations are posted PCI + * operations. + */ + + btread(BT848_I2C); /* This fixes the PCI posting delay */ + + if (-1 != btv->gq_grab) { + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + } + + /* + * We have allowed it to drain. + */ + + if(btv->fbuffer) + rvfree((void *) btv->fbuffer, gbuffers*gbufsize); + btv->fbuffer=0; + up(&btv->lock); + 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, unsigned long 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, unsigned long 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); +} + +/* + * ioctl routine + */ + + +static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; + int i,ret = 0; + + if (bttv_debug > 1) + printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->video_dev.name); + b.type = VID_TYPE_CAPTURE| + ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + b.channels = bttv_tvcards[btv->type].video_inputs; + b.audios = bttv_tvcards[btv->type].audio_inputs; + b.maxwidth = tvnorms[btv->win.norm].swidth; + b.maxheight = tvnorms[btv->win.norm].sheight; + 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; + v.norm = btv->win.norm; + if (v.channel>=bttv_tvcards[btv->type].video_inputs) + return -EINVAL; + if(v.channel==bttv_tvcards[btv->type].tuner) + { + strcpy(v.name,"Television"); + v.flags|=VIDEO_VC_TUNER; + v.type=VIDEO_TYPE_TV; + v.tuners=1; + } + else if(v.channel==bttv_tvcards[btv->type].svhs) + strcpy(v.name,"S-Video"); + else + sprintf(v.name,"Composite%d",v.channel); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* + * Each channel has 1 tuner + */ + case VIDIOCSCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + + if (v.channel>bttv_tvcards[btv->type].video_inputs) + return -EINVAL; + if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) + return -EOPNOTSUPP; + + bttv_call_i2c_clients(btv,cmd,&v); + down(&btv->lock); + bt848_muxsel(btv, v.channel); + btv->channel=v.channel; + if (btv->win.norm != v.norm) { + btv->win.norm = v.norm; + make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + } + up(&btv->lock); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||btv->channel) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Television"); + v.rangelow=0; + v.rangehigh=0xFFFFFFFF; + v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = btv->win.norm; + v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; + bttv_call_i2c_clients(btv,cmd,&v); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* We have but one tuner */ + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only one channel has a tuner */ + if(v.tuner!=bttv_tvcards[btv->type].tuner) + return -EINVAL; + + if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC + &&v.mode!=VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + bttv_call_i2c_clients(btv,cmd,&v); + if (btv->win.norm != v.mode) { + btv->win.norm = v.mode; + down(&btv->lock); + set_pll(btv); + make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + } + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=btv->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 > PALETTEFMT_MAX) + return -EINVAL; + down(&btv->lock); + /* 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; + up(&btv->lock); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp = NULL; + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + down(&btv->lock); + if(vw.flags || vw.width < 16 || vw.height < 16) + { + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + return -EINVAL; + } + if (btv->win.bpp < 4) + { /* adjust and align writes */ + vw.x = (vw.x + 3) & ~3; + vw.width &= ~3; + } + if (btv->needs_restart) + bt848_restart(btv); + btv->win.x=vw.x; + btv->win.y=vw.y; + btv->win.width=vw.width; + btv->win.height=vw.height; + + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_risc_jmps(btv,0); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + /* + * Do any clips. + */ + if(vw.clipcount<0) { + if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) + return -ENOMEM; + if(copy_from_user(vcp, vw.clips, + VIDEO_CLIPMAP_SIZE)) { + vfree(vcp); + return -EFAULT; + } + } else if (vw.clipcount) { + if((vcp=vmalloc(sizeof(struct video_clip)* + (vw.clipcount))) == NULL) + return -ENOMEM; + if(copy_from_user(vcp,vw.clips, + sizeof(struct video_clip)* + vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + } + make_clip_tab(btv, vcp, vw.clipcount); + if (vw.clipcount != 0) + vfree(vcp); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + 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) + return -EINVAL; + if (btv->win.width==0 || btv->win.height==0) + return -EINVAL; + spin_lock_irqsave(&btv->s_lock, irq_flags); + if (v == 1 && btv->win.vidadr != 0) + btv->scr_on = 1; + if (v == 0) + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + 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.depth; + v.bytesperline=btv->win.bpl; + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; + + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v.depth!=8 && v.depth!=15 && v.depth!=16 && + v.depth!=24 && v.depth!=32 && v.width > 16 && + v.height > 16 && v.bytesperline > 16) + return -EINVAL; + down(&btv->lock); + if (v.base) + btv->win.vidadr=(unsigned long)v.base; + btv->win.sheight=v.height; + btv->win.swidth=v.width; + btv->win.bpp=((v.depth+7)&0x38)/8; + btv->win.depth=v.depth; + btv->win.bpl=v.bytesperline; + + /* set sefault color format */ + switch (btv->win.bpp) { + case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; + case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; + case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; + case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; + case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; + } + + if (bttv_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); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + 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; + bttv_call_i2c_clients(btv,cmd,&v); +#if 0 + if (btv->type == BTTV_MIROPRO && btv->radio) + tea5757_set_freq(btv,v); +#endif + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio v; + + v=btv->audio_dev; + v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); + v.flags|=VIDEO_AUDIO_MUTABLE; + strcpy(v.name,"TV"); + + v.mode = VIDEO_SOUND_MONO; + bttv_call_i2c_clients(btv,cmd,&v); + + if (btv->type == BTTV_TERRATV) { + v.mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +#ifndef HAVE_TVAUDIO + else if (btv->audio_chip == TDA9840) { + /* begin of Horrible Hack */ + v.flags|=VIDEO_AUDIO_VOLUME; + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + v.volume = 32768; /* fixme */ + v.step = 4096; + } +#endif + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + + if(copy_from_user(&v,arg, sizeof(v))) + return -EFAULT; + down(&btv->lock); + if(v.flags&VIDEO_AUDIO_MUTE) + audio(btv, AUDIO_MUTE, 1); + /* One audio source per tuner -- huh? */ + if(v.audio<0 || v.audio >= bttv_tvcards[btv->type].audio_inputs) { + up(&btv->lock); + return -EINVAL; + } + /* bt848_muxsel(btv,v.audio); */ + if(!(v.flags&VIDEO_AUDIO_MUTE)) + audio(btv, AUDIO_UNMUTE, 1); + + bttv_call_i2c_clients(btv,cmd,&v); + + if (btv->type == BTTV_TERRATV) { + unsigned int con = 0; + btor(0x180000, BT848_GPIO_OUT_EN); + if (v.mode & VIDEO_SOUND_LANG2) + con = 0x080000; + if (v.mode & VIDEO_SOUND_STEREO) + con = 0x180000; + btaor(con, ~0x180000, BT848_GPIO_DATA); + + } else if (btv->type == BTTV_WINVIEW_601) + winview_setvol(btv,&v); + + btv->audio_dev=v; + up(&btv->lock); + return 0; + } + + case VIDIOCSYNC: + { + DECLARE_WAITQUEUE(wait, current); + + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + if (i < 0 || i >= gbuffers) + return -EINVAL; + switch (btv->gbuf[i].stat) { + case GBUFFER_UNUSED: + ret = -EINVAL; + break; + case GBUFFER_GRABBING: + add_wait_queue(&btv->capq, &wait); + current->state = TASK_INTERRUPTIBLE; + while(btv->gbuf[i].stat==GBUFFER_GRABBING) { + if (bttv_debug) + printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } + } + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + /* fall throuth */ + case GBUFFER_DONE: + case GBUFFER_ERROR: + ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; + if (bttv_debug) + printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); + btv->gbuf[i].stat = GBUFFER_UNUSED; + } + if (btv->needs_restart) { + down(&btv->lock); + bt848_restart(btv); + up(&btv->lock); + } + return ret; + } + + case BTTV_FIELDNR: + if(copy_to_user((void *) arg, (void *) &btv->last_field, + sizeof(btv->last_field))) + return -EFAULT; + break; + + case BTTV_PLLSET: { + struct bttv_pll_info p; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) + return -EFAULT; + down(&btv->lock); + btv->pll.pll_ifreq = p.pll_ifreq; + btv->pll.pll_ofreq = p.pll_ofreq; + btv->pll.pll_crystal = p.pll_crystal; + up(&btv->lock); + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + int ret; + if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) + return -EFAULT; + down(&btv->lock); + ret = vgrab(btv, &vm); + up(&btv->lock); + return ret; + } + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + memset(&vm, 0 , sizeof(vm)); + vm.size=gbufsize*gbuffers; + vm.frames=gbuffers; + for (i = 0; i < gbuffers; i++) + vm.offsets[i]=i*gbufsize; + if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video=btv->video_dev.minor; + vu.vbi=btv->vbi_dev.minor; + if(btv->radio_dev.minor!=-1) + vu.radio=btv->radio_dev.minor; + else + vu.radio=VIDEO_NO_UNIT; + vu.audio=VIDEO_NO_UNIT; + vu.teletext=VIDEO_NO_UNIT; + if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; + } + + case BTTV_BURST_ON: + { + burst(1); + return 0; + } + + case BTTV_BURST_OFF: + { + burst(0); + return 0; + } + + case BTTV_VERSION: + { + return BTTV_VERSION_CODE; + } + + case BTTV_PICNR: + { + /* return picture;*/ + return 0; + } + +#ifdef HACKING + /* playing with kiobufs and dma-to-userspace */ + case BTTV_JUST_HACKING: + { + DECLARE_WAITQUEUE(wait, current); + struct bttv_just_hacking hack; + struct kiobuf *iobuf; + int err; + + if(copy_from_user((void *) &hack, (void *) arg, sizeof(hack))) + return -EFAULT; + printk("bttv%d: hack: userland args: %dx%d, fmt=%d, buf=%lx, len=%d\n", + btv->nr,hack.width,hack.height,hack.format, + hack.buf,hack.len); + + /* pin down */ + err = alloc_kiovec(1,&iobuf); + if (err) + goto hack_oops; + err = map_user_kiobuf(READ, iobuf, hack.buf, hack.len); + if (err) + goto hack_oops; + err = lock_kiovec(1,&iobuf,1); + if (err) + goto hack_oops; + + /* have a look */ + printk("bttv%d: hack: kiobuf: nr_pages=%d, offset=%d, length=%d, locked=%d\n", + btv->nr,iobuf->nr_pages,iobuf->offset,iobuf->length, + iobuf->locked); + printk("bttv%d: hack: pages (bus addr):",btv->nr); + for (i = 0; i < iobuf->nr_pages; i++) { + printk(" %lx", virt_to_bus(page_address(iobuf->maplist[i]))); + } + printk("\n"); + + /* start capture */ + err = -EINVAL; + if (hack.height * hack.width * 2 * /* fixme: *2 */ + fmtbppx2[palette2fmt[hack.format]&0x0f]/2 > hack.len) + goto hack_oops; + err = vgrab_kiobuf(btv,&hack,iobuf); + if (err) + goto hack_oops; + printk("bttv%d: hack: capture started\n",btv->nr); + + /* wait */ + add_wait_queue(&btv->capq, &wait); + current->state = TASK_INTERRUPTIBLE; + while(btv->gbuf[0].stat==GBUFFER_GRABBING) { + if (bttv_debug) + printk("bttv%d: hack: cap sync: sleep on %d\n",btv->nr,0); + schedule(); +#if 0 + if(signal_pending(current)) { + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } +#endif + } + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + printk("bttv%d: hack: capture done\n",btv->nr); + + /* release */ + err = 0; + hack_oops: + free_kiovec(1,&iobuf); + return 0; + } +#endif + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int bttv_init_done(struct video_device *dev) +{ + return 0; +} + +/* + * This maps the vmalloced and reserved fbuffer to user space. + * + * FIXME: + * - PAGE_READONLY should suffice!? + * - remap_page_range is kind of inefficient for page by page remapping. + * But e.g. pte_alloc() does not work in modules ... :-( + */ + +static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) +{ + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + if (size>gbuffers*gbufsize) + return -EINVAL; + if (!btv->fbuffer) { + if(fbuffer_alloc(btv)) + return -EINVAL; + } + pos=(unsigned long) btv->fbuffer; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} + +static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct bttv *btv=(struct bttv *)dev; + int r; + + down(&btv->lock); + r=do_bttv_mmap(btv, adr, size); + up(&btv->lock); + return r; +} + + +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, + NULL, + bttv_ioctl, + bttv_mmap, + bttv_init_done, + NULL, + 0, + -1 +}; + + +static long vbi_read(struct video_device *v, char *buf, unsigned long count, + int nonblock) +{ + struct bttv *btv=(struct bttv *)(v-2); + int q,todo; + DECLARE_WAITQUEUE(wait, current); + + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) + { + if (btv->needs_restart) { + down(&btv->lock); + bt848_restart(btv); + up(&btv->lock); + } + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + schedule(); + if(signal_pending(current)) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +static unsigned int vbi_poll(struct video_device *dev, struct file *file, + poll_table *wait) +{ + struct bttv *btv=(struct bttv *)(dev-2); + unsigned int mask = 0; + + poll_wait(file, &btv->vbiq, wait); + + if (btv->vbip < VBIBUF_SIZE) + mask |= (POLLIN | POLLRDNORM); + + return mask; +} + +static int vbi_open(struct video_device *dev, int flags) +{ + struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; + + MOD_INC_USE_COUNT; + down(&btv->lock); + if (btv->needs_restart) + bt848_restart(btv); + set_pll(btv); + btv->vbip=VBIBUF_SIZE; + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->vbi_on = 1; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + + return 0; +} + +static void vbi_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; + + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->vbi_on = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + MOD_DEC_USE_COUNT; +} + +static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->vbi_dev.name); + b.type = ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_TELETEXT; + b.channels = 0; + b.audios = 0; + b.maxwidth = 0; + b.maxheight = 0; + b.minwidth = 0; + b.minheight = 0; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return bttv_ioctl((struct video_device *)btv,cmd,arg); + case BTTV_VBISIZE: + /* make alevt happy :-) */ + return VBIBUF_SIZE; + default: + return -EINVAL; + } +} + +static struct video_device vbi_template= +{ + "bttv vbi", + VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + VID_HARDWARE_BT848, + vbi_open, + vbi_close, + vbi_read, + bttv_write, + vbi_poll, + vbi_ioctl, + NULL, /* no mmap yet */ + bttv_init_done, + NULL, + 0, + -1 +}; + + +static int radio_open(struct video_device *dev, int flags) +{ + struct bttv *btv = (struct bttv *)(dev-1); + unsigned long v; + + MOD_INC_USE_COUNT; + down(&btv->lock); + if (btv->user) + goto busy_unlock; + btv->user++; + + btv->radio = 1; + v = 400*16; + bttv_call_i2c_clients(btv,VIDIOCSFREQ,&v); + bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); + bt848_muxsel(btv,0); + up(&btv->lock); + + return 0; + + busy_unlock: + up(&btv->lock); + MOD_DEC_USE_COUNT; + return -EBUSY; +} + +static void radio_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)(dev-1); + + down(&btv->lock); + btv->user--; + btv->radio = 0; + up(&btv->lock); + MOD_DEC_USE_COUNT; +} + +static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)(dev-1); + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + strcpy(v.name,btv->video_dev.name); + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + break; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||btv->channel) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Radio"); + v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */ + v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */ + v.flags= 0; /* XXX */ + v.mode = 0; /* XXX */ + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 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 || btv->channel) + return -EINVAL; + /* XXX anything to do ??? */ + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + bttv_ioctl((struct video_device *)btv,cmd,arg); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct video_device radio_template= +{ + "bttv radio", + VID_TYPE_TUNER, + VID_HARDWARE_BT848, + radio_open, + radio_close, + radio_read, /* just returns -EINVAL */ + bttv_write, /* just returns -EINVAL */ + NULL, /* no poll */ + radio_ioctl, + NULL, /* no mmap */ + bttv_init_done, /* just returns 0 */ + NULL, + 0, + -1 +}; + + +#define TRITON_PCON 0x50 +#define TRITON_BUS_CONCURRENCY (1<<0) +#define TRITON_STREAMING (1<<1) +#define TRITON_WRITE_BURST (1<<2) +#define TRITON_PEER_CONCURRENCY (1<<3) + + +static void __devinit handle_chipset(void) +{ + struct pci_dev *dev = NULL; + + /* Just in case some nut set this to something dangerous */ + if (triton1) + triton1=BT848_INT_ETBF; + + while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) + { + /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ + printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, dev))) + { + unsigned char b; + pci_read_config_byte(dev, 0x53, &b); + DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); + DEBUG(printk("bufcon=0x%02x\n",b)); + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) + { + printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); + triton1=BT848_INT_ETBF; + } +} + + +static void bt848_set_risc_jmps(struct bttv *btv, int flags) +{ + if (-1 == flags) { + /* defaults */ + flags = 0; + if (btv->scr_on) + flags |= 0x03; + if (btv->vbi_on) + flags |= 0x0c; + } + + if (bttv_debug > 1) + printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); + + /* Sync to start of odd field */ + btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRE); + btv->risc_jmp[1]=cpu_to_le32(0); + + /* Jump to odd vbi sub */ + btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); + if (flags&8) { + if (bttv_debug > 1) + printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + } + + /* Jump to odd sub */ + btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); + if (0 != btv->risc_cap_odd) { + if (bttv_debug > 1) + printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + flags |= 3; + btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); + } else if (flags&2) { + if (bttv_debug > 1) + printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); + } + + + /* Sync to start of even field */ + btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRO); + btv->risc_jmp[7]=cpu_to_le32(0); + + /* Jump to even vbi sub */ + btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); + if (flags&4) { + if (bttv_debug > 1) + printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + } + + /* Jump to even sub */ + btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); + if (0 != btv->risc_cap_even) { + if (bttv_debug > 1) + printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + flags |= 3; + btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); + } else if (flags&1) { + if (bttv_debug > 1) + printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); + } + + if (btv->gq_start) { + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } else { + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); + } + btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); + + /* enable cpaturing and DMA */ + if (bttv_debug > 1) + printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); + btaor(flags, ~0x0f, BT848_CAP_CTL); + if (flags&0x0f) + bt848_dma(btv, 3); + else + bt848_dma(btv, 0); +} + +static int __devinit init_video_dev(struct bttv *btv) +{ + memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); + memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); + memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); + + bttv_idcard(btv); + audio(btv, AUDIO_MUTE, 1); + + if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) + return -1; + if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) + { + video_unregister_device(&btv->video_dev); + return -1; + } + if (radio[btv->nr]) + { + if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) + { + video_unregister_device(&btv->vbi_dev); + video_unregister_device(&btv->video_dev); + return -1; + } + } + return 1; +} + +static int __devinit init_bt848(struct bttv *btv) +{ + int j; + unsigned long irq_flags; + + btv->user=0; + init_MUTEX(&btv->lock); + + /* dump current state of the gpio registers before changing them, + * might help to make a new card work */ + if (bttv_verbose >= 2) + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + btv->nr, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); + + /* reset the bt848 */ + btwrite(0, BT848_SRESET); + DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem)); + + /* not registered yet */ + btv->video_dev.minor = -1; + btv->radio_dev.minor = -1; + btv->vbi_dev.minor = -1; + + /* 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.bpp=2; + btv->win.depth=16; + btv->win.color_fmt=BT848_COLOR_FMT_RGB16; + btv->win.bpl=1024*btv->win.bpp; + btv->win.swidth=1024; + btv->win.sheight=768; + btv->win.vidadr=0; + btv->vbi_on=0; + btv->scr_on=0; + + btv->risc_scr_odd=0; + btv->risc_scr_even=0; + btv->risc_cap_odd=0; + btv->risc_cap_even=0; + btv->risc_jmp=0; + btv->vbibuf=0; + btv->field=btv->last_field=0; + + btv->errors=0; + btv->needs_restart=0; + + /* i2c */ + btv->tuner_type=-1; + init_bttv_i2c(btv); + + if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) + return -1; + btv->vbi_odd=btv->risc_jmp+16; + btv->vbi_even=btv->vbi_odd+256; + btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); + 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=(unsigned char *) vmalloc_32(VBIBUF_SIZE); + if (!btv->vbibuf) + return -1; + if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) + return -1; + for (j = 0; j < gbuffers; j++) { + if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) + return -1; + } + + memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random + memory to the user */ + + btv->fbuffer=NULL; + + bt848_muxsel(btv, 1); + bt848_set_winsize(btv); + +/* btwrite(0, BT848_TDEC); */ + btwrite(0x10, BT848_COLOR_CTL); + btwrite(0x00, BT848_CAP_CTL); + /* set planar and packed mode trigger points and */ + /* set rising edge of inverted GPINTR pin as irq trigger */ + btwrite(BT848_GPIO_DMA_CTL_PKTP_32| + BT848_GPIO_DMA_CTL_PLTP1_16| + BT848_GPIO_DMA_CTL_PLTP23_16| + BT848_GPIO_DMA_CTL_GPINTC| + BT848_GPIO_DMA_CTL_GPINTI, + BT848_GPIO_DMA_CTL); + + /* select direct input */ + btwrite(0x00, BT848_GPIO_REG_INP); + + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, + BT848_IFORM); + + btwrite(0xd8, BT848_CONTRAST_LO); + bt848_bright(btv, 0x10); + + btwrite(0x20, BT848_E_VSCALE_HI); + btwrite(0x20, 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); + + btv->picture.colour=254<<7; + btv->picture.brightness=128<<8; + btv->picture.hue=128<<8; + btv->picture.contrast=0xd8<<7; + + btwrite(0x00, BT848_E_SCLOOP); + btwrite(0x00, BT848_O_SCLOOP); + + /* clear interrupt status */ + btwrite(0xfffffUL, BT848_INT_STAT); + + /* set interrupt mask */ + btwrite(btv->triton1| + /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| + BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ + (fieldnr ? BT848_INT_VSYNC : 0)| + BT848_INT_GPINT| + BT848_INT_SCERR| + BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| + BT848_INT_FMTCHG|BT848_INT_HLOCK, + BT848_INT_MASK); + + make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + /* + * Now add the template and register the device unit. + */ + init_video_dev(btv); + + return 0; +} + +static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,astat; + u32 dstat; + int count,i; + 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%d: astat=%08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); + + /* get device status bits */ + dstat=btread(BT848_DSTATUS); + + if (astat&BT848_INT_GPINT) { + IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); + wake_up_interruptible(&btv->gpioq); + } + + if (astat&BT848_INT_FMTCHG) + { + IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); + /*btv->win.norm&= + (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ + } + if (astat&BT848_INT_VPRES) + { + IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr)); + } + if (astat&BT848_INT_VSYNC) + { + IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); + btv->field++; + } + if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { + if (bttv_verbose) + printk("bttv%d: irq:%s%s risc_count=%08x\n", + btv->nr, + (astat&BT848_INT_SCERR) ? " SCERR" : "", + (astat&BT848_INT_OCERR) ? " OCERR" : "", + btread(BT848_RISC_COUNT)); + btv->errors++; + if (btv->errors < BTTV_ERRORS) { + spin_lock(&btv->s_lock); + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(virt_to_bus(btv->risc_jmp+2), + BT848_RISC_STRT_ADD); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); + spin_unlock(&btv->s_lock); + } else { + if (bttv_verbose) + printk("bttv%d: aiee: error loops\n",btv->nr); + /* cancel all outstanding grab requests */ + spin_lock(&btv->s_lock); + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + if (btv->gbuf[i].stat == GBUFFER_GRABBING) + btv->gbuf[i].stat = GBUFFER_ERROR; + /* disable DMA */ + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,0); + btv->needs_restart = 1; + spin_unlock(&btv->s_lock); + + wake_up_interruptible(&btv->vbiq); + wake_up_interruptible(&btv->capq); + } + } + if (astat&BT848_INT_RISCI) + { + if (bttv_debug > 1) + printk("bttv%d: IRQ_RISCI\n",btv->nr); + + /* captured VBI frame */ + if (stat&(1<<28)) + { + btv->vbip=0; + /* inc vbi frame count for detecting drops */ + (*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++; + wake_up_interruptible(&btv->vbiq); + } + + /* captured full frame */ + if (stat&(2<<28) && btv->gq_grab != -1) + { + btv->last_field=btv->field; + if (bttv_debug) + printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); + do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); + spin_lock(&btv->s_lock); + btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; + btv->gq_grab = -1; + if (btv->gq_in != btv->gq_out) + { + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (bttv_debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); + } else { + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); + } + spin_unlock(&btv->s_lock); + wake_up_interruptible(&btv->capq); + break; + } + if (stat&(8<<28)) + { + spin_lock(&btv->s_lock); + btv->gq_start = 0; + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (bttv_debug) + printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); + spin_unlock(&btv->s_lock); + } + } + if (astat&BT848_INT_OCERR) + { + IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr)); + } + if (astat&BT848_INT_PABORT) + { + IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr)); + } + if (astat&BT848_INT_RIPERR) + { + IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr)); + } + if (astat&BT848_INT_PPERR) + { + IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr)); + } + if (astat&BT848_INT_FDSR) + { + IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr)); + } + if (astat&BT848_INT_FTRGT) + { + IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr)); + } + if (astat&BT848_INT_FBUS) + { + IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr)); + } + if (astat&BT848_INT_HLOCK) + { + if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) + audio(btv, AUDIO_ON,0); + else + audio(btv, AUDIO_OFF,0); + } + + if (astat&BT848_INT_I2CDONE) + { + IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); + } + count++; + if (count > 10) + printk (KERN_WARNING "bttv%d: irq loop %d\n", + btv->nr,count); + if (count > 20) + { + btwrite(0, BT848_INT_MASK); + printk(KERN_ERR + "bttv%d: IRQ lockup, cleared int mask\n", btv->nr); + } + } +} + + + +/* + * Scan for a Bt848 card, request the irq and map the io memory + */ + +static void __devinit bttv_remove(struct pci_dev *pci_dev) +{ + u8 command; + int j; + struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); + + /* unregister i2c_bus */ + if (0 == btv->i2c_ok) + i2c_bit_del_bus(&btv->i2c_adap); + + /* turn off all capturing, DMA and IRQs */ + btand(~15, BT848_GPIO_DMA_CTL); + + /* first disable interrupts before unmapping the memory! */ + btwrite(0, BT848_INT_MASK); + btwrite(~0x0UL,BT848_INT_STAT); + btwrite(0x0, BT848_GPIO_OUT_EN); + + /* disable PCI bus-mastering */ + pci_read_config_byte(btv->dev, PCI_COMMAND, &command); + /* Should this be &=~ ?? */ + command&=~PCI_COMMAND_MASTER; + pci_write_config_byte(btv->dev, PCI_COMMAND, command); + + /* unmap and free memory */ + for (j = 0; j < gbuffers; j++) + if (btv->gbuf[j].risc) + kfree(btv->gbuf[j].risc); + if (btv->gbuf) + kfree((void *) btv->gbuf); + + if (btv->risc_scr_odd) + kfree((void *) btv->risc_scr_odd); + + if (btv->risc_scr_even) + kfree((void *) btv->risc_scr_even); + + DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); + if (btv->risc_jmp) + kfree((void *) btv->risc_jmp); + + DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf)); + if (btv->vbibuf) + vfree((void *) btv->vbibuf); + + free_irq(btv->irq,btv); + DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); + if (btv->bt848_mem) + iounmap(btv->bt848_mem); + + if(btv->video_dev.minor!=-1) + video_unregister_device(&btv->video_dev); + if(btv->vbi_dev.minor!=-1) + video_unregister_device(&btv->vbi_dev); + if (radio[btv->nr] && btv->radio_dev.minor != -1) + video_unregister_device(&btv->radio_dev); + + release_mem_region(btv->bt848_adr, + pci_resource_len(btv->dev,0)); + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + btv->shutdown=1; + wake_up(&btv->gpioq); + + return; +} + + +static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) +{ + int result; + unsigned char command; + struct bttv *btv; +#if defined(__powerpc__) + unsigned int cmd; +#endif + + printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); + + btv=&bttvs[bttv_num]; + btv->dev=dev; + btv->nr = bttv_num; + btv->bt848_mem=NULL; + btv->vbibuf=NULL; + btv->risc_jmp=NULL; + btv->vbi_odd=NULL; + btv->vbi_even=NULL; + init_waitqueue_head(&btv->vbiq); + init_waitqueue_head(&btv->capq); + btv->vbip=VBIBUF_SIZE; + btv->s_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&btv->gpioq); + btv->shutdown=0; + + btv->id=dev->device; + btv->irq=dev->irq; + btv->bt848_adr=pci_resource_start(dev,0); + if (pci_enable_device(dev)) + return -EIO; + if (!request_mem_region(pci_resource_start(dev,0), + pci_resource_len(dev,0), + "bttv")) { + return -EBUSY; + } + if (btv->id >= 878) + btv->i2c_command = 0x83; + else + btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); + printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", + bttv_num,btv->id, btv->revision); + printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn); + printk("irq: %d, ",btv->irq); + printk("memory: 0x%lx.\n", btv->bt848_adr); + +#if defined(__powerpc__) + /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ + /* response on cards with no firmware is not enabled by OF */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY ); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif + +#ifdef __sparc__ + btv->bt848_mem=(unsigned char *)btv->bt848_adr; +#else + btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); +#endif + + /* clear interrupt mask */ + btwrite(0, BT848_INT_MASK); + + result = request_irq(btv->irq, bttv_irq, + SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); + if (result==-EINVAL) + { + printk(KERN_ERR "bttv%d: Bad irq number or handler\n", + bttv_num); + goto fail; + } + if (result==-EBUSY) + { + printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq); + goto fail; + } + if (result < 0) + goto fail; + + pci_set_master(dev); + + btv->triton1=triton1 ? BT848_INT_ETBF : 0; + if (triton1 && btv->id >= 878) + { + btv->triton1 = 0; + printk("bttv: Enabling 430FX compatibilty for bt878\n"); + pci_read_config_byte(dev, BT878_DEVCTRL, &command); + command|=BT878_EN_TBFX; + pci_write_config_byte(dev, BT878_DEVCTRL, command); + pci_read_config_byte(dev, BT878_DEVCTRL, &command); + if (!(command&BT878_EN_TBFX)) + { + printk("bttv: 430FX compatibility could not be enabled\n"); + free_irq(btv->irq,btv); + result = -1; + goto fail; + } + } + + PCI_SET_DRIVER_DATA(dev,btv); + + if(init_bt848(btv) < 0) { + bttv_remove(dev); + return -EIO; + } + bttv_num++; + + return 0; + + fail: + release_mem_region(pci_resource_start(btv->dev,0), + pci_resource_len(btv->dev,0)); + return result; +} + +static struct pci_device_id bttv_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); + +static struct pci_driver bttv_pci_driver = { + name: "bttv", + id_table: bttv_pci_tbl, + probe: bttv_probe, + remove: bttv_remove, +}; + +int bttv_init_module(void) +{ + bttv_num = 0; + + printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", + (BTTV_VERSION_CODE >> 16) & 0xff, + (BTTV_VERSION_CODE >> 8) & 0xff, + BTTV_VERSION_CODE & 0xff); + if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) + gbuffers = 2; + if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + if (bttv_verbose) + printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", + gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); + + handle_chipset(); + + return pci_module_init(&bttv_pci_driver); +} + +void bttv_cleanup_module(void) +{ + pci_unregister_driver(&bttv_pci_driver); + return; +} + +module_init(bttv_init_module); +module_exit(bttv_cleanup_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/bttv-if.c linux/drivers/media/video/bttv-if.c --- v2.4.0-test6/linux/drivers/media/video/bttv-if.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bttv-if.c Tue Jul 18 22:35:33 2000 @@ -0,0 +1,337 @@ +/* + bttv-if.c -- interfaces to other kernel modules + all the i2c code is here + also the gpio interface exported by bttv (used by lirc) + + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999,2000 Gerd Knorr + + 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. + +*/ + +#define __NO_VERSION__ 1 + +#include +#include +#include + +#include + +#include "bttv.h" +#include "tuner.h" + + +EXPORT_SYMBOL(bttv_get_cardinfo); +EXPORT_SYMBOL(bttv_get_id); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); +EXPORT_SYMBOL(bttv_get_gpio_queue); + +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) +{ + if (card >= bttv_num) { + return -1; + } + *type = bttvs[card].type; + *cardid = bttvs[card].cardid; + return 0; +} + +int bttv_get_id(unsigned int card) +{ + printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); + if (card >= bttv_num) { + return -1; + } + return bttvs[card].type; +} + +int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + btaor(data, ~mask, BT848_GPIO_OUT_EN); + return 0; +} + +int bttv_read_gpio(unsigned int card, unsigned long *data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + if(btv->shutdown) { + return -ENODEV; + } + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + *data = btread(BT848_GPIO_DATA); + return 0; +} + +int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + btaor(data & mask, ~mask, BT848_GPIO_DATA); + return 0; +} + +wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return NULL; + } + + btv = &bttvs[card]; + if (bttvs[card].shutdown) { + return NULL; + } + return &btv->gpioq; +} + + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ + +void bttv_bit_setscl(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x02; + else + btv->i2c_state &= ~0x02; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +void bttv_bit_setsda(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x01; + else + btv->i2c_state &= ~0x01; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +static int bttv_bit_getscl(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x02 ? 1 : 0; + return state; +} + +static int bttv_bit_getsda(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x01; + return state; +} + +static void bttv_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void bttv_dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +static int attach_inform(struct i2c_client *client) +{ + struct bttv *btv = (struct bttv*)client->adapter->data; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] == NULL || + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = client; + break; + } + } + if (btv->tuner_type != -1) + bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (bttv_verbose) + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct bttv *btv = (struct bttv*)client->adapter->data; + int i; + + if (bttv_verbose) + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL != btv->i2c_clients[i] && + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = NULL; + break; + } + } + return 0; +} + +void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL == btv->i2c_clients[i]) + continue; + if (NULL == btv->i2c_clients[i]->driver->command) + continue; + btv->i2c_clients[i]->driver->command( + btv->i2c_clients[i],cmd,arg); + } +} + +struct i2c_algo_bit_data bttv_i2c_algo_template = { + NULL, + bttv_bit_setsda, + bttv_bit_setscl, + bttv_bit_getsda, + bttv_bit_getscl, + 10, 10, 100, +}; + +struct i2c_adapter bttv_i2c_adap_template = { + "bt848", + I2C_HW_B_BT848, + NULL, + NULL, + bttv_inc_use, + bttv_dec_use, + attach_inform, + detach_inform, + NULL, +}; + +struct i2c_client bttv_i2c_client_template = { + "bttv internal", + -1, + 0, + 0, + NULL, + NULL +}; + + +/* read I2C */ +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +{ + unsigned char buffer = 0; + + if (0 != btv->i2c_ok) + return -1; + if (bttv_verbose && NULL != probe_for) + printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", + btv->nr,probe_for,addr); + btv->i2c_client.addr = addr >> 1; + if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { + if (NULL != probe_for) { + if (bttv_verbose) + printk("not found\n"); + } else + printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", + btv->nr,addr); + return -1; + } + if (bttv_verbose && NULL != probe_for) + printk("found\n"); + return buffer; +} + +/* write I2C */ +int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both) +{ + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + if (0 != btv->i2c_ok) + return -1; + btv->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) + return -1; + return 0; +} + +/* read EEPROM content */ +void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) +{ + int i; + + if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + btv->i2c_client.addr = addr >> 1; + for (i=0; i<256; i+=16) { + if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + } +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h --- v2.4.0-test6/linux/drivers/media/video/bttv.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bttv.h Sun Aug 6 12:45:28 2000 @@ -0,0 +1,425 @@ +/* + 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. +*/ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,38) + +#ifndef PCI_GET_DRIVER_DATA +# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) +# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) +#endif /* PCI_GET_DRIVER_DATA */ + +#include +#include +#include +#include +#include + +#include "audiochip.h" +#include "bt848.h" + +#ifdef __KERNEL__ + +/* fwd decl */ +struct bttv; + + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#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 BTTV_AVERMEDIA 0x06 +#define BTTV_MATRIX_VISION 0x07 +#define BTTV_FLYVIDEO 0x08 +#define BTTV_TURBOTV 0x09 +#define BTTV_HAUPPAUGE878 0x0a +#define BTTV_MIROPRO 0x0b +#define BTTV_ADSTECH_TV 0x0c +#define BTTV_AVERMEDIA98 0x0d +#define BTTV_VHX 0x0e +#define BTTV_ZOLTRIX 0x0f +#define BTTV_PIXVIEWPLAYTV 0x10 +#define BTTV_WINVIEW_601 0x11 +#define BTTV_AVEC_INTERCAP 0x12 +#define BTTV_LIFE_FLYKIT 0x13 +#define BTTV_CEI_RAFFLES 0x14 +#define BTTV_CONFERENCETV 0x15 +#define BTTV_PHOEBE_TVMAS 0x16 +#define BTTV_MODTEC_205 0x17 +#define BTTV_MAGICTVIEW061 0x18 +#define BTTV_VOBIS_BOOSTAR 0x19 +#define BTTV_HAUPPAUG_WCAM 0x1a +#define BTTV_MAXI 0x1b +#define BTTV_TERRATV 0x1c +#define BTTV_PXC200 0x1d +#define BTTV_FLYVIDEO_98 0x1e +#define BTTV_IPROTV 0x1f +#define BTTV_INTEL_C_S_PCI 0x20 +#define BTTV_TERRATVALUE 0x21 +#define BTTV_WINFAST2000 0x22 +#define BTTV_CHRONOS_VS2 0x23 +#define BTTV_TYPHOON_TVIEW 0x24 +#define BTTV_PXELVWPLTVPRO 0x25 +#define BTTV_MAGICTVIEW063 0x26 +#define BTTV_PINNACLERAVE 0x27 +#define BTTV_STB2 0x28 +#define BTTV_AVPHONE98 0x29 +#define BTTV_PV951 0x2a +#define BTTV_ONAIR_TV 0x2b +#define BTTV_SIGMA_TVII_FM 0x2c +#define BTTV_MATRIX_VISION2 0x2d +#define BTTV_ZOLTRIX_GENIE 0x2e +#define BTTV_TERRATVRADIO 0x2f +#define BTTV_DYNALINK 0x30 + +struct tvcard +{ + char *name; + int video_inputs; + int audio_inputs; + int tuner; + int svhs; + u32 gpiomask; + u32 muxsel[8]; + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* look for these i2c audio chips */ + int msp34xx:1; + int tda8425:1; + int tda9840:1; + int tda985x:1; + int tea63xx:1; + int tea64xx:1; + int tda7432:1; + int tda9875:1; + + /* other settings */ + int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + int tuner_type; +}; + +extern struct tvcard bttv_tvcards[]; +extern const int bttv_num_tvcards; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern void winview_setvol(struct bttv *btv, struct video_audio *v); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ +/* interface for gpio access by other modules */ + +/* returns card type + card ID (for bt878-based ones) + for possible values see lines below beginning with #define BTTV_UNKNOWN + returns negative value if error ocurred +*/ +extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid); + +/* obsolete, use bttv_get_cardinfo instead */ +extern int bttv_get_id(unsigned int card); + +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_gpio_enable(unsigned int card, + unsigned long mask, unsigned long data); + +/* fills data with GPDATA register contents + returns negative value if error ocurred +*/ +extern int bttv_read_gpio(unsigned int card, unsigned long *data); + +/* sets GPDATA register to new value: + (data & mask) | (current_GPDATA_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + +/* returns pointer to task queue which can be used as parameter to + interruptible_sleep_on + in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated + (wake_up_interruptible) and following call to the function bttv_read_gpio + should return new value of GPDATA, + returns NULL value if error ocurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* i2c */ +struct i2c_algo_bit_data bttv_i2c_algo_template; +struct i2c_adapter bttv_i2c_adap_template; +struct i2c_client bttv_i2c_client_template; +void bttv_bit_setscl(void *data, int state); +void bttv_bit_setsda(void *data, int state); +void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; + +/* Anybody who uses more than four? */ +#define BTTV_MAX 4 +extern int bttv_num; /* number of Bt848s in use */ +extern struct bttv bttvs[BTTV_MAX]; + + +#ifndef O_NONCAP +#define O_NONCAP O_TRUNC +#endif + +#define MAX_GBUFFERS 64 +#define RISCMEM_LEN (32744*2) +#define VBI_MAXLINES 16 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) + +#define BTTV_MAX_FBUF 0x208000 +#define I2C_CLIENTS_MAX 8 + +struct bttv_window +{ + int x, y; + ushort width, height; + ushort bpp, bpl; + ushort swidth, sheight; + unsigned long vidadr; + ushort freq; + int norm; + int interlace; + int color_fmt; + ushort depth; +}; + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +struct bttv_gbuf { + int stat; +#define GBUFFER_UNUSED 0 +#define GBUFFER_GRABBING 1 +#define GBUFFER_DONE 2 +#define GBUFFER_ERROR 3 + struct timeval tv; + + u16 width; + u16 height; + u16 fmt; + + u32 *risc; + unsigned long ro; + unsigned long re; +}; + +struct bttv { + struct video_device video_dev; + struct video_device radio_dev; + struct video_device vbi_dev; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + + spinlock_t s_lock; + struct semaphore lock; + int user; + int capuser; + + /* i2c */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_ok; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + + int tuner_type; + int channel; + + unsigned int nr; + unsigned short id; + struct pci_dev *dev; + unsigned int irq; /* IRQ used by Bt848 card */ + unsigned char revision; + unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *bt848_mem; /* pointer to mapped IO memory */ + unsigned long busriscmem; + u32 *riscmem; + + unsigned char *vbibuf; + struct bttv_window win; + int fb_color_ctl; + int type; /* card type */ + int cardid; + int audio; /* audio mode */ + int audio_chip; /* set to one of the chips supported by bttv.c */ + int radio; + + u32 *risc_jmp; + u32 *vbi_odd; + u32 *vbi_even; + u32 bus_vbi_even; + u32 bus_vbi_odd; + wait_queue_head_t vbiq; + wait_queue_head_t capq; + int vbip; + + u32 *risc_scr_odd; + u32 *risc_scr_even; + u32 risc_cap_odd; + u32 risc_cap_even; + int scr_on; + int vbi_on; + struct video_clip *cliprecs; + + struct bttv_gbuf *gbuf; + int gqueue[MAX_GBUFFERS]; + int gq_in,gq_out,gq_grab,gq_start; + char *fbuffer; + + struct bttv_pll_info pll; + unsigned int Fsc; + unsigned int field; + unsigned int last_field; /* number of last grabbed field */ + int i2c_command; + int triton1; + + int errors; + int needs_restart; + + wait_queue_head_t gpioq; + int shutdown; +}; +#endif + +#if defined(__powerpc__) /* big-endian */ +extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) +{ + __asm__ __volatile__ ("stwbrx %1,0,%2" : \ + "=m" (*addr) : "r" (val), "r" (addr)); + __asm__ __volatile__ ("eieio" : : : "memory"); +} + +#define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) +#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(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_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]) +#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]) +#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int) +#define BTTV_PLLSET _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info) +#define BTTV_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int) +#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int) +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + +#define AUDIO_TUNER 0x00 +#define AUDIO_RADIO 0x01 +#define AUDIO_EXTERN 0x02 +#define AUDIO_INTERN 0x03 +#define AUDIO_OFF 0x04 +#define AUDIO_ON 0x05 +#define AUDIO_MUTE 0x80 +#define AUDIO_UNMUTE 0x81 + +#define TDA9850 0x01 +#define TDA9840 0x02 +#define TDA8425 0x03 +#define TEA6300 0x04 + +#define I2C_TSA5522 0xc2 +#define I2C_TDA7432 0x8a +#define I2C_TDA8425 0x82 +#define I2C_TDA9840 0x84 +#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ +#define I2C_TDA9875 0xb0 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_VHX 0xc0 +#define I2C_MSP3400 0x80 +#define I2C_TEA6300 0x80 +#define I2C_DPL3518 0x84 + +#ifndef HAVE_TVAUDIO +#define TDA9840_SW 0x00 +#define TDA9840_LVADJ 0x02 +#define TDA9840_STADJ 0x03 +#define TDA9840_TEST 0x04 +#endif + +#define PT2254_L_CHANEL 0x10 +#define PT2254_R_CHANEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +struct bttv_just_hacking { + int height,width; /* size */ + unsigned int format; /* should be VIDEO_PALETTE_* */ + long buf; + int len; +}; + +#define BTTV_JUST_HACKING _IOR('v' , BASE_VIDIOCPRIVATE+31,struct bttv_just_hacking) + +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c --- v2.4.0-test6/linux/drivers/media/video/buz.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/buz.c Mon Aug 7 21:01:35 2000 @@ -0,0 +1,3479 @@ +#define MAX_KMALLOC_MEM (512*1024) +/* + buz - Iomega Buz driver version 1.0 + + Copyright (C) 1999 Rainer Johanni + + based on + + buz.0.0.3 Copyright (C) 1998 Dave Perks + + and + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include "buz.h" +#include +#include + +#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) +#define GPIO_MASK 0xdf + +/* + + BUZ + + GPIO0 = 1, take board out of reset + GPIO1 = 1, take JPEG codec out of sleep mode + GPIO3 = 1, deassert FRAME# to 36060 + + + GIRQ0 signals a vertical sync of the video signal + GIRQ1 signals that ZR36060's DATERR# line is asserted. + + SAA7111A + + In their infinite wisdom, the Iomega engineers decided to + use the same input line for composite and S-Video Color, + although there are two entries not connected at all! + Through this ingenious strike, it is not possible to + keep two running video sources connected at the same time + to Composite and S-VHS input! + + mode 0 - N/C + mode 1 - S-Video Y + mode 2 - noise or something I don't know + mode 3 - Composite and S-Video C + mode 4 - N/C + mode 5 - S-Video (gain C independently selectable of gain Y) + mode 6 - N/C + mode 7 - S-Video (gain C adapted to gain Y) + */ + +#define MAJOR_VERSION 1 /* driver major version */ +#define MINOR_VERSION 0 /* driver minor version */ + +#define BUZ_NAME "Iomega BUZ V-1.0" /* name of the driver */ + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define IOCTL_DEBUG(x) + + +/* The parameters for this driver */ + +/* + The video mem address of the video card. + The driver has a little database for some videocards + to determine it from there. If your video card is not in there + you have either to give it to the driver as a parameter + or set in in a VIDIOCSFBUF ioctl + */ + +static unsigned long vidmem = 0; /* Video memory base address */ + +/* Special purposes only: */ + +static int triton = 0; /* 0=no, 1=yes */ +static int natoma = 0; /* 0=no, 1=yes */ + +/* + Number and size of grab buffers for Video 4 Linux + The vast majority of applications should not need more than 2, + the very popular BTTV driver actually does ONLY have 2. + Time sensitive applications might need more, the maximum + is VIDEO_MAX_FRAME (defined in ). + + The size is set so that the maximum possible request + can be satisfied. Decrease it, if bigphys_area alloc'd + memory is low. If you don't have the bigphys_area patch, + set it to 128 KB. Will you allow only to grab small + images with V4L, but that's better than nothing. + + v4l_bufsize has to be given in KB ! + + */ + +static int v4l_nbufs = 2; +static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ + +/* + Default input and video norm at startup of the driver. + */ + +static int default_input = 0; /* 0=Composite, 1=S-VHS */ +static int default_norm = 0; /* 0=PAL, 1=NTSC */ + +MODULE_PARM(vidmem, "i"); +MODULE_PARM(triton, "i"); +MODULE_PARM(natoma, "i"); +MODULE_PARM(v4l_nbufs, "i"); +MODULE_PARM(v4l_bufsize, "i"); +MODULE_PARM(default_input, "i"); +MODULE_PARM(default_norm, "i"); + +/* Anybody who uses more than four? */ +#define BUZ_MAX 4 + +static int zoran_num; /* number of Buzs in use */ +static struct zoran zoran[BUZ_MAX]; + +/* forward references */ + +static void v4l_fbuffer_free(struct zoran *zr); +static void jpg_fbuffer_free(struct zoran *zr); +static void zoran_feed_stat_com(struct zoran *zr); + + + +/* + * Allocate the V4L grab buffers + * + * These have to be pysically contiguous. + * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc + */ + +static int v4l_fbuffer_alloc(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (zr->v4l_gbuf[i].fbuffer) + printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); + + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + /* Use kmalloc */ + + mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_reserve(virt_to_page(mem + off)); + DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); + } else { + return -ENOBUFS; + } + } + + return 0; +} + +/* free the V4L grab buffers */ +static void v4l_fbuffer_free(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (!zr->v4l_gbuf[i].fbuffer) + continue; + + mem = zr->v4l_gbuf[i].fbuffer; + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_unreserve(virt_to_page(mem + off)); + kfree((void *) zr->v4l_gbuf[i].fbuffer); + zr->v4l_gbuf[i].fbuffer = NULL; + } +} + +/* + * Allocate the MJPEG grab buffers. + * + * If the requested buffer size is smaller than MAX_KMALLOC_MEM, + * kmalloc is used to request a physically contiguous area, + * else we allocate the memory in framgents with get_free_page. + * + * If a Natoma chipset is present and this is a revision 1 zr36057, + * each MJPEG buffer needs to be physically contiguous. + * (RJ: This statement is from Dave Perks' original driver, + * I could never check it because I have a zr36067) + * The driver cares about this because it reduces the buffer + * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). + * + * RJ: The contents grab buffers needs never be accessed in the driver. + * Therefore there is no need to allocate them with vmalloc in order + * to get a contiguous virtual memory space. + * I don't understand why many other drivers first allocate them with + * vmalloc (which uses internally also get_free_page, but delivers you + * virtual addresses) and then again have to make a lot of efforts + * to get the physical address. + * + */ + +static int jpg_fbuffer_alloc(struct zoran *zr) +{ + int i, j, off, alloc_contig; + unsigned long mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->jpg_gbuf[i].frag_tab) + printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i); + + /* Allocate fragment table for this buffer */ + + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + memset((void *) mem, 0, PAGE_SIZE); + zr->jpg_gbuf[i].frag_tab = (u32 *) mem; + zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); + + if (alloc_contig) { + mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); + if (mem == 0) { + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1; + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_reserve(virt_to_page(mem + off)); + } else { + /* jpg_bufsize is alreay page aligned */ + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1; + mem_map_reserve(virt_to_page(mem)); + } + + zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; + } + } + + DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n", + (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); + zr->jpg_buffers_allocated = 1; + return 0; +} + +/* free the MJPEG grab buffers */ +static void jpg_fbuffer_free(struct zoran *zr) +{ + int i, j, off, alloc_contig; + unsigned char *mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (!zr->jpg_gbuf[i].frag_tab) + continue; + + if (alloc_contig) { + if (zr->jpg_gbuf[i].frag_tab[0]) { + mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]); + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_unreserve(virt_to_page(mem + off)); + kfree((void *) mem); + zr->jpg_gbuf[i].frag_tab[0] = 0; + zr->jpg_gbuf[i].frag_tab[1] = 0; + } + } else { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + if (!zr->jpg_gbuf[i].frag_tab[2 * j]) + break; + mem_map_unreserve(virt_to_page(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]))); + free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])); + zr->jpg_gbuf[i].frag_tab[2 * j] = 0; + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; + } + } + + free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); + zr->jpg_gbuf[i].frag_tab = NULL; + } + zr->jpg_buffers_allocated = 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* I2C functions */ + +#define I2C_DELAY 10 + + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) +{ + struct zoran *zr = (struct zoran *) bus->data; + btwrite((data << 1) | ctrl, ZR36057_I2CBR); + btread(ZR36057_I2CBR); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *zr = (struct zoran *) bus->data; + return (btread(ZR36057_I2CBR) >> 1) & 1; +} + +static void attach_inform(struct i2c_bus *bus, int id) +{ + DEBUG(struct zoran *zr = (struct zoran *) bus->data); + DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id)); +} + +static void detach_inform(struct i2c_bus *bus, int id) +{ + DEBUG(struct zoran *zr = (struct zoran *) bus->data); + DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); +} + +static struct i2c_bus zoran_i2c_bus_template = +{ + "zr36057", + I2C_BUSID_BT848, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL, +}; + + +/* ----------------------------------------------------------------------- */ + +static void GPIO(struct zoran *zr, unsigned bit, unsigned value) +{ + u32 reg; + u32 mask; + + mask = 1 << (24 + bit); + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) { + reg |= mask; + } + btwrite(reg, ZR36057_GPPGCR1); + /* Stop any PCI posting on the GPIO bus */ + btread(ZR36057_I2CBR); +} + + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.zoran.com - nicely done those folks. + */ + +struct tvnorm { + u16 Wt, Wa, Ht, Ha, HStart, VStart; +}; + +static struct tvnorm tvnorms[] = +{ + /* PAL-BDGHI */ + {864, 720, 625, 576, 31, 16}, + /* NTSC */ + {858, 720, 525, 480, 21, 8}, +}; +#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm)) + +static int format2bpp(int format) +{ + int bpp; + + /* Determine the number of bytes per pixel for the video format requested */ + + switch (format) { + + case VIDEO_PALETTE_YUV422: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB555: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB565: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB24: + bpp = 3; + break; + + case VIDEO_PALETTE_RGB32: + bpp = 4; + break; + + default: + bpp = 0; + } + + return bpp; +} + +/* + * set geometry + */ +static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, + unsigned int video_format) +{ + struct tvnorm *tvn; + unsigned HStart, HEnd, VStart, VEnd; + unsigned DispMode; + unsigned VidWinWid, VidWinHt; + unsigned hcrop1, hcrop2, vcrop1, vcrop2; + unsigned Wa, We, Ha, He; + unsigned X, Y, HorDcm, VerDcm; + u32 reg; + unsigned mask_line_size; + + if (zr->params.norm < 0 || zr->params.norm > 1) { + printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name, zr->params.norm); + return; + } + if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) { + printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height); + return; + } + tvn = &tvnorms[zr->params.norm]; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + /* if window has more than half of active height, + switch on interlacing - we want the full information */ + + zr->video_interlace = (video_height > Ha / 2); + +/**** zr36057 ****/ + + /* horizontal */ + VidWinWid = video_width; + X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; + We = (VidWinWid * 64) / X; + HorDcm = 64 - X; + hcrop1 = 2 * ((tvn->Wa - We) / 4); + hcrop2 = tvn->Wa - We - hcrop1; + HStart = tvn->HStart | 1; + HEnd = HStart + tvn->Wa - 1; + HStart += hcrop1; + HEnd -= hcrop2; + reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) + | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); + reg |= ZR36057_VFEHCR_HSPol; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + DispMode = !zr->video_interlace; + VidWinHt = DispMode ? video_height : video_height / 2; + Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; + He = (VidWinHt * 64) / Y; + VerDcm = 64 - Y; + vcrop1 = (tvn->Ha / 2 - He) / 2; + vcrop2 = tvn->Ha / 2 - He - vcrop1; + VStart = tvn->VStart; + VEnd = VStart + tvn->Ha / 2 - 1; + VStart += vcrop1; + VEnd -= vcrop2; + reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) + | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); + reg |= ZR36057_VFEVCR_VSPol; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ + | (HorDcm << ZR36057_VFESPFR_HorDcm) + | (VerDcm << ZR36057_VFESPFR_VerDcm) + | (DispMode << ZR36057_VFESPFR_DispMode) + | ZR36057_VFESPFR_LittleEndian; + /* RJ: I don't know, why the following has to be the opposite + of the corresponding ZR36060 setting, but only this way + we get the correct colors when uncompressing to the screen */ + reg |= ZR36057_VFESPFR_VCLKPol; + /* RJ: Don't know if that is needed for NTSC also */ + reg |= ZR36057_VFESPFR_TopField; + switch (video_format) { + + case VIDEO_PALETTE_YUV422: + reg |= ZR36057_VFESPFR_YUV422; + break; + + case VIDEO_PALETTE_RGB555: + reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB565: + reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB24: + reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; + break; + + case VIDEO_PALETTE_RGB32: + reg |= ZR36057_VFESPFR_RGB888; + break; + + default: + printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); + return; + + } + if (HorDcm >= 48) { + reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ + } else if (HorDcm >= 32) { + reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ + } else if (HorDcm >= 16) { + reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ + } + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + + reg = (16 << ZR36057_VDCR_MinPix) + | (VidWinHt << ZR36057_VDCR_VidWinHt) + | (VidWinWid << ZR36057_VDCR_VidWinWid); + if (triton) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); + + /* Write overlay clipping mask data, but don't enable overlay clipping */ + /* RJ: since this makes only sense on the screen, we use + zr->window.width instead of video_width */ + + mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + reg = virt_to_bus(zr->overlay_mask); + btwrite(reg, ZR36057_MMTR); + reg = virt_to_bus(zr->overlay_mask + mask_line_size); + btwrite(reg, ZR36057_MMBR); + reg = mask_line_size - (zr->window.width + 31) / 32; + if (DispMode == 0) + reg += mask_line_size; + reg <<= ZR36057_OCR_MaskStride; + btwrite(reg, ZR36057_OCR); + +} + +/* + * Switch overlay on or off + */ + +static void zr36057_overlay(struct zoran *zr, int on) +{ + int fmt, bpp; + u32 reg; + + if (on) { + /* do the necessary settings ... */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ + + switch (zr->buffer.depth) { + case 15: + fmt = VIDEO_PALETTE_RGB555; + bpp = 2; + break; + case 16: + fmt = VIDEO_PALETTE_RGB565; + bpp = 2; + break; + case 24: + fmt = VIDEO_PALETTE_RGB24; + bpp = 3; + break; + case 32: + fmt = VIDEO_PALETTE_RGB32; + bpp = 4; + break; + default: + fmt = 0; + bpp = 0; + } + + zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); + + /* Start and length of each line MUST be 4-byte aligned. + This should be allready checked before the call to this routine. + All error messages are internal driver checking only! */ + + /* video display top and bottom registers */ + + reg = (u32) zr->buffer.base + + zr->window.x * bpp + + zr->window.y * zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDTR); + if (reg & 3) + printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = zr->buffer.bytesperline - zr->window.width * bpp; + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + if (reg & 3) + printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ + btwrite(reg, ZR36057_VSSFGR); + + /* Set overlay clipping */ + + if (zr->window.clipcount) + btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); + + /* ... and switch it on */ + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } else { + /* Switch it off */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + } +} + +/* + * The overlay mask has one bit for each pixel on a scan line, + * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. + */ +static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count) +{ + unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + u32 *mask; + int x, y, width, height; + unsigned i, j, k; + u32 reg; + + /* fill mask with one bits */ + memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); + reg = 0; + + for (i = 0; i < count; ++i) { + /* pick up local copy of clip */ + x = vp[i].x; + y = vp[i].y; + width = vp[i].width; + height = vp[i].height; + + /* trim clips that extend beyond the window */ + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > zr->window.width) { + width = zr->window.width - x; + } + if (y + height > zr->window.height) { + height = zr->window.height - y; + } + /* ignore degenerate clips */ + if (height <= 0) { + continue; + } + if (width <= 0) { + continue; + } + /* apply clip for each scan line */ + for (j = 0; j < height; ++j) { + /* reset bit for each pixel */ + /* this can be optimized later if need be */ + mask = zr->overlay_mask + (y + j) * mask_line_size; + for (k = 0; k < width; ++k) { + mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); + } + } + } +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ + +static void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) + printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); + + /* switch on VSync interrupts */ + + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + + btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); + + /* enable SnapShot */ + + btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + +#ifdef XAWTV_HACK + zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat); +#else + zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); +#endif + + zr->v4l_memgrab_active = 1; + } else { + zr->v4l_memgrab_active = 0; + + /* switch off VSync interrupts */ + + btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); + + /* reenable grabbing to screen if it was running */ + + if (zr->v4l_overlay_active) { + zr36057_overlay(zr, 1); + } else { + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + } + } +} + +static int wait_grab_pending(struct zoran *zr) +{ + unsigned long flags; + + /* wait until all pending grabs are finished */ + + if (!zr->v4l_memgrab_active) + return 0; + + while (zr->v4l_pend_tail != zr->v4l_pend_head) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + zr36057_set_memgrab(zr, 0); + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* + * V4L Buffer grabbing + */ + +static int v4l_grab(struct zoran *zr, struct video_mmap *mp) +{ + unsigned long flags; + int res, bpp; + + /* + * There is a long list of limitations to what is allowed to be grabbed + * We don't output error messages her, since some programs (e.g. xawtv) + * just try several settings to find out what is valid or not. + */ + + /* No grabbing outside the buffer range! */ + + if (mp->frame >= v4l_nbufs || mp->frame < 0) + return -EINVAL; + + /* Check size and format of the grab wanted */ + + if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) + return -EINVAL; + if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) + return -EINVAL; + + bpp = format2bpp(mp->format); + if (bpp == 0) + return -EINVAL; + + /* Check against available buffer size */ + + if (mp->height * mp->width * bpp > v4l_bufsize) + return -EINVAL; + + /* The video front end needs 4-byte alinged line sizes */ + + if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) + return -EINVAL; + + /* + * To minimize the time spent in the IRQ routine, we avoid setting up + * the video front end there. + * If this grab has different parameters from a running streaming capture + * we stop the streaming capture and start it over again. + */ + + if (zr->v4l_memgrab_active && + (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { + res = wait_grab_pending(zr); + if (res) + return res; + } + zr->gwidth = mp->width; + zr->gheight = mp->height; + zr->gformat = mp->format; + zr->gbpl = bpp * zr->gwidth; + + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->v4l_gbuf[mp->frame].state) { + + default: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + case BUZ_STATE_DONE: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; + zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; + res = 0; + break; + + } + + /* put the 36057 into frame grabbing mode */ + + if (!res && !zr->v4l_memgrab_active) + zr36057_set_memgrab(zr, 1); + + spin_unlock_irqrestore(&zr->lock, flags); + + return res; +} + +/* + * Sync on a V4L buffer + */ + +static int v4l_sync(struct zoran *zr, int frame) +{ + unsigned long flags; + + + /* check passed-in frame number */ + if (frame >= v4l_nbufs || frame < 0) { + printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); + return -EINVAL; + } + /* Check if is buffer was queued at all */ + + if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { +// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); + return -EINVAL; + } + /* wait on this buffer to get ready */ + + while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); + + /* Check if streaming capture has finished */ + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->v4l_pend_tail == zr->v4l_pend_head) + zr36057_set_memgrab(zr, 0); + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +/* + * Wait til post office is no longer busy + */ + +static int post_office_wait(struct zoran *zr) +{ + u32 por; + u32 ct=0; + + while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { + ct++; + if(ct>100000) + { + printk(KERN_ERR "%s: timeout on post office.\n", zr->name); + return -1; + } + /* wait for something to happen */ + } + if ((por & ZR36057_POR_POPen) != 0) { + printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); + return -1; + } + if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { + printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); + return -1; + } + return 0; +} + +static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value) +{ + u32 por; + + post_office_wait(zr); + por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + return post_office_wait(zr); +} + +static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) +{ + u32 por; + + post_office_wait(zr); + por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) { + return -1; + } + return btread(ZR36057_POR) & 0xFF; +} + +static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_write(zr, 0, 3, val); +} + +static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 8)) { + return -1; + } + return zr36060_write_8(zr, reg + 1, val >> 0); +} + +static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 1, val >> 0); +} + +static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_16(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 2, val >> 0); +} + +static u32 zr36060_read_8(struct zoran *zr, unsigned reg) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_read(zr, 0, 3) & 0xFF; +} + +static int zr36060_reset(struct zoran *zr) +{ + return post_office_write(zr, 3, 0, 0); +} + +static void zr36060_sleep(struct zoran *zr, int sleep) +{ + GPIO(zr, 1, !sleep); +} + + +static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int size; + + reg = (1 << 0) /* CodeMstr */ + |(0 << 2) /* CFIS=0 */ + |(0 << 6) /* Endian=0 */ + |(0 << 7); /* Code16=0 */ + zr36060_write_8(zr, 0x002, reg); + + switch (mode) { + + case BUZ_MODE_MOTION_DECOMPRESS: + case BUZ_MODE_STILL_DECOMPRESS: + reg = 0x00; /* Codec mode = decompression */ + break; + + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_STILL_COMPRESS: + default: + reg = 0xa4; /* Codec mode = compression with variable scale factor */ + break; + + } + zr36060_write_8(zr, 0x003, reg); + + reg = 0x00; /* reserved, mbz */ + zr36060_write_8(zr, 0x004, reg); + + reg = 0xff; /* 510 bits/block */ + zr36060_write_8(zr, 0x005, reg); + + /* JPEG markers */ + reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ + if (zr->params.COM_len) + reg |= JPEG_MARKER_COM; + if (zr->params.APP_len) + reg |= JPEG_MARKER_APP; + zr36060_write_8(zr, 0x006, reg); + + reg = (0 << 3) /* DATERR=0 */ + |(0 << 2) /* END=0 */ + |(0 << 1) /* EOI=0 */ + |(0 << 0); /* EOAV=0 */ + zr36060_write_8(zr, 0x007, reg); + + /* code volume */ + + /* Target field size in pixels: */ + tvn = &tvnorms[zr->params.norm]; + size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm); + + /* Target compressed field size in bits: */ + size = size * 16; /* uncompressed size in bits */ + size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ + + /* Lower limit (arbitrary, 1 KB) */ + if (size < 8192) + size = 8192; + + /* Upper limit: 7/8 of the code buffers */ + if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7) + size = zr->jpg_bufsize * 7 / zr->params.field_per_buff; + + reg = size; + zr36060_write_32(zr, 0x009, reg); + + /* how do we set initial SF as a function of quality parameter? */ + reg = 0x0100; /* SF=1.0 */ + zr36060_write_16(zr, 0x011, reg); + + reg = 0x00ffffff; /* AF=max */ + zr36060_write_24(zr, 0x013, reg); + + reg = 0x0000; /* test */ + zr36060_write_16(zr, 0x024, reg); +} + +static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + + reg = (0 << 7) /* Video8=0 */ + |(0 << 6) /* Range=0 */ + |(0 << 3) /* FlDet=0 */ + |(1 << 2) /* FlVedge=1 */ + |(0 << 1) /* FlExt=0 */ + |(0 << 0); /* SyncMstr=0 */ + + /* According to ZR36067 documentation, FlDet should correspond + to the odd_even flag of the ZR36067 */ + if (zr->params.odd_even) + reg |= (1 << 3); + + if (mode != BUZ_MODE_STILL_DECOMPRESS) { + /* limit pixels to range 16..235 as per CCIR-601 */ + reg |= (1 << 6); /* Range=1 */ + } + zr36060_write_8(zr, 0x030, reg); + + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(0 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + zr36060_write_8(zr, 0x031, reg); + + switch (zr->params.HorDcm) { + default: + case 1: + reg = (0 << 0); + break; /* HScale = 0 */ + + case 2: + reg = (1 << 0); + break; /* HScale = 1 */ + + case 4: + reg = (2 << 0); + break; /* HScale = 2 */ + } + if (zr->params.VerDcm == 2) + reg |= (1 << 2); + zr36060_write_8(zr, 0x032, reg); + + reg = 0x80; /* BackY */ + zr36060_write_8(zr, 0x033, reg); + + reg = 0xe0; /* BackU */ + zr36060_write_8(zr, 0x034, reg); + + reg = 0xe0; /* BackV */ + zr36060_write_8(zr, 0x035, reg); + + /* sync generator */ + + tvn = &tvnorms[zr->params.norm]; + + reg = tvn->Ht - 1; /* Vtotal */ + zr36060_write_16(zr, 0x036, reg); + + reg = tvn->Wt - 1; /* Htotal */ + zr36060_write_16(zr, 0x038, reg); + + reg = 6 - 1; /* VsyncSize */ + zr36060_write_8(zr, 0x03a, reg); + + reg = 100 - 1; /* HsyncSize */ + zr36060_write_8(zr, 0x03b, reg); + + reg = tvn->VStart - 1; /* BVstart */ + zr36060_write_8(zr, 0x03c, reg); + + reg += tvn->Ha / 2; /* BVend */ + zr36060_write_16(zr, 0x03e, reg); + + reg = tvn->HStart - 1; /* BHstart */ + zr36060_write_8(zr, 0x03d, reg); + + reg += tvn->Wa; /* BHend */ + zr36060_write_16(zr, 0x040, reg); + + /* active area */ + reg = zr->params.img_y + tvn->VStart; /* Vstart */ + zr36060_write_16(zr, 0x042, reg); + + reg += zr->params.img_height; /* Vend */ + zr36060_write_16(zr, 0x044, reg); + + reg = zr->params.img_x + tvn->HStart; /* Hstart */ + zr36060_write_16(zr, 0x046, reg); + + reg += zr->params.img_width; /* Hend */ + zr36060_write_16(zr, 0x048, reg); + + /* subimage area */ + reg = zr->params.img_y + tvn->VStart; /* SVstart */ + zr36060_write_16(zr, 0x04a, reg); + + reg += zr->params.img_height; /* SVend */ + zr36060_write_16(zr, 0x04c, reg); + + reg = zr->params.img_x + tvn->HStart; /* SHstart */ + zr36060_write_16(zr, 0x04e, reg); + + reg += zr->params.img_width; /* SHend */ + zr36060_write_16(zr, 0x050, reg); +} + +static void zr36060_set_jpg_SOF(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffc0; /* SOF marker */ + zr36060_write_16(zr, 0x060, reg); + + reg = 17; /* SOF length */ + zr36060_write_16(zr, 0x062, reg); + + reg = 8; /* precision 8 bits */ + zr36060_write_8(zr, 0x064, reg); + + reg = zr->params.img_height / zr->params.VerDcm; /* image height */ + zr36060_write_16(zr, 0x065, reg); + + reg = zr->params.img_width / zr->params.HorDcm; /* image width */ + zr36060_write_16(zr, 0x067, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x069, reg); + + reg = 0x002100; /* Y component */ + zr36060_write_24(zr, 0x06a, reg); + + reg = 0x011101; /* U component */ + zr36060_write_24(zr, 0x06d, reg); + + reg = 0x021101; /* V component */ + zr36060_write_24(zr, 0x070, reg); +} + +static void zr36060_set_jpg_SOS(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffda; /* SOS marker */ + zr36060_write_16(zr, 0x07a, reg); + + reg = 12; /* SOS length */ + zr36060_write_16(zr, 0x07c, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x07e, reg); + + reg = 0x0000; /* Y component */ + zr36060_write_16(zr, 0x07f, reg); + + reg = 0x0111; /* U component */ + zr36060_write_16(zr, 0x081, reg); + + reg = 0x0211; /* V component */ + zr36060_write_16(zr, 0x083, reg); + + reg = 0x003f00; /* Start, end spectral scans */ + zr36060_write_24(zr, 0x085, reg); +} + +static void zr36060_set_jpg_DRI(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffdd; /* DRI marker */ + zr36060_write_16(zr, 0x0c0, reg); + + reg = 4; /* DRI length */ + zr36060_write_16(zr, 0x0c2, reg); + + reg = 8; /* length in MCUs */ + zr36060_write_16(zr, 0x0c4, reg); +} + +static void zr36060_set_jpg_DQT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dqt[] = + { + 0xff, 0xdb, /* DHT marker */ + 0x00, 0x84, /* DHT length */ + 0x00, /* table ID 0 */ + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, /* table ID 1 */ + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 + }; + + /* write fixed quantitization tables */ + adr = 0x0cc; + for (i = 0; i < sizeof(dqt); ++i) { + zr36060_write_8(zr, adr++, dqt[i]); + } +} + +static void zr36060_set_jpg_DHT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dht[] = + { + 0xff, 0xc4, /* DHT marker */ + 0x01, 0xa2, /* DHT length */ + 0x00, /* table class 0, ID 0 */ + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ + 0x00, /* values for codes of length 2 */ + 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ + 0x06, /* values for codes of length 4 */ + 0x07, /* values for codes of length 5 */ + 0x08, /* values for codes of length 6 */ + 0x09, /* values for codes of length 7 */ + 0x0a, /* values for codes of length 8 */ + 0x0b, /* values for codes of length 9 */ + 0x01, /* table class 0, ID 1 */ + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ + 0x00, 0x01, 0x02, /* values for codes of length 2 */ + 0x03, /* values for codes of length 3 */ + 0x04, /* values for codes of length 4 */ + 0x05, /* values for codes of length 5 */ + 0x06, /* values for codes of length 6 */ + 0x07, /* values for codes of length 7 */ + 0x08, /* values for codes of length 8 */ + 0x09, /* values for codes of length 9 */ + 0x0a, /* values for codes of length 10 */ + 0x0b, /* values for codes of length 11 */ + 0x10, + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, + 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, + 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, + 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, + 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, + 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, + 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa + }; + + /* write fixed Huffman tables */ + adr = 0x1d4; + for (i = 0; i < sizeof(dht); ++i) { + zr36060_write_8(zr, adr++, dht[i]); + } +} + +static void zr36060_set_jpg_APP(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.APP_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + i = zr->params.APPn; + if (i < 0) + i = 0; + if (i > 15) + i = 15; + + reg = 0xffe0 + i; /* APPn marker */ + zr36060_write_16(zr, 0x380, reg); + + reg = len + 2; /* APPn len */ + zr36060_write_16(zr, 0x382, reg); + + /* write APPn data */ + adr = 0x384; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0)); + } +} + +static void zr36060_set_jpg_COM(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.COM_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + reg = 0xfffe; /* COM marker */ + zr36060_write_16(zr, 0x3c0, reg); + + reg = len + 2; /* COM len */ + zr36060_write_16(zr, 0x3c2, reg); + + /* write COM data */ + adr = 0x3c4; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0)); + } +} + +static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) +{ + unsigned i; + u32 reg; + + zr36060_reset(zr); + mdelay(10); + + reg = (0 << 7) /* Load=0 */ + |(1 << 0); /* SynRst=1 */ + zr36060_write_8(zr, 0x000, reg); + + zr36060_set_jpg(zr, mode); + zr36060_set_video(zr, mode); + zr36060_set_jpg_SOF(zr); + zr36060_set_jpg_SOS(zr); + zr36060_set_jpg_DRI(zr); + zr36060_set_jpg_DQT(zr); + zr36060_set_jpg_DHT(zr); + zr36060_set_jpg_APP(zr); + zr36060_set_jpg_COM(zr); + + reg = (1 << 7) /* Load=1 */ + |(0 << 0); /* SynRst=0 */ + zr36060_write_8(zr, 0x000, reg); + + /* wait for codec to unbusy */ + for (i = 0; i < 1000; ++i) { + reg = zr36060_read_8(zr, 0x001); + if ((reg & (1 << 7)) == 0) { + DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i)); + return; + } + udelay(1000); + } + printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg); +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int i; + + tvn = &tvnorms[zr->params.norm]; + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + for (i = 0; i < BUZ_NUM_STAT_COM; ++i) { + zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ + } + for (i = 0; i < zr->jpg_nbufs; i++) { + zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* MJPEG compression mode */ + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPGCmpMode; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPGExpMode; + reg |= ZR36057_JMC_SyncMstr; + /* RJ: The following is experimental - improves the output to screen */ + if (zr->params.VFIFO_FB) + reg |= ZR36057_JMC_VFIFO_FB; + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPGCmpMode; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPGExpMode; + break; + + } + reg |= ZR36057_JMC_JPG; + if (zr->params.field_per_buff == 1) + reg |= ZR36057_JMC_Fld_per_buff; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); + reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); + btwrite(reg, ZR36057_VSP); + reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) + | (zr->params.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); + reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot); + btwrite(reg, ZR36057_HSP); + reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX) + | (zr->params.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->params.odd_even) + reg = ZR36057_FPP_Odd_Even; + else + reg = 0; + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); + + /* code base address and FIFO threshold */ + reg = virt_to_bus(zr->stat_com); + btwrite(reg, ZR36057_JCBA); + reg = 0x50; + btwrite(reg, ZR36057_JCFT); + + /* JPEG codec guest ID */ + reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg); + btwrite(reg, ZR36057_JCGI); + + /* Code transfer guest ID */ + reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg); + reg |= ZR36057_MCTCR_CFlush; + btwrite(reg, ZR36057_MCTCR); + + /* deassert P_Reset */ + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); +} + +static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + static int zero = 0; + static int one = 1; + + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + zr36060_set_cap(zr, mode); + zr36057_set_jpg(zr, mode); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); + + /* deassert P_Reset, assert Code transfer enable */ + btwrite(IRQ_MASK, ZR36057_ISR); + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one); + zr36060_set_cap(zr, mode); + zr36057_set_jpg(zr, mode); + + /* deassert P_Reset, assert Code transfer enable */ + btwrite(IRQ_MASK, ZR36057_ISR); + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + btwrite(0, ZR36057_ISR); + zr36060_reset(zr); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); + break; + + } + zr->codec_mode = mode; +} + +/* + * Queue a MJPEG buffer for capture/playback + */ + +static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode) +{ + unsigned long flags; + int res; + + /* Check if buffers are allocated */ + + if (!zr->jpg_buffers_allocated) { + printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name); + return -ENOMEM; + } + /* Does the user want to stop streaming? */ + + if (frame < 0) { + if (zr->codec_mode == mode) { + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + return 0; + } else { + printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name); + return -EINVAL; + } + } + /* No grabbing outside the buffer range! */ + + if (frame >= zr->jpg_nbufs) { + printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame); + return -EINVAL; + } + /* what is the codec mode right now? */ + + if (zr->codec_mode == BUZ_MODE_IDLE) { + /* Ok load up the zr36060 and go */ + zr36057_enable_jpg(zr, mode); + } else if (zr->codec_mode != mode) { + /* wrong codec mode active - invalid */ + printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name); + return -EINVAL; + } + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->jpg_gbuf[frame].state) { + + default: + case BUZ_STATE_DMA: + case BUZ_STATE_PEND: + case BUZ_STATE_DONE: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; + zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; + zoran_feed_stat_com(zr); + res = 0; + break; + + } + + spin_unlock_irqrestore(&zr->lock, flags); + + /* Start the zr36060 when the first frame is queued */ + if (zr->jpg_que_head == 1) { + btor(ZR36057_JMC_Go_en, ZR36057_JMC); + btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC); + } + return res; +} + +/* + * Sync on a MJPEG buffer + */ + +static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) +{ + unsigned long flags; + int frame; + + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && + zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + return -EINVAL; + } + while (zr->jpg_que_tail == zr->jpg_dma_tail) { + interruptible_sleep_on(&zr->jpg_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + + frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name); + + *bs = zr->jpg_gbuf[frame].bs; + zr->jpg_gbuf[frame].state = BUZ_STATE_USER; + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* when this is called the spinlock must be held */ +static void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int frame, i, max_stat_com; + + max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com + && zr->jpg_dma_head != zr->jpg_que_head) { + + frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; + if (zr->params.TmpDcm == 1) { + /* fill 1 stat_com entry */ + i = zr->jpg_dma_head & BUZ_MASK_STAT_COM; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + } else { + /* fill 2 stat_com entries */ + i = (zr->jpg_dma_head & 1) * 2; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus; + } + zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; + zr->jpg_dma_head++; + + } +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + int frame; + struct zoran_gbuffer *gbuf; + + /* In motion decompress we don't have a hardware frame counter, + we just count the interrupts here */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_seq_num++; + + while (zr->jpg_dma_tail != zr->jpg_dma_head) { + if (zr->params.TmpDcm == 1) + i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM; + else + i = (zr->jpg_dma_tail & 1) * 2 + 1; + + stat_com = zr->stat_com[i]; + + if ((stat_com & 1) == 0) { + return; + } + frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; + gbuf = &zr->jpg_gbuf[frame]; + get_fast_time(&gbuf->bs.timestamp); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + gbuf->bs.length = (stat_com & 0x7fffff) >> 1; + + /* update sequence number with the help of the counter in stat_com */ + + seq = stat_com >> 24; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } else { + gbuf->bs.length = 0; + } + gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + gbuf->state = BUZ_STATE_DONE; + + zr->jpg_dma_tail++; + } +} + +static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, astat; + int count; + struct zoran *zr; + unsigned long flags; + + zr = (struct zoran *) dev_id; + count = 0; + + spin_lock_irqsave(&zr->lock, flags); + while (1) { + /* get/clear interrupt status bits */ + stat = btread(ZR36057_ISR); + astat = stat & IRQ_MASK; + if (!astat) { + break; + } + btwrite(astat, ZR36057_ISR); + IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat)); + +#if (IRQ_MASK & ZR36057_ISR_GIRQ0) + if (astat & ZR36057_ISR_GIRQ0) { + + /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. + We simply ignore them */ + + if (zr->v4l_memgrab_active) { + +/* A lot more checks should be here ... */ + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) + printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name); + + if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { + /* There is a grab on a frame going on, check if it has finished */ + + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { + /* it is finished, notify the user */ + + zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE; + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq++; + zr->v4l_pend_tail++; + } + } + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) + wake_up_interruptible(&zr->v4l_capq); + + /* Check if there is another grab queued */ + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && + zr->v4l_pend_tail != zr->v4l_pend_head) { + + int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; + u32 reg; + + zr->v4l_grab_frame = frame; + + /* Set zr36057 video front end and enable video */ + + /* Buffer address */ + + reg = zr->v4l_gbuf[frame].fbuffer_bus; + btwrite(reg, ZR36057_VDTR); + if (zr->video_interlace) + reg += zr->gbpl; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + +#ifdef XAWTV_HACK + reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0; +#else + reg = 0; +#endif + if (zr->video_interlace) + reg += zr->gbpl; + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; + reg |= ZR36057_VSSFGR_SnapShot; + reg |= ZR36057_VSSFGR_FrameGrab; + btwrite(reg, ZR36057_VSSFGR); + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } + } + } +#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */ + +#if (IRQ_MASK & ZR36057_ISR_GIRQ1) + if (astat & ZR36057_ISR_GIRQ1) { + unsigned csr = zr36060_read_8(zr, 0x001); + unsigned isr = zr36060_read_8(zr, 0x008); + + IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n", + zr->name, csr, isr)); + + btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + } +#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */ + +#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) + if (astat & ZR36057_ISR_CodRepIRQ) { + IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name)); + btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); + } +#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ + +#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) + if ((astat & ZR36057_ISR_JPEGRepIRQ) && + (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || + zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + } +#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ + + count++; + if (count > 10) { + printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count); + if (count > 20) { + btwrite(0, ZR36057_ICR); + printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n", zr->name); + break; + } + } + } + spin_unlock_irqrestore(&zr->lock, flags); +} + +/* Check a zoran_params struct for correctness, insert default params */ + +static int zoran_check_params(struct zoran *zr, struct zoran_params *params) +{ + int err = 0, err0 = 0; + + /* insert constant params */ + + params->major_version = MAJOR_VERSION; + params->minor_version = MINOR_VERSION; + + /* Check input and norm */ + + if (params->input != 0 && params->input != 1) { + err++; + } + if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) { + err++; + } + /* Check decimation, set default values for decimation = 1, 2, 4 */ + + switch (params->decimation) { + case 1: + + params->HorDcm = 1; + params->VerDcm = 1; + params->TmpDcm = 1; + params->field_per_buff = 2; + + params->img_x = 0; + params->img_y = 0; + params->img_width = 720; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 2: + + params->HorDcm = 2; + params->VerDcm = 1; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = 704; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 4: + + params->HorDcm = 4; + params->VerDcm = 2; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = 704; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 0: + + /* We have to check the data the user has set */ + + if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4) + err0++; + if (params->VerDcm != 1 && params->VerDcm != 2) + err0++; + if (params->TmpDcm != 1 && params->TmpDcm != 2) + err0++; + if (params->field_per_buff != 1 && params->field_per_buff != 2) + err0++; + + if (params->img_x < 0) + err0++; + if (params->img_y < 0) + err0++; + if (params->img_width < 0) + err0++; + if (params->img_height < 0) + err0++; + if (params->img_x + params->img_width > 720) + err0++; + if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2) + err0++; + if (params->img_width % (16 * params->HorDcm) != 0) + err0++; + if (params->img_height % (8 * params->VerDcm) != 0) + err0++; + + if (err0) { + err++; + } + break; + + default: + err++; + break; + } + + if (params->quality > 100) + params->quality = 100; + if (params->quality < 5) + params->quality = 5; + + if (params->APPn < 0) + params->APPn = 0; + if (params->APPn > 15) + params->APPn = 15; + if (params->APP_len < 0) + params->APP_len = 0; + if (params->APP_len > 60) + params->APP_len = 60; + if (params->COM_len < 0) + params->COM_len = 0; + if (params->COM_len > 60) + params->COM_len = 60; + + if (err) + return -EINVAL; + + return 0; + +} +static void zoran_open_init_params(struct zoran *zr) +{ + int i; + + /* Per default, map the V4L Buffers */ + + zr->map_mjpeg_buffers = 0; + + /* User must explicitly set a window */ + + zr->window_set = 0; + + zr->window.x = 0; + zr->window.y = 0; + zr->window.width = 0; + zr->window.height = 0; + zr->window.chromakey = 0; + zr->window.flags = 0; + zr->window.clips = NULL; + zr->window.clipcount = 0; + + zr->video_interlace = 0; + + zr->v4l_memgrab_active = 0; + zr->v4l_overlay_active = 0; + + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq = 0; + + zr->gwidth = 0; + zr->gheight = 0; + zr->gformat = 0; + zr->gbpl = 0; + + /* DMA ring stuff for V4L */ + + zr->v4l_pend_tail = 0; + zr->v4l_pend_head = 0; + for (i = 0; i < v4l_nbufs; i++) { + zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* Set necessary params and call zoran_check_params to set the defaults */ + + zr->params.decimation = 1; + + zr->params.quality = 50; /* default compression factor 8 */ + zr->params.odd_even = 1; + + zr->params.APPn = 0; + zr->params.APP_len = 0; /* No APPn marker */ + for (i = 0; i < 60; i++) + zr->params.APP_data[i] = 0; + + zr->params.COM_len = 0; /* No COM marker */ + for (i = 0; i < 60; i++) + zr->params.COM_data[i] = 0; + + zr->params.VFIFO_FB = 0; + + memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); + + zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; + + i = zoran_check_params(zr, &zr->params); + if (i) + printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name); +} + +/* + * Open a buz card. Right now the flags stuff is just playing + */ + +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *zr = (struct zoran *) dev; + + DEBUG(printk(KERN_INFO ": zoran_open\n")); + + switch (flags) { + + case 0: + if (zr->user) + return -EBUSY; + zr->user++; + + if (v4l_fbuffer_alloc(zr) < 0) { + zr->user--; + return -ENOMEM; + } + /* default setup */ + + zoran_open_init_params(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts + + btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); + + break; + + default: + return -EBUSY; + + } + MOD_INC_USE_COUNT; + return 0; +} + +static void zoran_close(struct video_device *dev) +{ + struct zoran *zr = (struct zoran *) dev; + + DEBUG(printk(KERN_INFO ": zoran_close\n")); + + /* disable interrupts */ + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + + /* wake up sleeping beauties */ + wake_up_interruptible(&zr->v4l_capq); + wake_up_interruptible(&zr->jpg_capq); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + zr36057_set_memgrab(zr, 0); + if (zr->v4l_overlay_active) + zr36057_overlay(zr, 0); + + zr->user--; + + v4l_fbuffer_free(zr); + jpg_fbuffer_free(zr); + zr->jpg_nbufs = 0; + + MOD_DEC_USE_COUNT; + DEBUG(printk(KERN_INFO ": zoran_close done\n")); +} + + +static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +/* + * ioctl routine + */ + + +static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran *zr = (struct zoran *) dev; + + switch (cmd) { + + case VIDIOCGCAP: + { + struct video_capability b; + IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n")); + strncpy(b.name, zr->video_dev.name, sizeof(b.name)); + b.type = VID_TYPE_CAPTURE | + VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | + VID_TYPE_SCALES; + /* theoretically we could also flag VID_TYPE_SUBCAPTURE + but this is not even implemented in the BTTV driver */ + + b.channels = 2; /* composite, svhs */ + b.audios = 0; + b.maxwidth = BUZ_MAX_WIDTH; + b.maxheight = BUZ_MAX_HEIGHT; + b.minwidth = BUZ_MIN_WIDTH; + b.minheight = BUZ_MIN_HEIGHT; + 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; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel)); + switch (v.channel) { + case 0: + strcpy(v.name, "Composite"); + break; + case 1: + strcpy(v.name, "SVHS"); + break; + default: + return -EINVAL; + } + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = zr->params.norm; + if (copy_to_user(arg, &v, sizeof(v))) { + return -EFAULT; + } + return 0; + } + + /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: + + * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." + * ^^^^^^^ + * The famos BTTV driver has it implemented with a struct video_channel argument + * and we follow it for compatibility reasons + * + * BTW: this is the only way the user can set the norm! + */ + + case VIDIOCSCHAN: + { + struct video_channel v; + int input; + int on, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm)); + switch (v.channel) { + case 0: + input = 3; + break; + case 1: + input = 7; + break; + default: + return -EINVAL; + } + + if (v.norm != VIDEO_MODE_PAL + && v.norm != VIDEO_MODE_NTSC) { + return -EINVAL; + } + zr->params.norm = v.norm; + zr->params.input = v.channel; + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + if (on) + zr36057_overlay(zr, 1); + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + + case VIDIOCGPICT: + { + struct video_picture p = zr->picture; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n")); + p.depth = zr->buffer.depth; + switch (zr->buffer.depth) { + case 15: + p.palette = VIDEO_PALETTE_RGB555; + break; + + case 16: + p.palette = VIDEO_PALETTE_RGB565; + break; + + case 24: + p.palette = VIDEO_PALETTE_RGB24; + break; + + case 32: + p.palette = VIDEO_PALETTE_RGB32; + break; + } + + 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; + } + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); + IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", + p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette)); + /* The depth and palette values have no meaning to us, + should we return -EINVAL if they don't fit ? */ + zr->picture = p; + return 0; + } + + case VIDIOCCAPTURE: + { + int v, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v)); + /* If there is nothing to do, return immediatly */ + + if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active)) + return 0; + + if (v == 0) { + zr->v4l_overlay_active = 0; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 0); + /* When a grab is running, the video simply won't be switched on any more */ + } else { + if (!zr->buffer_set || !zr->window_set) { + return -EINVAL; + } + zr->v4l_overlay_active = 1; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 1); + /* When a grab is running, the video will be switched on when grab is finished */ + } + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + return 0; + } + + case VIDIOCGWIN: + { + IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n")); + if (copy_to_user(arg, &zr->window, sizeof(zr->window))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSWIN: + { + struct video_clip *vcp; + struct video_window vw; + int on, end, res; + + if (copy_from_user(&vw, arg, sizeof(vw))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount)); + if (!zr->buffer_set) { + return -EINVAL; + } + /* + * The video front end needs 4-byte alinged line sizes, we correct that + * silently here if necessary + */ + + if (zr->buffer.depth == 15 || zr->buffer.depth == 16) { + end = (vw.x + vw.width) & ~1; /* round down */ + vw.x = (vw.x + 1) & ~1; /* round up */ + vw.width = end - vw.x; + } + if (zr->buffer.depth == 24) { + end = (vw.x + vw.width) & ~3; /* round down */ + vw.x = (vw.x + 3) & ~3; /* round up */ + vw.width = end - vw.x; + } +#if 0 + // At least xawtv seems to care about the following - just leave it away + /* + * Also corrected silently (as long as window fits at all): + * video not fitting the screen + */ +#if 0 + if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width || + vw.y + vw.height > zr->buffer.height) { + printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n", + vw.width, vw.height, vw.x, vw.y); + return -EINVAL; + } +#else + if (vw.x < 0) + vw.x = 0; + if (vw.y < 0) + vw.y = 0; + if (vw.x + vw.width > zr->buffer.width) + vw.width = zr->buffer.width - vw.x; + if (vw.y + vw.height > zr->buffer.height) + vw.height = zr->buffer.height - vw.y; +#endif +#endif + + /* Check for vaild parameters */ + if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || + vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { + return -EINVAL; + } +#ifdef XAWTV_HACK + if (vw.width > 720) + vw.width = 720; +#endif + + zr->window.x = vw.x; + zr->window.y = vw.y; + zr->window.width = vw.width; + zr->window.height = vw.height; + zr->window.chromakey = 0; + zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? + + zr->window.clips = NULL; + zr->window.clipcount = vw.clipcount; + + /* + * If an overlay is running, we have to switch it off + * and switch it on again in order to get the new settings in effect. + * + * We also want to avoid that the overlay mask is written + * when an overlay is running. + */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + /* + * Write the overlay mask if clips are wanted. + */ + if (vw.clipcount) { + vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4)); + if (vcp == NULL) { + return -ENOMEM; + } + if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + write_overlay_mask(zr, vcp, vw.clipcount); + vfree(vcp); + } + if (on) + zr36057_overlay(zr, 1); + zr->window_set = 1; + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + + case VIDIOCGFBUF: + { + IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n")); + if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSFBUF: + { + struct video_buffer v; + + if (!capable(CAP_SYS_ADMIN) + || !capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline)); + if (zr->v4l_overlay_active) { + /* Has the user gotten crazy ... ? */ + return -EINVAL; + } + if (v.depth != 15 + && v.depth != 16 + && v.depth != 24 + && v.depth != 32) { + return -EINVAL; + } + if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) { + return -EINVAL; + } + if (v.bytesperline & 3) { + return -EINVAL; + } + if (v.base) { + zr->buffer.base = (void *) ((unsigned long) v.base & ~3); + } + zr->buffer.height = v.height; + zr->buffer.width = v.width; + zr->buffer.depth = v.depth; + zr->buffer.bytesperline = v.bytesperline; + + if (zr->buffer.base) + zr->buffer_set = 1; + zr->window_set = 0; /* The user should set new window parameters */ + return 0; + } + + /* RJ: what is VIDIOCKEY intended to do ??? */ + + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + + case VIDIOCSYNC: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v)); + return v4l_sync(zr, v); + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", + vm.frame, vm.height, vm.width, vm.format)); + return v4l_grab(zr, &vm); + } + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n")); + + vm.size = v4l_nbufs * v4l_bufsize; + vm.frames = v4l_nbufs; + for (i = 0; i < v4l_nbufs; i++) { + vm.offsets[i] = i * v4l_bufsize; + } + + /* The next mmap will map the V4L buffers */ + zr->map_mjpeg_buffers = 0; + + if (copy_to_user(arg, &vm, sizeof(vm))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n")); + vu.video = zr->video_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if (copy_to_user(arg, &vu, sizeof(vu))) + return -EFAULT; + return 0; + } + + /* + * RJ: In principal we could support subcaptures for V4L grabbing. + * Not even the famous BTTV driver has them, however. + * If there should be a strong demand, one could consider + * to implement them. + */ + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + return -EINVAL; + + case BUZIOC_G_PARAMS: + { + IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n")); + if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) + return -EFAULT; + return 0; + } + + case BUZIOC_S_PARAMS: + { + struct zoran_params bp; + int input, on; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + return -EINVAL; + } + if (copy_from_user(&bp, arg, sizeof(bp))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n")); + + /* Check the params first before overwriting our internal values */ + + if (zoran_check_params(zr, &bp)) + return -EINVAL; + + zr->params = bp; + + /* Make changes of input and norm go into effect immediatly */ + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + input = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + if (on) + zr36057_overlay(zr, 1); + + if (copy_to_user(arg, &bp, sizeof(bp))) { + return -EFAULT; + } + return 0; + } + + case BUZIOC_REQBUFS: + { + struct zoran_requestbuffers br; + + if (zr->jpg_buffers_allocated) { + return -EINVAL; + } + if (copy_from_user(&br, arg, sizeof(br))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", + br.count, br.size)); + /* Enforce reasonable lower and upper limits */ + if (br.count < 4) + br.count = 4; /* Could be choosen smaller */ + if (br.count > BUZ_MAX_FRAME) + br.count = BUZ_MAX_FRAME; + br.size = PAGE_ALIGN(br.size); + if (br.size < 8192) + br.size = 8192; /* Arbitrary */ + /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ + if (br.size > (512 * 1024)) + br.size = (512 * 1024); /* 512 K should be enough */ + if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM) + br.size = MAX_KMALLOC_MEM; + + zr->jpg_nbufs = br.count; + zr->jpg_bufsize = br.size; + + if (jpg_fbuffer_alloc(zr)) + return -ENOMEM; + + /* The next mmap will map the MJPEG buffers */ + zr->map_mjpeg_buffers = 1; + + if (copy_to_user(arg, &br, sizeof(br))) { + return -EFAULT; + } + return 0; + } + + case BUZIOC_QBUF_CAPT: + { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); + } + + case BUZIOC_QBUF_PLAY: + { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS); + } + + case BUZIOC_SYNC: + { + struct zoran_sync bs; + int res; + + IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n")); + res = jpg_sync(zr, &bs); + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return res; + } + + case BUZIOC_G_STATUS: + { + struct zoran_status bs; + int norm, input, status; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + return -EINVAL; + } + if (copy_from_user(&bs, arg, sizeof(bs))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n")); + switch (bs.input) { + case 0: + input = 3; + break; + case 1: + input = 7; + break; + default: + return -EINVAL; + } + + /* Set video norm to VIDEO_MODE_AUTO */ + + norm = VIDEO_MODE_AUTO; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + + /* sleep 1 second */ + + schedule_timeout(HZ); + + /* Get status of video decoder */ + + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status); + bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; + bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; + + /* restore previous input and norm */ + input = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return 0; + } + + default: + return -ENOIOCTLCMD; + + } + return 0; +} + + +/* + * This maps the buffers to user space. + * + * Depending on the state of zr->map_mjpeg_buffers + * the V4L or the MJPEG buffers are mapped + * + */ + +static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct zoran *zr = (struct zoran *) dev; + unsigned long start = (unsigned long) adr; + unsigned long page, pos, todo, fraglen; + int i, j; + + if (zr->map_mjpeg_buffers) { + /* Map the MJPEG buffers */ + + if (!zr->jpg_buffers_allocated) { + return -ENOMEM; + } + if (size > zr->jpg_nbufs * zr->jpg_bufsize) { + return -EINVAL; + } + + for (i = 0; i < zr->jpg_nbufs; i++) { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1; + todo = size; + if (todo > fraglen) + todo = fraglen; + pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; + page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ + if (remap_page_range(start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1) + break; /* was last fragment */ + } + if (size == 0) + break; + } + } else { + /* Map the V4L buffers */ + + if (size > v4l_nbufs * v4l_bufsize) { + return -EINVAL; + } + + for (i = 0; i < v4l_nbufs; i++) { + todo = size; + if (todo > v4l_bufsize) + todo = v4l_bufsize; + page = zr->v4l_gbuf[i].fbuffer_phys; + DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); + if (remap_page_range(start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + } + } + return 0; +} + +static int zoran_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device zoran_template = +{ + BUZ_NAME, + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | + VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + VID_HARDWARE_ZR36067, + zoran_open, + zoran_close, + zoran_read, + zoran_write, + NULL, + zoran_ioctl, + zoran_mmap, + zoran_init_done, + NULL, + 0, + 0 +}; + +static int zr36057_init(int i) +{ + struct zoran *zr = &zoran[i]; + unsigned long mem; + unsigned mem_needed; + int j; + int rev; + + /* reset zr36057 */ + btwrite(0, ZR36057_SPGPPCR); + mdelay(10); + + /* default setup of all parameters which will persist beetween opens */ + + zr->user = 0; + + init_waitqueue_head(&zr->v4l_capq); + init_waitqueue_head(&zr->jpg_capq); + + zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ + + zr->jpg_nbufs = 0; + zr->jpg_bufsize = 0; + zr->jpg_buffers_allocated = 0; + + zr->buffer_set = 0; /* Flag if frame buffer has been set */ + zr->buffer.base = (void *) vidmem; + zr->buffer.width = 0; + zr->buffer.height = 0; + zr->buffer.depth = 0; + zr->buffer.bytesperline = 0; + + zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */ + zr->params.input = default_input ? 1 : 0; /* Avoid nonsense settings from user */ + zr->video_interlace = 0; + + /* Should the following be reset at every open ? */ + + zr->picture.colour = 32768; + zr->picture.brightness = 32768; + zr->picture.hue = 32768; + zr->picture.contrast = 32768; + zr->picture.whiteness = 0; + zr->picture.depth = 0; + zr->picture.palette = 0; + + for (j = 0; j < VIDEO_MAX_FRAME; j++) { + zr->v4l_gbuf[i].fbuffer = 0; + zr->v4l_gbuf[i].fbuffer_phys = 0; + zr->v4l_gbuf[i].fbuffer_bus = 0; + } + + zr->stat_com = 0; + + /* default setup (will be repeated at every open) */ + + zoran_open_init_params(zr); + + /* allocate memory *before* doing anything to the hardware in case allocation fails */ + + /* STAT_COM table and overlay mask */ + + mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; + mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); + if (!mem) { + return -ENOMEM; + } + memset((void *) mem, 0, mem_needed); + + zr->stat_com = (u32 *) mem; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + } + zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); + + /* Initialize zr->jpg_gbuf */ + + for (j = 0; j < BUZ_MAX_FRAME; j++) { + zr->jpg_gbuf[j].frag_tab = 0; + zr->jpg_gbuf[j].frag_tab_bus = 0; + zr->jpg_gbuf[j].state = BUZ_STATE_USER; + zr->jpg_gbuf[j].bs.frame = j; + } + + /* take zr36057 out of reset now */ + btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); + mdelay(10); + + /* stop all DMA processes */ + btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + switch(zr->board) + { + case BOARD_BUZ: + + /* set up GPIO direction */ + btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); + + /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */ + btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1); + mdelay(10); + + /* reset video decoder */ + + GPIO(zr, 0, 0); + mdelay(10); + GPIO(zr, 0, 1); + mdelay(10); + + /* reset JPEG codec */ + zr36060_sleep(zr, 0); + mdelay(10); + zr36060_reset(zr); + mdelay(10); + + /* display codec revision */ + if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev); + kfree((void *) zr->stat_com); + return -1; + } + break; + + case BOARD_LML33: +// btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); +// udelay(100); +// btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); +// udelay(1000); + + /* + * Set up the GPIO direction + */ + btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR); + /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */ + btwrite(0xFF00F888, ZR36057_GPPGCR1); + mdelay(10); + GPIO(zr, 5, 0); /* Analog video bypass */ + udelay(3000); + GPIO(zr, 0, 0); /* Reset 819 */ + udelay(3000); + GPIO(zr, 0, 1); /* 819 back */ + udelay(3000); + /* reset JPEG codec */ + zr36060_sleep(zr, 0); + udelay(3000); + zr36060_reset(zr); + udelay(3000); + + /* display codec revision */ + if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); + kfree((void *) zr->stat_com); + return -1; + } + break; + } + /* i2c */ + memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); + sprintf(zr->i2c.name, "zoran%u", zr->id); + zr->i2c.data = zr; + if (i2c_register_bus(&zr->i2c) < 0) { + kfree((void *) zr->stat_com); + return -1; + } + /* + * Now add the template and register the device unit. + */ + memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); + sprintf(zr->video_dev.name, "zoran%u", zr->id); + if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + /* toggle JPEG codec sleep to sync PLL */ + zr36060_sleep(zr, 1); + mdelay(10); + zr36060_sleep(zr, 0); + mdelay(10); + + /* Enable bus-mastering */ + pci_set_master(zr->pci_dev); + + j = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + /* set individual interrupt enables (without GIRQ0) + but don't global enable until zoran_open() */ + + btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR); + + if(request_irq(zr->pci_dev->irq, zoran_irq, + SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0) + { + printk(KERN_ERR "%s: Can't assign irq.\n", zr->name); + video_unregister_device(&zr->video_dev); + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + zr->initialized = 1; + return 0; +} + + + +static void release_zoran(void) +{ + u8 command; + int i; + struct zoran *zr; + + for (i = 0; i < zoran_num; i++) { + zr = &zoran[i]; + + if (!zr->initialized) + continue; + + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + + /* disable PCI bus-mastering */ + pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); + + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + + free_irq(zr->pci_dev->irq, zr); + + /* unmap and free memory */ + + kfree((void *) zr->stat_com); + + iounmap(zr->zr36057_mem); + + video_unregister_device(&zr->video_dev); + } +} + +/* + * Scan for a Buz card (actually for the PCI controller ZR36057), + * request the irq and map the io memory + */ + +static int find_zr36057(void) +{ + unsigned char latency; + struct zoran *zr; + struct pci_dev *dev = NULL; + + zoran_num = 0; + + while (zoran_num < BUZ_MAX + && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { + zr = &zoran[zoran_num]; + zr->pci_dev = dev; + zr->zr36057_mem = NULL; + zr->id = zoran_num; + sprintf(zr->name, "zoran%u", zr->id); + + spin_lock_init(&zr->lock); + + if (pci_enable_device(dev)) + continue; + + zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); + pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); + if (zr->revision < 2) { + printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", + zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); + } else { + unsigned short ss_vendor_id, ss_id; + + ss_vendor_id = zr->pci_dev->subsystem_vendor; + ss_id = zr->pci_dev->subsystem_device; + printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", + zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); + printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n", + zr->name, ss_vendor_id, ss_id); + if(ss_vendor_id==0xFF10 && ss_id == 0xDE41) + { + zr->board = BOARD_LML33; + printk(KERN_INFO "%s: LML33 detected.\n", zr->name); + } + } + + zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); + if (!zr->zr36057_mem) { + printk(KERN_ERR "%s: ioremap failed\n", zr->name); + /* XXX handle error */ + } + + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); + if (latency != 48) { + printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency); + latency = 48; + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency); + } + zoran_num++; + } + if (zoran_num == 0) + printk(KERN_INFO "zoran: no cards found.\n"); + + return zoran_num; +} + +static void handle_chipset(void) +{ + if(pci_pci_problems&PCIPCI_FAIL) + { + printk(KERN_WARNING "buz: This configuration is known to have PCI to PCI DMA problems\n"); + printk(KERN_WARNING "buz: You may not be able to use overlay mode.\n"); + } + + + if(pci_pci_problems&PCIPCI_TRITON) + { + printk("buz: Enabling Triton support.\n"); + triton = 1; + } + + if(pci_pci_problems&PCIPCI_NATOMA) + { + printk("buz: Enabling Natoma workaround.\n"); + natoma = 1; + } +} + +#ifdef MODULE +int init_module(void) +#else +int init_zoran_cards(struct video_init *unused) +#endif +{ + int i; + + + printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n"); + + /* Look for Buz cards */ + + if (find_zr36057() <= 0) { + return -EIO; + } + printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num); + + if (zoran_num == 0) + return -ENXIO; + + + /* check the parameters we have been given, adjust if necessary */ + + if (v4l_nbufs < 0) + v4l_nbufs = 0; + if (v4l_nbufs > VIDEO_MAX_FRAME) + v4l_nbufs = VIDEO_MAX_FRAME; + /* The user specfies the in KB, we want them in byte (and page aligned) */ + v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); + if (v4l_bufsize < 32768) + v4l_bufsize = 32768; + /* 2 MB is arbitrary but sufficient for the maximum possible images */ + if (v4l_bufsize > 2048 * 1024) + v4l_bufsize = 2048 * 1024; + + printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10); + + /* Use parameter for vidmem or try to find a video card */ + + if (vidmem) { + printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem); + } + + /* check if we have a Triton or Natome chipset */ + + handle_chipset(); + + /* take care of Natoma chipset and a revision 1 zr36057 */ + + for (i = 0; i < zoran_num; i++) { + if (natoma && zoran[i].revision <= 1) { + zoran[i].need_contiguous = 1; + printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name); + } else { + zoran[i].need_contiguous = 0; + } + } + + /* initialize the Buzs */ + + /* We have to know which ones must be released if an error occurs */ + for (i = 0; i < zoran_num; i++) + zoran[i].initialized = 0; + + for (i = 0; i < zoran_num; i++) { + if (zr36057_init(i) < 0) { + release_zoran(); + return -EIO; + } + } + + return 0; +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + release_zoran(); +} + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/buz.h linux/drivers/media/video/buz.h --- v2.4.0-test6/linux/drivers/media/video/buz.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/buz.h Mon Jul 5 20:07:02 1999 @@ -0,0 +1,319 @@ +/* + buz - Iomega Buz driver + + Copyright (C) 1999 Rainer Johanni + + based on + + buz.0.0.3 Copyright (C) 1998 Dave Perks + + and + + 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. + */ + +#ifndef _BUZ_H_ +#define _BUZ_H_ + +/* The Buz only supports a maximum width of 720, but some V4L + applications (e.g. xawtv are more happy with 768). + If XAWTV_HACK is defined, we try to fake a device with bigger width */ + +#define XAWTV_HACK + +#ifdef XAWTV_HACK +#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ +#else +#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ +#endif +#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +struct zoran_requestbuffers { + unsigned long count; /* Number of buffers for MJPEG grabbing */ + unsigned long size; /* Size PER BUFFER in bytes */ +}; + +struct zoran_sync { + unsigned long frame; /* number of buffer that has been free'd */ + unsigned long length; /* number of code bytes in buffer (capture only) */ + unsigned long seq; /* frame sequence number */ + struct timeval timestamp; /* timestamp */ +}; + +struct zoran_status { + int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ + int signal; /* Returned: 1 if valid video signal detected */ + int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int color; /* Returned: 1 if color signal detected */ +}; + +struct zoran_params { + + /* The following parameters can only be queried */ + + int major_version; /* Major version number of driver */ + int minor_version; /* Minor version number of driver */ + + /* Main control parameters */ + + int input; /* Input channel: 0 = Composite, 1 = S-VHS */ + int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int decimation; /* decimation of captured video, + enlargement of video played back. + Valid values are 1, 2, 4 or 0. + 0 is a special value where the user + has full control over video scaling */ + + /* The following parameters only have to be set if decimation==0, + for other values of decimation they provide the data how the image is captured */ + + int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ + int VerDcm; /* Vertical decimation: 1 or 2 */ + int TmpDcm; /* Temporal decimation: 1 or 2, + if TmpDcm==2 in capture every second frame is dropped, + in playback every frame is played twice */ + int field_per_buff; /* Number of fields per buffer: 1 or 2 */ + int img_x; /* start of image in x direction */ + int img_y; /* start of image in y direction */ + int img_width; /* image width BEFORE decimation, + must be a multiple of HorDcm*16 */ + int img_height; /* image height BEFORE decimation, + must be a multiple of VerDcm*8 */ + + /* --- End of parameters for decimation==0 only --- */ + + /* JPEG control parameters */ + + int quality; /* Measure for quality of compressed images. + Scales linearly with the size of the compressed images. + Must be beetween 0 and 100, 100 is a compression + ratio of 1:4 */ + + int odd_even; /* Which field should come first ??? */ + + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + unsigned long jpeg_markers; /* Which markers should go into the JPEG output. + Unless you exactly know what you do, leave them untouched. + Inluding less markers will make the resulting code + smaller, but there will be fewer aplications + which can read it. + The presence of the APP and COM marker is + influenced by APP0_len and COM_len ONLY! */ +#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ + + int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. + If this flag is turned on and JPEG decompressing + is going to the screen, the decompress process + is stopped every time the Video Fifo is full. + This enables a smooth decompress to the screen + but the video output signal will get scrambled */ + + /* Misc */ + + char reserved[312]; /* Makes 512 bytes for this structure */ +}; + +/* + Private IOCTL to set up for displaying MJPEG + */ +#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) +#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) +#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) +#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) +#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) +#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) +#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) + + +#ifdef __KERNEL__ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ +#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ + +#if VIDEO_MAX_FRAME <= 32 +#define V4L_MAX_FRAME 32 +#elif VIDEO_MAX_FRAME <= 64 +#define V4L_MAX_FRAME 64 +#else +#error "Too many video frame buffers to handle" +#endif +#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) + + +#include "zr36057.h" + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_buffer_state { + BUZ_STATE_USER, /* buffer is owned by application */ + BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ + BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ + BUZ_STATE_DONE /* buffer is ready to return to application */ +}; + +struct zoran_gbuffer { + u32 *frag_tab; /* addresses of frag table */ + u32 frag_tab_bus; /* same value cached to save time in ISR */ + enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ + struct zoran_sync bs; /* DONE: info to return to application */ +}; + +struct v4l_gbuffer { + char *fbuffer; /* virtual address of frame buffer */ + unsigned long fbuffer_phys; /* physical address of frame buffer */ + unsigned long fbuffer_bus; /* bus address of frame buffer */ + enum zoran_buffer_state state; /* state: unused/pending/done */ +}; + +struct zoran { + struct video_device video_dev; + struct i2c_bus i2c; + + int initialized; /* flag if zoran has been correctly initalized */ + int user; /* number of current users (0 or 1) */ + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + int board; /* Board type */ +#define BOARD_BUZ 0 +#define BOARD_LML33 1 + unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *zr36057_mem; /* pointer to mapped IO memory */ + + int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ + + spinlock_t lock; /* Spinlock */ + + /* Video for Linux parameters */ + + struct video_picture picture; /* Current picture params */ + struct video_buffer buffer; /* Current buffer params */ + struct video_window window; /* Current window params */ + int buffer_set, window_set; /* Flags if the above structures are set */ + int video_interlace; /* Image on screen is interlaced */ + + u32 *overlay_mask; + + wait_queue_head_t v4l_capq; /* wait here for grab to finish */ + + int v4l_overlay_active; /* Overlay grab is activated */ + int v4l_memgrab_active; /* Memory grab is activated */ + + int v4l_grab_frame; /* Frame number being currently grabbed */ +#define NO_GRAB_ACTIVE (-1) + int v4l_grab_seq; /* Number of frames grabbed */ + int gwidth; /* Width of current memory capture */ + int gheight; /* Height of current memory capture */ + int gformat; /* Format of ... */ + int gbpl; /* byte per line of ... */ + + /* V4L grab queue of frames pending */ + + unsigned v4l_pend_head; + unsigned v4l_pend_tail; + int v4l_pend[V4L_MAX_FRAME]; + + struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ + + /* Buz MJPEG parameters */ + + unsigned long jpg_nbufs; /* Number of buffers */ + unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ + int jpg_buffers_allocated; /* Flag if buffers are allocated */ + int need_contiguous; /* Flag if contiguous buffers are needed */ + + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_params params; /* structure with a lot of things to play with */ + + wait_queue_head_t jpg_capq; /* wait here for grab to finish */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + + /* zr36057's code buffer table */ + u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + + /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ + int jpg_pend[BUZ_MAX_FRAME]; + + /* array indexed by frame number */ + struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ +}; + +#endif + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BUZ in the Makefile. */ + +#ifdef _ALPHA_BUZ +#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) +#define btread(adr) readl(zr->zr36057_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) +#define btread(adr) readl(zr->zr36057_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) + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_SAA7111 0x48 +#define I2C_SAA7185 0x88 + +#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.4.0-test6/linux/drivers/media/video/bw-qcam.c linux/drivers/media/video/bw-qcam.c --- v2.4.0-test6/linux/drivers/media/video/bw-qcam.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bw-qcam.c Sat Oct 2 07:35:15 1999 @@ -0,0 +1,1066 @@ +/* + * QuickCam Driver For Video4Linux. + * + * This version only works as a module. + * + * Video4Linux conversion work by Alan Cox. + * Parport compatibility by Phil Blundell. + * Busy loop avoidance by Mark Cooke. + * + * Module parameters: + * + * maxpoll=<1 - 5000> + * + * When polling the QuickCam for a response, busy-wait for a + * maximum of this many loops. The default of 250 gives little + * impact on interactive response. + * + * NOTE: If this parameter is set too high, the processor + * will busy wait until this loop times out, and then + * slowly poll for a further 5 seconds before failing + * the transaction. You have been warned. + * + * yieldlines=<1 - 250> + * + * When acquiring a frame from the camera, the data gathering + * loop will yield back to the scheduler after completing + * this many lines. The default of 4 provides a trade-off + * between increased frame acquisition time and impact on + * interactive response. + */ + +/* qcam-lib.c -- Library for programming with the Connectix QuickCam. + * See the included documentation for usage instructions and details + * of the protocol involved. */ + + +/* Version 0.5, August 4, 1996 */ +/* Version 0.7, August 27, 1996 */ +/* Version 0.9, November 17, 1996 */ + + +/****************************************************************** + +Copyright (C) 1996 by Scott Laird + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bw-qcam.h" + +static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ +static unsigned int yieldlines=4; /* Yield after this many during capture */ + +#if LINUX_VERSION_CODE >= 0x020117 +MODULE_PARM(maxpoll,"i"); +MODULE_PARM(yieldlines,"i"); +#endif + +extern __inline__ int read_lpstatus(struct qcam_device *q) +{ + return parport_read_status(q->pport); +} + +extern __inline__ int read_lpcontrol(struct qcam_device *q) +{ + return parport_read_control(q->pport); +} + +extern __inline__ int read_lpdata(struct qcam_device *q) +{ + return parport_read_data(q->pport); +} + +extern __inline__ void write_lpdata(struct qcam_device *q, int d) +{ + parport_write_data(q->pport, d); +} + +extern __inline__ void write_lpcontrol(struct qcam_device *q, int d) +{ + parport_write_control(q->pport, d); +} + +static int qc_waithand(struct qcam_device *q, int val); +static int qc_command(struct qcam_device *q, int command); +static int qc_readparam(struct qcam_device *q); +static int qc_setscanmode(struct qcam_device *q); +static int qc_readbytes(struct qcam_device *q, char buffer[]); + +static struct video_device qcam_template; + +static int qc_calibrate(struct qcam_device *q) +{ + /* + * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 + * The white balance is an individiual value for each + * quickcam. + */ + + int value; + int count = 0; + + qc_command(q, 27); /* AutoAdjustOffset */ + qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ + + /* GetOffset (33) will read 255 until autocalibration */ + /* is finished. After that, a value of 1-254 will be */ + /* returned. */ + + do { + qc_command(q, 33); + value = qc_readparam(q); + mdelay(1); + schedule(); + count++; + } while (value == 0xff && count<2048); + + q->whitebal = value; + return value; +} + +/* Initialize the QuickCam driver control structure. This is where + * defaults are set for people who don't have a config file.*/ + +static struct qcam_device *qcam_init(struct parport *port) +{ + struct qcam_device *q; + + q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + if(q==NULL) + return NULL; + + q->pport = port; + q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, + NULL, 0, NULL); + if (q->pdev == NULL) + { + printk(KERN_ERR "bw-qcam: couldn't register for %s.\n", + port->name); + kfree(q); + return NULL; + } + + memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); + + init_MUTEX(&q->lock); + + q->port_mode = (QC_ANY | QC_NOTSET); + q->width = 320; + q->height = 240; + q->bpp = 4; + q->transfer_scale = 2; + q->contrast = 192; + q->brightness = 180; + q->whitebal = 105; + q->top = 1; + q->left = 14; + q->mode = -1; + q->status = QC_PARAM_CHANGE; + return q; +} + + +/* qc_command is probably a bit of a misnomer -- it's used to send + * bytes *to* the camera. Generally, these bytes are either commands + * or arguments to commands, so the name fits, but it still bugs me a + * bit. See the documentation for a list of commands. */ + +static int qc_command(struct qcam_device *q, int command) +{ + int n1, n2; + int cmd; + + write_lpdata(q, command); + write_lpcontrol(q, 6); + + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + +static int qc_readparam(struct qcam_device *q) +{ + int n1, n2; + int cmd; + + write_lpcontrol(q, 6); + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + +/* qc_waithand busy-waits for a handshake signal from the QuickCam. + * Almost all communication with the camera requires handshaking. */ + +static int qc_waithand(struct qcam_device *q, int val) +{ + int status; + int runs=0; + + if (val) + { + while (!((status = read_lpstatus(q)) & 8)) + { + /* 1000 is enough spins on the I/O for all normal + cases, at that point we start to poll slowly + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ + + if(runs++>maxpoll) + { + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/200); + } + if(runs>(maxpoll+1000)) /* 5 seconds */ + return -1; + } + } + else + { + while (((status = read_lpstatus(q)) & 8)) + { + /* 1000 is enough spins on the I/O for all normal + cases, at that point we start to poll slowly + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ + + if(runs++>maxpoll) + { + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/200); + } + if(runs++>(maxpoll+1000)) /* 5 seconds */ + return -1; + } + } + + return status; +} + +/* Waithand2 is used when the qcam is in bidirectional mode, and the + * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1 + * (bit 3 of status register). It also returns the last value read, + * since this data is useful. */ + +static unsigned int qc_waithand2(struct qcam_device *q, int val) +{ + unsigned int status; + int runs=0; + + do + { + status = read_lpdata(q); + /* 1000 is enough spins on the I/O for all normal + cases, at that point we start to poll slowly + until the camera wakes up. However, we are + busy blocked until the camera responds, so + setting it lower is much better for interactive + response. */ + + if(runs++>maxpoll) + { + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/200); + } + if(runs++>(maxpoll+1000)) /* 5 seconds */ + return 0; + } + while ((status & 1) != val); + + return status; +} + + +/* Try to detect a QuickCam. It appears to flash the upper 4 bits of + the status register at 5-10 Hz. This is only used in the autoprobe + code. Be aware that this isn't the way Connectix detects the + camera (they send a reset and try to handshake), but this should be + almost completely safe, while their method screws up my printer if + I plug it in before the camera. */ + +static int qc_detect(struct qcam_device *q) +{ + int reg, lastreg; + int count = 0; + int i; + + lastreg = reg = read_lpstatus(q) & 0xf0; + + for (i = 0; i < 500; i++) + { + reg = read_lpstatus(q) & 0xf0; + if (reg != lastreg) + count++; + lastreg = reg; + mdelay(2); + } + + +#if 0 + /* Force camera detection during testing. Sometimes the camera + won't be flashing these bits. Possibly unloading the module + in the middle of a grab? Or some timeout condition? + I've seen this parameter as low as 19 on my 450Mhz box - mpc */ + printk("Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); + return 1; +#endif + + /* Be (even more) liberal in what you accept... */ + +/* if (count > 30 && count < 200) */ + if (count > 20 && count < 300) + return 1; /* found */ + else + return 0; /* not found */ +} + + +/* Reset the QuickCam. This uses the same sequence the Windows + * QuickPic program uses. Someone with a bi-directional port should + * check that bi-directional mode is detected right, and then + * implement bi-directional mode in qc_readbyte(). */ + +static void qc_reset(struct qcam_device *q) +{ + switch (q->port_mode & QC_FORCE_MASK) + { + case QC_FORCE_UNIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + + case QC_FORCE_BIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + break; + + case QC_ANY: + write_lpcontrol(q, 0x20); + write_lpdata(q, 0x75); + + if (read_lpdata(q) != 0x75) { + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + } else { + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + } + break; + } + + write_lpcontrol(q, 0xb); + udelay(250); + write_lpcontrol(q, 0xe); + qc_setscanmode(q); /* in case port_mode changed */ +} + + +/* Decide which scan mode to use. There's no real requirement that + * the scanmode match the resolution in q->height and q-> width -- the + * camera takes the picture at the resolution specified in the + * "scanmode" and then returns the image at the resolution specified + * with the resolution commands. If the scan is bigger than the + * requested resolution, the upper-left hand corner of the scan is + * returned. If the scan is smaller, then the rest of the image + * returned contains garbage. */ + +static int qc_setscanmode(struct qcam_device *q) +{ + int old_mode = q->mode; + + switch (q->transfer_scale) + { + case 1: + q->mode = 0; + break; + case 2: + q->mode = 4; + break; + case 4: + q->mode = 8; + break; + } + + switch (q->bpp) + { + case 4: + break; + case 6: + q->mode += 2; + break; + } + + switch (q->port_mode & QC_MODE_MASK) + { + case QC_BIDIR: + q->mode += 1; + break; + case QC_NOTSET: + case QC_UNIDIR: + break; + } + + if (q->mode != old_mode) + q->status |= QC_PARAM_CHANGE; + + return 0; +} + + +/* Reset the QuickCam and program for brightness, contrast, + * white-balance, and resolution. */ + +void qc_set(struct qcam_device *q) +{ + int val; + int val2; + + qc_reset(q); + + /* Set the brightness. Yes, this is repetitive, but it works. + * Shorter versions seem to fail subtly. Feel free to try :-). */ + /* I think the problem was in qc_command, not here -- bls */ + + qc_command(q, 0xb); + qc_command(q, q->brightness); + + val = q->height / q->transfer_scale; + qc_command(q, 0x11); + qc_command(q, val); + if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) { + /* The normal "transfers per line" calculation doesn't seem to work + as expected here (and yet it works fine in qc_scan). No idea + why this case is the odd man out. Fortunately, Laird's original + working version gives me a good way to guess at working values. + -- bls */ + val = q->width; + val2 = q->transfer_scale * 4; + } else { + val = q->width * q->bpp; + val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * + q->transfer_scale; + } + val = (val + val2 - 1) / val2; + qc_command(q, 0x13); + qc_command(q, val); + + /* Setting top and left -- bls */ + qc_command(q, 0xd); + qc_command(q, q->top); + qc_command(q, 0xf); + qc_command(q, q->left / 2); + + qc_command(q, 0x19); + qc_command(q, q->contrast); + qc_command(q, 0x1f); + qc_command(q, q->whitebal); + + /* Clear flag that we must update the grabbing parameters on the camera + before we grab the next frame */ + q->status &= (~QC_PARAM_CHANGE); +} + +/* Qc_readbytes reads some bytes from the QC and puts them in + the supplied buffer. It returns the number of bytes read, + or -1 on error. */ + +extern __inline__ int qc_readbytes(struct qcam_device *q, char buffer[]) +{ + int ret=1; + unsigned int hi, lo; + unsigned int hi2, lo2; + static int state = 0; + + if (buffer == NULL) + { + state = 0; + return 0; + } + + switch (q->port_mode & QC_MODE_MASK) + { + case QC_BIDIR: /* Bi-directional Port */ + write_lpcontrol(q, 0x26); + lo = (qc_waithand2(q, 1) >> 1); + hi = (read_lpstatus(q) >> 3) & 0x1f; + write_lpcontrol(q, 0x2e); + lo2 = (qc_waithand2(q, 0) >> 1); + hi2 = (read_lpstatus(q) >> 3) & 0x1f; + switch (q->bpp) + { + case 4: + buffer[0] = lo & 0xf; + buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); + buffer[2] = (hi & 0x1e) >> 1; + buffer[3] = lo2 & 0xf; + buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); + buffer[5] = (hi2 & 0x1e) >> 1; + ret = 6; + break; + case 6: + buffer[0] = lo & 0x3f; + buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); + buffer[2] = lo2 & 0x3f; + buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); + ret = 4; + break; + } + break; + + case QC_UNIDIR: /* Unidirectional Port */ + write_lpcontrol(q, 6); + lo = (qc_waithand(q, 1) & 0xf0) >> 4; + write_lpcontrol(q, 0xe); + hi = (qc_waithand(q, 0) & 0xf0) >> 4; + + switch (q->bpp) + { + case 4: + buffer[0] = lo; + buffer[1] = hi; + ret = 2; + break; + case 6: + switch (state) + { + case 0: + buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); + q->saved_bits = (hi & 3) << 4; + state = 1; + ret = 1; + break; + case 1: + buffer[0] = lo | q->saved_bits; + q->saved_bits = hi << 2; + state = 2; + ret = 1; + break; + case 2: + buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits; + buffer[1] = ((lo & 3) << 4) | hi; + state = 0; + ret = 2; + break; + } + break; + } + break; + } + return ret; +} + +/* requests a scan from the camera. It sends the correct instructions + * to the camera and then reads back the correct number of bytes. In + * previous versions of this routine the return structure contained + * the raw output from the camera, and there was a 'qc_convertscan' + * function that converted that to a useful format. In version 0.3 I + * rolled qc_convertscan into qc_scan and now I only return the + * converted scan. The format is just an one-dimensional array of + * characters, one for each pixel, with 0=black up to n=white, where + * n=2^(bit depth)-1. Ask me for more details if you don't understand + * this. */ + +long qc_capture(struct qcam_device * q, char *buf, unsigned long len) +{ + int i, j, k, yield; + int bytes; + int linestotrans, transperline; + int divisor; + int pixels_per_line; + int pixels_read = 0; + int got=0; + char buffer[6]; + int shift=8-q->bpp; + char invert; + + if (q->mode == -1) + return -ENXIO; + + qc_command(q, 0x7); + qc_command(q, q->mode); + + if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) + { + write_lpcontrol(q, 0x2e); /* turn port around */ + write_lpcontrol(q, 0x26); + (void) qc_waithand(q, 1); + write_lpcontrol(q, 0x2e); + (void) qc_waithand(q, 0); + } + + /* strange -- should be 15:63 below, but 4bpp is odd */ + invert = (q->bpp == 4) ? 16 : 63; + + linestotrans = q->height / q->transfer_scale; + pixels_per_line = q->width / q->transfer_scale; + transperline = q->width * q->bpp; + divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * + q->transfer_scale; + transperline = (transperline + divisor - 1) / divisor; + + for (i = 0, yield = yieldlines; i < linestotrans; i++) + { + for (pixels_read = j = 0; j < transperline; j++) + { + bytes = qc_readbytes(q, buffer); + for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) + { + int o; + if (buffer[k] == 0 && invert == 16) + { + /* 4bpp is odd (again) -- inverter is 16, not 15, but output + must be 0-15 -- bls */ + buffer[k] = 16; + } + o=i*pixels_per_line + pixels_read + k; + if(o= yield) { + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/200); + yield = i + yieldlines; + } + } + + if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) + { + write_lpcontrol(q, 2); + write_lpcontrol(q, 6); + udelay(3); + write_lpcontrol(q, 0xe); + } + if(gotbrightness<<8; + p.contrast=qcam->contrast<<8; + p.whiteness=qcam->whitebal<<8; + p.depth=qcam->bpp; + p.palette=VIDEO_PALETTE_GREY; + 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_GREY) + return -EINVAL; + if(p.depth!=4 && p.depth!=6) + return -EINVAL; + + /* + * Now load the camera. + */ + + qcam->brightness = p.brightness>>8; + qcam->contrast = p.contrast>>8; + qcam->whitebal = p.whiteness>>8; + qcam->bpp = p.depth; + + down(&qcam->lock); + qc_setscanmode(qcam); + up(&qcam->lock); + qcam->status |= QC_PARAM_CHANGE; + + 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<60||vw.height>240) + return -EINVAL; + if(vw.width<80||vw.width>320) + return -EINVAL; + + qcam->width = 320; + qcam->height = 240; + qcam->transfer_scale = 4; + + if(vw.width>=160 && vw.height>=120) + { + qcam->transfer_scale = 2; + } + if(vw.width>=320 && vw.height>=240) + { + qcam->width = 320; + qcam->height = 240; + qcam->transfer_scale = 1; + } + down(&qcam->lock); + qc_setscanmode(qcam); + up(&qcam->lock); + + /* We must update the camera before we grab. We could + just have changed the grab size */ + qcam->status |= QC_PARAM_CHANGE; + + /* 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=qcam->width/qcam->transfer_scale; + vw.height=qcam->height/qcam->transfer_scale; + 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 qcam_read(struct video_device *v, char *buf, unsigned long count, int noblock) +{ + struct qcam_device *qcam=(struct qcam_device *)v; + int len; + parport_claim_or_block(qcam->pdev); + + down(&qcam->lock); + + qc_reset(qcam); + + /* Update the camera parameters if we need to */ + if (qcam->status & QC_PARAM_CHANGE) + qc_set(qcam); + + len=qc_capture(qcam, buf,count); + + up(&qcam->lock); + + parport_release(qcam->pdev); + return len; +} + +static struct video_device qcam_template= +{ + "Connectix Quickcam", + VID_TYPE_CAPTURE, + VID_HARDWARE_QCAM_BW, + qcam_open, + qcam_close, + qcam_read, + qcam_write, + NULL, + qcam_ioctl, + NULL, + qcam_init_done, + NULL, + 0, + 0 +}; + +#define MAX_CAMS 4 +static struct qcam_device *qcams[MAX_CAMS]; +static unsigned int num_cams = 0; + +int init_bwqcam(struct parport *port) +{ + struct qcam_device *qcam; + + if (num_cams == MAX_CAMS) + { + printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); + return -ENOSPC; + } + + qcam=qcam_init(port); + if(qcam==NULL) + return -ENODEV; + + parport_claim_or_block(qcam->pdev); + + qc_reset(qcam); + + if(qc_detect(qcam)==0) + { + parport_release(qcam->pdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + qc_calibrate(qcam); + + parport_release(qcam->pdev); + + printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); + + if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) + { + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + qcams[num_cams++] = qcam; + + return 0; +} + +void close_bwqcam(struct qcam_device *qcam) +{ + video_unregister_device(&qcam->vdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); +} + +/* The parport parameter controls which parports will be scanned. + * Scanning all parports causes some printers to print a garbage page. + * -- March 14, 1999 Billy Donahue */ +#ifdef MODULE +static char *parport[MAX_CAMS] = { NULL, }; +MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s"); +#endif + +#ifdef MODULE +int init_module(void) +{ + struct parport *port; + int n; + if(parport[0] && strncmp(parport[0], "auto", 4)){ + /* user gave parport parameters */ + for(n=0; parport[n] && nnext){ + if(r!=port->number) + continue; + init_bwqcam(port); + break; + } + } + return (num_cams)?0:-ENODEV; + } + /* no parameter or "auto" */ + for (port = parport_enumerate(); port; port=port->next) + init_bwqcam(port); + + /* Do some sanity checks on the module parameters. */ + if (maxpoll > 5000) { + printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n"); + maxpoll = 5000; + } + + if (yieldlines < 1) { + printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n"); + yieldlines = 1; + } + + return (num_cams)?0:-ENODEV; +} + +void cleanup_module(void) +{ + unsigned int i; + for (i = 0; i < num_cams; i++) + close_bwqcam(qcams[i]); +} +#else +int __init init_bw_qcams(struct video_init *unused) +{ + struct parport *port; + + for (port = parport_enumerate(); port; port=port->next) + init_bwqcam(port); + return 0; +} +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/bw-qcam.h linux/drivers/media/video/bw-qcam.h --- v2.4.0-test6/linux/drivers/media/video/bw-qcam.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/bw-qcam.h Sat Oct 2 07:35:15 1999 @@ -0,0 +1,68 @@ +/* + * Video4Linux bw-qcam driver + * + * Derived from code.. + */ + +/****************************************************************** + +Copyright (C) 1996 by Scott Laird + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +/* One from column A... */ +#define QC_NOTSET 0 +#define QC_UNIDIR 1 +#define QC_BIDIR 2 +#define QC_SERIAL 3 + +/* ... and one from column B */ +#define QC_ANY 0x00 +#define QC_FORCE_UNIDIR 0x10 +#define QC_FORCE_BIDIR 0x20 +#define QC_FORCE_SERIAL 0x30 +/* in the port_mode member */ + +#define QC_MODE_MASK 0x07 +#define QC_FORCE_MASK 0x70 + +#define MAX_HEIGHT 243 +#define MAX_WIDTH 336 + +/* Bit fields for status flags */ +#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ + +struct qcam_device { + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + struct semaphore lock; + int width, height; + int bpp; + int mode; + int contrast, brightness, whitebal; + int port_mode; + int transfer_scale; + int top, left; + int status; + unsigned int saved_bits; +}; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c --- v2.4.0-test6/linux/drivers/media/video/c-qcam.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/c-qcam.c Mon Jun 19 17:59:42 2000 @@ -0,0 +1,901 @@ +/* + * Video4Linux Colour QuickCam driver + * Copyright 1997-2000 Philip Blundell + * + * Module parameters: + * + * parport=auto -- probe all parports (default) + * parport=0 -- parport0 becomes qcam1 + * parport=2,0,1 -- parports 2,0,1 are tried in that order + * + * probe=0 -- do no probing, assume camera is present + * probe=1 -- use IEEE-1284 autoprobe data only (default) + * probe=2 -- probe aggressively for cameras + * + * force_rgb=1 -- force data format to RGB (default is BGR) + * + * The parport parameter controls which parports will be scanned. + * Scanning all parports causes some printers to print a garbage page. + * -- March 14, 1999 Billy Donahue + * + * Fixed data format to BGR, added force_rgb parameter. Added missing + * parport_unregister_driver() on module removal. + * -- May 28, 2000 Claudio Matsuoka + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct qcam_device { + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + int width, height; + int ccd_width, ccd_height; + int mode; + int contrast, brightness, whitebal; + int top, left; + unsigned int bidirectional; + struct semaphore lock; +}; + +/* cameras maximum */ +#define MAX_CAMS 4 + +/* The three possible QuickCam modes */ +#define QC_MILLIONS 0x18 +#define QC_BILLIONS 0x10 +#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ + +/* The three possible decimations */ +#define QC_DECIMATION_1 0 +#define QC_DECIMATION_2 2 +#define QC_DECIMATION_4 4 + +#define BANNER "Colour QuickCam for Video4Linux v0.05" + +static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; +static int probe = 2; +static int force_rgb = 0; + +static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) +{ + /* note: the QC specs refer to the PCAck pin by voltage, not + software level. PC ports have builtin inverters. */ + parport_frob_control(qcam->pport, 8, i?8:0); +} + +static inline unsigned int qcam_ready1(struct qcam_device *qcam) +{ + return (parport_read_status(qcam->pport) & 0x8)?1:0; +} + +static inline unsigned int qcam_ready2(struct qcam_device *qcam) +{ + return (parport_read_data(qcam->pport) & 0x1)?1:0; +} + +static unsigned int qcam_await_ready1(struct qcam_device *qcam, + int value) +{ + unsigned long oldjiffies = jiffies; + unsigned int i; + + for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); ) + if (qcam_ready1(qcam) == value) + return 0; + + /* If the camera didn't respond within 1/25 second, poll slowly + for a while. */ + for (i = 0; i < 50; i++) + { + if (qcam_ready1(qcam) == value) + return 0; + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } + + /* Probably somebody pulled the plug out. Not much we can do. */ + printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value, + parport_read_status(qcam->pport), + parport_read_control(qcam->pport)); + return 1; +} + +static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) +{ + unsigned long oldjiffies = jiffies; + unsigned int i; + + for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); ) + if (qcam_ready2(qcam) == value) + return 0; + + /* If the camera didn't respond within 1/25 second, poll slowly + for a while. */ + for (i = 0; i < 50; i++) + { + if (qcam_ready2(qcam) == value) + return 0; + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } + + /* Probably somebody pulled the plug out. Not much we can do. */ + printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value, + parport_read_status(qcam->pport), + parport_read_control(qcam->pport), + parport_read_data(qcam->pport)); + return 1; +} + +static int qcam_read_data(struct qcam_device *qcam) +{ + unsigned int idata; + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) return -1; + idata = parport_read_status(qcam->pport) & 0xf0; + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) return -1; + idata |= (parport_read_status(qcam->pport) >> 4); + return idata; +} + +static int qcam_write_data(struct qcam_device *qcam, unsigned int data) +{ + unsigned int idata; + parport_write_data(qcam->pport, data); + idata = qcam_read_data(qcam); + if (data != idata) + { + printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, + idata); + return 1; + } + return 0; +} + +static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data) +{ + if (qcam_write_data(qcam, cmd)) + return -1; + if (qcam_write_data(qcam, data)) + return -1; + return 0; +} + +static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd) +{ + if (qcam_write_data(qcam, cmd)) + return -1; + return qcam_read_data(qcam); +} + +static int qc_detect(struct qcam_device *qcam) +{ + unsigned int stat, ostat, i, count = 0; + + /* The probe routine below is not very reliable. The IEEE-1284 + probe takes precedence. */ + /* XXX Currently parport provides no way to distinguish between + "the IEEE probe was not done" and "the probe was done, but + no device was found". Fix this one day. */ + if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA + && qcam->pport->probe_info[0].model + && !strcmp(qcam->pdev->port->probe_info[0].model, + "Color QuickCam 2.0")) { + printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n"); + return 1; + } + + if (probe < 2) + return 0; + + parport_write_control(qcam->pport, 0xc); + + /* look for a heartbeat */ + ostat = stat = parport_read_status(qcam->pport); + for (i=0; i<250; i++) + { + mdelay(1); + stat = parport_read_status(qcam->pport); + if (ostat != stat) + { + if (++count >= 3) return 1; + ostat = stat; + } + } + + /* Reset the camera and try again */ + parport_write_control(qcam->pport, 0xc); + parport_write_control(qcam->pport, 0x8); + mdelay(1); + parport_write_control(qcam->pport, 0xc); + mdelay(1); + count = 0; + + ostat = stat = parport_read_status(qcam->pport); + for (i=0; i<250; i++) + { + mdelay(1); + stat = parport_read_status(qcam->pport); + if (ostat != stat) + { + if (++count >= 3) return 1; + ostat = stat; + } + } + + /* no (or flatline) camera, give up */ + return 0; +} + +static void qc_reset(struct qcam_device *qcam) +{ + parport_write_control(qcam->pport, 0xc); + parport_write_control(qcam->pport, 0x8); + mdelay(1); + parport_write_control(qcam->pport, 0xc); + mdelay(1); +} + +/* Reset the QuickCam and program for brightness, contrast, + * white-balance, and resolution. */ + +static void qc_setup(struct qcam_device *q) +{ + qc_reset(q); + + /* Set the brightness. */ + qcam_set(q, 11, q->brightness); + + /* Set the height and width. These refer to the actual + CCD area *before* applying the selected decimation. */ + qcam_set(q, 17, q->ccd_height); + qcam_set(q, 19, q->ccd_width / 2); + + /* Set top and left. */ + qcam_set(q, 0xd, q->top); + qcam_set(q, 0xf, q->left); + + /* Set contrast and white balance. */ + qcam_set(q, 0x19, q->contrast); + qcam_set(q, 0x1f, q->whitebal); + + /* Set the speed. */ + qcam_set(q, 45, 2); +} + +/* Read some bytes from the camera and put them in the buffer. + nbytes should be a multiple of 3, because bidirectional mode gives + us three bytes at a time. */ + +static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) +{ + unsigned int bytes = 0; + + qcam_set_ack(q, 0); + if (q->bidirectional) + { + /* It's a bidirectional port */ + while (bytes < nbytes) + { + unsigned int lo1, hi1, lo2, hi2; + unsigned char r, g, b; + + if (qcam_await_ready2(q, 1)) return bytes; + lo1 = parport_read_data(q->pport) >> 1; + hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(q, 1); + if (qcam_await_ready2(q, 0)) return bytes; + lo2 = parport_read_data(q->pport) >> 1; + hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(q, 0); + r = (lo1 | ((hi1 & 1)<<7)); + g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); + b = (lo2 | ((hi2 & 1)<<7)); + if (force_rgb) { + buf[bytes++] = r; + buf[bytes++] = g; + buf[bytes++] = b; + } else { + buf[bytes++] = b; + buf[bytes++] = g; + buf[bytes++] = r; + } + } + } + else + { + /* It's a unidirectional port */ + int i = 0, n = bytes; + unsigned char rgb[3]; + + while (bytes < nbytes) + { + unsigned int hi, lo; + + if (qcam_await_ready1(q, 1)) return bytes; + hi = (parport_read_status(q->pport) & 0xf0); + qcam_set_ack(q, 1); + if (qcam_await_ready1(q, 0)) return bytes; + lo = (parport_read_status(q->pport) & 0xf0); + qcam_set_ack(q, 0); + /* flip some bits */ + rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; + if (i >= 2) { +get_fragment: + if (force_rgb) { + buf[n++] = rgb[0]; + buf[n++] = rgb[1]; + buf[n++] = rgb[2]; + } else { + buf[n++] = rgb[2]; + buf[n++] = rgb[1]; + buf[n++] = rgb[0]; + } + } + } + if (i) { + i = 0; + goto get_fragment; + } + } + return bytes; +} + +#define BUFSZ 150 + +static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) +{ + unsigned lines, pixelsperline, bitsperxfer; + unsigned int is_bi_dir = q->bidirectional; + size_t wantlen, outptr = 0; + char tmpbuf[BUFSZ]; + + if (verify_area(VERIFY_WRITE, buf, len)) + return -EFAULT; + + /* Wait for camera to become ready */ + for (;;) + { + int i = qcam_get(q, 41); + if (i == -1) { + qc_setup(q); + return -EIO; + } + if ((i & 0x80) == 0) + break; + else + schedule(); + } + + if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1)) + return -EIO; + + lines = q->height; + pixelsperline = q->width; + bitsperxfer = (is_bi_dir) ? 24 : 8; + + if (is_bi_dir) + { + /* Turn the port around */ + parport_data_reverse(q->pport); + mdelay(3); + qcam_set_ack(q, 0); + if (qcam_await_ready1(q, 1)) { + qc_setup(q); + return -EIO; + } + qcam_set_ack(q, 1); + if (qcam_await_ready1(q, 0)) { + qc_setup(q); + return -EIO; + } + } + + wantlen = lines * pixelsperline * 24 / 8; + + while (wantlen) + { + size_t t, s; + s = (wantlen > BUFSZ)?BUFSZ:wantlen; + t = qcam_read_bytes(q, tmpbuf, s); + if (outptr < len) + { + size_t sz = len - outptr; + if (sz > t) sz = t; + if (__copy_to_user(buf+outptr, tmpbuf, sz)) + break; + outptr += sz; + } + wantlen -= t; + if (t < s) + break; + if (current->need_resched) + schedule(); + } + + len = outptr; + + if (wantlen) + { + printk("qcam: short read.\n"); + if (is_bi_dir) + parport_data_forward(q->pport); + qc_setup(q); + return len; + } + + if (is_bi_dir) + { + int l; + do { + l = qcam_read_bytes(q, tmpbuf, 3); + if (current->need_resched) + schedule(); + } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + printk("qcam: bad EOF\n"); + } + qcam_set_ack(q, 0); + if (qcam_await_ready1(q, 1)) + { + printk("qcam: no ack after EOF\n"); + parport_data_forward(q->pport); + qc_setup(q); + return len; + } + parport_data_forward(q->pport); + mdelay(3); + qcam_set_ack(q, 1); + if (qcam_await_ready1(q, 0)) + { + printk("qcam: no ack to port turnaround\n"); + qc_setup(q); + return len; + } + } + else + { + int l; + do { + l = qcam_read_bytes(q, tmpbuf, 1); + if (current->need_resched) + schedule(); + } while (l && tmpbuf[0] == 0x7e); + l = qcam_read_bytes(q, tmpbuf+1, 2); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + printk("qcam: bad EOF\n"); + } + } + + qcam_write_data(q, 0); + return len; +} + +/* + * Video4linux interfacing + */ + +static int qcam_open(struct video_device *dev, int flags) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void qcam_close(struct video_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +static int qcam_init_done(struct video_device *dev) +{ + return 0; +} + +static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct qcam_device *qcam=(struct qcam_device *)dev; + + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, "Quickcam"); + b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES; + b.channels = 1; + b.audios = 0; + b.maxwidth = 320; + b.maxheight = 240; + b.minwidth = 80; + b.minheight = 60; + 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) + return -EINVAL; + v.flags=0; + v.tuners=0; + /* Good question.. its composite or SVHS so.. */ + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "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) + return -EINVAL; + 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= 0; + v.mode = VIDEO_MODE_AUTO; + 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; + if(v.mode!=VIDEO_MODE_AUTO) + return -EINVAL; + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p; + p.colour=0x8000; + p.hue=0x8000; + p.brightness=qcam->brightness<<8; + p.contrast=qcam->contrast<<8; + p.whiteness=qcam->whitebal<<8; + p.depth=24; + p.palette=VIDEO_PALETTE_RGB24; + 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; + + /* + * Sanity check args + */ + if (p.depth != 24 || p.palette != VIDEO_PALETTE_RGB24) + return -EINVAL; + + /* + * Now load the camera. + */ + qcam->brightness = p.brightness>>8; + qcam->contrast = p.contrast>>8; + qcam->whitebal = p.whiteness>>8; + + down(&qcam->lock); + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + up(&qcam->lock); + 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<60||vw.height>240) + return -EINVAL; + if(vw.width<80||vw.width>320) + return -EINVAL; + + qcam->width = 80; + qcam->height = 60; + qcam->mode = QC_DECIMATION_4; + + if(vw.width>=160 && vw.height>=120) + { + qcam->width = 160; + qcam->height = 120; + qcam->mode = QC_DECIMATION_2; + } + if(vw.width>=320 && vw.height>=240) + { + qcam->width = 320; + qcam->height = 240; + qcam->mode = QC_DECIMATION_1; + } + qcam->mode |= QC_MILLIONS; +#if 0 + if(vw.width>=640 && vw.height>=480) + { + qcam->width = 640; + qcam->height = 480; + qcam->mode = QC_BILLIONS | QC_DECIMATION_1; + } +#endif + /* Ok we figured out what to use from our + wide choice */ + down(&qcam->lock); + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + up(&qcam->lock); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + vw.x=0; + vw.y=0; + vw.width=qcam->width; + vw.height=qcam->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 qcam_read(struct video_device *v, char *buf, unsigned long count, int noblock) +{ + struct qcam_device *qcam=(struct qcam_device *)v; + int len; + + down(&qcam->lock); + parport_claim_or_block(qcam->pdev); + /* Probably should have a semaphore against multiple users */ + len = qc_capture(qcam, buf,count); + parport_release(qcam->pdev); + up(&qcam->lock); + return len; +} + +/* video device template */ +static struct video_device qcam_template= +{ + "Colour QuickCam", + VID_TYPE_CAPTURE, + VID_HARDWARE_QCAM_C, + qcam_open, + qcam_close, + qcam_read, + qcam_write, + NULL, + qcam_ioctl, + NULL, + qcam_init_done, + NULL, + 0, + 0 +}; + +/* Initialize the QuickCam driver control structure. */ + +static struct qcam_device *qcam_init(struct parport *port) +{ + struct qcam_device *q; + + q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + if(q==NULL) + return NULL; + + q->pport = port; + q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, + NULL, 0, NULL); + + q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0; + + if (q->pdev == NULL) + { + printk(KERN_ERR "c-qcam: couldn't register for %s.\n", + port->name); + kfree(q); + return NULL; + } + + memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); + + init_MUTEX(&q->lock); + q->width = q->ccd_width = 320; + q->height = q->ccd_height = 240; + q->mode = QC_MILLIONS | QC_DECIMATION_1; + q->contrast = 192; + q->brightness = 240; + q->whitebal = 128; + q->top = 1; + q->left = 14; + return q; +} + +static struct qcam_device *qcams[MAX_CAMS]; +static unsigned int num_cams = 0; + +int init_cqcam(struct parport *port) +{ + struct qcam_device *qcam; + + if (parport[0] != -1) + { + /* The user gave specific instructions */ + int i, found = 0; + for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) + { + if (parport[0] == port->number) + found = 1; + } + if (!found) + return -ENODEV; + } + + if (num_cams == MAX_CAMS) + return -ENOSPC; + + qcam = qcam_init(port); + if (qcam==NULL) + return -ENODEV; + + parport_claim_or_block(qcam->pdev); + + qc_reset(qcam); + + if (probe && qc_detect(qcam)==0) + { + parport_release(qcam->pdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + qc_setup(qcam); + + parport_release(qcam->pdev); + + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) + { + printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", + qcam->pport->name); + parport_unregister_device(qcam->pdev); + kfree(qcam); + return -ENODEV; + } + + printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", + qcam->vdev.minor, qcam->pport->name); + + qcams[num_cams++] = qcam; + + return 0; +} + +void close_cqcam(struct qcam_device *qcam) +{ + video_unregister_device(&qcam->vdev); + parport_unregister_device(qcam->pdev); + kfree(qcam); +} + +static void cq_attach(struct parport *port) +{ + init_cqcam(port); +} + +static void cq_detach(struct parport *port) +{ + /* Write this some day. */ +} + +static struct parport_driver cqcam_driver = { + "cqcam", + cq_attach, + cq_detach, + NULL +}; + +static int __init cqcam_init (void) +{ + printk(BANNER "\n"); + + return parport_register_driver(&cqcam_driver); +} + +static void __exit cqcam_cleanup (void) +{ + unsigned int i; + + for (i = 0; i < num_cams; i++) + close_cqcam(qcams[i]); + + parport_unregister_driver(&cqcam_driver); +} + +MODULE_AUTHOR("Philip Blundell "); +MODULE_DESCRIPTION(BANNER); +MODULE_PARM_DESC(parport ,"parport= for port detection method\n\ +probe=<0|1|2> for camera detection method\n\ +force_rgb=<0|1> for RGB data format (default BGR)"); +MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); +MODULE_PARM(probe, "i"); +MODULE_PARM(force_rgb, "i"); + +module_init(cqcam_init); +module_exit(cqcam_cleanup); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- v2.4.0-test6/linux/drivers/media/video/cpia.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/cpia.c Mon Aug 7 21:01:35 2000 @@ -0,0 +1,3324 @@ +/* + * cpia CPiA driver + * + * Supports CPiA based Video Camera's. + * + * (C) Copyright 1999-2000 Peter Pregler, + * (C) Copyright 1999-2000 Scott J. Bertin, + * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.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 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. + */ + +/* #define _CPIA_DEBUG_ define for verbose debug output */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KMOD +#include +#endif + +#include "cpia.h" + +#ifdef CONFIG_VIDEO_CPIA_PP +extern int cpia_pp_init(void); +#endif +#ifdef CONFIG_VIDEO_CPIA_USB +extern int cpia_usb_init(void); +#endif + +#ifdef MODULE +MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); +MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras"); +MODULE_SUPPORTED_DEVICE("video"); +#endif + +#define ABOUT "V4L-Driver for Vision CPiA based cameras" + +#ifndef VID_HARDWARE_CPIA +#define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */ +#endif + +#define CPIA_MODULE_CPIA (0<<5) +#define CPIA_MODULE_SYSTEM (1<<5) +#define CPIA_MODULE_VP_CTRL (5<<5) +#define CPIA_MODULE_CAPTURE (6<<5) +#define CPIA_MODULE_DEBUG (7<<5) + +#define INPUT (DATA_IN << 8) +#define OUTPUT (DATA_OUT << 8) + +#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1) +#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2) +#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3) +#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4) +#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5) +#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7) +#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8) +#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10) + +#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1) +#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2) +#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3) +#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4) +#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5) +#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6) +#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7) +#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8) +#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9) +#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10) +#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11) +#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12) +#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) + +#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) +#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) +#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) +#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) +#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7) +#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8) +#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9) +#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10) +#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11) +#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16) +#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17) +#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18) +#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19) +#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25) +#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30) +#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31) + +#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1) +#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2) +#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3) +#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4) +#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5) +#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6) +#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7) +#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8) +#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9) +#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10) +#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11) +#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) +#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) +#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) + +#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) +#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) +#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5) +#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6) +#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) +#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) +#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) + +enum { + FRAME_READY, /* Ready to grab into */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_UNUSED, /* Unused (no MCAPTURE) */ +}; + +#define COMMAND_NONE 0x0000 +#define COMMAND_SETCOMPRESSION 0x0001 +#define COMMAND_SETCOMPRESSIONTARGET 0x0002 +#define COMMAND_SETCOLOURPARAMS 0x0004 +#define COMMAND_SETFORMAT 0x0008 +#define COMMAND_PAUSE 0x0010 +#define COMMAND_RESUME 0x0020 +#define COMMAND_SETYUVTHRESH 0x0040 +#define COMMAND_SETECPTIMING 0x0080 +#define COMMAND_SETCOMPRESSIONPARAMS 0x0100 +#define COMMAND_SETEXPOSURE 0x0200 +#define COMMAND_SETCOLOURBALANCE 0x0400 +#define COMMAND_SETSENSORFPS 0x0800 +#define COMMAND_SETAPCOR 0x1000 +#define COMMAND_SETFLICKERCTRL 0x2000 +#define COMMAND_SETVLOFFSET 0x4000 + +/* Developer's Guide Table 5 p 3-34 + * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ +static u8 flicker_jumps[2][2][4] = +{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } }, + { { 64, 32, 16, 8 }, { 76, 38, 19, 9} } +}; + +/* forward declaration of local function */ +static void reset_camera_struct(struct cam_data *cam); + +/********************************************************************** + * + * Memory management + * + * This is a shameless copy from the USB-cpia driver (linux kernel + * version 2.3.29 or so, I have no idea what this code actually does ;). + * Actually it seems to be a copy of a shameless copy of the bttv-driver. + * Or that is a copy of a shameless copy of ... (To the powers: is there + * no generic kernel-function to do this sort of stuff?) + * + * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says + * there will be one, but apparentely not yet - jerdfelt + * + **********************************************************************/ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if (pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE-1)); + } + } + } + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr, page; + + /* Round it off to PAGE_SIZE */ + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (!mem) + return; + + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + vfree(mem); +} + +/********************************************************************** + * + * /proc interface + * + **********************************************************************/ +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *cpia_proc_root=NULL; + +static int cpia_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *out = page; + int len, tmp; + struct cam_data *cam = data; + char tmpstr[20]; + + /* IMPORTANT: This output MUST be kept under PAGE_SIZE + * or we need to get more sophisticated. */ + + out += sprintf(out, "read-only\n-----------------------\n"); + out += sprintf(out, "V4L Driver version: %d.%d.%d\n", + CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); + out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n", + cam->params.version.firmwareVersion, + cam->params.version.firmwareRevision, + cam->params.version.vcVersion, + cam->params.version.vcRevision); + out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n", + cam->params.pnpID.vendor, cam->params.pnpID.product, + cam->params.pnpID.deviceRevision); + out += sprintf(out, "VP-Version: %d.%d %04x\n", + cam->params.vpVersion.vpVersion, + cam->params.vpVersion.vpRevision, + cam->params.vpVersion.cameraHeadID); + + out += sprintf(out, "system_state: %#04x\n", + cam->params.status.systemState); + out += sprintf(out, "grab_state: %#04x\n", + cam->params.status.grabState); + out += sprintf(out, "stream_state: %#04x\n", + cam->params.status.streamState); + out += sprintf(out, "fatal_error: %#04x\n", + cam->params.status.fatalError); + out += sprintf(out, "cmd_error: %#04x\n", + cam->params.status.cmdError); + out += sprintf(out, "debug_flags: %#04x\n", + cam->params.status.debugFlags); + out += sprintf(out, "vp_status: %#04x\n", + cam->params.status.vpStatus); + out += sprintf(out, "error_code: %#04x\n", + cam->params.status.errorCode); + out += sprintf(out, "video_size: %s\n", + cam->params.format.videoSize == VIDEOSIZE_CIF ? + "CIF " : "QCIF"); + out += sprintf(out, "sub_sample: %s\n", + cam->params.format.subSample == SUBSAMPLE_420 ? + "420" : "422"); + out += sprintf(out, "yuv_order: %s\n", + cam->params.format.yuvOrder == YUVORDER_YUYV ? + "YUYV" : "UYVY"); + out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n", + cam->params.roi.colStart*8, + cam->params.roi.rowStart*4, + cam->params.roi.colEnd*8, + cam->params.roi.rowEnd*4); + out += sprintf(out, "actual_fps: %3d\n", cam->fps); + out += sprintf(out, "transfer_rate: %4dkB/s\n", + cam->transfer_rate); + + out += sprintf(out, "\nread-write\n"); + out += sprintf(out, "----------------------- current min" + " max default comment\n"); + out += sprintf(out, "brightness: %8d %8d %8d %8d\n", + cam->params.colourParams.brightness, 0, 100, 50); + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) + /* 1-02 firmware limits contrast to 80 */ + tmp = 80; + else + tmp = 96; + + out += sprintf(out, "contrast: %8d %8d %8d %8d" + " steps of 8\n", + cam->params.colourParams.contrast, 0, tmp, 48); + out += sprintf(out, "saturation: %8d %8d %8d %8d\n", + cam->params.colourParams.saturation, 0, 100, 50); + tmp = (25000+5000*cam->params.sensorFps.baserate)/ + (1<params.sensorFps.divisor); + out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n", + tmp/1000, tmp%1000, 3, 30, 15); + out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n", + 2*cam->params.streamStartLine, 0, + cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, + cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); + out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n", + cam->params.ecpTiming ? "slow" : "normal", "slow", + "normal", "normal"); + + if (cam->params.colourBalance.balanceModeIsAuto) { + sprintf(tmpstr, "auto"); + } else { + sprintf(tmpstr, "manual"); + } + out += sprintf(out, "color_balance_mode: %8s %8s %8s" + " %8s\n", tmpstr, "manual", "auto", "auto"); + out += sprintf(out, "red_gain: %8d %8d %8d %8d\n", + cam->params.colourBalance.redGain, 0, 212, 32); + out += sprintf(out, "green_gain: %8d %8d %8d %8d\n", + cam->params.colourBalance.greenGain, 0, 212, 6); + out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n", + cam->params.colourBalance.blueGain, 0, 212, 92); + + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) + /* 1-02 firmware limits gain to 2 */ + sprintf(tmpstr, "%8d %8d", 1, 2); + else + sprintf(tmpstr, "1,2,4,8"); + + if (cam->params.exposure.gainMode == 0) + out += sprintf(out, "max_gain: unknown %18s" + " %8d\n", tmpstr, 2); + else + out += sprintf(out, "max_gain: %8d %18s %8d\n", + 1<<(cam->params.exposure.gainMode-1), tmpstr, 2); + + switch(cam->params.exposure.expMode) { + case 1: + case 3: + sprintf(tmpstr, "manual"); + break; + case 2: + sprintf(tmpstr, "auto"); + break; + default: + sprintf(tmpstr, "unknown"); + break; + } + out += sprintf(out, "exposure_mode: %8s %8s %8s" + " %8s\n", tmpstr, "manual", "auto", "auto"); + out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n", + (2-cam->params.exposure.centreWeight) ? "on" : "off", + "off", "on", "on"); + out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", + 1<params.exposure.gain, 1, 1); + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) + /* 1-02 firmware limits fineExp to 127 */ + tmp = 255; + else + tmp = 511; + + out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n", + cam->params.exposure.fineExp*2, 0, tmp, 0); + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) + /* 1-02 firmware limits coarseExpHi to 0 */ + tmp = 255; + else + tmp = 65535; + + out += sprintf(out, "coarse_exp: %8d %8d %8d" + " %8d\n", cam->params.exposure.coarseExpLo+ + 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); + out += sprintf(out, "red_comp: %8d %8d %8d %8d\n", + cam->params.exposure.redComp, 220, 255, 220); + out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n", + cam->params.exposure.green1Comp, 214, 255, 214); + out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n", + cam->params.exposure.green2Comp, 214, 255, 214); + out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n", + cam->params.exposure.blueComp, 230, 255, 230); + + out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n", + cam->params.apcor.gain1, 0, 0xff, 0x1c); + out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n", + cam->params.apcor.gain2, 0, 0xff, 0x1a); + out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n", + cam->params.apcor.gain4, 0, 0xff, 0x2d); + out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n", + cam->params.apcor.gain8, 0, 0xff, 0x2a); + out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n", + cam->params.vlOffset.gain1, 0, 255, 24); + out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n", + cam->params.vlOffset.gain2, 0, 255, 28); + out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n", + cam->params.vlOffset.gain4, 0, 255, 30); + out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n", + cam->params.vlOffset.gain8, 0, 255, 30); + out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n", + cam->params.flickerControl.flickerMode ? "on" : "off", + "off", "on", "off"); + out += sprintf(out, "mains_frequency: %8d %8d %8d %8d" + " only 50/60\n", + cam->mainsFreq ? 60 : 50, 50, 60, 50); + out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n", + cam->params.flickerControl.allowableOverExposure, 0, + 255, 0); + out += sprintf(out, "compression_mode: "); + switch(cam->params.compression.mode) { + case CPIA_COMPRESSION_NONE: + out += sprintf(out, "%8s", "none"); + break; + case CPIA_COMPRESSION_AUTO: + out += sprintf(out, "%8s", "auto"); + break; + case CPIA_COMPRESSION_MANUAL: + out += sprintf(out, "%8s", "manual"); + break; + default: + out += sprintf(out, "%8s", "unknown"); + break; + } + out += sprintf(out, " none,auto,manual auto\n"); + out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n", + cam->params.compression.decimation == + DECIMATION_ENAB ? "on":"off", "off", "off", + "off"); + out += sprintf(out, "compression_target: %9s %9s %9s %9s\n", + cam->params.compressionTarget.frTargeting == + CPIA_COMPRESSION_TARGET_FRAMERATE ? + "framerate":"quality", + "framerate", "quality", "quality"); + out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n", + cam->params.compressionTarget.targetFR, 0, 30, 7); + out += sprintf(out, "target_quality: %8d %8d %8d %8d\n", + cam->params.compressionTarget.targetQ, 0, 255, 10); + out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n", + cam->params.yuvThreshold.yThreshold, 0, 31, 15); + out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n", + cam->params.yuvThreshold.uvThreshold, 0, 31, 15); + out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n", + cam->params.compressionParams.hysteresis, 0, 255, 3); + out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n", + cam->params.compressionParams.threshMax, 0, 255, 11); + out += sprintf(out, "small_step: %8d %8d %8d %8d\n", + cam->params.compressionParams.smallStep, 0, 255, 1); + out += sprintf(out, "large_step: %8d %8d %8d %8d\n", + cam->params.compressionParams.largeStep, 0, 255, 3); + out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n", + cam->params.compressionParams.decimationHysteresis, + 0, 255, 2); + out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n", + cam->params.compressionParams.frDiffStepThresh, + 0, 255, 5); + out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n", + cam->params.compressionParams.qDiffStepThresh, + 0, 255, 3); + out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", + cam->params.compressionParams.decimationThreshMod, + 0, 255, 2); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) return 0; + } else + len = count; + + *start = page + off; + return len; +} + +static int cpia_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct cam_data *cam = data; + struct cam_params new_params; + int retval, find_colon; + int size = count; + unsigned long val; + u32 command_flags = 0; + u8 new_mains; + + if (down_interruptible(&cam->param_lock)) + return -ERESTARTSYS; + + /* + * Skip over leading whitespace + */ + while (count && isspace(*buffer)) { + --count; + ++buffer; + } + + memcpy(&new_params, &cam->params, sizeof(struct cam_params)); + new_mains = cam->mainsFreq; + +#define MATCH(x) \ + ({ \ + int _len = strlen(x), _ret, _colon_found; \ + _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \ + if (_ret) { \ + buffer += _len; \ + count -= _len; \ + if (find_colon) { \ + _colon_found = 0; \ + while (count && (*buffer == ' ' || *buffer == '\t' || \ + (!_colon_found && *buffer == ':'))) { \ + if (*buffer == ':') \ + _colon_found = 1; \ + --count; \ + ++buffer; \ + } \ + if (!count || !_colon_found) \ + retval = -EINVAL; \ + find_colon = 0; \ + } \ + } \ + _ret; \ + }) +#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \ + new_params.version.firmwareRevision == (y)) +#define VALUE \ + ({ \ + char *_p; \ + unsigned long int _ret; \ + _ret = simple_strtoul(buffer, &_p, 0); \ + if (_p == buffer) \ + retval = -EINVAL; \ + else { \ + count -= _p - buffer; \ + buffer = _p; \ + } \ + _ret; \ + }) + + retval = 0; + while (count && !retval) { + find_colon = 1; + if (MATCH("brightness")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 100) + new_params.colourParams.brightness = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOLOURPARAMS; + } else if (MATCH("contrast")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 100) { + /* contrast is in steps of 8, so round*/ + val = ((val + 3) / 8) * 8; + /* 1-02 firmware limits contrast to 80*/ + if (FIRMWARE_VERSION(1,2) && val > 80) + val = 80; + + new_params.colourParams.contrast = val; + } else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOLOURPARAMS; + } else if (MATCH("saturation")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 100) + new_params.colourParams.saturation = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOLOURPARAMS; + } else if (MATCH("sensor_fps")) { + if (!retval) + val = VALUE; + + if (!retval) { + /* find values so that sensorFPS is minimized, + * but >= val */ + if (val > 30) + retval = -EINVAL; + else if (val > 25) { + new_params.sensorFps.divisor = 0; + new_params.sensorFps.baserate = 1; + } else if (val > 15) { + new_params.sensorFps.divisor = 0; + new_params.sensorFps.baserate = 0; + } else if (val > 12) { + new_params.sensorFps.divisor = 1; + new_params.sensorFps.baserate = 1; + } else if (val > 7) { + new_params.sensorFps.divisor = 1; + new_params.sensorFps.baserate = 0; + } else if (val > 6) { + new_params.sensorFps.divisor = 2; + new_params.sensorFps.baserate = 1; + } else if (val > 3) { + new_params.sensorFps.divisor = 2; + new_params.sensorFps.baserate = 0; + } else { + new_params.sensorFps.divisor = 3; + /* Either base rate would work here */ + new_params.sensorFps.baserate = 1; + } + new_params.flickerControl.coarseJump = + flicker_jumps[new_mains] + [new_params.sensorFps.baserate] + [new_params.sensorFps.divisor]; + if (new_params.flickerControl.flickerMode) + command_flags |= COMMAND_SETFLICKERCTRL; + } + command_flags |= COMMAND_SETSENSORFPS; + } else if (MATCH("stream_start_line")) { + if (!retval) + val = VALUE; + + if (!retval) { + int max_line = 288; + + if (new_params.format.videoSize == VIDEOSIZE_QCIF) + max_line = 144; + if (val <= max_line) + new_params.streamStartLine = val/2; + else + retval = -EINVAL; + } + } else if (MATCH("ecp_timing")) { + if (!retval && MATCH("normal")) + new_params.ecpTiming = 0; + else if (!retval && MATCH("slow")) + new_params.ecpTiming = 1; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETECPTIMING; + } else if (MATCH("color_balance_mode")) { + if (!retval && MATCH("manual")) + new_params.colourBalance.balanceModeIsAuto = 0; + else if (!retval && MATCH("auto")) + new_params.colourBalance.balanceModeIsAuto = 1; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETCOLOURBALANCE; + } else if (MATCH("red_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 212) + new_params.colourBalance.redGain = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOLOURBALANCE; + } else if (MATCH("green_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 212) + new_params.colourBalance.greenGain = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOLOURBALANCE; + } else if (MATCH("blue_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 212) + new_params.colourBalance.blueGain = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOLOURBALANCE; + } else if (MATCH("max_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + /* 1-02 firmware limits gain to 2 */ + if (FIRMWARE_VERSION(1,2) && val > 2) + val = 2; + switch(val) { + case 1: + new_params.exposure.gainMode = 1; + break; + case 2: + new_params.exposure.gainMode = 2; + break; + case 4: + new_params.exposure.gainMode = 3; + break; + case 8: + new_params.exposure.gainMode = 4; + break; + default: + retval = -EINVAL; + break; + } + } + command_flags |= COMMAND_SETEXPOSURE; + } else if (MATCH("exposure_mode")) { + if (!retval && MATCH("auto")) + new_params.exposure.expMode = 2; + else if (!retval && MATCH("manual")) { + if (new_params.exposure.expMode == 2) + new_params.exposure.expMode = 3; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + } else + retval = -EINVAL; + + command_flags |= COMMAND_SETEXPOSURE; + } else if (MATCH("centre_weight")) { + if (!retval && MATCH("on")) + new_params.exposure.centreWeight = 1; + else if (!retval && MATCH("off")) + new_params.exposure.centreWeight = 2; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETEXPOSURE; + } else if (MATCH("gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + switch(val) { + case 1: + new_params.exposure.gain = 0; + new_params.exposure.expMode = 1; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + break; + case 2: + new_params.exposure.gain = 1; + new_params.exposure.expMode = 1; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + break; + case 4: + new_params.exposure.gain = 2; + new_params.exposure.expMode = 1; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + break; + case 8: + new_params.exposure.gain = 3; + new_params.exposure.expMode = 1; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + break; + default: + retval = -EINVAL; + break; + } + command_flags |= COMMAND_SETEXPOSURE; + if (new_params.exposure.gain > + new_params.exposure.gainMode-1) + retval = -EINVAL; + } + } else if (MATCH("fine_exp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 256) { + /* 1-02 firmware limits fineExp to 127*/ + if (FIRMWARE_VERSION(1,2) && val > 127) + val = 127; + new_params.exposure.fineExp = val; + new_params.exposure.expMode = 1; + command_flags |= COMMAND_SETEXPOSURE; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + } else + retval = -EINVAL; + } + } else if (MATCH("coarse_exp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 65536) { + /* 1-02 firmware limits + * coarseExp to 255 */ + if (FIRMWARE_VERSION(1,2) && val > 255) + val = 255; + new_params.exposure.coarseExpLo = + val & 0xff; + new_params.exposure.coarseExpHi = + val >> 8; + new_params.exposure.expMode = 1; + command_flags |= COMMAND_SETEXPOSURE; + new_params.flickerControl.flickerMode = 0; + command_flags |= COMMAND_SETFLICKERCTRL; + } else + retval = -EINVAL; + } + } else if (MATCH("red_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 220 && val <= 255) { + new_params.exposure.redComp = val; + command_flags |= COMMAND_SETEXPOSURE; + } else + retval = -EINVAL; + } + } else if (MATCH("green1_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 214 && val <= 255) { + new_params.exposure.green1Comp = val; + command_flags |= COMMAND_SETEXPOSURE; + } else + retval = -EINVAL; + } + } else if (MATCH("green2_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 214 && val <= 255) { + new_params.exposure.green2Comp = val; + command_flags |= COMMAND_SETEXPOSURE; + } else + retval = -EINVAL; + } + } else if (MATCH("blue_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 230 && val <= 255) { + new_params.exposure.blueComp = val; + command_flags |= COMMAND_SETEXPOSURE; + } else + retval = -EINVAL; + } + } else if (MATCH("apcor_gain1")) { + if (!retval) + val = VALUE; + + if (!retval) { + command_flags |= COMMAND_SETAPCOR; + if (val <= 0xff) + new_params.apcor.gain1 = val; + else + retval = -EINVAL; + } + } else if (MATCH("apcor_gain2")) { + if (!retval) + val = VALUE; + + if (!retval) { + command_flags |= COMMAND_SETAPCOR; + if (val <= 0xff) + new_params.apcor.gain2 = val; + else + retval = -EINVAL; + } + } else if (MATCH("apcor_gain4")) { + if (!retval) + val = VALUE; + + if (!retval) { + command_flags |= COMMAND_SETAPCOR; + if (val <= 0xff) + new_params.apcor.gain4 = val; + else + retval = -EINVAL; + } + } else if (MATCH("apcor_gain8")) { + if (!retval) + val = VALUE; + + if (!retval) { + command_flags |= COMMAND_SETAPCOR; + if (val <= 0xff) + new_params.apcor.gain8 = val; + else + retval = -EINVAL; + } + } else if (MATCH("vl_offset_gain1")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain1 = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETVLOFFSET; + } else if (MATCH("vl_offset_gain2")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain2 = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETVLOFFSET; + } else if (MATCH("vl_offset_gain4")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain4 = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETVLOFFSET; + } else if (MATCH("vl_offset_gain8")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain8 = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETVLOFFSET; + } else if (MATCH("flicker_control")) { + if (!retval && MATCH("on")) { + new_params.flickerControl.flickerMode = 1; + new_params.exposure.expMode = 2; + command_flags |= COMMAND_SETEXPOSURE; + } else if (!retval && MATCH("off")) + new_params.flickerControl.flickerMode = 0; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETFLICKERCTRL; + } else if (MATCH("mains_frequency")) { + if (!retval && MATCH("50")) { + new_mains = 0; + new_params.flickerControl.coarseJump = + flicker_jumps[new_mains] + [new_params.sensorFps.baserate] + [new_params.sensorFps.divisor]; + if (new_params.flickerControl.flickerMode) + command_flags |= COMMAND_SETFLICKERCTRL; + } else if (!retval && MATCH("60")) { + new_mains = 1; + new_params.flickerControl.coarseJump = + flicker_jumps[new_mains] + [new_params.sensorFps.baserate] + [new_params.sensorFps.divisor]; + if (new_params.flickerControl.flickerMode) + command_flags |= COMMAND_SETFLICKERCTRL; + } else + retval = -EINVAL; + } else if (MATCH("allowable_overexposure")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) { + new_params.flickerControl. + allowableOverExposure = val; + command_flags |= COMMAND_SETFLICKERCTRL; + } else + retval = -EINVAL; + } + } else if (MATCH("compression_mode")) { + if (!retval && MATCH("none")) + new_params.compression.mode = + CPIA_COMPRESSION_NONE; + else if (!retval && MATCH("auto")) + new_params.compression.mode = + CPIA_COMPRESSION_AUTO; + else if (!retval && MATCH("manual")) + new_params.compression.mode = + CPIA_COMPRESSION_MANUAL; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETCOMPRESSION; + } else if (MATCH("decimation_enable")) { + if (!retval && MATCH("off")) + new_params.compression.decimation = 0; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETCOMPRESSION; + } else if (MATCH("compression_target")) { + if (!retval && MATCH("quality")) + new_params.compressionTarget.frTargeting = + CPIA_COMPRESSION_TARGET_QUALITY; + else if (!retval && MATCH("framerate")) + new_params.compressionTarget.frTargeting = + CPIA_COMPRESSION_TARGET_FRAMERATE; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETCOMPRESSIONTARGET; + } else if (MATCH("target_framerate")) { + if (!retval) + val = VALUE; + + if (!retval) + new_params.compressionTarget.targetFR = val; + command_flags |= COMMAND_SETCOMPRESSIONTARGET; + } else if (MATCH("target_quality")) { + if (!retval) + val = VALUE; + + if (!retval) + new_params.compressionTarget.targetQ = val; + + command_flags |= COMMAND_SETCOMPRESSIONTARGET; + } else if (MATCH("y_threshold")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 32) + new_params.yuvThreshold.yThreshold = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETYUVTHRESH; + } else if (MATCH("uv_threshold")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 32) + new_params.yuvThreshold.uvThreshold = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETYUVTHRESH; + } else if (MATCH("hysteresis")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.hysteresis = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("threshold_max")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.threshMax = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("small_step")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.smallStep = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("large_step")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.largeStep = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("decimation_hysteresis")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.decimationHysteresis = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("fr_diff_step_thresh")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.frDiffStepThresh = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("q_diff_step_thresh")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.qDiffStepThresh = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("decimation_thresh_mod")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.decimationThreshMod = val; + else + retval = -EINVAL; + } + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else { + DBG("No match found\n"); + retval = -EINVAL; + } + + if (!retval) { + while (count && isspace(*buffer) && *buffer != '\n') { + --count; + ++buffer; + } + if (count) { + if (*buffer != '\n' && *buffer != ';') + retval = -EINVAL; + else { + --count; + ++buffer; + } + } + } + } +#undef MATCH +#undef FIRMWARE_VERSION +#undef VALUE +#undef FIND_VALUE +#undef FIND_END + if (!retval) { + if (command_flags & COMMAND_SETCOLOURPARAMS) { + /* Adjust cam->vp to reflect these changes */ + cam->vp.brightness = + new_params.colourParams.brightness*65535/100; + cam->vp.contrast = + new_params.colourParams.contrast*65535/100; + cam->vp.colour = + new_params.colourParams.saturation*65535/100; + } + + memcpy(&cam->params, &new_params, sizeof(struct cam_params)); + cam->mainsFreq = new_mains; + cam->cmd_queue |= command_flags; + retval = size; + } else + DBG("error: %d\n", retval); + + up(&cam->param_lock); + + return retval; +} + +static void create_proc_cpia_cam(struct cam_data *cam) +{ + char name[7]; + struct proc_dir_entry *ent; + + if (!cpia_proc_root || !cam) + return; + + sprintf(name, "video%d", cam->vdev.minor); + + ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root); + if (!ent) + return; + + ent->data = cam; + ent->read_proc = cpia_read_proc; + ent->write_proc = cpia_write_proc; + ent->size = 3626; + cam->proc_entry = ent; +} + +static void destroy_proc_cpia_cam(struct cam_data *cam) +{ + char name[7]; + + if (!cam || !cam->proc_entry) + return; + + sprintf(name, "video%d", cam->vdev.minor); + remove_proc_entry(name, cpia_proc_root); + cam->proc_entry = NULL; +} + +static void proc_cpia_create(void) +{ + cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0); + + if (cpia_proc_root) + cpia_proc_root->owner = THIS_MODULE; + else + LOG("Unable to initialise /proc/cpia\n"); +} + +static void proc_cpia_destroy(void) +{ + remove_proc_entry("cpia", 0); +} +#endif /* CONFIG_PROC_FS */ + +/* ----------------------- debug functions ---------------------- */ + +#define printstatus(cam) \ + DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\ + cam->params.status.systemState, cam->params.status.grabState, \ + cam->params.status.streamState, cam->params.status.fatalError, \ + cam->params.status.cmdError, cam->params.status.debugFlags, \ + cam->params.status.vpStatus, cam->params.status.errorCode); + +/* ----------------------- v4l helpers -------------------------- */ + +/* supported frame palettes and depths */ +static inline int valid_mode(u16 palette, u16 depth) +{ + return (palette == VIDEO_PALETTE_GREY && depth == 8) || + (palette == VIDEO_PALETTE_RGB555 && depth == 16) || + (palette == VIDEO_PALETTE_RGB565 && depth == 16) || + (palette == VIDEO_PALETTE_RGB24 && depth == 24) || + (palette == VIDEO_PALETTE_RGB32 && depth == 32) || + (palette == VIDEO_PALETTE_YUV422 && depth == 16) || + (palette == VIDEO_PALETTE_YUYV && depth == 16) || + (palette == VIDEO_PALETTE_UYVY && depth == 16); +} + +static int match_videosize( int width, int height ) +{ + /* return the best match, where 'best' is as always + * the largest that is not bigger than what is requested. */ + if (width>=352 && height>=288) + return VIDEOSIZE_352_288; /* CIF */ + + if (width>=320 && height>=240) + return VIDEOSIZE_320_240; /* SIF */ + + if (width>=288 && height>=216) + return VIDEOSIZE_288_216; + + if (width>=256 && height>=192) + return VIDEOSIZE_256_192; + + if (width>=224 && height>=168) + return VIDEOSIZE_224_168; + + if (width>=192 && height>=144) + return VIDEOSIZE_192_144; + + if (width>=176 && height>=144) + return VIDEOSIZE_176_144; /* QCIF */ + + if (width>=160 && height>=120) + return VIDEOSIZE_160_120; /* QSIF */ + + if (width>=128 && height>=96) + return VIDEOSIZE_128_96; + + if (width>=88 && height>=72) + return VIDEOSIZE_88_72; + + if (width>=64 && height>=48) + return VIDEOSIZE_64_48; + + if (width>=48 && height>=48) + return VIDEOSIZE_48_48; + + return -1; +} + +/* these are the capture sizes we support */ +static void set_vw_size(struct cam_data *cam) +{ + /* the col/row/start/end values are the result of simple math */ + /* study the SetROI-command in cpia developers guide p 2-22 */ + /* streamStartLine is set to the recommended value in the cpia */ + /* developers guide p 3-37 */ + switch(cam->video_size) { + case VIDEOSIZE_CIF: + cam->vw.width = 352; + cam->vw.height = 288; + cam->params.format.videoSize=VIDEOSIZE_CIF; + cam->params.roi.colStart=0; + cam->params.roi.colEnd=44; + cam->params.roi.rowStart=0; + cam->params.roi.rowEnd=72; + cam->params.streamStartLine = 120; + break; + case VIDEOSIZE_SIF: + cam->vw.width = 320; + cam->vw.height = 240; + cam->params.format.videoSize=VIDEOSIZE_CIF; + cam->params.roi.colStart=2; + cam->params.roi.colEnd=42; + cam->params.roi.rowStart=6; + cam->params.roi.rowEnd=66; + cam->params.streamStartLine = 120; + break; + case VIDEOSIZE_288_216: + cam->vw.width = 288; + cam->vw.height = 216; + cam->params.format.videoSize=VIDEOSIZE_CIF; + cam->params.roi.colStart=4; + cam->params.roi.colEnd=40; + cam->params.roi.rowStart=9; + cam->params.roi.rowEnd=63; + cam->params.streamStartLine = 120; + break; + case VIDEOSIZE_256_192: + cam->vw.width = 256; + cam->vw.height = 192; + cam->params.format.videoSize=VIDEOSIZE_CIF; + cam->params.roi.colStart=6; + cam->params.roi.colEnd=38; + cam->params.roi.rowStart=12; + cam->params.roi.rowEnd=60; + cam->params.streamStartLine = 120; + break; + case VIDEOSIZE_224_168: + cam->vw.width = 224; + cam->vw.height = 168; + cam->params.format.videoSize=VIDEOSIZE_CIF; + cam->params.roi.colStart=8; + cam->params.roi.colEnd=36; + cam->params.roi.rowStart=15; + cam->params.roi.rowEnd=57; + cam->params.streamStartLine = 120; + break; + case VIDEOSIZE_192_144: + cam->vw.width = 192; + cam->vw.height = 144; + cam->params.format.videoSize=VIDEOSIZE_CIF; + cam->params.roi.colStart=10; + cam->params.roi.colEnd=34; + cam->params.roi.rowStart=18; + cam->params.roi.rowEnd=54; + cam->params.streamStartLine = 120; + break; + case VIDEOSIZE_QCIF: + cam->vw.width = 176; + cam->vw.height = 144; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=0; + cam->params.roi.colEnd=22; + cam->params.roi.rowStart=0; + cam->params.roi.rowEnd=36; + cam->params.streamStartLine = 60; + break; + case VIDEOSIZE_QSIF: + cam->vw.width = 160; + cam->vw.height = 120; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=1; + cam->params.roi.colEnd=21; + cam->params.roi.rowStart=3; + cam->params.roi.rowEnd=33; + cam->params.streamStartLine = 60; + break; + case VIDEOSIZE_128_96: + cam->vw.width = 128; + cam->vw.height = 96; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=3; + cam->params.roi.colEnd=19; + cam->params.roi.rowStart=6; + cam->params.roi.rowEnd=30; + cam->params.streamStartLine = 60; + break; + case VIDEOSIZE_88_72: + cam->vw.width = 88; + cam->vw.height = 72; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=5; + cam->params.roi.colEnd=16; + cam->params.roi.rowStart=9; + cam->params.roi.rowEnd=27; + cam->params.streamStartLine = 60; + break; + case VIDEOSIZE_64_48: + cam->vw.width = 64; + cam->vw.height = 48; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=7; + cam->params.roi.colEnd=15; + cam->params.roi.rowStart=12; + cam->params.roi.rowEnd=24; + cam->params.streamStartLine = 60; + break; + case VIDEOSIZE_48_48: + cam->vw.width = 48; + cam->vw.height = 48; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=8; + cam->params.roi.colEnd=14; + cam->params.roi.rowStart=6; + cam->params.roi.rowEnd=30; + cam->params.streamStartLine = 60; + break; + default: + LOG("bad videosize value: %d\n", cam->video_size); + } + + return; +} + +static int allocate_frame_buf(struct cam_data *cam) +{ + int i; + + cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE); + if (!cam->frame_buf) + return -ENOBUFS; + + for (i = 0; i < FRAME_NUM; i++) + cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE; + + return 0; +} + +static int free_frame_buf(struct cam_data *cam) +{ + int i; + + rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE); + cam->frame_buf = 0; + for (i=0; i < FRAME_NUM; i++) + cam->frame[i].data = NULL; + + return 0; +} + + +static void inline free_frames(struct cpia_frame frame[FRAME_NUM]) +{ + int i; + + for (i=0; i < FRAME_NUM; i++) + frame[i].state = FRAME_UNUSED; + return; +} + +/********************************************************************** + * + * General functions + * + **********************************************************************/ +/* send an arbitrary command to the camera */ +static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) +{ + int retval, datasize; + u8 cmd[8], data[8]; + + switch(command) { + case CPIA_COMMAND_GetCPIAVersion: + case CPIA_COMMAND_GetPnPID: + case CPIA_COMMAND_GetCameraStatus: + case CPIA_COMMAND_GetVPVersion: + datasize=8; + break; + case CPIA_COMMAND_GetColourParams: + case CPIA_COMMAND_GetColourBalance: + case CPIA_COMMAND_GetExposure: + down(&cam->param_lock); + datasize=8; + break; + default: + datasize=0; + break; + } + + cmd[0] = command>>8; + cmd[1] = command&0xff; + cmd[2] = a; + cmd[3] = b; + cmd[4] = c; + cmd[5] = d; + cmd[6] = datasize; + cmd[7] = 0; + + retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); + if (retval) { + DBG("%x - failed, retval=%d\n", command, retval); + if (command == CPIA_COMMAND_GetColourParams || + command == CPIA_COMMAND_GetColourBalance || + command == CPIA_COMMAND_GetExposure) + up(&cam->param_lock); + } else { + switch(command) { + case CPIA_COMMAND_GetCPIAVersion: + cam->params.version.firmwareVersion = data[0]; + cam->params.version.firmwareRevision = data[1]; + cam->params.version.vcVersion = data[2]; + cam->params.version.vcRevision = data[3]; + break; + case CPIA_COMMAND_GetPnPID: + cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8); + cam->params.pnpID.product = data[2]+(((u16)data[3])<<8); + cam->params.pnpID.deviceRevision = + data[4]+(((u16)data[5])<<8); + break; + case CPIA_COMMAND_GetCameraStatus: + cam->params.status.systemState = data[0]; + cam->params.status.grabState = data[1]; + cam->params.status.streamState = data[2]; + cam->params.status.fatalError = data[3]; + cam->params.status.cmdError = data[4]; + cam->params.status.debugFlags = data[5]; + cam->params.status.vpStatus = data[6]; + cam->params.status.errorCode = data[7]; + break; + case CPIA_COMMAND_GetVPVersion: + cam->params.vpVersion.vpVersion = data[0]; + cam->params.vpVersion.vpRevision = data[1]; + cam->params.vpVersion.cameraHeadID = + data[2]+(((u16)data[3])<<8); + break; + case CPIA_COMMAND_GetColourParams: + cam->params.colourParams.brightness = data[0]; + cam->params.colourParams.contrast = data[1]; + cam->params.colourParams.saturation = data[2]; + up(&cam->param_lock); + break; + case CPIA_COMMAND_GetColourBalance: + cam->params.colourBalance.redGain = data[0]; + cam->params.colourBalance.greenGain = data[1]; + cam->params.colourBalance.blueGain = data[2]; + up(&cam->param_lock); + break; + case CPIA_COMMAND_GetExposure: + cam->params.exposure.gain = data[0]; + cam->params.exposure.fineExp = data[1]; + cam->params.exposure.coarseExpLo = data[2]; + cam->params.exposure.coarseExpHi = data[3]; + cam->params.exposure.redComp = data[4]; + cam->params.exposure.green1Comp = data[5]; + cam->params.exposure.green2Comp = data[6]; + cam->params.exposure.blueComp = data[7]; + /* If the *Comp parameters are wacko, generate + * a warning, and reset them back to default + * values. - rich@annexia.org + */ + if (cam->params.exposure.redComp < 220 || + cam->params.exposure.redComp > 255 || + cam->params.exposure.green1Comp < 214 || + cam->params.exposure.green1Comp > 255 || + cam->params.exposure.green2Comp < 214 || + cam->params.exposure.green2Comp > 255 || + cam->params.exposure.blueComp < 230 || + cam->params.exposure.blueComp > 255) + { + printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n", + cam->params.exposure.redComp, + cam->params.exposure.green1Comp, + cam->params.exposure.green2Comp, + cam->params.exposure.blueComp); + cam->params.exposure.redComp = 220; + cam->params.exposure.green1Comp = 214; + cam->params.exposure.green2Comp = 214; + cam->params.exposure.blueComp = 230; + } + up(&cam->param_lock); + break; + default: + break; + } + } + return retval; +} + +/* send a command to the camera with an additional data transaction */ +static int do_command_extended(struct cam_data *cam, u16 command, + u8 a, u8 b, u8 c, u8 d, + u8 e, u8 f, u8 g, u8 h, + u8 i, u8 j, u8 k, u8 l) +{ + int retval; + u8 cmd[8], data[8]; + + cmd[0] = command>>8; + cmd[1] = command&0xff; + cmd[2] = a; + cmd[3] = b; + cmd[4] = c; + cmd[5] = d; + cmd[6] = 8; + cmd[7] = 0; + data[0] = e; + data[1] = f; + data[2] = g; + data[3] = h; + data[4] = i; + data[5] = j; + data[6] = k; + data[7] = l; + + retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); + if (retval) + LOG("%x - failed\n", command); + + return retval; +} + +/********************************************************************** + * + * Colorspace conversion + * + **********************************************************************/ +#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) + +static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt, + int in_uyvy, int mmap_kludge) +{ + int y, u, v, r, g, b, y1; + + switch(out_fmt) { + case VIDEO_PALETTE_RGB555: + case VIDEO_PALETTE_RGB565: + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_RGB32: + if (in_uyvy) { + u = *yuv++ - 128; + y = (*yuv++ - 16) * 76310; + v = *yuv++ - 128; + y1 = (*yuv - 16) * 76310; + } else { + y = (*yuv++ - 16) * 76310; + u = *yuv++ - 128; + y1 = (*yuv++ - 16) * 76310; + v = *yuv - 128; + } + r = 104635 * v; + g = -25690 * u + -53294 * v; + b = 132278 * u; + break; + default: + y = *yuv++; + u = *yuv++; + y1 = *yuv++; + v = *yuv; + /* Just to avoid compiler warnings */ + r = 0; + g = 0; + b = 0; + break; + } + switch(out_fmt) { + case VIDEO_PALETTE_RGB555: + *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3); + *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6); + *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3); + *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6); + return 4; + case VIDEO_PALETTE_RGB565: + *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3); + *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5); + *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3); + *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5); + return 4; + case VIDEO_PALETTE_RGB24: + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } + return 6; + case VIDEO_PALETTE_RGB32: + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + rgb++; + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + rgb++; + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } + return 8; + case VIDEO_PALETTE_GREY: + *rgb++ = y; + *rgb = y1; + return 2; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + *rgb++ = y; + *rgb++ = u; + *rgb++ = y1; + *rgb = v; + return 4; + case VIDEO_PALETTE_UYVY: + *rgb++ = u; + *rgb++ = y; + *rgb++ = v; + *rgb = y1; + return 4; + default: + DBG("Empty: %d\n", out_fmt); + return 0; + } +} + +static int skipcount(int count, int fmt) +{ + switch(fmt) { + case VIDEO_PALETTE_GREY: + case VIDEO_PALETTE_RGB555: + case VIDEO_PALETTE_RGB565: + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_UYVY: + return 2*count; + case VIDEO_PALETTE_RGB24: + return 3*count; + case VIDEO_PALETTE_RGB32: + return 4*count; + default: + return 0; + } +} + +static int parse_picture(struct cam_data *cam, int size) +{ + u8 *obuf, *ibuf, *end_obuf; + int ll, in_uyvy, compressed, origsize, out_fmt; + + /* make sure params don't change while we are decoding */ + down(&cam->param_lock); + + obuf = cam->decompressed_frame.data; + end_obuf = obuf+CPIA_MAX_FRAME_SIZE; + ibuf = cam->raw_image; + origsize = size; + out_fmt = cam->vp.palette; + + if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) { + LOG("header not found\n"); + up(&cam->param_lock); + return -1; + } + + if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) { + LOG("wrong video size\n"); + up(&cam->param_lock); + return -1; + } + + if (ibuf[17] != SUBSAMPLE_422) { + LOG("illegal subtype %d\n",ibuf[17]); + up(&cam->param_lock); + return -1; + } + + if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) { + LOG("illegal yuvorder %d\n",ibuf[18]); + up(&cam->param_lock); + return -1; + } + in_uyvy = ibuf[18] == YUVORDER_UYVY; + +#if 0 + /* FIXME: ROI mismatch occurs when switching capture sizes */ + if ((ibuf[24] != cam->params.roi.colStart) || + (ibuf[25] != cam->params.roi.colEnd) || + (ibuf[26] != cam->params.roi.rowStart) || + (ibuf[27] != cam->params.roi.rowEnd)) { + LOG("ROI mismatch\n"); + up(&cam->param_lock); + return -1; + } +#endif + + if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) { + LOG("illegal compression %d\n",ibuf[28]); + up(&cam->param_lock); + return -1; + } + compressed = (ibuf[28] == COMPRESSED); + + if (ibuf[29] != NO_DECIMATION) { + LOG("decimation not supported\n"); + up(&cam->param_lock); + return -1; + } + + cam->params.yuvThreshold.yThreshold = ibuf[30]; + cam->params.yuvThreshold.uvThreshold = ibuf[31]; + cam->params.status.systemState = ibuf[32]; + cam->params.status.grabState = ibuf[33]; + cam->params.status.streamState = ibuf[34]; + cam->params.status.fatalError = ibuf[35]; + cam->params.status.cmdError = ibuf[36]; + cam->params.status.debugFlags = ibuf[37]; + cam->params.status.vpStatus = ibuf[38]; + cam->params.status.errorCode = ibuf[39]; + cam->fps = ibuf[41]; + up(&cam->param_lock); + + ibuf += FRAME_HEADER_SIZE; + size -= FRAME_HEADER_SIZE; + ll = ibuf[0] | (ibuf[1] << 8); + ibuf += 2; + + while (size > 0) { + size -= (ll+2); + if (size < 0) { + LOG("Insufficient data in buffer\n"); + return -1; + } + + while (ll > 1) { + if (!compressed || (compressed && !(*ibuf & 1))) { + obuf += yuvconvert(ibuf, obuf, out_fmt, + in_uyvy, cam->mmap_kludge); + ibuf += 4; + ll -= 4; + } else { + /*skip compressed interval from previous frame*/ + int skipsize = skipcount(*ibuf >> 1, out_fmt); + obuf += skipsize; + if (obuf > end_obuf) { + LOG("Insufficient data in buffer\n"); + return -1; + } + ++ibuf; + ll--; + } + } + if (ll == 1) { + if (*ibuf != EOL) { + LOG("EOL not found giving up after %d/%d" + " bytes\n", origsize-size, origsize); + return -1; + } + + ibuf++; /* skip over EOL */ + + if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) && + (ibuf[2] == EOI) && (ibuf[3] == EOI)) { + size -= 4; + break; + } + + if (size > 1) { + ll = ibuf[0] | (ibuf[1] << 8); + ibuf += 2; /* skip over line length */ + } + } else { + LOG("line length was not 1 but %d after %d/%d bytes\n", + ll, origsize-size, origsize); + return -1; + } + } + + cam->decompressed_frame.count = obuf-cam->decompressed_frame.data; + + return cam->decompressed_frame.count; +} + +/* InitStreamCap wrapper to select correct start line */ +static inline int init_stream_cap(struct cam_data *cam) +{ + return do_command(cam, CPIA_COMMAND_InitStreamCap, + 0, cam->params.streamStartLine, 0, 0); +} + +/* update various camera modes and settings */ +static void dispatch_commands(struct cam_data *cam) +{ + down(&cam->param_lock); + if (cam->cmd_queue==COMMAND_NONE) { + up(&cam->param_lock); + return; + } + DEB_BYTE(cam->cmd_queue); + DEB_BYTE(cam->cmd_queue>>8); + if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS) + do_command(cam, CPIA_COMMAND_SetColourParams, + cam->params.colourParams.brightness, + cam->params.colourParams.contrast, + cam->params.colourParams.saturation, 0); + + if (cam->cmd_queue & COMMAND_SETCOMPRESSION) + do_command(cam, CPIA_COMMAND_SetCompression, + cam->params.compression.mode, + cam->params.compression.decimation, 0, 0); + + if (cam->cmd_queue & COMMAND_SETFORMAT) { + do_command(cam, CPIA_COMMAND_SetFormat, + cam->params.format.videoSize, + cam->params.format.subSample, + cam->params.format.yuvOrder, 0); + do_command(cam, CPIA_COMMAND_SetROI, + cam->params.roi.colStart, cam->params.roi.colEnd, + cam->params.roi.rowStart, cam->params.roi.rowEnd); + cam->first_frame = 1; + } + + if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET) + do_command(cam, CPIA_COMMAND_SetCompressionTarget, + cam->params.compressionTarget.frTargeting, + cam->params.compressionTarget.targetFR, + cam->params.compressionTarget.targetQ, 0); + + if (cam->cmd_queue & COMMAND_SETYUVTHRESH) + do_command(cam, CPIA_COMMAND_SetYUVThresh, + cam->params.yuvThreshold.yThreshold, + cam->params.yuvThreshold.uvThreshold, 0, 0); + + if (cam->cmd_queue & COMMAND_SETECPTIMING) + do_command(cam, CPIA_COMMAND_SetECPTiming, + cam->params.ecpTiming, 0, 0, 0); + + if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS) + do_command_extended(cam, CPIA_COMMAND_SetCompressionParams, + 0, 0, 0, 0, + cam->params.compressionParams.hysteresis, + cam->params.compressionParams.threshMax, + cam->params.compressionParams.smallStep, + cam->params.compressionParams.largeStep, + cam->params.compressionParams.decimationHysteresis, + cam->params.compressionParams.frDiffStepThresh, + cam->params.compressionParams.qDiffStepThresh, + cam->params.compressionParams.decimationThreshMod); + + if (cam->cmd_queue & COMMAND_SETEXPOSURE) + do_command_extended(cam, CPIA_COMMAND_SetExposure, + cam->params.exposure.gainMode, + cam->params.exposure.expMode, + cam->params.exposure.compMode, + cam->params.exposure.centreWeight, + cam->params.exposure.gain, + cam->params.exposure.fineExp, + cam->params.exposure.coarseExpLo, + cam->params.exposure.coarseExpHi, + cam->params.exposure.redComp, + cam->params.exposure.green1Comp, + cam->params.exposure.green2Comp, + cam->params.exposure.blueComp); + + if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) { + if (cam->params.colourBalance.balanceModeIsAuto) { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 2, 0, 0, 0); + } else { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 1, + cam->params.colourBalance.redGain, + cam->params.colourBalance.greenGain, + cam->params.colourBalance.blueGain); + do_command(cam, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); + } + } + + if (cam->cmd_queue & COMMAND_SETSENSORFPS) + do_command(cam, CPIA_COMMAND_SetSensorFPS, + cam->params.sensorFps.divisor, + cam->params.sensorFps.baserate, 0, 0); + + if (cam->cmd_queue & COMMAND_SETAPCOR) + do_command(cam, CPIA_COMMAND_SetApcor, + cam->params.apcor.gain1, + cam->params.apcor.gain2, + cam->params.apcor.gain4, + cam->params.apcor.gain8); + + if (cam->cmd_queue & COMMAND_SETFLICKERCTRL) + do_command(cam, CPIA_COMMAND_SetFlickerCtrl, + cam->params.flickerControl.flickerMode, + cam->params.flickerControl.coarseJump, + cam->params.flickerControl.allowableOverExposure, 0); + + if (cam->cmd_queue & COMMAND_SETVLOFFSET) + do_command(cam, CPIA_COMMAND_SetVLOffset, + cam->params.vlOffset.gain1, + cam->params.vlOffset.gain2, + cam->params.vlOffset.gain4, + cam->params.vlOffset.gain8); + + if (cam->cmd_queue & COMMAND_PAUSE) + do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); + + if (cam->cmd_queue & COMMAND_RESUME) + init_stream_cap(cam); + + up(&cam->param_lock); + cam->cmd_queue = COMMAND_NONE; + return; +} + +/* kernel thread function to read image from camera */ +static void fetch_frame(void *data) +{ + int image_size, retry; + struct cam_data *cam = (struct cam_data *)data; + unsigned long oldjif, rate, diff; + + /* Allow up to two bad images in a row to be read and + * ignored before an error is reported */ + for (retry = 0; retry < 3; ++retry) { + if (retry) + DBG("retry=%d\n", retry); + + if (!cam->ops) + continue; + + /* load first frame always uncompressed */ + if (cam->first_frame && + cam->params.compression.mode != CPIA_COMPRESSION_NONE) + do_command(cam, CPIA_COMMAND_SetCompression, + CPIA_COMPRESSION_NONE, + NO_DECIMATION, 0, 0); + + /* init camera upload */ + if (do_command(cam, CPIA_COMMAND_SetGrabMode, + CPIA_GRAB_CONTINUOUS, 0, 0, 0)) + continue; + + if (do_command(cam, CPIA_COMMAND_GrabFrame, 0, + cam->params.streamStartLine, 0, 0)) + continue; + + if (cam->ops->wait_for_stream_ready) { + /* loop until image ready */ + do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0); + while (cam->params.status.streamState != STREAM_READY) { + if (current->need_resched) + schedule(); + + current->state = TASK_INTERRUPTIBLE; + + /* sleep for 10 ms, hopefully ;) */ + schedule_timeout(10*HZ/1000); + if (signal_pending(current)) + return; + + do_command(cam, CPIA_COMMAND_GetCameraStatus, + 0, 0, 0, 0); + } + } + + /* grab image from camera */ + if (current->need_resched) + schedule(); + + oldjif = jiffies; + image_size = cam->ops->streamRead(cam->lowlevel_data, + cam->raw_image, 0); + if (image_size <= 0) { + DBG("streamRead failed: %d\n", image_size); + continue; + } + + rate = image_size * HZ / 1024; + diff = jiffies-oldjif; + cam->transfer_rate = diff==0 ? rate : rate/diff; + /* diff==0 ? unlikely but possible */ + + /* camera idle now so dispatch queued commands */ + dispatch_commands(cam); + + /* Update our knowledge of the camera state - FIXME: necessary? */ + do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + + /* decompress and convert image to by copying it from + * raw_image to decompressed_frame + */ + if (current->need_resched) + schedule(); + + cam->image_size = parse_picture(cam, image_size); + if (cam->image_size <= 0) + DBG("parse_picture failed %d\n", cam->image_size); + else + break; + } + + if (retry < 3) { + /* FIXME: this only works for double buffering */ + if (cam->frame[cam->curframe].state == FRAME_READY) { + memcpy(cam->frame[cam->curframe].data, + cam->decompressed_frame.data, + cam->decompressed_frame.count); + cam->frame[cam->curframe].state = FRAME_DONE; + } else + cam->decompressed_frame.state = FRAME_DONE; + +#if 0 + if (cam->first_frame && + cam->params.compression.mode != CPIA_COMPRESSION_NONE) { + cam->first_frame = 0; + cam->cmd_queue |= COMMAND_SETCOMPRESSION; + } +#else + if (cam->first_frame) { + cam->first_frame = 0; + cam->cmd_queue |= COMMAND_SETCOMPRESSION; + cam->cmd_queue |= COMMAND_SETEXPOSURE; + } +#endif + } +} + +static int capture_frame(struct cam_data *cam, struct video_mmap *vm) +{ + int retval = 0; + + if (!cam->frame_buf) { + /* we do lazy allocation */ + if ((retval = allocate_frame_buf(cam))) + return retval; + } + + /* FIXME: the first frame seems to be captured by the camera + without regards to any initial settings, so we throw away + that one, the next one is generated with our settings + (exposure, color balance, ...) + */ + if (cam->first_frame) { + cam->curframe = vm->frame; + cam->frame[cam->curframe].state = FRAME_READY; + fetch_frame(cam); + if (cam->frame[cam->curframe].state != FRAME_DONE) + retval = -EIO; + } + cam->curframe = vm->frame; + cam->frame[cam->curframe].state = FRAME_READY; + fetch_frame(cam); + if (cam->frame[cam->curframe].state != FRAME_DONE) + retval=-EIO; + + return retval; +} + +static int goto_high_power(struct cam_data *cam) +{ + if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0)) + return -1; + mdelay(100); /* windows driver does it too */ + if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) + return -1; + if (cam->params.status.systemState == HI_POWER_STATE) { + DBG("camera now in HIGH power state\n"); + return 0; + } + printstatus(cam); + return -1; +} + +static int goto_low_power(struct cam_data *cam) +{ + if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0)) + return -1; + if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) + return -1; + if (cam->params.status.systemState == LO_POWER_STATE) { + DBG("camera now in LOW power state\n"); + return 0; + } + printstatus(cam); + return -1; +} + +static void save_camera_state(struct cam_data *cam) +{ + do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + + DBG("%d/%d/%d/%d/%d/%d/%d/%d\n", + cam->params.exposure.gain, + cam->params.exposure.fineExp, + cam->params.exposure.coarseExpLo, + cam->params.exposure.coarseExpHi, + cam->params.exposure.redComp, + cam->params.exposure.green1Comp, + cam->params.exposure.green2Comp, + cam->params.exposure.blueComp); + DBG("%d/%d/%d\n", + cam->params.colourBalance.redGain, + cam->params.colourBalance.greenGain, + cam->params.colourBalance.blueGain); +} + +static void set_camera_state(struct cam_data *cam) +{ + if(cam->params.colourBalance.balanceModeIsAuto) { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 2, 0, 0, 0); + } else { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 1, + cam->params.colourBalance.redGain, + cam->params.colourBalance.greenGain, + cam->params.colourBalance.blueGain); + do_command(cam, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); + } + + + do_command_extended(cam, CPIA_COMMAND_SetExposure, + cam->params.exposure.gainMode, 1, 1, + cam->params.exposure.centreWeight, + cam->params.exposure.gain, + cam->params.exposure.fineExp, + cam->params.exposure.coarseExpLo, + cam->params.exposure.coarseExpHi, + cam->params.exposure.redComp, + cam->params.exposure.green1Comp, + cam->params.exposure.green2Comp, + cam->params.exposure.blueComp); + do_command_extended(cam, CPIA_COMMAND_SetExposure, + 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0); + + if (!cam->params.exposure.gainMode) + cam->params.exposure.gainMode = 2; + if (!cam->params.exposure.expMode) + cam->params.exposure.expMode = 2; + if (!cam->params.exposure.centreWeight) + cam->params.exposure.centreWeight = 1; + + cam->cmd_queue = COMMAND_SETCOMPRESSION | + COMMAND_SETCOMPRESSIONTARGET | + COMMAND_SETCOLOURPARAMS | + COMMAND_SETFORMAT | + COMMAND_SETYUVTHRESH | + COMMAND_SETECPTIMING | + COMMAND_SETCOMPRESSIONPARAMS | +#if 0 + COMMAND_SETEXPOSURE | +#endif + COMMAND_SETCOLOURBALANCE | + COMMAND_SETSENSORFPS | + COMMAND_SETAPCOR | + COMMAND_SETFLICKERCTRL | + COMMAND_SETVLOFFSET; + dispatch_commands(cam); + save_camera_state(cam); + + return; +} + +static void get_version_information(struct cam_data *cam) +{ + /* GetCPIAVersion */ + do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0); + + /* GetPnPID */ + do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0); +} + +/* initialize camera */ +static int reset_camera(struct cam_data *cam) +{ + /* Start the camera in low power mode */ + if (goto_low_power(cam)) { + if (cam->params.status.systemState != WARM_BOOT_STATE) + return -ENODEV; + + /* FIXME: this is just dirty trial and error */ + reset_camera_struct(cam); + goto_high_power(cam); + do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); + if (goto_low_power(cam)) + return -NODEV; + } + + /* procedure described in developer's guide p3-28 */ + + /* Check the firmware version FIXME: should we check PNPID? */ + cam->params.version.firmwareVersion = 0; + get_version_information(cam); + if (cam->params.version.firmwareVersion != 1) + return -ENODEV; + + /* The fatal error checking should be done after + * the camera powers up (developer's guide p 3-38) */ + + /* Set streamState before transition to high power to avoid bug + * in firmware 1-02 */ + do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0, + STREAM_NOT_READY, 0); + + /* GotoHiPower */ + if (goto_high_power(cam)) + return -ENODEV; + + /* Check the camera status */ + if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) + return -EIO; + + if (cam->params.status.fatalError) { + DBG("fatal_error: %#04x\n", + cam->params.status.fatalError); + DBG("vp_status: %#04x\n", + cam->params.status.vpStatus); + if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) { + /* Fatal error in camera */ + return -EIO; + } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) { + /* Firmware 1-02 may do this for parallel port cameras, + * just clear the flags (developer's guide p 3-38) */ + do_command(cam, CPIA_COMMAND_ModifyCameraStatus, + FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0); + } + } + + /* Check the camera status again */ + if (cam->params.status.fatalError) { + if (cam->params.status.fatalError) + return -EIO; + } + + /* VPVersion can't be retrieved before the camera is in HiPower, + * so get it here instead of in get_version_information. */ + do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); + + /* set camera to a known state */ + set_camera_state(cam); + + return 0; +} + +/* ------------------------- V4L interface --------------------- */ +static int cpia_open(struct video_device *dev, int flags) +{ + int i; + struct cam_data *cam = dev->priv; + + if (!cam) { + DBG("Internal error, cam_data not found!\n"); + return -EBUSY; + } + + if (cam->open_count > 0) { + DBG("Camera already open\n"); + return -EBUSY; + } + + if (!cam->raw_image) { + cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE); + if (!cam->raw_image) + return -ENOMEM; + } + + if (!cam->decompressed_frame.data) { + cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE); + if (!cam->decompressed_frame.data) { + rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); + cam->raw_image = NULL; + return -ENOMEM; + } + } + + /* open cpia */ + if (cam->ops->open(cam->lowlevel_data)) { + rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); + cam->decompressed_frame.data = NULL; + rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); + cam->raw_image = NULL; + return -ENODEV; + } + + /* reset the camera */ + if ((i = reset_camera(cam)) != 0) { + cam->ops->close(cam->lowlevel_data); + rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); + cam->decompressed_frame.data = NULL; + rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); + cam->raw_image = NULL; + return i; + } + + /* Set ownership of /proc/cpia/videoX to current user */ + if(cam->proc_entry) + cam->proc_entry->uid = current->uid; + + /* set mark for loading first frame uncompressed */ + cam->first_frame = 1; + + /* init it to something */ + cam->mmap_kludge = 0; + + ++cam->open_count; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +static void cpia_close(struct video_device *dev) +{ + struct cam_data *cam; + + cam = dev->priv; + + if (cam->ops) { + /* Return ownership of /proc/cpia/videoX to root */ + if(cam->proc_entry) + cam->proc_entry->uid = 0; + + /* save camera state for later open (developers guide ch 3.5.3) */ + save_camera_state(cam); + + /* GotoLoPower */ + goto_low_power(cam); + + /* Update the camera ststus */ + do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + + /* cleanup internal state stuff */ + free_frames(cam->frame); + + /* close cpia */ + cam->ops->close(cam->lowlevel_data); + } + + if (--cam->open_count == 0) { + /* clean up capture-buffers */ + if (cam->raw_image) { + rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); + cam->raw_image = NULL; + } + + if (cam->decompressed_frame.data) { + rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); + cam->decompressed_frame.data = NULL; + } + + if (cam->frame_buf) + free_frame_buf(cam); + + if (!cam->ops) { + video_unregister_device(dev); + kfree(cam); + } + } + + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return; +} + +static long cpia_read(struct video_device *dev, char *buf, + unsigned long count, int noblock) +{ + struct cam_data *cam = dev->priv; + + /* make this _really_ smp and multithredi-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + if (!buf) { + DBG("buf NULL\n"); + up(&cam->busy_lock); + return -EINVAL; + } + + if (!count) { + DBG("count 0\n"); + up(&cam->busy_lock); + return 0; + } + + if (!cam->ops) { + DBG("ops NULL\n"); + up(&cam->busy_lock); + return -ENODEV; + } + + /* upload frame */ + cam->decompressed_frame.state = FRAME_READY; + cam->mmap_kludge=0; + fetch_frame(cam); + if (cam->decompressed_frame.state != FRAME_DONE) { + DBG("upload failed %d/%d\n", cam->decompressed_frame.count, + cam->decompressed_frame.state); + up(&cam->busy_lock); + return -EIO; + } + cam->decompressed_frame.state = FRAME_UNUSED; + + /* copy data to user space */ + if (cam->decompressed_frame.count > count) { + DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count, + count); + up(&cam->busy_lock); + return -EFAULT; + } + if (copy_to_user(buf, cam->decompressed_frame.data, + cam->decompressed_frame.count)) { + DBG("copy_to_user failed\n"); + up(&cam->busy_lock); + return -EFAULT; + } + + up(&cam->busy_lock); + return cam->decompressed_frame.count; +} + +static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg) +{ + struct cam_data *cam = dev->priv; + int retval = 0; + + if (!cam || !cam->ops) + return -ENODEV; + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + //DBG("cpia_ioctl: %u\n", ioctlnr); + + switch (ioctlnr) { + /* query capabilites */ + case VIDIOCGCAP: + { + struct video_capability b; + + DBG("VIDIOCGCAP\n"); + strcpy(b.name, "CPiA Camera"); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = 352; /* VIDEOSIZE_CIF */ + b.maxheight = 288; + b.minwidth = 48; /* VIDEOSIZE_48_48 */ + b.minheight = 48; + + if (copy_to_user(arg, &b, sizeof(b))) + retval = -EFAULT; + + break; + } + + /* get/set video source - we are a camera and nothing else */ + case VIDIOCGCHAN: + { + struct video_channel v; + + DBG("VIDIOCGCHAN\n"); + if (copy_from_user(&v, arg, sizeof(v))) { + retval = -EFAULT; + break; + } + if (v.channel != 0) { + retval = -EINVAL; + break; + } + + v.channel = 0; + strcpy(v.name, "Camera"); + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = 0; + + if (copy_to_user(arg, &v, sizeof(v))) + retval = -EFAULT; + break; + } + + case VIDIOCSCHAN: + { + int v; + + DBG("VIDIOCSCHAN\n"); + if (copy_from_user(&v, arg, sizeof(v))) + retval = -EFAULT; + + if (retval == 0 && v != 0) + retval = -EINVAL; + + break; + } + + /* image properties */ + case VIDIOCGPICT: + DBG("VIDIOCGPICT\n"); + if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture))) + retval = -EFAULT; + break; + + case VIDIOCSPICT: + { + struct video_picture vp; + + DBG("VIDIOCSPICT\n"); + + /* copy_from_user */ + if (copy_from_user(&vp, arg, sizeof(vp))) { + retval = -EFAULT; + break; + } + + /* check validity */ + DBG("palette: %d\n", vp.palette); + DBG("depth: %d\n", vp.depth); + if (!valid_mode(vp.palette, vp.depth)) { + retval = -EINVAL; + break; + } + + down(&cam->param_lock); + /* brightness, colour, contrast need no check 0-65535 */ + memcpy( &cam->vp, &vp, sizeof(vp) ); + /* update cam->params.colourParams */ + cam->params.colourParams.brightness = vp.brightness*100/65535; + cam->params.colourParams.contrast = vp.contrast*100/65535; + cam->params.colourParams.saturation = vp.colour*100/65535; + /* contrast is in steps of 8, so round */ + cam->params.colourParams.contrast = + ((cam->params.colourParams.contrast + 3) / 8) * 8; + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2 && + cam->params.colourParams.contrast > 80) { + /* 1-02 firmware limits contrast to 80 */ + cam->params.colourParams.contrast = 80; + } + + /* queue command to update camera */ + cam->cmd_queue |= COMMAND_SETCOLOURPARAMS; + up(&cam->param_lock); + DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n", + vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour, + vp.contrast); + break; + } + + /* get/set capture window */ + case VIDIOCGWIN: + DBG("VIDIOCGWIN\n"); + + if (copy_to_user(arg, &cam->vw, sizeof(struct video_window))) + retval = -EFAULT; + break; + + case VIDIOCSWIN: + { + /* copy_from_user, check validity, copy to internal structure */ + struct video_window vw; + DBG("VIDIOCSWIN\n"); + if (copy_from_user(&vw, arg, sizeof(vw))) { + retval = -EFAULT; + break; + } + + if (vw.clipcount != 0) { /* clipping not supported */ + retval = -EINVAL; + break; + } + if (vw.clips != NULL) { /* clipping not supported */ + retval = -EINVAL; + break; + } + + /* we set the video window to something smaller or equal to what + * is requested by the user??? + */ + down(&cam->param_lock); + if (vw.width != cam->vw.width || vw.height != cam->vw.height) { + int video_size = match_videosize(vw.width, vw.height); + + if (video_size < 0) { + retval = -EINVAL; + up(&cam->param_lock); + break; + } + cam->video_size = video_size; + set_vw_size(cam); + DBG("%d / %d\n", cam->vw.width, cam->vw.height); + cam->cmd_queue |= COMMAND_SETFORMAT; + } + + // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw)); + up(&cam->param_lock); + + /* setformat ignored by camera during streaming, + * so stop/dispatch/start */ + if (cam->cmd_queue & COMMAND_SETFORMAT) { + DBG("\n"); + dispatch_commands(cam); + } + DBG("%d/%d:%d\n", cam->video_size, + cam->vw.width, cam->vw.height); + break; + } + + /* mmap interface */ + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + DBG("VIDIOCGMBUF\n"); + memset(&vm, 0, sizeof(vm)); + vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM; + vm.frames = FRAME_NUM; + for (i = 0; i < FRAME_NUM; i++) + vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + retval = -EFAULT; + + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + int video_size; + + if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) { + retval = -EFAULT; + break; + } +#if 1 + DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame, + vm.width, vm.height); +#endif + if (vm.frame<0||vm.frame>FRAME_NUM) { + retval = -EINVAL; + break; + } + + /* set video format */ + cam->vp.palette = vm.format; + switch(vm.format) { + case VIDEO_PALETTE_GREY: + case VIDEO_PALETTE_RGB555: + case VIDEO_PALETTE_RGB565: + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_UYVY: + cam->vp.depth = 16; + break; + case VIDEO_PALETTE_RGB24: + cam->vp.depth = 24; + break; + case VIDEO_PALETTE_RGB32: + cam->vp.depth = 32; + break; + default: + retval = -EINVAL; + break; + } + if (retval) + break; + + /* set video size */ + video_size = match_videosize(vm.width, vm.height); + if (cam->video_size < 0) { + retval = -EINVAL; + break; + } + if (video_size != cam->video_size) { + cam->video_size = video_size; + set_vw_size(cam); + cam->cmd_queue |= COMMAND_SETFORMAT; + dispatch_commands(cam); + } +#if 0 + DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size, + cam->vw.width, cam->vw.height); +#endif + /* according to v4l-spec we must start streaming here */ + cam->mmap_kludge = 1; + retval = capture_frame(cam, &vm); + + break; + } + + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *)&frame, arg, sizeof(int))) { + retval = -EFAULT; + break; + } + //DBG("VIDIOCSYNC: %d\n", frame); + + if (frame<0 || frame >= FRAME_NUM) { + retval = -EINVAL; + break; + } + + switch (cam->frame[frame].state) { + case FRAME_UNUSED: + case FRAME_READY: + case FRAME_GRABBING: + DBG("sync to unused frame %d\n", frame); + retval = -EINVAL; + break; + + case FRAME_DONE: + cam->frame[frame].state = FRAME_UNUSED; + //DBG("VIDIOCSYNC: %d synced\n", frame); + break; + } + if (retval == -EINTR) { + /* FIXME - xawtv does not handle this nice */ + retval = 0; + } + break; + } + + /* pointless to implement overlay with this camera */ + case VIDIOCCAPTURE: + retval = -EINVAL; + break; + case VIDIOCGFBUF: + retval = -EINVAL; + break; + case VIDIOCSFBUF: + retval = -EINVAL; + break; + case VIDIOCKEY: + retval = -EINVAL; + break; + + /* tuner interface - we have none */ + case VIDIOCGTUNER: + retval = -EINVAL; + break; + case VIDIOCSTUNER: + retval = -EINVAL; + break; + case VIDIOCGFREQ: + retval = -EINVAL; + break; + case VIDIOCSFREQ: + retval = -EINVAL; + break; + + /* audio interface - we have none */ + case VIDIOCGAUDIO: + retval = -EINVAL; + break; + case VIDIOCSAUDIO: + retval = -EINVAL; + break; + default: + retval = -ENOIOCTLCMD; + break; + } + + up(&cam->param_lock); + up(&cam->busy_lock); + return retval; +} + +/* FIXME */ +static int cpia_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + struct cam_data *cam = dev->priv; + int retval; + + if (!cam || !cam->ops) + return -ENODEV; + + DBG("cpia_mmap: %ld\n", size); + + if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE) + return -EINVAL; + + if (!cam || !cam->ops) + return -ENODEV; + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + if (!cam->frame_buf) { /* we do lazy allocation */ + if ((retval = allocate_frame_buf(cam))) { + up(&cam->busy_lock); + return retval; + } + } + + pos = (unsigned long)(cam->frame_buf); + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + up(&cam->busy_lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + DBG("cpia_mmap: %ld\n", size); + up(&cam->busy_lock); + + return 0; +} + +int cpia_video_init(struct video_device *vdev) +{ +#ifdef CONFIG_PROC_FS + create_proc_cpia_cam(vdev->priv); +#endif + return 0; +} + +static struct video_device cpia_template = { + "CPiA Camera", + VID_TYPE_CAPTURE, + VID_HARDWARE_CPIA, /* FIXME */ + cpia_open, /* open */ + cpia_close, /* close */ + cpia_read, /* read */ + NULL, /* no write */ + NULL, /* no poll */ + cpia_ioctl, /* ioctl */ + cpia_mmap, /* mmap */ + cpia_video_init, /* initialize */ + NULL, /* priv */ + 0, /* busy */ + -1 /* minor - unset */ +}; + +/* initialise cam_data structure */ +static void reset_camera_struct(struct cam_data *cam) +{ + /* The following parameter values are the defaults from + * "Software Developer's Guide for CPiA Cameras". Any changes + * to the defaults are noted in comments. */ + cam->params.colourParams.brightness = 50; + cam->params.colourParams.contrast = 48; + cam->params.colourParams.saturation = 50; + cam->params.exposure.gainMode = 2; + cam->params.exposure.expMode = 2; /* AEC */ + cam->params.exposure.compMode = 1; + cam->params.exposure.centreWeight = 1; + cam->params.exposure.gain = 0; + cam->params.exposure.fineExp = 0; + cam->params.exposure.coarseExpLo = 185; + cam->params.exposure.coarseExpHi = 0; + cam->params.exposure.redComp = 220; + cam->params.exposure.green1Comp = 214; + cam->params.exposure.green2Comp = 214; + cam->params.exposure.blueComp = 230; + cam->params.colourBalance.balanceModeIsAuto = 1; + cam->params.colourBalance.redGain = 32; + cam->params.colourBalance.greenGain = 6; + cam->params.colourBalance.blueGain = 92; + cam->params.apcor.gain1 = 0x1c; + cam->params.apcor.gain2 = 0x1a; + cam->params.apcor.gain4 = 0x2d; + cam->params.apcor.gain8 = 0x2a; + cam->params.flickerControl.flickerMode = 0; + cam->params.flickerControl.coarseJump = + flicker_jumps[cam->mainsFreq] + [cam->params.sensorFps.baserate] + [cam->params.sensorFps.divisor]; + cam->params.vlOffset.gain1 = 24; + cam->params.vlOffset.gain2 = 28; + cam->params.vlOffset.gain4 = 30; + cam->params.vlOffset.gain8 = 30; + cam->params.compressionParams.hysteresis = 3; + cam->params.compressionParams.threshMax = 11; + cam->params.compressionParams.smallStep = 1; + cam->params.compressionParams.largeStep = 3; + cam->params.compressionParams.decimationHysteresis = 2; + cam->params.compressionParams.frDiffStepThresh = 5; + cam->params.compressionParams.qDiffStepThresh = 3; + cam->params.compressionParams.decimationThreshMod = 2; + /* End of default values from Software Developer's Guide */ + + cam->transfer_rate = 0; + + /* Set Sensor FPS to 15fps. This seems better than 30fps + * for indoor lighting. */ + cam->params.sensorFps.divisor = 1; + cam->params.sensorFps.baserate = 1; + + cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */ + cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */ + + cam->params.format.subSample = SUBSAMPLE_422; + cam->params.format.yuvOrder = YUVORDER_YUYV; + + cam->params.compression.mode = CPIA_COMPRESSION_AUTO; + cam->params.compressionTarget.frTargeting = + CPIA_COMPRESSION_TARGET_QUALITY; + cam->params.compressionTarget.targetFR = 7; /* FIXME? */ + cam->params.compressionTarget.targetQ = 10; /* FIXME? */ + + cam->video_size = VIDEOSIZE_CIF; + + cam->vp.colour = 32768; /* 50% */ + cam->vp.hue = 32768; /* 50% */ + cam->vp.brightness = 32768; /* 50% */ + cam->vp.contrast = 32768; /* 50% */ + cam->vp.whiteness = 0; /* not used -> grayscale only */ + cam->vp.depth = 0; /* FIXME: to be set by user? */ + cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */ + + cam->vw.x = 0; + cam->vw.y = 0; + set_vw_size(cam); + cam->vw.chromakey = 0; + /* PP NOTE: my extension to use vw.flags for this, bear it! */ + cam->vw.flags = 0; + cam->vw.clipcount = 0; + cam->vw.clips = NULL; + + cam->cmd_queue = COMMAND_NONE; + cam->first_frame = 0; + + return; +} + +/* initialize cam_data structure */ +static void init_camera_struct(struct cam_data *cam, + struct cpia_camera_ops *ops ) +{ + int i; + + /* Default everything to 0 */ + memset(cam, 0, sizeof(struct cam_data)); + + cam->ops = ops; + init_MUTEX(&cam->param_lock); + init_MUTEX(&cam->busy_lock); + + reset_camera_struct(cam); + + cam->proc_entry = NULL; + + memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template)); + cam->vdev.priv = cam; + + cam->curframe = 0; + for (i = 0; i < FRAME_NUM; i++) { + cam->frame[i].width = 0; + cam->frame[i].height = 0; + cam->frame[i].state = FRAME_UNUSED; + cam->frame[i].data = NULL; + } + cam->decompressed_frame.width = 0; + cam->decompressed_frame.height = 0; + cam->decompressed_frame.state = FRAME_UNUSED; + cam->decompressed_frame.data = NULL; +} + +struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel) +{ + struct cam_data *camera; + + /* Need a lock when adding/removing cameras. This doesn't happen + * often and doesn't take very long, so grabbing the kernel lock + * should be OK. */ + + if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) { + unlock_kernel(); + return NULL; + } + + init_camera_struct( camera, ops ); + camera->lowlevel_data = lowlevel; + + /* register v4l device */ + if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) { + kfree(camera); + unlock_kernel(); + printk(KERN_DEBUG "video_register_device failed\n"); + return NULL; + } + + /* get version information from camera: open/reset/close */ + + /* open cpia */ + if (camera->ops->open(camera->lowlevel_data)) + return camera; + + /* reset the camera */ + if (reset_camera(camera) != 0) { + camera->ops->close(camera->lowlevel_data); + return camera; + } + + /* close cpia */ + camera->ops->close(camera->lowlevel_data); + +/* Eh? Feeling happy? - jerdfelt */ +/* + camera->ops->open(camera->lowlevel_data); + camera->ops->close(camera->lowlevel_data); +*/ + + printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n", + camera->params.version.firmwareVersion, + camera->params.version.firmwareRevision, + camera->params.version.vcVersion, + camera->params.version.vcRevision); + printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n", + camera->params.pnpID.vendor, + camera->params.pnpID.product, + camera->params.pnpID.deviceRevision); + printk(KERN_INFO " VP-Version: %d.%d %04x\n", + camera->params.vpVersion.vpVersion, + camera->params.vpVersion.vpRevision, + camera->params.vpVersion.cameraHeadID); + + return camera; +} + +void cpia_unregister_camera(struct cam_data *cam) +{ + if (!cam->open_count) { + DBG("unregistering video\n"); + video_unregister_device(&cam->vdev); + } else { + LOG("/dev/video%d removed while open, " + "deferring video_unregister_device\n", cam->vdev.minor); + DBG("camera open -- setting ops to NULL\n"); + cam->ops = NULL; + } + +#ifdef CONFIG_PROC_FS + DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor); + destroy_proc_cpia_cam(cam); +#endif + if (!cam->open_count) { + DBG("freeing camera\n"); + kfree(cam); + } +} + +/**************************************************************************** + * + * Module routines + * + ***************************************************************************/ + +#ifdef MODULE +int init_module(void) +{ + printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, + CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); +#ifdef CONFIG_PROC_FS + proc_cpia_create(); +#endif +#ifdef CONFIG_KMOD +#ifdef CONFIG_VIDEO_CPIA_PP_MODULE + request_module("cpia_pp"); +#endif +#ifdef CONFIG_VIDEO_CPIA_USB_MODULE + request_module("cpia_usb"); +#endif +#endif +return 0; +} + +void cleanup_module(void) +{ +#ifdef CONFIG_PROC_FS + proc_cpia_destroy(); +#endif +} + +#else + +int cpia_init(struct video_init *unused) +{ + printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, + CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); +#ifdef CONFIG_PROC_FS + proc_cpia_create(); +#endif + +#ifdef CONFIG_VIDEO_CPIA_PP + cpia_pp_init(); +#endif +#ifdef CONFIG_KMOD +#ifdef CONFIG_VIDEO_CPIA_PP_MODULE + request_module("cpia_pp"); +#endif + +#ifdef CONFIG_VIDEO_CPIA_USB_MODULE + request_module("cpia_usb"); +#endif +#endif /* CONFIG_KMOD */ +#ifdef CONFIG_VIDEO_CPIA_USB + cpia_usb_init(); +#endif + return 0; +} + +/* Exported symbols for modules. */ + +EXPORT_SYMBOL(cpia_register_camera); +EXPORT_SYMBOL(cpia_unregister_camera); + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/cpia.h linux/drivers/media/video/cpia.h --- v2.4.0-test6/linux/drivers/media/video/cpia.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/cpia.h Mon Mar 27 10:22:31 2000 @@ -0,0 +1,421 @@ +#ifndef cpia_h +#define cpia_h + +/* + * CPiA Parallel Port Video4Linux driver + * + * Supports CPiA based parallel port Video Camera's. + * + * (C) Copyright 1999 Bas Huisman, + * Peter Pregler, + * Scott J. Bertin, + * VLSI Vision Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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. + */ + +#define CPIA_MAJ_VER 0 +#define CPIA_MIN_VER 7 +#define CPIA_PATCH_VER 4 + +#define CPIA_PP_MAJ_VER 0 +#define CPIA_PP_MIN_VER 7 +#define CPIA_PP_PATCH_VER 4 + +#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */ +#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */ + +#ifdef __KERNEL__ + +#include +#include +#include + +struct cpia_camera_ops +{ + /* open sets privdata to point to structure for this camera. + * Returns negative value on error, otherwise 0. + */ + int (*open)(void *privdata); + + /* Registers callback function cb to be called with cbdata + * when an image is ready. If cb is NULL, only single image grabs + * should be used. cb should immediately call streamRead to read + * the data or data may be lost. Returns negative value on error, + * otherwise 0. + */ + int (*registerCallback)(void *privdata, void (*cb)(void *cbdata), + void *cbdata); + + /* transferCmd sends commands to the camera. command MUST point to + * an 8 byte buffer in kernel space. data can be NULL if no extra + * data is needed. The size of the data is given by the last 2 + * bytes of comand. data must also point to memory in kernel space. + * Returns negative value on error, otherwise 0. + */ + int (*transferCmd)(void *privdata, u8 *command, u8 *data); + + /* streamStart initiates stream capture mode. + * Returns negative value on error, otherwise 0. + */ + int (*streamStart)(void *privdata); + + /* streamStop terminates stream capture mode. + * Returns negative value on error, otherwise 0. + */ + int (*streamStop)(void *privdata); + + /* streamRead reads a frame from the camera. buffer points to a + * buffer large enough to hold a complete frame in kernel space. + * noblock indicates if this should be a non blocking read. + * Returns the number of bytes read, or negative value on error. + */ + int (*streamRead)(void *privdata, u8 *buffer, int noblock); + + /* close disables the device until open() is called again. + * Returns negative value on error, otherwise 0. + */ + int (*close)(void *privdata); + + /* If wait_for_stream_ready is non-zero, wait until the streamState + * is STREAM_READY before calling streamRead. + */ + int wait_for_stream_ready; +}; + +struct cpia_frame { + u8 *data; + int count; + int width; + int height; + volatile int state; +}; + +struct cam_params { + struct { + u8 firmwareVersion; + u8 firmwareRevision; + u8 vcVersion; + u8 vcRevision; + } version; + struct { + u16 vendor; + u16 product; + u16 deviceRevision; + } pnpID; + struct { + u8 vpVersion; + u8 vpRevision; + u16 cameraHeadID; + } vpVersion; + struct { + u8 systemState; + u8 grabState; + u8 streamState; + u8 fatalError; + u8 cmdError; + u8 debugFlags; + u8 vpStatus; + u8 errorCode; + } status; + struct { + u8 brightness; + u8 contrast; + u8 saturation; + } colourParams; + struct { + u8 gainMode; + u8 expMode; + u8 compMode; + u8 centreWeight; + u8 gain; + u8 fineExp; + u8 coarseExpLo; + u8 coarseExpHi; + u8 redComp; + u8 green1Comp; + u8 green2Comp; + u8 blueComp; + } exposure; + struct { + u8 balanceModeIsAuto; + u8 redGain; + u8 greenGain; + u8 blueGain; + } colourBalance; + struct { + u8 divisor; + u8 baserate; + } sensorFps; + struct { + u8 gain1; + u8 gain2; + u8 gain4; + u8 gain8; + } apcor; + struct { + u8 flickerMode; + u8 coarseJump; + u8 allowableOverExposure; + } flickerControl; + struct { + u8 gain1; + u8 gain2; + u8 gain4; + u8 gain8; + } vlOffset; + struct { + u8 mode; + u8 decimation; + } compression; + struct { + u8 frTargeting; + u8 targetFR; + u8 targetQ; + } compressionTarget; + struct { + u8 yThreshold; + u8 uvThreshold; + } yuvThreshold; + struct { + u8 hysteresis; + u8 threshMax; + u8 smallStep; + u8 largeStep; + u8 decimationHysteresis; + u8 frDiffStepThresh; + u8 qDiffStepThresh; + u8 decimationThreshMod; + } compressionParams; + struct { + u8 videoSize; /* CIF/QCIF */ + u8 subSample; + u8 yuvOrder; + } format; + struct { + u8 colStart; /* skip first 8*colStart pixels */ + u8 colEnd; /* finish at 8*colEnd pixels */ + u8 rowStart; /* skip first 4*rowStart lines */ + u8 rowEnd; /* finish at 4*rowEnd lines */ + } roi; + u8 ecpTiming; + u8 streamStartLine; +}; + +enum v4l_camstates { + CPIA_V4L_IDLE = 0, + CPIA_V4L_ERROR, + CPIA_V4L_COMMAND, + CPIA_V4L_GRABBING, + CPIA_V4L_STREAMING, + CPIA_V4L_STREAMING_PAUSED, +}; + +#define FRAME_NUM 2 /* double buffering for now */ + +struct cam_data { + struct cam_data **previous; + struct cam_data *next; + + struct semaphore busy_lock; /* guard against SMP multithreading */ + struct cpia_camera_ops *ops; /* lowlevel driver operations */ + void *lowlevel_data; /* private data for lowlevel driver */ + u8 *raw_image; /* buffer for raw image data */ + struct cpia_frame decompressed_frame; + /* buffer to hold decompressed frame */ + int image_size; /* sizeof last decompressed image */ + int open_count; /* # of process that have camera open */ + + /* camera status */ + int fps; /* actual fps reported by the camera */ + int transfer_rate; /* transfer rate from camera in kB/s */ + u8 mainsFreq; /* for flicker control */ + + /* proc interface */ + struct semaphore param_lock; /* params lock for this camera */ + struct cam_params params; /* camera settings */ + struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */ + + /* v4l */ + int video_size; /* VIDEO_SIZE_ */ + volatile enum v4l_camstates camstate; /* v4l layer status */ + struct video_device vdev; /* v4l videodev */ + struct video_picture vp; /* v4l camera settings */ + struct video_window vw; /* v4l capture area */ + + /* mmap interface */ + int curframe; /* the current frame to grab into */ + u8 *frame_buf; /* frame buffer data */ + struct cpia_frame frame[FRAME_NUM]; + /* FRAME_NUM-buffering, so we need a array */ + + int first_frame; + int mmap_kludge; /* 'wrong' byte order for mmap */ + volatile u32 cmd_queue; /* queued commands */ +}; + +/* cpia_register_camera is called by low level driver for each camera. + * A unique camera number is returned, or a negative value on error */ +struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel); + +/* cpia_unregister_camera is called by low level driver when a camera + * is removed. This must not fail. */ +void cpia_unregister_camera(struct cam_data *cam); + +/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI + + * one byte 16bit DMA alignment + */ +#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5) + +/* constant value's */ +#define MAGIC_0 0x19 +#define MAGIC_1 0x68 +#define DATA_IN 0xC0 +#define DATA_OUT 0x40 +#define VIDEOSIZE_QCIF 0 /* 176x144 */ +#define VIDEOSIZE_CIF 1 /* 352x288 */ +#define VIDEOSIZE_SIF 2 /* 320x240 */ +#define VIDEOSIZE_QSIF 3 /* 160x120 */ +#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */ +#define VIDEOSIZE_64_48 5 +#define VIDEOSIZE_128_96 6 +#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF +#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF +#define VIDEOSIZE_192_144 7 +#define VIDEOSIZE_224_168 8 +#define VIDEOSIZE_256_192 9 +#define VIDEOSIZE_288_216 10 +#define VIDEOSIZE_320_240 VIDEOSIZE_SIF +#define VIDEOSIZE_352_288 VIDEOSIZE_CIF +#define VIDEOSIZE_88_72 11 /* quarter CIF */ +#define SUBSAMPLE_420 0 +#define SUBSAMPLE_422 1 +#define YUVORDER_YUYV 0 +#define YUVORDER_UYVY 1 +#define NOT_COMPRESSED 0 +#define COMPRESSED 1 +#define NO_DECIMATION 0 +#define DECIMATION_ENAB 1 +#define EOI 0xff /* End Of Image */ +#define EOL 0xfd /* End Of Line */ +#define FRAME_HEADER_SIZE 64 + +/* Image grab modes */ +#define CPIA_GRAB_SINGLE 0 +#define CPIA_GRAB_CONTINUOUS 1 + +/* Compression parameters */ +#define CPIA_COMPRESSION_NONE 0 +#define CPIA_COMPRESSION_AUTO 1 +#define CPIA_COMPRESSION_MANUAL 2 +#define CPIA_COMPRESSION_TARGET_QUALITY 0 +#define CPIA_COMPRESSION_TARGET_FRAMERATE 1 + +/* Return offsets for GetCameraState */ +#define SYSTEMSTATE 0 +#define GRABSTATE 1 +#define STREAMSTATE 2 +#define FATALERROR 3 +#define CMDERROR 4 +#define DEBUGFLAGS 5 +#define VPSTATUS 6 +#define ERRORCODE 7 + +/* SystemState */ +#define UNINITIALISED_STATE 0 +#define PASS_THROUGH_STATE 1 +#define LO_POWER_STATE 2 +#define HI_POWER_STATE 3 +#define WARM_BOOT_STATE 4 + +/* GrabState */ +#define GRAB_IDLE 0 +#define GRAB_ACTIVE 1 +#define GRAB_DONE 2 + +/* StreamState */ +#define STREAM_NOT_READY 0 +#define STREAM_READY 1 +#define STREAM_OPEN 2 +#define STREAM_PAUSED 3 +#define STREAM_FINISHED 4 + +/* Fatal Error, CmdError, and DebugFlags */ +#define CPIA_FLAG 1 +#define SYSTEM_FLAG 2 +#define INT_CTRL_FLAG 4 +#define PROCESS_FLAG 8 +#define COM_FLAG 16 +#define VP_CTRL_FLAG 32 +#define CAPTURE_FLAG 64 +#define DEBUG_FLAG 128 + +/* VPStatus */ +#define VP_STATE_OK 0x00 + +#define VP_STATE_FAILED_VIDEOINIT 0x01 +#define VP_STATE_FAILED_AECACBINIT 0x02 +#define VP_STATE_AEC_MAX 0x04 +#define VP_STATE_ACB_BMAX 0x08 + +#define VP_STATE_ACB_RMIN 0x10 +#define VP_STATE_ACB_GMIN 0x20 +#define VP_STATE_ACB_RMAX 0x40 +#define VP_STATE_ACB_GMAX 0x80 + +/* ErrorCode */ +#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */ + +#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args) +#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args) + +#ifdef _CPIA_DEBUG_ +#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args) +#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args) +#else +#define DBG(fmn,args...) do {} while(0) +#endif + +#define DEB_BYTE(p)\ + DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\ + (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\ + (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0); + +#define ADD_TO_LIST(l, drv) \ + {\ + lock_kernel();\ + (drv)->next = l;\ + (drv)->previous = &(l);\ + (l) = drv;\ + unlock_kernel();\ + } while(0) + +#define REMOVE_FROM_LIST(drv) \ + {\ + if ((drv)->previous != NULL) {\ + lock_kernel();\ + if ((drv)->next != NULL)\ + (drv)->next->previous = (drv)->previous;\ + *((drv)->previous) = (drv)->next;\ + (drv)->previous = NULL;\ + (drv)->next = NULL;\ + unlock_kernel();\ + }\ + } while (0) + + +#endif /* __KERNEL__ */ + +#endif /* cpia_h */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c --- v2.4.0-test6/linux/drivers/media/video/cpia_pp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/cpia_pp.c Mon Mar 27 10:22:31 2000 @@ -0,0 +1,745 @@ +/* + * cpia_pp CPiA Parallel Port driver + * + * Supports CPiA based parallel port Video Camera's. + * + * (C) Copyright 1999 Bas Huisman + * (C) Copyright 1999-2000 Scott J. Bertin , + * (C) Copyright 1999-2000 Peter Pregler + * + * 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. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_KMOD +#include +#endif + +/* #define _CPIA_DEBUG_ define for verbose debug output */ +#include "cpia.h" + +static int cpia_pp_open(void *privdata); +static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata), + void *cbdata); +static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data); +static int cpia_pp_streamStart(void *privdata); +static int cpia_pp_streamStop(void *privdata); +static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock); +static int cpia_pp_close(void *privdata); + +#define ABOUT "Parallel port driver for Vision CPiA based cameras" + +/* IEEE 1284 Compatiblity Mode signal names */ +#define nStrobe PARPORT_CONTROL_STROBE /* inverted */ +#define nAutoFd PARPORT_CONTROL_AUTOFD /* inverted */ +#define nInit PARPORT_CONTROL_INIT +#define nSelectIn PARPORT_CONTROL_SELECT +#define IntrEnable PARPORT_CONTROL_INTEN /* normally zero for no IRQ */ +#define DirBit PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse */ + +#define nFault PARPORT_STATUS_ERROR +#define Select PARPORT_STATUS_SELECT +#define PError PARPORT_STATUS_PAPEROUT +#define nAck PARPORT_STATUS_ACK +#define Busy PARPORT_STATUS_BUSY /* inverted */ + +/* some more */ +#define HostClk nStrobe +#define HostAck nAutoFd +#define nReverseRequest nInit +#define Active_1284 nSelectIn +#define nPeriphRequest nFault +#define XFlag Select +#define nAckReverse PError +#define PeriphClk nAck +#define PeriphAck Busy + +/* these can be used to correct for the inversion on some bits */ +#define STATUS_INVERSION_MASK (Busy) +#define CONTROL_INVERSION_MASK (nStrobe|nAutoFd|nSelectIn) + +#define ECR_empty 0x01 +#define ECR_full 0x02 +#define ECR_serviceIntr 0x04 +#define ECR_dmaEn 0x08 +#define ECR_nErrIntrEn 0x10 + +#define ECR_mode_mask 0xE0 +#define ECR_SPP_mode 0x00 +#define ECR_PS2_mode 0x20 +#define ECR_FIFO_mode 0x40 +#define ECR_ECP_mode 0x60 + +#define ECP_FIFO_SIZE 16 +#define DMA_BUFFER_SIZE PAGE_SIZE + /* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */ +#define PARPORT_CHUNK_SIZE PAGE_SIZE/* >=2.3.x */ + /* we read this many bytes at once */ + +#define GetECRMasked(port,mask) (parport_read_econtrol(port) & (mask)) +#define GetStatus(port) ((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8)) +#define SetStatus(port,val) parport_write_status(port,(val)^STATUS_INVERSION_MASK) +#define GetControl(port) ((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f)) +#define SetControl(port,val) parport_write_control(port,(val)^CONTROL_INVERSION_MASK) + +#define GetStatusMasked(port,mask) (GetStatus(port) & (mask)) +#define GetControlMasked(port,mask) (GetControl(port) & (mask)) +#define SetControlMasked(port,mask) SetControl(port,GetControl(port) | (mask)); +#define ClearControlMasked(port,mask) SetControl(port,GetControl(port)&~(mask)); +#define FrobControlBit(port,mask,value) SetControl(port,(GetControl(port)&~(mask))|((value)&(mask))); + +#define PACKET_LENGTH 8 + +/* Magic numbers for defining port-device mappings */ +#define PPCPIA_PARPORT_UNSPEC -4 +#define PPCPIA_PARPORT_AUTO -3 +#define PPCPIA_PARPORT_OFF -2 +#define PPCPIA_PARPORT_NONE -1 + +#ifdef MODULE +static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; +static char *parport[PARPORT_MAX] = {NULL,}; + +MODULE_AUTHOR("B. Huisman & Peter Pregler "); +MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras"); +MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s"); +MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); +#else +static int parport_nr[PARPORT_MAX] __initdata = + {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; +static int parport_ptr = 0; +#endif + +struct pp_cam_entry { + struct pardevice *pdev; + struct parport *port; + struct tq_struct cb_task; + int open_count; + wait_queue_head_t wq_stream; + /* image state flags */ + int image_ready; /* we got an interrupt */ + int image_complete; /* we have seen 4 EOI */ + + int streaming; /* we are in streaming mode */ + int stream_irq; +}; + +static struct cpia_camera_ops cpia_pp_ops = +{ + cpia_pp_open, + cpia_pp_registerCallback, + cpia_pp_transferCmd, + cpia_pp_streamStart, + cpia_pp_streamStop, + cpia_pp_streamRead, + cpia_pp_close, + 1 +}; + +static struct cam_data *cam_list; + +#ifdef _CPIA_DEBUG_ +#define DEB_PORT(port) { \ +u8 controll = GetControl(port); \ +u8 statusss = GetStatus(port); \ +DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir %c\n",\ +((controll & nSelectIn) ? 'U' : 'D'), \ +((statusss & PError) ? 'U' : 'D'), \ +((controll & nAutoFd) ? 'U' : 'D'), \ +((controll & nStrobe) ? 'U' : 'D'), \ +((statusss & nAck) ? 'U' : 'D'), \ +((statusss & Busy) ? 'U' : 'D'), \ +((statusss & nFault) ? 'U' : 'D'), \ +((statusss & Select) ? 'U' : 'D'), \ +((controll & nInit) ? 'U' : 'D'), \ +((controll & DirBit) ? 'R' : 'F') \ +); } +#else +#define DEB_PORT(port) {} +#endif + +#define WHILE_OUT_TIMEOUT (HZ/10) +#define DMA_TIMEOUT 10*HZ + +/* FIXME */ +static void cpia_parport_enable_irq( struct parport *port ) { + parport_enable_irq(port); + mdelay(10); + return; +} + +static void cpia_parport_disable_irq( struct parport *port ) { + parport_disable_irq(port); + mdelay(10); + return; +} + +/**************************************************************************** + * + * EndTransferMode + * + ***************************************************************************/ +static void EndTransferMode(struct pp_cam_entry *cam) +{ + parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); +} + +/**************************************************************************** + * + * ForwardSetup + * + ***************************************************************************/ +static int ForwardSetup(struct pp_cam_entry *cam) +{ + int retry; + + /* After some commands the camera needs extra time before + * it will respond again, so we try up to 3 times */ + for(retry=0; retry<3; ++retry) { + if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) { + break; + } + } + if(retry == 3) { + DBG("Unable to negotiate ECP mode\n"); + return -1; + } + return 0; +} + +/**************************************************************************** + * + * ReverseSetup + * + ***************************************************************************/ +static int ReverseSetup(struct pp_cam_entry *cam, int extensibility) +{ + int retry; + int mode = IEEE1284_MODE_ECP; + if(extensibility) mode = 8|3|IEEE1284_EXT_LINK; + + /* After some commands the camera needs extra time before + * it will respond again, so we try up to 3 times */ + for(retry=0; retry<3; ++retry) { + if(!parport_negotiate(cam->port, mode)) { + break; + } + } + if(retry == 3) { + if(extensibility) + DBG("Unable to negotiate extensibility mode\n"); + else + DBG("Unable to negotiate ECP mode\n"); + return -1; + } + if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP; + return 0; +} + +/**************************************************************************** + * + * WritePacket + * + ***************************************************************************/ +static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size) +{ + int retval=0; + int size_written; + + if (packet == NULL) { + return -EINVAL; + } + if (ForwardSetup(cam)) { + DBG("Write failed in setup\n"); + return -EIO; + } + size_written = parport_write(cam->port, packet, size); + if(size_written != size) { + DBG("Write failed, wrote %d/%d\n", size_written, size); + retval = -EIO; + } + EndTransferMode(cam); + return retval; +} + +/**************************************************************************** + * + * ReadPacket + * + ***************************************************************************/ +static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size) +{ + int retval=0; + if (packet == NULL) { + return -EINVAL; + } + if (ReverseSetup(cam, 0)) { + return -EIO; + } + if(parport_read(cam->port, packet, size) != size) { + retval = -EIO; + } + EndTransferMode(cam); + return retval; +} + +/**************************************************************************** + * + * cpia_pp_streamStart + * + ***************************************************************************/ +static int cpia_pp_streamStart(void *privdata) +{ + struct pp_cam_entry *cam = privdata; + DBG("\n"); + cam->streaming=1; + cam->image_ready=0; + //if (ReverseSetup(cam,1)) return -EIO; + if(cam->stream_irq) cpia_parport_enable_irq(cam->port); + return 0; +} + +/**************************************************************************** + * + * cpia_pp_streamStop + * + ***************************************************************************/ +static int cpia_pp_streamStop(void *privdata) +{ + struct pp_cam_entry *cam = privdata; + + DBG("\n"); + cam->streaming=0; + cpia_parport_disable_irq(cam->port); + //EndTransferMode(cam); + + return 0; +} + +static int cpia_pp_read(struct parport *port, u8 *buffer, int len) +{ + int bytes_read, new_bytes; + for(bytes_read=0; bytes_readstreaming) DBG("%d / %d\n", cam->image_ready, noblock); + if( cam->stream_irq ) { + DBG("%d\n", cam->image_ready); + cam->image_ready--; + } + cam->image_complete=0; + if (0/*cam->streaming*/) { + if(!cam->image_ready) { + if(noblock) return -EWOULDBLOCK; + interruptible_sleep_on(&cam->wq_stream); + if( signal_pending(current) ) return -EINTR; + DBG("%d\n", cam->image_ready); + } + } else { + if (ReverseSetup(cam, 1)) { + DBG("unable to ReverseSetup\n"); + return -EIO; + } + } + endseen = 0; + block_size = PARPORT_CHUNK_SIZE; + while( !cam->image_complete ) { + if(current->need_resched) schedule(); + + new_bytes = cpia_pp_read(cam->port, buffer, block_size ); + if( new_bytes <= 0 ) { + break; + } + i=-1; + while(++iimage_complete=1; + break; + } + if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) { + block_size=CPIA_MAX_IMAGE_SIZE-read_bytes; + } + } + EndTransferMode(cam); + return cam->image_complete ? read_bytes : -EIO; +} + +/**************************************************************************** + * + * cpia_pp_transferCmd + * + ***************************************************************************/ +static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data) +{ + int err; + int retval=0; + int databytes; + struct pp_cam_entry *cam = privdata; + + if(cam == NULL) { + DBG("Internal driver error: cam is NULL\n"); + return -EINVAL; + } + if(command == NULL) { + DBG("Internal driver error: command is NULL\n"); + return -EINVAL; + } + databytes = (((int)command[7])<<8) | command[6]; + if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) { + DBG("Error writing command\n"); + return err; + } + if(command[0] == DATA_IN) { + u8 buffer[8]; + if(data == NULL) { + DBG("Internal driver error: data is NULL\n"); + return -EINVAL; + } + if((err = ReadPacket(cam, buffer, 8)) < 0) { + return err; + DBG("Error reading command result\n"); + } + memcpy(data, buffer, databytes); + } else if(command[0] == DATA_OUT) { + if(databytes > 0) { + if(data == NULL) { + DBG("Internal driver error: data is NULL\n"); + retval = -EINVAL; + } else { + if((err=WritePacket(cam, data, databytes)) < 0){ + DBG("Error writing command data\n"); + return err; + } + } + } + } else { + DBG("Unexpected first byte of command: %x\n", command[0]); + retval = -EINVAL; + } + return retval; +} + +/**************************************************************************** + * + * cpia_pp_open + * + ***************************************************************************/ +static int cpia_pp_open(void *privdata) +{ + struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata; + + if (cam == NULL) + return -EINVAL; + + if(cam->open_count == 0) { + if (parport_claim(cam->pdev)) { + DBG("failed to claim the port\n"); + return -EBUSY; + } + parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); + parport_data_forward(cam->port); + parport_write_control(cam->port, PARPORT_CONTROL_SELECT); + udelay(50); + parport_write_control(cam->port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); + } + + ++cam->open_count; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +/**************************************************************************** + * + * cpia_pp_registerCallback + * + ***************************************************************************/ +static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata) +{ + struct pp_cam_entry *cam = privdata; + int retval = 0; + + if(cam->port->irq != PARPORT_IRQ_NONE) { + cam->cb_task.routine = cb; + cam->cb_task.data = cbdata; + } else { + retval = -1; + } + return retval; +} + +/**************************************************************************** + * + * cpia_pp_close + * + ***************************************************************************/ +static int cpia_pp_close(void *privdata) +{ + struct pp_cam_entry *cam = privdata; +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + if (--cam->open_count == 0) { + parport_release(cam->pdev); + } + return 0; +} + +/**************************************************************************** + * + * cpia_pp_register + * + ***************************************************************************/ +static int cpia_pp_register(struct parport *port) +{ + struct pardevice *pdev = NULL; + struct pp_cam_entry *cam; + struct cam_data *cpia; + + if (!(port->modes & PARPORT_MODE_ECP) && + !(port->modes & PARPORT_MODE_TRISTATE)) { + LOG("port is not ECP capable\n"); + return -ENXIO; + } + + cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL); + if (cam == NULL) { + LOG("failed to allocate camera structure\n"); + return -ENOMEM; + } + memset(cam,0,sizeof(struct pp_cam_entry)); + + pdev = parport_register_device(port, "cpia_pp", NULL, NULL, + NULL, 0, cam); + + if (!pdev) { + LOG("failed to parport_register_device\n"); + kfree(cam); + return -ENXIO; + } + + cam->pdev = pdev; + cam->port = port; + init_waitqueue_head(&cam->wq_stream); + + cam->streaming = 0; + cam->stream_irq = 0; + + if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) { + LOG("failed to cpia_register_camera\n"); + parport_unregister_device(pdev); + kfree(cam); + return -ENXIO; + } + ADD_TO_LIST(cam_list, cpia); + + return 0; +} + +static void cpia_pp_detach (struct parport *port) +{ + struct cam_data *cpia; + + for(cpia = cam_list; cpia != NULL; cpia = cpia->next) { + struct pp_cam_entry *cam = cpia->lowlevel_data; + if (cam && cam->port->number == port->number) { + REMOVE_FROM_LIST(cpia); + + cpia_unregister_camera(cpia); + + if(cam->open_count > 0) { + cpia_pp_close(cam); + } + + parport_unregister_device(cam->pdev); + + kfree(cam); + cpia->lowlevel_data = NULL; + break; + } + } +} + +static void cpia_pp_attach (struct parport *port) +{ + unsigned int i; + + switch (parport_nr[0]) + { + case PPCPIA_PARPORT_UNSPEC: + case PPCPIA_PARPORT_AUTO: + if (port->probe_info[0].class != PARPORT_CLASS_MEDIA || + port->probe_info[0].cmdset == NULL || + strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0) + return; + + cpia_pp_register(port); + + break; + + default: + for (i = 0; i < PARPORT_MAX; ++i) { + if (port->number == parport_nr[i]) { + cpia_pp_register(port); + break; + } + } + break; + } +} + +static struct parport_driver cpia_pp_driver = { + "cpia_pp", + cpia_pp_attach, + cpia_pp_detach, + NULL +}; + +int cpia_pp_init(void) +{ + printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, + CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); + + if(parport_nr[0] == PPCPIA_PARPORT_OFF) { + printk(" disabled\n"); + return 0; + } + + if (parport_register_driver (&cpia_pp_driver)) { + LOG ("unable to register with parport\n"); + return -EIO; + } + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + if (parport[0]) { + /* The user gave some parameters. Let's see what they were. */ + if (!strncmp(parport[0], "auto", 4)) { + parport_nr[0] = PPCPIA_PARPORT_AUTO; + } else { + int n; + for (n = 0; n < PARPORT_MAX && parport[n]; n++) { + if (!strncmp(parport[n], "none", 4)) { + parport_nr[n] = PPCPIA_PARPORT_NONE; + } else { + char *ep; + unsigned long r = simple_strtoul(parport[n], &ep, 0); + if (ep != parport[n]) { + parport_nr[n] = r; + } else { + LOG("bad port specifier `%s'\n", parport[n]); + return -ENODEV; + } + } + } + } + } +#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE) + if(parport_enumerate() && !parport_enumerate()->probe_info.model) { + request_module("parport_probe"); + } +#endif + return cpia_pp_init(); +} + +void cleanup_module(void) +{ + parport_unregister_driver (&cpia_pp_driver); + return; +} + +#else /* !MODULE */ + +static int __init cpia_pp_setup(char *str) +{ +#if 0 + /* Is this only a 2.2ism? -jerdfelt */ + if (!str) { + if (ints[0] == 0 || ints[1] == 0) { + /* disable driver on "cpia_pp=" or "cpia_pp=0" */ + parport_nr[0] = PPCPIA_PARPORT_OFF; + } + } else +#endif + if (!strncmp(str, "parport", 7)) { + int n = simple_strtoul(str + 7, NULL, 10); + if (parport_ptr < PARPORT_MAX) { + parport_nr[parport_ptr++] = n; + } else { + LOG("too many ports, %s ignored.\n", str); + } + } else if (!strcmp(str, "auto")) { + parport_nr[0] = PPCPIA_PARPORT_AUTO; + } else if (!strcmp(str, "none")) { + parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; + } + + return 0; +} + +__setup("cpia_pp=", cpia_pp_setup); + +#endif /* !MODULE */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/cpia_usb.c linux/drivers/media/video/cpia_usb.c --- v2.4.0-test6/linux/drivers/media/video/cpia_usb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/cpia_usb.c Thu Mar 30 18:00:01 2000 @@ -0,0 +1,626 @@ +/* + * cpia_usb CPiA USB driver + * + * Supports CPiA based parallel port Video Camera's. + * + * Copyright (C) 1999 Jochen Scharrlach + * Copyright (C) 1999, 2000 Johannes Erdfelt + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpia.h" + +#define USB_REQ_CPIA_GRAB_FRAME 0xC1 +#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2 +#define WAIT_FOR_NEXT_FRAME 0 +#define FORCE_FRAME_UPLOAD 1 + +#define FRAMES_PER_DESC 10 +#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */ +#define CPIA_NUMSBUF 2 +#define STREAM_BUF_SIZE (PAGE_SIZE * 4) +#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) + +struct cpia_sbuf { + char *data; + urb_t *urb; +}; + +#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100) +enum framebuf_status { + FRAME_EMPTY, + FRAME_READING, + FRAME_READY, + FRAME_ERROR, +}; + +struct framebuf { + int length; + enum framebuf_status status; + u8 data[FRAMEBUF_LEN]; + struct framebuf *next; +}; + +struct usb_cpia { + /* Device structure */ + struct usb_device *dev; + + unsigned char iface; + wait_queue_head_t wq_stream; + + int cursbuf; /* Current receiving sbuf */ + struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */ + + int streaming; + int open; + int present; + struct framebuf *buffers[3]; + struct framebuf *curbuff, *workbuff; +}; + +static int cpia_usb_open(void *privdata); +static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata), + void *cbdata); +static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data); +static int cpia_usb_streamStart(void *privdata); +static int cpia_usb_streamStop(void *privdata); +static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock); +static int cpia_usb_close(void *privdata); + +#define ABOUT "USB driver for Vision CPiA based cameras" + +static struct cpia_camera_ops cpia_usb_ops = { + cpia_usb_open, + cpia_usb_registerCallback, + cpia_usb_transferCmd, + cpia_usb_streamStart, + cpia_usb_streamStop, + cpia_usb_streamRead, + cpia_usb_close, + 0 +}; + +static struct cam_data *cam_list; + +static void cpia_usb_complete(struct urb *urb) +{ + int i; + char *cdata; + struct usb_cpia *ucpia; + + if (!urb || !urb->context) + return; + + ucpia = (struct usb_cpia *) urb->context; + + if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open) + return; + + if (ucpia->workbuff->status == FRAME_EMPTY) { + ucpia->workbuff->status = FRAME_READING; + ucpia->workbuff->length = 0; + } + + for (i = 0; i < urb->number_of_packets; i++) { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) + printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st); + + if (FRAMEBUF_LEN < ucpia->workbuff->length + n) { + printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n); + return; + } + + if (n) { + if ((ucpia->workbuff->length > 0) || + (0x19 == cdata[0] && 0x68 == cdata[1])) { + memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n); + ucpia->workbuff->length += n; + } else + DBG("Ignoring packet!\n"); + } else { + if (ucpia->workbuff->length > 4 && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) { + ucpia->workbuff->status = FRAME_READY; + ucpia->curbuff = ucpia->workbuff; + ucpia->workbuff = ucpia->workbuff->next; + ucpia->workbuff->status = FRAME_EMPTY; + ucpia->workbuff->length = 0; + + if (waitqueue_active(&ucpia->wq_stream)) + wake_up_interruptible(&ucpia->wq_stream); + } + } + } +} + +static int cpia_usb_open(void *privdata) +{ + struct usb_cpia *ucpia = (struct usb_cpia *) privdata; + urb_t *urb; + int ret, retval = 0, fx, err; + + if (!ucpia) + return -EINVAL; + + ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ucpia->sbuf[0].data) + return -EINVAL; + + ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ucpia->sbuf[1].data) { + retval = -EINVAL; + goto error_0; + } + + ret = usb_set_interface(ucpia->dev, ucpia->iface, 3); + if (ret < 0) { + printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret); + retval = -EBUSY; + goto error_all; + } + + ucpia->buffers[0]->status = FRAME_EMPTY; + ucpia->buffers[0]->length = 0; + ucpia->buffers[1]->status = FRAME_EMPTY; + ucpia->buffers[1]->length = 0; + ucpia->buffers[2]->status = FRAME_EMPTY; + ucpia->buffers[2]->length = 0; + ucpia->curbuff = ucpia->buffers[0]; + ucpia->workbuff = ucpia->buffers[1]; + + /* We double buffer the Iso lists */ + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); + retval = -ENOMEM; + goto error_all; + } + + ucpia->sbuf[0].urb = urb; + urb->dev = ucpia->dev; + urb->context = ucpia; + urb->pipe = usb_rcvisocpipe(ucpia->dev, 1); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ucpia->sbuf[0].data; + urb->complete = cpia_usb_complete; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); + retval = -ENOMEM; + goto error_all; + } + + ucpia->sbuf[1].urb = urb; + urb->dev = ucpia->dev; + urb->context = ucpia; + urb->pipe = usb_rcvisocpipe(ucpia->dev, 1); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ucpia->sbuf[1].data; + urb->complete = cpia_usb_complete; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb; + ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb; + + err = usb_submit_urb(ucpia->sbuf[0].urb); + if (err) + printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n", + err); + err = usb_submit_urb(ucpia->sbuf[1].urb); + if (err) + printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n", + err); + + ucpia->streaming = 1; + ucpia->open = 1; + + return 0; + +error_all: + kfree (ucpia->sbuf[1].data); +error_0: + kfree (ucpia->sbuf[0].data); + + return retval; +} + +// +// convenience functions +// + +/**************************************************************************** + * + * WritePacket + * + ***************************************************************************/ +static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size) +{ + if (!packet) + return -EINVAL; + + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + packet[1] + (packet[0] << 8), + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + packet[2] + (packet[3] << 8), + packet[4] + (packet[5] << 8), buf, size, HZ); +} + +/**************************************************************************** + * + * ReadPacket + * + ***************************************************************************/ +static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size) +{ + if (!packet || size <= 0) + return -EINVAL; + + return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + packet[1] + (packet[0] << 8), + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + packet[2] + (packet[3] << 8), + packet[4] + (packet[5] << 8), buf, size, HZ); +} + +static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data) +{ + int err = 0; + int databytes; + struct usb_cpia *ucpia = (struct usb_cpia *)privdata; + struct usb_device *udev = ucpia->dev; + + if (!udev) { + DBG("Internal driver error: udev is NULL\n"); + return -EINVAL; + } + + if (!command) { + DBG("Internal driver error: command is NULL\n"); + return -EINVAL; + } + + databytes = (((int)command[7])<<8) | command[6]; + + if (command[0] == DATA_IN) { + u8 buffer[8]; + + if (!data) { + DBG("Internal driver error: data is NULL\n"); + return -EINVAL; + } + + err = ReadPacket(udev, command, buffer, 8); + if (err < 0) + return err; + + memcpy(data, buffer, databytes); + } else if(command[0] == DATA_OUT) + WritePacket(udev, command, data, databytes); + else { + DBG("Unexpected first byte of command: %x\n", command[0]); + err = -EINVAL; + } + + return 0; +} + +static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata), + void *cbdata) +{ + return -ENODEV; +} + +static int cpia_usb_streamStart(void *privdata) +{ + return -ENODEV; +} + +static int cpia_usb_streamStop(void *privdata) +{ + return -ENODEV; +} + +static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock) +{ + struct usb_cpia *ucpia = (struct usb_cpia *) privdata; + struct framebuf *mybuff; + + if (!ucpia || !ucpia->present) + return -1; + + if (ucpia->curbuff->status != FRAME_READY) + interruptible_sleep_on(&ucpia->wq_stream); + else + DBG("Frame already waiting!\n"); + + mybuff = ucpia->curbuff; + + if (!mybuff) + return -1; + + if (mybuff->status != FRAME_READY || mybuff->length < 4) { + DBG("Something went wrong!\n"); + return -1; + } + + memcpy(frame, mybuff->data, mybuff->length); + mybuff->status = FRAME_EMPTY; + +/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */ +/* mybuff->length, frame[0], frame[1], */ +/* frame[mybuff->length-4], frame[mybuff->length-3], */ +/* frame[mybuff->length-2], frame[mybuff->length-1]); */ + + return mybuff->length; +} + +static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try) +{ + if (!ucpia->streaming) + return; + + ucpia->streaming = 0; + + /* Set packet size to 0 */ + if (try) { + int ret; + + ret = usb_set_interface(ucpia->dev, ucpia->iface, 0); + if (ret < 0) { + printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret); + return; + } + } + + /* Unschedule all of the iso td's */ + if (ucpia->sbuf[1].urb) { + usb_unlink_urb(ucpia->sbuf[1].urb); + usb_free_urb(ucpia->sbuf[1].urb); + ucpia->sbuf[1].urb = NULL; + } + + if (ucpia->sbuf[0].urb) { + usb_unlink_urb(ucpia->sbuf[0].urb); + usb_free_urb(ucpia->sbuf[0].urb); + ucpia->sbuf[0].urb = NULL; + } +} + +static int cpia_usb_close(void *privdata) +{ + struct usb_cpia *ucpia = (struct usb_cpia *) privdata; + + ucpia->open = 0; + + cpia_usb_free_resources(ucpia, 1); + + if (!ucpia->present) + kfree(ucpia); + + return 0; +} + +int cpia_usb_init(void) +{ + /* return -ENODEV; */ + return 0; +} + +/* Probing and initializing */ + +static void *cpia_probe(struct usb_device *udev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_cpia *ucpia; + struct cam_data *cam; + int ret; + + /* A multi-config CPiA camera? */ + if (udev->descriptor.bNumConfigurations != 1) + return NULL; + + interface = &udev->actconfig->interface[ifnum].altsetting[0]; + + /* Is it a CPiA? */ + if (udev->descriptor.idVendor != 0x0553) + return NULL; + if (udev->descriptor.idProduct != 0x0002) + return NULL; + + /* We found a CPiA */ + printk(KERN_INFO "USB CPiA camera found\n"); + + ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL); + if (!ucpia) { + printk(KERN_ERR "couldn't kmalloc cpia struct\n"); + return NULL; + } + + memset(ucpia, 0, sizeof(*ucpia)); + + ucpia->dev = udev; + ucpia->iface = interface->bInterfaceNumber; + init_waitqueue_head(&ucpia->wq_stream); + + ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0])); + if (!ucpia->buffers[0]) { + printk(KERN_ERR "couldn't vmalloc frame buffer 0\n"); + goto fail_alloc_0; + } + + ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1])); + if (!ucpia->buffers[1]) { + printk(KERN_ERR "couldn't vmalloc frame buffer 1\n"); + goto fail_alloc_1; + } + + ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2])); + if (!ucpia->buffers[2]) { + printk(KERN_ERR "couldn't vmalloc frame buffer 2\n"); + goto fail_alloc_2; + } + + ucpia->buffers[0]->next = ucpia->buffers[1]; + ucpia->buffers[1]->next = ucpia->buffers[2]; + ucpia->buffers[2]->next = ucpia->buffers[0]; + + ret = usb_set_interface(udev, ucpia->iface, 0); + if (ret < 0) { + printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret); + /* goto fail_all; */ + } + + /* Before register_camera, important */ + ucpia->present = 1; + + cam = cpia_register_camera(&cpia_usb_ops, ucpia); + if (!cam) { + LOG("failed to cpia_register_camera\n"); + goto fail_all; + } + + ADD_TO_LIST(cam_list, cam); + + return cam; + +fail_all: + vfree(ucpia->buffers[2]); + ucpia->buffers[2] = NULL; +fail_alloc_2: + vfree(ucpia->buffers[1]); + ucpia->buffers[1] = NULL; +fail_alloc_1: + vfree(ucpia->buffers[0]); + ucpia->buffers[0] = NULL; +fail_alloc_0: + + return NULL; +} + +static void cpia_disconnect(struct usb_device *dev, void *ptr); + +static struct usb_driver cpia_driver = { + "cpia", + cpia_probe, + cpia_disconnect, + { NULL, NULL } +}; + +/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */ +/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */ +/* will do it for us as well as passing a udev structure - jerdfelt */ +static void cpia_disconnect(struct usb_device *udev, void *ptr) +{ + struct cam_data *cam = (struct cam_data *) ptr; + struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data; + + REMOVE_FROM_LIST(cam); + + /* Don't even try to reset the altsetting if we're disconnected */ + cpia_usb_free_resources(ucpia, 0); + + ucpia->present = 0; + + cpia_unregister_camera(cam); + + ucpia->curbuff->status = FRAME_ERROR; + + if (waitqueue_active(&ucpia->wq_stream)) + wake_up_interruptible(&ucpia->wq_stream); + + usb_driver_release_interface(&cpia_driver, + &udev->actconfig->interface[0]); + + ucpia->curbuff = ucpia->workbuff = NULL; + + if (ucpia->buffers[2]) { + vfree(ucpia->buffers[2]); + ucpia->buffers[2] = NULL; + } + + if (ucpia->buffers[1]) { + vfree(ucpia->buffers[1]); + ucpia->buffers[1] = NULL; + } + + if (ucpia->buffers[0]) { + vfree(ucpia->buffers[0]); + ucpia->buffers[0] = NULL; + } + + if (!ucpia->open) + kfree(ucpia); +} + +int usb_cpia_init(void) +{ + cam_list = NULL; + + return usb_register(&cpia_driver); +} + +void usb_cpia_cleanup(void) +{ +/* + struct cam_data *cam; + + while ((cam = cam_list) != NULL) + cpia_disconnect(NULL, cam); +*/ + + usb_deregister(&cpia_driver); +} + +#ifdef MODULE +int init_module(void) +{ + return usb_cpia_init(); +} + +void cleanup_module(void) +{ + usb_cpia_cleanup(); +} +#endif /* !MODULE */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/cs8420.h linux/drivers/media/video/cs8420.h --- v2.4.0-test6/linux/drivers/media/video/cs8420.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/cs8420.h Wed Nov 10 13:58:46 1999 @@ -0,0 +1,50 @@ +/* cs8420.h - cs8420 initializations + Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) + + 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 __CS8420_H__ +#define __CS8420_H__ + +/* Initialization Sequence */ + +static __u8 init8420[] = { + 1, 0x01, 2, 0x02, 3, 0x00, 4, 0x46, + 5, 0x24, 6, 0x84, 18, 0x18, 19, 0x13, +}; + +#define INIT8420LEN (sizeof(init8420)/2) + +static __u8 mode8420pro[] = { /* professional output mode */ + 32, 0xa1, 33, 0x00, 34, 0x00, 35, 0x00, + 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, + 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, + 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, + 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, + 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, +}; +#define MODE8420LEN (sizeof(mode8420pro)/2) + +static __u8 mode8420con[] = { /* consumer output mode */ + 32, 0x20, 33, 0x00, 34, 0x00, 35, 0x48, + 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, + 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, + 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, + 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, + 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, +}; + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/i2c-old.c linux/drivers/media/video/i2c-old.c --- v2.4.0-test6/linux/drivers/media/video/i2c-old.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/i2c-old.c Mon Aug 14 11:56:53 2000 @@ -0,0 +1,450 @@ +/* + * Generic i2c interface for linux + * + * (c) 1998 Gerd Knorr + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REGPRINT(x) if (verbose) (x) +#define I2C_DEBUG(x) if (i2c_debug) (x) + +static int scan = 0; +static int verbose = 0; +static int i2c_debug = 0; + +#if LINUX_VERSION_CODE >= 0x020117 +MODULE_PARM(scan,"i"); +MODULE_PARM(verbose,"i"); +MODULE_PARM(i2c_debug,"i"); +#endif + +/* ----------------------------------------------------------------------- */ + +static struct i2c_bus *busses[I2C_BUS_MAX]; +static struct i2c_driver *drivers[I2C_DRIVER_MAX]; +static int bus_count = 0, driver_count = 0; + +#ifdef CONFIG_VIDEO_BUZ +extern int saa7111_init(void); +extern int saa7185_init(void); +#endif +#ifdef CONFIG_VIDEO_LML33 +extern int bt819_init(void); +extern int bt856_init(void); +#endif + +int i2c_init(void) +{ + printk(KERN_INFO "i2c: initialized%s\n", + scan ? " (i2c bus scan enabled)" : ""); + /* anything to do here ? */ +#ifdef CONFIG_VIDEO_BUZ + saa7111_init(); + saa7185_init(); +#endif +#ifdef CONFIG_VIDEO_LML33 + bt819_init(); + bt856_init(); +#endif + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver) +{ + struct i2c_device *device; + int i,j,ack=1; + unsigned char addr; + LOCK_FLAGS; + + /* probe for device */ + LOCK_I2C_BUS(bus); + for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) + { + i2c_start(bus); + ack = i2c_sendbyte(bus,addr,0); + i2c_stop(bus); + if (!ack) + break; + } + UNLOCK_I2C_BUS(bus); + if (ack) + return; + + /* got answer */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (NULL == driver->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + return; + + for (j = 0; j < I2C_DEVICE_MAX; j++) + if (NULL == bus->devices[j]) + break; + if (I2C_DEVICE_MAX == j) + return; + + if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL))) + return; + device->bus = bus; + device->driver = driver; + device->addr = addr; + + /* Attach */ + + if (driver->attach(device)!=0) + { + kfree(device); + return; + } + driver->devices[i] = device; + driver->devcount++; + bus->devices[j] = device; + bus->devcount++; + + if (bus->attach_inform) + bus->attach_inform(bus,driver->id); + REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name)); +} + +static void i2c_detach_device(struct i2c_device *device) +{ + int i; + + if (device->bus->detach_inform) + device->bus->detach_inform(device->bus,device->driver->id); + device->driver->detach(device); + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (device == device->driver->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + { + printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", + device->name); + return; + } + device->driver->devices[i] = NULL; + device->driver->devcount--; + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (device == device->bus->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + { + printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", + device->name); + return; + } + device->bus->devices[i] = NULL; + device->bus->devcount--; + + REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name)); + kfree(device); +} + +/* ----------------------------------------------------------------------- */ + +int i2c_register_bus(struct i2c_bus *bus) +{ + int i,ack; + LOCK_FLAGS; + + memset(bus->devices,0,sizeof(bus->devices)); + bus->devcount = 0; + + for (i = 0; i < I2C_BUS_MAX; i++) + if (NULL == busses[i]) + break; + if (I2C_BUS_MAX == i) + return -ENOMEM; + + busses[i] = bus; + bus_count++; + REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); + + MOD_INC_USE_COUNT; + + if (scan) + { + /* scan whole i2c bus */ + LOCK_I2C_BUS(bus); + for (i = 0; i < 256; i+=2) + { + i2c_start(bus); + ack = i2c_sendbyte(bus,i,0); + i2c_stop(bus); + if (!ack) + { + printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", + bus->name,i); + } + } + UNLOCK_I2C_BUS(bus); + } + + /* probe available drivers */ + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (drivers[i]) + i2c_attach_device(bus,drivers[i]); + return 0; +} + +int i2c_unregister_bus(struct i2c_bus *bus) +{ + int i; + + /* detach devices */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (bus->devices[i]) + i2c_detach_device(bus->devices[i]); + + for (i = 0; i < I2C_BUS_MAX; i++) + if (bus == busses[i]) + break; + if (I2C_BUS_MAX == i) + { + printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", + bus->name); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; + + busses[i] = NULL; + bus_count--; + REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int i2c_register_driver(struct i2c_driver *driver) +{ + int i; + + memset(driver->devices,0,sizeof(driver->devices)); + driver->devcount = 0; + + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (NULL == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) + return -ENOMEM; + + drivers[i] = driver; + driver_count++; + + MOD_INC_USE_COUNT; + + REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); + + /* Probe available busses */ + for (i = 0; i < I2C_BUS_MAX; i++) + if (busses[i]) + i2c_attach_device(busses[i],driver); + + return 0; +} + +int i2c_unregister_driver(struct i2c_driver *driver) +{ + int i; + + /* detach devices */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (driver->devices[i]) + i2c_detach_device(driver->devices[i]); + + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (driver == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) + { + printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", + driver->name); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; + + drivers[i] = NULL; + driver_count--; + REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int i2c_control_device(struct i2c_bus *bus, int id, + unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (bus->devices[i] && bus->devices[i]->driver->id == id) + break; + if (i == I2C_DEVICE_MAX) + return -ENODEV; + if (NULL == bus->devices[i]->driver->command) + return -ENODEV; + return bus->devices[i]->driver->command(bus->devices[i],cmd,arg); +} + +/* ----------------------------------------------------------------------- */ + +#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data)) +#define I2C_GET(bus) (bus->i2c_getdataline(bus)) + +void i2c_start(struct i2c_bus *bus) +{ + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + I2C_SET(bus,1,0); + I2C_SET(bus,0,0); + I2C_DEBUG(printk("%s: < ",bus->name)); +} + +void i2c_stop(struct i2c_bus *bus) +{ + I2C_SET(bus,0,0); + I2C_SET(bus,1,0); + I2C_SET(bus,1,1); + I2C_DEBUG(printk(">\n")); +} + +void i2c_one(struct i2c_bus *bus) +{ + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + I2C_SET(bus,0,1); +} + +void i2c_zero(struct i2c_bus *bus) +{ + I2C_SET(bus,0,0); + I2C_SET(bus,1,0); + I2C_SET(bus,0,0); +} + +int i2c_ack(struct i2c_bus *bus) +{ + int ack; + + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + ack = I2C_GET(bus); + I2C_SET(bus,0,1); + return ack; +} + +int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) +{ + int i, ack; + + I2C_SET(bus,0,0); + for (i=7; i>=0; i--) + (data&(1<=0; i--) + { + I2C_SET(bus,1,1); + if (I2C_GET(bus)) + data |= (1<i2c_read) + return bus->i2c_read(bus, addr); + + i2c_start(bus); + i2c_sendbyte(bus,addr,0); + ret = i2c_readbyte(bus,1); + i2c_stop(bus); + return ret; +} + +int i2c_write(struct i2c_bus *bus, unsigned char addr, + unsigned char data1, unsigned char data2, int both) +{ + int ack; + + if (bus->i2c_write) + return bus->i2c_write(bus, addr, data1, data2, both); + + i2c_start(bus); + i2c_sendbyte(bus,addr,0); + ack = i2c_sendbyte(bus,data1,0); + if (both) + ack = i2c_sendbyte(bus,data2,0); + i2c_stop(bus); + return ack ? -1 : 0 ; +} + +/* ----------------------------------------------------------------------- */ + +#ifdef MODULE + +#if LINUX_VERSION_CODE >= 0x020100 +EXPORT_SYMBOL(i2c_register_bus); +EXPORT_SYMBOL(i2c_unregister_bus); +EXPORT_SYMBOL(i2c_register_driver); +EXPORT_SYMBOL(i2c_unregister_driver); +EXPORT_SYMBOL(i2c_control_device); +EXPORT_SYMBOL(i2c_start); +EXPORT_SYMBOL(i2c_stop); +EXPORT_SYMBOL(i2c_one); +EXPORT_SYMBOL(i2c_zero); +EXPORT_SYMBOL(i2c_ack); +EXPORT_SYMBOL(i2c_sendbyte); +EXPORT_SYMBOL(i2c_readbyte); +EXPORT_SYMBOL(i2c_read); +EXPORT_SYMBOL(i2c_write); +#endif + +int init_module(void) +{ + return i2c_init(); +} + +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/i2c-parport.c linux/drivers/media/video/i2c-parport.c --- v2.4.0-test6/linux/drivers/media/video/i2c-parport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/i2c-parport.c Wed Jul 12 16:24:33 2000 @@ -0,0 +1,147 @@ +/* + * I2C driver for parallel port + * + * Author: Phil Blundell + * + * 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 driver implements a simple I2C protocol by bit-twiddling some + * signals on the parallel port. Since the outputs on the parallel port + * aren't open collector, three lines rather than two are used: + * + * D0 clock out + * D1 data out + * BUSY data in + */ + +#include +#include +#include +#include +#include +#include + +#define I2C_DELAY 10 + +static int debug = 0; + +struct parport_i2c_bus +{ + struct i2c_bus i2c; + struct parport_i2c_bus *next; +}; + +static struct parport_i2c_bus *bus_list; + +static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED; + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus, int clk, int data) +{ + struct parport *p = bus->data; + parport_write_data(p, (clk?1:0) | (data?2:0)); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct parport *p = bus->data; + return (parport_read_status(p) & PARPORT_STATUS_BUSY) ? 0 : 1; +} + +static struct i2c_bus parport_i2c_bus_template = +{ + "...", + I2C_BUSID_PARPORT, + NULL, + + SPIN_LOCK_UNLOCKED, + + NULL, + NULL, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL, +}; + +static void i2c_parport_attach(struct parport *port) +{ + struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), + GFP_KERNEL); + b->i2c = parport_i2c_bus_template; + b->i2c.data = parport_get_port (port); + strncpy(b->i2c.name, port->name, 32); + spin_lock(&bus_list_lock); + b->next = bus_list; + bus_list = b; + spin_unlock(&bus_list_lock); + i2c_register_bus(&b->i2c); + if (debug) + printk(KERN_DEBUG "i2c: attached to %s\n", port->name); +} + +static void i2c_parport_detach(struct parport *port) +{ + struct parport_i2c_bus *b, *old_b = NULL; + spin_lock(&bus_list_lock); + b = bus_list; + while (b) + { + if (b->i2c.data == port) + { + if (old_b) + old_b->next = b->next; + else + bus_list = b->next; + i2c_unregister_bus(&b->i2c); + kfree(b); + break; + } + old_b = b; + b = b->next; + } + spin_unlock(&bus_list_lock); + if (debug) + printk(KERN_DEBUG "i2c: detached from %s\n", port->name); +} + +static struct parport_driver parport_i2c_driver = +{ + "i2c", + i2c_parport_attach, + i2c_parport_detach +}; + +#ifdef MODULE +int init_module(void) +#else +int __init i2c_parport_init(void) +#endif +{ + printk("I2C: driver for parallel port v0.1 philb@gnu.org\n"); + parport_register_driver(&parport_i2c_driver); + return 0; +} + +#ifdef MODULE +MODULE_PARM(debug, "i"); + +void cleanup_module(void) +{ + struct parport_i2c_bus *b = bus_list; + while (b) + { + struct parport_i2c_bus *next = b->next; + i2c_unregister_bus(&b->i2c); + kfree(b); + b = next; + } + parport_unregister_driver(&parport_i2c_driver); +} +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/ibmmpeg2.h linux/drivers/media/video/ibmmpeg2.h --- v2.4.0-test6/linux/drivers/media/video/ibmmpeg2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/ibmmpeg2.h Wed Nov 10 13:58:46 1999 @@ -0,0 +1,94 @@ +/* ibmmpeg2.h - IBM MPEGCD21 definitions */ + +#ifndef __IBM_MPEG2__ +#define __IBM_MPEG2__ + +/* Define all MPEG Decoder registers */ +/* Chip Control and Status */ +#define IBM_MP2_CHIP_CONTROL 0x200*2 +#define IBM_MP2_CHIP_MODE 0x201*2 +/* Timer Control and Status */ +#define IBM_MP2_SYNC_STC2 0x202*2 +#define IBM_MP2_SYNC_STC1 0x203*2 +#define IBM_MP2_SYNC_STC0 0x204*2 +#define IBM_MP2_SYNC_PTS2 0x205*2 +#define IBM_MP2_SYNC_PTS1 0x206*2 +#define IBM_MP2_SYNC_PTS0 0x207*2 +/* Video FIFO Control */ +#define IBM_MP2_FIFO 0x208*2 +#define IBM_MP2_FIFOW 0x100*2 +#define IBM_MP2_FIFO_STAT 0x209*2 +#define IBM_MP2_RB_THRESHOLD 0x22b*2 +/* Command buffer */ +#define IBM_MP2_COMMAND 0x20a*2 +#define IBM_MP2_CMD_DATA 0x20b*2 +#define IBM_MP2_CMD_STAT 0x20c*2 +#define IBM_MP2_CMD_ADDR 0x20d*2 +/* Internal Processor Control and Status */ +#define IBM_MP2_PROC_IADDR 0x20e*2 +#define IBM_MP2_PROC_IDATA 0x20f*2 +#define IBM_MP2_WR_PROT 0x235*2 +/* DRAM Access */ +#define IBM_MP2_DRAM_ADDR 0x210*2 +#define IBM_MP2_DRAM_DATA 0x212*2 +#define IBM_MP2_DRAM_CMD_STAT 0x213*2 +#define IBM_MP2_BLOCK_SIZE 0x23b*2 +#define IBM_MP2_SRC_ADDR 0x23c*2 +/* Onscreen Display */ +#define IBM_MP2_OSD_ADDR 0x214*2 +#define IBM_MP2_OSD_DATA 0x215*2 +#define IBM_MP2_OSD_MODE 0x217*2 +#define IBM_MP2_OSD_LINK_ADDR 0x229*2 +#define IBM_MP2_OSD_SIZE 0x22a*2 +/* Interrupt Control */ +#define IBM_MP2_HOST_INT 0x218*2 +#define IBM_MP2_MASK0 0x219*2 +#define IBM_MP2_HOST_INT1 0x23e*2 +#define IBM_MP2_MASK1 0x23f*2 +/* Audio Control */ +#define IBM_MP2_AUD_IADDR 0x21a*2 +#define IBM_MP2_AUD_IDATA 0x21b*2 +#define IBM_MP2_AUD_FIFO 0x21c*2 +#define IBM_MP2_AUD_FIFOW 0x101*2 +#define IBM_MP2_AUD_CTL 0x21d*2 +#define IBM_MP2_BEEP_CTL 0x21e*2 +#define IBM_MP2_FRNT_ATTEN 0x22d*2 +/* Display Control */ +#define IBM_MP2_DISP_MODE 0x220*2 +#define IBM_MP2_DISP_DLY 0x221*2 +#define IBM_MP2_VBI_CTL 0x222*2 +#define IBM_MP2_DISP_LBOR 0x223*2 +#define IBM_MP2_DISP_TBOR 0x224*2 +/* Polarity Control */ +#define IBM_MP2_INFC_CTL 0x22c*2 + +/* control commands */ +#define IBM_MP2_PLAY 0 +#define IBM_MP2_PAUSE 1 +#define IBM_MP2_SINGLE_FRAME 2 +#define IBM_MP2_FAST_FORWARD 3 +#define IBM_MP2_SLOW_MOTION 4 +#define IBM_MP2_IMED_NORM_PLAY 5 +#define IBM_MP2_RESET_WINDOW 6 +#define IBM_MP2_FREEZE_FRAME 7 +#define IBM_MP2_RESET_VID_RATE 8 +#define IBM_MP2_CONFIG_DECODER 9 +#define IBM_MP2_CHANNEL_SWITCH 10 +#define IBM_MP2_RESET_AUD_RATE 11 +#define IBM_MP2_PRE_OP_CHN_SW 12 +#define IBM_MP2_SET_STILL_MODE 14 + +/* Define Xilinx FPGA Internal Registers */ + +/* general control register 0 */ +#define XILINX_CTL0 0x600 +/* genlock delay resister 1 */ +#define XILINX_GLDELAY 0x602 +/* send 16 bits to CS3310 port */ +#define XILINX_CS3310 0x604 +/* send 16 bits to CS3310 and complete */ +#define XILINX_CS3310_CMPLT 0x60c +/* pulse width modulator control */ +#define XILINX_PWM 0x606 + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c --- v2.4.0-test6/linux/drivers/media/video/msp3400.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/msp3400.c Sun Aug 6 12:45:28 2000 @@ -0,0 +1,1454 @@ +/* + * programming the msp34* sound processor family + * + * (c) 1997-2000 Gerd Knorr + * + * what works and what doesn't: + * + * AM-Mono + * Support for Hauppauge cards added (decoding handled by tuner) added by + * Frederic Crozat + * + * FM-Mono + * should work. The stereo modes are backward compatible to FM-mono, + * therefore FM-Mono should be allways available. + * + * FM-Stereo (B/G, used in germany) + * should work, with autodetect + * + * FM-Stereo (satellite) + * should work, no autodetect (i.e. default is mono, but you can + * switch to stereo -- untested) + * + * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) + * should work, with autodetect. Support for NICAM was added by + * Pekka Pietikainen + * + * + * TODO: + * - better SAT support + * + * + * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) + * using soundcore instead of OSS + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SMP +#include +#include +#endif +/* kernel_thread */ +#define __KERNEL_SYSCALLS__ +#include + +#include "audiochip.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* insmod parameters */ +static int debug = 0; /* debug output */ +static int once = 0; /* no continous stereo monitoring */ +static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), + the autoscan seems work well only with FM... */ +static int simple = -1; /* use short programming (>= msp3410 only) */ +static int dolby = 0; + +struct msp3400c { + int simple; + int nicam; + int mode; + int norm; + int stereo; + int nicam_on; + int main, second; /* sound carrier */ + + int left, right; /* volume */ + int bass, treble; + + /* thread */ + struct task_struct *thread; + wait_queue_head_t wq; + + struct semaphore *notify; + int active,restart,rmmod; + + int watch_stereo; + struct timer_list wake_stereo; +}; + +#define MSP3400_MAX 4 +static struct i2c_client *msps[MSP3400_MAX]; + +#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ + +/* ---------------------------------------------------------------------- */ + +#define dprintk if (debug) printk + +MODULE_PARM(once,"i"); +MODULE_PARM(debug,"i"); +MODULE_PARM(simple,"i"); +MODULE_PARM(amsound,"i"); +MODULE_PARM(dolby,"i"); + +/* ---------------------------------------------------------------------- */ + +#define I2C_MSP3400C 0x80 +#define I2C_MSP3400C_DEM 0x10 +#define I2C_MSP3400C_DFP 0x12 + +/* ----------------------------------------------------------------------- */ +/* functions for talking to the MSP3400C Sound processor */ + +static int msp3400c_reset(struct i2c_client *client) +{ + static char reset_off[3] = { 0x00, 0x80, 0x00 }; + static char reset_on[3] = { 0x00, 0x00, 0x00 }; + + i2c_master_send(client,reset_off,3); /* XXX ignore errors here */ + if (3 != i2c_master_send(client,reset_on, 3)) { + printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n"); + return -1; + } + return 0; +} + +static int +msp3400c_read(struct i2c_client *client, int dev, int addr) +{ + int err; + + unsigned char write[3]; + unsigned char read[2]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read } + }; + write[0] = dev+1; + write[1] = addr >> 8; + write[2] = addr & 0xff; + + for (err = 0; err < 3;) { + if (2 == i2c_transfer(client->adapter,msgs,2)) + break; + err++; + printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", + err, dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } + if (3 == err) { + printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); + msp3400c_reset(client); + return -1; + } + return read[0] << 8 | read[1]; +} + +static int +msp3400c_write(struct i2c_client *client, int dev, int addr, int val) +{ + int err; + unsigned char buffer[5]; + + buffer[0] = dev; + buffer[1] = addr >> 8; + buffer[2] = addr & 0xff; + buffer[3] = val >> 8; + buffer[4] = val & 0xff; + + for (err = 0; err < 3;) { + if (5 == i2c_master_send(client, buffer, 5)) + break; + err++; + printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", + err, dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } + if (3 == err) { + printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); + msp3400c_reset(client); + return -1; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ + +/* This macro is allowed for *constants* only, gcc must calculate it + at compile time. Remember -- no floats in kernel mode */ +#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) + +#define MSP_MODE_AM_DETECT 0 +#define MSP_MODE_FM_RADIO 2 +#define MSP_MODE_FM_TERRA 3 +#define MSP_MODE_FM_SAT 4 +#define MSP_MODE_FM_NICAM1 5 +#define MSP_MODE_FM_NICAM2 6 +#define MSP_MODE_AM_NICAM 7 +#define MSP_MODE_BTSC 8 + +static struct MSP_INIT_DATA_DEM { + int fir1[6]; + int fir2[6]; + int cdo1; + int cdo2; + int ad_cv; + int mode_reg; + int dfp_src; + int dfp_matrix; +} msp_init_data[] = { + /* AM (for carrier detect / msp3400) */ + { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0500, 0x0020, 0x3000}, + + /* AM (for carrier detect / msp3410) */ + { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0100, 0x0020, 0x3000}, + + /* FM Radio */ + { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, + MSP_CARRIER(10.7), MSP_CARRIER(10.7), + 0x00d0, 0x0480, 0x0020, 0x3000 }, + + /* Terrestial FM-mono + FM-stereo */ + { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0480, 0x0030, 0x3000}, + + /* Sat FM-mono */ + { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0480, 0x0000, 0x3000}, + + /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ + { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0040, 0x0120, 0x3000}, + + /* NICAM/FM -- I (6.0/6.552) */ + { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(6.0), MSP_CARRIER(6.0), + 0x00d0, 0x0040, 0x0120, 0x3000}, + + /* NICAM/AM -- L (6.5/5.85) */ + { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0140, 0x0120, 0x7c03}, +}; + +struct CARRIER_DETECT { + int cdo; + char *name; +}; + +static struct CARRIER_DETECT carrier_detect_main[] = { + /* main carrier */ + { MSP_CARRIER(4.5), "4.5 NTSC" }, + { MSP_CARRIER(5.5), "5.5 PAL B/G" }, + { MSP_CARRIER(6.0), "6.0 PAL I" }, + { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } +}; + +static struct CARRIER_DETECT carrier_detect_55[] = { + /* PAL B/G */ + { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, + { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } +}; + +static struct CARRIER_DETECT carrier_detect_65[] = { + /* PAL SAT / SECAM */ + { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, + { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, + { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, + { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, + { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, + { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, +}; + +#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) + +/* ------------------------------------------------------------------------ */ + +static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) +{ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ +} + +static void msp3400c_setvolume(struct i2c_client *client, int left, int right) +{ + int vol,val,balance; + + vol = (left > right) ? left : right; + val = (vol * 0x73 / 65535) << 8; + balance = 0; + if (vol > 0) + balance = ((right-left) * 127) / vol; + + dprintk("msp34xx: setvolume: %d:%d 0x%02x 0x%02x\n", + left,right,val>>8,balance); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ + /* scart - on/off only */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8); +} + +static void msp3400c_setbass(struct i2c_client *client, int bass) +{ + int val = ((bass-32768) * 0x60 / 65535) << 8; + + dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ +} + +static void msp3400c_settreble(struct i2c_client *client, int treble) +{ + int val = ((treble-32768) * 0x60 / 65535) << 8; + + dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ +} + +static void msp3400c_setmode(struct i2c_client *client, int type) +{ + struct msp3400c *msp = client->data; + int i; + + dprintk("msp3400: setmode: %d\n",type); + msp->mode = type; + msp->stereo = VIDEO_SOUND_MONO; + + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ + msp_init_data[type].ad_cv); + + for (i = 5; i >= 0; i--) /* fir 1 */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, + msp_init_data[type].fir1[i]); + + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); + for (i = 5; i >= 0; i--) + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, + msp_init_data[type].fir2[i]); + + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ + msp_init_data[type].mode_reg); + + msp3400c_setcarrier(client, msp_init_data[type].cdo1, + msp_init_data[type].cdo2); + + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + + if (dolby) { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + 0x0520); /* I2S1 */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + 0x0620); /* I2S2 */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, + msp_init_data[type].dfp_src); + } else { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + msp_init_data[type].dfp_src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + msp_init_data[type].dfp_src); + } + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, + msp_init_data[type].dfp_src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, + msp_init_data[type].dfp_matrix); + + if (msp->nicam) { + /* nicam prescale */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ + } +} + +/* turn on/off nicam + stereo */ +static void msp3400c_setstereo(struct i2c_client *client, int mode) +{ + struct msp3400c *msp = client->data; + int nicam=0; /* channel source: FM/AM or nicam */ + int src=0; + + /* switch demodulator */ + switch (msp->mode) { + case MSP_MODE_FM_TERRA: + dprintk("msp3400: FM setstereo: %d\n",mode); + msp3400c_setcarrier(client,msp->second,msp->main); + switch (mode) { + case VIDEO_SOUND_STEREO: + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); + break; + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_LANG1: + case VIDEO_SOUND_LANG2: + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); + break; + } + break; + case MSP_MODE_FM_SAT: + dprintk("msp3400: SAT setstereo: %d\n",mode); + switch (mode) { + case VIDEO_SOUND_MONO: + msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + break; + case VIDEO_SOUND_STEREO: + msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + break; + case VIDEO_SOUND_LANG1: + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + case VIDEO_SOUND_LANG2: + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + } + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + dprintk("msp3400: NICAM setstereo: %d\n",mode); + msp3400c_setcarrier(client,msp->second,msp->main); + if (msp->nicam_on) + nicam=0x0100; + break; + case MSP_MODE_BTSC: + dprintk("msp3400: BTSC setstereo: %d\n",mode); + nicam=0x0300; + break; + default: + dprintk("msp3400: mono setstereo\n"); + return; + } + + /* switch audio */ + switch (mode) { + case VIDEO_SOUND_STEREO: + src = 0x0020 | nicam; +#if 0 + /* spatial effect */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); +#endif + break; + case VIDEO_SOUND_MONO: + if (msp->mode == MSP_MODE_AM_NICAM) { + dprintk("msp3400: switching to AM mono\n"); + /* AM mono decoding is handled by tuner, not MSP chip */ + /* so let's redirect sound from tuner via SCART */ + /* volume prescale for SCART */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); + /* SCART switching control register*/ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900); + src = 0x0200; + break; + } + case VIDEO_SOUND_LANG1: + src = 0x0000 | nicam; + break; + case VIDEO_SOUND_LANG2: + src = 0x0010 | nicam; + break; + } + if (dolby) { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); + } else { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + } +} + +static void +msp3400c_print_mode(struct msp3400c *msp) +{ + if (msp->main == msp->second) { + printk("msp3400: mono sound carrier: %d.%03d MHz\n", + msp->main/910000,(msp->main/910)%1000); + } else { + printk("msp3400: main sound carrier: %d.%03d MHz\n", + msp->main/910000,(msp->main/910)%1000); + } + if (msp->mode == MSP_MODE_FM_NICAM1 || + msp->mode == MSP_MODE_FM_NICAM2) + printk("msp3400: NICAM/FM carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + if (msp->mode == MSP_MODE_AM_NICAM) + printk("msp3400: NICAM/AM carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + if (msp->mode == MSP_MODE_FM_TERRA && + msp->main != msp->second) { + printk("msp3400: FM-stereo carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + } +} + +/* ----------------------------------------------------------------------- */ + +struct REGISTER_DUMP { + int addr; + char *name; +}; + +struct REGISTER_DUMP d1[] = { + { 0x007e, "autodetect" }, + { 0x0023, "C_AD_BITS " }, + { 0x0038, "ADD_BITS " }, + { 0x003e, "CIB_BITS " }, + { 0x0057, "ERROR_RATE" }, +}; + +static int +autodetect_stereo(struct i2c_client *client) +{ + struct msp3400c *msp = client->data; + int val; + int newstereo = msp->stereo; + int newnicam = msp->nicam_on; + int update = 0; + + switch (msp->mode) { + case MSP_MODE_FM_TERRA: + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); + if (val > 32768) + val -= 65536; + dprintk("msp34xx: stereo detect register: %d\n",val); + + if (val > 4096) { + newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO; + } else if (val < -4096) { + newstereo = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } else { + newstereo = VIDEO_SOUND_MONO; + } + newnicam = 0; + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); + dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1); + + if (val & 1) { + /* nicam synced */ + switch ((val & 0x1e) >> 1) { + case 0: + case 8: + newstereo = VIDEO_SOUND_STEREO; + break; + case 1: + case 9: + newstereo = VIDEO_SOUND_MONO + | VIDEO_SOUND_LANG1; + break; + case 2: + case 10: + newstereo = VIDEO_SOUND_MONO + | VIDEO_SOUND_LANG1 + | VIDEO_SOUND_LANG2; + break; + default: + newstereo = VIDEO_SOUND_MONO; + break; + } + newnicam=1; + } else { + newnicam = 0; + newstereo = VIDEO_SOUND_MONO; + } + break; + case MSP_MODE_BTSC: + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); + dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", + val, + (val & 0x0002) ? "no" : "yes", + (val & 0x0004) ? "no" : "yes", + (val & 0x0040) ? "stereo" : "mono", + (val & 0x0080) ? ", nicam 2nd mono" : "", + (val & 0x0100) ? ", bilingual/SAP" : ""); + newstereo = VIDEO_SOUND_MONO; + if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO; + if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1; + break; + } + if (newstereo != msp->stereo) { + update = 1; + dprintk("msp34xx: watch: stereo %d => %d\n", + msp->stereo,newstereo); + msp->stereo = newstereo; + } + if (newnicam != msp->nicam_on) { + update = 1; + dprintk("msp34xx: watch: nicam %d => %d\n", + msp->nicam_on,newnicam); + msp->nicam_on = newnicam; + } + return update; +} + +/* + * A kernel thread for msp3400 control -- we don't want to block the + * in the ioctl while doing the sound carrier & stereo detect + */ + +static void msp3400c_stereo_wake(unsigned long data) +{ + struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */ + + wake_up_interruptible(&msp->wq); +} + +/* stereo/multilang monitoring */ +static void watch_stereo(struct i2c_client *client) +{ + struct msp3400c *msp = client->data; + + if (autodetect_stereo(client)) { + if (msp->stereo & VIDEO_SOUND_STEREO) + msp3400c_setstereo(client,VIDEO_SOUND_STEREO); + else if (msp->stereo & VIDEO_SOUND_LANG1) + msp3400c_setstereo(client,VIDEO_SOUND_LANG1); + else + msp3400c_setstereo(client,VIDEO_SOUND_MONO); + } + if (once) + msp->watch_stereo = 0; + if (msp->watch_stereo) + mod_timer(&msp->wake_stereo, jiffies+5*HZ); +} + +static int msp3400c_thread(void *data) +{ + struct i2c_client *client = data; + struct msp3400c *msp = client->data; + + struct CARRIER_DETECT *cd; + int count, max1,max2,val1,val2, val,this; + +#ifdef CONFIG_SMP + lock_kernel(); +#endif + + daemonize(); + sigfillset(¤t->blocked); + strcpy(current->comm,"msp3400"); + + msp->thread = current; + +#ifdef CONFIG_SMP + unlock_kernel(); +#endif + + printk("msp3400: daemon started\n"); + if(msp->notify != NULL) + up(msp->notify); + + for (;;) { + if (msp->rmmod) + goto done; + if (debug > 1) + printk("msp3400: thread: sleep\n"); + interruptible_sleep_on(&msp->wq); + if (debug > 1) + printk("msp3400: thread: wakeup\n"); + if (msp->rmmod || signal_pending(current)) + goto done; + + if (VIDEO_MODE_RADIO == msp->norm) + continue; /* nothing to do */ + + msp->active = 1; + + if (msp->watch_stereo) { + watch_stereo(client); + msp->active = 0; + continue; + } + + /* some time for the tuner to sync */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/5); + if (signal_pending(current)) + goto done; + + restart: + msp->restart = 0; + msp3400c_setvolume(client, 0, 0); + msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); + val1 = val2 = 0; + max1 = max2 = -1; + del_timer(&msp->wake_stereo); + msp->watch_stereo = 0; + + /* carrier detect pass #1 -- main carrier */ + cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); + + if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { + /* autodetect doesn't work well with AM ... */ + max1 = 3; + count = 0; + dprintk("msp3400: AM sound override\n"); + } + + for (this = 0; this < count; this++) { + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + if (signal_pending(current)) + goto done; + if (msp->restart) + msp->restart = 0; + + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; + if (val1 < val) + val1 = val, max1 = this; + dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); + } + + /* carrier detect pass #2 -- second (stereo) carrier */ + switch (max1) { + case 1: /* 5.5 */ + cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55); + break; + case 3: /* 6.5 */ + cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65); + break; + case 0: /* 4.5 */ + case 2: /* 6.0 */ + default: + cd = NULL; count = 0; + break; + } + + if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { + /* autodetect doesn't work well with AM ... */ + cd = NULL; count = 0; max2 = 0; + } + for (this = 0; this < count; this++) { + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + if (signal_pending(current)) + goto done; + if (msp->restart) + goto restart; + + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; + if (val2 < val) + val2 = val, max2 = this; + dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); + } + + /* programm the msp3400 according to the results */ + msp->main = carrier_detect_main[max1].cdo; + switch (max1) { + case 1: /* 5.5 */ + if (max2 == 0) { + /* B/G FM-stereo */ + msp->second = carrier_detect_55[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + } else if (max2 == 1 && msp->nicam) { + /* B/G NICAM */ + msp->second = carrier_detect_55[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); + msp->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 2: /* 6.0 */ + /* PAL I NICAM */ + msp->second = MSP_CARRIER(6.552); + msp3400c_setmode(client, MSP_MODE_FM_NICAM2); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); + msp->watch_stereo = 1; + break; + case 3: /* 6.5 */ + if (max2 == 1 || max2 == 2) { + /* D/K FM-stereo */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + } else if (max2 == 0 && + msp->norm == VIDEO_MODE_SECAM) { + /* L NICAM or AM-mono */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_AM_NICAM); + msp->nicam_on = 0; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + msp3400c_setcarrier(client, msp->second, msp->main); + msp->watch_stereo = 1; + } else if (max2 == 0 && msp->nicam) { + /* D/K NICAM */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); + msp->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 0: /* 4.5 */ + default: + no_second: + msp->second = carrier_detect_main[max1].cdo; + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + msp->nicam_on = 0; + msp3400c_setcarrier(client, msp->second, msp->main); + msp->stereo = VIDEO_SOUND_MONO; + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + break; + } + + /* unmute */ + msp3400c_setvolume(client, msp->left, msp->right); + + if (msp->watch_stereo) + mod_timer(&msp->wake_stereo, jiffies+5*HZ); + + if (debug) + msp3400c_print_mode(msp); + + msp->active = 0; + } + +done: + dprintk("msp3400: thread: exit\n"); + msp->active = 0; + msp->thread = NULL; + + if(msp->notify != NULL) + up(msp->notify); + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* this one uses the automatic sound standard detection of newer */ +/* msp34xx chip versions */ + +static struct MODES { + int retval; + int main, second; + char *name; +} modelist[] = { + { 0x0000, 0, 0, "ERROR" }, + { 0x0001, 0, 0, "autodetect start" }, + { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, + { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, + { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, + { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, + { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, + { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, + { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, + { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, + { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, + { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, + { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, + { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, + { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, + { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, + { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, + { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, + { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, + { -1, 0, 0, NULL }, /* EOF */ +}; + +static int msp3410d_thread(void *data) +{ + struct i2c_client *client = data; + struct msp3400c *msp = client->data; + int mode,val,i,std; + +#ifdef CONFIG_SMP + lock_kernel(); +#endif + + daemonize(); + sigfillset(¤t->blocked); + strcpy(current->comm,"msp3410 [auto]"); + + msp->thread = current; + +#ifdef CONFIG_SMP + unlock_kernel(); +#endif + + printk("msp3410: daemon started\n"); + if(msp->notify != NULL) + up(msp->notify); + + for (;;) { + if (msp->rmmod) + goto done; + if (debug > 1) + printk("msp3410: thread: sleep\n"); + interruptible_sleep_on(&msp->wq); + if (debug > 1) + printk("msp3410: thread: wakeup\n"); + if (msp->rmmod || signal_pending(current)) + goto done; + + if (VIDEO_MODE_RADIO == msp->norm) + continue; /* nothing to do */ + + msp->active = 1; + + if (msp->watch_stereo) { + watch_stereo(client); + msp->active = 0; + continue; + } + + /* some time for the tuner to sync */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/5); + if (signal_pending(current)) + goto done; + + restart: + msp->restart = 0; + del_timer(&msp->wake_stereo); + msp->watch_stereo = 0; + + /* put into sane state (and mute) */ + msp3400c_reset(client); + + /* start autodetect */ + switch (msp->norm) { + case VIDEO_MODE_PAL: + mode = 0x1003; + std = 1; + break; + case VIDEO_MODE_NTSC: /* BTSC */ + mode = 0x2003; + std = 0x0020; + break; + case VIDEO_MODE_SECAM: + mode = 0x0003; + std = 1; + break; + default: + mode = 0x0003; + std = 1; + break; + } + msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); + if (debug) { + int i; + for (i = 0; modelist[i].name != NULL; i++) + if (modelist[i].retval == std) + break; + printk("msp3410: setting mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown",std); + } + + if (std != 1) { + /* programmed some specific mode */ + val = std; + } else { + /* triggered autodetect */ + for (;;) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + if (signal_pending(current)) + goto done; + if (msp->restart) + goto restart; + + /* check results */ + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); + if (val < 0x07ff) + break; + dprintk("msp3410: detection still in progress\n"); + } + } + for (i = 0; modelist[i].name != NULL; i++) + if (modelist[i].retval == val) + break; + dprintk("msp3410: current mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown", + val); + msp->main = modelist[i].main; + msp->second = modelist[i].second; + + if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { + /* autodetection has failed, let backup */ + dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n", + modelist[8].name ? modelist[8].name : "unknown",val); + val = 0x0009; + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); + } + + /* set prescale / stereo */ + switch (val) { + case 0x0009: + msp->mode = MSP_MODE_AM_NICAM; + msp->stereo = VIDEO_SOUND_MONO; + msp3400c_setstereo(client,VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + break; + case 0x0020: /* BTSC */ + /* just turn on stereo */ + msp->mode = MSP_MODE_BTSC; + msp->stereo = VIDEO_SOUND_STEREO; + msp->watch_stereo = 1; + msp3400c_setstereo(client,VIDEO_SOUND_STEREO); + /* set prescale */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ + break; + case 0x0003: + msp->mode = MSP_MODE_FM_TERRA; + msp->stereo = VIDEO_SOUND_MONO; + msp->watch_stereo = 1; + /* fall */ + default: + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */ + break; + } + + /* unmute */ + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->left, msp->right); + + if (msp->watch_stereo) + mod_timer(&msp->wake_stereo, jiffies+HZ); + + msp->active = 0; + } + +done: + dprintk("msp3410: thread: exit\n"); + msp->active = 0; + msp->thread = NULL; + + if(msp->notify != NULL) + up(msp->notify); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int msp_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind); +static int msp_detach(struct i2c_client *client); +static int msp_probe(struct i2c_adapter *adap); +static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); + +static struct i2c_driver driver = { + "i2c msp3400 driver", + I2C_DRIVERID_MSP3400, + I2C_DF_NOTIFY, + msp_probe, + msp_detach, + msp_command, +}; + +static struct i2c_client client_template = +{ + "unset", + -1, + 0, + 0, + NULL, + &driver +}; + +static int msp_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + DECLARE_MUTEX_LOCKED(sem); + struct msp3400c *msp; + struct i2c_client *c; + int rev1,rev2,i; + + client_template.adapter = adap; + client_template.addr = addr; + + if (-1 == msp3400c_reset(&client_template)) { + dprintk("msp3400: no chip found\n"); + return -1; + } + + if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(c,&client_template,sizeof(struct i2c_client)); + if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { + kfree(c); + return -ENOMEM; + } + + memset(msp,0,sizeof(struct msp3400c)); + msp->left = 65535; + msp->right = 65535; + msp->bass = 32768; + msp->treble = 32768; + c->data = msp; + init_waitqueue_head(&msp->wq); + + if (-1 == msp3400c_reset(c)) { + kfree(msp); + dprintk("msp3400: no chip found\n"); + return -1; + } + + rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e); + rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f); + if (0 == rev1 && 0 == rev2) { + kfree(msp); + printk("msp3400: error while reading chip version\n"); + return -1; + } + +#if 0 + /* this will turn on a 1kHz beep - might be useful for debugging... */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0014, 0x1040); +#endif + + sprintf(c->name,"MSP34%02d%c-%c%d", + (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); + msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; + + if (simple == -1) { + /* default mode */ + /* msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; */ + msp->simple = ((rev1&0xff)+'@' > 'C'); + } else { + /* use insmod option */ + msp->simple = simple; + } + + /* timer for stereo checking */ + msp->wake_stereo.function = msp3400c_stereo_wake; + msp->wake_stereo.data = (unsigned long)msp; + + /* hello world :-) */ + printk(KERN_INFO "msp3400: init: chip=%s",c->name); + if (msp->nicam) + printk(", has NICAM support"); + printk("\n"); + + /* startup control thread */ + MOD_INC_USE_COUNT; + msp->notify = &sem; + kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread, + (void *)c, 0); + down(&sem); + msp->notify = NULL; + wake_up_interruptible(&msp->wq); + +#ifdef REGISTER_MIXER + if ((msp->mixer_num = register_sound_mixer(&msp3400c_mixer_fops,mixer)) < 0) + printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); +#endif + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (NULL == msps[i]) { + msps[i] = c; + break; + } + } + + /* done */ + i2c_attach_client(c); + return 0; +} + +static int msp_detach(struct i2c_client *client) +{ + DECLARE_MUTEX_LOCKED(sem); + struct msp3400c *msp = (struct msp3400c*)client->data; + int i; + +#ifdef REGISTER_MIXER + if (msp->mixer_num >= 0) + unregister_sound_mixer(msp->mixer_num); +#endif + + /* shutdown control thread */ + del_timer(&msp->wake_stereo); + if (msp->thread) + { + msp->notify = &sem; + msp->rmmod = 1; + wake_up_interruptible(&msp->wq); + down(&sem); + msp->notify = NULL; + } + msp3400c_reset(client); + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (client == msps[i]) { + msps[i] = NULL; + break; + } + } + + i2c_detach_client(client); + kfree(msp); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int msp_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, msp_attach); + return 0; +} + +static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) +{ + struct msp3400c *msp = (struct msp3400c*)client->data; +#if 0 + int *iarg = (int*)arg; + __u16 *sarg = arg; +#endif + + switch (cmd) { + + case AUDC_SET_RADIO: + msp->norm = VIDEO_MODE_RADIO; + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + if (msp->simple) { + msp3400c_reset(client); + msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, 0x0003); /* automatic */ + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, 0x0040); /* FM Radio */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM prescale */ + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->left, msp->right); + } else { + msp3400c_setmode(client,MSP_MODE_FM_RADIO); + msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); + msp3400c_setvolume(client,msp->left, msp->right); + } + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(msp->left,msp->right); + va->balance=(32768*MIN(msp->left,msp->right))/ + (va->volume ? va->volume : 1); + va->balance=(msp->leftright)? + (65535-va->balance) : va->balance; + va->bass = msp->bass; + va->treble = msp->treble; + + autodetect_stereo(client); + va->mode = msp->stereo; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + msp->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + msp->right = (MIN(va->balance,32768) * + va->volume) / 32768; + msp->bass = va->bass; + msp->treble = va->treble; + msp3400c_setvolume(client,msp->left, msp->right); + msp3400c_setbass(client,msp->bass); + msp3400c_settreble(client,msp->treble); + + if (va->mode != 0) { + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + msp->stereo = va->mode; + msp3400c_setstereo(client,va->mode); + } + break; + } + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + msp->norm = vc->norm; + break; + } + case VIDIOCSFREQ: + { + /* new channel -- kick audio carrier scan */ + msp3400c_setvolume(client,0,0); + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + if (msp->active) + msp->restart = 1; + wake_up_interruptible(&msp->wq); + break; + } + + /* --- v4l2 ioctls --- */ + /* NOT YET */ + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_SET_TVNORM: + msp->norm = *iarg; + break; + case AUDC_SWITCH_MUTE: + /* channels switching step one -- mute */ + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + msp3400c_setvolume(client,0,0); + break; + case AUDC_NEWCHANNEL: + /* channels switching step two -- trigger sound carrier scan */ + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + if (msp->active) + msp->restart = 1; + wake_up_interruptible(&msp->wq); + break; + + case AUDC_GET_VOLUME_LEFT: + *sarg = msp->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = msp->right; + break; + case AUDC_SET_VOLUME_LEFT: + msp->left = *sarg; + msp3400c_setvolume(client,msp->left, msp->right); + break; + case AUDC_SET_VOLUME_RIGHT: + msp->right = *sarg; + msp3400c_setvolume(client,msp->left, msp->right); + break; + + case AUDC_GET_BASS: + *sarg = msp->bass; + break; + case AUDC_SET_BASS: + msp->bass = *sarg; + msp3400c_setbass(client,msp->bass); + break; + + case AUDC_GET_TREBLE: + *sarg = msp->treble; + break; + case AUDC_SET_TREBLE: + msp->treble = *sarg; + msp3400c_settreble(client,msp->treble); + break; + + case AUDC_GET_STEREO: + autodetect_stereo(client); + *sarg = msp->stereo; + break; + case AUDC_SET_STEREO: + if (*sarg) { + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + msp->stereo = *sarg; + msp3400c_setstereo(client,*sarg); + } + break; + + case AUDC_GET_DC: + if (msp->simple) + break; /* fixme */ + *sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) + + (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c)); + break; +#endif + default: + /* nothing */ + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int msp3400_init_module(void) +{ + i2c_add_driver(&driver); + return 0; +} + +void msp3400_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(msp3400_init_module); +module_exit(msp3400_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c --- v2.4.0-test6/linux/drivers/media/video/planb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/planb.c Mon Aug 7 21:01:36 2000 @@ -0,0 +1,2341 @@ +/* + planb - PlanB frame grabber driver + + PlanB is used in the 7x00/8x00 series of PowerMacintosh + Computers as video input DMA controller. + + Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) + + Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) + + Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) + + 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. +*/ + +/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "planb.h" +#include "saa7196.h" + + +/* Would you mind for some ugly debugging? */ +//#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */ +#define DEBUG(x...) /* Don't debug driver */ +//#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */ +#define IDEBUG(x...) /* Don't debug interrupt part */ + +/* Ever seen a Mac with more than 1 of these? */ +#define PLANB_MAX 1 + +static int planb_num; +static struct planb planbs[PLANB_MAX]; +static volatile struct planb_registers *planb_regs; + +static int def_norm = PLANB_DEF_NORM; /* default norm */ + +MODULE_PARM(def_norm, "i"); +MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); + +/* ------------------ PlanB Exported Functions ------------------ */ +static long planb_write(struct video_device *, const char *, unsigned long, int); +static long planb_read(struct video_device *, char *, unsigned long, int); +static int planb_open(struct video_device *, int); +static void planb_close(struct video_device *); +static int planb_ioctl(struct video_device *, unsigned int, void *); +static int planb_init_done(struct video_device *); +static int planb_mmap(struct video_device *, const char *, unsigned long); +static void planb_irq(int, void *, struct pt_regs *); +static void release_planb(void); +int init_planbs(struct video_init *); + +/* ------------------ PlanB Internal Functions ------------------ */ +static int planb_prepare_open(struct planb *); +static void planb_prepare_close(struct planb *); +static void saa_write_reg(unsigned char, unsigned char); +static unsigned char saa_status(int, struct planb *); +static void saa_set(unsigned char, unsigned char, struct planb *); +static void saa_init_regs(struct planb *); +static int grabbuf_alloc(struct planb *); +static int vgrab(struct planb *, struct video_mmap *); +static void add_clip(struct planb *, struct video_clip *); +static void fill_cmd_buff(struct planb *); +static void cmd_buff(struct planb *); +static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *); +static void overlay_start(struct planb *); +static void overlay_stop(struct planb *); +static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short, + unsigned int); +static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int, + unsigned int); +static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short, + unsigned short, unsigned int, unsigned int); +static int init_planb(struct planb *); +static int find_planb(void); +static void planb_pre_capture(int, int, struct planb *); +static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *, + int, int, int, int, int, struct planb *); +static inline void planb_dbdma_stop(volatile struct dbdma_regs *); +static unsigned int saa_geo_setup(int, int, int, int, struct planb *); +static inline int overlay_is_active(struct planb *); + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +static int grabbuf_alloc(struct planb *pb) +{ + int i, npage; + + npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1) +#ifndef PLANB_GSCANLINE + + MAX_LNUM +#endif /* PLANB_GSCANLINE */ + ); + if ((pb->rawbuf = (unsigned char**) kmalloc (npage + * sizeof(unsigned long), GFP_KERNEL)) == 0) + return -ENOMEM; + for (i = 0; i < npage; i++) { + pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL + |GFP_DMA, 0); + if (!pb->rawbuf[i]) + break; + mem_map_reserve(virt_to_page(pb->rawbuf[i])); + } + if (i-- < npage) { + printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); + for (; i > 0; i--) { + mem_map_unreserve(virt_to_page(pb->rawbuf[i])); + free_pages((unsigned long)pb->rawbuf[i], 0); + } + kfree(pb->rawbuf); + return -ENOBUFS; + } + pb->rawbuf_size = npage; + return 0; +} + +/*****************************/ +/* Hardware access functions */ +/*****************************/ + +static void saa_write_reg(unsigned char addr, unsigned char val) +{ + planb_regs->saa_addr = addr; eieio(); + planb_regs->saa_regval = val; eieio(); + return; +} + +/* return status byte 0 or 1: */ +static unsigned char saa_status(int byte, struct planb *pb) +{ + saa_regs[pb->win.norm][SAA7196_STDC] = + (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1); + saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]); + + /* Let's wait 30msec for this one */ + current->state = TASK_INTERRUPTIBLE; +#if LINUX_VERSION_CODE >= 0x02017F + schedule_timeout(30 * HZ / 1000); +#else + current->timeout = jiffies + 30 * HZ / 1000; /* 30 ms */; + schedule(); +#endif + + return (unsigned char)in_8 (&planb_regs->saa_status); +} + +static void saa_set(unsigned char addr, unsigned char val, struct planb *pb) +{ + if(saa_regs[pb->win.norm][addr] != val) { + saa_regs[pb->win.norm][addr] = val; + saa_write_reg (addr, val); + } + return; +} + +static void saa_init_regs(struct planb *pb) +{ + int i; + + for (i = 0; i < SAA7196_NUMREGS; i++) + saa_write_reg (i, saa_regs[pb->win.norm][i]); +} + +static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp, + struct planb *pb) +{ + int ht, norm = pb->win.norm; + + switch(bpp) { + case 2: + /* RGB555+a 1x16-bit + 16-bit transparent */ + saa_regs[norm][SAA7196_FMTS] &= ~0x3; + break; + case 1: + case 4: + /* RGB888 1x24-bit + 8-bit transparent */ + saa_regs[norm][SAA7196_FMTS] &= ~0x1; + saa_regs[norm][SAA7196_FMTS] |= 0x2; + break; + default: + return -EINVAL; + } + ht = (interlace ? height / 2 : height); + saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff); + saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3) + | (width >> 8 & 0x3); + saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff); + saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3) + | (ht >> 8 & 0x3); + /* feed both fields if interlaced, or else feed only even fields */ + saa_regs[norm][SAA7196_FMTS] = (interlace) ? + (saa_regs[norm][SAA7196_FMTS] & ~0x60) + : (saa_regs[norm][SAA7196_FMTS] | 0x60); + /* transparent mode; extended format enabled */ + saa_regs[norm][SAA7196_DPATH] |= 0x3; + + return 0; +} + +/***************************/ +/* DBDMA support functions */ +/***************************/ + +static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch) +{ + out_le32(&ch->control, PLANB_CLR(RUN)); + out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE)); +} + +static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch) +{ + int i = 0; + + out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH)); + while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { + IDEBUG("PlanB: waiting for DMA to stop\n"); + i++; + } +} + +static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch, + unsigned short command, unsigned int cmd_dep) +{ + st_le16(&ch->command, command); + st_le32(&ch->cmd_dep, cmd_dep); +} + +static inline void tab_cmd_store(volatile struct dbdma_cmd *ch, + unsigned int phy_addr, unsigned int cmd_dep) +{ + st_le16(&ch->command, STORE_WORD | KEY_SYSTEM); + st_le16(&ch->req_count, 4); + st_le32(&ch->phy_addr, phy_addr); + st_le32(&ch->cmd_dep, cmd_dep); +} + +static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch, + unsigned short command, unsigned short req_count, + unsigned int phy_addr, unsigned int cmd_dep) +{ + st_le16(&ch->command, command); + st_le16(&ch->req_count, req_count); + st_le32(&ch->phy_addr, phy_addr); + st_le32(&ch->cmd_dep, cmd_dep); +} + +static volatile struct dbdma_cmd *cmd_geo_setup( + volatile struct dbdma_cmd *c1, int width, int height, int interlace, + int bpp, int clip, struct planb *pb) +{ + int norm = pb->win.norm; + + if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0) + return (volatile struct dbdma_cmd *)NULL; + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_FMTS); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_FMTS]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_DPATH); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_DPATH]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even), + bpp | ((clip)? PLANB_CLIPMASK: 0)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd), + bpp | ((clip)? PLANB_CLIPMASK: 0)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_OUTPIX); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_OUTPIX]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_HFILT); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_HFILT]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_OUTLINE); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_OUTLINE]); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), + SAA7196_VYP); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), + saa_regs[norm][SAA7196_VYP]); + return c1; +} + +/******************************/ +/* misc. supporting functions */ +/******************************/ + +static void __planb_wait(struct planb *pb) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&pb->lockq, &wait); +repeat: + set_current_state(TASK_UNINTERRUPTIBLE); + if (pb->lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&pb->lockq, &wait); + current->state = TASK_RUNNING; +} + +static inline void planb_wait(struct planb *pb) +{ + DEBUG("PlanB: planb_wait\n"); + if(pb->lock) + __planb_wait(pb); +} + +static inline void planb_lock(struct planb *pb) +{ + DEBUG("PlanB: planb_lock\n"); + if(pb->lock) + __planb_wait(pb); + pb->lock = 1; +} + +static inline void planb_unlock(struct planb *pb) +{ + DEBUG("PlanB: planb_unlock\n"); + pb->lock = 0; + wake_up(&pb->lockq); +} + +/***************/ +/* Driver Core */ +/***************/ + +static int planb_prepare_open(struct planb *pb) +{ + int i, size; + + /* allocate memory for two plus alpha command buffers (size: max lines, + plus 40 commands handling, plus 1 alignment), plus dummy command buf, + plus clipmask buffer, plus frame grabbing status */ + size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS + * PLANB_DUMMY)*sizeof(struct dbdma_cmd) + +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 + +MAX_GBUFFERS*sizeof(unsigned int); + if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0) + return -ENOMEM; + memset ((void *) pb->priv_space, 0, size); + pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) + DBDMA_ALIGN (pb->priv_space); + pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; + pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd); + pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size; + pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR; + for (i = 1; i < MAX_GBUFFERS; i++) { + pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY; + pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR; + } + pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1] + + PLANB_DUMMY); + pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); + + pb->rawbuf = NULL; + pb->rawbuf_size = 0; + pb->grabbing = 0; + for (i = 0; i < MAX_GBUFFERS; i++) { + pb->frame_stat[i] = GBUFFER_UNUSED; + pb->gwidth[i] = 0; + pb->gheight[i] = 0; + pb->gfmt[i] = 0; + pb->gnorm_switch[i] = 0; +#ifndef PLANB_GSCANLINE + pb->lsize[i] = 0; + pb->lnum[i] = 0; +#endif /* PLANB_GSCANLINE */ + } + pb->gcount = 0; + pb->suspend = 0; + pb->last_fr = -999; + pb->prev_last_fr = -999; + + /* Reset DMA controllers */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + return 0; +} + +static void planb_prepare_close(struct planb *pb) +{ + int i; + + /* make sure the dma's are idle */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + /* free kernel memory of command buffers */ + if(pb->priv_space != 0) { + kfree (pb->priv_space); + pb->priv_space = 0; + pb->cmd_buff_inited = 0; + } + if(pb->rawbuf) { + for (i = 0; i < pb->rawbuf_size; i++) { + mem_map_unreserve(virt_to_page(pb->rawbuf[i])); + free_pages((unsigned long)pb->rawbuf[i], 0); + } + kfree(pb->rawbuf); + } + pb->rawbuf = NULL; +} + +/*****************************/ +/* overlay support functions */ +/*****************************/ + +static void overlay_start(struct planb *pb) +{ + + DEBUG("PlanB: overlay_start()\n"); + + if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + + DEBUG("PlanB: presumably, grabbing is in progress...\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + out_le32 (&pb->planb_base->ch2.cmdptr, + virt_to_bus(pb->ch2_cmd)); + planb_dbdma_restart(&pb->planb_base->ch2); + st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->ch1_cmd)); + eieio(); + pb->prev_last_fr = pb->last_fr; + pb->last_fr = -2; + if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + IDEBUG("PlanB: became inactive " + "in the mean time... reactivating\n"); + planb_dbdma_stop(&pb->planb_base->ch1); + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->ch1_cmd)); + planb_dbdma_restart(&pb->planb_base->ch1); + } + } else { + + DEBUG("PlanB: currently idle, so can do whatever\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + st_le32 (&pb->planb_base->ch2.cmdptr, + virt_to_bus(pb->ch2_cmd)); + st_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->ch1_cmd)); + out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + planb_dbdma_restart(&pb->planb_base->ch2); + planb_dbdma_restart(&pb->planb_base->ch1); + pb->last_fr = -1; + } + return; +} + +static void overlay_stop(struct planb *pb) +{ + DEBUG("PlanB: overlay_stop()\n"); + + if(pb->last_fr == -1) { + + DEBUG("PlanB: no grabbing, it seems...\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + pb->last_fr = -999; + } else if(pb->last_fr == -2) { + unsigned int cmd_dep; + tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); + eieio(); + cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); + if(overlay_is_active(pb)) { + + DEBUG("PlanB: overlay is currently active\n"); + + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + if(cmd_dep != pb->ch1_cmd_phys) { + out_le32(&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->overlay_last1)); + planb_dbdma_restart(&pb->planb_base->ch1); + } + } + pb->last_fr = pb->prev_last_fr; + pb->prev_last_fr = -999; + } + return; +} + +static void suspend_overlay(struct planb *pb) +{ + int fr = -1; + struct dbdma_cmd last; + + DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); + + if(pb->suspend++) + return; + if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + if(pb->last_fr == -2) { + fr = pb->prev_last_fr; + memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); + tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + } + if(overlay_is_active(pb)) { + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + pb->suspended.overlay = 1; + pb->suspended.frame = fr; + memcpy(&pb->suspended.cmd, &last, sizeof(last)); + return; + } + } + pb->suspended.overlay = 0; + pb->suspended.frame = fr; + memcpy(&pb->suspended.cmd, &last, sizeof(last)); + return; +} + +static void resume_overlay(struct planb *pb) +{ + + DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); + + if(pb->suspend > 1) + return; + if(pb->suspended.frame != -1) { + memcpy((void*)pb->last_cmd[pb->suspended.frame], + &pb->suspended.cmd, sizeof(pb->suspended.cmd)); + } + if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { + goto finish; + } + if(pb->suspended.overlay) { + + DEBUG("PlanB: overlay being resumed\n"); + + st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); + st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); + /* Set command buffer addresses */ + st_le32(&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->overlay_last1)); + out_le32(&pb->planb_base->ch2.cmdptr, + virt_to_bus(pb->overlay_last2)); + /* Start the DMA controller */ + out_le32 (&pb->planb_base->ch2.control, + PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + out_le32 (&pb->planb_base->ch1.control, + PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + } else if(pb->suspended.frame != -1) { + out_le32(&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->last_cmd[pb->suspended.frame])); + out_le32 (&pb->planb_base->ch1.control, + PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); + } + +finish: + pb->suspend--; + wake_up_interruptible(&pb->suspendq); +} + +static void add_clip(struct planb *pb, struct video_clip *clip) +{ + volatile unsigned char *base; + int xc = clip->x, yc = clip->y; + int wc = clip->width, hc = clip->height; + int ww = pb->win.width, hw = pb->win.height; + int x, y, xtmp1, xtmp2; + + DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); + + if(xc < 0) { + wc += xc; + xc = 0; + } + if(yc < 0) { + hc += yc; + yc = 0; + } + if(xc + wc > ww) + wc = ww - xc; + if(wc <= 0) /* Nothing to do */ + return; + if(yc + hc > hw) + hc = hw - yc; + + for (y = yc; y < yc+hc; y++) { + xtmp1=xc>>3; + xtmp2=(xc+wc)>>3; + base = pb->mask + y*96; + if(xc != 0 || wc >= 8) + *(base + xtmp1) &= (unsigned char)(0x00ff & + (0xff00 >> (xc&7))); + for (x = xtmp1 + 1; x < xtmp2; x++) { + *(base + x) = 0; + } + if(xc < (ww & ~0x7)) + *(base + xtmp2) &= (unsigned char)(0x00ff >> + ((xc+wc) & 7)); + } + + return; +} + +static void fill_cmd_buff(struct planb *pb) +{ + int restore = 0; + volatile struct dbdma_cmd last; + + DEBUG("PlanB: fill_cmd_buff()\n"); + + if(pb->overlay_last1 != pb->ch1_cmd) { + restore = 1; + last = *(pb->overlay_last1); + } + memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size + * sizeof(struct dbdma_cmd)); + cmd_buff (pb); + if(restore) + *(pb->overlay_last1) = last; + if(pb->suspended.overlay) { + unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep); + if(jump_addr != pb->ch1_cmd_phys) { + int i; + + DEBUG("PlanB: adjusting ch1's jump address\n"); + + for(i = 0; i < MAX_GBUFFERS; i++) { + if(pb->need_pre_capture[i]) { + if(jump_addr == virt_to_bus(pb->pre_cmd[i])) + goto found; + } else { + if(jump_addr == virt_to_bus(pb->cap_cmd[i])) + goto found; + } + } + + DEBUG("PlanB: not found...\n"); + + goto out; +found: + if(pb->need_pre_capture[i]) + out_le32(&pb->pre_cmd[i]->phy_addr, + virt_to_bus(pb->overlay_last1)); + else + out_le32(&pb->cap_cmd[i]->phy_addr, + virt_to_bus(pb->overlay_last1)); + } + } +out: + pb->cmd_buff_inited = 1; + + return; +} + +static void cmd_buff(struct planb *pb) +{ + int i, bpp, count, nlines, stepsize, interlace; + unsigned long base, jump, addr_com, addr_dep; + volatile struct dbdma_cmd *c1 = pb->ch1_cmd; + volatile struct dbdma_cmd *c2 = pb->ch2_cmd; + + interlace = pb->win.interlace; + bpp = pb->win.bpp; + count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ? + (pb->win.swidth - pb->win.x) : pb->win.width)); + nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ? + (pb->win.sheight - pb->win.y) : pb->win.height); + + /* Do video in: */ + + /* Preamble commands: */ + addr_com = virt_to_bus(c1); + addr_dep = virt_to_bus(&c1->cmd_dep); + tab_cmd_dbdma(c1++, DBDMA_NOP, 0); + jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ + if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, + bpp, 1, pb)) == NULL) { + printk(KERN_WARNING "PlanB: encountered serious problems\n"); + tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); + tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); + return; + } + tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); + tab_cmd_store(c1++, addr_dep, jump); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); + /* (1) wait for field sync to be set */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + /* wait for field sync to be cleared */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + /* if not odd field, wait until field sync is set again */ + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; + /* assert ch_sync to ch2 */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), + PLANB_SET(CH_SYNC)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl + + pb->win.pad) + pb->win.x * bpp); + + if (interlace) { + stepsize = 2; + jump = virt_to_bus(c1 + (nlines + 1) / 2); + } else { + stepsize = 1; + jump = virt_to_bus(c1 + nlines); + } + + /* even field data: */ + for (i=0; i < nlines; i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, + count, base + i * (pb->win.bpl + pb->win.pad), jump); + + /* For non-interlaced, we use even fields only */ + if (!interlace) + goto cmd_tab_data_end; + + /* Resync to odd field */ + /* (2) wait for field sync to be set */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + /* wait for field sync to be cleared */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + /* if not odd field, wait until field sync is set again */ + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; + /* assert ch_sync to ch2 */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), + PLANB_SET(CH_SYNC)); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + /* odd field data: */ + jump = virt_to_bus(c1 + nlines / 2); + for (i=1; i < nlines; i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + base + i * (pb->win.bpl + pb->win.pad), jump); + + /* And jump back to the start */ +cmd_tab_data_end: + pb->overlay_last1 = c1; /* keep a pointer to the last command */ + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd)); + + /* Clipmask command buffer */ + + /* Preamble commands: */ + tab_cmd_dbdma(c2++, DBDMA_NOP, 0); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), + PLANB_SET(CH_SYNC)); + /* wait until ch1 asserts ch_sync */ + tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); + /* clear ch_sync asserted by ch1 */ + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control), + PLANB_CLR(CH_SYNC)); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), + PLANB_SET(FIELD_SYNC)); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + PLANB_SET(ODD_FIELD)); + + /* jump to end of even field if appropriate */ + /* this points to (interlace)? pos. C: pos. B */ + jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2): + virt_to_bus(c2 + nlines + 2); + /* if odd field, skip over to odd field clipmasking */ + tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); + + /* even field mask: */ + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + PLANB_SET(DMA_ABORT)); + /* this points to pos. B */ + jump = (interlace) ? virt_to_bus(c2 + nlines + 1): + virt_to_bus(c2 + nlines); + base = virt_to_bus(pb->mask); + for (i=0; i < nlines; i += stepsize, c2++) + tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, + base + i * 96, jump); + + /* For non-interlaced, we use only even fields */ + if(!interlace) + goto cmd_tab_mask_end; + + /* odd field mask: */ +/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), + PLANB_SET(DMA_ABORT)); + /* this points to pos. B */ + jump = virt_to_bus(c2 + nlines / 2); + base = virt_to_bus(pb->mask); + for (i=1; i < nlines; i += 2, c2++) /* abort if set */ + tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, + base + i * 96, jump); + + /* Inform channel 1 and jump back to start */ +cmd_tab_mask_end: + /* ok, I just realized this is kind of flawed. */ + /* this part is reached only after odd field clipmasking. */ + /* wanna clean up? */ + /* wait for field sync to be set */ + /* corresponds to fsync (1) of ch1 */ +/* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); + /* restart ch1, meant to clear any dead bit or something */ + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), + PLANB_CLR(RUN)); + tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), + PLANB_SET(RUN)); + pb->overlay_last2 = c2; /* keep a pointer to the last command */ + /* start over even field clipmasking */ + tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd)); + + eieio(); + return; +} + +/*********************************/ +/* grabdisplay support functions */ +/*********************************/ + +static int palette2fmt[] = { + 0, + PLANB_GRAY, + 0, + 0, + 0, + PLANB_COLOUR32, + PLANB_COLOUR15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +#define PLANB_PALETTE_MAX 15 + +static inline int overlay_is_active(struct planb *pb) +{ + unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); + unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr); + + return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys) + && (caddr < (pb->ch1_cmd_phys + size)) + && (caddr >= (unsigned)pb->ch1_cmd_phys); +} + +static int vgrab(struct planb *pb, struct video_mmap *mp) +{ + unsigned int fr = mp->frame; + unsigned int format; + + if(pb->rawbuf==NULL) { + int err; + if((err=grabbuf_alloc(pb))) + return err; + } + + IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, + mp->width, mp->height, fr); + + if(pb->grabbing >= MAX_GBUFFERS) + return -ENOBUFS; + if(fr > (MAX_GBUFFERS - 1) || fr < 0) + return -EINVAL; + if(mp->height <= 0 || mp->width <= 0) + return -EINVAL; + if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) + return -EINVAL; + if((format = palette2fmt[mp->format]) == 0) + return -EINVAL; + if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ + return -EINVAL; + + planb_lock(pb); + if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || + format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { + int i; +#ifndef PLANB_GSCANLINE + unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] + * pb->gfmt[fr]; + unsigned int nsize = mp->width * mp->height * format; +#endif + + IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", + mp->width, mp->height, mp->format); + +#ifndef PLANB_GSCANLINE + if(pb->gnorm_switch[fr]) + nsize = 0; + if (nsize < osize) { + for(i = pb->gbuf_idx[fr]; osize > 0; i++) { + memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); + osize -= PAGE_SIZE; + } + } + for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] + + pb->lnum[fr]; i++) + memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); +#else +/* XXX TODO */ +/* + if(pb->gnorm_switch[fr]) + memset((void *)pb->gbuffer[fr], 0, + pb->gbytes_per_line * pb->gheight[fr]); + else { + if(mp-> + for(i = 0; i < pb->gheight[fr]; i++) { + memset((void *)(pb->gbuffer[fr] + + pb->gbytes_per_line * i + } + } +*/ +#endif + pb->gwidth[fr] = mp->width; + pb->gheight[fr] = mp->height; + pb->gfmt[fr] = format; + pb->last_cmd[fr] = setup_grab_cmd(fr, pb); + planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */ + pb->need_pre_capture[fr] = 1; + pb->gnorm_switch[fr] = 0; + } else + pb->need_pre_capture[fr] = 0; + pb->frame_stat[fr] = GBUFFER_GRABBING; + if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + + IDEBUG("PlanB: ch1 inactive, initiating grabbing\n"); + + planb_dbdma_stop(&pb->planb_base->ch1); + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->pre_cmd[fr])); + } else { + tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + /* let's be on the safe side. here is not timing critical. */ + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0); + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->cap_cmd[fr])); + } + planb_dbdma_restart(&pb->planb_base->ch1); + pb->last_fr = fr; + } else { + int i; + + IDEBUG("PlanB: ch1 active, grabbing being queued\n"); + + if((pb->last_fr == -1) || ((pb->last_fr == -2) && + overlay_is_active(pb))) { + + IDEBUG("PlanB: overlay is active, grabbing defered\n"); + + tab_cmd_dbdma(pb->last_cmd[fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->ch1_cmd)); + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + tab_cmd_store(pb->pre_cmd[fr], + virt_to_bus(&pb->overlay_last1->cmd_dep), + virt_to_bus(pb->ch1_cmd)); + eieio(); + out_le32 (&pb->overlay_last1->cmd_dep, + virt_to_bus(pb->pre_cmd[fr])); + } else { + tab_cmd_store(pb->cap_cmd[fr], + virt_to_bus(&pb->overlay_last1->cmd_dep), + virt_to_bus(pb->ch1_cmd)); + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP, 0); + eieio(); + out_le32 (&pb->overlay_last1->cmd_dep, + virt_to_bus(pb->cap_cmd[fr])); + } + for(i = 0; overlay_is_active(pb) && i < 999; i++) + IDEBUG("PlanB: waiting for overlay done\n"); + tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); + pb->prev_last_fr = fr; + pb->last_fr = -2; + } else if(pb->last_fr == -2) { + + IDEBUG("PlanB: mixed mode detected, grabbing" + " will be done before activating overlay\n"); + + tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->pre_cmd[fr])); + eieio(); + } else { + tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + if(pb->gwidth[pb->prev_last_fr] != + pb->gwidth[fr] + || pb->gheight[pb->prev_last_fr] != + pb->gheight[fr] + || pb->gfmt[pb->prev_last_fr] != + pb->gfmt[fr]) + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP, 0); + else + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr] + 16)); + tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr])); + eieio(); + } + tab_cmd_dbdma(pb->last_cmd[fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->ch1_cmd)); + eieio(); + pb->prev_last_fr = fr; + pb->last_fr = -2; + } else { + + IDEBUG("PlanB: active grabbing session detected\n"); + + if(pb->need_pre_capture[fr]) { + + IDEBUG("PlanB: padding pre-capture sequence\n"); + + tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->pre_cmd[fr])); + eieio(); + } else { + tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); + tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); + if(pb->gwidth[pb->last_fr] != pb->gwidth[fr] + || pb->gheight[pb->last_fr] != + pb->gheight[fr] + || pb->gfmt[pb->last_fr] != + pb->gfmt[fr]) + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP, 0); + else + tab_cmd_dbdma((pb->cap_cmd[fr] + 1), + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr] + 16)); + tab_cmd_dbdma(pb->last_cmd[pb->last_fr], + DBDMA_NOP | BR_ALWAYS, + virt_to_bus(pb->cap_cmd[fr])); + eieio(); + } + pb->last_fr = fr; + } + if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { + + IDEBUG("PlanB: became inactive in the mean time..." + "reactivating\n"); + + planb_dbdma_stop(&pb->planb_base->ch1); + out_le32 (&pb->planb_base->ch1.cmdptr, + virt_to_bus(pb->cap_cmd[fr])); + planb_dbdma_restart(&pb->planb_base->ch1); + } + } + pb->grabbing++; + planb_unlock(pb); + + return 0; +} + +static void planb_pre_capture(int fr, int bpp, struct planb *pb) +{ + volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr]; + int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; + + tab_cmd_dbdma(c1++, DBDMA_NOP, 0); + if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, + bpp, 0, pb)) == NULL) { + printk(KERN_WARNING "PlanB: encountered some problems\n"); + tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0); + return; + } + /* Sync to even field */ + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; + tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + /* For non-interlaced, we use even fields only */ + if (pb->gheight[fr] <= pb->maxlines/2) + goto cmd_tab_data_end; + /* Sync to odd field */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); +cmd_tab_data_end: + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr])); + + eieio(); +} + +static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) +{ + int i, bpp, count, nlines, stepsize, interlace; +#ifdef PLANB_GSCANLINE + int scanline; +#else + int nlpp, leftover1; + unsigned long base; +#endif + unsigned long jump; + int pagei; + volatile struct dbdma_cmd *c1; + volatile struct dbdma_cmd *jump_addr; + + c1 = pb->cap_cmd[fr]; + interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; + bpp = pb->gfmt[fr]; /* gfmt = bpp */ + count = bpp * pb->gwidth[fr]; + nlines = pb->gheight[fr]; +#ifdef PLANB_GSCANLINE + scanline = pb->gbytes_per_line; +#else + pb->lsize[fr] = count; + pb->lnum[fr] = 0; +#endif + + /* Do video in: */ + + /* Preamble commands: */ + tab_cmd_dbdma(c1++, DBDMA_NOP, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; + if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, + bpp, 0, pb)) == NULL) { + printk(KERN_WARNING "PlanB: encountered serious problems\n"); + tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0); + return (pb->cap_cmd[fr] + 2); + } + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), + PLANB_SET(FIELD_SYNC)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; + tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + if (interlace) { + stepsize = 2; + jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2; + } else { + stepsize = 1; + jump_addr = c1 + TAB_FACTOR * nlines; + } + jump = virt_to_bus(jump_addr); + + /* even field data: */ + + pagei = pb->gbuf_idx[fr]; +#ifdef PLANB_GSCANLINE + for (i = 0; i < nlines; i += stepsize) { + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + virt_to_bus(pb->rawbuf[pagei + + i * scanline / PAGE_SIZE]), jump); + } +#else + i = 0; + leftover1 = 0; + do { + int j; + + base = virt_to_bus(pb->rawbuf[pagei]); + nlpp = (PAGE_SIZE - leftover1) / count / stepsize; + for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, + count, base + count * j * stepsize + leftover1, jump); + if(i < nlines) { + int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; + + if(lov0 == 0) + leftover1 = 0; + else { + if(lov0 >= count) { + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base + + count * nlpp * stepsize + leftover1, jump); + } else { + pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + + count * nlpp * stepsize + leftover1; + pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; + pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] + + pb->lnum[fr]]), jump); + if(++pb->lnum[fr] > MAX_LNUM) + pb->lnum[fr]--; + } + leftover1 = count * stepsize - lov0; + i += stepsize; + } + } + pagei++; + } while(i < nlines); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); + c1 = jump_addr; +#endif /* PLANB_GSCANLINE */ + + /* For non-interlaced, we use even fields only */ + if (!interlace) + goto cmd_tab_data_end; + + /* Sync to odd field */ + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(ODD_FIELD)); + tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); + tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), + PLANB_SET(DMA_ABORT)); + + /* odd field data: */ + jump_addr = c1 + TAB_FACTOR * nlines / 2; + jump = virt_to_bus(jump_addr); +#ifdef PLANB_GSCANLINE + for (i = 1; i < nlines; i += stepsize) { + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + virt_to_bus(pb->rawbuf[pagei + + i * scanline / PAGE_SIZE]), jump); + } +#else + i = 1; + leftover1 = 0; + pagei = pb->gbuf_idx[fr]; + if(nlines <= 1) + goto skip; + do { + int j; + + base = virt_to_bus(pb->rawbuf[pagei]); + nlpp = (PAGE_SIZE - leftover1) / count / stepsize; + if(leftover1 >= count) { + tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + base + leftover1 - count, jump); + i += stepsize; + } + for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) + tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, + base + count * (j * stepsize + 1) + leftover1, jump); + if(i < nlines) { + int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; + + if(lov0 == 0) + leftover1 = 0; + else { + if(lov0 > count) { + pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + + count * (nlpp * stepsize + 1) + leftover1; + pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; + pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize + - lov0; + tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, + virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] + + pb->lnum[fr]]), jump); + if(++pb->lnum[fr] > MAX_LNUM) + pb->lnum[fr]--; + i += stepsize; + } + leftover1 = count * stepsize - lov0; + } + } + pagei++; + } while(i < nlines); +skip: + tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); + c1 = jump_addr; +#endif /* PLANB_GSCANLINE */ + +cmd_tab_data_end: + tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), + (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); + /* stop it */ + tab_cmd_dbdma(c1, DBDMA_STOP, 0); + + eieio(); + return c1; +} + +static void planb_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + unsigned int stat, astat; + struct planb *pb = (struct planb *)dev_id; + + IDEBUG("PlanB: planb_irq()\n"); + + /* get/clear interrupt status bits */ + eieio(); + stat = in_le32(&pb->planb_base->intr_stat); + astat = stat & pb->intr_mask; + out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ + & ~astat & stat & ~PLANB_GEN_IRQ); + IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); + + if(astat & PLANB_FRM_IRQ) { + unsigned int fr = stat >> 9; +#ifndef PLANB_GSCANLINE + int i; +#endif + IDEBUG("PlanB: PLANB_FRM_IRQ\n"); + + pb->gcount++; + + IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n", + pb->grabbing, fr, pb->gcount); +#ifndef PLANB_GSCANLINE + IDEBUG("PlanB: %d * %d bytes are being copied over\n", + pb->lnum[fr], pb->lsize[fr]); + for(i = 0; i < pb->lnum[fr]; i++) { + int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; + + memcpy(pb->l_to_addr[fr][i], + pb->rawbuf[pb->l_fr_addr_idx[fr] + i], + first); + memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], + pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, + pb->l_to_next_size[fr][i]); + } +#endif + pb->frame_stat[fr] = GBUFFER_DONE; + pb->grabbing--; + wake_up_interruptible(&pb->capq); + return; + } + /* incorrect interrupts? */ + pb->intr_mask = PLANB_CLR_IRQ; + out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts" + " unconditionally\n"); +} + +/******************************* + * Device Operations functions * + *******************************/ + +static int planb_open(struct video_device *dev, int mode) +{ + struct planb *pb = (struct planb *)dev; + + if (pb->user == 0) { + int err; + if((err = planb_prepare_open(pb)) != 0) + return err; + } + pb->user++; + + DEBUG("PlanB: device opened\n"); + + MOD_INC_USE_COUNT; + return 0; +} + +static void planb_close(struct video_device *dev) +{ + struct planb *pb = (struct planb *)dev; + + if(pb->user < 1) /* ??? */ + return; + planb_lock(pb); + if (pb->user == 1) { + if (pb->overlay) { + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + pb->overlay = 0; + } + planb_prepare_close(pb); + } + pb->user--; + planb_unlock(pb); + + DEBUG("PlanB: device closed\n"); + + MOD_DEC_USE_COUNT; +} + +static long planb_read(struct video_device *v, char *buf, unsigned long count, + int nonblock) +{ + DEBUG("planb: read request\n"); + return -EINVAL; +} + +static long planb_write(struct video_device *v, const char *buf, + unsigned long count, int nonblock) +{ + DEBUG("planb: write request\n"); + return -EINVAL; +} + +static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct planb *pb=(struct planb *)dev; + + switch (cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + + DEBUG("PlanB: IOCTL VIDIOCGCAP\n"); + + strcpy (b.name, pb->video_dev.name); + b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | VID_TYPE_SCALES | + VID_TYPE_CAPTURE; + b.channels = 2; /* composite & svhs */ + b.audios = 0; + b.maxwidth = PLANB_MAXPIXELS; + b.maxheight = PLANB_MAXLINES; + b.minwidth = 32; /* wild guess */ + b.minheight = 32; + if (copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCSFBUF: + { + struct video_buffer v; + unsigned short bpp; + unsigned int fmt; + + DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); + + if (!capable(CAP_SYS_ADMIN) + || !capable(CAP_SYS_RAWIO)) + return -EPERM; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + planb_lock(pb); + switch(v.depth) { + case 8: + bpp = 1; + fmt = PLANB_GRAY; + break; + case 15: + case 16: + bpp = 2; + fmt = PLANB_COLOUR15; + break; + case 24: + case 32: + bpp = 4; + fmt = PLANB_COLOUR32; + break; + default: + planb_unlock(pb); + return -EINVAL; + } + if (bpp * v.width > v.bytesperline) { + planb_unlock(pb); + return -EINVAL; + } + pb->win.bpp = bpp; + pb->win.color_fmt = fmt; + pb->frame_buffer_phys = (unsigned long) v.base; + pb->win.sheight = v.height; + pb->win.swidth = v.width; + pb->picture.depth = pb->win.depth = v.depth; + pb->win.bpl = pb->win.bpp * pb->win.swidth; + pb->win.pad = v.bytesperline - pb->win.bpl; + + DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d," + " bpl %d (+ %d)\n", v.base, v.width,v.height, + pb->win.bpp, pb->win.bpl, pb->win.pad); + + pb->cmd_buff_inited = 0; + if(pb->overlay) { + suspend_overlay(pb); + fill_cmd_buff(pb); + resume_overlay(pb); + } + planb_unlock(pb); + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + + DEBUG("PlanB: IOCTL VIDIOCGFBUF\n"); + + v.base = (void *)pb->frame_buffer_phys; + v.height = pb->win.sheight; + v.width = pb->win.swidth; + v.depth = pb->win.depth; + v.bytesperline = pb->win.bpl + pb->win.pad; + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int i; + + if(copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + if(i==0) { + DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); + + if (!(pb->overlay)) + return 0; + planb_lock(pb); + pb->overlay = 0; + overlay_stop(pb); + planb_unlock(pb); + } else { + DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); + + if (pb->frame_buffer_phys == 0 || + pb->win.width == 0 || + pb->win.height == 0) + return -EINVAL; + if (pb->overlay) + return 0; + planb_lock(pb); + pb->overlay = 1; + if(!(pb->cmd_buff_inited)) + fill_cmd_buff(pb); + overlay_start(pb); + planb_unlock(pb); + } + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + DEBUG("PlanB: IOCTL VIDIOCGCHAN\n"); + + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = pb->win.norm; + switch(v.channel) + { + case 0: + strcpy(v.name,"Composite"); + break; + case 1: + strcpy(v.name,"SVHS"); + break; + default: + return -EINVAL; + break; + } + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel v; + + DEBUG("PlanB: IOCTL VIDIOCSCHAN\n"); + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v.norm != pb->win.norm) { + int i, maxlines; + + switch (v.norm) + { + case VIDEO_MODE_PAL: + case VIDEO_MODE_SECAM: + maxlines = PLANB_MAXLINES; + break; + case VIDEO_MODE_NTSC: + maxlines = PLANB_NTSC_MAXLINES; + break; + default: + return -EINVAL; + break; + } + planb_lock(pb); + /* empty the grabbing queue */ + while(pb->grabbing) + interruptible_sleep_on(&pb->capq); + pb->maxlines = maxlines; + pb->win.norm = v.norm; + /* Stop overlay if running */ + suspend_overlay(pb); + for(i = 0; i < MAX_GBUFFERS; i++) + pb->gnorm_switch[i] = 1; + /* I know it's an overkill, but.... */ + fill_cmd_buff(pb); + /* ok, now init it accordingly */ + saa_init_regs (pb); + /* restart overlay if it was running */ + resume_overlay(pb); + planb_unlock(pb); + } + + switch(v.channel) + { + case 0: /* Composite */ + saa_set (SAA7196_IOCC, + ((saa_regs[pb->win.norm][SAA7196_IOCC] & + ~7) | 3), pb); + break; + case 1: /* SVHS */ + saa_set (SAA7196_IOCC, + ((saa_regs[pb->win.norm][SAA7196_IOCC] & + ~7) | 4), pb); + break; + default: + return -EINVAL; + break; + } + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture vp = pb->picture; + + DEBUG("PlanB: IOCTL VIDIOCGPICT\n"); + + switch(pb->win.color_fmt) { + case PLANB_GRAY: + vp.palette = VIDEO_PALETTE_GREY; + case PLANB_COLOUR15: + vp.palette = VIDEO_PALETTE_RGB555; + break; + case PLANB_COLOUR32: + vp.palette = VIDEO_PALETTE_RGB32; + break; + default: + vp.palette = 0; + break; + } + + if(copy_to_user(arg,&vp,sizeof(vp))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture vp; + + DEBUG("PlanB: IOCTL VIDIOCSPICT\n"); + + if(copy_from_user(&vp,arg,sizeof(vp))) + return -EFAULT; + pb->picture = vp; + /* Should we do sanity checks here? */ + saa_set (SAA7196_BRIG, (unsigned char) + ((pb->picture.brightness) >> 8), pb); + saa_set (SAA7196_HUEC, (unsigned char) + ((pb->picture.hue) >> 8) ^ 0x80, pb); + saa_set (SAA7196_CSAT, (unsigned char) + ((pb->picture.colour) >> 9), pb); + saa_set (SAA7196_CONT, (unsigned char) + ((pb->picture.contrast) >> 9), pb); + + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip clip; + int i; + + DEBUG("PlanB: IOCTL VIDIOCSWIN\n"); + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + planb_lock(pb); + /* Stop overlay if running */ + suspend_overlay(pb); + pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0; + if (pb->win.x != vw.x || + pb->win.y != vw.y || + pb->win.width != vw.width || + pb->win.height != vw.height || + !pb->cmd_buff_inited) { + pb->win.x = vw.x; + pb->win.y = vw.y; + pb->win.width = vw.width; + pb->win.height = vw.height; + fill_cmd_buff(pb); + } + /* Reset clip mask */ + memset ((void *) pb->mask, 0xff, (pb->maxlines + * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); + /* Add any clip rects */ + for (i = 0; i < vw.clipcount; i++) { + if (copy_from_user(&clip, vw.clips + i, + sizeof(struct video_clip))) + return -EFAULT; + add_clip(pb, &clip); + } + /* restart overlay if it was running */ + resume_overlay(pb); + planb_unlock(pb); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + + DEBUG("PlanB: IOCTL VIDIOCGWIN\n"); + + vw.x=pb->win.x; + vw.y=pb->win.y; + vw.width=pb->win.width; + vw.height=pb->win.height; + vw.chromakey=0; + vw.flags=0; + if(pb->win.interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + if(copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCSYNC: { + int i; + + IDEBUG("PlanB: IOCTL VIDIOCSYNC\n"); + + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + + IDEBUG("PlanB: sync to frame %d\n", i); + + if(i > (MAX_GBUFFERS - 1) || i < 0) + return -EINVAL; +chk_grab: + switch (pb->frame_stat[i]) { + case GBUFFER_UNUSED: + return -EINVAL; + case GBUFFER_GRABBING: + IDEBUG("PlanB: waiting for grab" + " done (%d)\n", i); + interruptible_sleep_on(&pb->capq); + if(signal_pending(current)) + return -EINTR; + goto chk_grab; + case GBUFFER_DONE: + pb->frame_stat[i] = GBUFFER_UNUSED; + break; + } + return 0; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + volatile unsigned int status; + + IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n"); + + if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) + return -EFAULT; + status = pb->frame_stat[vm.frame]; + if (status != GBUFFER_UNUSED) + return -EBUSY; + + return vgrab(pb, &vm); + } + + case VIDIOCGMBUF: + { + int i; + struct video_mbuf vm; + + DEBUG("PlanB: IOCTL VIDIOCGMBUF\n"); + + memset(&vm, 0 , sizeof(vm)); + vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; + vm.frames = MAX_GBUFFERS; + for(i = 0; i= SAA7196_NUMREGS) + return -EINVAL; + preg.val = saa_regs[pb->win.norm][preg.addr]; + if(copy_to_user((void *)arg, (void *)&preg, + sizeof(preg))) + return -EFAULT; + return 0; + } + + case PLANBIOCSSAAREGS: + { + struct planb_saa_regs preg; + + DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); + + if(copy_from_user(&preg, arg, sizeof(preg))) + return -EFAULT; + if(preg.addr >= SAA7196_NUMREGS) + return -EINVAL; + saa_set (preg.addr, preg.val, pb); + return 0; + } + + case PLANBIOCGSTAT: + { + struct planb_stat_regs pstat; + + DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); + + pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); + pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); + pstat.saa_stat0 = saa_status(0, pb); + pstat.saa_stat1 = saa_status(1, pb); + + if(copy_to_user((void *)arg, (void *)&pstat, + sizeof(pstat))) + return -EFAULT; + return 0; + } + + case PLANBIOCSMODE: { + int v; + + DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + switch(v) + { + case PLANB_TV_MODE: + saa_set (SAA7196_STDC, + (saa_regs[pb->win.norm][SAA7196_STDC] & + 0x7f), pb); + break; + case PLANB_VTR_MODE: + saa_set (SAA7196_STDC, + (saa_regs[pb->win.norm][SAA7196_STDC] | + 0x80), pb); + break; + default: + return -EINVAL; + break; + } + pb->win.mode = v; + return 0; + } + case PLANBIOCGMODE: { + int v=pb->win.mode; + + DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } +#ifdef PLANB_GSCANLINE + case PLANBG_GRAB_BPL: { + int v=pb->gbytes_per_line; + + DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } +#endif /* PLANB_GSCANLINE */ + case PLANB_INTR_DEBUG: { + int i; + + DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); + + if(copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + + /* avoid hang ups all together */ + for (i = 0; i < MAX_GBUFFERS; i++) { + if(pb->frame_stat[i] == GBUFFER_GRABBING) { + pb->frame_stat[i] = GBUFFER_DONE; + } + } + if(pb->grabbing) + pb->grabbing--; + wake_up_interruptible(&pb->capq); + return 0; + } + case PLANB_INV_REGS: { + int i; + struct planb_any_regs any; + + DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); + + if(copy_from_user(&any, arg, sizeof(any))) + return -EFAULT; + if(any.offset < 0 || any.offset + any.bytes > 0x400) + return -EINVAL; + if(any.bytes > 128) + return -EINVAL; + for (i = 0; i < any.bytes; i++) { + any.data[i] = + in_8((unsigned char *)pb->planb_base + + any.offset + i); + } + if(copy_to_user(arg,&any,sizeof(any))) + return -EFAULT; + return 0; + } + default: + { + DEBUG("PlanB: Unimplemented IOCTL\n"); + return -ENOIOCTLCMD; + } + /* Some IOCTLs are currently unsupported on PlanB */ + case VIDIOCGTUNER: { + DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); + goto unimplemented; } + case VIDIOCSTUNER: { + DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); + goto unimplemented; } + case VIDIOCSFREQ: { + DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); + goto unimplemented; } + case VIDIOCGFREQ: { + DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); + goto unimplemented; } + case VIDIOCKEY: { + DEBUG("PlanB: IOCTL VIDIOCKEY\n"); + goto unimplemented; } + case VIDIOCSAUDIO: { + DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); + goto unimplemented; } + case VIDIOCGAUDIO: { + DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); + goto unimplemented; } +unimplemented: + DEBUG(" Unimplemented\n"); + return -ENOIOCTLCMD; + } + return 0; +} + +static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + int i; + struct planb *pb = (struct planb *)dev; + unsigned long start = (unsigned long)adr; + + if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) + return -EINVAL; + if (!pb->rawbuf) { + int err; + if((err=grabbuf_alloc(pb))) + return err; + } + for (i = 0; i < pb->rawbuf_size; i++) { + if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), + PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + if (size <= PAGE_SIZE) + break; + size -= PAGE_SIZE; + } + return 0; +} + +/* This gets called upon device registration */ +/* we could do some init here */ +static int planb_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device planb_template= +{ + PLANB_DEVICE_NAME, + VID_TYPE_OVERLAY, + VID_HARDWARE_PLANB, + planb_open, + planb_close, + planb_read, + planb_write, +#if LINUX_VERSION_CODE >= 0x020100 + NULL, /* poll */ +#endif + planb_ioctl, + planb_mmap, /* mmap? */ + planb_init_done, + NULL, /* pointer to private data */ + 0, + 0 +}; + +static int init_planb(struct planb *pb) +{ + unsigned char saa_rev; + int i, result; + unsigned long flags; + + memset ((void *) &pb->win, 0, sizeof (struct planb_window)); + /* Simple sanity check */ + if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { + printk(KERN_ERR "PlanB: Option(s) invalid\n"); + return -2; + } + pb->win.norm = def_norm; + pb->win.mode = PLANB_TV_MODE; /* TV mode */ + pb->win.interlace=1; + pb->win.x=0; + pb->win.y=0; + pb->win.width=768; /* 640 */ + pb->win.height=576; /* 480 */ + pb->maxlines=576; +#if 0 + btv->win.cropwidth=768; /* 640 */ + btv->win.cropheight=576; /* 480 */ + btv->win.cropx=0; + btv->win.cropy=0; +#endif + pb->win.pad=0; + pb->win.bpp=4; + pb->win.depth=32; + pb->win.color_fmt=PLANB_COLOUR32; + pb->win.bpl=1024*pb->win.bpp; + pb->win.swidth=1024; + pb->win.sheight=768; +#ifdef PLANB_GSCANLINE + if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE + || (pb->gbytes_per_line <= 0)) + return -3; + else { + /* page align pb->gbytes_per_line for DMA purpose */ + for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) + i>>=1; + pb->gbytes_per_line = i; + } +#endif + pb->tab_size = PLANB_MAXLINES + 40; + pb->suspend = 0; + pb->lock = 0; + init_waitqueue_head(&pb->lockq); + pb->ch1_cmd = 0; + pb->ch2_cmd = 0; + pb->mask = 0; + pb->priv_space = 0; + pb->offset = 0; + pb->user = 0; + pb->overlay = 0; + init_waitqueue_head(&pb->suspendq); + pb->cmd_buff_inited = 0; + pb->frame_buffer_phys = 0; + + /* Reset DMA controllers */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + saa_rev = (saa_status(0, pb) & 0xf0) >> 4; + printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev); + /* Initialize the SAA registers in memory and on chip */ + saa_init_regs (pb); + + /* clear interrupt mask */ + pb->intr_mask = PLANB_CLR_IRQ; + + save_flags(flags); cli(); + result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb); + if (result < 0) { + if (result==-EINVAL) + printk(KERN_ERR "PlanB: Bad irq number (%d) " + "or handler\n", (int)pb->irq); + else if (result==-EBUSY) + printk(KERN_ERR "PlanB: I don't know why, " + "but IRQ %d is busy\n", (int)pb->irq); + restore_flags(flags); + return result; + } + disable_irq(pb->irq); + restore_flags(flags); + + /* Now add the template and register the device unit. */ + memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); + + pb->picture.brightness=0x90<<8; + pb->picture.contrast = 0x70 << 8; + pb->picture.colour = 0x70<<8; + pb->picture.hue = 0x8000; + pb->picture.whiteness = 0; + pb->picture.depth = pb->win.depth; + + pb->frame_stat=NULL; + init_waitqueue_head(&pb->capq); + for(i=0; igbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; + pb->gwidth[i]=0; + pb->gheight[i]=0; + pb->gfmt[i]=0; + pb->cap_cmd[i]=NULL; +#ifndef PLANB_GSCANLINE + pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF + / PAGE_SIZE + 1) + MAX_LNUM * i; + pb->lsize[i] = 0; + pb->lnum[i] = 0; +#endif + } + pb->rawbuf=NULL; + pb->grabbing=0; + + /* enable interrupts */ + out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + pb->intr_mask = PLANB_FRM_IRQ; + enable_irq(pb->irq); + + if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0) + return -1; + + return 0; +} + +/* + * Scan for a PlanB controller, request the irq and map the io memory + */ + +static int find_planb(void) +{ + struct planb *pb; + struct device_node *planb_devices; + unsigned char dev_fn, confreg, bus; + unsigned int old_base, new_base; + unsigned int irq; + struct pci_dev *pdev; + + if (_machine != _MACH_Pmac) + return 0; + + planb_devices = find_devices("planb"); + if (planb_devices == 0) { + planb_num=0; + printk(KERN_WARNING "PlanB: no device found!\n"); + return planb_num; + } + + if (planb_devices->next != NULL) + printk(KERN_ERR "Warning: only using first PlanB device!\n"); + pb = &planbs[0]; + planb_num = 1; + + if (planb_devices->n_addrs != 1) { + printk (KERN_WARNING "PlanB: expecting 1 address for planb " + "(got %d)", planb_devices->n_addrs); + return 0; + } + + if (planb_devices->n_intrs == 0) { + printk(KERN_WARNING "PlanB: no intrs for device %s\n", + planb_devices->full_name); + return 0; + } else { + irq = planb_devices->intrs[0].line; + } + + /* Initialize PlanB's PCI registers */ + + /* There is a bug with the way OF assigns addresses + to the devices behind the chaos bridge. + control needs only 0x1000 of space, but decodes only + the upper 16 bits. It therefore occupies a full 64K. + OF assigns the planb controller memory within this space; + so we need to change that here in order to access planb. */ + + /* We remap to 0xf1000000 in hope that nobody uses it ! */ + + bus = (planb_devices->addrs[0].space >> 16) & 0xff; + dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; + confreg = planb_devices->addrs[0].space & 0xff; + old_base = planb_devices->addrs[0].address; + new_base = 0xf1000000; + + DEBUG("PlanB: Found on bus %d, dev %d, func %d, " + "membase 0x%x (base reg. 0x%x)\n", + bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); + + pdev = pci_find_slot (bus, dev_fn); + if (!pdev) { + printk(KERN_ERR "cannot find slot\n"); + /* XXX handle error */ + } + + /* Enable response in memory space, bus mastering, + use memory write and invalidate */ + pci_write_config_word (pdev, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE); + /* Set PCI Cache line size & latency timer */ + pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, 0x8); + pci_write_config_byte (pdev, PCI_LATENCY_TIMER, 0x40); + + /* Set the new base address */ + pci_write_config_dword (pdev, confreg, new_base); + + planb_regs = (volatile struct planb_registers *) + ioremap (new_base, 0x400); + pb->planb_base = planb_regs; + pb->planb_base_phys = (struct planb_registers *)new_base; + pb->irq = irq; + + return planb_num; +} + +static void release_planb(void) +{ + int i; + struct planb *pb; + + for (i=0;iplanb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + /* clear and free interrupts */ + pb->intr_mask = PLANB_CLR_IRQ; + out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); + free_irq(pb->irq, pb); + + /* make sure all allocated memory are freed */ + planb_prepare_close(pb); + + printk(KERN_INFO "PlanB: unregistering with v4l\n"); + video_unregister_device(&pb->video_dev); + + /* note that iounmap() does nothing on the PPC right now */ + iounmap ((void *)pb->planb_base); + } +} + +#ifdef MODULE + +int init_module(void) +{ +#else +int __init init_planbs(struct video_init *unused) +{ +#endif + int i; + + if (find_planb()<=0) + return -EIO; + + for (i=0; i +#include "saa7196.h" +#endif /* __KERNEL__ */ + +#define PLANB_DEVICE_NAME "Apple PlanB Video-In" +#define PLANB_REV "1.0" + +#ifdef __KERNEL__ +//#define PLANB_GSCANLINE /* use this if apps have the notion of */ + /* grab buffer scanline */ +/* This should be safe for both PAL and NTSC */ +#define PLANB_MAXPIXELS 768 +#define PLANB_MAXLINES 576 +#define PLANB_NTSC_MAXLINES 480 + +/* Uncomment your preferred norm ;-) */ +#define PLANB_DEF_NORM VIDEO_MODE_PAL +//#define PLANB_DEF_NORM VIDEO_MODE_NTSC +//#define PLANB_DEF_NORM VIDEO_MODE_SECAM + +/* fields settings */ +#define PLANB_GRAY 0x1 /* 8-bit mono? */ +#define PLANB_COLOUR15 0x2 /* 16-bit mode */ +#define PLANB_COLOUR32 0x4 /* 32-bit mode */ +#define PLANB_CLIPMASK 0x8 /* hardware clipmasking */ + +/* misc. flags for PlanB DMA operation */ +#define CH_SYNC 0x1 /* synchronize channels (set by ch1; + cleared by ch2) */ +#define FIELD_SYNC 0x2 /* used for the start of each field + (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */ +#define EVEN_FIELD 0x0 /* even field is detected if unset */ +#define DMA_ABORT 0x2 /* error or just out of sync if set */ +#define ODD_FIELD 0x4 /* odd field is detected if set */ + +/* for capture operations */ +#define MAX_GBUFFERS 2 +/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ +#ifdef PLANB_GSCANLINE +#define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ +#define TAB_FACTOR (1) +#else +#define PLANB_MAX_FBUF 0x1b0000 /* 576 * 768 * 4 */ +#define TAB_FACTOR (2) +#endif +#endif /* __KERNEL__ */ + +struct planb_saa_regs { + unsigned char addr; + unsigned char val; +}; + +struct planb_stat_regs { + unsigned int ch1_stat; + unsigned int ch2_stat; + unsigned char saa_stat0; + unsigned char saa_stat1; +}; + +struct planb_any_regs { + unsigned int offset; + unsigned int bytes; + unsigned char data[128]; +}; + +/* planb private ioctls */ +#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) /* Read a saa7196 reg value */ +#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) /* Set a saa7196 reg value */ +#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) /* Read planb status */ +#define PLANB_TV_MODE 1 +#define PLANB_VTR_MODE 2 +#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) /* Get TV/VTR mode */ +#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) /* Set TV/VTR mode */ + +#ifdef PLANB_GSCANLINE +#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) /* # of bytes per scanline in grab buffer */ +#endif + +/* call wake_up_interruptible() with appropriate actions */ +#define PLANB_INTR_DEBUG _IOW('v', BASE_VIDIOCPRIVATE + 20, int) +/* investigate which reg does what */ +#define PLANB_INV_REGS _IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs) + +#ifdef __KERNEL__ + +/* Potentially useful macros */ +#define PLANB_SET(x) ((x) << 16 | (x)) +#define PLANB_CLR(x) ((x) << 16) + +/* This represents the physical register layout */ +struct planb_registers { + volatile struct dbdma_regs ch1; /* 0x00: video in */ + volatile unsigned int even; /* 0x40: even field setting */ + volatile unsigned int odd; /* 0x44; odd field setting */ + unsigned int pad1[14]; /* empty? */ + volatile struct dbdma_regs ch2; /* 0x80: clipmask out */ + unsigned int pad2[16]; /* 0xc0: empty? */ + volatile unsigned int reg3; /* 0x100: ???? */ + volatile unsigned int intr_stat; /* 0x104: irq status */ +#define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ +#define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ +#define PLANB_FRM_IRQ 0x0100 /* end of frame */ + unsigned int pad3[1]; /* empty? */ + volatile unsigned int reg5; /* 0x10c: ??? */ + unsigned int pad4[60]; /* empty? */ + volatile unsigned char saa_addr; /* 0x200: SAA subadr */ + char pad5[3]; + volatile unsigned char saa_regval; /* SAA7196 write reg. val */ + char pad6[3]; + volatile unsigned char saa_status; /* SAA7196 status byte */ + /* There is more unused stuff here */ +}; + +struct planb_window { + int x, y; + ushort width, height; + ushort bpp, bpl, depth, pad; + ushort swidth, sheight; + int norm; + int interlace; + u32 color_fmt; + int chromakey; + int mode; /* used to switch between TV/VTR modes */ +}; + +struct planb_suspend { + int overlay; + int frame; + struct dbdma_cmd cmd; +}; + +struct planb { + struct video_device video_dev; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + + volatile struct planb_registers *planb_base; /* virt base of planb */ + struct planb_registers *planb_base_phys; /* phys base of planb */ + void *priv_space; /* Org. alloc. mem for kfree */ + int user; + unsigned int tab_size; + int maxlines; + int lock; + wait_queue_head_t lockq; + unsigned int irq; /* interrupt number */ + volatile unsigned int intr_mask; + + int overlay; /* overlay running? */ + struct planb_window win; + unsigned long frame_buffer_phys; /* We need phys for DMA */ + int offset; /* offset of pixel 1 */ + volatile struct dbdma_cmd *ch1_cmd; /* Video In DMA cmd buffer */ + volatile struct dbdma_cmd *ch2_cmd; /* Clip Out DMA cmd buffer */ + volatile struct dbdma_cmd *overlay_last1; + volatile struct dbdma_cmd *overlay_last2; + unsigned long ch1_cmd_phys; + volatile unsigned char *mask; /* Clipmask buffer */ + int suspend; + wait_queue_head_t suspendq; + struct planb_suspend suspended; + int cmd_buff_inited; /* cmd buffer inited? */ + + int grabbing; + unsigned int gcount; + wait_queue_head_t capq; + int last_fr; + int prev_last_fr; + unsigned char **rawbuf; + int rawbuf_size; + int gbuf_idx[MAX_GBUFFERS]; + volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; + volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; + volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; + int need_pre_capture[MAX_GBUFFERS]; +#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ + int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS]; + unsigned int gfmt[MAX_GBUFFERS]; + int gnorm_switch[MAX_GBUFFERS]; + volatile unsigned int *frame_stat; +#define GBUFFER_UNUSED 0x00U +#define GBUFFER_GRABBING 0x01U +#define GBUFFER_DONE 0x02U +#ifdef PLANB_GSCANLINE + int gbytes_per_line; +#else +#define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ + /* PLANB_MAXPIXELS changes */ + int l_fr_addr_idx[MAX_GBUFFERS]; + unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; + int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; +#endif +}; + +#endif /* __KERNEL__ */ + +#endif /* _PLANB_H_ */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/pms.c linux/drivers/media/video/pms.c --- v2.4.0-test6/linux/drivers/media/video/pms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/pms.c Wed Nov 10 13:39:06 1999 @@ -0,0 +1,1074 @@ +/* + * 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@redhat.com 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); +} + +static int pms_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); +} + +static int pms_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; +} + +static int pms_i2c_read(int slave, int sub) +{ + int i=0; + for(i=0;i>8)&0x01); +} + +#endif + +static void pms_secamcross(short cross) +{ + if(decoder==PHILIPS2) + pms_i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5); + else if(decoder==PHILIPS1) + pms_i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5); +} + + +static void pms_swsense(short sense) +{ + if(decoder==PHILIPS2) + { + pms_i2c_write(0x8A, 0x0A, sense); + pms_i2c_write(0x8A, 0x0B, sense); + } + else if(decoder==PHILIPS1) + { + pms_i2c_write(0x42, 0x0A, sense); + pms_i2c_write(0x42, 0x0B, sense); + } +} + + +static void pms_framerate(short frr) +{ + int fps=(standard==1)?30:25; + if(frr==0) + return; + fps=fps/frr; + mvv_write(0x14,0x80|fps); + mvv_write(0x15,1); +} + +static void pms_vert(u8 deciden, u8 decinum) +{ + mvv_write(0x1C, deciden); /* Denominator */ + mvv_write(0x1D, decinum); /* Numerator */ +} + +/* + * Turn 16bit ratios into best small ratio the chipset can grok + */ + +static void pms_vertdeci(unsigned short decinum, unsigned short deciden) +{ + /* Knock it down by /5 once */ + if(decinum%5==0) + { + deciden/=5; + decinum/=5; + } + /* + * 3's + */ + while(decinum%3==0 && deciden%3==0) + { + deciden/=3; + decinum/=3; + } + /* + * 2's + */ + while(decinum%2==0 && deciden%2==0) + { + decinum/=2; + deciden/=2; + } + /* + * Fudgyify + */ + while(deciden>32) + { + 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|deciden)&1)==0) + { + decinum>>=1; + deciden>>=1; + } + while(deciden>32) + { + deciden>>=1; + decinum=(decinum+1)>>1; + } + if(deciden==32) + deciden--; + + mvv_write(0x24, 0x80|deciden); + mvv_write(0x25, decinum); +} + +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>fg_height) + 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); +} + + +/* + * Set Input + */ + +static void pms_vcrinput(short input) +{ + if(decoder==PHILIPS2) + pms_i2c_andor(0x8A,0x0D,0x7F,(input&1)<<7); + else if(decoder==PHILIPS1) + pms_i2c_andor(0x42,0x0D,0x7F,(input&1)<<7); +} + + +static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count) +{ + int y; + int dw = 2*dev->width; + u32 src = mem_base; + + char tmp[dw+32]; /* using a temp buffer is faster than direct */ + int cnt = 0; + int len=0; + unsigned char r8 = 0x5; /* value for reg8 */ + + if (rgb555) + r8 |= 0x20; /* else use untranslated rgb = 565 */ + mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */ + +/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */ + + for (y = 0; y < dev->height; y++ ) + { + isa_writeb(0, src); /* synchronisiert neue Zeile */ + + /* + * This is in truth a fifo, be very careful as if you + * forgot this odd things will occur 8) + */ + + isa_memcpy_fromio(tmp, src, dw+32); /* discard 16 word */ + cnt -= dev->height; + while (cnt <= 0) + { + /* + * Don't copy too far + */ + int dt=dw; + if(dt+len>count) + dt=count-len; + cnt += dev->height; + copy_to_user(buf, tmp+32, dt); + buf += dt; + len += dt; + } + } + 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; + switch(v.channel) + { + case 0: + strcpy(v.name, "Composite");break; + case 1: + strcpy(v.name, "SVideo");break; + case 2: + strcpy(v.name, "Composite(VCR)");break; + case 3: + strcpy(v.name, "SVideo(VCR)");break; + } + 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>>8); + pms_hue(p.hue>>8); + pms_colour(p.colour>>8); + pms_contrast(p.contrast>>8); + 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, + NULL, /* FIXME - we can use POLL on this board with the irq */ + 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=pms_i2c_stat(0x43); + + if(decst!=-1) + idec=2; + else if(pms_i2c_stat(0xb9)!=-1) + idec=3; + else if(pms_i2c_stat(0x8b)!=-1) + idec=1; + else + idec=0; + + printk(KERN_INFO "PMS type is %d\n", idec); + 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) + pms_i2c_andor(0x8A, i, 0x07,0x00); + else + pms_i2c_write(0x8A, i, i2c_defs[i]); + } + + pms_i2c_write(0xB8,0x00,0x12); + pms_i2c_write(0xB8,0x04,0x00); + pms_i2c_write(0xB8,0x07,0x00); + pms_i2c_write(0xB8,0x08,0x00); + pms_i2c_write(0xB8,0x09,0xFF); + pms_i2c_write(0xB8,0x0A,0x00); + pms_i2c_write(0xB8,0x0B,0x10); + pms_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; +} + +/* + * Initialization and module stuff + */ + +static int __init init_pms_cards(void) +{ + printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n"); + + data_port = io_port +1; + + 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_swsense(75); + pms_resolution(320,240); + return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER); +} + +MODULE_PARM(io_port,"i"); +MODULE_PARM(mem_base,"i"); + +static void __exit shutdown_mediavision(void) +{ + release_region(io_port,3); + release_region(0x9A01, 1); +} + +static void __exit cleanup_pms_module(void) +{ + shutdown_mediavision(); + video_unregister_device((struct video_device *)&pms_device); +} + +module_init(init_pms_cards); +module_exit(cleanup_pms_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c --- v2.4.0-test6/linux/drivers/media/video/saa5249.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa5249.c Wed Feb 9 18:48:03 2000 @@ -0,0 +1,683 @@ +/* + * Cleaned up to use existing videodev interface and allow the idea + * of multiple teletext decoders on the video4linux iface. Changed i2c + * to cover addressing clashes on device busses. It's also rebuilt so + * you can add arbitary multiple teletext devices to Linux video4linux + * now (well 32 anyway). + * + * Alan Cox + * + * The original driver was heavily modified to match the i2c interface + * It was truncated to use the WinTV boards, too. + * + * Copyright (c) 1998 Richard Guenther + * + * $Id: saa5249.c,v 1.1 1998/03/30 22:23:23 alan Exp $ + * + * Derived From + * + * vtx.c: + * This is a loadable character-device-driver for videotext-interfaces + * (aka teletext). Please check the Makefile/README for a list of supported + * interfaces. + * + * Copyright (c) 1994-97 Martin Buck + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define VTX_VER_MAJ 1 +#define VTX_VER_MIN 7 + + + +#define NUM_DAUS 4 +#define NUM_BUFS 8 +#define IF_NAME "SAA5249" + +static const int disp_modes[8][3] = +{ + { 0x46, 0x03, 0x03 }, /* DISPOFF */ + { 0x46, 0xcc, 0xcc }, /* DISPNORM */ + { 0x44, 0x0f, 0x0f }, /* DISPTRANS */ + { 0x46, 0xcc, 0x46 }, /* DISPINS */ + { 0x44, 0x03, 0x03 }, /* DISPOFF, interlaced */ + { 0x44, 0xcc, 0xcc }, /* DISPNORM, interlaced */ + { 0x44, 0x0f, 0x0f }, /* DISPTRANS, interlaced */ + { 0x44, 0xcc, 0x46 } /* DISPINS, interlaced */ +}; + + + +#define PAGE_WAIT (300*HZ/1000) /* Time between requesting page and */ + /* checking status bits */ +#define PGBUF_EXPIRE (15*HZ) /* Time to wait before retransmitting */ + /* page regardless of infobits */ +typedef struct { + u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */ + u8 laststat[10]; /* Last value of infobits for DAU */ + u8 sregs[7]; /* Page-request registers */ + unsigned long expire; /* Time when page will be expired */ + unsigned clrfound : 1; /* VTXIOCCLRFOUND has been called */ + unsigned stopped : 1; /* VTXIOCSTOPDAU has been called */ +} vdau_t; + +struct saa5249_device +{ + vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */ + /* real DAU, so we have to simulate some more) */ + int vtx_use_count; + int is_searching[NUM_DAUS]; + int disp_mode; + int virtual_mode; + struct i2c_client *client; +}; + + +#define CCTWR 34 /* I²C write/read-address of vtx-chip */ +#define CCTRD 35 +#define NOACK_REPEAT 10 /* Retry access this many times on failure */ +#define CLEAR_DELAY (HZ/20) /* Time required to clear a page */ +#define READY_TIMEOUT (30*HZ/1000) /* Time to wait for ready signal of I²C-bus interface */ +#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */ +#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */ + +#define VTX_DEV_MINOR 0 + +/* General defines and debugging support */ + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define RESCHED \ + do { \ + if (current->need_resched) \ + schedule(); \ + } while (0) + +static struct video_device saa_template; /* Declared near bottom */ + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +static struct i2c_client client_template; + +static int saa5249_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) +{ + int pgbuf; + int err; + struct i2c_client *client; + struct video_device *vd; + struct saa5249_device *t; + + printk(KERN_INFO "saa5249: teletext chip found.\n"); + client=kmalloc(sizeof(*client), GFP_KERNEL); + if(client==NULL) + return -ENOMEM; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(*client)); + t = kmalloc(sizeof(*t), GFP_KERNEL); + if(t==NULL) + { + kfree(client); + return -ENOMEM; + } + memset(t, 0, sizeof(*t)); + strcpy(client->name, IF_NAME); + + /* + * Now create a video4linux device + */ + + client->data = vd=(struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL); + if(vd==NULL) + { + kfree(t); + kfree(client); + return -ENOMEM; + } + memcpy(vd, &saa_template, sizeof(*vd)); + + for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) + { + memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); + memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); + memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); + t->vdau[pgbuf].expire = 0; + t->vdau[pgbuf].clrfound = TRUE; + t->vdau[pgbuf].stopped = TRUE; + t->is_searching[pgbuf] = FALSE; + } + vd->priv=t; + + /* + * Register it + */ + + if((err=video_register_device(vd, VFL_TYPE_VTX))<0) + { + kfree(t); + kfree(vd); + kfree(client); + return err; + } + t->client = client; + i2c_attach_client(client); + MOD_INC_USE_COUNT; + return 0; +} + +/* + * We do most of the hard work when we become a device on the i2c. + */ + +static int saa5249_probe(struct i2c_adapter *adap) +{ + /* Only attach these chips to the BT848 bus for now */ + + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + { + return i2c_probe(adap, &addr_data, saa5249_attach); + } + return 0; +} + +static int saa5249_detach(struct i2c_client *client) +{ + struct video_device *vd=client->data; + i2c_detach_client(client); + video_unregister_device(vd); + kfree(vd->priv); + kfree(vd); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa5249_command(struct i2c_client *device, + unsigned int cmd, void *arg) +{ + return -EINVAL; +} + +/* new I2C driver support */ + +static struct i2c_driver i2c_driver_videotext = +{ + IF_NAME, /* name */ + I2C_DRIVERID_SAA5249, /* in i2c.h */ + I2C_DF_NOTIFY, + saa5249_probe, + saa5249_detach, + saa5249_command +}; + +static struct i2c_client client_template = { + "(unset)", + -1, + 0, + 0, + NULL, + &i2c_driver_videotext +}; + +/* + * Wait the given number of jiffies (10ms). This calls the scheduler, so the actual + * delay may be longer. + */ + +static void jdelay(unsigned long delay) +{ + sigset_t oldblocked = current->blocked; + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(delay); + + spin_lock_irq(¤t->sigmask_lock); + current->blocked = oldblocked; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); +} + + +/* + * I2C interfaces + */ + +static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data) +{ + char buf[64]; + + buf[0] = reg; + memcpy(buf+1, data, count); + + if(i2c_master_send(t->client, buf, count+1)==count+1) + return 0; + return -1; +} + +static int i2c_senddata(struct saa5249_device *t, ...) +{ + unsigned char buf[64]; + int v; + int ct=0; + va_list argp; + va_start(argp,t); + + while((v=va_arg(argp,int))!=-1) + buf[ct++]=v; + return i2c_sendbuf(t, buf[0], ct-1, buf+1); +} + +/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop + * handshaking is done by this routine, ack will be sent after the last byte to inhibit further + * sending of data. If uaccess is TRUE, data is written to user-space with put_user. + * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise + */ + +static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf) +{ + if(i2c_master_recv(t->client, buf, count)!=count) + return -1; + return 0; +} + + +/* + * Standard character-device-driver functions + */ + +static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg) +{ + struct saa5249_device *t=vd->priv; + static int virtual_mode = FALSE; + + switch(cmd) + { + case VTXIOCGETINFO: + { + vtx_info_t info; + info.version_major = VTX_VER_MAJ; + info.version_minor = VTX_VER_MIN; + info.numpages = NUM_DAUS; + /*info.cct_type = CCT_TYPE;*/ + if(copy_to_user((void*)arg, &info, sizeof(vtx_info_t))) + return -EFAULT; + return 0; + } + + case VTXIOCCLRPAGE: + { + vtx_pagereq_t req; + + if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) + return -EFAULT; + if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) + return -EINVAL; + memset(t->vdau[req.pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); + t->vdau[req.pgbuf].clrfound = TRUE; + return 0; + } + + case VTXIOCCLRFOUND: + { + vtx_pagereq_t req; + + if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) + return -EFAULT; + if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) + return -EINVAL; + t->vdau[req.pgbuf].clrfound = TRUE; + return 0; + } + + case VTXIOCPAGEREQ: + { + vtx_pagereq_t req; + if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) + return -EFAULT; + if (!(req.pagemask & PGMASK_PAGE)) + req.page = 0; + if (!(req.pagemask & PGMASK_HOUR)) + req.hour = 0; + if (!(req.pagemask & PGMASK_MINUTE)) + req.minute = 0; + if (req.page < 0 || req.page > 0x8ff) /* 7FF ?? */ + return -EINVAL; + req.page &= 0x7ff; + if (req.hour < 0 || req.hour > 0x3f || req.minute < 0 || req.minute > 0x7f || + req.pagemask < 0 || req.pagemask >= PGMASK_MAX || req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) + return -EINVAL; + t->vdau[req.pgbuf].sregs[0] = (req.pagemask & PG_HUND ? 0x10 : 0) | (req.page / 0x100); + t->vdau[req.pgbuf].sregs[1] = (req.pagemask & PG_TEN ? 0x10 : 0) | ((req.page / 0x10) & 0xf); + t->vdau[req.pgbuf].sregs[2] = (req.pagemask & PG_UNIT ? 0x10 : 0) | (req.page & 0xf); + t->vdau[req.pgbuf].sregs[3] = (req.pagemask & HR_TEN ? 0x10 : 0) | (req.hour / 0x10); + t->vdau[req.pgbuf].sregs[4] = (req.pagemask & HR_UNIT ? 0x10 : 0) | (req.hour & 0xf); + t->vdau[req.pgbuf].sregs[5] = (req.pagemask & MIN_TEN ? 0x10 : 0) | (req.minute / 0x10); + t->vdau[req.pgbuf].sregs[6] = (req.pagemask & MIN_UNIT ? 0x10 : 0) | (req.minute & 0xf); + t->vdau[req.pgbuf].stopped = FALSE; + t->vdau[req.pgbuf].clrfound = TRUE; + t->is_searching[req.pgbuf] = TRUE; + return 0; + } + + case VTXIOCGETSTAT: + { + vtx_pagereq_t req; + u8 infobits[10]; + vtx_pageinfo_t info; + int a; + + if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) + return -EFAULT; + if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) + return -EINVAL; + if (!t->vdau[req.pgbuf].stopped) + { + if (i2c_senddata(t, 2, 0, -1) || + i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req.pgbuf].sregs) || + i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) || + i2c_senddata(t, 2, 0, t->vdau[req.pgbuf].sregs[0] | 8, -1) || + i2c_senddata(t, 8, 0, 25, 0, -1)) + return -EIO; + jdelay(PAGE_WAIT); + if (i2c_getdata(t, 10, infobits)) + return -EIO; + + if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) && /* check FOUND-bit */ + (memcmp(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)) || + time_after_eq(jiffies, t->vdau[req.pgbuf].expire))) + { /* check if new page arrived */ + if (i2c_senddata(t, 8, 0, 0, 0, -1) || + i2c_getdata(t, VTX_PAGESIZE, t->vdau[req.pgbuf].pgbuf)) + return -EIO; + t->vdau[req.pgbuf].expire = jiffies + PGBUF_EXPIRE; + memset(t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE); + if (t->virtual_mode) + { + /* Packet X/24 */ + if (i2c_senddata(t, 8, 0, 0x20, 0, -1) || + i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40)) + return -EIO; + /* Packet X/27/0 */ + if (i2c_senddata(t, 8, 0, 0x21, 0, -1) || + i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40)) + return -EIO; + /* Packet 8/30/0...8/30/15 + * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30, + * so we should undo this here. + */ + if (i2c_senddata(t, 8, 0, 0x22, 0, -1) || + i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40)) + return -EIO; + } + t->vdau[req.pgbuf].clrfound = FALSE; + memcpy(t->vdau[req.pgbuf].laststat, infobits, sizeof(infobits)); + } + else + { + memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)); + } + } + else + { + memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)); + } + + info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f); + if (info.pagenum < 0x100) + info.pagenum += 0x800; + info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f); + info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f); + info.charset = ((infobits[7] >> 1) & 7); + info.delete = !!(infobits[3] & 8); + info.headline = !!(infobits[5] & 4); + info.subtitle = !!(infobits[5] & 8); + info.supp_header = !!(infobits[6] & 1); + info.update = !!(infobits[6] & 2); + info.inter_seq = !!(infobits[6] & 4); + info.dis_disp = !!(infobits[6] & 8); + info.serial = !!(infobits[7] & 1); + info.notfound = !!(infobits[8] & 0x10); + info.pblf = !!(infobits[9] & 0x20); + info.hamming = 0; + for (a = 0; a <= 7; a++) + { + if (infobits[a] & 0xf0) + { + info.hamming = 1; + break; + } + } + if (t->vdau[req.pgbuf].clrfound) + info.notfound = 1; + if(copy_to_user(req.buffer, &info, sizeof(vtx_pageinfo_t))) + return -EFAULT; + if (!info.hamming && !info.notfound) + { + t->is_searching[req.pgbuf] = FALSE; + } + return 0; + } + + case VTXIOCGETPAGE: + { + vtx_pagereq_t req; + int start, end; + + if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) + return -EFAULT; + if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS || req.start < 0 || + req.start > req.end || req.end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE)) + return -EINVAL; + if(copy_to_user(req.buffer, &t->vdau[req.pgbuf].pgbuf[req.start], req.end - req.start + 1)) + return -EFAULT; + + /* + * Always read the time directly from SAA5249 + */ + + if (req.start <= 39 && req.end >= 32) + { + int len; + char buf[16]; + start = MAX(req.start, 32); + end = MIN(req.end, 39); + len=end-start+1; + if (i2c_senddata(t, 8, 0, 0, start, -1) || + i2c_getdata(t, len, buf)) + return -EIO; + if(copy_to_user(req.buffer+start-req.start, buf, len)) + return -EFAULT; + } + /* Insert the current header if DAU is still searching for a page */ + if (req.start <= 31 && req.end >= 7 && t->is_searching[req.pgbuf]) + { + char buf[32]; + int len; + start = MAX(req.start, 7); + end = MIN(req.end, 31); + len=end-start+1; + if (i2c_senddata(t, 8, 0, 0, start, -1) || + i2c_getdata(t, len, buf)) + return -EIO; + if(copy_to_user(req.buffer+start-req.start, buf, len)) + return -EFAULT; + } + return 0; + } + + case VTXIOCSTOPDAU: + { + vtx_pagereq_t req; + + if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t))) + return -EFAULT; + if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS) + return -EINVAL; + t->vdau[req.pgbuf].stopped = TRUE; + t->is_searching[req.pgbuf] = FALSE; + return 0; + } + + case VTXIOCPUTPAGE: + case VTXIOCSETDISP: + case VTXIOCPUTSTAT: + return 0; + + case VTXIOCCLRCACHE: + { + if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11, + ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', + ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1)) + return -EIO; + if (i2c_senddata(t, 3, 0x20, -1)) + return -EIO; + jdelay(10 * CLEAR_DELAY); /* I have no idea how long we have to wait here */ + return 0; + } + + case VTXIOCSETVIRT: + { + /* The SAA5249 has virtual-row reception turned on always */ + t->virtual_mode = (int)arg; + return 0; + } + } + return -EINVAL; +} + + +static int saa5249_open(struct video_device *vd, int nb) +{ + struct saa5249_device *t=vd->priv; + int pgbuf; + + if (t->client==NULL) + return -ENODEV; + + if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */ + /* Turn off parity checks (we do this ourselves) */ + i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) || + /* Display TV-picture, no virtual rows */ + i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */ + + { + return -EIO; + } + + for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) + { + memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); + memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); + memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); + t->vdau[pgbuf].expire = 0; + t->vdau[pgbuf].clrfound = TRUE; + t->vdau[pgbuf].stopped = TRUE; + t->is_searching[pgbuf] = FALSE; + } + t->virtual_mode=FALSE; + MOD_INC_USE_COUNT; + return 0; +} + + + +static void saa5249_release(struct video_device *vd) +{ + struct saa5249_device *t=vd->priv; + i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */ + i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */ + MOD_DEC_USE_COUNT; + return; +} + +static long saa5249_write(struct video_device *v, const char *buf, unsigned long l, int nb) +{ + return -EINVAL; +} + +static int __init init_saa_5249 (void) +{ + printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n", + VTX_VER_MAJ, VTX_VER_MIN); + return i2c_add_driver(&i2c_driver_videotext); +} + +static void __exit cleanup_saa_5249 (void) +{ + i2c_del_driver(&i2c_driver_videotext); +} + +module_init(init_saa_5249); +module_exit(cleanup_saa_5249); + +static struct video_device saa_template = +{ + IF_NAME, + VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */ + VID_HARDWARE_SAA5249, + saa5249_open, + saa5249_release, + NULL, /* read */ + saa5249_write, + NULL, /* poll */ + saa5249_ioctl, + /* the rest are null */ +}; + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7110.c linux/drivers/media/video/saa7110.c --- v2.4.0-test6/linux/drivers/media/video/saa7110.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7110.c Wed Dec 29 17:08:55 1999 @@ -0,0 +1,429 @@ +/* + saa7110 - Philips SAA7110(A) video decoder driver + + Copyright (C) 1998 Pauline Middelink + + 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. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "linux/video_decoder.h" + +#define DEBUG(x...) /* remove when no long debugging */ + +#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ +#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ + +#define I2C_SAA7110 0x9C /* or 0x9E */ + +#define I2C_DELAY 10 /* 10 us or 100khz */ + +struct saa7110 { + struct i2c_bus *bus; + int addr; + unsigned char reg[36]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +/* ----------------------------------------------------------------------- */ +/* I2C support functions */ +/* ----------------------------------------------------------------------- */ +static +int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); + i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY); + i2c_stop(decoder->bus); + decoder->reg[subaddr] = data; + UNLOCK_I2C_BUS(decoder->bus); + return ack; +} + +static +int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len) +{ + unsigned subaddr = *data; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY); + while (len-- > 0) { + if (i2c_sendbyte(decoder->bus,*data,0)) { + i2c_stop(decoder->bus); + return -EAGAIN; + } + decoder->reg[subaddr++] = *data++; + } + i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); + + return 0; +} + +static +int saa7110_read(struct saa7110* decoder) +{ + int data; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY); + data = i2c_readbyte(decoder->bus, 1); + i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); + return data; +} + +/* ----------------------------------------------------------------------- */ +/* SAA7110 functions */ +/* ----------------------------------------------------------------------- */ +static +int saa7110_selmux(struct i2c_device *device, int chan) +{ +static const unsigned char modes[9][8] = { +/* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, +/* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, +/* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, +/* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, +/* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, +/* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, +/* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, +/* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, +/* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; + struct saa7110* decoder = device->data; + const unsigned char* ptr = modes[chan]; + + saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ + saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */ + saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */ + saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */ + saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */ + saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */ + saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */ + saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */ + + return 0; +} + +static +int determine_norm(struct i2c_device* dev) +{ + struct saa7110* decoder = dev->data; + int status; + + /* mode changed, start automatic detection */ + status = saa7110_read(decoder); + if ((status & 3) == 0) { + saa7110_write(decoder,0x06,0x80); + if (status & 0x20) { + DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); + saa7110_write(decoder,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); + saa7110_write(decoder,0x2E,0x9A); + return VIDEO_MODE_PAL; + } + + saa7110_write(decoder,0x06,0x00); + if (status & 0x20) { /* 60Hz */ + DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); + saa7110_write(decoder,0x0D,0x06); + saa7110_write(decoder,0x11,0x2C); + saa7110_write(decoder,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + + /* 50Hz -> PAL/SECAM */ + saa7110_write(decoder,0x0D,0x06); + saa7110_write(decoder,0x11,0x59); + saa7110_write(decoder,0x2E,0x9A); + + mdelay(150); /* pause 150 ms */ + + status = saa7110_read(decoder); + if ((status & 0x03) == 0x01) { + DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); + saa7110_write(decoder,0x0D,0x07); + return VIDEO_MODE_SECAM; + } + DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); + return VIDEO_MODE_PAL; +} + +static +int saa7110_attach(struct i2c_device *device) +{ +static const unsigned char initseq[] = { + 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, + 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90, + 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, + 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, + 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, + 0x40, 0x75, 0x01, 0x8C, 0x03}; + struct saa7110* decoder; + int rv; + + device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); + if (device->data == 0) + return -ENOMEM; + + MOD_INC_USE_COUNT; + + /* clear our private data */ + memset(decoder, 0, sizeof(struct saa7110)); + strcpy(device->name, "saa7110"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_PAL; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + + rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); + if (rv < 0) + printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); + else { + saa7110_write(decoder,0x21,0x16); + saa7110_write(decoder,0x0D,0x04); + DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); + saa7110_write(decoder,0x0D,0x06); + } + + /* setup and implicit mode 0 select has been performed */ + return 0; +} + +static +int saa7110_detach(struct i2c_device *device) +{ + struct saa7110* decoder = device->data; + + DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); + + /* stop further output */ + saa7110_write(decoder,0x0E,0x00); + + kfree(device->data); + + MOD_DEC_USE_COUNT; + return 0; +} + +static +int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7110* decoder = device->data; + int v; + + switch (cmd) { + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *dc = arg; + dc->flags = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC + | VIDEO_DECODER_SECAM + | VIDEO_DECODER_AUTO + | VIDEO_DECODER_CCIR; + dc->inputs = SAA7110_MAX_INPUT; + dc->outputs = SAA7110_MAX_OUTPUT; + } + break; + + case DECODER_GET_STATUS: + { + struct saa7110* decoder = device->data; + int status; + int res = 0; + + status = i2c_read(device->bus,device->addr|1); + if (status & 0x40) + res |= DECODER_STATUS_GOOD; + if (status & 0x03) + res |= DECODER_STATUS_COLOR; + + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + case VIDEO_MODE_SECAM: + res |= DECODER_STATUS_SECAM; + break; + } + *(int*)arg = res; + } + break; + + case DECODER_SET_NORM: + v = *(int*)arg; + if (decoder->norm != v) { + decoder->norm = v; + saa7110_write(decoder, 0x06, 0x00); + switch (v) { + case VIDEO_MODE_NTSC: + saa7110_write(decoder, 0x0D, 0x06); + saa7110_write(decoder, 0x11, 0x2C); + saa7110_write(decoder, 0x30, 0x81); +saa7110_write(decoder, 0x2A, 0xDF); + break; + case VIDEO_MODE_PAL: + saa7110_write(decoder, 0x0D, 0x06); + saa7110_write(decoder, 0x11, 0x59); + saa7110_write(decoder, 0x2E, 0x9A); + break; + case VIDEO_MODE_SECAM: + saa7110_write(decoder, 0x0D, 0x07); + saa7110_write(decoder, 0x11, 0x59); + saa7110_write(decoder, 0x2E, 0x9A); + break; + case VIDEO_MODE_AUTO: + *(int*)arg = determine_norm(device); + break; + default: + return -EPERM; + } + } + break; + + case DECODER_SET_INPUT: + v = *(int*)arg; + if (v<0 || v>SAA7110_MAX_INPUT) + return -EINVAL; + if (decoder->input != v) { + decoder->input = v; + saa7110_selmux(device, v); + } + break; + + case DECODER_SET_OUTPUT: + v = *(int*)arg; + /* not much choice of outputs */ + if (v != 0) + return -EINVAL; + break; + + case DECODER_ENABLE_OUTPUT: + v = *(int*)arg; + if (decoder->enable != v) { + decoder->enable = v; + saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; + saa7110_write(decoder, 0x19, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; + saa7110_write(decoder, 0x13, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; + saa7110_write(decoder, 0x12, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); + } + } + break; + + case DECODER_DUMP: + for (v=0; v<34; v+=16) { + int j; + DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); + for (j=0; j<16; j++) { + DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); + } + DEBUG(printk(KERN_INFO "\n")); + } + break; + + default: + DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd)); + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7110 = +{ + "saa7110", /* name */ + + I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ + I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ + + saa7110_attach, + saa7110_detach, + saa7110_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7110_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7110); +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7110); +} +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7111.c linux/drivers/media/video/saa7111.c --- v2.4.0-test6/linux/drivers/media/video/saa7111.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7111.c Wed Dec 29 17:08:55 1999 @@ -0,0 +1,418 @@ +/* + saa7111 - Philips SAA7111A video decoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEBUG(x) /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct saa7111 { + struct i2c_bus *bus; + int addr; + unsigned char reg[32]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_SAA7111 0x48 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) +{ + int ack = 0; + unsigned subaddr; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) +{ + int data; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +/* ----------------------------------------------------------------------- */ + +static int saa7111_attach(struct i2c_device *device) +{ + int i; + struct saa7111 *decoder; + + static const unsigned char init[] = + { + 0x00, 0x00, /* 00 - ID byte */ + 0x01, 0x00, /* 01 - reserved */ + + /*front end */ + 0x02, 0xd0, /* 02 - FUSE=3, GUDL=2, MODE=0 */ + 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ + 0x04, 0x00, /* 04 - GAI1=256 */ + 0x05, 0x00, /* 05 - GAI2=256 */ + + /* decoder */ + 0x06, 0xf6, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ + 0x07, 0xdd, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ + 0x08, 0xc8, /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */ + 0x09, 0x01, /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */ + 0x0a, 0x80, /* 0a - BRIG=128 */ + 0x0b, 0x47, /* 0b - CONT=1.109 */ + 0x0c, 0x40, /* 0c - SATN=1.0 */ + 0x0d, 0x00, /* 0d - HUE=0 */ + 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */ + 0x0f, 0x00, /* 0f - reserved */ + 0x10, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ + 0x11, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */ + 0x12, 0x00, /* 12 - output control 2 */ + 0x13, 0x00, /* 13 - output control 3 */ + 0x14, 0x00, /* 14 - reserved */ + 0x15, 0x00, /* 15 - VBI */ + 0x16, 0x00, /* 16 - VBI */ + 0x17, 0x00, /* 17 - VBI */ + }; + + device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); + if (decoder == NULL) { + return -ENOMEM; + } + MOD_INC_USE_COUNT; + + memset(decoder, 0, sizeof(struct saa7111)); + strcpy(device->name, "saa7111"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_NTSC; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + + i = saa7111_write_block(decoder, init, sizeof(init)); + if (i < 0) { + printk(KERN_ERR "%s_attach: init status %d\n", device->name, i); + } else { + printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00)); + } + return 0; +} + + +static int saa7111_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7111 *decoder = device->data; + + switch (cmd) { + +#if defined(DECODER_DUMP) + case DECODER_DUMP: + { + int i; + + for (i = 0; i < 32; i += 16) { + int j; + + printk("KERN_DEBUG %s: %03x", device->name, i); + for (j = 0; j < 16; ++j) { + printk(" %02x", saa7111_read(decoder, i + j)); + } + printk("\n"); + } + } + break; +#endif /* defined(DECODER_DUMP) */ + + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *cap = arg; + + cap->flags + = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC + | VIDEO_DECODER_AUTO + | VIDEO_DECODER_CCIR; + cap->inputs = 8; + cap->outputs = 1; + } + break; + + case DECODER_GET_STATUS: + { + int *iarg = arg; + int status; + int res; + + status = saa7111_read(decoder, 0x1f); + res = 0; + if ((status & (1 << 6)) == 0) { + res |= DECODER_STATUS_GOOD; + } + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + default: + case VIDEO_MODE_AUTO: + if ((status & (1 << 5)) != 0) { + res |= DECODER_STATUS_NTSC; + } else { + res |= DECODER_STATUS_PAL; + } + break; + } + if ((status & (1 << 0)) != 0) { + res |= DECODER_STATUS_COLOR; + } + *iarg = res; + } + break; + + case DECODER_SET_NORM: + { + int *iarg = arg; + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); + break; + + case VIDEO_MODE_PAL: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); + break; + + case VIDEO_MODE_AUTO: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); + break; + + default: + return -EINVAL; + + } + decoder->norm = *iarg; + } + break; + + case DECODER_SET_INPUT: + { + int *iarg = arg; + + if (*iarg < 0 || *iarg > 7) { + return -EINVAL; + } + if (decoder->input != *iarg) { + decoder->input = *iarg; + /* select mode */ + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + /* bypass chrominance trap for modes 4..7 */ + saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); + } + } + break; + + case DECODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case DECODER_ENABLE_OUTPUT: + { + int *iarg = arg; + int enable = (*iarg != 0); + + if (decoder->enable != enable) { + decoder->enable = enable; + +// RJ: If output should be disabled (for playing videos), we also need a open PLL. + // The input is set to 0 (where no input source is connected), although this + // is not necessary. + // + // If output should be enabled, we have to reverse the above. + + if (decoder->enable) { + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb)); + saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); + } else { + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8)); + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); + saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3)); + } + } + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; + saa7111_write(decoder, 0x0a, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; + saa7111_write(decoder, 0x0b, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; + saa7111_write(decoder, 0x0c, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8); + } + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7111 = +{ + "saa7111", /* name */ + I2C_DRIVERID_VIDEODECODER, /* ID */ + I2C_SAA7111, I2C_SAA7111 + 1, + + saa7111_attach, + saa7111_detach, + saa7111_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7111_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7111); +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7111); +} + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7121.h linux/drivers/media/video/saa7121.h --- v2.4.0-test6/linux/drivers/media/video/saa7121.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7121.h Wed Nov 10 13:58:46 1999 @@ -0,0 +1,132 @@ +/* saa7121.h - saa7121 initializations + Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) + + 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 __SAA7121_H__ +#define __SAA7121_H__ + +#define NTSC_BURST_START 0x19 /* 28 */ +#define NTSC_BURST_END 0x1d /* 29 */ +#define NTSC_CHROMA_PHASE 0x67 /* 5a */ +#define NTSC_GAINU 0x76 /* 5b */ +#define NTSC_GAINV 0xa5 /* 5c */ +#define NTSC_BLACK_LEVEL 0x2a /* 5d */ +#define NTSC_BLANKING_LEVEL 0x2e /* 5e */ +#define NTSC_VBI_BLANKING 0x2e /* 5f */ +#define NTSC_DAC_CONTROL 0x11 /* 61 */ +#define NTSC_BURST_AMP 0x3f /* 62 */ +#define NTSC_SUBC3 0x1f /* 63 */ +#define NTSC_SUBC2 0x7c /* 64 */ +#define NTSC_SUBC1 0xf0 /* 65 */ +#define NTSC_SUBC0 0x21 /* 66 */ +#define NTSC_HTRIG 0x72 /* 6c */ +#define NTSC_VTRIG 0x00 /* 6c */ +#define NTSC_MULTI 0x30 /* 6e */ +#define NTSC_CCTTX 0x11 /* 6f */ +#define NTSC_FIRST_ACTIVE 0x12 /* 7a */ +#define NTSC_LAST_ACTIVE 0x02 /* 7b */ +#define NTSC_MSB_VERTICAL 0x40 /* 7c */ + +#define PAL_BURST_START 0x21 /* 28 */ +#define PAL_BURST_END 0x1d /* 29 */ +#define PAL_CHROMA_PHASE 0x3f /* 5a */ +#define PAL_GAINU 0x7d /* 5b */ +#define PAL_GAINV 0xaf /* 5c */ +#define PAL_BLACK_LEVEL 0x23 /* 5d */ +#define PAL_BLANKING_LEVEL 0x35 /* 5e */ +#define PAL_VBI_BLANKING 0x35 /* 5f */ +#define PAL_DAC_CONTROL 0x02 /* 61 */ +#define PAL_BURST_AMP 0x2f /* 62 */ +#define PAL_SUBC3 0xcb /* 63 */ +#define PAL_SUBC2 0x8a /* 64 */ +#define PAL_SUBC1 0x09 /* 65 */ +#define PAL_SUBC0 0x2a /* 66 */ +#define PAL_HTRIG 0x86 /* 6c */ +#define PAL_VTRIG 0x04 /* 6d */ +#define PAL_MULTI 0x20 /* 6e */ +#define PAL_CCTTX 0x15 /* 6f */ +#define PAL_FIRST_ACTIVE 0x16 /* 7a */ +#define PAL_LAST_ACTIVE 0x36 /* 7b */ +#define PAL_MSB_VERTICAL 0x40 /* 7c */ + +/* Initialization Sequence */ + +static __u8 init7121ntsc[] = { + 0x26, 0x0, 0x27, 0x0, + 0x28, NTSC_BURST_START, 0x29, NTSC_BURST_END, + 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, + 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, + 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, + 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, + 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, + 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, + 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, + 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, + 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, + 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, + 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, + 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, + 0x5a, NTSC_CHROMA_PHASE, 0x5b, NTSC_GAINU, + 0x5c, NTSC_GAINV, 0x5d, NTSC_BLACK_LEVEL, + 0x5e, NTSC_BLANKING_LEVEL, 0x5f, NTSC_VBI_BLANKING, + 0x60, 0x0, 0x61, NTSC_DAC_CONTROL, + 0x62, NTSC_BURST_AMP, 0x63, NTSC_SUBC3, + 0x64, NTSC_SUBC2, 0x65, NTSC_SUBC1, + 0x66, NTSC_SUBC0, 0x67, 0x80, 0x68, 0x80, + 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, + 0x6c, NTSC_HTRIG, 0x6d, NTSC_VTRIG, + 0x6e, NTSC_MULTI, 0x6f, NTSC_CCTTX, + 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, + 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, + 0x78, 0x0, 0x79, 0x0, 0x7a, NTSC_FIRST_ACTIVE, + 0x7b, NTSC_LAST_ACTIVE, 0x7c, NTSC_MSB_VERTICAL, + 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 +}; +#define INIT7121LEN (sizeof(init7121ntsc)/2) + +static __u8 init7121pal[] = { + 0x26, 0x0, 0x27, 0x0, + 0x28, PAL_BURST_START, 0x29, PAL_BURST_END, + 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, + 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, + 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, + 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, + 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, + 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, + 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, + 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, + 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, + 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, + 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, + 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, + 0x5a, PAL_CHROMA_PHASE, 0x5b, PAL_GAINU, + 0x5c, PAL_GAINV, 0x5d, PAL_BLACK_LEVEL, + 0x5e, PAL_BLANKING_LEVEL, 0x5f, PAL_VBI_BLANKING, + 0x60, 0x0, 0x61, PAL_DAC_CONTROL, + 0x62, PAL_BURST_AMP, 0x63, PAL_SUBC3, + 0x64, PAL_SUBC2, 0x65, PAL_SUBC1, + 0x66, PAL_SUBC0, 0x67, 0x80, 0x68, 0x80, + 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, + 0x6c, PAL_HTRIG, 0x6d, PAL_VTRIG, + 0x6e, PAL_MULTI, 0x6f, PAL_CCTTX, + 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, + 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, + 0x78, 0x0, 0x79, 0x0, 0x7a, PAL_FIRST_ACTIVE, + 0x7b, PAL_LAST_ACTIVE, 0x7c, PAL_MSB_VERTICAL, + 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 +}; +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7146.h linux/drivers/media/video/saa7146.h --- v2.4.0-test6/linux/drivers/media/video/saa7146.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7146.h Wed Nov 10 13:58:46 1999 @@ -0,0 +1,117 @@ +/* + saa7146.h - definitions philips saa7146 based cards + Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) + + 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 __SAA7146__ +#define __SAA7146__ + +#define SAA7146_VERSION_CODE 0x000101 + +#include +#include + +#include +#include + +#ifndef O_NONCAP +#define O_NONCAP O_TRUNC +#endif + +#define MAX_GBUFFERS 2 +#define FBUF_SIZE 0x190000 + +#ifdef __KERNEL__ + +struct saa7146_window +{ + int x, y; + ushort width, height; + ushort bpp, bpl; + ushort swidth, sheight; + short cropx, cropy; + ushort cropwidth, cropheight; + unsigned long vidadr; + int color_fmt; + ushort depth; +}; + +/* Per-open data for handling multiple opens on one device */ +struct device_open +{ + int isopen; + int noncapturing; + struct saa7146 *dev; +}; +#define MAX_OPENS 3 + +struct saa7146 +{ + struct video_device video_dev; + struct video_picture picture; + struct video_audio audio_dev; + struct video_info vidinfo; + int user; + int cap; + int capuser; + int irqstate; /* irq routine is state driven */ + int writemode; + int playmode; + unsigned int nr; + unsigned long irq; /* IRQ used by SAA7146 card */ + unsigned short id; + struct i2c_bus i2c; + struct pci_dev *dev; + unsigned char revision; + unsigned char boardcfg[64]; /* 64 bytes of config from eeprom */ + unsigned long saa7146_adr; /* bus address of IO mem from PCI BIOS */ + struct saa7146_window win; + unsigned char *saa7146_mem; /* pointer to mapped IO memory */ + struct device_open open_data[MAX_OPENS]; +#define MAX_MARKS 16 + /* for a/v sync */ + int endmark[MAX_MARKS], endmarkhead, endmarktail; + u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2, + *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out, + *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in, + *pagea1out, *pagea2in, *pagea2out; + wait_queue_head_t i2cq, debiq, audq, vidq; + u8 *vidbuf, *audbuf, *osdbuf, *dmadebi; + int audhead, vidhead, osdhead, audtail, vidtail, osdtail; + spinlock_t lock; /* the device lock */ +}; +#endif + +#ifdef _ALPHA_SAA7146 +#define saawrite(dat,adr) writel((dat),(char *) (saa->saa7146_adr+(adr))) +#define saaread(adr) readl(saa->saa7146_adr+(adr)) +#else +#define saawrite(dat,adr) writel((dat), (char *) (saa->saa7146_mem+(adr))) +#define saaread(adr) readl(saa->saa7146_mem+(adr)) +#endif + +#define saaand(dat,adr) saawrite((dat) & saaread(adr), adr) +#define saaor(dat,adr) saawrite((dat) | saaread(adr), adr) +#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr) + +/* bitmask of attached hardware found */ +#define SAA7146_UNKNOWN 0x00000000 +#define SAA7146_SAA7111 0x00000001 +#define SAA7146_SAA7121 0x00000002 +#define SAA7146_IBMMPEG 0x00000004 + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7146reg.h linux/drivers/media/video/saa7146reg.h --- v2.4.0-test6/linux/drivers/media/video/saa7146reg.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7146reg.h Wed Nov 10 13:58:46 1999 @@ -0,0 +1,283 @@ +/* + saa7146.h - definitions philips saa7146 based cards + Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) + + 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 __SAA7146_REG__ +#define __SAA7146_REG__ +#define SAA7146_BASE_ODD1 0x00 +#define SAA7146_BASE_EVEN1 0x04 +#define SAA7146_PROT_ADDR1 0x08 +#define SAA7146_PITCH1 0x0c +#define SAA7146_PAGE1 0x10 +#define SAA7146_NUM_LINE_BYTE1 0x14 +#define SAA7146_BASE_ODD2 0x18 +#define SAA7146_BASE_EVEN2 0x1c +#define SAA7146_PROT_ADDR2 0x20 +#define SAA7146_PITCH2 0x24 +#define SAA7146_PAGE2 0x28 +#define SAA7146_NUM_LINE_BYTE2 0x2c +#define SAA7146_BASE_ODD3 0x30 +#define SAA7146_BASE_EVEN3 0x34 +#define SAA7146_PROT_ADDR3 0x38 +#define SAA7146_PITCH3 0x3c +#define SAA7146_PAGE3 0x40 +#define SAA7146_NUM_LINE_BYTE3 0x44 +#define SAA7146_PCI_BT_V1 0x48 +#define SAA7146_PCI_BT_V2 0x49 +#define SAA7146_PCI_BT_V3 0x4a +#define SAA7146_PCI_BT_DEBI 0x4b +#define SAA7146_PCI_BT_A 0x4c +#define SAA7146_DD1_INIT 0x50 +#define SAA7146_DD1_STREAM_B 0x54 +#define SAA7146_DD1_STREAM_A 0x56 +#define SAA7146_BRS_CTRL 0x58 +#define SAA7146_HPS_CTRL 0x5c +#define SAA7146_HPS_V_SCALE 0x60 +#define SAA7146_HPS_V_GAIN 0x64 +#define SAA7146_HPS_H_PRESCALE 0x68 +#define SAA7146_HPS_H_SCALE 0x6c +#define SAA7146_BCS_CTRL 0x70 +#define SAA7146_CHROMA_KEY_RANGE 0x74 +#define SAA7146_CLIP_FORMAT_CTRL 0x78 +#define SAA7146_DEBI_CONFIG 0x7c +#define SAA7146_DEBI_COMMAND 0x80 +#define SAA7146_DEBI_PAGE 0x84 +#define SAA7146_DEBI_AD 0x88 +#define SAA7146_I2C_TRANSFER 0x8c +#define SAA7146_I2C_STATUS 0x90 +#define SAA7146_BASE_A1_IN 0x94 +#define SAA7146_PROT_A1_IN 0x98 +#define SAA7146_PAGE_A1_IN 0x9C +#define SAA7146_BASE_A1_OUT 0xa0 +#define SAA7146_PROT_A1_OUT 0xa4 +#define SAA7146_PAGE_A1_OUT 0xa8 +#define SAA7146_BASE_A2_IN 0xac +#define SAA7146_PROT_A2_IN 0xb0 +#define SAA7146_PAGE_A2_IN 0xb4 +#define SAA7146_BASE_A2_OUT 0xb8 +#define SAA7146_PROT_A2_OUT 0xbc +#define SAA7146_PAGE_A2_OUT 0xc0 +#define SAA7146_RPS_PAGE0 0xc4 +#define SAA7146_RPS_PAGE1 0xc8 +#define SAA7146_RPS_THRESH0 0xcc +#define SAA7146_RPS_THRESH1 0xd0 +#define SAA7146_RPS_TOV0 0xd4 +#define SAA7146_RPS_TOV1 0xd8 +#define SAA7146_IER 0xdc +#define SAA7146_GPIO_CTRL 0xe0 +#define SAA7146_EC1SSR 0xe4 +#define SAA7146_EC2SSR 0xe8 +#define SAA7146_ECT1R 0xec +#define SAA7146_ECT2R 0xf0 +#define SAA7146_ACON1 0xf4 +#define SAA7146_ACON2 0xf8 +#define SAA7146_MC1 0xfc +#define SAA7146_MC2 0x100 +#define SAA7146_RPS_ADDR0 0x104 +#define SAA7146_RPS_ADDR1 0x108 +#define SAA7146_ISR 0x10c +#define SAA7146_PSR 0x110 +#define SAA7146_SSR 0x114 +#define SAA7146_EC1R 0x118 +#define SAA7146_EC2R 0x11c +#define SAA7146_VDP1 0x120 +#define SAA7146_VDP2 0x124 +#define SAA7146_VDP3 0x128 +#define SAA7146_ADP1 0x12c +#define SAA7146_ADP2 0x130 +#define SAA7146_ADP3 0x134 +#define SAA7146_ADP4 0x138 +#define SAA7146_DDP 0x13c +#define SAA7146_LEVEL_REP 0x140 +#define SAA7146_FB_BUFFER1 0x144 +#define SAA7146_FB_BUFFER2 0x148 +#define SAA7146_A_TIME_SLOT1 0x180 +#define SAA7146_A_TIME_SLOT2 0x1C0 + +/* bitfield defines */ +#define MASK_31 0x80000000 +#define MASK_30 0x40000000 +#define MASK_29 0x20000000 +#define MASK_28 0x10000000 +#define MASK_27 0x08000000 +#define MASK_26 0x04000000 +#define MASK_25 0x02000000 +#define MASK_24 0x01000000 +#define MASK_23 0x00800000 +#define MASK_22 0x00400000 +#define MASK_21 0x00200000 +#define MASK_20 0x00100000 +#define MASK_19 0x00080000 +#define MASK_18 0x00040000 +#define MASK_17 0x00020000 +#define MASK_16 0x00010000 +#define MASK_15 0x00008000 +#define MASK_14 0x00004000 +#define MASK_13 0x00002000 +#define MASK_12 0x00001000 +#define MASK_11 0x00000800 +#define MASK_10 0x00000400 +#define MASK_09 0x00000200 +#define MASK_08 0x00000100 +#define MASK_07 0x00000080 +#define MASK_06 0x00000040 +#define MASK_05 0x00000020 +#define MASK_04 0x00000010 +#define MASK_03 0x00000008 +#define MASK_02 0x00000004 +#define MASK_01 0x00000002 +#define MASK_00 0x00000001 +#define MASK_B0 0x000000ff +#define MASK_B1 0x0000ff00 +#define MASK_B2 0x00ff0000 +#define MASK_B3 0xff000000 +#define MASK_W0 0x0000ffff +#define MASK_W1 0xffff0000 +#define MASK_PA 0xfffffffc +#define MASK_PR 0xfffffffe +#define MASK_ER 0xffffffff +#define MASK_NONE 0x00000000 + +#define SAA7146_PAGE_MAP_EN MASK_11 +/* main control register 1 */ +#define SAA7146_MC1_MRST_N MASK_15 +#define SAA7146_MC1_ERPS1 MASK_13 +#define SAA7146_MC1_ERPS0 MASK_12 +#define SAA7146_MC1_EDP MASK_11 +#define SAA7146_MC1_EVP MASK_10 +#define SAA7146_MC1_EAP MASK_09 +#define SAA7146_MC1_EI2C MASK_08 +#define SAA7146_MC1_TR_E_DEBI MASK_07 +#define SAA7146_MC1_TR_E_1 MASK_06 +#define SAA7146_MC1_TR_E_2 MASK_05 +#define SAA7146_MC1_TR_E_3 MASK_04 +#define SAA7146_MC1_TR_E_A2_OUT MASK_03 +#define SAA7146_MC1_TR_E_A2_IN MASK_02 +#define SAA7146_MC1_TR_E_A1_OUT MASK_01 +#define SAA7146_MC1_TR_E_A1_IN MASK_00 +/* main control register 2 */ +#define SAA7146_MC2_RPS_SIG4 MASK_15 +#define SAA7146_MC2_RPS_SIG3 MASK_14 +#define SAA7146_MC2_RPS_SIG2 MASK_13 +#define SAA7146_MC2_RPS_SIG1 MASK_12 +#define SAA7146_MC2_RPS_SIG0 MASK_11 +#define SAA7146_MC2_UPLD_D1_B MASK_10 +#define SAA7146_MC2_UPLD_D1_A MASK_09 +#define SAA7146_MC2_UPLD_BRS MASK_08 +#define SAA7146_MC2_UPLD_HPS_H MASK_06 +#define SAA7146_MC2_UPLD_HPS_V MASK_05 +#define SAA7146_MC2_UPLD_DMA3 MASK_04 +#define SAA7146_MC2_UPLD_DMA2 MASK_03 +#define SAA7146_MC2_UPLD_DMA1 MASK_02 +#define SAA7146_MC2_UPLD_DEBI MASK_01 +#define SAA7146_MC2_UPLD_I2C MASK_00 +/* Primary Status Register and Interrupt Enable/Status Registers */ +#define SAA7146_PSR_PPEF MASK_31 +#define SAA7146_PSR_PABO MASK_30 +#define SAA7146_PSR_PPED MASK_29 +#define SAA7146_PSR_RPS_I1 MASK_28 +#define SAA7146_PSR_RPS_I0 MASK_27 +#define SAA7146_PSR_RPS_LATE1 MASK_26 +#define SAA7146_PSR_RPS_LATE0 MASK_25 +#define SAA7146_PSR_RPS_E1 MASK_24 +#define SAA7146_PSR_RPS_E0 MASK_23 +#define SAA7146_PSR_RPS_TO1 MASK_22 +#define SAA7146_PSR_RPS_TO0 MASK_21 +#define SAA7146_PSR_UPLD MASK_20 +#define SAA7146_PSR_DEBI_S MASK_19 +#define SAA7146_PSR_DEBI_E MASK_18 +#define SAA7146_PSR_I2C_S MASK_17 +#define SAA7146_PSR_I2C_E MASK_16 +#define SAA7146_PSR_A2_IN MASK_15 +#define SAA7146_PSR_A2_OUT MASK_14 +#define SAA7146_PSR_A1_IN MASK_13 +#define SAA7146_PSR_A1_OUT MASK_12 +#define SAA7146_PSR_AFOU MASK_11 +#define SAA7146_PSR_V_PE MASK_10 +#define SAA7146_PSR_VFOU MASK_09 +#define SAA7146_PSR_FIDA MASK_08 +#define SAA7146_PSR_FIDB MASK_07 +#define SAA7146_PSR_PIN3 MASK_06 +#define SAA7146_PSR_PIN2 MASK_05 +#define SAA7146_PSR_PIN1 MASK_04 +#define SAA7146_PSR_PIN0 MASK_03 +#define SAA7146_PSR_ECS MASK_02 +#define SAA7146_PSR_EC3S MASK_01 +#define SAA7146_PSR_EC0S MASK_00 +/* Secondary Status Register */ +#define SAA7146_SSR_PRQ MASK_31 +#define SAA7146_SSR_PMA MASK_30 +#define SAA7146_SSR_RPS_RE1 MASK_29 +#define SAA7146_SSR_RPS_PE1 MASK_28 +#define SAA7146_SSR_RPS_A1 MASK_27 +#define SAA7146_SSR_RPS_RE0 MASK_26 +#define SAA7146_SSR_RPS_PE0 MASK_25 +#define SAA7146_SSR_RPS_A0 MASK_24 +#define SAA7146_SSR_DEBI_TO MASK_23 +#define SAA7146_SSR_DEBI_EF MASK_22 +#define SAA7146_SSR_I2C_EA MASK_21 +#define SAA7146_SSR_I2C_EW MASK_20 +#define SAA7146_SSR_I2C_ER MASK_19 +#define SAA7146_SSR_I2C_EL MASK_18 +#define SAA7146_SSR_I2C_EF MASK_17 +#define SAA7146_SSR_V3P MASK_16 +#define SAA7146_SSR_V2P MASK_15 +#define SAA7146_SSR_V1P MASK_14 +#define SAA7146_SSR_VF3 MASK_13 +#define SAA7146_SSR_VF2 MASK_12 +#define SAA7146_SSR_VF1 MASK_11 +#define SAA7146_SSR_AF2_IN MASK_10 +#define SAA7146_SSR_AF2_OUT MASK_09 +#define SAA7146_SSR_AF1_IN MASK_08 +#define SAA7146_SSR_AF1_OUT MASK_07 +#define SAA7146_SSR_VGT MASK_05 +#define SAA7146_SSR_LNQG MASK_04 +#define SAA7146_SSR_EC5S MASK_03 +#define SAA7146_SSR_EC4S MASK_02 +#define SAA7146_SSR_EC2S MASK_01 +#define SAA7146_SSR_EC1S MASK_00 +/* I2C status register */ +#define SAA7146_I2C_ABORT MASK_07 +#define SAA7146_I2C_SPERR MASK_06 +#define SAA7146_I2C_APERR MASK_05 +#define SAA7146_I2C_DTERR MASK_04 +#define SAA7146_I2C_DRERR MASK_03 +#define SAA7146_I2C_AL MASK_02 +#define SAA7146_I2C_ERR MASK_01 +#define SAA7146_I2C_BUSY MASK_00 +/* output formats */ +#define SAA7146_YUV422 0 +#define SAA7146_RGB16 0 +#define SAA7146_YUV444 1 +#define SAA7146_RGB24 1 +#define SAA7146_ARGB32 2 +#define SAA7146_YUV411 3 +#define SAA7146_ARGB15 3 +#define SAA7146_YUV2 4 +#define SAA7146_RGAB15 4 +#define SAA7146_Y8 6 +#define SAA7146_YUV8 7 +#define SAA7146_RGB8 7 +#define SAA7146_YUV444p 8 +#define SAA7146_YUV422p 9 +#define SAA7146_YUV420p 10 +#define SAA7146_YUV1620 11 +#define SAA7146_Y1 13 +#define SAA7146_Y2 14 +#define SAA7146_YUV1 15 +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7185.c linux/drivers/media/video/saa7185.c --- v2.4.0-test6/linux/drivers/media/video/saa7185.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7185.c Wed Dec 29 17:08:55 1999 @@ -0,0 +1,377 @@ +/* + saa7185 - Philips SAA7185B video encoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct saa7185 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_SAA7185 0x88 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) +{ + int ack = 0; + unsigned subaddr; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +/* ----------------------------------------------------------------------- */ + +static const unsigned char init_common[] = +{ + 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */ + + 0x42, 0x6b, /* OVLY0=107 */ + 0x43, 0x00, /* OVLU0=0 white */ + 0x44, 0x00, /* OVLV0=0 */ + 0x45, 0x22, /* OVLY1=34 */ + 0x46, 0xac, /* OVLU1=172 yellow */ + 0x47, 0x0e, /* OVLV1=14 */ + 0x48, 0x03, /* OVLY2=3 */ + 0x49, 0x1d, /* OVLU2=29 cyan */ + 0x4a, 0xac, /* OVLV2=172 */ + 0x4b, 0xf0, /* OVLY3=240 */ + 0x4c, 0xc8, /* OVLU3=200 green */ + 0x4d, 0xb9, /* OVLV3=185 */ + 0x4e, 0xd4, /* OVLY4=212 */ + 0x4f, 0x38, /* OVLU4=56 magenta */ + 0x50, 0x47, /* OVLV4=71 */ + 0x51, 0xc1, /* OVLY5=193 */ + 0x52, 0xe3, /* OVLU5=227 red */ + 0x53, 0x54, /* OVLV5=84 */ + 0x54, 0xa3, /* OVLY6=163 */ + 0x55, 0x54, /* OVLU6=84 blue */ + 0x56, 0xf2, /* OVLV6=242 */ + 0x57, 0x90, /* OVLY7=144 */ + 0x58, 0x00, /* OVLU7=0 black */ + 0x59, 0x00, /* OVLV7=0 */ + + 0x5a, 0x00, /* CHPS=0 */ + 0x5b, 0x76, /* GAINU=118 */ + 0x5c, 0xa5, /* GAINV=165 */ + 0x5d, 0x3c, /* BLCKL=60 */ + 0x5e, 0x3a, /* BLNNL=58 */ + 0x5f, 0x3a, /* CCRS=0, BLNVB=58 */ + 0x60, 0x00, /* NULL */ + +/* 0x61 - 0x66 set according to norm */ + + 0x67, 0x00, /* 0 : caption 1st byte odd field */ + 0x68, 0x00, /* 0 : caption 2nd byte odd field */ + 0x69, 0x00, /* 0 : caption 1st byte even field */ + 0x6a, 0x00, /* 0 : caption 2nd byte even field */ + + 0x6b, 0x91, /* MODIN=2, PCREF=0, SCCLN=17 */ + 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */ + 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ + + 0x6e, 0x0e, /* HTRIG=0x00e, approx. centered, at least for PAL */ + 0x6f, 0x00, /* HTRIG upper bits */ + 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ + +/* The following should not be needed */ + + 0x71, 0x15, /* BMRQ=0x115 */ + 0x72, 0x90, /* EMRQ=0x690 */ + 0x73, 0x61, /* EMRQ=0x690, BMRQ=0x115 */ + 0x74, 0x00, /* NULL */ + 0x75, 0x00, /* NULL */ + 0x76, 0x00, /* NULL */ + 0x77, 0x15, /* BRCV=0x115 */ + 0x78, 0x90, /* ERCV=0x690 */ + 0x79, 0x61, /* ERCV=0x690, BRCV=0x115 */ + +/* Field length controls */ + + 0x7a, 0x70, /* FLC=0 */ + +/* The following should not be needed if SBLN = 1 */ + + 0x7b, 0x16, /* FAL=22 */ + 0x7c, 0x35, /* LAL=244 */ + 0x7d, 0x20, /* LAL=244, FAL=22 */ +}; + +static const unsigned char init_pal[] = +{ + 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ + 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ + 0x63, 0xcb, /* FSC0 */ + 0x64, 0x8a, /* FSC1 */ + 0x65, 0x09, /* FSC2 */ + 0x66, 0x2a, /* FSC3 */ +}; + +static const unsigned char init_ntsc[] = +{ + 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ + 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ + 0x63, 0x1f, /* FSC0 */ + 0x64, 0x7c, /* FSC1 */ + 0x65, 0xf0, /* FSC2 */ + 0x66, 0x21, /* FSC3 */ +}; + +static int saa7185_attach(struct i2c_device *device) +{ + int i; + struct saa7185 *encoder; + + device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); + if (encoder == NULL) { + return -ENOMEM; + } + MOD_INC_USE_COUNT; + + memset(encoder, 0, sizeof(struct saa7185)); + strcpy(device->name, "saa7185"); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_NTSC; + encoder->enable = 1; + + i = saa7185_write_block(encoder, init_common, sizeof(init_common)); + if (i >= 0) { + i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + } + if (i < 0) { + printk(KERN_ERR "%s_attach: init error %d\n", device->name, i); + } + return 0; +} + + +static int saa7185_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7185 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + cap->flags + = VIDEO_ENCODER_PAL + | VIDEO_ENCODER_NTSC + | VIDEO_ENCODER_SECAM + | VIDEO_ENCODER_CCIR; + cap->inputs = 1; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int *iarg = arg; + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + break; + + case VIDEO_MODE_PAL: + saa7185_write_block(encoder, init_pal, sizeof(init_pal)); + break; + + case VIDEO_MODE_SECAM: + default: + return -EINVAL; + + } + encoder->norm = *iarg; + } + break; + + case ENCODER_SET_INPUT: + { + int *iarg = arg; + +#if 0 + /* not much choice of inputs */ + if (*iarg != 0) { + return -EINVAL; + } +#else + /* RJ: *iarg = 0: input is from SA7111 + *iarg = 1: input is from ZR36060 */ + + switch (*iarg) { + + case 0: + /* Switch RTCE to 1 */ + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); + break; + + case 1: + /* Switch RTCE to 0 */ + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); + break; + + default: + return -EINVAL; + + } +#endif + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7185 = +{ + "saa7185", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_SAA7185, I2C_SAA7185 + 1, + + saa7185_attach, + saa7185_detach, + saa7185_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7185_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7185); +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7185); +} + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/saa7196.h linux/drivers/media/video/saa7196.h --- v2.4.0-test6/linux/drivers/media/video/saa7196.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/saa7196.h Fri May 7 11:05:30 1999 @@ -0,0 +1,117 @@ +/* + Definitions for the Philips SAA7196 digital video decoder, + scaler, and clock generator circuit (DESCpro), as used in + the PlanB video input of the Powermac 7x00/8x00 series. + + Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) + + The register defines are shamelessly copied from the meteor + driver out of NetBSD (with permission), + and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe + (Thanks !) + + Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) + + The default values used for PlanB are my mistakes. +*/ + +/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */ + +#ifndef _SAA7196_H_ +#define _SAA7196_H_ + +#define SAA7196_NUMREGS 0x31 /* Number of registers (used)*/ +#define NUM_SUPPORTED_NORM 3 /* Number of supported norms by PlanB */ + +/* Decoder part: */ +#define SAA7196_IDEL 0x00 /* Increment delay */ +#define SAA7196_HSB5 0x01 /* H-sync begin; 50 hz */ +#define SAA7196_HSS5 0x02 /* H-sync stop; 50 hz */ +#define SAA7196_HCB5 0x03 /* H-clamp begin; 50 hz */ +#define SAA7196_HCS5 0x04 /* H-clamp stop; 50 hz */ +#define SAA7196_HSP5 0x05 /* H-sync after PHI1; 50 hz */ +#define SAA7196_LUMC 0x06 /* Luminance control */ +#define SAA7196_HUEC 0x07 /* Hue control */ +#define SAA7196_CKTQ 0x08 /* Colour Killer Threshold QAM (PAL, NTSC) */ +#define SAA7196_CKTS 0x09 /* Colour Killer Threshold SECAM */ +#define SAA7196_PALS 0x0a /* PAL switch sensitivity */ +#define SAA7196_SECAMS 0x0b /* SECAM switch sensitivity */ +#define SAA7196_CGAINC 0x0c /* Chroma gain control */ +#define SAA7196_STDC 0x0d /* Standard/Mode control */ +#define SAA7196_IOCC 0x0e /* I/O and Clock Control */ +#define SAA7196_CTRL1 0x0f /* Control #1 */ +#define SAA7196_CTRL2 0x10 /* Control #2 */ +#define SAA7196_CGAINR 0x11 /* Chroma Gain Reference */ +#define SAA7196_CSAT 0x12 /* Chroma Saturation */ +#define SAA7196_CONT 0x13 /* Luminance Contrast */ +#define SAA7196_HSB6 0x14 /* H-sync begin; 60 hz */ +#define SAA7196_HSS6 0x15 /* H-sync stop; 60 hz */ +#define SAA7196_HCB6 0x16 /* H-clamp begin; 60 hz */ +#define SAA7196_HCS6 0x17 /* H-clamp stop; 60 hz */ +#define SAA7196_HSP6 0x18 /* H-sync after PHI1; 60 hz */ +#define SAA7196_BRIG 0x19 /* Luminance Brightness */ + +/* Scaler part: */ +#define SAA7196_FMTS 0x20 /* Formats and sequence */ +#define SAA7196_OUTPIX 0x21 /* Output data pixel/line */ +#define SAA7196_INPIX 0x22 /* Input data pixel/line */ +#define SAA7196_HWS 0x23 /* Horiz. window start */ +#define SAA7196_HFILT 0x24 /* Horiz. filter */ +#define SAA7196_OUTLINE 0x25 /* Output data lines/field */ +#define SAA7196_INLINE 0x26 /* Input data lines/field */ +#define SAA7196_VWS 0x27 /* Vertical window start */ +#define SAA7196_VYP 0x28 /* AFS/vertical Y processing */ +#define SAA7196_VBS 0x29 /* Vertical Bypass start */ +#define SAA7196_VBCNT 0x2a /* Vertical Bypass count */ +#define SAA7196_VBP 0x2b /* veritcal Bypass Polarity */ +#define SAA7196_VLOW 0x2c /* Colour-keying lower V limit */ +#define SAA7196_VHIGH 0x2d /* Colour-keying upper V limit */ +#define SAA7196_ULOW 0x2e /* Colour-keying lower U limit */ +#define SAA7196_UHIGH 0x2f /* Colour-keying upper U limit */ +#define SAA7196_DPATH 0x30 /* Data path setting */ + +/* Initialization default values: */ + +unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = { + +/* PAL, 768x576 (no scaling), composite video-in */ +/* Decoder: */ + { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, + 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98, + 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, + 0xe9, 0xa2, +/* Padding */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* Scaler: */ + 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, + 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x87 }, + +/* NTSC, 640x480? (no scaling), composite video-in */ +/* Decoder: */ + { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00, + 0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98, + 0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2, + 0xe9, 0x98, +/* Padding */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* Scaler: */ + 0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d, + 0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x87 }, + +/* SECAM, 768x576 (no scaling), composite video-in */ +/* Decoder: */ + { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, + 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98, + 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, + 0xe9, 0xa2, +/* Padding */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* Scaler: */ + 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, + 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x87 } + }; + +#endif /* _SAA7196_H_ */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/stallion.c linux/drivers/media/video/stallion.c --- v2.4.0-test6/linux/drivers/media/video/stallion.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/stallion.c Tue Jul 18 15:58:54 2000 @@ -0,0 +1,5329 @@ +/*****************************************************************************/ + +/* + * stallion.c -- stallion multiport serial driver. + * + * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1994-1996 Greg Ungerer. + * + * This code is loosely based on the Linux serial driver, written by + * Linus Torvalds, Theodore T'so and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/*****************************************************************************/ + +#include +#include +#include /* for linux/stallion.h */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_PCI +#include +#endif + +/*****************************************************************************/ + +/* + * Define different board types. Use the standard Stallion "assigned" + * board numbers. Boards supported in this driver are abbreviated as + * EIO = EasyIO and ECH = EasyConnection 8/32. + */ +#define BRD_EASYIO 20 +#define BRD_ECH 21 +#define BRD_ECHMC 22 +#define BRD_ECHPCI 26 +#define BRD_ECH64PCI 27 +#define BRD_EASYIOPCI 28 + +/* + * Define a configuration structure to hold the board configuration. + * Need to set this up in the code (for now) with the boards that are + * to be configured into the system. This is what needs to be modified + * when adding/removing/modifying boards. Each line entry in the + * stl_brdconf[] array is a board. Each line contains io/irq/memory + * ranges for that board (as well as what type of board it is). + * Some examples: + * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, + * This line would configure an EasyIO board (4 or 8, no difference), + * at io address 2a0 and irq 10. + * Another example: + * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 }, + * This line will configure an EasyConnection 8/32 board at primary io + * address 2a8, secondary io address 280 and irq 12. + * Enter as many lines into this array as you want (only the first 4 + * will actually be used!). Any combination of EasyIO and EasyConnection + * boards can be specified. EasyConnection 8/32 boards can share their + * secondary io addresses between each other. + * + * NOTE: there is no need to put any entries in this table for PCI + * boards. They will be found automatically by the driver - provided + * PCI BIOS32 support is compiled into the kernel. + */ + +typedef struct { + int brdtype; + int ioaddr1; + int ioaddr2; + unsigned long memaddr; + int irq; + int irqtype; +} stlconf_t; + +static stlconf_t stl_brdconf[] = { + /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ +}; + +static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); + +/*****************************************************************************/ + +/* + * Define some important driver characteristics. Device major numbers + * allocated as per Linux Device Registry. + */ +#ifndef STL_SIOMEMMAJOR +#define STL_SIOMEMMAJOR 28 +#endif +#ifndef STL_SERIALMAJOR +#define STL_SERIALMAJOR 24 +#endif +#ifndef STL_CALLOUTMAJOR +#define STL_CALLOUTMAJOR 25 +#endif + +#define STL_DRVTYPSERIAL 1 +#define STL_DRVTYPCALLOUT 2 + +/* + * Set the TX buffer size. Bigger is better, but we don't want + * to chew too much memory with buffers! + */ +#define STL_TXBUFLOW 512 +#define STL_TXBUFSIZE 4096 + +/*****************************************************************************/ + +/* + * Define our local driver identity first. Set up stuff to deal with + * all the local structures required by a serial tty driver. + */ +static char *stl_drvtitle = "Stallion Multiport Serial Driver"; +static char *stl_drvname = "stallion"; +static char *stl_drvversion = "5.6.0"; +static char *stl_serialname = "ttyE"; +static char *stl_calloutname = "cue"; + +static struct tty_driver stl_serial; +static struct tty_driver stl_callout; +static struct tty_struct *stl_ttys[STL_MAXDEVS]; +static struct termios *stl_termios[STL_MAXDEVS]; +static struct termios *stl_termioslocked[STL_MAXDEVS]; +static int stl_refcount = 0; + +/* + * We will need to allocate a temporary write buffer for chars that + * come direct from user space. The problem is that a copy from user + * space might cause a page fault (typically on a system that is + * swapping!). All ports will share one buffer - since if the system + * is already swapping a shared buffer won't make things any worse. + */ +static char *stl_tmpwritebuf; +static DECLARE_MUTEX(stl_tmpwritesem); + +/* + * Define a local default termios struct. All ports will be created + * with this termios initially. Basically all it defines is a raw port + * at 9600, 8 data bits, 1 stop bit. + */ +static struct termios stl_deftermios = { + 0, + 0, + (B9600 | CS8 | CREAD | HUPCL | CLOCAL), + 0, + 0, + INIT_C_CC +}; + +/* + * Define global stats structures. Not used often, and can be + * re-used for each stats call. + */ +static comstats_t stl_comstats; +static combrd_t stl_brdstats; +static stlbrd_t stl_dummybrd; +static stlport_t stl_dummyport; + +/* + * Define global place to put buffer overflow characters. + */ +static char stl_unwanted[SC26198_RXFIFOSIZE]; + +/* + * Keep track of what interrupts we have requested for us. + * We don't need to request an interrupt twice if it is being + * shared with another Stallion board. + */ +static int stl_gotintrs[STL_MAXBRDS]; +static int stl_numintrs = 0; + +/*****************************************************************************/ + +static stlbrd_t *stl_brds[STL_MAXBRDS]; + +/* + * Per board state flags. Used with the state field of the board struct. + * Not really much here! + */ +#define BRD_FOUND 0x1 + +/* + * Define the port structure istate flags. These set of flags are + * modified at interrupt time - so setting and reseting them needs + * to be atomic. Use the bit clear/setting routines for this. + */ +#define ASYI_TXBUSY 1 +#define ASYI_TXLOW 2 +#define ASYI_DCDCHANGE 3 +#define ASYI_TXFLOWED 4 + +/* + * Define an array of board names as printable strings. Handy for + * referencing boards when printing trace and stuff. + */ +static char *stl_brdnames[] = { + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + (char *) NULL, + "EasyIO", + "EC8/32-AT", + "EC8/32-MC", + (char *) NULL, + (char *) NULL, + (char *) NULL, + "EC8/32-PCI", + "EC8/64-PCI", + "EasyIO-PCI", +}; + +/*****************************************************************************/ + +#ifdef MODULE +/* + * Define some string labels for arguments passed from the module + * load line. These allow for easy board definitions, and easy + * modification of the io, memory and irq resoucres. + */ + +static char *board0[4]; +static char *board1[4]; +static char *board2[4]; +static char *board3[4]; + +static char **stl_brdsp[] = { + (char **) &board0, + (char **) &board1, + (char **) &board2, + (char **) &board3 +}; + +/* + * Define a set of common board names, and types. This is used to + * parse any module arguments. + */ + +typedef struct stlbrdtype { + char *name; + int type; +} stlbrdtype_t; + +static stlbrdtype_t stl_brdstr[] = { + { "easyio", BRD_EASYIO }, + { "eio", BRD_EASYIO }, + { "20", BRD_EASYIO }, + { "ec8/32", BRD_ECH }, + { "ec8/32-at", BRD_ECH }, + { "ec8/32-isa", BRD_ECH }, + { "ech", BRD_ECH }, + { "echat", BRD_ECH }, + { "21", BRD_ECH }, + { "ec8/32-mc", BRD_ECHMC }, + { "ec8/32-mca", BRD_ECHMC }, + { "echmc", BRD_ECHMC }, + { "echmca", BRD_ECHMC }, + { "22", BRD_ECHMC }, + { "ec8/32-pc", BRD_ECHPCI }, + { "ec8/32-pci", BRD_ECHPCI }, + { "26", BRD_ECHPCI }, + { "ec8/64-pc", BRD_ECH64PCI }, + { "ec8/64-pci", BRD_ECH64PCI }, + { "ech-pci", BRD_ECH64PCI }, + { "echpci", BRD_ECH64PCI }, + { "echpc", BRD_ECH64PCI }, + { "27", BRD_ECH64PCI }, + { "easyio-pc", BRD_EASYIOPCI }, + { "easyio-pci", BRD_EASYIOPCI }, + { "eio-pci", BRD_EASYIOPCI }, + { "eiopci", BRD_EASYIOPCI }, + { "28", BRD_EASYIOPCI }, +}; + +/* + * Define the module agruments. + */ +MODULE_AUTHOR("Greg Ungerer"); +MODULE_DESCRIPTION("Stallion Multiport Serial Driver"); + +MODULE_PARM(board0, "1-4s"); +MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board1, "1-4s"); +MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board2, "1-4s"); +MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]"); +MODULE_PARM(board3, "1-4s"); +MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]"); + +#endif + +/*****************************************************************************/ + +/* + * Hardware ID bits for the EasyIO and ECH boards. These defines apply + * to the directly accessible io ports of these boards (not the uarts - + * they are in cd1400.h and sc26198.h). + */ +#define EIO_8PORTRS 0x04 +#define EIO_4PORTRS 0x05 +#define EIO_8PORTDI 0x00 +#define EIO_8PORTM 0x06 +#define EIO_MK3 0x03 +#define EIO_IDBITMASK 0x07 + +#define EIO_BRDMASK 0xf0 +#define ID_BRD4 0x10 +#define ID_BRD8 0x20 +#define ID_BRD16 0x30 + +#define EIO_INTRPEND 0x08 +#define EIO_INTEDGE 0x00 +#define EIO_INTLEVEL 0x08 +#define EIO_0WS 0x10 + +#define ECH_ID 0xa0 +#define ECH_IDBITMASK 0xe0 +#define ECH_BRDENABLE 0x08 +#define ECH_BRDDISABLE 0x00 +#define ECH_INTENABLE 0x01 +#define ECH_INTDISABLE 0x00 +#define ECH_INTLEVEL 0x02 +#define ECH_INTEDGE 0x00 +#define ECH_INTRPEND 0x01 +#define ECH_BRDRESET 0x01 + +#define ECHMC_INTENABLE 0x01 +#define ECHMC_BRDRESET 0x02 + +#define ECH_PNLSTATUS 2 +#define ECH_PNL16PORT 0x20 +#define ECH_PNLIDMASK 0x07 +#define ECH_PNLXPID 0x40 +#define ECH_PNLINTRPEND 0x80 + +#define ECH_ADDR2MASK 0x1e0 + +/* + * Define the vector mapping bits for the programmable interrupt board + * hardware. These bits encode the interrupt for the board to use - it + * is software selectable (except the EIO-8M). + */ +static unsigned char stl_vecmap[] = { + 0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07, + 0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03 +}; + +/* + * Set up enable and disable macros for the ECH boards. They require + * the secondary io address space to be activated and deactivated. + * This way all ECH boards can share their secondary io region. + * If this is an ECH-PCI board then also need to set the page pointer + * to point to the correct page. + */ +#define BRDENABLE(brdnr,pagenr) \ + if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ + outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE), \ + stl_brds[(brdnr)]->ioctrl); \ + else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI) \ + outb((pagenr), stl_brds[(brdnr)]->ioctrl); + +#define BRDDISABLE(brdnr) \ + if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ + outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \ + stl_brds[(brdnr)]->ioctrl); + +#define STL_CD1400MAXBAUD 230400 +#define STL_SC26198MAXBAUD 460800 + +#define STL_BAUDBASE 115200 +#define STL_CLOSEDELAY (5 * HZ / 10) + +/*****************************************************************************/ + +#ifdef CONFIG_PCI + +/* + * Define the Stallion PCI vendor and device IDs. + */ +#ifndef PCI_VENDOR_ID_STALLION +#define PCI_VENDOR_ID_STALLION 0x124d +#endif +#ifndef PCI_DEVICE_ID_ECHPCI832 +#define PCI_DEVICE_ID_ECHPCI832 0x0000 +#endif +#ifndef PCI_DEVICE_ID_ECHPCI864 +#define PCI_DEVICE_ID_ECHPCI864 0x0002 +#endif +#ifndef PCI_DEVICE_ID_EIOPCI +#define PCI_DEVICE_ID_EIOPCI 0x0003 +#endif + +/* + * Define structure to hold all Stallion PCI boards. + */ +typedef struct stlpcibrd { + unsigned short vendid; + unsigned short devid; + int brdtype; +} stlpcibrd_t; + +static stlpcibrd_t stl_pcibrds[] = { + { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI }, + { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI }, + { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI }, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI }, +}; + +static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t); + +#endif + +/*****************************************************************************/ + +/* + * Define macros to extract a brd/port number from a minor number. + */ +#define MINOR2BRD(min) (((min) & 0xc0) >> 6) +#define MINOR2PORT(min) ((min) & 0x3f) + +/* + * Define a baud rate table that converts termios baud rate selector + * into the actual baud rate value. All baud rate calculations are + * based on the actual baud rate required. + */ +static unsigned int stl_baudrates[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 +}; + +/* + * Define some handy local macros... + */ +#undef MIN +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) + +#undef TOLOWER +#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) + +/*****************************************************************************/ + +/* + * Declare all those functions in this driver! + */ + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +static void stl_argbrds(void); +static int stl_parsebrd(stlconf_t *confp, char **argp); + +static unsigned long stl_atol(char *str); +#endif + +int stl_init(void); +static int stl_open(struct tty_struct *tty, struct file *filp); +static void stl_close(struct tty_struct *tty, struct file *filp); +static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void stl_putchar(struct tty_struct *tty, unsigned char ch); +static void stl_flushchars(struct tty_struct *tty); +static int stl_writeroom(struct tty_struct *tty); +static int stl_charsinbuffer(struct tty_struct *tty); +static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +static void stl_settermios(struct tty_struct *tty, struct termios *old); +static void stl_throttle(struct tty_struct *tty); +static void stl_unthrottle(struct tty_struct *tty); +static void stl_stop(struct tty_struct *tty); +static void stl_start(struct tty_struct *tty); +static void stl_flushbuffer(struct tty_struct *tty); +static void stl_breakctl(struct tty_struct *tty, int state); +static void stl_waituntilsent(struct tty_struct *tty, int timeout); +static void stl_sendxchar(struct tty_struct *tty, char ch); +static void stl_hangup(struct tty_struct *tty); +static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); +static int stl_portinfo(stlport_t *portp, int portnr, char *pos); +static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); + +static int stl_brdinit(stlbrd_t *brdp); +static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); +static int stl_mapirq(int irq, char *name); +static void stl_getserial(stlport_t *portp, struct serial_struct *sp); +static int stl_setserial(stlport_t *portp, struct serial_struct *sp); +static int stl_getbrdstats(combrd_t *bp); +static int stl_getportstats(stlport_t *portp, comstats_t *cp); +static int stl_clrportstats(stlport_t *portp, comstats_t *cp); +static int stl_getportstruct(unsigned long arg); +static int stl_getbrdstruct(unsigned long arg); +static int stl_waitcarrier(stlport_t *portp, struct file *filp); +static void stl_delay(int len); +static void stl_intr(int irq, void *dev_id, struct pt_regs *regs); +static void stl_eiointr(stlbrd_t *brdp); +static void stl_echatintr(stlbrd_t *brdp); +static void stl_echmcaintr(stlbrd_t *brdp); +static void stl_echpciintr(stlbrd_t *brdp); +static void stl_echpci64intr(stlbrd_t *brdp); +static void stl_offintr(void *private); +static void *stl_memalloc(int len); +static stlbrd_t *stl_allocbrd(void); +static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); + +static inline int stl_initbrds(void); +static inline int stl_initeio(stlbrd_t *brdp); +static inline int stl_initech(stlbrd_t *brdp); +static inline int stl_getbrdnr(void); + +#ifdef CONFIG_PCI +static inline int stl_findpcibrds(void); +static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp); +#endif + +/* + * CD1400 uart specific handling functions. + */ +static void stl_cd1400setreg(stlport_t *portp, int regnr, int value); +static int stl_cd1400getreg(stlport_t *portp, int regnr); +static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); +static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); +static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); +static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); +static int stl_cd1400getsignals(stlport_t *portp); +static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); +static void stl_cd1400ccrwait(stlport_t *portp); +static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); +static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); +static void stl_cd1400disableintrs(stlport_t *portp); +static void stl_cd1400sendbreak(stlport_t *portp, int len); +static void stl_cd1400flowctrl(stlport_t *portp, int state); +static void stl_cd1400sendflow(stlport_t *portp, int state); +static void stl_cd1400flush(stlport_t *portp); +static int stl_cd1400datastate(stlport_t *portp); +static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase); +static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase); +static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); +static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); +static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); + +static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr); + +/* + * SC26198 uart specific handling functions. + */ +static void stl_sc26198setreg(stlport_t *portp, int regnr, int value); +static int stl_sc26198getreg(stlport_t *portp, int regnr); +static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); +static int stl_sc26198getglobreg(stlport_t *portp, int regnr); +static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); +static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); +static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); +static int stl_sc26198getsignals(stlport_t *portp); +static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); +static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); +static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); +static void stl_sc26198disableintrs(stlport_t *portp); +static void stl_sc26198sendbreak(stlport_t *portp, int len); +static void stl_sc26198flowctrl(stlport_t *portp, int state); +static void stl_sc26198sendflow(stlport_t *portp, int state); +static void stl_sc26198flush(stlport_t *portp); +static int stl_sc26198datastate(stlport_t *portp); +static void stl_sc26198wait(stlport_t *portp); +static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); +static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); +static void stl_sc26198txisr(stlport_t *port); +static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); +static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); +static void stl_sc26198rxbadchars(stlport_t *portp); +static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); + +/*****************************************************************************/ + +/* + * Generic UART support structure. + */ +typedef struct uart { + int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); + void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); + void (*setport)(stlport_t *portp, struct termios *tiosp); + int (*getsignals)(stlport_t *portp); + void (*setsignals)(stlport_t *portp, int dtr, int rts); + void (*enablerxtx)(stlport_t *portp, int rx, int tx); + void (*startrxtx)(stlport_t *portp, int rx, int tx); + void (*disableintrs)(stlport_t *portp); + void (*sendbreak)(stlport_t *portp, int len); + void (*flowctrl)(stlport_t *portp, int state); + void (*sendflow)(stlport_t *portp, int state); + void (*flush)(stlport_t *portp); + int (*datastate)(stlport_t *portp); + void (*intr)(stlpanel_t *panelp, unsigned int iobase); +} uart_t; + +/* + * Define some macros to make calling these functions nice and clean. + */ +#define stl_panelinit (* ((uart_t *) panelp->uartp)->panelinit) +#define stl_portinit (* ((uart_t *) portp->uartp)->portinit) +#define stl_setport (* ((uart_t *) portp->uartp)->setport) +#define stl_getsignals (* ((uart_t *) portp->uartp)->getsignals) +#define stl_setsignals (* ((uart_t *) portp->uartp)->setsignals) +#define stl_enablerxtx (* ((uart_t *) portp->uartp)->enablerxtx) +#define stl_startrxtx (* ((uart_t *) portp->uartp)->startrxtx) +#define stl_disableintrs (* ((uart_t *) portp->uartp)->disableintrs) +#define stl_sendbreak (* ((uart_t *) portp->uartp)->sendbreak) +#define stl_flowctrl (* ((uart_t *) portp->uartp)->flowctrl) +#define stl_sendflow (* ((uart_t *) portp->uartp)->sendflow) +#define stl_flush (* ((uart_t *) portp->uartp)->flush) +#define stl_datastate (* ((uart_t *) portp->uartp)->datastate) + +/*****************************************************************************/ + +/* + * CD1400 UART specific data initialization. + */ +static uart_t stl_cd1400uart = { + stl_cd1400panelinit, + stl_cd1400portinit, + stl_cd1400setport, + stl_cd1400getsignals, + stl_cd1400setsignals, + stl_cd1400enablerxtx, + stl_cd1400startrxtx, + stl_cd1400disableintrs, + stl_cd1400sendbreak, + stl_cd1400flowctrl, + stl_cd1400sendflow, + stl_cd1400flush, + stl_cd1400datastate, + stl_cd1400eiointr +}; + +/* + * Define the offsets within the register bank of a cd1400 based panel. + * These io address offsets are common to the EasyIO board as well. + */ +#define EREG_ADDR 0 +#define EREG_DATA 4 +#define EREG_RXACK 5 +#define EREG_TXACK 6 +#define EREG_MDACK 7 + +#define EREG_BANKSIZE 8 + +#define CD1400_CLK 25000000 +#define CD1400_CLK8M 20000000 + +/* + * Define the cd1400 baud rate clocks. These are used when calculating + * what clock and divisor to use for the required baud rate. Also + * define the maximum baud rate allowed, and the default base baud. + */ +static int stl_cd1400clkdivs[] = { + CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 +}; + +/*****************************************************************************/ + +/* + * SC26198 UART specific data initization. + */ +static uart_t stl_sc26198uart = { + stl_sc26198panelinit, + stl_sc26198portinit, + stl_sc26198setport, + stl_sc26198getsignals, + stl_sc26198setsignals, + stl_sc26198enablerxtx, + stl_sc26198startrxtx, + stl_sc26198disableintrs, + stl_sc26198sendbreak, + stl_sc26198flowctrl, + stl_sc26198sendflow, + stl_sc26198flush, + stl_sc26198datastate, + stl_sc26198intr +}; + +/* + * Define the offsets within the register bank of a sc26198 based panel. + */ +#define XP_DATA 0 +#define XP_ADDR 1 +#define XP_MODID 2 +#define XP_STATUS 2 +#define XP_IACK 3 + +#define XP_BANKSIZE 4 + +/* + * Define the sc26198 baud rate table. Offsets within the table + * represent the actual baud rate selector of sc26198 registers. + */ +static unsigned int sc26198_baudtable[] = { + 50, 75, 150, 200, 300, 450, 600, 900, 1200, 1800, 2400, 3600, + 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, + 230400, 460800, 921600 +}; + +#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int)) + +/*****************************************************************************/ + +/* + * Define the driver info for a user level control device. Used mainly + * to get at port stats - only not using the port device itself. + */ +static struct file_operations stl_fsiomem = { + owner: THIS_MODULE, + ioctl: stl_memioctl, +}; + +/*****************************************************************************/ + +static devfs_handle_t devfs_handle = NULL; + +#ifdef MODULE + +/* + * Loadable module initialization stuff. + */ + +int init_module() +{ + unsigned long flags; + +#if DEBUG + printk("init_module()\n"); +#endif + + save_flags(flags); + cli(); + stl_init(); + restore_flags(flags); + + return(0); +} + +/*****************************************************************************/ + +void cleanup_module() +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + stlport_t *portp; + unsigned long flags; + int i, j, k; + +#if DEBUG + printk("cleanup_module()\n"); +#endif + + printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, + stl_drvversion); + + save_flags(flags); + cli(); + +/* + * Free up all allocated resources used by the ports. This includes + * memory and interrupts. As part of this process we will also do + * a hangup on every open port - to try to flush out any processes + * hanging onto ports. + */ + i = tty_unregister_driver(&stl_serial); + j = tty_unregister_driver(&stl_callout); + if (i || j) { + printk("STALLION: failed to un-register tty driver, " + "errno=%d,%d\n", -i, -j); + restore_flags(flags); + return; + } + devfs_unregister (devfs_handle); + if ((i = devfs_unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) + printk("STALLION: failed to un-register serial memory device, " + "errno=%d\n", -i); + + if (stl_tmpwritebuf != (char *) NULL) + kfree(stl_tmpwritebuf); + + for (i = 0; (i < stl_nrbrds); i++) { + if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) + continue; + for (j = 0; (j < STL_MAXPANELS); j++) { + panelp = brdp->panels[j]; + if (panelp == (stlpanel_t *) NULL) + continue; + for (k = 0; (k < STL_PORTSPERPANEL); k++) { + portp = panelp->ports[k]; + if (portp == (stlport_t *) NULL) + continue; + if (portp->tty != (struct tty_struct *) NULL) + stl_hangup(portp->tty); + if (portp->tx.buf != (char *) NULL) + kfree(portp->tx.buf); + kfree(portp); + } + kfree(panelp); + } + + release_region(brdp->ioaddr1, brdp->iosize1); + if (brdp->iosize2 > 0) + release_region(brdp->ioaddr2, brdp->iosize2); + + kfree(brdp); + stl_brds[i] = (stlbrd_t *) NULL; + } + + for (i = 0; (i < stl_numintrs); i++) + free_irq(stl_gotintrs[i], NULL); + + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Check for any arguments passed in on the module load command line. + */ + +static void stl_argbrds() +{ + stlconf_t conf; + stlbrd_t *brdp; + int nrargs, i; + +#if DEBUG + printk("stl_argbrds()\n"); +#endif + + nrargs = sizeof(stl_brdsp) / sizeof(char **); + + for (i = stl_nrbrds; (i < nrargs); i++) { + memset(&conf, 0, sizeof(conf)); + if (stl_parsebrd(&conf, stl_brdsp[i]) == 0) + continue; + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + continue; + stl_nrbrds = i + 1; + brdp->brdnr = i; + brdp->brdtype = conf.brdtype; + brdp->ioaddr1 = conf.ioaddr1; + brdp->ioaddr2 = conf.ioaddr2; + brdp->irq = conf.irq; + brdp->irqtype = conf.irqtype; + stl_brdinit(brdp); + } +} + +/*****************************************************************************/ + +/* + * Convert an ascii string number into an unsigned long. + */ + +static unsigned long stl_atol(char *str) +{ + unsigned long val; + int base, c; + char *sp; + + val = 0; + sp = str; + if ((*sp == '0') && (*(sp+1) == 'x')) { + base = 16; + sp += 2; + } else if (*sp == '0') { + base = 8; + sp++; + } else { + base = 10; + } + + for (; (*sp != 0); sp++) { + c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); + if ((c < 0) || (c >= base)) { + printk("STALLION: invalid argument %s\n", str); + val = 0; + break; + } + val = (val * base) + c; + } + return(val); +} + +/*****************************************************************************/ + +/* + * Parse the supplied argument string, into the board conf struct. + */ + +static int stl_parsebrd(stlconf_t *confp, char **argp) +{ + char *sp; + int nrbrdnames, i; + +#if DEBUG + printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp); +#endif + + if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) + return(0); + + for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) + *sp = TOLOWER(*sp); + + nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t); + for (i = 0; (i < nrbrdnames); i++) { + if (strcmp(stl_brdstr[i].name, argp[0]) == 0) + break; + } + if (i >= nrbrdnames) { + printk("STALLION: unknown board name, %s?\n", argp[0]); + return(0); + } + + confp->brdtype = stl_brdstr[i].type; + + i = 1; + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->ioaddr1 = stl_atol(argp[i]); + i++; + if (confp->brdtype == BRD_ECH) { + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->ioaddr2 = stl_atol(argp[i]); + i++; + } + if ((argp[i] != (char *) NULL) && (*argp[i] != 0)) + confp->irq = stl_atol(argp[i]); + return(1); +} + +#endif + +/*****************************************************************************/ + +/* + * Local driver kernel memory allocation routine. + */ + +static void *stl_memalloc(int len) +{ + return((void *) kmalloc(len, GFP_KERNEL)); +} + +/*****************************************************************************/ + +/* + * Allocate a new board structure. Fill out the basic info in it. + */ + +static stlbrd_t *stl_allocbrd() +{ + stlbrd_t *brdp; + + brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); + if (brdp == (stlbrd_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", + sizeof(stlbrd_t)); + return((stlbrd_t *) NULL); + } + + memset(brdp, 0, sizeof(stlbrd_t)); + brdp->magic = STL_BOARDMAGIC; + return(brdp); +} + +/*****************************************************************************/ + +static int stl_open(struct tty_struct *tty, struct file *filp) +{ + stlport_t *portp; + stlbrd_t *brdp; + unsigned int minordev; + int brdnr, panelnr, portnr, rc; + +#if DEBUG + printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, + (int) filp, tty->device); +#endif + + minordev = MINOR(tty->device); + brdnr = MINOR2BRD(minordev); + if (brdnr >= stl_nrbrds) + return(-ENODEV); + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + minordev = MINOR2PORT(minordev); + for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) { + if (brdp->panels[panelnr] == (stlpanel_t *) NULL) + break; + if (minordev < brdp->panels[panelnr]->nrports) { + portnr = minordev; + break; + } + minordev -= brdp->panels[panelnr]->nrports; + } + if (portnr < 0) + return(-ENODEV); + + portp = brdp->panels[panelnr]->ports[portnr]; + if (portp == (stlport_t *) NULL) + return(-ENODEV); + + MOD_INC_USE_COUNT; + +/* + * On the first open of the device setup the port hardware, and + * initialize the per port data structure. + */ + portp->tty = tty; + tty->driver_data = portp; + portp->refcount++; + + if ((portp->flags & ASYNC_INITIALIZED) == 0) { + if (portp->tx.buf == (char *) NULL) { + portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE); + if (portp->tx.buf == (char *) NULL) + return(-ENOMEM); + portp->tx.head = portp->tx.buf; + portp->tx.tail = portp->tx.buf; + } + stl_setport(portp, tty->termios); + portp->sigs = stl_getsignals(portp); + stl_setsignals(portp, 1, 1); + stl_enablerxtx(portp, 1, 1); + stl_startrxtx(portp, 1, 0); + clear_bit(TTY_IO_ERROR, &tty->flags); + portp->flags |= ASYNC_INITIALIZED; + } + +/* + * Check if this port is in the middle of closing. If so then wait + * until it is closed then return error status, based on flag settings. + * The sleep here does not need interrupt protection since the wakeup + * for it is done with the same context. + */ + if (portp->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&portp->close_wait); + if (portp->flags & ASYNC_HUP_NOTIFY) + return(-EAGAIN); + return(-ERESTARTSYS); + } + +/* + * Based on type of open being done check if it can overlap with any + * previous opens still in effect. If we are a normal serial device + * then also we might have to wait for carrier. + */ + if (tty->driver.subtype == STL_DRVTYPCALLOUT) { + if (portp->flags & ASYNC_NORMAL_ACTIVE) + return(-EBUSY); + if (portp->flags & ASYNC_CALLOUT_ACTIVE) { + if ((portp->flags & ASYNC_SESSION_LOCKOUT) && + (portp->session != current->session)) + return(-EBUSY); + if ((portp->flags & ASYNC_PGRP_LOCKOUT) && + (portp->pgrp != current->pgrp)) + return(-EBUSY); + } + portp->flags |= ASYNC_CALLOUT_ACTIVE; + } else { + if (filp->f_flags & O_NONBLOCK) { + if (portp->flags & ASYNC_CALLOUT_ACTIVE) + return(-EBUSY); + } else { + if ((rc = stl_waitcarrier(portp, filp)) != 0) + return(rc); + } + portp->flags |= ASYNC_NORMAL_ACTIVE; + } + + if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == STL_DRVTYPSERIAL) + *tty->termios = portp->normaltermios; + else + *tty->termios = portp->callouttermios; + stl_setport(portp, tty->termios); + } + + portp->session = current->session; + portp->pgrp = current->pgrp; + return(0); +} + +/*****************************************************************************/ + +/* + * Possibly need to wait for carrier (DCD signal) to come high. Say + * maybe because if we are clocal then we don't need to wait... + */ + +static int stl_waitcarrier(stlport_t *portp, struct file *filp) +{ + unsigned long flags; + int rc, doclocal; + +#if DEBUG + printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp); +#endif + + rc = 0; + doclocal = 0; + + if (portp->flags & ASYNC_CALLOUT_ACTIVE) { + if (portp->normaltermios.c_cflag & CLOCAL) + doclocal++; + } else { + if (portp->tty->termios->c_cflag & CLOCAL) + doclocal++; + } + + save_flags(flags); + cli(); + portp->openwaitcnt++; + if (! tty_hung_up_p(filp)) + portp->refcount--; + + for (;;) { + if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) + stl_setsignals(portp, 1, 1); + if (tty_hung_up_p(filp) || + ((portp->flags & ASYNC_INITIALIZED) == 0)) { + if (portp->flags & ASYNC_HUP_NOTIFY) + rc = -EBUSY; + else + rc = -ERESTARTSYS; + break; + } + if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) && + ((portp->flags & ASYNC_CLOSING) == 0) && + (doclocal || (portp->sigs & TIOCM_CD))) { + break; + } + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&portp->open_wait); + } + + if (! tty_hung_up_p(filp)) + portp->refcount++; + portp->openwaitcnt--; + restore_flags(flags); + + return(rc); +} + +/*****************************************************************************/ + +static void stl_close(struct tty_struct *tty, struct file *filp) +{ + stlport_t *portp; + unsigned long flags; + +#if DEBUG + printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp); +#endif + + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + save_flags(flags); + cli(); + if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + if ((tty->count == 1) && (portp->refcount != 1)) + portp->refcount = 1; + if (portp->refcount-- > 1) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + + portp->refcount = 0; + portp->flags |= ASYNC_CLOSING; + + if (portp->flags & ASYNC_NORMAL_ACTIVE) + portp->normaltermios = *tty->termios; + if (portp->flags & ASYNC_CALLOUT_ACTIVE) + portp->callouttermios = *tty->termios; + +/* + * May want to wait for any data to drain before closing. The BUSY + * flag keeps track of whether we are still sending or not - it is + * very accurate for the cd1400, not quite so for the sc26198. + * (The sc26198 has no "end-of-data" interrupt only empty FIFO) + */ + tty->closing = 1; + if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, portp->closing_wait); + stl_waituntilsent(tty, (HZ / 2)); + + portp->flags &= ~ASYNC_INITIALIZED; + stl_disableintrs(portp); + if (tty->termios->c_cflag & HUPCL) + stl_setsignals(portp, 0, 0); + stl_enablerxtx(portp, 0, 0); + stl_flushbuffer(tty); + portp->istate = 0; + if (portp->tx.buf != (char *) NULL) { + kfree(portp->tx.buf); + portp->tx.buf = (char *) NULL; + portp->tx.head = (char *) NULL; + portp->tx.tail = (char *) NULL; + } + set_bit(TTY_IO_ERROR, &tty->flags); + if (tty->ldisc.flush_buffer) + (tty->ldisc.flush_buffer)(tty); + + tty->closing = 0; + portp->tty = (struct tty_struct *) NULL; + + if (portp->openwaitcnt) { + if (portp->close_delay) + stl_delay(portp->close_delay); + wake_up_interruptible(&portp->open_wait); + } + + portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&portp->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Wait for a specified delay period, this is not a busy-loop. It will + * give up the processor while waiting. Unfortunately this has some + * rather intimate knowledge of the process management stuff. + */ + +static void stl_delay(int len) +{ +#if DEBUG + printk("stl_delay(len=%d)\n", len); +#endif + if (len > 0) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(len); + current->state = TASK_RUNNING; + } +} + +/*****************************************************************************/ + +/* + * Write routine. Take data and stuff it in to the TX ring queue. + * If transmit interrupts are not running then start them. + */ + +static int stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) +{ + stlport_t *portp; + unsigned int len, stlen; + unsigned char *chbuf; + char *head, *tail; + +#if DEBUG + printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", + (int) tty, from_user, (int) buf, count); +#endif + + if ((tty == (struct tty_struct *) NULL) || + (stl_tmpwritebuf == (char *) NULL)) + return(0); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(0); + if (portp->tx.buf == (char *) NULL) + return(0); + +/* + * If copying direct from user space we must cater for page faults, + * causing us to "sleep" here for a while. To handle this copy in all + * the data we need now, into a local buffer. Then when we got it all + * copy it into the TX buffer. + */ + chbuf = (unsigned char *) buf; + if (from_user) { + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : + (tail - head - 1); + count = MIN(len, count); + + down(&stl_tmpwritesem); + copy_from_user(stl_tmpwritebuf, chbuf, count); + chbuf = &stl_tmpwritebuf[0]; + } + + head = portp->tx.head; + tail = portp->tx.tail; + if (head >= tail) { + len = STL_TXBUFSIZE - (head - tail) - 1; + stlen = STL_TXBUFSIZE - (head - portp->tx.buf); + } else { + len = tail - head - 1; + stlen = len; + } + + len = MIN(len, count); + count = 0; + while (len > 0) { + stlen = MIN(len, stlen); + memcpy(head, chbuf, stlen); + len -= stlen; + chbuf += stlen; + count += stlen; + head += stlen; + if (head >= (portp->tx.buf + STL_TXBUFSIZE)) { + head = portp->tx.buf; + stlen = tail - head; + } + } + portp->tx.head = head; + + clear_bit(ASYI_TXLOW, &portp->istate); + stl_startrxtx(portp, -1, 1); + + if (from_user) + up(&stl_tmpwritesem); + + return(count); +} + +/*****************************************************************************/ + +static void stl_putchar(struct tty_struct *tty, unsigned char ch) +{ + stlport_t *portp; + unsigned int len; + char *head, *tail; + +#if DEBUG + printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + if (portp->tx.buf == (char *) NULL) + return; + + head = portp->tx.head; + tail = portp->tx.tail; + + len = (head >= tail) ? (STL_TXBUFSIZE - (head - tail)) : (tail - head); + len--; + + if (len > 0) { + *head++ = ch; + if (head >= (portp->tx.buf + STL_TXBUFSIZE)) + head = portp->tx.buf; + } + portp->tx.head = head; +} + +/*****************************************************************************/ + +/* + * If there are any characters in the buffer then make sure that TX + * interrupts are on and get'em out. Normally used after the putchar + * routine has been called. + */ + +static void stl_flushchars(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_flushchars(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + if (portp->tx.buf == (char *) NULL) + return; + +#if 0 + if (tty->stopped || tty->hw_stopped || + (portp->tx.head == portp->tx.tail)) + return; +#endif + stl_startrxtx(portp, -1, 1); +} + +/*****************************************************************************/ + +static int stl_writeroom(struct tty_struct *tty) +{ + stlport_t *portp; + char *head, *tail; + +#if DEBUG + printk("stl_writeroom(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return(0); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(0); + if (portp->tx.buf == (char *) NULL) + return(0); + + head = portp->tx.head; + tail = portp->tx.tail; + return((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1)); +} + +/*****************************************************************************/ + +/* + * Return number of chars in the TX buffer. Normally we would just + * calculate the number of chars in the buffer and return that, but if + * the buffer is empty and TX interrupts are still on then we return + * that the buffer still has 1 char in it. This way whoever called us + * will not think that ALL chars have drained - since the UART still + * must have some chars in it (we are busy after all). + */ + +static int stl_charsinbuffer(struct tty_struct *tty) +{ + stlport_t *portp; + unsigned int size; + char *head, *tail; + +#if DEBUG + printk("stl_charsinbuffer(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return(0); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(0); + if (portp->tx.buf == (char *) NULL) + return(0); + + head = portp->tx.head; + tail = portp->tx.tail; + size = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((size == 0) && test_bit(ASYI_TXBUSY, &portp->istate)) + size = 1; + return(size); +} + +/*****************************************************************************/ + +/* + * Generate the serial struct info. + */ + +static void stl_getserial(stlport_t *portp, struct serial_struct *sp) +{ + struct serial_struct sio; + stlbrd_t *brdp; + +#if DEBUG + printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); +#endif + + memset(&sio, 0, sizeof(struct serial_struct)); + sio.line = portp->portnr; + sio.port = portp->ioaddr; + sio.flags = portp->flags; + sio.baud_base = portp->baud_base; + sio.close_delay = portp->close_delay; + sio.closing_wait = portp->closing_wait; + sio.custom_divisor = portp->custom_divisor; + sio.hub6 = 0; + if (portp->uartp == &stl_cd1400uart) { + sio.type = PORT_CIRRUS; + sio.xmit_fifo_size = CD1400_TXFIFOSIZE; + } else { + sio.type = PORT_UNKNOWN; + sio.xmit_fifo_size = SC26198_TXFIFOSIZE; + } + + brdp = stl_brds[portp->brdnr]; + if (brdp != (stlbrd_t *) NULL) + sio.irq = brdp->irq; + + copy_to_user(sp, &sio, sizeof(struct serial_struct)); +} + +/*****************************************************************************/ + +/* + * Set port according to the serial struct info. + * At this point we do not do any auto-configure stuff, so we will + * just quietly ignore any requests to change irq, etc. + */ + +static int stl_setserial(stlport_t *portp, struct serial_struct *sp) +{ + struct serial_struct sio; + +#if DEBUG + printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp); +#endif + + copy_from_user(&sio, sp, sizeof(struct serial_struct)); + if (!capable(CAP_SYS_ADMIN)) { + if ((sio.baud_base != portp->baud_base) || + (sio.close_delay != portp->close_delay) || + ((sio.flags & ~ASYNC_USR_MASK) != + (portp->flags & ~ASYNC_USR_MASK))) + return(-EPERM); + } + + portp->flags = (portp->flags & ~ASYNC_USR_MASK) | + (sio.flags & ASYNC_USR_MASK); + portp->baud_base = sio.baud_base; + portp->close_delay = sio.close_delay; + portp->closing_wait = sio.closing_wait; + portp->custom_divisor = sio.custom_divisor; + stl_setport(portp, portp->tty->termios); + return(0); +} + +/*****************************************************************************/ + +static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +{ + stlport_t *portp; + unsigned int ival; + int rc; + +#if DEBUG + printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", + (int) tty, (int) file, cmd, (int) arg); +#endif + + if (tty == (struct tty_struct *) NULL) + return(-ENODEV); + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return(-ENODEV); + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return(-EIO); + } + + rc = 0; + + switch (cmd) { + case TIOCGSOFTCAR: + rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = stl_getsignals(portp); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + stl_getserial(portp, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = stl_setserial(portp, (struct serial_struct *) arg); + break; + case COM_GETPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_getportstats(portp, (comstats_t *) arg); + break; + case COM_CLRPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_clrportstats(portp, (comstats_t *) arg); + break; + case TIOCSERCONFIG: + case TIOCSERGWILD: + case TIOCSERSWILD: + case TIOCSERGETLSR: + case TIOCSERGSTRUCT: + case TIOCSERGETMULTI: + case TIOCSERSETMULTI: + default: + rc = -ENOIOCTLCMD; + break; + } + + return(rc); +} + +/*****************************************************************************/ + +static void stl_settermios(struct tty_struct *tty, struct termios *old) +{ + stlport_t *portp; + struct termios *tiosp; + +#if DEBUG + printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + tiosp = tty->termios; + if ((tiosp->c_cflag == old->c_cflag) && + (tiosp->c_iflag == old->c_iflag)) + return; + + stl_setport(portp, tiosp); + stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), + -1); + if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) { + tty->hw_stopped = 0; + stl_start(tty); + } + if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) + wake_up_interruptible(&portp->open_wait); +} + +/*****************************************************************************/ + +/* + * Attempt to flow control who ever is sending us data. Based on termios + * settings use software or/and hardware flow control. + */ + +static void stl_throttle(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_throttle(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_flowctrl(portp, 0); +} + +/*****************************************************************************/ + +/* + * Unflow control the device sending us data... + */ + +static void stl_unthrottle(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_unthrottle(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_flowctrl(portp, 1); +} + +/*****************************************************************************/ + +/* + * Stop the transmitter. Basically to do this we will just turn TX + * interrupts off. + */ + +static void stl_stop(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_stop(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_startrxtx(portp, -1, 0); +} + +/*****************************************************************************/ + +/* + * Start the transmitter again. Just turn TX interrupts back on. + */ + +static void stl_start(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_start(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + stl_startrxtx(portp, -1, 1); +} + +/*****************************************************************************/ + +/* + * Hangup this port. This is pretty much like closing the port, only + * a little more brutal. No waiting for data to drain. Shutdown the + * port and maybe drop signals. + */ + +static void stl_hangup(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_hangup(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + portp->flags &= ~ASYNC_INITIALIZED; + stl_disableintrs(portp); + if (tty->termios->c_cflag & HUPCL) + stl_setsignals(portp, 0, 0); + stl_enablerxtx(portp, 0, 0); + stl_flushbuffer(tty); + portp->istate = 0; + set_bit(TTY_IO_ERROR, &tty->flags); + if (portp->tx.buf != (char *) NULL) { + kfree(portp->tx.buf); + portp->tx.buf = (char *) NULL; + portp->tx.head = (char *) NULL; + portp->tx.tail = (char *) NULL; + } + portp->tty = (struct tty_struct *) NULL; + portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + portp->refcount = 0; + wake_up_interruptible(&portp->open_wait); +} + +/*****************************************************************************/ + +static void stl_flushbuffer(struct tty_struct *tty) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_flushbuffer(tty=%x)\n", (int) tty); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + stl_flush(portp); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/*****************************************************************************/ + +static void stl_breakctl(struct tty_struct *tty, int state) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + stl_sendbreak(portp, ((state == -1) ? 1 : 2)); +} + +/*****************************************************************************/ + +static void stl_waituntilsent(struct tty_struct *tty, int timeout) +{ + stlport_t *portp; + unsigned long tend; + +#if DEBUG + printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + if (timeout == 0) + timeout = HZ; + tend = jiffies + timeout; + + while (stl_datastate(portp)) { + if (signal_pending(current)) + break; + stl_delay(2); + if (time_after_eq(jiffies, tend)) + break; + } +} + +/*****************************************************************************/ + +static void stl_sendxchar(struct tty_struct *tty, char ch) +{ + stlport_t *portp; + +#if DEBUG + printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); +#endif + + if (tty == (struct tty_struct *) NULL) + return; + portp = tty->driver_data; + if (portp == (stlport_t *) NULL) + return; + + if (ch == STOP_CHAR(tty)) + stl_sendflow(portp, 0); + else if (ch == START_CHAR(tty)) + stl_sendflow(portp, 1); + else + stl_putchar(tty, ch); +} + +/*****************************************************************************/ + +#define MAXLINE 80 + +/* + * Format info for a specified port. The line is deliberately limited + * to 80 characters. (If it is too long it will be truncated, if too + * short then padded with spaces). + */ + +static int stl_portinfo(stlport_t *portp, int portnr, char *pos) +{ + char *sp; + int sigs, cnt; + + sp = pos; + sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d", + portnr, (portp->hwid == 1) ? "SC26198" : "CD1400", + (int) portp->stats.txtotal, (int) portp->stats.rxtotal); + + if (portp->stats.rxframing) + sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing); + if (portp->stats.rxparity) + sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity); + if (portp->stats.rxbreaks) + sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks); + if (portp->stats.rxoverrun) + sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun); + + sigs = stl_getsignals(portp); + cnt = sprintf(sp, "%s%s%s%s%s ", + (sigs & TIOCM_RTS) ? "|RTS" : "", + (sigs & TIOCM_CTS) ? "|CTS" : "", + (sigs & TIOCM_DTR) ? "|DTR" : "", + (sigs & TIOCM_CD) ? "|DCD" : "", + (sigs & TIOCM_DSR) ? "|DSR" : ""); + *sp = ' '; + sp += cnt; + + for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) + *sp++ = ' '; + if (cnt >= MAXLINE) + pos[(MAXLINE - 2)] = '+'; + pos[(MAXLINE - 1)] = '\n'; + + return(MAXLINE); +} + +/*****************************************************************************/ + +/* + * Port info, read from the /proc file system. + */ + +static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + stlport_t *portp; + int brdnr, panelnr, portnr, totalport; + int curoff, maxoff; + char *pos; + +#if DEBUG + printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," + "data=%x\n", (int) page, (int) start, (int) off, count, + (int) eof, (int) data); +#endif + + pos = page; + totalport = 0; + curoff = 0; + + if (off == 0) { + pos += sprintf(pos, "%s: version %s", stl_drvtitle, + stl_drvversion); + while (pos < (page + MAXLINE - 1)) + *pos++ = ' '; + *pos++ = '\n'; + } + curoff = MAXLINE; + +/* + * We scan through for each board, panel and port. The offset is + * calculated on the fly, and irrelevant ports are skipped. + */ + for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + continue; + if (brdp->state == 0) + continue; + + maxoff = curoff + (brdp->nrports * MAXLINE); + if (off >= maxoff) { + curoff = maxoff; + continue; + } + + totalport = brdnr * STL_MAXPORTS; + for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { + panelp = brdp->panels[panelnr]; + if (panelp == (stlpanel_t *) NULL) + continue; + + maxoff = curoff + (panelp->nrports * MAXLINE); + if (off >= maxoff) { + curoff = maxoff; + totalport += panelp->nrports; + continue; + } + + for (portnr = 0; (portnr < panelp->nrports); portnr++, + totalport++) { + portp = panelp->ports[portnr]; + if (portp == (stlport_t *) NULL) + continue; + if (off >= (curoff += MAXLINE)) + continue; + if ((pos - page + MAXLINE) > count) + goto stl_readdone; + pos += stl_portinfo(portp, totalport, pos); + } + } + } + + *eof = 1; + +stl_readdone: + *start = page; + return(pos - page); +} + +/*****************************************************************************/ + +/* + * All board interrupts are vectored through here first. This code then + * calls off to the approrpriate board interrupt handlers. + */ + +static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + stlbrd_t *brdp; + int i; + +#if DEBUG + printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); +#endif + + for (i = 0; (i < stl_nrbrds); i++) { + if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) + continue; + if (brdp->state == 0) + continue; + (* brdp->isr)(brdp); + } +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for EasyIO board types. + */ + +static void stl_eiointr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int iobase; + + panelp = brdp->panels[0]; + iobase = panelp->iobase; + while (inb(brdp->iostatus) & EIO_INTRPEND) + (* panelp->isr)(panelp, iobase); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-AT board types. + */ + +static void stl_echatintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); + + while (inb(brdp->iostatus) & ECH_INTRPEND) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } + } + + outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-MCA board types. + */ + +static void stl_echmcaintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + while (inb(brdp->iostatus) & ECH_INTRPEND) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } + } +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-PCI board types. + */ + +static void stl_echpciintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr, recheck; + + while (1) { + recheck = 0; + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + recheck++; + } + } + if (! recheck) + break; + } +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for ECH-8/64-PCI board types. + */ + +static void stl_echpci64intr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + while (inb(brdp->ioctrl) & 0x1) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } + } +} + +/*****************************************************************************/ + +/* + * Service an off-level request for some channel. + */ +static void stl_offintr(void *private) +{ + stlport_t *portp; + struct tty_struct *tty; + unsigned int oldsigs; + + portp = private; + +#if DEBUG + printk("stl_offintr(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + lock_kernel(); + if (test_bit(ASYI_TXLOW, &portp->istate)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { + clear_bit(ASYI_DCDCHANGE, &portp->istate); + oldsigs = portp->sigs; + portp->sigs = stl_getsignals(portp); + if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) + wake_up_interruptible(&portp->open_wait); + if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { + if (portp->flags & ASYNC_CHECK_CD) { + if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && + (portp->flags & ASYNC_CALLOUT_NOHUP))) { + tty_hangup(tty); + } + } + } + } + unlock_kernel(); +} + +/*****************************************************************************/ + +/* + * Map in interrupt vector to this driver. Check that we don't + * already have this vector mapped, we might be sharing this + * interrupt across multiple boards. + */ + +static int __init stl_mapirq(int irq, char *name) +{ + int rc, i; + +#if DEBUG + printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); +#endif + + rc = 0; + for (i = 0; (i < stl_numintrs); i++) { + if (stl_gotintrs[i] == irq) + break; + } + if (i >= stl_numintrs) { + if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, irq); + rc = -ENODEV; + } else { + stl_gotintrs[stl_numintrs++] = irq; + } + } + return(rc); +} + +/*****************************************************************************/ + +/* + * Initialize all the ports on a panel. + */ + +static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) +{ + stlport_t *portp; + int chipmask, i; + +#if DEBUG + printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); +#endif + + chipmask = stl_panelinit(brdp, panelp); + +/* + * All UART's are initialized (if found!). Now go through and setup + * each ports data structures. + */ + for (i = 0; (i < panelp->nrports); i++) { + portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); + if (portp == (stlport_t *) NULL) { + printk("STALLION: failed to allocate memory " + "(size=%d)\n", sizeof(stlport_t)); + break; + } + memset(portp, 0, sizeof(stlport_t)); + + portp->magic = STL_PORTMAGIC; + portp->portnr = i; + portp->brdnr = panelp->brdnr; + portp->panelnr = panelp->panelnr; + portp->uartp = panelp->uartp; + portp->clk = brdp->clk; + portp->baud_base = STL_BAUDBASE; + portp->close_delay = STL_CLOSEDELAY; + portp->closing_wait = 30 * HZ; + portp->normaltermios = stl_deftermios; + portp->callouttermios = stl_deftermios; + portp->tqueue.routine = stl_offintr; + portp->tqueue.data = portp; + init_waitqueue_head(&portp->open_wait); + init_waitqueue_head(&portp->close_wait); + portp->stats.brd = portp->brdnr; + portp->stats.panel = portp->panelnr; + portp->stats.port = portp->portnr; + panelp->ports[i] = portp; + stl_portinit(brdp, panelp, portp); + } + + return(0); +} + +/*****************************************************************************/ + +/* + * Try to find and initialize an EasyIO board. + */ + +static inline int stl_initeio(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int status; + char *name; + int rc; + +#if DEBUG + printk("stl_initeio(brdp=%x)\n", (int) brdp); +#endif + + brdp->ioctrl = brdp->ioaddr1 + 1; + brdp->iostatus = brdp->ioaddr1 + 2; + + status = inb(brdp->iostatus); + if ((status & EIO_IDBITMASK) == EIO_MK3) + brdp->ioctrl++; + +/* + * Handle board specific stuff now. The real difference is PCI + * or not PCI. + */ + if (brdp->brdtype == BRD_EASYIOPCI) { + brdp->iosize1 = 0x80; + brdp->iosize2 = 0x80; + name = "serial(EIO-PCI)"; + outb(0x41, (brdp->ioaddr2 + 0x4c)); + } else { + brdp->iosize1 = 8; + name = "serial(EIO)"; + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", + brdp->irq, brdp->brdnr); + return(-EINVAL); + } + outb((stl_vecmap[brdp->irq] | EIO_0WS | + ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), + brdp->ioctrl); + } + + if (check_region(brdp->ioaddr1, brdp->iosize1)) { + printk("STALLION: Warning, board %d I/O address %x conflicts " + "with another device\n", brdp->brdnr, brdp->ioaddr1); + } + if (brdp->iosize2 > 0) { + if (check_region(brdp->ioaddr2, brdp->iosize2)) { + printk("STALLION: Warning, board %d I/O address %x " + "conflicts with another device\n", + brdp->brdnr, brdp->ioaddr2); + } + } + +/* + * Everything looks OK, so let's go ahead and probe for the hardware. + */ + brdp->clk = CD1400_CLK; + brdp->isr = stl_eiointr; + + switch (status & EIO_IDBITMASK) { + case EIO_8PORTM: + brdp->clk = CD1400_CLK8M; + /* fall thru */ + case EIO_8PORTRS: + case EIO_8PORTDI: + brdp->nrports = 8; + break; + case EIO_4PORTRS: + brdp->nrports = 4; + break; + case EIO_MK3: + switch (status & EIO_BRDMASK) { + case ID_BRD4: + brdp->nrports = 4; + break; + case ID_BRD8: + brdp->nrports = 8; + break; + case ID_BRD16: + brdp->nrports = 16; + break; + default: + return(-ENODEV); + } + break; + default: + return(-ENODEV); + } + +/* + * We have verfied that the board is actually present, so now we + * can complete the setup. + */ + request_region(brdp->ioaddr1, brdp->iosize1, name); + if (brdp->iosize2 > 0) + request_region(brdp->ioaddr2, brdp->iosize2, name); + + panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); + if (panelp == (stlpanel_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", + sizeof(stlpanel_t)); + return(-ENOMEM); + } + memset(panelp, 0, sizeof(stlpanel_t)); + + panelp->magic = STL_PANELMAGIC; + panelp->brdnr = brdp->brdnr; + panelp->panelnr = 0; + panelp->nrports = brdp->nrports; + panelp->iobase = brdp->ioaddr1; + panelp->hwid = status; + if ((status & EIO_IDBITMASK) == EIO_MK3) { + panelp->uartp = (void *) &stl_sc26198uart; + panelp->isr = stl_sc26198intr; + } else { + panelp->uartp = (void *) &stl_cd1400uart; + panelp->isr = stl_cd1400eiointr; + } + + brdp->panels[0] = panelp; + brdp->nrpanels = 1; + brdp->state |= BRD_FOUND; + brdp->hwid = status; + rc = stl_mapirq(brdp->irq, name); + return(rc); +} + +/*****************************************************************************/ + +/* + * Try to find an ECH board and initialize it. This code is capable of + * dealing with all types of ECH board. + */ + +static int inline stl_initech(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int status, nxtid, ioaddr, conflict; + int panelnr, banknr, i; + char *name; + +#if DEBUG + printk("stl_initech(brdp=%x)\n", (int) brdp); +#endif + + status = 0; + conflict = 0; + +/* + * Set up the initial board register contents for boards. This varies a + * bit between the different board types. So we need to handle each + * separately. Also do a check that the supplied IRQ is good. + */ + switch (brdp->brdtype) { + + case BRD_ECH: + brdp->isr = stl_echatintr; + brdp->ioctrl = brdp->ioaddr1 + 1; + brdp->iostatus = brdp->ioaddr1 + 1; + status = inb(brdp->iostatus); + if ((status & ECH_IDBITMASK) != ECH_ID) + return(-ENODEV); + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", + brdp->irq, brdp->brdnr); + return(-EINVAL); + } + status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); + status |= (stl_vecmap[brdp->irq] << 1); + outb((status | ECH_BRDRESET), brdp->ioaddr1); + brdp->ioctrlval = ECH_INTENABLE | + ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); + for (i = 0; (i < 10); i++) + outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); + brdp->iosize1 = 2; + brdp->iosize2 = 32; + name = "serial(EC8/32)"; + outb(status, brdp->ioaddr1); + break; + + case BRD_ECHMC: + brdp->isr = stl_echmcaintr; + brdp->ioctrl = brdp->ioaddr1 + 0x20; + brdp->iostatus = brdp->ioctrl; + status = inb(brdp->iostatus); + if ((status & ECH_IDBITMASK) != ECH_ID) + return(-ENODEV); + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", + brdp->irq, brdp->brdnr); + return(-EINVAL); + } + outb(ECHMC_BRDRESET, brdp->ioctrl); + outb(ECHMC_INTENABLE, brdp->ioctrl); + brdp->iosize1 = 64; + name = "serial(EC8/32-MC)"; + break; + + case BRD_ECHPCI: + brdp->isr = stl_echpciintr; + brdp->ioctrl = brdp->ioaddr1 + 2; + brdp->iosize1 = 4; + brdp->iosize2 = 8; + name = "serial(EC8/32-PCI)"; + break; + + case BRD_ECH64PCI: + brdp->isr = stl_echpci64intr; + brdp->ioctrl = brdp->ioaddr2 + 0x40; + outb(0x43, (brdp->ioaddr1 + 0x4c)); + brdp->iosize1 = 0x80; + brdp->iosize2 = 0x80; + name = "serial(EC8/64-PCI)"; + break; + + default: + printk("STALLION: unknown board type=%d\n", brdp->brdtype); + return(-EINVAL); + break; + } + +/* + * Check boards for possible IO address conflicts. We won't actually + * do anything about it here, just issue a warning... + */ + conflict = check_region(brdp->ioaddr1, brdp->iosize1) ? + brdp->ioaddr1 : 0; + if ((conflict == 0) && (brdp->iosize2 > 0)) + conflict = check_region(brdp->ioaddr2, brdp->iosize2) ? + brdp->ioaddr2 : 0; + if (conflict) { + printk("STALLION: Warning, board %d I/O address %x conflicts " + "with another device\n", brdp->brdnr, conflict); + } + + request_region(brdp->ioaddr1, brdp->iosize1, name); + if (brdp->iosize2 > 0) + request_region(brdp->ioaddr2, brdp->iosize2, name); + +/* + * Scan through the secondary io address space looking for panels. + * As we find'em allocate and initialize panel structures for each. + */ + brdp->clk = CD1400_CLK; + brdp->hwid = status; + + ioaddr = brdp->ioaddr2; + banknr = 0; + panelnr = 0; + nxtid = 0; + + for (i = 0; (i < STL_MAXPANELS); i++) { + if (brdp->brdtype == BRD_ECHPCI) { + outb(nxtid, brdp->ioctrl); + ioaddr = brdp->ioaddr2; + } + status = inb(ioaddr + ECH_PNLSTATUS); + if ((status & ECH_PNLIDMASK) != nxtid) + break; + panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); + if (panelp == (stlpanel_t *) NULL) { + printk("STALLION: failed to allocate memory " + "(size=%d)\n", sizeof(stlpanel_t)); + break; + } + memset(panelp, 0, sizeof(stlpanel_t)); + panelp->magic = STL_PANELMAGIC; + panelp->brdnr = brdp->brdnr; + panelp->panelnr = panelnr; + panelp->iobase = ioaddr; + panelp->pagenr = nxtid; + panelp->hwid = status; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; + + if (status & ECH_PNLXPID) { + panelp->uartp = (void *) &stl_sc26198uart; + panelp->isr = stl_sc26198intr; + if (status & ECH_PNL16PORT) { + panelp->nrports = 16; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + 4 + + ECH_PNLSTATUS; + } else { + panelp->nrports = 8; + } + } else { + panelp->uartp = (void *) &stl_cd1400uart; + panelp->isr = stl_cd1400echintr; + if (status & ECH_PNL16PORT) { + panelp->nrports = 16; + panelp->ackmask = 0x80; + if (brdp->brdtype != BRD_ECHPCI) + ioaddr += EREG_BANKSIZE; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = ++nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + + ECH_PNLSTATUS; + } else { + panelp->nrports = 8; + panelp->ackmask = 0xc0; + } + } + + nxtid++; + ioaddr += EREG_BANKSIZE; + brdp->nrports += panelp->nrports; + brdp->panels[panelnr++] = panelp; + if ((brdp->brdtype != BRD_ECHPCI) && + (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) + break; + } + + brdp->nrpanels = panelnr; + brdp->nrbnks = banknr; + if (brdp->brdtype == BRD_ECH) + outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); + + brdp->state |= BRD_FOUND; + i = stl_mapirq(brdp->irq, name); + return(i); +} + +/*****************************************************************************/ + +/* + * Initialize and configure the specified board. + * Scan through all the boards in the configuration and see what we + * can find. Handle EIO and the ECH boards a little differently here + * since the initial search and setup is very different. + */ + +static int __init stl_brdinit(stlbrd_t *brdp) +{ + int i; + +#if DEBUG + printk("stl_brdinit(brdp=%x)\n", (int) brdp); +#endif + + switch (brdp->brdtype) { + case BRD_EASYIO: + case BRD_EASYIOPCI: + stl_initeio(brdp); + break; + case BRD_ECH: + case BRD_ECHMC: + case BRD_ECHPCI: + case BRD_ECH64PCI: + stl_initech(brdp); + break; + default: + printk("STALLION: board=%d is unknown board type=%d\n", + brdp->brdnr, brdp->brdtype); + return(ENODEV); + } + + stl_brds[brdp->brdnr] = brdp; + if ((brdp->state & BRD_FOUND) == 0) { + printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", + stl_brdnames[brdp->brdtype], brdp->brdnr, + brdp->ioaddr1, brdp->irq); + return(ENODEV); + } + + for (i = 0; (i < STL_MAXPANELS); i++) + if (brdp->panels[i] != (stlpanel_t *) NULL) + stl_initports(brdp, brdp->panels[i]); + + printk("STALLION: %s found, board=%d io=%x irq=%d " + "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], + brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, + brdp->nrports); + return(0); +} + +/*****************************************************************************/ + +/* + * Find the next available board number that is free. + */ + +static inline int stl_getbrdnr() +{ + int i; + + for (i = 0; (i < STL_MAXBRDS); i++) { + if (stl_brds[i] == (stlbrd_t *) NULL) { + if (i >= stl_nrbrds) + stl_nrbrds = i + 1; + return(i); + } + } + return(-1); +} + +/*****************************************************************************/ + +#ifdef CONFIG_PCI + +/* + * We have a Stallion board. Allocate a board structure and + * initialize it. Read its IO and IRQ resources from PCI + * configuration space. + */ + +static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) +{ + stlbrd_t *brdp; + +#if DEBUG + printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, + devp->bus->number, devp->devfn); +#endif + + if (pci_enable_device(devp)) + return(-EIO); + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + return(-ENOMEM); + if ((brdp->brdnr = stl_getbrdnr()) < 0) { + printk("STALLION: too many boards found, " + "maximum supported %d\n", STL_MAXBRDS); + return(0); + } + brdp->brdtype = brdtype; + +/* + * Different Stallion boards use the BAR registers in different ways, + * so set up io addresses based on board type. + */ +#if DEBUG + printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, + pci_resource_start(devp, 0), pci_resource_start(devp, 1), + pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); +#endif + +/* + * We have all resources from the board, so let's setup the actual + * board structure now. + */ + switch (brdtype) { + case BRD_ECHPCI: + brdp->ioaddr2 = pci_resource_start(devp, 0); + brdp->ioaddr1 = pci_resource_start(devp, 1); + break; + case BRD_ECH64PCI: + brdp->ioaddr2 = pci_resource_start(devp, 2); + brdp->ioaddr1 = pci_resource_start(devp, 1); + break; + case BRD_EASYIOPCI: + brdp->ioaddr1 = pci_resource_start(devp, 2); + brdp->ioaddr2 = pci_resource_start(devp, 1); + break; + default: + printk("STALLION: unknown PCI board type=%d\n", brdtype); + break; + } + + brdp->irq = devp->irq; + stl_brdinit(brdp); + + return(0); +} + +/*****************************************************************************/ + +/* + * Find all Stallion PCI boards that might be installed. Initialize each + * one as it is found. + */ + + +static inline int stl_findpcibrds() +{ + struct pci_dev *dev = NULL; + int i, rc; + +#if DEBUG + printk("stl_findpcibrds()\n"); +#endif + + if (! pci_present()) + return(0); + + for (i = 0; (i < stl_nrpcibrds); i++) + while ((dev = pci_find_device(stl_pcibrds[i].vendid, + stl_pcibrds[i].devid, dev))) { + +/* + * Found a device on the PCI bus that has our vendor and + * device ID. Need to check now that it is really us. + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) + continue; + + rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev); + if (rc) + return(rc); + } + + return(0); +} + +#endif + +/*****************************************************************************/ + +/* + * Scan through all the boards in the configuration and see what we + * can find. Handle EIO and the ECH boards a little differently here + * since the initial search and setup is too different. + */ + +static inline int stl_initbrds() +{ + stlbrd_t *brdp; + stlconf_t *confp; + int i; + +#if DEBUG + printk("stl_initbrds()\n"); +#endif + + if (stl_nrbrds > STL_MAXBRDS) { + printk("STALLION: too many boards in configuration table, " + "truncating to %d\n", STL_MAXBRDS); + stl_nrbrds = STL_MAXBRDS; + } + +/* + * Firstly scan the list of static boards configured. Allocate + * resources and initialize the boards as found. + */ + for (i = 0; (i < stl_nrbrds); i++) { + confp = &stl_brdconf[i]; +#ifdef MODULE + stl_parsebrd(confp, stl_brdsp[i]); +#endif + if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL) + return(-ENOMEM); + brdp->brdnr = i; + brdp->brdtype = confp->brdtype; + brdp->ioaddr1 = confp->ioaddr1; + brdp->ioaddr2 = confp->ioaddr2; + brdp->irq = confp->irq; + brdp->irqtype = confp->irqtype; + stl_brdinit(brdp); + } + +/* + * Find any dynamically supported boards. That is via module load + * line options or auto-detected on the PCI bus. + */ +#ifdef MODULE + stl_argbrds(); +#endif +#ifdef CONFIG_PCI + stl_findpcibrds(); +#endif + + return(0); +} + +/*****************************************************************************/ + +/* + * Return the board stats structure to user app. + */ + +static int stl_getbrdstats(combrd_t *bp) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + int i; + + copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)); + if (stl_brdstats.brd >= STL_MAXBRDS) + return(-ENODEV); + brdp = stl_brds[stl_brdstats.brd]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + + memset(&stl_brdstats, 0, sizeof(combrd_t)); + stl_brdstats.brd = brdp->brdnr; + stl_brdstats.type = brdp->brdtype; + stl_brdstats.hwid = brdp->hwid; + stl_brdstats.state = brdp->state; + stl_brdstats.ioaddr = brdp->ioaddr1; + stl_brdstats.ioaddr2 = brdp->ioaddr2; + stl_brdstats.irq = brdp->irq; + stl_brdstats.nrpanels = brdp->nrpanels; + stl_brdstats.nrports = brdp->nrports; + for (i = 0; (i < brdp->nrpanels); i++) { + panelp = brdp->panels[i]; + stl_brdstats.panels[i].panel = i; + stl_brdstats.panels[i].hwid = panelp->hwid; + stl_brdstats.panels[i].nrports = panelp->nrports; + } + + copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Resolve the referenced port number into a port struct pointer. + */ + +static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + + if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) + return((stlport_t *) NULL); + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + return((stlport_t *) NULL); + if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) + return((stlport_t *) NULL); + panelp = brdp->panels[panelnr]; + if (panelp == (stlpanel_t *) NULL) + return((stlport_t *) NULL); + if ((portnr < 0) || (portnr >= panelp->nrports)) + return((stlport_t *) NULL); + return(panelp->ports[portnr]); +} + +/*****************************************************************************/ + +/* + * Return the port stats structure to user app. A NULL port struct + * pointer passed in means that we need to find out from the app + * what port to get stats for (used through board control device). + */ + +static int stl_getportstats(stlport_t *portp, comstats_t *cp) +{ + unsigned char *head, *tail; + unsigned long flags; + + if (portp == (stlport_t *) NULL) { + copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); + portp = stl_getport(stl_comstats.brd, stl_comstats.panel, + stl_comstats.port); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + } + + portp->stats.state = portp->istate; + portp->stats.flags = portp->flags; + portp->stats.hwid = portp->hwid; + + portp->stats.ttystate = 0; + portp->stats.cflags = 0; + portp->stats.iflags = 0; + portp->stats.oflags = 0; + portp->stats.lflags = 0; + portp->stats.rxbuffered = 0; + + save_flags(flags); + cli(); + if (portp->tty != (struct tty_struct *) NULL) { + if (portp->tty->driver_data == portp) { + portp->stats.ttystate = portp->tty->flags; + portp->stats.rxbuffered = portp->tty->flip.count; + if (portp->tty->termios != (struct termios *) NULL) { + portp->stats.cflags = portp->tty->termios->c_cflag; + portp->stats.iflags = portp->tty->termios->c_iflag; + portp->stats.oflags = portp->tty->termios->c_oflag; + portp->stats.lflags = portp->tty->termios->c_lflag; + } + } + } + restore_flags(flags); + + head = portp->tx.head; + tail = portp->tx.tail; + portp->stats.txbuffered = ((head >= tail) ? (head - tail) : + (STL_TXBUFSIZE - (tail - head))); + + portp->stats.signals = (unsigned long) stl_getsignals(portp); + + copy_to_user(cp, &portp->stats, sizeof(comstats_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Clear the port stats structure. We also return it zeroed out... + */ + +static int stl_clrportstats(stlport_t *portp, comstats_t *cp) +{ + if (portp == (stlport_t *) NULL) { + copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); + portp = stl_getport(stl_comstats.brd, stl_comstats.panel, + stl_comstats.port); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + } + + memset(&portp->stats, 0, sizeof(comstats_t)); + portp->stats.brd = portp->brdnr; + portp->stats.panel = portp->panelnr; + portp->stats.port = portp->portnr; + copy_to_user(cp, &portp->stats, sizeof(comstats_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Return the entire driver ports structure to a user app. + */ + +static int stl_getportstruct(unsigned long arg) +{ + stlport_t *portp; + + copy_from_user(&stl_dummyport, (void *) arg, sizeof(stlport_t)); + portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, + stl_dummyport.portnr); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + copy_to_user((void *) arg, portp, sizeof(stlport_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Return the entire driver board structure to a user app. + */ + +static int stl_getbrdstruct(unsigned long arg) +{ + stlbrd_t *brdp; + + copy_from_user(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t)); + if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) + return(-ENODEV); + brdp = stl_brds[stl_dummybrd.brdnr]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + copy_to_user((void *) arg, brdp, sizeof(stlbrd_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * The "staliomem" device is also required to do some special operations + * on the board and/or ports. In this driver it is mostly used for stats + * collection. + */ + +static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +{ + int brdnr, rc; + +#if DEBUG + printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, + (int) fp, cmd, (int) arg); +#endif + + brdnr = MINOR(ip->i_rdev); + if (brdnr >= STL_MAXBRDS) + return(-ENODEV); + rc = 0; + + switch (cmd) { + case COM_GETPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_getportstats((stlport_t *) NULL, + (comstats_t *) arg); + break; + case COM_CLRPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(comstats_t))) == 0) + rc = stl_clrportstats((stlport_t *) NULL, + (comstats_t *) arg); + break; + case COM_GETBRDSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(combrd_t))) == 0) + rc = stl_getbrdstats((combrd_t *) arg); + break; + case COM_READPORT: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(stlport_t))) == 0) + rc = stl_getportstruct(arg); + break; + case COM_READBOARD: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(stlbrd_t))) == 0) + rc = stl_getbrdstruct(arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return(rc); +} + +/*****************************************************************************/ + +int __init stl_init(void) +{ + printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion); + + stl_initbrds(); + +/* + * Allocate a temporary write buffer. + */ + stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); + if (stl_tmpwritebuf == (char *) NULL) + printk("STALLION: failed to allocate memory (size=%d)\n", + STL_TXBUFSIZE); + +/* + * Set up a character driver for per board stuff. This is mainly used + * to do stats ioctls on the ports. + */ + if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) + printk("STALLION: failed to register serial board device\n"); + devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL); + devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, + STL_SIOMEMMAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &stl_fsiomem, NULL); + +/* + * Set up the tty driver structure and register us as a driver. + * Also setup the callout tty device. + */ + memset(&stl_serial, 0, sizeof(struct tty_driver)); + stl_serial.magic = TTY_DRIVER_MAGIC; + stl_serial.driver_name = stl_drvname; + stl_serial.name = stl_serialname; + stl_serial.major = STL_SERIALMAJOR; + stl_serial.minor_start = 0; + stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; + stl_serial.type = TTY_DRIVER_TYPE_SERIAL; + stl_serial.subtype = STL_DRVTYPSERIAL; + stl_serial.init_termios = stl_deftermios; + stl_serial.flags = TTY_DRIVER_REAL_RAW; + stl_serial.refcount = &stl_refcount; + stl_serial.table = stl_ttys; + stl_serial.termios = stl_termios; + stl_serial.termios_locked = stl_termioslocked; + + stl_serial.open = stl_open; + stl_serial.close = stl_close; + stl_serial.write = stl_write; + stl_serial.put_char = stl_putchar; + stl_serial.flush_chars = stl_flushchars; + stl_serial.write_room = stl_writeroom; + stl_serial.chars_in_buffer = stl_charsinbuffer; + stl_serial.ioctl = stl_ioctl; + stl_serial.set_termios = stl_settermios; + stl_serial.throttle = stl_throttle; + stl_serial.unthrottle = stl_unthrottle; + stl_serial.stop = stl_stop; + stl_serial.start = stl_start; + stl_serial.hangup = stl_hangup; + stl_serial.flush_buffer = stl_flushbuffer; + stl_serial.break_ctl = stl_breakctl; + stl_serial.wait_until_sent = stl_waituntilsent; + stl_serial.send_xchar = stl_sendxchar; + stl_serial.read_proc = stl_readproc; + + stl_callout = stl_serial; + stl_callout.name = stl_calloutname; + stl_callout.major = STL_CALLOUTMAJOR; + stl_callout.subtype = STL_DRVTYPCALLOUT; + stl_callout.read_proc = 0; + + if (tty_register_driver(&stl_serial)) + printk("STALLION: failed to register serial driver\n"); + if (tty_register_driver(&stl_callout)) + printk("STALLION: failed to register callout driver\n"); + + return(0); +} + +/*****************************************************************************/ +/* CD1400 HARDWARE FUNCTIONS */ +/*****************************************************************************/ + +/* + * These functions get/set/update the registers of the cd1400 UARTs. + * Access to the cd1400 registers is via an address/data io port pair. + * (Maybe should make this inline...) + */ + +static int stl_cd1400getreg(stlport_t *portp, int regnr) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + return(inb(portp->ioaddr + EREG_DATA)); +} + +static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + outb(value, portp->ioaddr + EREG_DATA); +} + +static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + if (inb(portp->ioaddr + EREG_DATA) != value) { + outb(value, portp->ioaddr + EREG_DATA); + return(1); + } + return(0); +} + +/*****************************************************************************/ + +/* + * Inbitialize the UARTs in a panel. We don't care what sort of board + * these ports are on - since the port io registers are almost + * identical when dealing with ports. + */ + +static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +{ + unsigned int gfrcr; + int chipmask, i, j; + int nrchips, uartaddr, ioaddr; + +#if DEBUG + printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); +#endif + + BRDENABLE(panelp->brdnr, panelp->pagenr); + +/* + * Check that each chip is present and started up OK. + */ + chipmask = 0; + nrchips = panelp->nrports / CD1400_PORTS; + for (i = 0; (i < nrchips); i++) { + if (brdp->brdtype == BRD_ECHPCI) { + outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); + ioaddr = panelp->iobase; + } else { + ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); + } + uartaddr = (i & 0x01) ? 0x080 : 0; + outb((GFRCR + uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); + outb((CCR + uartaddr), ioaddr); + outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); + outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); + outb((GFRCR + uartaddr), ioaddr); + for (j = 0; (j < CCR_MAXWAIT); j++) { + if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) + break; + } + if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { + printk("STALLION: cd1400 not responding, " + "brd=%d panel=%d chip=%d\n", + panelp->brdnr, panelp->panelnr, i); + continue; + } + chipmask |= (0x1 << i); + outb((PPR + uartaddr), ioaddr); + outb(PPR_SCALAR, (ioaddr + EREG_DATA)); + } + + BRDDISABLE(panelp->brdnr); + return(chipmask); +} + +/*****************************************************************************/ + +/* + * Initialize hardware specific port registers. + */ + +static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +{ +#if DEBUG + printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", + (int) brdp, (int) panelp, (int) portp); +#endif + + if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || + (portp == (stlport_t *) NULL)) + return; + + portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || + (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); + portp->uartaddr = (portp->portnr & 0x04) << 5; + portp->pagenr = panelp->pagenr + (portp->portnr >> 3); + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); + portp->hwid = stl_cd1400getreg(portp, GFRCR); + BRDDISABLE(portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Wait for the command register to be ready. We will poll this, + * since it won't usually take too long to be ready. + */ + +static void stl_cd1400ccrwait(stlport_t *portp) +{ + int i; + + for (i = 0; (i < CCR_MAXWAIT); i++) { + if (stl_cd1400getreg(portp, CCR) == 0) { + return; + } + } + + printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n", + portp->portnr, portp->panelnr, portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Set up the cd1400 registers for a port based on the termios port + * settings. + */ + +static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) +{ + stlbrd_t *brdp; + unsigned long flags; + unsigned int clkdiv, baudrate; + unsigned char cor1, cor2, cor3; + unsigned char cor4, cor5, ccr; + unsigned char srer, sreron, sreroff; + unsigned char mcor1, mcor2, rtpr; + unsigned char clk, div; + + cor1 = 0; + cor2 = 0; + cor3 = 0; + cor4 = 0; + cor5 = 0; + ccr = 0; + rtpr = 0; + clk = 0; + div = 0; + mcor1 = 0; + mcor2 = 0; + sreron = 0; + sreroff = 0; + + brdp = stl_brds[portp->brdnr]; + if (brdp == (stlbrd_t *) NULL) + return; + +/* + * Set up the RX char ignore mask with those RX error types we + * can ignore. We can get the cd1400 to help us out a little here, + * it will ignore parity errors and breaks for us. + */ + portp->rxignoremsk = 0; + if (tiosp->c_iflag & IGNPAR) { + portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); + cor1 |= COR1_PARIGNORE; + } + if (tiosp->c_iflag & IGNBRK) { + portp->rxignoremsk |= ST_BREAK; + cor4 |= COR4_IGNBRK; + } + + portp->rxmarkmsk = ST_OVERRUN; + if (tiosp->c_iflag & (INPCK | PARMRK)) + portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); + if (tiosp->c_iflag & BRKINT) + portp->rxmarkmsk |= ST_BREAK; + +/* + * Go through the char size, parity and stop bits and set all the + * option register appropriately. + */ + switch (tiosp->c_cflag & CSIZE) { + case CS5: + cor1 |= COR1_CHL5; + break; + case CS6: + cor1 |= COR1_CHL6; + break; + case CS7: + cor1 |= COR1_CHL7; + break; + default: + cor1 |= COR1_CHL8; + break; + } + + if (tiosp->c_cflag & CSTOPB) + cor1 |= COR1_STOP2; + else + cor1 |= COR1_STOP1; + + if (tiosp->c_cflag & PARENB) { + if (tiosp->c_cflag & PARODD) + cor1 |= (COR1_PARENB | COR1_PARODD); + else + cor1 |= (COR1_PARENB | COR1_PAREVEN); + } else { + cor1 |= COR1_PARNONE; + } + +/* + * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing + * space for hardware flow control and the like. This should be set to + * VMIN. Also here we will set the RX data timeout to 10ms - this should + * really be based on VTIME. + */ + cor3 |= FIFO_RXTHRESHOLD; + rtpr = 2; + +/* + * Calculate the baud rate timers. For now we will just assume that + * the input and output baud are the same. Could have used a baud + * table here, but this way we can generate virtually any baud rate + * we like! + */ + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + baudrate = stl_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (portp->baud_base / portp->custom_divisor); + } + if (baudrate > STL_CD1400MAXBAUD) + baudrate = STL_CD1400MAXBAUD; + + if (baudrate > 0) { + for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { + clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); + if (clkdiv < 0x100) + break; + } + div = (unsigned char) clkdiv; + } + +/* + * Check what form of modem signaling is required and set it up. + */ + if ((tiosp->c_cflag & CLOCAL) == 0) { + mcor1 |= MCOR1_DCD; + mcor2 |= MCOR2_DCD; + sreron |= SRER_MODEM; + portp->flags |= ASYNC_CHECK_CD; + } else { + portp->flags &= ~ASYNC_CHECK_CD; + } + +/* + * Setup cd1400 enhanced modes if we can. In particular we want to + * handle as much of the flow control as possible automatically. As + * well as saving a few CPU cycles it will also greatly improve flow + * control reliability. + */ + if (tiosp->c_iflag & IXON) { + cor2 |= COR2_TXIBE; + cor3 |= COR3_SCD12; + if (tiosp->c_iflag & IXANY) + cor2 |= COR2_IXM; + } + + if (tiosp->c_cflag & CRTSCTS) { + cor2 |= COR2_CTSAE; + mcor1 |= FIFO_RTSTHRESHOLD; + } + +/* + * All cd1400 register values calculated so go through and set + * them all up. + */ + +#if DEBUG + printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", + portp->portnr, portp->panelnr, portp->brdnr); + printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", + cor1, cor2, cor3, cor4, cor5); + printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", + mcor1, mcor2, rtpr, sreron, sreroff); + printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); + printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); + srer = stl_cd1400getreg(portp, SRER); + stl_cd1400setreg(portp, SRER, 0); + if (stl_cd1400updatereg(portp, COR1, cor1)) + ccr = 1; + if (stl_cd1400updatereg(portp, COR2, cor2)) + ccr = 1; + if (stl_cd1400updatereg(portp, COR3, cor3)) + ccr = 1; + if (ccr) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_CORCHANGE); + } + stl_cd1400setreg(portp, COR4, cor4); + stl_cd1400setreg(portp, COR5, cor5); + stl_cd1400setreg(portp, MCOR1, mcor1); + stl_cd1400setreg(portp, MCOR2, mcor2); + if (baudrate > 0) { + stl_cd1400setreg(portp, TCOR, clk); + stl_cd1400setreg(portp, TBPR, div); + stl_cd1400setreg(portp, RCOR, clk); + stl_cd1400setreg(portp, RBPR, div); + } + stl_cd1400setreg(portp, SCHR1, tiosp->c_cc[VSTART]); + stl_cd1400setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); + stl_cd1400setreg(portp, SCHR3, tiosp->c_cc[VSTART]); + stl_cd1400setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); + stl_cd1400setreg(portp, RTPR, rtpr); + mcor1 = stl_cd1400getreg(portp, MSVR1); + if (mcor1 & MSVR1_DCD) + portp->sigs |= TIOCM_CD; + else + portp->sigs &= ~TIOCM_CD; + stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Set the state of the DTR and RTS signals. + */ + +static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) +{ + unsigned char msvr1, msvr2; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", + (int) portp, dtr, rts); +#endif + + msvr1 = 0; + msvr2 = 0; + if (dtr > 0) + msvr1 = MSVR1_DTR; + if (rts > 0) + msvr2 = MSVR2_RTS; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + if (rts >= 0) + stl_cd1400setreg(portp, MSVR2, msvr2); + if (dtr >= 0) + stl_cd1400setreg(portp, MSVR1, msvr1); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the state of the signals. + */ + +static int stl_cd1400getsignals(stlport_t *portp) +{ + unsigned char msvr1, msvr2; + unsigned long flags; + int sigs; + +#if DEBUG + printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + msvr1 = stl_cd1400getreg(portp, MSVR1); + msvr2 = stl_cd1400getreg(portp, MSVR2); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + sigs = 0; + sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; + sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; + sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; + sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; +#if 0 + sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; + sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; +#else + sigs |= TIOCM_DSR; +#endif + return(sigs); +} + +/*****************************************************************************/ + +/* + * Enable/Disable the Transmitter and/or Receiver. + */ + +static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char ccr; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + ccr = 0; + + if (tx == 0) + ccr |= CCR_TXDISABLE; + else if (tx > 0) + ccr |= CCR_TXENABLE; + if (rx == 0) + ccr |= CCR_RXDISABLE; + else if (rx > 0) + ccr |= CCR_RXENABLE; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, ccr); + stl_cd1400ccrwait(portp); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Start/stop the Transmitter and/or Receiver. + */ + +static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char sreron, sreroff; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + + sreron = 0; + sreroff = 0; + if (tx == 0) + sreroff |= (SRER_TXDATA | SRER_TXEMPTY); + else if (tx == 1) + sreron |= SRER_TXDATA; + else if (tx >= 2) + sreron |= SRER_TXEMPTY; + if (rx == 0) + sreroff |= SRER_RXDATA; + else if (rx > 0) + sreron |= SRER_RXDATA; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, + ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); + if (tx > 0) + set_bit(ASYI_TXBUSY, &portp->istate); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Disable all interrupts from this port. + */ + +static void stl_cd1400disableintrs(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); +#endif + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, 0); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_cd1400sendbreak(stlport_t *portp, int len) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, + ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | + SRER_TXEMPTY)); + BRDDISABLE(portp->brdnr); + portp->brklen = len; + if (len == 1) + portp->stats.txbreaks++; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Take flow control actions... + */ + +static void stl_cd1400flowctrl(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + + if (state) { + if (tty->termios->c_iflag & IXOFF) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); + portp->stats.rxxon++; + stl_cd1400ccrwait(portp); + } +/* + * Question: should we return RTS to what it was before? It may + * have been set by an ioctl... Suppose not, since if you have + * hardware flow control set then it is pretty silly to go and + * set the RTS line by hand. + */ + if (tty->termios->c_cflag & CRTSCTS) { + stl_cd1400setreg(portp, MCOR1, + (stl_cd1400getreg(portp, MCOR1) | + FIFO_RTSTHRESHOLD)); + stl_cd1400setreg(portp, MSVR2, MSVR2_RTS); + portp->stats.rxrtson++; + } + } else { + if (tty->termios->c_iflag & IXOFF) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); + portp->stats.rxxoff++; + stl_cd1400ccrwait(portp); + } + if (tty->termios->c_cflag & CRTSCTS) { + stl_cd1400setreg(portp, MCOR1, + (stl_cd1400getreg(portp, MCOR1) & 0xf0)); + stl_cd1400setreg(portp, MSVR2, 0); + portp->stats.rxrtsoff++; + } + } + + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Send a flow control character... + */ + +static void stl_cd1400sendflow(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + if (state) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); + portp->stats.rxxon++; + stl_cd1400ccrwait(portp); + } else { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); + portp->stats.rxxoff++; + stl_cd1400ccrwait(portp); + } + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_cd1400flush(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400flush(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_TXFLUSHFIFO); + stl_cd1400ccrwait(portp); + portp->tx.tail = portp->tx.head; + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the current state of data flow on this port. This is only + * really interresting when determining if data has fully completed + * transmission or not... This is easy for the cd1400, it accurately + * maintains the busy port flag. + */ + +static int stl_cd1400datastate(stlport_t *portp) +{ +#if DEBUG + printk("stl_cd1400datastate(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return(0); + + return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for cd1400 EasyIO boards. + */ + +static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) +{ + unsigned char svrtype; + +#if DEBUG + printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", + (int) panelp, iobase); +#endif + + outb(SVRR, iobase); + svrtype = inb(iobase + EREG_DATA); + if (panelp->nrports > 4) { + outb((SVRR + 0x80), iobase); + svrtype |= inb(iobase + EREG_DATA); + } + + if (svrtype & SVRR_RX) + stl_cd1400rxisr(panelp, iobase); + else if (svrtype & SVRR_TX) + stl_cd1400txisr(panelp, iobase); + else if (svrtype & SVRR_MDM) + stl_cd1400mdmisr(panelp, iobase); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for cd1400 panels. + */ + +static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase) +{ + unsigned char svrtype; + +#if DEBUG + printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, + iobase); +#endif + + outb(SVRR, iobase); + svrtype = inb(iobase + EREG_DATA); + outb((SVRR + 0x80), iobase); + svrtype |= inb(iobase + EREG_DATA); + if (svrtype & SVRR_RX) + stl_cd1400rxisr(panelp, iobase); + else if (svrtype & SVRR_TX) + stl_cd1400txisr(panelp, iobase); + else if (svrtype & SVRR_MDM) + stl_cd1400mdmisr(panelp, iobase); +} + + +/*****************************************************************************/ + +/* + * Unfortunately we need to handle breaks in the TX data stream, since + * this is the only way to generate them on the cd1400. + */ + +static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr) +{ + if (portp->brklen == 1) { + outb((COR2 + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) | COR2_ETC), + (ioaddr + EREG_DATA)); + outb((TDR + portp->uartaddr), ioaddr); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_STARTBREAK, (ioaddr + EREG_DATA)); + outb((SRER + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) & ~(SRER_TXDATA | SRER_TXEMPTY)), + (ioaddr + EREG_DATA)); + return(1); + } else if (portp->brklen > 1) { + outb((TDR + portp->uartaddr), ioaddr); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); + portp->brklen = -1; + return(1); + } else { + outb((COR2 + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), + (ioaddr + EREG_DATA)); + portp->brklen = 0; + } + return(0); +} + +/*****************************************************************************/ + +/* + * Transmit interrupt handler. This has gotta be fast! Handling TX + * chars is pretty simple, stuff as many as possible from the TX buffer + * into the cd1400 FIFO. Must also handle TX breaks here, since they + * are embedded as commands in the data stream. Oh no, had to use a goto! + * This could be optimized more, will do when I get time... + * In practice it is possible that interrupts are enabled but that the + * port has been hung up. Need to handle not having any TX buffer here, + * this is done by using the side effect that head and tail will also + * be NULL if the buffer has been freed. + */ + +static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + int len, stlen; + char *head, *tail; + unsigned char ioack, srer; + +#if DEBUG + printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); +#endif + + ioack = inb(ioaddr + EREG_TXACK); + if (((ioack & panelp->ackmask) != 0) || + ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { + printk("STALLION: bad TX interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + +/* + * Unfortunately we need to handle breaks in the data stream, since + * this is the only way to generate them on the cd1400. Do it now if + * a break is to be sent. + */ + if (portp->brklen != 0) + if (stl_cd1400breakisr(portp, ioaddr)) + goto stl_txalldone; + + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((len == 0) || ((len < STL_TXBUFLOW) && + (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { + set_bit(ASYI_TXLOW, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + } + + if (len == 0) { + outb((SRER + portp->uartaddr), ioaddr); + srer = inb(ioaddr + EREG_DATA); + if (srer & SRER_TXDATA) { + srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; + } else { + srer &= ~(SRER_TXDATA | SRER_TXEMPTY); + clear_bit(ASYI_TXBUSY, &portp->istate); + } + outb(srer, (ioaddr + EREG_DATA)); + } else { + len = MIN(len, CD1400_TXFIFOSIZE); + portp->stats.txtotal += len; + stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + outb((TDR + portp->uartaddr), ioaddr); + outsb((ioaddr + EREG_DATA), tail, stlen); + len -= stlen; + tail += stlen; + if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) + tail = portp->tx.buf; + if (len > 0) { + outsb((ioaddr + EREG_DATA), tail, len); + tail += len; + } + portp->tx.tail = tail; + } + +stl_txalldone: + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ + +/* + * Receive character interrupt handler. Determine if we have good chars + * or bad chars and then process appropriately. Good chars are easy + * just shove the lot into the RX buffer and set all status byte to 0. + * If a bad RX char then process as required. This routine needs to be + * fast! In practice it is possible that we get an interrupt on a port + * that is closed. This can happen on hangups - since they completely + * shutdown a port not in user context. Need to handle this case. + */ + +static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + struct tty_struct *tty; + unsigned int ioack, len, buflen; + unsigned char status; + char ch; + +#if DEBUG + printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); +#endif + + ioack = inb(ioaddr + EREG_RXACK); + if ((ioack & panelp->ackmask) != 0) { + printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + tty = portp->tty; + + if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { + outb((RDCR + portp->uartaddr), ioaddr); + len = inb(ioaddr + EREG_DATA); + if ((tty == (struct tty_struct *) NULL) || + (tty->flip.char_buf_ptr == (char *) NULL) || + ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + len = MIN(len, sizeof(stl_unwanted)); + outb((RDSR + portp->uartaddr), ioaddr); + insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); + portp->stats.rxlost += len; + portp->stats.rxtotal += len; + } else { + len = MIN(len, buflen); + if (len > 0) { + outb((RDSR + portp->uartaddr), ioaddr); + insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + tty->flip.char_buf_ptr += len; + tty->flip.count += len; + tty_schedule_flip(tty); + portp->stats.rxtotal += len; + } + } + } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { + outb((RDSR + portp->uartaddr), ioaddr); + status = inb(ioaddr + EREG_DATA); + ch = inb(ioaddr + EREG_DATA); + if (status & ST_PARITY) + portp->stats.rxparity++; + if (status & ST_FRAMING) + portp->stats.rxframing++; + if (status & ST_OVERRUN) + portp->stats.rxoverrun++; + if (status & ST_BREAK) + portp->stats.rxbreaks++; + if (status & ST_SCHARMASK) { + if ((status & ST_SCHARMASK) == ST_SCHAR1) + portp->stats.txxon++; + if ((status & ST_SCHARMASK) == ST_SCHAR2) + portp->stats.txxoff++; + goto stl_rxalldone; + } + if ((tty != (struct tty_struct *) NULL) && + ((portp->rxignoremsk & status) == 0)) { + if (portp->rxmarkmsk & status) { + if (status & ST_BREAK) { + status = TTY_BREAK; + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + BRDENABLE(portp->brdnr, portp->pagenr); + } + } else if (status & ST_PARITY) { + status = TTY_PARITY; + } else if (status & ST_FRAMING) { + status = TTY_FRAME; + } else if(status & ST_OVERRUN) { + status = TTY_OVERRUN; + } else { + status = 0; + } + } else { + status = 0; + } + if (tty->flip.char_buf_ptr != (char *) NULL) { + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.flag_buf_ptr++ = status; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + } + tty_schedule_flip(tty); + } + } + } else { + printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + return; + } + +stl_rxalldone: + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ + +/* + * Modem interrupt handler. The is called when the modem signal line + * (DCD) has changed state. Leave most of the work to the off-level + * processing routine. + */ + +static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + unsigned int ioack; + unsigned char misr; + +#if DEBUG + printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp); +#endif + + ioack = inb(ioaddr + EREG_MDACK); + if (((ioack & panelp->ackmask) != 0) || + ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { + printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + + outb((MISR + portp->uartaddr), ioaddr); + misr = inb(ioaddr + EREG_DATA); + if (misr & MISR_DCD) { + set_bit(ASYI_DCDCHANGE, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + portp->stats.modem++; + } + + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ +/* SC26198 HARDWARE FUNCTIONS */ +/*****************************************************************************/ + +/* + * These functions get/set/update the registers of the sc26198 UARTs. + * Access to the sc26198 registers is via an address/data io port pair. + * (Maybe should make this inline...) + */ + +static int stl_sc26198getreg(stlport_t *portp, int regnr) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + return(inb(portp->ioaddr + XP_DATA)); +} + +static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + outb(value, (portp->ioaddr + XP_DATA)); +} + +static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + if (inb(portp->ioaddr + XP_DATA) != value) { + outb(value, (portp->ioaddr + XP_DATA)); + return(1); + } + return(0); +} + +/*****************************************************************************/ + +/* + * Functions to get and set the sc26198 global registers. + */ + +static int stl_sc26198getglobreg(stlport_t *portp, int regnr) +{ + outb(regnr, (portp->ioaddr + XP_ADDR)); + return(inb(portp->ioaddr + XP_DATA)); +} + +#if 0 +static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) +{ + outb(regnr, (portp->ioaddr + XP_ADDR)); + outb(value, (portp->ioaddr + XP_DATA)); +} +#endif + +/*****************************************************************************/ + +/* + * Inbitialize the UARTs in a panel. We don't care what sort of board + * these ports are on - since the port io registers are almost + * identical when dealing with ports. + */ + +static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +{ + int chipmask, i; + int nrchips, ioaddr; + +#if DEBUG + printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", + (int) brdp, (int) panelp); +#endif + + BRDENABLE(panelp->brdnr, panelp->pagenr); + +/* + * Check that each chip is present and started up OK. + */ + chipmask = 0; + nrchips = (panelp->nrports + 4) / SC26198_PORTS; + if (brdp->brdtype == BRD_ECHPCI) + outb(panelp->pagenr, brdp->ioctrl); + + for (i = 0; (i < nrchips); i++) { + ioaddr = panelp->iobase + (i * 4); + outb(SCCR, (ioaddr + XP_ADDR)); + outb(CR_RESETALL, (ioaddr + XP_DATA)); + outb(TSTR, (ioaddr + XP_ADDR)); + if (inb(ioaddr + XP_DATA) != 0) { + printk("STALLION: sc26198 not responding, " + "brd=%d panel=%d chip=%d\n", + panelp->brdnr, panelp->panelnr, i); + continue; + } + chipmask |= (0x1 << i); + outb(GCCR, (ioaddr + XP_ADDR)); + outb(GCCR_IVRTYPCHANACK, (ioaddr + XP_DATA)); + outb(WDTRCR, (ioaddr + XP_ADDR)); + outb(0xff, (ioaddr + XP_DATA)); + } + + BRDDISABLE(panelp->brdnr); + return(chipmask); +} + +/*****************************************************************************/ + +/* + * Initialize hardware specific port registers. + */ + +static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +{ +#if DEBUG + printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n", + (int) brdp, (int) panelp, (int) portp); +#endif + + if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || + (portp == (stlport_t *) NULL)) + return; + + portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4); + portp->uartaddr = (portp->portnr & 0x07) << 4; + portp->pagenr = panelp->pagenr; + portp->hwid = 0x1; + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IOPCR, IOPCR_SETSIGS); + BRDDISABLE(portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Set up the sc26198 registers for a port based on the termios port + * settings. + */ + +static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) +{ + stlbrd_t *brdp; + unsigned long flags; + unsigned int baudrate; + unsigned char mr0, mr1, mr2, clk; + unsigned char imron, imroff, iopr, ipr; + + mr0 = 0; + mr1 = 0; + mr2 = 0; + clk = 0; + iopr = 0; + imron = 0; + imroff = 0; + + brdp = stl_brds[portp->brdnr]; + if (brdp == (stlbrd_t *) NULL) + return; + +/* + * Set up the RX char ignore mask with those RX error types we + * can ignore. + */ + portp->rxignoremsk = 0; + if (tiosp->c_iflag & IGNPAR) + portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING | + SR_RXOVERRUN); + if (tiosp->c_iflag & IGNBRK) + portp->rxignoremsk |= SR_RXBREAK; + + portp->rxmarkmsk = SR_RXOVERRUN; + if (tiosp->c_iflag & (INPCK | PARMRK)) + portp->rxmarkmsk |= (SR_RXPARITY | SR_RXFRAMING); + if (tiosp->c_iflag & BRKINT) + portp->rxmarkmsk |= SR_RXBREAK; + +/* + * Go through the char size, parity and stop bits and set all the + * option register appropriately. + */ + switch (tiosp->c_cflag & CSIZE) { + case CS5: + mr1 |= MR1_CS5; + break; + case CS6: + mr1 |= MR1_CS6; + break; + case CS7: + mr1 |= MR1_CS7; + break; + default: + mr1 |= MR1_CS8; + break; + } + + if (tiosp->c_cflag & CSTOPB) + mr2 |= MR2_STOP2; + else + mr2 |= MR2_STOP1; + + if (tiosp->c_cflag & PARENB) { + if (tiosp->c_cflag & PARODD) + mr1 |= (MR1_PARENB | MR1_PARODD); + else + mr1 |= (MR1_PARENB | MR1_PAREVEN); + } else { + mr1 |= MR1_PARNONE; + } + + mr1 |= MR1_ERRBLOCK; + +/* + * Set the RX FIFO threshold at 8 chars. This gives a bit of breathing + * space for hardware flow control and the like. This should be set to + * VMIN. + */ + mr2 |= MR2_RXFIFOHALF; + +/* + * Calculate the baud rate timers. For now we will just assume that + * the input and output baud are the same. The sc26198 has a fixed + * baud rate table, so only discrete baud rates possible. + */ + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + baudrate = stl_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (portp->baud_base / portp->custom_divisor); + } + if (baudrate > STL_SC26198MAXBAUD) + baudrate = STL_SC26198MAXBAUD; + + if (baudrate > 0) { + for (clk = 0; (clk < SC26198_NRBAUDS); clk++) { + if (baudrate <= sc26198_baudtable[clk]) + break; + } + } + +/* + * Check what form of modem signaling is required and set it up. + */ + if (tiosp->c_cflag & CLOCAL) { + portp->flags &= ~ASYNC_CHECK_CD; + } else { + iopr |= IOPR_DCDCOS; + imron |= IR_IOPORT; + portp->flags |= ASYNC_CHECK_CD; + } + +/* + * Setup sc26198 enhanced modes if we can. In particular we want to + * handle as much of the flow control as possible automatically. As + * well as saving a few CPU cycles it will also greatly improve flow + * control reliability. + */ + if (tiosp->c_iflag & IXON) { + mr0 |= MR0_SWFTX | MR0_SWFT; + imron |= IR_XONXOFF; + } else { + imroff |= IR_XONXOFF; + } + if (tiosp->c_iflag & IXOFF) + mr0 |= MR0_SWFRX; + + if (tiosp->c_cflag & CRTSCTS) { + mr2 |= MR2_AUTOCTS; + mr1 |= MR1_AUTORTS; + } + +/* + * All sc26198 register values calculated so go through and set + * them all up. + */ + +#if DEBUG + printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", + portp->portnr, portp->panelnr, portp->brdnr); + printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); + printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); + printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], + tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IMR, 0); + stl_sc26198updatereg(portp, MR0, mr0); + stl_sc26198updatereg(portp, MR1, mr1); + stl_sc26198setreg(portp, SCCR, CR_RXERRBLOCK); + stl_sc26198updatereg(portp, MR2, mr2); + stl_sc26198updatereg(portp, IOPIOR, + ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr)); + + if (baudrate > 0) { + stl_sc26198setreg(portp, TXCSR, clk); + stl_sc26198setreg(portp, RXCSR, clk); + } + + stl_sc26198setreg(portp, XONCR, tiosp->c_cc[VSTART]); + stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]); + + ipr = stl_sc26198getreg(portp, IPR); + if (ipr & IPR_DCD) + portp->sigs &= ~TIOCM_CD; + else + portp->sigs |= TIOCM_CD; + + portp->imr = (portp->imr & ~imroff) | imron; + stl_sc26198setreg(portp, IMR, portp->imr); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Set the state of the DTR and RTS signals. + */ + +static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) +{ + unsigned char iopioron, iopioroff; + unsigned long flags; + +#if DEBUG + printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", + (int) portp, dtr, rts); +#endif + + iopioron = 0; + iopioroff = 0; + if (dtr == 0) + iopioroff |= IPR_DTR; + else if (dtr > 0) + iopioron |= IPR_DTR; + if (rts == 0) + iopioroff |= IPR_RTS; + else if (rts > 0) + iopioron |= IPR_RTS; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IOPIOR, + ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the state of the signals. + */ + +static int stl_sc26198getsignals(stlport_t *portp) +{ + unsigned char ipr; + unsigned long flags; + int sigs; + +#if DEBUG + printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + ipr = stl_sc26198getreg(portp, IPR); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + sigs = 0; + sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; + sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS; + sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR; + sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS; + sigs |= TIOCM_DSR; + return(sigs); +} + +/*****************************************************************************/ + +/* + * Enable/Disable the Transmitter and/or Receiver. + */ + +static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char ccr; + unsigned long flags; + +#if DEBUG + printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + + ccr = portp->crenable; + if (tx == 0) + ccr &= ~CR_TXENABLE; + else if (tx > 0) + ccr |= CR_TXENABLE; + if (rx == 0) + ccr &= ~CR_RXENABLE; + else if (rx > 0) + ccr |= CR_RXENABLE; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, ccr); + BRDDISABLE(portp->brdnr); + portp->crenable = ccr; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Start/stop the Transmitter and/or Receiver. + */ + +static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char imr; + unsigned long flags; + +#if DEBUG + printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", + (int) portp, rx, tx); +#endif + + imr = portp->imr; + if (tx == 0) + imr &= ~IR_TXRDY; + else if (tx == 1) + imr |= IR_TXRDY; + if (rx == 0) + imr &= ~(IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG); + else if (rx > 0) + imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IMR, imr); + BRDDISABLE(portp->brdnr); + portp->imr = imr; + if (tx > 0) + set_bit(ASYI_TXBUSY, &portp->istate); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Disable all interrupts from this port. + */ + +static void stl_sc26198disableintrs(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + portp->imr = 0; + stl_sc26198setreg(portp, IMR, 0); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_sc26198sendbreak(stlport_t *portp, int len) +{ + unsigned long flags; + +#if DEBUG + printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + if (len == 1) { + stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); + portp->stats.txbreaks++; + } else { + stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); + } + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Take flow control actions... + */ + +static void stl_sc26198flowctrl(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + unsigned char mr0; + +#if DEBUG + printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + + if (state) { + if (tty->termios->c_iflag & IXOFF) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); + mr0 |= MR0_SWFRX; + portp->stats.rxxon++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } +/* + * Question: should we return RTS to what it was before? It may + * have been set by an ioctl... Suppose not, since if you have + * hardware flow control set then it is pretty silly to go and + * set the RTS line by hand. + */ + if (tty->termios->c_cflag & CRTSCTS) { + stl_sc26198setreg(portp, MR1, + (stl_sc26198getreg(portp, MR1) | MR1_AUTORTS)); + stl_sc26198setreg(portp, IOPIOR, + (stl_sc26198getreg(portp, IOPIOR) | IOPR_RTS)); + portp->stats.rxrtson++; + } + } else { + if (tty->termios->c_iflag & IXOFF) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); + mr0 &= ~MR0_SWFRX; + portp->stats.rxxoff++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } + if (tty->termios->c_cflag & CRTSCTS) { + stl_sc26198setreg(portp, MR1, + (stl_sc26198getreg(portp, MR1) & ~MR1_AUTORTS)); + stl_sc26198setreg(portp, IOPIOR, + (stl_sc26198getreg(portp, IOPIOR) & ~IOPR_RTS)); + portp->stats.rxrtsoff++; + } + } + + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Send a flow control character. + */ + +static void stl_sc26198sendflow(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + unsigned char mr0; + +#if DEBUG + printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state); +#endif + + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + if (state) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); + mr0 |= MR0_SWFRX; + portp->stats.rxxon++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } else { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); + mr0 &= ~MR0_SWFRX; + portp->stats.rxxoff++; + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + } + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_sc26198flush(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_sc26198flush(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, CR_TXRESET); + stl_sc26198setreg(portp, SCCR, portp->crenable); + BRDDISABLE(portp->brdnr); + portp->tx.tail = portp->tx.head; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the current state of data flow on this port. This is only + * really interresting when determining if data has fully completed + * transmission or not... The sc26198 interrupt scheme cannot + * determine when all data has actually drained, so we need to + * check the port statusy register to be sure. + */ + +static int stl_sc26198datastate(stlport_t *portp) +{ + unsigned long flags; + unsigned char sr; + +#if DEBUG + printk("stl_sc26198datastate(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return(0); + if (test_bit(ASYI_TXBUSY, &portp->istate)) + return(1); + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + sr = stl_sc26198getreg(portp, SR); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + return((sr & SR_TXEMPTY) ? 0 : 1); +} + +/*****************************************************************************/ + +/* + * Delay for a small amount of time, to give the sc26198 a chance + * to process a command... + */ + +static void stl_sc26198wait(stlport_t *portp) +{ + int i; + +#if DEBUG + printk("stl_sc26198wait(portp=%x)\n", (int) portp); +#endif + + if (portp == (stlport_t *) NULL) + return; + + for (i = 0; (i < 20); i++) + stl_sc26198getglobreg(portp, TSTR); +} + +/*****************************************************************************/ + +/* + * If we are TX flow controlled and in IXANY mode then we may + * need to unflow control here. We gotta do this because of the + * automatic flow control modes of the sc26198. + */ + +static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) +{ + unsigned char mr0; + + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_HOSTXON); + stl_sc26198wait(portp); + stl_sc26198setreg(portp, MR0, mr0); + clear_bit(ASYI_TXFLOWED, &portp->istate); +} + +/*****************************************************************************/ + +/* + * Interrupt service routine for sc26198 panels. + */ + +static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) +{ + stlport_t *portp; + unsigned int iack; + +/* + * Work around bug in sc26198 chip... Cannot have A6 address + * line of UART high, else iack will be returned as 0. + */ + outb(0, (iobase + 1)); + + iack = inb(iobase + XP_IACK); + portp = panelp->ports[(iack & IVR_CHANMASK) + ((iobase & 0x4) << 1)]; + + if (iack & IVR_RXDATA) + stl_sc26198rxisr(portp, iack); + else if (iack & IVR_TXDATA) + stl_sc26198txisr(portp); + else + stl_sc26198otherisr(portp, iack); +} + +/*****************************************************************************/ + +/* + * Transmit interrupt handler. This has gotta be fast! Handling TX + * chars is pretty simple, stuff as many as possible from the TX buffer + * into the sc26198 FIFO. + * In practice it is possible that interrupts are enabled but that the + * port has been hung up. Need to handle not having any TX buffer here, + * this is done by using the side effect that head and tail will also + * be NULL if the buffer has been freed. + */ + +static void stl_sc26198txisr(stlport_t *portp) +{ + unsigned int ioaddr; + unsigned char mr0; + int len, stlen; + char *head, *tail; + +#if DEBUG + printk("stl_sc26198txisr(portp=%x)\n", (int) portp); +#endif + + ioaddr = portp->ioaddr; + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((len == 0) || ((len < STL_TXBUFLOW) && + (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { + set_bit(ASYI_TXLOW, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + } + + if (len == 0) { + outb((MR0 | portp->uartaddr), (ioaddr + XP_ADDR)); + mr0 = inb(ioaddr + XP_DATA); + if ((mr0 & MR0_TXMASK) == MR0_TXEMPTY) { + portp->imr &= ~IR_TXRDY; + outb((IMR | portp->uartaddr), (ioaddr + XP_ADDR)); + outb(portp->imr, (ioaddr + XP_DATA)); + clear_bit(ASYI_TXBUSY, &portp->istate); + } else { + mr0 |= ((mr0 & ~MR0_TXMASK) | MR0_TXEMPTY); + outb(mr0, (ioaddr + XP_DATA)); + } + } else { + len = MIN(len, SC26198_TXFIFOSIZE); + portp->stats.txtotal += len; + stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + outb(GTXFIFO, (ioaddr + XP_ADDR)); + outsb((ioaddr + XP_DATA), tail, stlen); + len -= stlen; + tail += stlen; + if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) + tail = portp->tx.buf; + if (len > 0) { + outsb((ioaddr + XP_DATA), tail, len); + tail += len; + } + portp->tx.tail = tail; + } +} + +/*****************************************************************************/ + +/* + * Receive character interrupt handler. Determine if we have good chars + * or bad chars and then process appropriately. Good chars are easy + * just shove the lot into the RX buffer and set all status byte to 0. + * If a bad RX char then process as required. This routine needs to be + * fast! In practice it is possible that we get an interrupt on a port + * that is closed. This can happen on hangups - since they completely + * shutdown a port not in user context. Need to handle this case. + */ + +static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) +{ + struct tty_struct *tty; + unsigned int len, buflen, ioaddr; + +#if DEBUG + printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack); +#endif + + tty = portp->tty; + ioaddr = portp->ioaddr; + outb(GIBCR, (ioaddr + XP_ADDR)); + len = inb(ioaddr + XP_DATA) + 1; + + if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { + if ((tty == (struct tty_struct *) NULL) || + (tty->flip.char_buf_ptr == (char *) NULL) || + ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + len = MIN(len, sizeof(stl_unwanted)); + outb(GRXFIFO, (ioaddr + XP_ADDR)); + insb((ioaddr + XP_DATA), &stl_unwanted[0], len); + portp->stats.rxlost += len; + portp->stats.rxtotal += len; + } else { + len = MIN(len, buflen); + if (len > 0) { + outb(GRXFIFO, (ioaddr + XP_ADDR)); + insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + tty->flip.char_buf_ptr += len; + tty->flip.count += len; + tty_schedule_flip(tty); + portp->stats.rxtotal += len; + } + } + } else { + stl_sc26198rxbadchars(portp); + } + +/* + * If we are TX flow controlled and in IXANY mode then we may need + * to unflow control here. We gotta do this because of the automatic + * flow control modes of the sc26198. + */ + if (test_bit(ASYI_TXFLOWED, &portp->istate)) { + if ((tty != (struct tty_struct *) NULL) && + (tty->termios != (struct termios *) NULL) && + (tty->termios->c_iflag & IXANY)) { + stl_sc26198txunflow(portp, tty); + } + } +} + +/*****************************************************************************/ + +/* + * Process an RX bad character. + */ + +static void inline stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) +{ + struct tty_struct *tty; + unsigned int ioaddr; + + tty = portp->tty; + ioaddr = portp->ioaddr; + + if (status & SR_RXPARITY) + portp->stats.rxparity++; + if (status & SR_RXFRAMING) + portp->stats.rxframing++; + if (status & SR_RXOVERRUN) + portp->stats.rxoverrun++; + if (status & SR_RXBREAK) + portp->stats.rxbreaks++; + + if ((tty != (struct tty_struct *) NULL) && + ((portp->rxignoremsk & status) == 0)) { + if (portp->rxmarkmsk & status) { + if (status & SR_RXBREAK) { + status = TTY_BREAK; + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + BRDENABLE(portp->brdnr, portp->pagenr); + } + } else if (status & SR_RXPARITY) { + status = TTY_PARITY; + } else if (status & SR_RXFRAMING) { + status = TTY_FRAME; + } else if(status & SR_RXOVERRUN) { + status = TTY_OVERRUN; + } else { + status = 0; + } + } else { + status = 0; + } + + if (tty->flip.char_buf_ptr != (char *) NULL) { + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.flag_buf_ptr++ = status; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + } + tty_schedule_flip(tty); + } + + if (status == 0) + portp->stats.rxtotal++; + } +} + +/*****************************************************************************/ + +/* + * Process all characters in the RX FIFO of the UART. Check all char + * status bytes as well, and process as required. We need to check + * all bytes in the FIFO, in case some more enter the FIFO while we + * are here. To get the exact character error type we need to switch + * into CHAR error mode (that is why we need to make sure we empty + * the FIFO). + */ + +static void stl_sc26198rxbadchars(stlport_t *portp) +{ + unsigned char status, mr1; + char ch; + +/* + * To get the precise error type for each character we must switch + * back into CHAR error mode. + */ + mr1 = stl_sc26198getreg(portp, MR1); + stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK)); + + while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) { + stl_sc26198setreg(portp, SCCR, CR_CLEARRXERR); + ch = stl_sc26198getreg(portp, RXFIFO); + stl_sc26198rxbadch(portp, status, ch); + } + +/* + * To get correct interrupt class we must switch back into BLOCK + * error mode. + */ + stl_sc26198setreg(portp, MR1, mr1); +} + +/*****************************************************************************/ + +/* + * Other interrupt handler. This includes modem signals, flow + * control actions, etc. Most stuff is left to off-level interrupt + * processing time. + */ + +static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) +{ + unsigned char cir, ipr, xisr; + +#if DEBUG + printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack); +#endif + + cir = stl_sc26198getglobreg(portp, CIR); + + switch (cir & CIR_SUBTYPEMASK) { + case CIR_SUBCOS: + ipr = stl_sc26198getreg(portp, IPR); + if (ipr & IPR_DCDCHANGE) { + set_bit(ASYI_DCDCHANGE, &portp->istate); + queue_task(&portp->tqueue, &tq_scheduler); + portp->stats.modem++; + } + break; + case CIR_SUBXONXOFF: + xisr = stl_sc26198getreg(portp, XISR); + if (xisr & XISR_RXXONGOT) { + set_bit(ASYI_TXFLOWED, &portp->istate); + portp->stats.txxoff++; + } + if (xisr & XISR_RXXOFFGOT) { + clear_bit(ASYI_TXFLOWED, &portp->istate); + portp->stats.txxon++; + } + break; + case CIR_SUBBREAK: + stl_sc26198setreg(portp, SCCR, CR_BREAKRESET); + stl_sc26198rxbadchars(portp); + break; + default: + break; + } +} + +/*****************************************************************************/ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c --- v2.4.0-test6/linux/drivers/media/video/stradis.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/stradis.c Wed Jul 5 10:56:13 2000 @@ -0,0 +1,2287 @@ +/* + * stradis.c - stradis 4:2:2 mpeg decoder driver + * + * Stradis 4:2:2 MPEG-2 Decoder Driver + * Copyright (C) 1999 Nathan Laredo + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "saa7146.h" +#include "saa7146reg.h" +#include "ibmmpeg2.h" +#include "saa7121.h" +#include "cs8420.h" + +#define DEBUG(x) /* debug driver */ +#undef IDEBUG(x) /* debug irq handler */ +#undef MDEBUG(x) /* debug memory management */ + +#define SAA7146_MAX 6 + +static struct saa7146 saa7146s[SAA7146_MAX]; + +static int saa_num = 0; /* number of SAA7146s in use */ + +#define nDebNormal 0x00480000 +#define nDebNoInc 0x00480000 +#define nDebVideo 0xd0480000 +#define nDebAudio 0xd0400000 +#define nDebDMA 0x02c80000 + +#define oDebNormal 0x13c80000 +#define oDebNoInc 0x13c80000 +#define oDebVideo 0xd1080000 +#define oDebAudio 0xd1080000 +#define oDebDMA 0x03080000 + +#define NewCard (saa->boardcfg[3]) +#define ChipControl (saa->boardcfg[1]) +#define NTSCFirstActive (saa->boardcfg[4]) +#define PALFirstActive (saa->boardcfg[5]) +#define NTSCLastActive (saa->boardcfg[54]) +#define PALLastActive (saa->boardcfg[55]) +#define Have2MB (saa->boardcfg[18] & 0x40) +#define HaveCS8420 (saa->boardcfg[18] & 0x04) +#define IBMMPEGCD20 (saa->boardcfg[18] & 0x20) +#define HaveCS3310 (saa->boardcfg[18] & 0x01) +#define CS3310MaxLvl ((saa->boardcfg[30] << 8) | saa->boardcfg[31]) +#define HaveCS4341 (saa->boardcfg[40] == 2) +#define SDIType (saa->boardcfg[27]) +#define CurrentMode (saa->boardcfg[2]) + +#define debNormal (NewCard ? nDebNormal : oDebNormal) +#define debNoInc (NewCard ? nDebNoInc : oDebNoInc) +#define debVideo (NewCard ? nDebVideo : oDebVideo) +#define debAudio (NewCard ? nDebAudio : oDebAudio) +#define debDMA (NewCard ? nDebDMA : oDebDMA) + +#ifdef DEBUG +int stradis_driver(void) /* for the benefit of ksymoops */ +{ + return 1; +} +#endif + +#ifdef USE_RESCUE_EEPROM_SDM275 +static unsigned char rescue_eeprom[64] = { +0x00,0x01,0x04,0x13,0x26,0x0f,0x10,0x00,0x00,0x00,0x43,0x63,0x22,0x01,0x29,0x15,0x73,0x00,0x1f, 'd', 'e', 'c', 'x', 'l', 'd', 'v', 'a',0x02,0x00,0x01,0x00,0xcc,0xa4,0x63,0x09,0xe2,0x10,0x00,0x0a,0x00,0x02,0x02, 'd', 'e', 'c', 'x', 'l', 'a',0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +#endif + +/* ----------------------------------------------------------------------- */ +/* Hardware I2C functions */ +static void I2CWipe(struct saa7146 *saa) +{ + int i; + /* set i2c to ~=100kHz, abort transfer, clear busy */ + saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS); + saawrite((SAA7146_MC2_UPLD_I2C << 16) | + SAA7146_MC2_UPLD_I2C, SAA7146_MC2); + /* wait for i2c registers to be programmed */ + for (i = 0; i < 1000 && + !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) + schedule(); + saawrite(0x600, SAA7146_I2C_STATUS); + saawrite((SAA7146_MC2_UPLD_I2C << 16) | + SAA7146_MC2_UPLD_I2C, SAA7146_MC2); + /* wait for i2c registers to be programmed */ + for (i = 0; i < 1000 && + !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) + schedule(); + saawrite(0x600, SAA7146_I2C_STATUS); + saawrite((SAA7146_MC2_UPLD_I2C << 16) | + SAA7146_MC2_UPLD_I2C, SAA7146_MC2); + /* wait for i2c registers to be programmed */ + for (i = 0; i < 1000 && + !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) + schedule(); +} +/* read I2C */ +static int I2CRead(struct i2c_bus *bus, unsigned char addr, + unsigned char subaddr, int dosub) +{ + struct saa7146 *saa = (struct saa7146 *) bus->data; + int i; + + + if (saaread(SAA7146_I2C_STATUS) & 0x3c) + I2CWipe(saa); + for (i = 0; i < 1000 && + (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++) + schedule(); + if (i == 1000) + I2CWipe(saa); + if (dosub) + saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) | + ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER); + else + saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) | + 0xf1, SAA7146_I2C_TRANSFER); + saawrite((SAA7146_MC2_UPLD_I2C << 16) | + SAA7146_MC2_UPLD_I2C, SAA7146_MC2); + /* wait for i2c registers to be programmed */ + for (i = 0; i < 1000 && + !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) + schedule(); + /* wait for valid data */ + for (i = 0; i < 1000 && + (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++) + schedule(); + if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR) + return -1; + if (i == 1000) + printk("i2c setup read timeout\n"); + saawrite(0x41, SAA7146_I2C_TRANSFER); + saawrite((SAA7146_MC2_UPLD_I2C << 16) | + SAA7146_MC2_UPLD_I2C, SAA7146_MC2); + /* wait for i2c registers to be programmed */ + for (i = 0; i < 1000 && + !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++) + schedule(); + /* wait for valid data */ + for (i = 0; i < 1000 && + (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++) + schedule(); + if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR) + return -1; + if (i == 1000) + printk("i2c read timeout\n"); + return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff); +} +static int I2CReadOld(struct i2c_bus *bus, unsigned char addr) +{ + return I2CRead(bus, addr, 0, 0); +} + +/* set both to write both bytes, reset it to write only b1 */ + +static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1, + unsigned char b2, int both) +{ + struct saa7146 *saa = (struct saa7146 *) bus->data; + int i; + u32 data; + + if (saaread(SAA7146_I2C_STATUS) & 0x3c) + I2CWipe(saa); + for (i = 0; i < 1000 && + (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++) + schedule(); + if (i == 1000) + I2CWipe(saa); + data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16); + if (both) + data |= ((b2 & 0xff) << 8) | 0xe5; + else + data |= 0xd1; + saawrite(data, SAA7146_I2C_TRANSFER); + saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C, + SAA7146_MC2); + return 0; +} + +static void attach_inform(struct i2c_bus *bus, int id) +{ + struct saa7146 *saa = (struct saa7146 *) bus->data; + int i; + + DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr, id)); + if (id == 0xa0) { /* we have rev2 or later board, fill in info */ + for (i = 0; i < 64; i++) + saa->boardcfg[i] = I2CRead(bus, 0xa0, i, 1); +#ifdef USE_RESCUE_EEPROM_SDM275 + if (saa->boardcfg[0] != 0) { + printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE BEEN IGNORED\n", saa->nr); + for (i = 0; i < 64; i++) + saa->boardcfg[i] = rescue_eeprom[i]; + } +#endif + printk("stradis%d: config =", saa->nr); + for (i = 0; i < 51; i++) { + printk(" %02x",saa->boardcfg[i]); + } + printk("\n"); + } +} + +static void detach_inform(struct i2c_bus *bus, int id) +{ + struct saa7146 *saa = (struct saa7146 *) bus->data; + int i; + i = saa->nr; +} + +static void I2CBusScan(struct i2c_bus *bus) +{ + int i; + for (i = 0; i < 0xff; i += 2) + if ((I2CRead(bus, i, 0, 0)) >= 0) + attach_inform(bus, i); +} + +static struct i2c_bus saa7146_i2c_bus_template = +{ + "saa7146", + I2C_BUSID_BT848, + NULL, + SPIN_LOCK_UNLOCKED, + attach_inform, + detach_inform, + NULL, + NULL, + I2CReadOld, + I2CWrite, +}; + +static int debiwait_maxwait = 0; + +static int wait_for_debi_done(struct saa7146 *saa) +{ + int i; + + /* wait for registers to be programmed */ + for (i = 0; i < 100000 && + !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++) + saaread(SAA7146_MC2); + /* wait for transfer to complete */ + for (i = 0; i < 500000 && + (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++) + saaread(SAA7146_MC2); + if (i > debiwait_maxwait) + printk("wait-for-debi-done maxwait: %d\n", + debiwait_maxwait = i); + + if (i == 500000) + return -1; + return 0; +} + +static int debiwrite(struct saa7146 *saa, u32 config, int addr, + u32 val, int count) +{ + u32 cmd; + if (count <= 0 || count > 32764) + return -1; + if (wait_for_debi_done(saa) < 0) + return -1; + saawrite(config, SAA7146_DEBI_CONFIG); + if (count <= 4) /* immediate transfer */ + saawrite(val, SAA7146_DEBI_AD); + else /* block transfer */ + saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD); + saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND); + saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI, + SAA7146_MC2); + return 0; +} + +static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count) +{ + u32 result = 0; + + if (count > 32764 || count <= 0) + return 0; + if (wait_for_debi_done(saa) < 0) + return 0; + saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD); + saawrite((count << 17) | 0x10000 | (addr & 0xffff), + SAA7146_DEBI_COMMAND); + saawrite(config, SAA7146_DEBI_CONFIG); + saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI, + SAA7146_MC2); + if (count > 4) /* not an immediate transfer */ + return count; + wait_for_debi_done(saa); + result = saaread(SAA7146_DEBI_AD); + if (count == 1) + result &= 0xff; + if (count == 2) + result &= 0xffff; + if (count == 3) + result &= 0xffffff; + return result; +} + +#if 0 /* unused */ +/* MUST be a multiple of 8 bytes and 8-byte aligned and < 32768 bytes */ +/* data copied into saa->dmadebi buffer, caller must re-enable interrupts */ +static void ibm_block_dram_read(struct saa7146 *saa, int address, int bytes) +{ + int i, j; + u32 *buf; + buf = (u32 *) saa->dmadebi; + if (bytes > 0x7000) + bytes = 0x7000; + saawrite(0, SAA7146_IER); /* disable interrupts */ + for (i=0; i < 10000 && + (debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2) + & 0x8000); i++) + saaread(SAA7146_MC2); + if (i == 10000) + printk(KERN_ERR "stradis%d: dram_busy never cleared\n", + saa->nr); + debiwrite(saa, debNormal, IBM_MP2_SRC_ADDR, (address<<16) | + (address>>16), 4); + debiwrite(saa, debNormal, IBM_MP2_BLOCK_SIZE, bytes, 2); + debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 0x8a10, 2); + for (j = 0; j < bytes/4; j++) { + for (i = 0; i < 10000 && + (!(debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2) + & 0x4000)); i++) + saaread(SAA7146_MC2); + if (i == 10000) + printk(KERN_ERR "stradis%d: dram_ready never set\n", + saa->nr); + buf[j] = debiread(saa, debNormal, IBM_MP2_DRAM_DATA, 4); + } +} +#endif /* unused */ + +static void do_irq_send_data(struct saa7146 *saa) +{ + int split, audbytes, vidbytes; + + saawrite(SAA7146_PSR_PIN1, SAA7146_IER); + /* if special feature mode in effect, disable audio sending */ + if (saa->playmode != VID_PLAY_NORMAL) + saa->audtail = saa->audhead = 0; + if (saa->audhead <= saa->audtail) + audbytes = saa->audtail - saa->audhead; + else + audbytes = 65536 - (saa->audhead - saa->audtail); + if (saa->vidhead <= saa->vidtail) + vidbytes = saa->vidtail - saa->vidhead; + else + vidbytes = 524288 - (saa->vidhead - saa->vidtail); + if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) { + saawrite(0, SAA7146_IER); + return; + } + /* if at least 1 block audio waiting and audio fifo isn't full */ + if (audbytes >= 2048 && (debiread(saa, debNormal, + IBM_MP2_AUD_FIFO, 2) & 0xff) < 60) { + if (saa->audhead > saa->audtail) + split = 65536 - saa->audhead; + else + split = 0; + audbytes = 2048; + if (split > 0 && split < 2048) { + memcpy(saa->dmadebi, saa->audbuf + saa->audhead, + split); + saa->audhead = 0; + audbytes -= split; + } else + split = 0; + memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead, + audbytes); + saa->audhead += audbytes; + saa->audhead &= 0xffff; + debiwrite(saa, debAudio, (NewCard? IBM_MP2_AUD_FIFO : + IBM_MP2_AUD_FIFOW), 0, 2048); + wake_up_interruptible(&saa->audq); + /* if at least 1 block video waiting and video fifo isn't full */ + } else if (vidbytes >= 30720 && (debiread(saa, debNormal, + IBM_MP2_FIFO, 2)) < 16384) { + if (saa->vidhead > saa->vidtail) + split = 524288 - saa->vidhead; + else + split = 0; + vidbytes = 30720; + if (split > 0 && split < 30720) { + memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, + split); + saa->vidhead = 0; + vidbytes -= split; + } else + split = 0; + memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead, + vidbytes); + saa->vidhead += vidbytes; + saa->vidhead &= 0x7ffff; + debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO : + IBM_MP2_FIFOW), 0, 30720); + wake_up_interruptible(&saa->vidq); + } + saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER); +} + +static void send_osd_data(struct saa7146 *saa) +{ + int size = saa->osdtail - saa->osdhead; + if (size > 30720) + size = 30720; + /* ensure some multiple of 8 bytes is transferred */ + size = 8 * ((size + 8)>>3); + if (size) { + debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, + (saa->osdhead>>3), 2); + memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size); + saa->osdhead += size; + /* block transfer of next 8 bytes to ~32k bytes */ + debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size); + } + if (saa->osdhead >= saa->osdtail) { + saa->osdhead = saa->osdtail = 0; + debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2); + } +} + +static void saa7146_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct saa7146 *saa = (struct saa7146 *) dev_id; + u32 stat, astat; + int count; + + count = 0; + while (1) { + /* get/clear interrupt status bits */ + stat = saaread(SAA7146_ISR); + astat = stat & saaread(SAA7146_IER); + if (!astat) + return; + saawrite(astat, SAA7146_ISR); + if (astat & SAA7146_PSR_DEBI_S) { + do_irq_send_data(saa); + } + if (astat & SAA7146_PSR_PIN1) { + int istat; + /* the following read will trigger DEBI_S */ + istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2); + if (istat & 1) { + saawrite(0, SAA7146_IER); + send_osd_data(saa); + saawrite(SAA7146_PSR_DEBI_S | + SAA7146_PSR_PIN1, SAA7146_IER); + } + if (istat & 0x20) { /* Video Start */ + saa->vidinfo.frame_count++; + } + if (istat & 0x400) { /* Picture Start */ + /* update temporal reference */ + } + if (istat & 0x200) { /* Picture Resolution Change */ + /* read new resolution */ + } + if (istat & 0x100) { /* New User Data found */ + /* read new user data */ + } + if (istat & 0x1000) { /* new GOP/SMPTE */ + /* read new SMPTE */ + } + if (istat & 0x8000) { /* Sequence Start Code */ + /* reset frame counter, load sizes */ + saa->vidinfo.frame_count = 0; + saa->vidinfo.h_size = 704; + saa->vidinfo.v_size = 480; +#if 0 + if (saa->endmarkhead != saa->endmarktail) { + saa->audhead = + saa->endmark[saa->endmarkhead]; + saa->endmarkhead++; + if (saa->endmarkhead >= MAX_MARKS) + saa->endmarkhead = 0; + } +#endif + } + if (istat & 0x4000) { /* Sequence Error Code */ + if (saa->endmarkhead != saa->endmarktail) { + saa->audhead = + saa->endmark[saa->endmarkhead]; + saa->endmarkhead++; + if (saa->endmarkhead >= MAX_MARKS) + saa->endmarkhead = 0; + } + } + } +#ifdef IDEBUG + if (astat & SAA7146_PSR_PPEF) { + IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr)); + } + if (astat & SAA7146_PSR_PABO) { + IDEBUG(printk("stradis%d irq: PABO\n", saa->nr)); + } + if (astat & SAA7146_PSR_PPED) { + IDEBUG(printk("stradis%d irq: PPED\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_I1) { + IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_I0) { + IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_LATE1) { + IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_LATE0) { + IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_E1) { + IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_E0) { + IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_TO1) { + IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr)); + } + if (astat & SAA7146_PSR_RPS_TO0) { + IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr)); + } + if (astat & SAA7146_PSR_UPLD) { + IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr)); + } + if (astat & SAA7146_PSR_DEBI_E) { + IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr)); + } + if (astat & SAA7146_PSR_I2C_S) { + IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr)); + } + if (astat & SAA7146_PSR_I2C_E) { + IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr)); + } + if (astat & SAA7146_PSR_A2_IN) { + IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr)); + } + if (astat & SAA7146_PSR_A2_OUT) { + IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr)); + } + if (astat & SAA7146_PSR_A1_IN) { + IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr)); + } + if (astat & SAA7146_PSR_A1_OUT) { + IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr)); + } + if (astat & SAA7146_PSR_AFOU) { + IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr)); + } + if (astat & SAA7146_PSR_V_PE) { + IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr)); + } + if (astat & SAA7146_PSR_VFOU) { + IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr)); + } + if (astat & SAA7146_PSR_FIDA) { + IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr)); + } + if (astat & SAA7146_PSR_FIDB) { + IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr)); + } + if (astat & SAA7146_PSR_PIN3) { + IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr)); + } + if (astat & SAA7146_PSR_PIN2) { + IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr)); + } + if (astat & SAA7146_PSR_PIN0) { + IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr)); + } + if (astat & SAA7146_PSR_ECS) { + IDEBUG(printk("stradis%d irq: ECS\n", saa->nr)); + } + if (astat & SAA7146_PSR_EC3S) { + IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr)); + } + if (astat & SAA7146_PSR_EC0S) { + IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr)); + } +#endif + count++; + if (count > 15) + printk(KERN_WARNING "stradis%d: irq loop %d\n", + saa->nr, count); + if (count > 20) { + saawrite(0, SAA7146_IER); + printk(KERN_ERR + "stradis%d: IRQ loop cleared\n", saa->nr); + } + } +} + +static int ibm_send_command(struct saa7146 *saa, + int command, int data, int chain) +{ + int i; + + if (chain) + debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1) | 1, 2); + else + debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2); + debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2); + debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2); + for (i = 0; i < 100 && + (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++) + schedule(); + if (i == 100) + return -1; + return 0; +} + +static void cs4341_setlevel(struct saa7146 *saa, int left, int right) +{ + I2CWrite(&(saa->i2c), 0x22, 0x03, + left > 94 ? 94 : left, 2); + I2CWrite(&(saa->i2c), 0x22, 0x04, + right > 94 ? 94 : right, 2); +} + +static void initialize_cs4341(struct saa7146 *saa) +{ + int i; + for (i = 0; i < 200; i++) { + /* auto mute off, power on, no de-emphasis */ + /* I2S data up to 24-bit 64xFs internal SCLK */ + I2CWrite(&(saa->i2c), 0x22, 0x01, 0x11, 2); + /* ATAPI mixer setings */ + I2CWrite(&(saa->i2c), 0x22, 0x02, 0x49, 2); + /* attenuation left 3db */ + I2CWrite(&(saa->i2c), 0x22, 0x03, 0x00, 2); + /* attenuation right 3db */ + I2CWrite(&(saa->i2c), 0x22, 0x04, 0x00, 2); + I2CWrite(&(saa->i2c), 0x22, 0x01, 0x10, 2); + if (I2CRead(&(saa->i2c), 0x22, 0x02, 1) == 0x49) + break; + schedule(); + } + printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i); + return; +} + +static void initialize_cs8420(struct saa7146 *saa, int pro) +{ + int i; + u8 *sequence; + if (pro) + sequence = mode8420pro; + else + sequence = mode8420con; + for (i = 0; i < INIT8420LEN; i++) + I2CWrite(&(saa->i2c), 0x20, init8420[i * 2], + init8420[i * 2 + 1], 2); + for (i = 0; i < MODE8420LEN; i++) + I2CWrite(&(saa->i2c), 0x20, sequence[i * 2], + sequence[i * 2 + 1], 2); + printk("stradis%d: CS8420 initialized\n", saa->nr); +} + +static void initialize_saa7121(struct saa7146 *saa, int dopal) +{ + int i, mod; + u8 *sequence; + if (dopal) + sequence = init7121pal; + else + sequence = init7121ntsc; + mod = saaread(SAA7146_PSR) & 0x08; + /* initialize PAL/NTSC video encoder */ + for (i = 0; i < INIT7121LEN; i++) { + if (NewCard) { /* handle new card encoder differences */ + if (sequence[i*2] == 0x3a) + I2CWrite(&(saa->i2c), 0x88, 0x3a, 0x13, 2); + else if (sequence[i*2] == 0x6b) + I2CWrite(&(saa->i2c), 0x88, 0x6b, 0x20, 2); + else if (sequence[i*2] == 0x6c) + I2CWrite(&(saa->i2c), 0x88, 0x6c, + dopal ? 0x09 : 0xf5, 2); + else if (sequence[i*2] == 0x6d) + I2CWrite(&(saa->i2c), 0x88, 0x6d, + dopal ? 0x20 : 0x00, 2); + else if (sequence[i*2] == 0x7a) + I2CWrite(&(saa->i2c), 0x88, 0x7a, + dopal ? (PALFirstActive - 1) : + (NTSCFirstActive - 4), 2); + else if (sequence[i*2] == 0x7b) + I2CWrite(&(saa->i2c), 0x88, 0x7b, + dopal ? PALLastActive : + NTSCLastActive, 2); + else I2CWrite(&(saa->i2c), 0x88, sequence[i * 2], + sequence[i * 2 + 1], 2); + } else { + if (sequence[i*2] == 0x6b && mod) + I2CWrite(&(saa->i2c), 0x88, 0x6b, + (sequence[i * 2 + 1] ^ 0x09), 2); + else if (sequence[i*2] == 0x7a) + I2CWrite(&(saa->i2c), 0x88, 0x7a, + dopal ? (PALFirstActive - 1) : + (NTSCFirstActive - 4), 2); + else if (sequence[i*2] == 0x7b) + I2CWrite(&(saa->i2c), 0x88, 0x7b, + dopal ? PALLastActive : + NTSCLastActive, 2); + else + I2CWrite(&(saa->i2c), 0x88, sequence[i * 2], + sequence[i * 2 + 1], 2); + } + } +} + +static void set_genlock_offset(struct saa7146 *saa, int noffset) +{ + int nCode; + int PixelsPerLine = 858; + if (CurrentMode == VIDEO_MODE_PAL) + PixelsPerLine = 864; + if (noffset > 500) + noffset = 500; + else if (noffset < -500) + noffset = -500; + nCode = noffset + 0x100; + if (nCode == 1) + nCode = 0x401; + else if (nCode < 1) nCode = 0x400 + PixelsPerLine + nCode; + debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2); +} + +static void set_out_format(struct saa7146 *saa, int mode) +{ + initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1)); + saa->boardcfg[2] = mode; + /* do not adjust analog video parameters here, use saa7121 init */ + /* you will affect the SDI output on the new card */ + if (mode == VIDEO_MODE_PAL) { /* PAL */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2); + mdelay(50); + saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1); + if (NewCard) { + debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, + 0xe100, 2); + mdelay(50); + } + debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, + NewCard ? 0xe500: 0x6500, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_DLY, + (1 << 8) | + (NewCard ? PALFirstActive : PALFirstActive-6), 2); + } else { /* NTSC */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2); + mdelay(50); + saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1); + debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, + NewCard ? 0xe100: 0x6100, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_DLY, + (1 << 8) | + (NewCard ? NTSCFirstActive : NTSCFirstActive-6), 2); + } +} + + +/* Intialize bitmangler to map from a byte value to the mangled word that + * must be output to program the Xilinx part through the DEBI port. + * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0 + * transfer FPGA code, init IBM chip, transfer IBM microcode + * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0 + */ +static u16 bitmangler[256]; + +static int initialize_fpga(struct video_code *bitdata) +{ + int i, num, startindex, failure = 0, loadtwo, loadfile = 0; + u16 *dmabuf; + u8 *newdma; + struct saa7146 *saa; + + /* verify fpga code */ + for (startindex = 0; startindex < bitdata->datasize; startindex++) + if (bitdata->data[startindex] == 255) + break; + if (startindex == bitdata->datasize) { + printk(KERN_INFO "stradis: bad fpga code\n"); + return -1; + } + /* initialize all detected cards */ + for (num = 0; num < saa_num; num++) { + saa = &saa7146s[num]; + if (saa->boardcfg[0] > 20) + continue; /* card was programmed */ + loadtwo = (saa->boardcfg[18] & 0x10); + if (!NewCard) /* we have an old board */ + for (i = 0; i < 256; i++) + bitmangler[i] = ((i & 0x01) << 15) | + ((i & 0x02) << 6) | ((i & 0x04) << 4) | + ((i & 0x08) << 9) | ((i & 0x10) << 7) | + ((i & 0x20) >> 3) | ((i & 0x40) >> 5) | + ((i & 0x80) >> 7); + else /* else we have a new board */ + for (i = 0; i < 256; i++) + bitmangler[i] = ((i & 0x01) << 7) | + ((i & 0x02) << 5) | ((i & 0x04) << 3) | + ((i & 0x08) << 1) | ((i & 0x10) >> 1) | + ((i & 0x20) >> 3) | ((i & 0x40) >> 5) | + ((i & 0x80) >> 7); + + dmabuf = (u16 *) saa->dmadebi; + newdma = (u8 *) saa->dmadebi; + if (NewCard) { /* SDM2xxx */ + if (!strncmp(bitdata->loadwhat, "decoder2", 8)) + continue; /* fpga not for this card */ + if (!strncmp(&saa->boardcfg[42], + bitdata->loadwhat, 8)) { + loadfile = 1; + } else if (loadtwo && !strncmp(&saa->boardcfg[19], + bitdata->loadwhat, 8)) { + loadfile = 2; + } else if (!saa->boardcfg[42] && /* special */ + !strncmp("decxl", bitdata->loadwhat, 8)) { + loadfile = 1; + } else + continue; /* fpga not for this card */ + if (loadfile != 1 && loadfile != 2) { + continue; /* skip to next card */ + } + if (saa->boardcfg[0] && loadfile == 1 ) + continue; /* skip to next card */ + if (saa->boardcfg[0] != 1 && loadfile == 2) + continue; /* skip to next card */ + saa->boardcfg[0]++; /* mark fpga handled */ + printk("stradis%d: loading %s\n", saa->nr, + bitdata->loadwhat); + if (loadtwo && loadfile == 2) + goto send_fpga_stuff; + /* turn on the Audio interface to set PROG low */ + saawrite(0x00400040, SAA7146_GPIO_CTRL); + saaread(SAA7146_PSR); /* ensure posted write */ + /* wait for everyone to reset */ + mdelay(10); + saawrite(0x00400000, SAA7146_GPIO_CTRL); + } else { /* original card */ + if (strncmp(bitdata->loadwhat, "decoder2", 8)) + continue; /* fpga not for this card */ + /* Pull the Xilinx PROG signal WS3 low */ + saawrite(0x02000200, SAA7146_MC1); + /* Turn on the Audio interface so can set PROG low */ + saawrite(0x000000c0, SAA7146_ACON1); + /* Pull the Xilinx INIT signal (GPIO2) low */ + saawrite(0x00400000, SAA7146_GPIO_CTRL); + /* Make sure everybody resets */ + saaread(SAA7146_PSR); /* ensure posted write */ + mdelay(10); + /* Release the Xilinx PROG signal */ + saawrite(0x00000000, SAA7146_ACON1); + /* Turn off the Audio interface */ + saawrite(0x02000000, SAA7146_MC1); + } + /* Release Xilinx INIT signal (WS2) */ + saawrite(0x00000000, SAA7146_GPIO_CTRL); + /* Wait for the INIT to go High */ + for (i = 0; i < 10000 && + !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++) + schedule(); + if (i == 1000) { + printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr); + return -1; + } +send_fpga_stuff: + if (NewCard) { + for (i = startindex; i < bitdata->datasize; i++) + newdma[i - startindex] = + bitmangler[bitdata->data[i]]; + debiwrite(saa, 0x01420000, 0, 0, + ((bitdata->datasize - startindex) + 5)); + if (loadtwo) { + if (loadfile == 1) { + printk("stradis%d: " + "awaiting 2nd FPGA bitfile\n", + saa->nr); + continue; /* skip to next card */ + } + + } + } else { + for (i = startindex; i < bitdata->datasize; i++) + dmabuf[i - startindex] = + bitmangler[bitdata->data[i]]; + debiwrite(saa, 0x014a0000, 0, 0, + ((bitdata->datasize - startindex) + 5) * 2); + } + for (i = 0; i < 1000 && + !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++) + schedule(); + if (i == 1000) { + printk(KERN_INFO "stradis%d: FPGA load failed\n", + saa->nr); + failure++; + continue; + } + if (!NewCard) { + /* Pull the Xilinx INIT signal (GPIO2) low */ + saawrite(0x00400000, SAA7146_GPIO_CTRL); + saaread(SAA7146_PSR); /* ensure posted write */ + mdelay(2); + saawrite(0x00000000, SAA7146_GPIO_CTRL); + mdelay(2); + } + printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr); + saa->boardcfg[0] = 26; /* mark fpga programmed */ + /* set VXCO to its lowest frequency */ + debiwrite(saa, debNormal, XILINX_PWM, 0, 2); + if (NewCard) { + /* mute CS3310 */ + if (HaveCS3310) + debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, + 0, 2); + /* set VXCO to PWM mode, release reset, blank on */ + debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2); + mdelay(10); + /* unmute CS3310 */ + if (HaveCS3310) + debiwrite(saa, debNormal, XILINX_CTL0, + 0x2020, 2); + } + /* set source Black */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2); + saa->boardcfg[4] = 22; /* set NTSC First Active Line */ + saa->boardcfg[5] = 23; /* set PAL First Active Line */ + saa->boardcfg[54] = 2; /* set NTSC Last Active Line - 256 */ + saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */ + set_out_format(saa, VIDEO_MODE_NTSC); + mdelay(50); + /* begin IBM chip init */ + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2); + saaread(SAA7146_PSR); /* wait for reset */ + mdelay(5); + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2); + debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2); + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2); + debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2); + if (NewCard) { + mdelay(5); + /* set i2s rate converter to 48KHz */ + debiwrite(saa, debNormal, 0x80c0, 6, 2); + /* we must init CS8420 first since rev b pulls i2s */ + /* master clock low and CS4341 needs i2s master to */ + /* run the i2c port. */ + if (HaveCS8420) { + /* 0=consumer, 1=pro */ + initialize_cs8420(saa, 0); + } + mdelay(5); + if (HaveCS4341) + initialize_cs4341(saa); + } + debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2); + debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2); + if (NewCard) + set_genlock_offset(saa, 0); + debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2); +#if 0 + /* enable genlock */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2); +#else + /* disable genlock */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2); +#endif + } + return failure; +} + +static int do_ibm_reset(struct saa7146 *saa) +{ + /* failure if decoder not previously programmed */ + if (saa->boardcfg[0] < 37) + return -EIO; + /* mute CS3310 */ + if (HaveCS3310) + debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2); + /* disable interrupts */ + saawrite(0, SAA7146_IER); + saa->audhead = saa->audtail = 0; + saa->vidhead = saa->vidtail = 0; + /* tristate debi bus, disable debi transfers */ + saawrite(0x00880000, SAA7146_MC1); + /* ensure posted write */ + saaread(SAA7146_MC1); + mdelay(50); + /* re-enable debi transfers */ + saawrite(0x00880088, SAA7146_MC1); + /* set source Black */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2); + /* begin IBM chip init */ + set_out_format(saa, CurrentMode); + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2); + saaread(SAA7146_PSR); /* wait for reset */ + mdelay(5); + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2); + debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2); + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2); + debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2); + if (NewCard) { + mdelay(5); + /* set i2s rate converter to 48KHz */ + debiwrite(saa, debNormal, 0x80c0, 6, 2); + /* we must init CS8420 first since rev b pulls i2s */ + /* master clock low and CS4341 needs i2s master to */ + /* run the i2c port. */ + if (HaveCS8420) { + /* 0=consumer, 1=pro */ + initialize_cs8420(saa, 1); + } + mdelay(5); + if (HaveCS4341) + initialize_cs4341(saa); + } + debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2); + debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2); + if (NewCard) + set_genlock_offset(saa, 0); + debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2); + debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2); + if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER, + (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) { + printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr); + } + if (HaveCS3310) { + int i = CS3310MaxLvl; + debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i<<8)|i), 2); + } + /* start video decoder */ + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2); + /* 256k vid, 3520 bytes aud */ + debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2); + debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2); + ibm_send_command(saa, IBM_MP2_PLAY, 0, 0); + /* enable buffer threshold irq */ + debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2); + /* clear pending interrupts */ + debiread(saa, debNormal, IBM_MP2_HOST_INT, 2); + debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2); + return 0; +} + +/* load the decoder microcode */ +static int initialize_ibmmpeg2(struct video_code *microcode) +{ + int i, num; + struct saa7146 *saa; + + for (num = 0; num < saa_num; num++) { + saa = &saa7146s[num]; + /* check that FPGA is loaded */ + debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2); + if ((i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2)) != + 0xa55a) { + printk(KERN_INFO "stradis%d: %04x != 0xa55a\n", + saa->nr, i); +#if 0 + return -1; +#endif + } + if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) { + if (saa->boardcfg[0] > 27) + continue; /* skip to next card */ + /* load video control store */ + saa->boardcfg[1] = 0x13; /* no-sync default */ + debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2); + debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2); + for (i = 0; i < microcode->datasize / 2; i++) + debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA, + (microcode->data[i * 2] << 8) | + microcode->data[i * 2 + 1], 2); + debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + saa->boardcfg[0] = 28; + } + if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) { + if (saa->boardcfg[0] > 35) + continue; /* skip to next card */ + /* load audio control store */ + debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2); + debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2); + for (i = 0; i < microcode->datasize; i++) + debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA, + microcode->data[i], 1); + debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2); + debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2); + if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER, + 0xe000, 1)) { + printk(KERN_ERR + "stradis%d: IBM config failed\n", + saa->nr); + return -1; + } + /* set PWM to center value */ + if (NewCard) { + debiwrite(saa, debNormal, XILINX_PWM, + saa->boardcfg[14] + + (saa->boardcfg[13]<<8), 2); + } else + debiwrite(saa, debNormal, XILINX_PWM, + 0x46, 2); + if (HaveCS3310) { + i = CS3310MaxLvl; + debiwrite(saa, debNormal, + XILINX_CS3310_CMPLT, ((i<<8)|i), 2); + } + printk(KERN_INFO + "stradis%d: IBM MPEGCD%d Initialized\n", + saa->nr, 18 + (debiread(saa, debNormal, + IBM_MP2_CHIP_CONTROL, 2) >> 12)); + /* start video decoder */ + debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, + 0x4037, 2); /* 256k vid, 3520 bytes aud */ + debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2); + ibm_send_command(saa, IBM_MP2_PLAY, 0, 0); + /* enable buffer threshold irq */ + debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2); + debiread(saa, debNormal, IBM_MP2_HOST_INT, 2); + /* enable gpio irq */ + saawrite(0x00002000, SAA7146_GPIO_CTRL); + /* enable decoder output to HPS */ + debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2); + saa->boardcfg[0] = 37; + } + } + return 0; +} + +static u32 palette2fmt[] = +{ /* some of these YUV translations are wrong */ + 0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000, + 0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000, + 0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000 +}; +static int bpp2fmt[4] = +{ + VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24, + VIDEO_PALETTE_RGB32 +}; + +/* I wish I could find a formula to calculate these... */ +static u32 h_prescale[64] = +{ + 0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808, + 0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460, + 0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f, + 0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000, + 0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000, + 0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000, + 0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000, + 0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000, + 0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000, + 0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000, + 0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000, +}; +static u32 v_gain[64] = +{ + 0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff, + 0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, + 0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, + 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, +}; + + +static void saa7146_set_winsize(struct saa7146 *saa) +{ + u32 format; + int offset, yacl, ysci; + saa->win.color_fmt = format = + (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] : + palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]]; + offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl; + saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1); + saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1); + saawrite(saa->win.bpl * 2, SAA7146_PITCH1); + saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight, + SAA7146_PROT_ADDR1); + saawrite(0, SAA7146_PAGE1); + saawrite(format|0x60, SAA7146_CLIP_FORMAT_CTRL); + offset = (704 / (saa->win.width - 1)) & 0x3f; + saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE); + offset = (720896 / saa->win.width) / (offset + 1); + saawrite((offset<<12)|0x0c, SAA7146_HPS_H_SCALE); + if (CurrentMode == VIDEO_MODE_NTSC) { + yacl = /*(480 / saa->win.height - 1) & 0x3f*/ 0; + ysci = 1024 - (saa->win.height * 1024 / 480); + } else { + yacl = /*(576 / saa->win.height - 1) & 0x3f*/ 0; + ysci = 1024 - (saa->win.height * 1024 / 576); + } + saawrite((1<<31)|(ysci<<21)|(yacl<<15), SAA7146_HPS_V_SCALE); + saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN); + saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V | + SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 | + SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), + SAA7146_MC2); +} + +/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area + * bitmap is fixed width, 128 bytes (1024 pixels represented) + * arranged most-sigificant-bit-left in 32-bit words + * based on saa7146 clipping hardware, it swaps bytes if LE + * much of this makes up for egcs brain damage -- so if you + * are wondering "why did he do this?" it is because the C + * was adjusted to generate the optimal asm output without + * writing non-portable __asm__ directives. + */ + +static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h) +{ + register int startword, endword; + register u32 bitsleft, bitsright; + u32 *temp; + if (x < 0) { + w += x; + x = 0; + } + if (y < 0) { + h += y; + y = 0; + } + if (w <= 0 || h <= 0 || x > 1023 || y > 639) + return; /* throw away bad clips */ + if (x + w > 1024) + w = 1024 - x; + if (y + h > 640) + h = 640 - y; + startword = (x >> 5); + endword = ((x + w) >> 5); + bitsleft = (0xffffffff >> (x & 31)); + bitsright = (0xffffffff << (~((x + w) - (endword<<5)))); + temp = &clipmap[(y<<5) + startword]; + w = endword - startword; + if (!w) { + bitsleft |= bitsright; + for (y = 0; y < h; y++) { + *temp |= bitsleft; + temp += 32; + } + } else { + for (y = 0; y < h; y++) { + *temp++ |= bitsleft; + for (x = 1; x < w; x++) + *temp++ = 0xffffffff; + *temp |= bitsright; + temp += (32 - w); + } + } +} + +static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr) +{ + int i, width, height; + u32 *clipmap; + + clipmap = saa->dmavid2; + if((width=saa->win.width)>1023) + width = 1023; /* sanity check */ + if((height=saa->win.height)>640) + height = 639; /* sanity check */ + if (ncr > 0) { /* rectangles pased */ + /* convert rectangular clips to a bitmap */ + memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ + for (i = 0; i < ncr; i++) + clip_draw_rectangle(clipmap, cr[i].x, cr[i].y, + cr[i].width, cr[i].height); + } + /* clip against viewing window AND screen + so we do not have to rely on the user program + */ + clip_draw_rectangle(clipmap,(saa->win.x+width>saa->win.swidth) ? + (saa->win.swidth-saa->win.x) : width, 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(saa->win.y+height>saa->win.sheight) ? + (saa->win.sheight-saa->win.y) : height,1024,768); + if (saa->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(saa->win.x), 768); + if (saa->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(saa->win.y)); +} + +static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct saa7146 *saa = (struct saa7146 *) dev; + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name, saa->video_dev.name); + b.type = VID_TYPE_CAPTURE | + VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | + VID_TYPE_SCALES; + b.channels = 1; + b.audios = 1; + 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 VIDIOCGPICT: + { + struct video_picture p = saa->picture; + if (saa->win.depth == 8) + p.palette = VIDEO_PALETTE_HI240; + if (saa->win.depth == 15) + p.palette = VIDEO_PALETTE_RGB555; + if (saa->win.depth == 16) + p.palette = VIDEO_PALETTE_RGB565; + if (saa->win.depth == 24) + p.palette = VIDEO_PALETTE_RGB24; + if (saa->win.depth == 32) + p.palette = VIDEO_PALETTE_RGB32; + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + u32 format; + if (copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + if (p.palette < sizeof(palette2fmt) / sizeof(u32)) { + format = palette2fmt[p.palette]; + saa->win.color_fmt = format; + saawrite(format|0x60, SAA7146_CLIP_FORMAT_CTRL); + } + saawrite(((p.brightness & 0xff00) << 16) | + ((p.contrast & 0xfe00) << 7) | + ((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL); + saa->picture = p; + /* upload changed registers */ + saawrite(((SAA7146_MC2_UPLD_HPS_H | + SAA7146_MC2_UPLD_HPS_V) << 16) | + SAA7146_MC2_UPLD_HPS_H | SAA7146_MC2_UPLD_HPS_V, + SAA7146_MC2); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp = NULL; + + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + + if (vw.flags || vw.width < 16 || vw.height < 16) { /* stop capture */ + saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1); + return -EINVAL; + } + if (saa->win.bpp < 4) { /* 32-bit align start and adjust width */ + int i = vw.x; + vw.x = (vw.x + 3) & ~3; + i = vw.x - i; + vw.width -= i; + } + saa->win.x = vw.x; + saa->win.y = vw.y; + saa->win.width = vw.width; + if (saa->win.width > 768) + saa->win.width = 768; + saa->win.height = vw.height; + if (CurrentMode == VIDEO_MODE_NTSC) { + if (saa->win.height > 480) + saa->win.height = 480; + } else { + if (saa->win.height > 576) + saa->win.height = 576; + } + + /* stop capture */ + saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1); + saa7146_set_winsize(saa); + + /* + * Do any clips. + */ + if (vw.clipcount < 0) { + if (copy_from_user(saa->dmavid2, vw.clips, + VIDEO_CLIPMAP_SIZE)) + return -EFAULT; + } else if (vw.clipcount > 0) { + if ((vcp = vmalloc(sizeof(struct video_clip) * + (vw.clipcount))) == NULL) + return -ENOMEM; + if (copy_from_user(vcp, vw.clips, + sizeof(struct video_clip) * + vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + } else /* nothing clipped */ + memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE); + make_clip_tab(saa, vcp, vw.clipcount); + if (vw.clipcount > 0) + vfree(vcp); + + /* start capture & clip dma if we have an address */ + if ((saa->cap & 3) && saa->win.vidadr != 0) + saawrite(((SAA7146_MC1_TR_E_1 | + SAA7146_MC1_TR_E_2) << 16) | 0xffff, + SAA7146_MC1); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + vw.x = saa->win.x; + vw.y = saa->win.y; + vw.width = saa->win.width; + vw.height = saa->win.height; + vw.chromakey = 0; + vw.flags = 0; + 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 (v == 0) { + saa->cap &= ~1; + saawrite((SAA7146_MC1_TR_E_1 << 16), + SAA7146_MC1); + } else { + if (saa->win.vidadr == 0 || saa->win.width == 0 + || saa->win.height == 0) + return -EINVAL; + saa->cap |= 1; + saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff, + SAA7146_MC1); + } + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + v.base = (void *) saa->win.vidadr; + v.height = saa->win.sheight; + v.width = saa->win.swidth; + v.depth = saa->win.depth; + v.bytesperline = saa->win.bpl; + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.depth != 8 && v.depth != 15 && v.depth != 16 && + v.depth != 24 && v.depth != 32 && v.width > 16 && + v.height > 16 && v.bytesperline > 16) + return -EINVAL; + if (v.base) + saa->win.vidadr = (unsigned long) v.base; + saa->win.sheight = v.height; + saa->win.swidth = v.width; + saa->win.bpp = ((v.depth + 7) & 0x38) / 8; + saa->win.depth = v.depth; + saa->win.bpl = v.bytesperline; + + DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width, v.height, saa->win.bpp, saa->win.bpl)); + saa7146_set_winsize(saa); + return 0; + } + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio v; + v = saa->audio_dev; + v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE); + v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; + strcpy(v.name, "MPEG"); + v.mode = VIDEO_SOUND_STEREO; + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + int i; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + i = (~(v.volume>>8))&0xff; + if (!HaveCS4341) { + if (v.flags & VIDEO_AUDIO_MUTE) { + debiwrite(saa, debNormal, + IBM_MP2_FRNT_ATTEN, + 0xffff, 2); + } + if (!(v.flags & VIDEO_AUDIO_MUTE)) + debiwrite(saa, debNormal, + IBM_MP2_FRNT_ATTEN, + 0x0000, 2); + if (v.flags & VIDEO_AUDIO_VOLUME) + debiwrite(saa, debNormal, + IBM_MP2_FRNT_ATTEN, + (i<<8)|i, 2); + } else { + if (v.flags & VIDEO_AUDIO_MUTE) + cs4341_setlevel(saa, 0xff, 0xff); + if (!(v.flags & VIDEO_AUDIO_MUTE)) + cs4341_setlevel(saa, 0, 0); + if (v.flags & VIDEO_AUDIO_VOLUME) + cs4341_setlevel(saa, i, i); + } + saa->audio_dev = v; + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video = saa->video_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if (copy_to_user((void *) arg, (void *) &vu, sizeof(vu))) + return -EFAULT; + return 0; + } + case VIDIOCSPLAYMODE: + { + struct video_play_mode pmode; + if (copy_from_user((void *) &pmode, arg, + sizeof(struct video_play_mode))) + return -EFAULT; + switch (pmode.mode) { + case VID_PLAY_VID_OUT_MODE: + if (pmode.p1 != VIDEO_MODE_NTSC && + pmode.p1 != VIDEO_MODE_PAL) + return -EINVAL; + set_out_format(saa, pmode.p1); + return 0; + case VID_PLAY_GENLOCK: + debiwrite(saa, debNormal, + XILINX_CTL0, + (pmode.p1 ? 0x8000 : 0x8080), + 2); + if (NewCard) + set_genlock_offset(saa, + pmode.p2); + return 0; + case VID_PLAY_NORMAL: + debiwrite(saa, debNormal, + IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + ibm_send_command(saa, + IBM_MP2_PLAY, 0, 0); + saa->playmode = pmode.mode; + return 0; + case VID_PLAY_PAUSE: + /* IBM removed the PAUSE command */ + /* they say use SINGLE_FRAME now */ + case VID_PLAY_SINGLE_FRAME: + ibm_send_command(saa, + IBM_MP2_SINGLE_FRAME, + 0, 0); + if (saa->playmode == pmode.mode) { + debiwrite(saa, debNormal, + IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + } + saa->playmode = pmode.mode; + return 0; + case VID_PLAY_FAST_FORWARD: + ibm_send_command(saa, + IBM_MP2_FAST_FORWARD, 0, 0); + saa->playmode = pmode.mode; + return 0; + case VID_PLAY_SLOW_MOTION: + ibm_send_command(saa, + IBM_MP2_SLOW_MOTION, + pmode.p1, 0); + saa->playmode = pmode.mode; + return 0; + case VID_PLAY_IMMEDIATE_NORMAL: + /* ensure transfers resume */ + debiwrite(saa, debNormal, + IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + ibm_send_command(saa, + IBM_MP2_IMED_NORM_PLAY, 0, 0); + saa->playmode = VID_PLAY_NORMAL; + return 0; + case VID_PLAY_SWITCH_CHANNELS: + saa->audhead = saa->audtail = 0; + saa->vidhead = saa->vidtail = 0; + ibm_send_command(saa, + IBM_MP2_FREEZE_FRAME, 0, 1); + ibm_send_command(saa, + IBM_MP2_RESET_AUD_RATE, 0, 1); + debiwrite(saa, debNormal, + IBM_MP2_CHIP_CONTROL, 0, 2); + ibm_send_command(saa, + IBM_MP2_CHANNEL_SWITCH, 0, 1); + debiwrite(saa, debNormal, + IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + ibm_send_command(saa, + IBM_MP2_PLAY, 0, 0); + saa->playmode = VID_PLAY_NORMAL; + return 0; + case VID_PLAY_FREEZE_FRAME: + ibm_send_command(saa, + IBM_MP2_FREEZE_FRAME, 0, 0); + saa->playmode = pmode.mode; + return 0; + case VID_PLAY_STILL_MODE: + ibm_send_command(saa, + IBM_MP2_SET_STILL_MODE, 0, 0); + saa->playmode = pmode.mode; + return 0; + case VID_PLAY_MASTER_MODE: + if (pmode.p1 == VID_PLAY_MASTER_NONE) + saa->boardcfg[1] = 0x13; + else if (pmode.p1 == + VID_PLAY_MASTER_VIDEO) + saa->boardcfg[1] = 0x23; + else if (pmode.p1 == + VID_PLAY_MASTER_AUDIO) + saa->boardcfg[1] = 0x43; + else + return -EINVAL; + debiwrite(saa, debNormal, + IBM_MP2_CHIP_CONTROL, + ChipControl, 2); + return 0; + case VID_PLAY_ACTIVE_SCANLINES: + if (CurrentMode == VIDEO_MODE_PAL) { + if (pmode.p1 < 1 || + pmode.p2 > 625) + return -EINVAL; + saa->boardcfg[5] = pmode.p1; + saa->boardcfg[55] = (pmode.p1 + + (pmode.p2/2) - 1) & + 0xff; + } else { + if (pmode.p1 < 4 || + pmode.p2 > 525) + return -EINVAL; + saa->boardcfg[4] = pmode.p1; + saa->boardcfg[54] = (pmode.p1 + + (pmode.p2/2) - 4) & + 0xff; + } + set_out_format(saa, CurrentMode); + case VID_PLAY_RESET: + return do_ibm_reset(saa); + case VID_PLAY_END_MARK: + if (saa->endmarktail < + saa->endmarkhead) { + if (saa->endmarkhead - + saa->endmarktail < 2) + return -ENOSPC; + } else if (saa->endmarkhead <= + saa->endmarktail) { + if (saa->endmarktail - + saa->endmarkhead > + (MAX_MARKS - 2)) + return -ENOSPC; + } else + return -ENOSPC; + saa->endmark[saa->endmarktail] = + saa->audtail; + saa->endmarktail++; + if (saa->endmarktail >= MAX_MARKS) + saa->endmarktail = 0; + } + return -EINVAL; + } + case VIDIOCSWRITEMODE: + { + int mode; + if (copy_from_user((void *) &mode, arg, sizeof(int))) + return -EFAULT; + if (mode == VID_WRITE_MPEG_AUD || + mode == VID_WRITE_MPEG_VID || + mode == VID_WRITE_CC || + mode == VID_WRITE_TTX || + mode == VID_WRITE_OSD) { + saa->writemode = mode; + return 0; + } + return -EINVAL; + } + case VIDIOCSMICROCODE: + { + struct video_code ucode; + __u8 *udata; + int i; + if (copy_from_user((void *) &ucode, arg, + sizeof(ucode))) + return -EFAULT; + if (ucode.datasize > 65536 || ucode.datasize < 1024 || + strncmp(ucode.loadwhat, "dec", 3)) + return -EINVAL; + if ((udata = vmalloc(ucode.datasize)) == NULL) + return -ENOMEM; + if (copy_from_user((void *) udata, ucode.data, + ucode.datasize)) { + vfree(udata); + return -EFAULT; + } + ucode.data = udata; + if (!strncmp(ucode.loadwhat, "decoder.aud", 11) + || !strncmp(ucode.loadwhat, "decoder.vid", 11)) + i = initialize_ibmmpeg2(&ucode); + else + i = initialize_fpga(&ucode); + vfree(udata); + if (i) + return -EINVAL; + return 0; + + } + case VIDIOCGCHAN: /* this makes xawtv happy */ + { + struct video_channel v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + v.flags = VIDEO_VC_AUDIO; + v.tuners = 0; + v.type = VID_TYPE_MPEG_DECODER; + v.norm = CurrentMode; + strcpy(v.name, "MPEG2"); + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSCHAN: /* this makes xawtv happy */ + { + struct video_channel v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* do nothing */ + return 0; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int saa_init_done(struct video_device *dev) +{ + return 0; +} + +static int saa_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + struct saa7146 *saa = (struct saa7146 *) dev; + printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr); + return -EINVAL; +} + +static long saa_read(struct video_device *dev, char *buf, + unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long saa_write(struct video_device *dev, const char *buf, + unsigned long count, int nonblock) +{ + struct saa7146 *saa = (struct saa7146 *) dev; + unsigned long todo = count; + int blocksize, split; + unsigned long flags; + + while (todo > 0) { + if (saa->writemode == VID_WRITE_MPEG_AUD) { + spin_lock_irqsave(&saa->lock, flags); + if (saa->audhead <= saa->audtail) + blocksize = 65536-(saa->audtail - saa->audhead); + else + blocksize = saa->audhead - saa->audtail; + spin_unlock_irqrestore(&saa->lock, flags); + if (blocksize < 16384) { + saawrite(SAA7146_PSR_DEBI_S | + SAA7146_PSR_PIN1, SAA7146_IER); + saawrite(SAA7146_PSR_PIN1, SAA7146_PSR); + /* wait for buffer space to open */ + interruptible_sleep_on(&saa->audq); + } + spin_lock_irqsave(&saa->lock, flags); + if (saa->audhead <= saa->audtail) { + blocksize = 65536-(saa->audtail - saa->audhead); + split = 65536 - saa->audtail; + } else { + blocksize = saa->audhead - saa->audtail; + split = 65536; + } + spin_unlock_irqrestore(&saa->lock, flags); + blocksize--; + if (blocksize > todo) + blocksize = todo; + /* double check that we really have space */ + if (!blocksize) + return -ENOSPC; + if (split < blocksize) { + if (copy_from_user(saa->audbuf + + saa->audtail, buf, split)) + return -EFAULT; + buf += split; + todo -= split; + blocksize -= split; + saa->audtail = 0; + } + if (copy_from_user(saa->audbuf + saa->audtail, buf, + blocksize)) + return -EFAULT; + saa->audtail += blocksize; + todo -= blocksize; + buf += blocksize; + saa->audtail &= 0xffff; + } else if (saa->writemode == VID_WRITE_MPEG_VID) { + spin_lock_irqsave(&saa->lock, flags); + if (saa->vidhead <= saa->vidtail) + blocksize=524288-(saa->vidtail - saa->vidhead); + else + blocksize = saa->vidhead - saa->vidtail; + spin_unlock_irqrestore(&saa->lock, flags); + if (blocksize < 65536) { + saawrite(SAA7146_PSR_DEBI_S | + SAA7146_PSR_PIN1, SAA7146_IER); + saawrite(SAA7146_PSR_PIN1, SAA7146_PSR); + /* wait for buffer space to open */ + interruptible_sleep_on(&saa->vidq); + } + spin_lock_irqsave(&saa->lock, flags); + if (saa->vidhead <= saa->vidtail) { + blocksize=524288-(saa->vidtail - saa->vidhead); + split = 524288 - saa->vidtail; + } else { + blocksize = saa->vidhead - saa->vidtail; + split = 524288; + } + spin_unlock_irqrestore(&saa->lock, flags); + blocksize--; + if (blocksize > todo) + blocksize = todo; + /* double check that we really have space */ + if (!blocksize) + return -ENOSPC; + if (split < blocksize) { + if (copy_from_user(saa->vidbuf + + saa->vidtail, buf, split)) + return -EFAULT; + buf += split; + todo -= split; + blocksize -= split; + saa->vidtail = 0; + } + if (copy_from_user(saa->vidbuf + saa->vidtail, buf, + blocksize)) + return -EFAULT; + saa->vidtail += blocksize; + todo -= blocksize; + buf += blocksize; + saa->vidtail &= 0x7ffff; + } else if (saa->writemode == VID_WRITE_OSD) { + if (count > 131072) + return -ENOSPC; + if (copy_from_user(saa->osdbuf, buf, count)) + return -EFAULT; + buf += count; + saa->osdhead = 0; + saa->osdtail = count; + debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2); + debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2); + debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, + debiread(saa, debNormal, + IBM_MP2_DISP_MODE, 2) | 1, 2); + /* trigger osd data transfer */ + saawrite(SAA7146_PSR_DEBI_S | + SAA7146_PSR_PIN1, SAA7146_IER); + saawrite(SAA7146_PSR_PIN1, SAA7146_PSR); + } + } + return count; +} + +static int saa_open(struct video_device *dev, int flags) +{ + struct saa7146 *saa = (struct saa7146 *) dev; + + saa->video_dev.busy = 0; + saa->user++; + if (saa->user > 1) + return 0; /* device open already, don't reset */ + saa->writemode = VID_WRITE_MPEG_VID; /* default to video */ + return 0; +} + +static void saa_close(struct video_device *dev) +{ + struct saa7146 *saa = (struct saa7146 *) dev; + saa->user--; + saa->video_dev.busy = 0; + if (saa->user > 0) /* still someone using device */ + return; + saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */ +} + +/* template for video_device-structure */ +static struct video_device saa_template = +{ + "SAA7146A", + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY, + VID_HARDWARE_SAA7146, + saa_open, + saa_close, + saa_read, + saa_write, + NULL, /* poll */ + saa_ioctl, + saa_mmap, + saa_init_done, + NULL, + 0, + 0 +}; + +static int configure_saa7146(struct pci_dev *dev, int num) +{ + int result; + struct saa7146 *saa; + + saa = &saa7146s[num]; + + saa->endmarkhead = saa->endmarktail = 0; + saa->win.x = saa->win.y = 0; + saa->win.width = saa->win.cropwidth = 720; + saa->win.height = saa->win.cropheight = 480; + saa->win.cropx = saa->win.cropy = 0; + saa->win.bpp = 2; + saa->win.depth = 16; + saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565]; + saa->win.bpl = 1024 * saa->win.bpp; + saa->win.swidth = 1024; + saa->win.sheight = 768; + saa->picture.brightness = 32768; + saa->picture.contrast = 38768; + saa->picture.colour = 32768; + saa->cap = 0; + saa->dev = dev; + saa->nr = num; + saa->playmode = VID_PLAY_NORMAL; + memset(saa->boardcfg, 0, 64); /* clear board config area */ + saa->saa7146_mem = NULL; + saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in = + saa->dmaa1out = saa->dmaa2in = saa->dmaa2out = + saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in = + saa->pagea1out = saa->pagea2in = saa->pagea2out = + saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 = + saa->pageRPS2 = NULL; + saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL; + saa->audhead = saa->vidtail = 0; + + init_waitqueue_head(&saa->i2cq); + init_waitqueue_head(&saa->audq); + init_waitqueue_head(&saa->debiq); + init_waitqueue_head(&saa->vidq); + spin_lock_init(&saa->lock); + + if (pci_enable_device(dev)) + return -EIO; + + saa->id = dev->device; + saa->irq = dev->irq; + saa->video_dev.minor = -1; + saa->saa7146_adr = pci_resource_start(dev, 0); + pci_read_config_byte(dev, PCI_CLASS_REVISION, &saa->revision); + + saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200); + if (!saa->saa7146_mem) + return -EIO; + + memcpy(&(saa->i2c), &saa7146_i2c_bus_template, sizeof(struct i2c_bus)); + memcpy(&saa->video_dev, &saa_template, sizeof(saa_template)); + sprintf(saa->i2c.name, "stradis%d", num); + saa->i2c.data = saa; + saawrite(0, SAA7146_IER); /* turn off all interrupts */ + result = request_irq(saa->irq, saa7146_irq, + SA_SHIRQ | SA_INTERRUPT, "stradis", (void *) saa); + if (result == -EINVAL) + printk(KERN_ERR "stradis%d: Bad irq number or handler\n", + num); + if (result == -EBUSY) + printk(KERN_ERR "stradis%d: IRQ %ld busy, change your PnP" + " config in BIOS\n", num, saa->irq); + if (result < 0) + return result; + pci_set_master(dev); + if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER) < 0) + return -1; +#if 0 + /* i2c generic interface is currently BROKEN */ + i2c_register_bus(&saa->i2c); +#endif + return 0; +} + +static int init_saa7146(int i) +{ + struct saa7146 *saa = &saa7146s[i]; + + saa->user = 0; + /* reset the saa7146 */ + saawrite(0xffff0000, SAA7146_MC1); + mdelay(5); + /* enable debi and i2c transfers and pins */ + saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C | + SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1); + /* ensure proper state of chip */ + saawrite(0x00000000, SAA7146_PAGE1); + saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1); + saawrite(0x00000000, SAA7146_PAGE2); + saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2); + saawrite(0x00000000, SAA7146_DD1_INIT); + saawrite(0x00000000, SAA7146_DD1_STREAM_B); + saawrite(0x00000000, SAA7146_DD1_STREAM_A); + saawrite(0x00000000, SAA7146_BRS_CTRL); + saawrite(0x80400040, SAA7146_BCS_CTRL); + saawrite(0x0000e000 /*| (1<<29)*/, SAA7146_HPS_CTRL); + saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL); + saawrite(0x00000000, SAA7146_ACON1); + saawrite(0x00000000, SAA7146_ACON2); + saawrite(0x00000600, SAA7146_I2C_STATUS); + saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A | + SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H | + SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 | + SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff, + SAA7146_MC2); + /* setup arbitration control registers */ + saawrite(0x1412121a, SAA7146_PCI_BT_V1); + + /* allocate 32k dma buffer + 4k for page table */ + if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "stradis%d: debi kmalloc failed\n", i); + return -1; + } +#if 0 + saa->pagedebi = saa->dmadebi + 32768; /* top 4k is for mmu */ + saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE); + for (i = 0; i < 12; i++) /* setup mmu page table */ + saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096)); +#endif + saa->audhead = saa->vidhead = saa->osdhead = 0; + saa->audtail = saa->vidtail = saa->osdtail = 0; + if (saa->vidbuf == NULL) + if ((saa->vidbuf = vmalloc(524288)) == NULL) { + printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr); + return -ENOMEM; + } + if (saa->audbuf == NULL) + if ((saa->audbuf = vmalloc(65536)) == NULL) { + printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr); + vfree(saa->vidbuf); + saa->vidbuf = NULL; + return -ENOMEM; + } + if (saa->osdbuf == NULL) + if ((saa->osdbuf = vmalloc(131072)) == NULL) { + printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr); + vfree(saa->vidbuf); + vfree(saa->audbuf); + saa->vidbuf = saa->audbuf = NULL; + return -ENOMEM; + } + /* allocate 81920 byte buffer for clipping */ + if ((saa->dmavid2 = kmalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "stradis%d: clip kmalloc failed\n", saa->nr); + vfree(saa->vidbuf); + vfree(saa->audbuf); + vfree(saa->osdbuf); + saa->vidbuf = saa->audbuf = saa->osdbuf = NULL; + saa->dmavid2 = NULL; + return -1; + } + memset(saa->dmavid2, 0x00, VIDEO_CLIPMAP_SIZE); /* clip everything */ + /* setup clipping registers */ + saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2); + saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2); + saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE, + SAA7146_PROT_ADDR2); + saawrite(256, SAA7146_PITCH2); + saawrite(4, SAA7146_PAGE2); /* dma direction: read, no byteswap */ + saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2, + SAA7146_MC2); + I2CBusScan(&(saa->i2c)); + return 0; +} + +static void release_saa(void) +{ + u8 command; + int i; + struct saa7146 *saa; + + for (i = 0; i < saa_num; i++) { + saa = &saa7146s[i]; + + /* turn off all capturing, DMA and IRQs */ + saawrite(0xffff0000, SAA7146_MC1); /* reset chip */ + saawrite(0, SAA7146_MC2); + saawrite(0, SAA7146_IER); + saawrite(0xffffffffUL, SAA7146_ISR); +#if 0 + /* unregister i2c_bus */ + i2c_unregister_bus((&saa->i2c)); +#endif + + /* disable PCI bus-mastering */ + pci_read_config_byte(saa->dev, PCI_COMMAND, &command); + /* Should this be &=~ ?? */ + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(saa->dev, PCI_COMMAND, command); + /* unmap and free memory */ + saa->audhead = saa->audtail = saa->osdhead = 0; + saa->vidhead = saa->vidtail = saa->osdtail = 0; + if (saa->vidbuf) + vfree(saa->vidbuf); + if (saa->audbuf) + vfree(saa->audbuf); + if (saa->osdbuf) + vfree(saa->osdbuf); + if (saa->dmavid2) + kfree((void *) saa->dmavid2); + saa->audbuf = saa->vidbuf = saa->osdbuf = NULL; + saa->dmavid2 = NULL; + if (saa->dmadebi) + kfree((void *) saa->dmadebi); + if (saa->dmavid1) + kfree((void *) saa->dmavid1); + if (saa->dmavid2) + kfree((void *) saa->dmavid2); + if (saa->dmavid3) + kfree((void *) saa->dmavid3); + if (saa->dmaa1in) + kfree((void *) saa->dmaa1in); + if (saa->dmaa1out) + kfree((void *) saa->dmaa1out); + if (saa->dmaa2in) + kfree((void *) saa->dmaa2in); + if (saa->dmaa2out) + kfree((void *) saa->dmaa2out); + if (saa->dmaRPS1) + kfree((void *) saa->dmaRPS1); + if (saa->dmaRPS2) + kfree((void *) saa->dmaRPS2); + free_irq(saa->irq, saa); + if (saa->saa7146_mem) + iounmap(saa->saa7146_mem); + if (saa->video_dev.minor != -1) + video_unregister_device(&saa->video_dev); + } +} + + +static int __init stradis_init (void) +{ + struct pci_dev *dev = NULL; + int result = 0, i; + + saa_num = 0; + + while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) { + if (!dev->subsystem_vendor) + printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num); + else + printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); + result = configure_saa7146(dev, saa_num++); + if (result) + return result; + } + if (saa_num) + printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num); + else + return -EINVAL; + for (i = 0; i < saa_num; i++) + if (init_saa7146(i) < 0) { + release_saa(); + return -EIO; + } + return 0; +} + + +static void __exit stradis_exit (void) +{ + release_saa(); + printk(KERN_INFO "stradis: module cleanup complete\n"); +} + + +module_init(stradis_init); +module_exit(stradis_exit); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tda7432.c linux/drivers/media/video/tda7432.c --- v2.4.0-test6/linux/drivers/media/video/tda7432.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tda7432.c Mon May 15 12:06:25 2000 @@ -0,0 +1,505 @@ +/* + * For the STS-Thompson TDA7432 audio processor chip + * + * Handles audio functions: volume, balance, tone, loudness + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 2000 Eric Sandeen + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * set to 2 if you'd like to be inundated with debug messages + * + * loudness - set between 0 and 15 for varying degrees of loudness effect + * + * TODO: + * Implement tone controls + * + * Revision: 0.3 - Fixed silly reversed volume controls. :) + * Revision: 0.2 - Cleaned up #defines + * fixed volume control + * Added I2C_DRIVERID_TDA7432 + * added loudness insmod control + * Revision: 0.1 - initial version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */ +#ifndef I2C_DRIVERID_TDA7432 + #define I2C_DRIVERID_TDA7432 27 +#endif + + +MODULE_AUTHOR("Eric Sandeen "); +MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip"); + +MODULE_PARM(debug,"i"); +MODULE_PARM(loudness,"i"); +static int loudness = 0; /* disable loudness by default */ +static int debug = 0; /* insmod parameter */ + + +/* Address to scan (I2C address of this chip) */ +static unsigned short normal_i2c[] = { + I2C_TDA7432 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* Structure of address and subaddresses for the tda7432 */ + +struct tda7432 { + int addr; + int input; + int volume; + int tone; + int lf, lr, rf, rr; + int loud; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk +#define d2printk if (debug > 1) printk + +/* The TDA7432 is made by STS-Thompson + * http://www.st.com + * http://us.st.com/stonline/books/pdf/docs/4056.pdf + * + * TDA7432: I2C-bus controlled basic audio processor + * + * The TDA7432 controls basic audio functions like volume, balance, + * and tone control (including loudness). It also has four channel + * output (for front and rear). Since most vidcap cards probably + * don't have 4 channel output, this driver will set front & rear + * together (no independent control). + */ + + /* Subaddresses for TDA7432 */ + +#define TDA7432_IN 0x00 /* Input select */ +#define TDA7432_VL 0x01 /* Volume */ +#define TDA7432_TN 0x02 /* Bass, Treble (Tone) */ +#define TDA7432_LF 0x03 /* Attenuation LF (Left Front) */ +#define TDA7432_LR 0x04 /* Attenuation LR (Left Rear) */ +#define TDA7432_RF 0x05 /* Attenuation RF (Right Front) */ +#define TDA7432_RR 0x06 /* Attenuation RR (Right Rear) */ +#define TDA7432_LD 0x07 /* Loudness */ + + + /* Masks for bits in TDA7432 subaddresses */ + +/* Many of these not used - just for documentation */ + +/* Subaddress 0x00 - Input selection and bass control */ + +/* Bits 0,1,2 control input: + * 0x00 - Stereo input + * 0x02 - Mono input + * 0x03 - Mute + * Mono probably isn't used - I'm guessing only the stereo + * input is connected on most cards, so we'll set it to stereo. + * + * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut + * Bit 4 controls bass range: 0/1 is extended/standard bass range + * + * Highest 3 bits not used + */ + +#define TDA7432_STEREO_IN 0 +#define TDA7432_MONO_IN 2 /* Probably won't be used */ +#define TDA7432_MUTE 3 /* Probably won't be used */ +#define TDA7432_BASS_SYM 1 << 3 +#define TDA7432_BASS_NORM 1 << 4 + +/* Subaddress 0x01 - Volume */ + +/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps + * Recommended maximum is +20 dB + * + * +32dB: 0x00 + * +20dB: 0x0c + * 0dB: 0x20 + * -79dB: 0x6f + * + * MSB (bit 7) controls loudness: 1/0 is loudness on/off + */ + +#define TDA7432_VOL_0DB 0x20 +#define TDA7432_LD_ON 1 << 7 + + +/* Subaddress 0x02 - Tone control */ + +/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB + * 0x0 is 14dB, 0x7 is 0dB + * + * Bit 3 controls treble attenuation/gain (sign) + * 1 = gain (+) + * 0 = attenuation (-) + * + * Bits 4,5,6 control absolute bass gain from 0dB to 14dB + * (This is only true for normal base range, set in 0x00) + * 0x0 << 4 is 14dB, 0x7 is 0dB + * + * Bit 7 controls bass attenuation/gain (sign) + * 1 << 7 = gain (+) + * 0 << 7 = attenuation (-) + * + * Example: + * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble + */ + +#define TDA7432_TREBLE_0DB 0xf +#define TDA7432_TREBLE 7 +#define TDA7432_TREBLE_GAIN 1 << 3 +#define TDA7432_BASS_0DB 0xf << 4 +#define TDA7432_BASS 7 << 4 +#define TDA7432_BASS_GAIN 1 << 7 + + +/* Subaddress 0x03 - Left Front attenuation */ +/* Subaddress 0x04 - Left Rear attenuation */ +/* Subaddress 0x05 - Right Front attenuation */ +/* Subaddress 0x06 - Right Rear attenuation */ + +/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB + * in 1.5dB steps. + * + * 0x00 is 0dB + * 0x1f is -37.5dB + * + * Bit 5 mutes that channel when set (1 = mute, 0 = unmute) + * We'll use the mute on the input, though (above) + * Bits 6,7 unused + */ + +#define TDA7432_ATTEN_0DB 0x00 + + +/* Subaddress 0x07 - Loudness Control */ + +/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps + * when bit 4 is NOT set + * + * 0x0 is 0dB + * 0xf is -15dB + * + * If bit 4 is set, then there is a flat attenuation according to + * the lower 4 bits, as above. + * + * Bits 5,6,7 unused + */ + + + +/* Begin code */ + +static int tda7432_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + d2printk("tda7432: In tda7432_write\n"); + dprintk("tda7432: Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +/* I don't think we ever actually _read_ the chip... */ +#if 0 +static int tda7432_read(struct i2c_client *client) +{ + unsigned char buffer; + d2printk("tda7432: In tda7432_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda7432: I/O error, trying (read)\n"); + return -1; + } + dprintk("tda7432: Read 0x%02x\n", buffer); + return buffer; +} +#endif + +static int tda7432_set(struct i2c_client *client) +{ + struct tda7432 *t = client->data; + unsigned char buf[16]; + d2printk("tda7432: In tda7432_set\n"); + + dprintk(KERN_INFO + "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud); + buf[0] = TDA7432_IN; + buf[1] = t->input; + buf[2] = t->volume; + buf[3] = t->tone; + buf[4] = t->lf; + buf[5] = t->lr; + buf[6] = t->rf; + buf[7] = t->rr; + buf[8] = t->loud; + if (9 != i2c_master_send(client,buf,9)) { + printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n"); + return -1; + } + + return 0; +} + +static void do_tda7432_init(struct i2c_client *client) +{ + struct tda7432 *t = client->data; + d2printk("tda7432: In tda7432_init\n"); + + t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ + TDA7432_BASS_SYM | /* Symmetric bass cut */ + TDA7432_BASS_NORM; /* Normal bass range */ + t->volume = TDA7432_VOL_0DB; /* 0dB Volume */ + if (loudness) /* Turn loudness on? */ + t->volume |= TDA7432_LD_ON; + t->tone = TDA7432_TREBLE_0DB | /* 0dB Treble */ + TDA7432_BASS_0DB; /* 0dB Bass */ + t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->loud = loudness; /* insmod parameter */ + + tda7432_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda7432_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda7432 *t; + struct i2c_client *client; + d2printk("tda7432: In tda7432_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda7432_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA7432"); + printk(KERN_INFO "tda7432: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda7432_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda7432_attach); + return 0; +} + +static int tda7432_detach(struct i2c_client *client) +{ + struct tda7432 *t = client->data; + + do_tda7432_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda7432_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda7432 *t = client->data; + d2printk("tda7432: In tda7432_command\n"); +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + + /* Query card - scale from TDA7432 settings to V4L settings */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + dprintk("tda7432: VIDIOCGAUDIO\n"); + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* Master volume control + * V4L volume is min 0, max 65535 + * TDA7432 Volume: + * Min (-79dB) is 0x6f + * Max (+20dB) is 0x07 + * (Mask out bit 7 of vol - it's for the loudness setting) + */ + + va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; + + /* Balance depends on L,R attenuation + * V4L balance is 0 to 65535, middle is 32768 + * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f + * to scale up to V4L numbers, mult by 1057 + * attenuation exists for lf, lr, rf, rr + * we use only lf and rf (front channels) + */ + + if ( (t->lf) < (t->rf) ) + /* right is attenuated, balance shifted left */ + va->balance = (32768 - 1057*(t->rf)); + else + /* left is attenuated, balance shifted right */ + va->balance = (32768 + 1057*(t->lf)); + + /* Bass/treble */ + va->bass = 32768; /* brain hurts... set to middle for now */ + va->treble = 32768; /* brain hurts... set to middle for now */ + + break; /* VIDIOCGAUDIO case */ + } + + /* Set card - scale from V4L settings to TDA7432 settings */ + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + dprintk("tda7432: VIDEOCSAUDIO\n"); + + t->volume = 0x6f - ( (va->volume)/630 ); + + if (loudness) /* Turn on the loudness bit */ + t->volume |= TDA7432_LD_ON; + + if (va->balance < 32768) { + /* shifted to left, attenuate right */ + t->rr = (32768 - va->balance)/1057; + t->rf = t->rr; + } + else { + /* shifted to right, attenuate left */ + t->lf = (va->balance - 32768)/1057; + t->lr = t->lf; + } + + /* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */ + + tda7432_write(client,TDA7432_VL, t->volume); + /* tda7432_write(client,TDA7432_TN, t->tone); */ + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + d2printk("tda7432: Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda7432 driver", + I2C_DRIVERID_TDA7432, + I2C_DF_NOTIFY, + tda7432_probe, + tda7432_detach, + tda7432_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda7432_init(void) +#endif +{ + + if ( (loudness < 0) || (loudness > 15) ) + { + printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n"); + return -EINVAL; + } + + + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tda8425.c linux/drivers/media/video/tda8425.c --- v2.4.0-test6/linux/drivers/media/video/tda8425.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tda8425.c Mon May 15 12:06:25 2000 @@ -0,0 +1,324 @@ +/* + * for the TDA8425 chip (I don't know which cards have this) + * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT + * CHIP IS AT ADDRESS 0x82 (it relies on i2c to make sure that there is a + * device acknowledging that address) + * + * Copyright (c) 1998 Greg Alexander + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * All of this should work, though it would be nice to eventually support + * balance (different left,right values). Also, the chip seems (?) to have + * two stereo inputs, so if someone has this card, could they tell me if the + * second one can be used for anything (i.e., does it have an external input + * that you can't hear even if you set input to composite?) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + I2C_TDA8425 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ +#define dprintk if (debug) printk + + +struct tda8425 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; + __u16 left,right; + __u16 bass,treble; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + + +#define TDA8425_VL 0x00 /* volume left */ +#define TDA8425_VR 0x01 /* volume right */ +#define TDA8425_BA 0x02 /* bass */ +#define TDA8425_TR 0x03 /* treble */ +#define TDA8425_S1 0x08 /* switch functions */ + /* values for those registers: */ +#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ +#define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */ + + +/* ******************************** * + * functions for talking to TDA8425 * + * ******************************** */ + +static int tda8425_write(struct i2c_client *client, int addr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = addr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda8425: I/O error, trying (write %d 0x%x)\n", + addr, val); + return -1; + } + return 0; +} + +static void tda8425_set(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + /* mode is ignored today */ + dprintk(KERN_DEBUG "tda8425_set(%04x,%04x,%04x,%04x)\n",tda->left>>10,tda->right>>10,tda->bass>>12,tda->treble>>12); + tda8425_write(client, TDA8425_VL, tda->left>>10 |0xC0); + tda8425_write(client, TDA8425_VR, tda->right>>10 |0xC0); + tda8425_write(client, TDA8425_BA, tda->bass>>12 |0xF0); + tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0); +} + +static void do_tda8425_init(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + tda->left=tda->right =61440; /* 0dB */ + tda->bass=tda->treble=24576; /* 0dB */ + tda->mode=AUDIO_OFF; + tda->stereo=1; + /* left=right=0x27<<10, bass=treble=0x07<<12 */ + tda8425_write(client, TDA8425_S1, TDA8425_S1_OFF); /* mute */ + tda8425_set(client); +} + +static void tda8425_audio(struct i2c_client *client, int mode) +{ + struct tda8425 *tda = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tda8425_audio:%d (T,R,E,I,O)\n",mode); + tda->mode=mode; + tda8425_write(client, TDA8425_S1, + (mode==AUDIO_OFF)?TDA8425_S1_OFF:TDA8425_S1_ON); + /* this is the function we'll need to change if it turns out the + * input-selecting capabilities should be used. */ +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda8425_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda8425 *tda; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tda = kmalloc(sizeof *tda,GFP_KERNEL); + if (!tda) + return -ENOMEM; + memset(tda,0,sizeof *tda); + do_tda8425_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA8425"); + printk(KERN_INFO "tda8425: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda8425_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda8425_attach); + return 0; +} + + +static int tda8425_detach(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + do_tda8425_init(client); + i2c_detach_client(client); + + kfree(tda); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda8425_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda8425 *tda = client->data; + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tda8425_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tda8425_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(tda->left,tda->right); + va->balance=(32768*MIN(tda->left,tda->right))/ + (va->volume ? va->volume : 1); + va->balance=(tda->leftright)? + (65535-va->balance) : va->balance; + va->bass = tda->bass; + va->treble = tda->treble; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + tda->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tda->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tda->bass = va->bass; + tda->treble = va->treble; + tda8425_set(client); + break; + } + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = tda->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = tda->right; + break; + case AUDC_SET_VOLUME_LEFT: + tda->left = *sarg; + tda8425_set(client); + break; + case AUDC_SET_VOLUME_RIGHT: + tda->right = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_BASS: + *sarg = tda->bass; + break; + case AUDC_SET_BASS: + tda->bass = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_TREBLE: + *sarg = tda->treble; + break; + case AUDC_SET_TREBLE: + tda->treble = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_STEREO: + *sarg = tda->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + tda->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; + /* TODO: make this write to the TDA9850? */ + break; + +/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to + case AUDC_NEWCHANNEL: it and it would require preserving state + case AUDC_GET_DC: huh?? (not used by bttv.c) +*/ +#endif + default: + /* nothing */ + } + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda8424 driver", + I2C_DRIVERID_TDA8425, + I2C_DF_NOTIFY, + tda8425_probe, + tda8425_detach, + tda8425_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda8425_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tda985x.c linux/drivers/media/video/tda985x.c --- v2.4.0-test6/linux/drivers/media/video/tda985x.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tda985x.c Mon May 15 12:06:25 2000 @@ -0,0 +1,536 @@ +/* + * For the TDA9850 and TDA9855 chips + * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used + * on STB cards. Other cards probably use these chips as well.) + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 1999 Gerd Knorr + * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * - set to 2 if you'd like to be flooded with debug messages + * chip - set to 9850 or 9855 to select your chip (default 9855) + * + * TODO: + * Fix channel change bug - sound goes out when changeing channels, mute + * and unmote to fix. - Is this still here? + * Fine tune sound + * Get rest of capabilities into video_audio struct... + * + * Revision 0.5 - cleaned up debugging messages, added debug level=2 + * Revision: 0.4 - check for correct chip= insmod value + * also cleaned up comments a bit + * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command + * Revision: 0.2 - added insmod option chip= + * Revision: 0.1 - original version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +MODULE_PARM(debug,"i"); +MODULE_PARM(chip,"i"); +MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855"); + +static int debug = 0; /* insmod parameter */ +static int chip = 9855; /* insmod parameter */ + +/* Addresses to scan */ +#define I2C_TDA985x_L 0xb4 +#define I2C_TDA985x_H 0xb6 +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = { + I2C_TDA985x_L >> 1, + I2C_TDA985x_H >> 1, + I2C_CLIENT_END +}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* This is a superset of the TDA9850 and TDA9855 members */ + +struct tda985x { + int addr; + int rvol, lvol; + int bass, treble, sub; + int c4, c5, c6, c7; + int a1, a2, a3; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk +#define d2printk if (debug == 2) printk + +/* The TDA9850 and TDA9855 are both made by Philips Semiconductor + * http://www.semiconductors.philips.com + * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder + * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor + * + * The TDA9850 has more or less a subset of the functions that the TDA9855 + * has. As a result, we can re-use many of these defines. Anything with + * TDA9855 is specific to that chip, anything with TDA9850 is specific + * to that chip, and anything with TDA985x is valid for either. + * + * To complicate things further, the TDA9850 uses labels C1 through C4 + * for subaddresses 0x04 through 0x07, while the TDA9855 uses + * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing. + * To help keep things straight, I have renamed the various C[1,4] labels + * to C[4,7] so that the numerical label matches the hex value of the + * subaddress for both chips. At least the A[1,3] labels line up. :) + */ + + /* subaddresses for TDA9855 */ +#define TDA9855_VR 0x00 /* Volume, right */ +#define TDA9855_VL 0x01 /* Volume, left */ +#define TDA9855_BA 0x02 /* Bass */ +#define TDA9855_TR 0x03 /* Treble */ +#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ + + /* subaddresses for TDA9850 */ +#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */ + + /* subaddesses for both chips */ +#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */ +#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */ +#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */ +#define TDA985x_A1 0x08 /* Alignment 1 for both chips */ +#define TDA985x_A2 0x09 /* Alignment 2 for both chips */ +#define TDA985x_A3 0x0a /* Alignment 3 for both chips */ + + /* Masks for bits in TDA9855 subaddresses */ +/* 0x00 - VR in TDA9855 */ +/* 0x01 - VL in TDA9855 */ +/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) + * in 1dB steps - mute is 0x27 */ + + +/* 0x02 - BA in TDA9855 */ +/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) + * in .5dB steps - 0 is 0x0E */ + + +/* 0x03 - TR in TDA9855 */ +/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) + * in 3dB steps - 0 is 0x7 */ + + /* Masks for bits in both chips' subaddresses */ +/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */ +/* Unique to TDA9855: */ +/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf) + * in 3dB steps - mute is 0x0 */ + +/* Unique to TDA9850: */ +/* lower 4 bits control stereo noise threshold, over which stereo turns off + * set to values of 0x00 through 0x0f for Ster1 through Ster16 */ + + +/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/ +/* Unique to TDA9855: */ +#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ +#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ +#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ +#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ +#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ +#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ + +/* Unique to TDA9850: */ +/* lower 4 bits contol SAP noise threshold, over which SAP turns off + * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ + + +/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ +/* Common to TDA9855 and TDA9850: */ +#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA985x_MONO 0 /* Forces Mono output */ +#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ + +/* Unique to TDA9855: */ +#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ +#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ +#define TDA9855_LINEAR 0 /* Linear Stereo */ +#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ +#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ +#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ +#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ + + +/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) + * in .5dB steps - 0dB is 0x7 */ + + +/* 0x08, 0x09 - A1 and A2 (read/write) */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 5 bites are wideband and spectral expander alignment + * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ +#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */ +#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ +#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ + + +/* 0x0a - A3 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), + * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ +#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ + +/* Unique to TDA9855: */ +/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), + * 1200ohm (0x1), 2100ohm (0x3) */ + + +/* Begin code */ + +static int tda985x_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + d2printk("tda985x: In tda985x_write\n"); + dprintk("tda985x: Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +static int tda985x_read(struct i2c_client *client) +{ + unsigned char buffer; + d2printk("tda985x: In tda985x_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda985x: I/O error, trying (read)\n"); + return -1; + } + dprintk("tda985x: Read 0x%02x\n", buffer); + return buffer; +} + +static int tda985x_set(struct i2c_client *client) +{ + struct tda985x *t = client->data; + unsigned char buf[16]; + d2printk("tda985x: In tda985x_set\n"); + + if (chip == 9855) + { + dprintk(KERN_INFO + "tda985x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->rvol,t->lvol,t->bass,t->treble,t->sub, + t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9855_VR; + buf[1] = t->rvol; + buf[2] = t->lvol; + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->sub; + buf[6] = t->c5; + buf[7] = t->c6; + buf[8] = t->c7; + buf[9] = t->a1; + buf[10] = t->a2; + buf[11] = t->a3; + if (12 != i2c_master_send(client,buf,12)) { + printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n"); + return -1; + } + } + + else if (chip == 9850) + { + dprintk(KERN_INFO + "tda986x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9850_C4; + buf[1] = t->c4; + buf[2] = t->c5; + buf[3] = t->c6; + buf[4] = t->c7; + buf[5] = t->a1; + buf[6] = t->a2; + buf[7] = t->a3; + if (8 != i2c_master_send(client,buf,8)) { + printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n"); + return -1; + } + } + + return 0; +} + +static void do_tda985x_init(struct i2c_client *client) +{ + struct tda985x *t = client->data; + d2printk("tda985x: In tda985x_init\n"); + + if (chip == 9855) + { + printk("tda985x: Using tda9855 options\n"); + t->rvol = 0x6f; /* 0dB */ + t->lvol = 0x6f; /* 0dB */ + t->bass = 0x0e; /* 0dB */ + t->treble = (0x07 << 1); /* 0dB */ + t->sub = 0x8 << 2; /* 0dB */ + t->c5 = TDA9855_MUTE | TDA9855_AVL | + TDA9855_LOUD | TDA9855_INT; + /* Set Mute, AVL, Loudness off, Internal sound */ + t->c6 = TDA985x_STEREO | TDA9855_LINEAR | + TDA9855_TZCM | TDA9855_VZCM; + /* Stereo linear mode, also wait til zero crossings */ + t->c7 = 0x07; /* 0dB input gain */ + } + + else if (chip == 9850) + { + printk("tda985x: Using tda9850 options\n"); + t->c4 = 0x08; /* Set stereo noise thresh to nominal */ + t->c5 = 0x08; /* Set SAP noise threshold to nominal */ + t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */ + t->c7 = 0x07; /* 0dB input gain */ + } + + /* The following is valid for both chip types */ + t->a1 = 0x10; /* Select nominal wideband expander */ + t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */ + t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */ + + tda985x_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda985x_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda985x *t; + struct i2c_client *client; + d2printk("tda985x: In tda985x_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda985x_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA985x"); + printk(KERN_INFO "tda985x: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda985x_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda985x_attach); + return 0; +} + +static int tda985x_detach(struct i2c_client *client) +{ + struct tda985x *t = client->data; + + do_tda985x_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda985x_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda985x *t = client->data; + d2printk("tda985x: In tda985x_command\n"); +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + dprintk("tda985x: VIDIOCGAUDIO\n"); + if (chip == 9855) + { + int left,right; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is 0x27 max is 0x7f, vstep is 2e8 */ + left = (t->lvol-0x27)*0x2e8; + right = (t->rvol-0x27)*0x2e8; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */ + va->treble = ((t->treble>>1)-0x3)*0x1c71; + } + + /* Valid for both chips: */ + { + va->mode = ((TDA985x_STP | TDA985x_SAPP) & + tda985x_read(client)) >> 4; + /* Add mono mode regardless of SAP and stereo */ + /* Allows forced mono */ + va->mode |= VIDEO_SOUND_MONO; + } + + break; /* VIDIOCGAUDIO case */ + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + dprintk("tda985x: VIDEOCSAUDIO\n"); + if (chip == 9855) + { + int left,right; + + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/0x2e8+0x27; + t->rvol = right/0x2e8+0x27; + t->bass = va->bass/0xccc+0x6; + t->treble = (va->treble/0x1c71+0x3)<<1; + tda985x_write(client,TDA9855_VL,t->lvol); + tda985x_write(client,TDA9855_VR,t->rvol); + tda985x_write(client,TDA9855_BA, t->bass); + tda985x_write(client,TDA9855_TR,t->treble); + } + + /* The following is valid for both chips */ + + switch (va->mode) { + case VIDEO_SOUND_MONO: + dprintk("tda985x: VIDEO_SOUND_MONO\n"); + t->c6= TDA985x_MONO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_STEREO: + dprintk("tda985x: VIDEO_SOUND_STEREO\n"); + t->c6= TDA985x_STEREO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_LANG1: + dprintk("tda985x: VIDEO_SOUND_LANG1\n"); + t->c6= TDA985x_SAP | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + } /* End of (va->mode) switch */ + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + d2printk("tda985x: Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda985x driver", + I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */ + I2C_DF_NOTIFY, + tda985x_probe, + tda985x_detach, + tda985x_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda985x_init(void) +#endif +{ + if ( (chip != 9850) && (chip != 9855) ) + { + printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n"); + return -EINVAL; + } + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tda9875.c linux/drivers/media/video/tda9875.c --- v2.4.0-test6/linux/drivers/media/video/tda9875.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tda9875.c Sun Aug 6 12:45:28 2000 @@ -0,0 +1,403 @@ +/* + * For the TDA9875 chip + * (The TDA9875 is used on the Diamond DTV2000 french version + * Other cards probably use these chips as well.) + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and + * Eric Sandeen + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * + * Revision: 0.1 - original version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */ +#ifndef I2C_DRIVERID_TDA9875 + #define I2C_DRIVERID_TDA9875 28 +#endif + + +MODULE_PARM(debug,"i"); + +static int debug = 0; /* insmod parameter */ + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + I2C_TDA9875 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* This is a superset of the TDA9875 */ +struct tda9875 { + int mode; + int rvol, lvol; + int bass, treble; +}; + + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk + +/* The TDA9875 is made by Philips Semiconductor + * http://www.semiconductors.philips.com + * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator + * + */ + + /* subaddresses for TDA9875 */ +#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/ +#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */ +#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ +#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ + +#define TDA9875_CH1V 0x0c /*Chanel 1 volume (mute)*/ +#define TDA9875_CH2V 0x0d /*Chanel 2 volume (mute)*/ +#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ +#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ + +#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/ +#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/ +#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/ +#define TDA9875_MVL 0x1a /* Main volume gauche */ +#define TDA9875_MVR 0x1b /* Main volume droite */ +#define TDA9875_MBA 0x1d /* Main Basse */ +#define TDA9875_MTR 0x1e /* Main treble */ +#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/ +#define TDA9875_AVL 0x20 /* Auxilary volume gauche */ +#define TDA9875_AVR 0x21 /* Auxilary volume droite */ +#define TDA9875_ABA 0x22 /* Auxilary Basse */ +#define TDA9875_ATR 0x23 /* Auxilary treble */ + +#define TDA9875_MSR 0x02 /* Monitor select register */ +#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */ +#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */ +#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */ +#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */ +#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */ +#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */ +#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/ +#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/ +#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/ + +/* values */ +#define TDA9875_MUTE_ON 0xff /* general mute */ +#define TDA9875_MUTE_OFF 0xcc /* general no mute */ + + + +/* Begin code */ + +static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char val) +{ + unsigned char buffer[2]; + dprintk("In tda9875_write\n"); + dprintk("Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda9875: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +#if 0 +static int tda9875_read(struct i2c_client *client) +{ + unsigned char buffer; + dprintk("In tda9875_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda9875: I/O error, trying (read)\n"); + return -1; + } + dprintk("Read 0x%02x\n", buffer); + return buffer; +} +#endif + +static void tda9875_set(struct i2c_client *client) +{ + struct tda9875 *tda = client->data; + unsigned char a; + + dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",tda->lvol,tda->rvol,tda->bass,tda->treble); + + + a = tda->lvol & 0xff; + tda9875_write(client, TDA9875_MVL, a); + a =tda->rvol & 0xff; + tda9875_write(client, TDA9875_MVR, a); + a =tda->bass & 0xff; + tda9875_write(client, TDA9875_MBA, a); + a =tda->treble & 0xff; + tda9875_write(client, TDA9875_MTR, a); +} + +static void do_tda9875_init(struct i2c_client *client) +{ + struct tda9875 *t = client->data; + dprintk("In tda9875_init\n"); + tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/ + tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/ + tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/ + tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/ + tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/ + tda9875_write(client, TDA9875_C2MSB, 0x00 ); /*Car2(NICAM) MSB XMHz*/ + tda9875_write(client, TDA9875_C2MIB, 0x00 ); /*Car2(NICAM) MIB XMHz*/ + tda9875_write(client, TDA9875_C2LSB, 0x00 ); /*Car2(NICAM) LSB XMHz*/ + tda9875_write(client, TDA9875_DCR, 0x00 ); /*Demod config 0x00*/ + tda9875_write(client, TDA9875_DEEM, 0x44 ); /*DE-Emph 0b0100 0100*/ + tda9875_write(client, TDA9875_FMAT, 0x00 ); /*FM Matrix reg 0x00*/ + tda9875_write(client, TDA9875_SC1, 0x00 ); /* SCART 1 (SC1)*/ + tda9875_write(client, TDA9875_SC2, 0x01 ); /* SCART 2 (sc2)*/ + + tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Chanel volume 1 mute*/ + tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Chanel volume 2 mute */ + tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/ + tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/ + tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/ + tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */ + tda9875_write(client, TDA9875_MCS, 0x44 ); /* Main ch select (DAC) */ + tda9875_write(client, TDA9875_MVL, 0x03 ); /* Vol Main left 10dB */ + tda9875_write(client, TDA9875_MVR, 0x03 ); /* Vol Main right 10dB*/ + tda9875_write(client, TDA9875_MBA, 0x00 ); /* Main Bass Main 0dB*/ + tda9875_write(client, TDA9875_MTR, 0x00 ); /* Main Treble Main 0dB*/ + tda9875_write(client, TDA9875_ACS, 0x44 ); /* Aux chan select (dac)*/ + tda9875_write(client, TDA9875_AVL, 0x00 ); /* Vol Aux left 0dB*/ + tda9875_write(client, TDA9875_AVR, 0x00 ); /* Vol Aux right 0dB*/ + tda9875_write(client, TDA9875_ABA, 0x00 ); /* Aux Bass Main 0dB*/ + tda9875_write(client, TDA9875_ATR, 0x00 ); /* Aux Aigus Main 0dB*/ + + tda9875_write(client, TDA9875_MUT, 0xcc ); /* General mute */ + + t->mode=AUDIO_UNMUTE; + t->lvol=t->rvol =0; /* 0dB */ + t->bass=0; /* 0dB */ + t->treble=0; /* 0dB */ + tda9875_set(client); + +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda9875_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda9875 *t; + struct i2c_client *client; + dprintk("In tda9875_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda9875_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA9875"); + printk(KERN_INFO "tda9875: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda9875_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda9875_attach); + return 0; +} + +static int tda9875_detach(struct i2c_client *client) +{ + struct tda9875 *t = client->data; + + do_tda9875_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda9875_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda9875 *t = client->data; + + dprintk("In tda9875_command...\n"); + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + int left,right; + + dprintk("VIDIOCGAUDIO\n"); + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is -84 max is 24 */ + left = (t->lvol+84)*606; + right = (t->rvol+84)*606; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass+12)*2427; /* min -12 max +15 */ + va->treble = (t->treble+12)*2730;/* min -12 max +12 */ + + va->mode |= VIDEO_SOUND_MONO; + + + break; /* VIDIOCGAUDIO case */ + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + int left,right; + + dprintk("VIDEOCSAUDIO...\n"); + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = ((left/606)-84) & 0xff; + if (t->lvol > 24) + t->lvol = 24; + if (t->lvol < -84) + t->lvol = -84 & 0xff; + + t->rvol = ((right/606)-84) & 0xff; + if (t->rvol > 24) + t->rvol = 24; + if (t->rvol < -84) + t->rvol = -84 & 0xff; + + t->bass = ((va->bass/2400)-12) & 0xff; + if (t->bass > 15) + t->bass = 15; + if (t->bass < -12) + t->bass = -12 & 0xff; + + t->treble = ((va->treble/2700)-12) & 0xff; + if (t->treble > 12) + t->treble = 12; + if (t->treble < -12) + t->treble = -12 & 0xff; + + + +//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + + + tda9875_set(client); + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + dprintk("Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda9875 driver", + I2C_DRIVERID_TDA9875, /* Get new one for TDA9875 */ + I2C_DF_NOTIFY, + tda9875_probe, + tda9875_detach, + tda9875_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda9875_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tea6300.c linux/drivers/media/video/tea6300.c --- v2.4.0-test6/linux/drivers/media/video/tea6300.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tea6300.c Sat Jan 8 12:54:54 2000 @@ -0,0 +1,344 @@ +/* + * for the TEA6300 chip (only found on Gateway STB TV/FM cards tho the best + * of my knowledge) + * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF THE WRONG + * CHIP (i.e., an MSP3400) IS ON I2C ADDRESS 0x80 (it relies on i2c to + * make sure that there is a device acknowledging that address). This + * is a potential problem because the MSP3400 is very popular and does + * use this address! You have been warned! + * + * Copyright (c) 1998 Greg Alexander + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * All of this should work, though it would be nice to eventually support + * balance (different left,right values) and, if someone ever finds a card + * with the support (or if you're careful with a soldering iron), fade + * (front/back). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + + +/* Addresses to scan */ +#define I2C_TEA6300 0x80 +static unsigned short normal_i2c[] = { + I2C_TEA6300 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +#define dprintk if (debug) printk + + +struct tea6300 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; + __u16 left,right; + __u16 bass,treble; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define TEA6300_VL 0x00 /* volume left */ +#define TEA6300_VR 0x01 /* volume right */ +#define TEA6300_BA 0x02 /* bass */ +#define TEA6300_TR 0x03 /* treble */ +#define TEA6300_FA 0x04 /* fader control */ +#define TEA6300_S 0x05 /* switch register */ + /* values for those registers: */ +#define TEA6300_S_SA 0x01 /* stereo A input */ +#define TEA6300_S_SB 0x02 /* stereo B */ +#define TEA6300_S_SC 0x04 /* stereo C */ +#define TEA6300_S_GMU 0x80 /* general mute */ + + +/* ******************************** * + * functions for talking to TEA6300 * + * ******************************** */ + +static int tea6300_write(struct i2c_client *client, int addr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = addr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tea6300: I/O error, trying (write %d 0x%x)\n", + addr, val); + return -1; + } + return 0; +} + +static void tea6300_set(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + /* mode is ignored today */ + dprintk(KERN_DEBUG "tea6300_set(%04x,%04x,%04x,%04x)\n",tea->left>>10,tea->right>>10,tea->bass>>12,tea->treble>>12); + tea6300_write(client, TEA6300_VL, tea->left>>10 ); + tea6300_write(client, TEA6300_VR, tea->right>>10 ); + tea6300_write(client, TEA6300_BA, tea->bass>>12 ); + tea6300_write(client, TEA6300_TR, tea->treble>>12); +} + +static void do_tea6300_init(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + tea->left=tea->right =49152; /* -10dB (loud enough, but not beyond + normal line levels - so as to avoid + clipping */ + tea->bass=tea->treble=28672; /* 0dB */ + tea->mode=AUDIO_OFF; + tea->stereo=1; + /* left=right=0x27<<10, bass=treble=0x07<<12 */ + tea6300_write(client, TEA6300_FA, 0x3f ); /* fader off */ + tea6300_write(client, TEA6300_S , TEA6300_S_GMU); /* mute */ + tea6300_set(client); +} + +static void tea6300_audio(struct i2c_client *client, int mode) +{ + struct tea6300 *tea = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tea6300_audio:%d (T,R,E,I,O)\n",mode); + tea->mode=mode; + if (mode==AUDIO_OFF) { /* just mute it */ + tea6300_write(client, TEA6300_S, TEA6300_S_GMU); + return; + } + switch(mode) { + case AUDIO_TUNER: + tea6300_write(client, TEA6300_S, TEA6300_S_SA); + break; + case AUDIO_RADIO: + tea6300_write(client, TEA6300_S, TEA6300_S_SB); + break; + case AUDIO_EXTERN: + tea6300_write(client, TEA6300_S, TEA6300_S_SC); + break; + } +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tea6300_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tea6300 *tea; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); + if (!tea) + return -ENOMEM; + memset(tea,0,sizeof *tea); + do_tea6300_init(client); + + MOD_INC_USE_COUNT; + strcpy(client->name,"TEA6300T"); + printk(KERN_INFO "tea6300: initialized\n"); + + i2c_attach_client(client); + return 0; +} + +static int tea6300_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tea6300_attach); + return 0; +} + +static int tea6300_detach(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + do_tea6300_init(client); + i2c_detach_client(client); + + kfree(tea); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tea6300 *tea = client->data; + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tea6300_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tea6300_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(tea->left,tea->right); + va->balance=(32768*MIN(tea->left,tea->right))/ + (va->volume ? va->volume : 1); + va->balance=(tea->leftright)? + (65535-va->balance) : va->balance; + va->bass = tea->bass; + va->treble = tea->treble; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + tea->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tea->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tea->bass = va->bass; + tea->treble = va->treble; + tea6300_set(client); + break; + } +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = tea->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = tea->right; + break; + case AUDC_SET_VOLUME_LEFT: + tea->left = *sarg; + tea6300_set(client); + break; + case AUDC_SET_VOLUME_RIGHT: + tea->right = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_BASS: + *sarg = tea->bass; + break; + case AUDC_SET_BASS: + tea->bass = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_TREBLE: + *sarg = tea->treble; + break; + case AUDC_SET_TREBLE: + tea->treble = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_STEREO: + *sarg = tea->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + tea->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; + /* TODO: make this write to the TDA9850? */ + break; + +/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to + case AUDC_NEWCHANNEL: it and it would require preserving state + case AUDC_GET_DC: huh?? (not used by bttv.c) +*/ +#endif + default: + /* nothing */ + } + return 0; +} + +static struct i2c_driver driver = { + "i2c tea6300 driver", + I2C_DRIVERID_TEA6300, + I2C_DF_NOTIFY, + tea6300_probe, + tea6300_detach, + tea6300_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tea6300_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tea6420.c linux/drivers/media/video/tea6420.c --- v2.4.0-test6/linux/drivers/media/video/tea6420.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tea6420.c Mon Aug 21 09:18:19 2000 @@ -0,0 +1,273 @@ +/* + * for the TEA6420 chip (only found on 3DFX (STB) TV/FM cards to the best + * of my knowledge) + * Copyright (C) 2000 Dave Stuart + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from tea6300 by . . . + * + * Copyright (c) 1998 Greg Alexander + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * Changes: + * Arnaldo Carvalho de Melo - 08/14/2000 + * - resource allocation fixes in tea6300_attach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + + +/* Addresses to scan */ +#define I2C_TEA6420 0x98 +static unsigned short normal_i2c[] = { + I2C_TEA6420 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +#define dprintk if (debug) printk + + +struct tea6420 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define TEA6420_S_SA 0x00 /* stereo A input */ +#define TEA6420_S_SB 0x01 /* stereo B */ +#define TEA6420_S_SC 0x02 /* stereo C */ +#define TEA6420_S_SD 0x03 /* stereo D */ +#define TEA6420_S_SE 0x04 /* stereo E */ +#define TEA6420_S_GMU 0x05 /* general mute */ + + +/* ******************************** * + * functions for talking to TEA6420 * + * ******************************** */ + +static int tea6420_write(struct i2c_client *client, int val) +{ + unsigned char buffer[2]; + int result; + +/* buffer[0] = addr; */ + buffer[0] = val; + result = i2c_master_send(client,buffer,1); + if (1 != result) { + printk(KERN_WARNING "tea6420: I/O error, trying (write +0x%x) result = %d\n", val, result); + return -1; + } + return 0; +} + + +static void do_tea6420_init(struct i2c_client *client) +{ + struct tea6420 *tea = client->data; + + tea->mode=AUDIO_OFF; + tea->stereo=1; + tea6420_write(client, TEA6420_S_GMU); /* mute */ +} + +static void tea6420_audio(struct i2c_client *client, int mode) +{ + struct tea6420 *tea = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tea6420_audio:%d (T,R,E,I,O)\n",mode); + tea->mode=mode; + if (mode==AUDIO_OFF) { /* just mute it */ + tea6420_write(client, TEA6420_S_GMU); + return; + } + switch(mode) { + case AUDIO_TUNER: + tea6420_write(client, TEA6420_S_SA); + break; + case AUDIO_RADIO: + tea6420_write(client, TEA6420_S_SB); + break; + case AUDIO_EXTERN: + tea6420_write(client, TEA6420_S_SC); + break; + } +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tea6420_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tea6420 *tea; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); + if (!tea) { + kfree(client); + return -ENOMEM; + } + memset(tea,0,sizeof *tea); + do_tea6420_init(client); + + MOD_INC_USE_COUNT; + strcpy(client->name,"TEA6420"); + printk(KERN_INFO "tea6420: initialized\n"); + + i2c_attach_client(client); + return 0; +} + +static int tea6420_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tea6420_attach); + return 0; +} + +static int tea6420_detach(struct i2c_client *client) +{ + struct tea6420 *tea = client->data; + + do_tea6420_init(client); + i2c_detach_client(client); + + kfree(tea); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tea6420_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tea6420_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tea6420_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; +/* va->volume=MAX(tea->left,tea->right); + va->balance=(32768*MIN(tea->left,tea->right))/ + (va->volume ? va->volume : 1); + va->balance=(tea->leftright)? + (65535-va->balance) : va->balance; + va->bass = tea->bass; + va->treble = tea->treble; +*/ break; + } + case VIDIOCSAUDIO: + { + +/* tea->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tea->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tea->bass = va->bass; + tea->treble = va->treble; + tea6420_set(client); +*/ break; + } + +default: + /* nothing */ + } + return 0; +} + +static struct i2c_driver driver = { + "i2c tea6420 driver", + I2C_DRIVERID_TEA6420, + I2C_DF_NOTIFY, + tea6420_probe, + tea6420_detach, + tea6420_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tea6420_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tuner-3036.c linux/drivers/media/video/tuner-3036.c --- v2.4.0-test6/linux/drivers/media/video/tuner-3036.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tuner-3036.c Mon Feb 28 14:56:10 2000 @@ -0,0 +1,227 @@ +/* + * Driver for Philips SAB3036 "CITAC" tuner control chip. + * + * Author: Phil Blundell + * + * The SAB3036 is just about different enough from the chips that + * tuner.c copes with to make it not worth the effort to crowbar + * the support into that file. So instead we have a separate driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tuner.h" + +static int debug; /* insmod parameter */ +static int this_adap; + +static struct i2c_client client_template; + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x60, 0x61, I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* ---------------------------------------------------------------------- */ + +static unsigned char +tuner_getstatus (struct i2c_client *c) +{ + unsigned char byte; + if (i2c_master_recv(c, &byte, 1) != 1) + printk(KERN_ERR "tuner-3036: I/O error.\n"); + return byte; +} + +#define TUNER_FL 0x80 + +static int +tuner_islocked (struct i2c_client *c) +{ + return (tuner_getstatus(c) & TUNER_FL); +} + +/* ---------------------------------------------------------------------- */ + +static void +set_tv_freq(struct i2c_client *c, int freq) +{ + u16 div = ((freq * 20) / 16); + unsigned long give_up = jiffies + HZ; + unsigned char buffer[2]; + + if (debug) + printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div); + + /* Select high tuning current */ + buffer[0] = 0x29; + buffer[1] = 0x3e; + + if (i2c_master_send(c, buffer, 2) != 2) + printk("tuner: i2c i/o error 1\n"); + + buffer[0] = 0x80 | ((div>>8) & 0x7f); + buffer[1] = div & 0xff; + + if (i2c_master_send(c, buffer, 2) != 2) + printk("tuner: i2c i/o error 2\n"); + + while (!tuner_islocked(c) && time_before(jiffies, give_up)) + schedule(); + + if (!tuner_islocked(c)) + printk(KERN_WARNING "tuner: failed to achieve PLL lock\n"); + + /* Select low tuning current and engage AFC */ + buffer[0] = 0x29; + buffer[1] = 0xb2; + + if (i2c_master_send(c, buffer, 2) != 2) + printk("tuner: i2c i/o error 3\n"); + + if (debug) + printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c)); +} + +/* ---------------------------------------------------------------------- */ + +static int +tuner_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 }; + + struct i2c_client *client; + + if (this_adap > 0) + return -1; + this_adap++; + + client_template.adapter = adap; + client_template.addr = addr; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) + return -ENOMEM; + memcpy(client, &client_template, sizeof(struct i2c_client)); + + printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client)); + + i2c_attach_client(client); + MOD_INC_USE_COUNT; + + if (i2c_master_send(client, buffer, 2) != 2) + printk("tuner: i2c i/o error 1\n"); + if (i2c_master_send(client, buffer+2, 2) != 2) + printk("tuner: i2c i/o error 2\n"); + if (i2c_master_send(client, buffer+4, 2) != 2) + printk("tuner: i2c i/o error 3\n"); + return 0; +} + +static int +tuner_detach(struct i2c_client *c) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + int *iarg = (int*)arg; + + switch (cmd) + { + case TUNER_SET_TVFREQ: + set_tv_freq(client, *iarg); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int +tuner_probe(struct i2c_adapter *adap) +{ + this_adap = 0; + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_LP)) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver +i2c_driver_tuner = +{ + "sab3036", /* name */ + I2C_DRIVERID_SAB3036, /* ID */ + I2C_DF_NOTIFY, + tuner_probe, + tuner_detach, + tuner_command +}; + +static struct i2c_client client_template = +{ + "SAB3036", /* name */ + -1, + 0, + 0, + NULL, + &i2c_driver_tuner +}; + +EXPORT_NO_SYMBOLS; + +int __init +tuner3036_init(void) +{ + i2c_add_driver(&i2c_driver_tuner); + return 0; +} + +void __exit +tuner3036_exit(void) +{ + i2c_del_driver(&i2c_driver_tuner); +} + +MODULE_DESCRIPTION("SAB3036 tuner driver"); +MODULE_AUTHOR("Philip Blundell "); +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug,"Enable debugging output"); + +module_init(tuner3036_init); +module_exit(tuner3036_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tuner.c linux/drivers/media/video/tuner.c --- v2.4.0-test6/linux/drivers/media/video/tuner.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tuner.c Tue Jul 18 22:35:33 2000 @@ -0,0 +1,451 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tuner.h" +#include "audiochip.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +static int debug = 0; /* insmod parameter */ +static int type = -1; /* insmod parameter */ + +static int addr = 0; +static int this_adap; + +#define dprintk if (debug) printk + +MODULE_PARM(debug,"i"); +MODULE_PARM(type,"i"); +MODULE_PARM(addr,"i"); + +struct tuner +{ + int type; /* chip type */ + int freq; /* keep track of the current settings */ + int std; + + int radio; + int mode; /* PAL(0)/SECAM(1) mode (PHILIPS_SECAM only) */ +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +/* ---------------------------------------------------------------------- */ + +struct tunertype +{ + char *name; + unsigned char Vendor; + unsigned char Type; + + unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */ + unsigned short thresh2; + unsigned char VHF_L; + unsigned char VHF_H; + unsigned char UHF; + unsigned char config; + unsigned short IFPCoff; + unsigned char mode; /* mode change value (tested PHILIPS_SECAM only) */ + /* 0x01 -> ??? no change ??? */ + /* 0x02 -> PAL BDGHI / SECAM L */ + /* 0x04 -> ??? PAL others / SECAM others ??? */ + int capability; +}; + +/* + * 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,623}, + { "Philips PAL_I", Philips, PAL_I, + 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, + { "Philips NTSC", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, + { "Philips SECAM", Philips, SECAM, + 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623,0x02}, + { "NoTuner", NoTuner, NOTUNER, + 0,0,0x00,0x00,0x00,0x00,0x00,000}, + { "Philips PAL", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, + { "Temic NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, + { "Temic PAL_I", TEMIC, PAL_I, + 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, + { "Temic 4036 FY5 NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, + { "Alps HSBH1", TEMIC, NTSC, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBE1",TEMIC,PAL, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, + { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, + { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, + { "Temic 4006FH5", TEMIC, PAL_I, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, +}; +#define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) + +/* ---------------------------------------------------------------------- */ + +static int tuner_getstatus(struct i2c_client *c) +{ + unsigned char byte; + + if (1 != i2c_master_recv(c,&byte,1)) + return 0; + return byte; +} + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_MODE 0x38 +#define TUNER_AFC 0x07 + +static int tuner_islocked (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_FL); +} + +static int tuner_afcstatus (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_AFC) - 2; +} + +#if 0 /* unused */ +static int tuner_mode (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_MODE) >> 3; +} +#endif + +static void set_tv_freq(struct i2c_client *c, int freq) +{ + u8 config; + u16 div; + struct tunertype *tun; + struct tuner *t = c->data; + unsigned char buffer[4]; + int rc; + + if (t->type == -1) { + printk("tuner: tuner type not set\n"); + return; + } + + tun=&tuners[t->type]; + if (freq < tun->thresh1) + config = tun->VHF_L; + else if (freq < tun->thresh2) + config = tun->VHF_H; + else + config = tun->UHF; + +#if 1 // Fix colorstandard mode change + if (t->type == TUNER_PHILIPS_SECAM && t->mode) + config |= tun->mode; + else + config &= ~tun->mode; +#else + config &= ~tun->mode; +#endif + + div=freq + tun->IFPCoff; + + /* + * Philips FI1216MK2 remark from specification : + * for channel selection involving band switching, and to ensure + * smooth tuning to the desired channel without causing + * unnecessary charge pump action, it is recommended to consider + * the difference between wanted channel frequency and the + * current channel frequency. Unnecessary charge pump action + * will result in very low tuning voltage which may drive the + * oscillator to extreme conditions. + */ + /* + * Progfou: specification says to send config data before + * frequency in case (wanted frequency < current frequency). + */ + + if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { + buffer[0] = tun->config; + buffer[1] = config; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; + } else { + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; + } + + if (4 != (rc = i2c_master_send(c,buffer,4))) + printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); + +} + +static void set_radio_freq(struct i2c_client *c, int freq) +{ + u8 config; + u16 div; + struct tunertype *tun; + struct tuner *t = (struct tuner*)c->data; + unsigned char buffer[4]; + int rc; + + if (t->type == -1) { + printk("tuner: tuner type not set\n"); + return; + } + + tun=&tuners[t->type]; + config = 0xa5; + div=freq + (int)(16*10.7); + div&=0x7fff; + + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; + if (4 != (rc = i2c_master_send(c,buffer,4))) + printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); + + if (debug) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + + if (tuner_islocked (c)) + printk ("tuner: PLL locked\n"); + else + printk ("tuner: PLL not locked\n"); + + printk ("tuner: AFC: %d\n", tuner_afcstatus (c)); + } +} +/* ---------------------------------------------------------------------- */ + + +static int tuner_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tuner *t; + struct i2c_client *client; + + if (this_adap > 0) + return -1; + this_adap++; + + client_template.adapter = adap; + client_template.addr = addr; + + printk("tuner: chip found @ 0x%x\n",addr); + + if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); + if (NULL == t) { + kfree(client); + return -ENOMEM; + } + memset(t,0,sizeof(struct tuner)); + if (type >= 0 && type < TUNERS) { + t->type = type; + strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + } else { + t->type = -1; + } + i2c_attach_client(client); + MOD_INC_USE_COUNT; + + return 0; +} + +static int tuner_probe(struct i2c_adapter *adap) +{ + if (0 != addr) { + normal_i2c_range[0] = addr; + normal_i2c_range[1] = addr; + } + this_adap = 0; + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; +} + +static int tuner_detach(struct i2c_client *client) +{ + struct tuner *t = (struct tuner*)client->data; + + i2c_detach_client(client); + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tuner *t = (struct tuner*)client->data; + int *iarg = (int*)arg; +#if 0 + __u16 *sarg = (__u16*)arg; +#endif + + switch (cmd) { + + /* --- configuration --- */ + case TUNER_SET_TYPE: + if (t->type != -1) + return 0; + if (*iarg < 0 || *iarg >= TUNERS) + return 0; + t->type = *iarg; + dprintk("tuner: type set to %d (%s)\n", + t->type,tuners[t->type].name); + strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + break; + case AUDC_SET_RADIO: + t->radio = 1; + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + t->radio = 0; + if (t->type == TUNER_PHILIPS_SECAM) { + t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; + set_tv_freq(client,t->freq); + } + return 0; + } + case VIDIOCSFREQ: + { + unsigned long *v = arg; + + t->freq = *v; + if (t->radio) { + dprintk("tuner: radio freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_radio_freq(client,t->freq); + } else { + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(client,t->freq); + } + return 0; + } +#if 0 + /* --- old, obsolete interface --- */ + case TUNER_SET_TVFREQ: + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(client,*iarg); + t->radio = 0; + t->freq = *iarg; + break; + + case TUNER_SET_RADIOFREQ: + dprintk("tuner: radio freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_radio_freq(client,*iarg); + t->radio = 1; + t->freq = *iarg; + break; + case TUNER_SET_MODE: + if (t->type != TUNER_PHILIPS_SECAM) { + dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); + } else { + int mode=(*sarg==VIDEO_MODE_SECAM)?1:0; + dprintk("tuner: mode set to %d\n", *sarg); + t->mode = mode; + set_tv_freq(client,t->freq); + } + break; +#endif + default: + /* nothing */ + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver driver = { + "i2c TV tuner driver", + I2C_DRIVERID_TUNER, + I2C_DF_NOTIFY, + tuner_probe, + tuner_detach, + tuner_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +EXPORT_NO_SYMBOLS; + +int tuner_init_module(void) +{ + i2c_add_driver(&driver); + return 0; +} + +void tuner_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(tuner_init_module); +module_exit(tuner_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tuner.h linux/drivers/media/video/tuner.h --- v2.4.0-test6/linux/drivers/media/video/tuner.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tuner.h Thu Nov 18 19:25:28 1999 @@ -0,0 +1,57 @@ +/* + 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 TUNER_TEMIC_4036FY5_NTSC 8 +#define TUNER_ALPS_TSBH1_NTSC 9 +#define TUNER_ALPS_TSBE1_PAL 10 +#define TUNER_ALPS_TSBB5_PAL_I 11 +#define TUNER_ALPS_TSBE5_PAL 12 +#define TUNER_ALPS_TSBC5_PAL 13 + +#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 +#define Alps 4 + +#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ +#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ +#define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */ +#define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */ + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/tvmixer.c linux/drivers/media/video/tvmixer.c --- v2.4.0-test6/linux/drivers/media/video/tvmixer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/tvmixer.c Tue Jul 18 22:35:33 2000 @@ -0,0 +1,353 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "audiochip.h" + +#define DEV_MAX 4 + +static int debug = 0; +static int devnr = -1; + +MODULE_PARM(debug,"i"); +MODULE_PARM(devnr,"i"); + +/* ----------------------------------------------------------------------- */ + +struct TVMIXER { + struct i2c_client *dev; + int minor; + int count; +}; + +static struct TVMIXER devices[DEV_MAX]; + +static int tvmixer_adapters(struct i2c_adapter *adap); +static int tvmixer_clients(struct i2c_client *client); + +static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int tvmixer_open(struct inode *inode, struct file *file); +static int tvmixer_release(struct inode *inode, struct file *file); +static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin); + + +static struct i2c_driver driver = { + "tv card mixer driver", + 42 /* I2C_DRIVERID_FIXME */, + I2C_DF_DUMMY, + tvmixer_adapters, + tvmixer_clients, +}; + +static struct file_operations tvmixer_fops = { + owner: THIS_MODULE, + llseek: tvmixer_llseek, + ioctl: tvmixer_ioctl, + open: tvmixer_open, + release: tvmixer_release, +}; + +/* ----------------------------------------------------------------------- */ + +static int mix_to_v4l(int i) +{ + int r; + + r = ((i & 0xff) * 65536 + 50) / 100; + if (r > 65535) r = 65535; + if (r < 0) r = 0; + return r; +} + +static int v4l_to_mix(int i) +{ + int r; + + r = (i * 100 + 32768) / 65536; + if (r > 100) r = 100; + if (r < 0) r = 0; + return r | (r << 8); +} + +static int v4l_to_mix2(int l, int r) +{ + r = (r * 100 + 32768) / 65536; + if (r > 100) r = 100; + if (r < 0) r = 0; + l = (l * 100 + 32768) / 65536; + if (l > 100) l = 100; + if (l < 0) l = 0; + return (r << 8) | l; +} + +static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct video_audio va; + int left,right,ret,val = 0; + struct TVMIXER *mix = file->private_data; + struct i2c_client *client = mix->dev; + + if (NULL == client) + return -ENODEV; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "tv card", sizeof(info.id)); + strncpy(info.name, client->name, sizeof(info.name)); + info.modify_counter = 42 /* FIXME */; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "tv card", sizeof(info.id)); + strncpy(info.name, client->name, sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + if (get_user(val, (int *)arg)) + return -EFAULT; + + /* read state */ + memset(&va,0,sizeof(va)); + client->driver->command(client,VIDIOCGAUDIO,&va); + + switch (cmd) { + case MIXER_READ(SOUND_MIXER_RECMASK): + case MIXER_READ(SOUND_MIXER_CAPS): + case MIXER_READ(SOUND_MIXER_RECSRC): + case MIXER_WRITE(SOUND_MIXER_RECSRC): + ret = 0; + break; + + case MIXER_READ(SOUND_MIXER_STEREODEVS): + ret = SOUND_MASK_VOLUME; + break; + case MIXER_READ(SOUND_MIXER_DEVMASK): + ret = SOUND_MASK_VOLUME; + if (va.flags & VIDEO_AUDIO_BASS) + ret |= SOUND_MASK_BASS; + if (va.flags & VIDEO_AUDIO_TREBLE) + ret |= SOUND_MASK_TREBLE; + break; + + case MIXER_WRITE(SOUND_MIXER_VOLUME): + left = mix_to_v4l(val); + right = mix_to_v4l(val >> 8); + va.volume = MAX(left,right); + va.balance = (32768*MIN(left,right)) / (va.volume ? va.volume : 1); + va.balance = (leftdriver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_VOLUME): + left = (MIN(65536 - va.balance,32768) * + va.volume) / 32768; + right = (MIN(va.balance,32768) * + va.volume) / 32768; + ret = v4l_to_mix2(left,right); + break; + + case MIXER_WRITE(SOUND_MIXER_BASS): + va.bass = mix_to_v4l(val); + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_BASS): + ret = v4l_to_mix(va.bass); + break; + + case MIXER_WRITE(SOUND_MIXER_TREBLE): + va.treble = mix_to_v4l(val); + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_TREBLE): + ret = v4l_to_mix(va.treble); + break; + + default: + return -EINVAL; + } + if (put_user(ret, (int *)arg)) + return -EFAULT; + return 0; +} + +static int tvmixer_open(struct inode *inode, struct file *file) +{ + int i, minor = MINOR(inode->i_rdev); + struct TVMIXER *mix = NULL; + struct i2c_client *client = NULL; + + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].minor == minor) { + mix = devices+i; + client = mix->dev; + break; + } + } + + if (NULL == client) + return -ENODEV; + + /* lock bttv in memory while the mixer is in use */ + file->private_data = mix; + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); + return 0; +} + +static int tvmixer_release(struct inode *inode, struct file *file) +{ + struct TVMIXER *mix = file->private_data; + struct i2c_client *client; + + client = mix->dev; + if (NULL == client) { + return -ENODEV; + } + + if (client->adapter->dec_use) + client->adapter->dec_use(client->adapter); + return 0; +} + +static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* ----------------------------------------------------------------------- */ + +static int tvmixer_adapters(struct i2c_adapter *adap) +{ + return 0; +} + +static int tvmixer_clients(struct i2c_client *client) +{ + struct video_audio va; + int i,minor; + + /* TV card ??? */ + if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) { + if (debug) + printk("tvmixer: %s is not a tv card\n", + client->adapter->name); + return -1; + } + printk("tvmixer: debug: %s\n",client->name); + + /* unregister ?? */ + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].dev == client) { + /* unregister */ + unregister_sound_mixer(devices[i].minor); + devices[i].dev = NULL; + devices[i].minor = -1; + printk("tvmixer: %s unregistered (#1)\n",client->name); + return 0; + } + } + + /* look for a free slot */ + for (i = 0; i < DEV_MAX; i++) + if (NULL == devices[i].dev) + break; + if (i == DEV_MAX) { + printk(KERN_WARNING "tvmixer: DEV_MAX too small\n"); + return -1; + } + + /* audio chip with mixer ??? */ + if (NULL == client->driver->command) { + if (debug) + printk("tvmixer: %s: driver->command is NULL\n", + client->driver->name); + return -1; + } + memset(&va,0,sizeof(va)); + if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) { + if (debug) + printk("tvmixer: %s: VIDIOCGAUDIO failed\n", + client->name); + return -1; + } + if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) { + if (debug) + printk("tvmixer: %s: has no volume control\n", + client->name); + return -1; + } + + /* everything is fine, register */ + if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) { + printk(KERN_ERR "tvmixer: cannot allocate mixer device\n"); + return -1; + } + + devices[i].minor = minor; + devices[i].count = 0; + devices[i].dev = client; + printk("tvmixer: %s (%s) registered with minor %d\n", + client->name,client->adapter->name,minor); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int tvmixer_init_module(void) +{ + int i; + + for (i = 0; i < DEV_MAX; i++) + devices[i].minor = -1; + i2c_add_driver(&driver); + return 0; +} + +void tvmixer_cleanup_module(void) +{ + int i; + + i2c_del_driver(&driver); + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].minor != -1) { + unregister_sound_mixer(devices[i].minor); + printk("tvmixer: %s unregistered (#2)\n", + devices[i].dev->name); + } + } +} + +module_init(tvmixer_init_module); +module_exit(tvmixer_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c --- v2.4.0-test6/linux/drivers/media/video/videodev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/videodev.c Tue Jul 18 22:35:33 2000 @@ -0,0 +1,581 @@ +/* + * 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: 20000516 Claudio Matsuoka + * - Added procfs support + */ + +#include +#include +#include +#include +#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]; + + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + +#include + +struct videodev_proc_data { + struct list_head proc_list; + char name[16]; + struct video_device *vdev; + struct proc_dir_entry *proc_entry; +}; + +static struct proc_dir_entry *video_dev_proc_entry = NULL; +struct proc_dir_entry *video_proc_entry = NULL; +EXPORT_SYMBOL(video_proc_entry); +LIST_HEAD(videodev_proc_list); + +#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ + + +#ifdef CONFIG_VIDEO_BWQCAM +extern int init_bw_qcams(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_CPIA +extern int cpia_init(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_PLANB +extern int init_planbs(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_ZORAN +extern int init_zoran_cards(struct video_init *); +#endif + +static struct video_init video_init_list[]={ +#ifdef CONFIG_VIDEO_BWQCAM + {"bw-qcam", init_bw_qcams}, +#endif +#ifdef CONFIG_VIDEO_CPIA + {"cpia", cpia_init}, +#endif +#ifdef CONFIG_VIDEO_PLANB + {"planb", init_planbs}, +#endif +#ifdef CONFIG_VIDEO_ZORAN + {"zoran", init_zoran_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) +{ + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + if(vfl->read) + return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); + else + return -EINVAL; +} + + +/* + * 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) +{ + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + if(vfl->write) + return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); + else + return 0; +} + +/* + * Poll to see if we're readable, can probably be used for timing on incoming + * frames, etc.. + */ + +static unsigned int video_poll(struct file *file, poll_table * wait) +{ + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + if(vfl->poll) + return vfl->poll(vfl, file, wait); + else + return 0; +} + + +/* + * 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) { + char modname[20]; + + sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor); + request_module(modname); + 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; + lock_kernel(); + vfl=video_device[MINOR(inode->i_rdev)]; + if(vfl->close) + vfl->close(vfl); + vfl->busy=0; + unlock_kernel(); + 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 + */ + + +int video_mmap(struct file *file, struct vm_area_struct *vma) +{ + int ret = -EINVAL; + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + if(vfl->mmap) { + lock_kernel(); + ret = vfl->mmap(vfl, (char *)vma->vm_start, + (unsigned long)(vma->vm_end-vma->vm_start)); + unlock_kernel(); + } + return ret; +} + +/* + * /proc support + */ + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + +/* Hmm... i'd like to see video_capability information here, but + * how can I access it (without changing the other drivers? -claudio + */ +static int videodev_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *out = page; + struct video_device *vfd = data; + struct videodev_proc_data *d; + struct list_head *tmp; + int len; + char c = ' '; + + list_for_each (tmp, &videodev_proc_list) { + d = list_entry(tmp, struct videodev_proc_data, proc_list); + if (vfd == d->vdev) + break; + } + + /* Sanity check */ + if (tmp == &videodev_proc_list) + goto skip; + +#define PRINT_VID_TYPE(x) do { if (vfd->type & x) \ + out += sprintf (out, "%c%s", c, #x); c='|';} while (0) + + out += sprintf (out, "name : %s\n", vfd->name); + out += sprintf (out, "type :"); + PRINT_VID_TYPE(VID_TYPE_CAPTURE); + PRINT_VID_TYPE(VID_TYPE_TUNER); + PRINT_VID_TYPE(VID_TYPE_TELETEXT); + PRINT_VID_TYPE(VID_TYPE_OVERLAY); + PRINT_VID_TYPE(VID_TYPE_CHROMAKEY); + PRINT_VID_TYPE(VID_TYPE_CLIPPING); + PRINT_VID_TYPE(VID_TYPE_FRAMERAM); + PRINT_VID_TYPE(VID_TYPE_SCALES); + PRINT_VID_TYPE(VID_TYPE_MONOCHROME); + PRINT_VID_TYPE(VID_TYPE_SUBCAPTURE); + PRINT_VID_TYPE(VID_TYPE_MPEG_DECODER); + PRINT_VID_TYPE(VID_TYPE_MPEG_ENCODER); + PRINT_VID_TYPE(VID_TYPE_MJPEG_DECODER); + PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER); + out += sprintf (out, "\n"); + out += sprintf (out, "hardware : 0x%x\n", vfd->hardware); +#if 0 + out += sprintf (out, "channels : %d\n", d->vcap.channels); + out += sprintf (out, "audios : %d\n", d->vcap.audios); + out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth); + out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight); + out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth); + out += sprintf (out, "minheight : %d\n", d->vcap.minheight); +#endif + +skip: + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + + return len; +} + +static void videodev_proc_create(void) +{ + video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root); + + if (video_proc_entry == NULL) { + printk("video_dev: unable to initialise /proc/video\n"); + return; + } + + video_proc_entry->owner = THIS_MODULE; + video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry); + + if (video_dev_proc_entry == NULL) { + printk("video_dev: unable to initialise /proc/video/dev\n"); + return; + } + + video_dev_proc_entry->owner = THIS_MODULE; +} + +#ifdef MODULE +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +static void videodev_proc_destroy(void) +{ + if (video_dev_proc_entry != NULL) + remove_proc_entry("dev", video_proc_entry); + + if (video_proc_entry != NULL) + remove_proc_entry("video", &proc_root); +} +#endif +#endif + +static void videodev_proc_create_dev (struct video_device *vfd, char *name) +{ + struct videodev_proc_data *d; + struct proc_dir_entry *p; + + if (video_dev_proc_entry == NULL) + return; + + d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL); + if (!d) + return; + + p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry); + p->data = vfd; + p->read_proc = videodev_proc_read; + + d->proc_entry = p; + d->vdev = vfd; + strcpy (d->name, name); + + /* How can I get capability information ? */ + + list_add (&d->proc_list, &videodev_proc_list); +} + +static void videodev_proc_destroy_dev (struct video_device *vfd) +{ + struct list_head *tmp; + struct videodev_proc_data *d; + + list_for_each (tmp, &videodev_proc_list) { + d = list_entry(tmp, struct videodev_proc_data, proc_list); + if (vfd == d->vdev) { + remove_proc_entry(d->name, video_dev_proc_entry); + list_del (&d->proc_list); + kfree (d); + break; + } + } +} + +#endif /* CONFIG_VIDEO_PROC_FS */ + +extern struct file_operations video_fops; + +/** + * video_register_device - register video4linux devices + * @vfd: video device structure we want to register + * @type: type of device to register + * FIXME: needs a semaphore on 2.3.x + * + * The registration code assigns minor numbers based on the type + * requested. -ENFILE is returned in all the device slots for this + * category are full. If not then the minor field is set and the + * driver initialize function is called (if non %NULL). + * + * Zero is returned on success. + * + * Valid types are + * + * %VFL_TYPE_GRABBER - A frame grabber + * + * %VFL_TYPE_VTX - A teletext device + * + * %VFL_TYPE_VBI - Vertical blank data (undecoded) + * + * %VFL_TYPE_RADIO - A radio card + */ + +int video_register_device(struct video_device *vfd, int type) +{ + int i=0; + int base; + int err; + int end; + char *name_base; + + switch(type) + { + case VFL_TYPE_GRABBER: + base=0; + end=64; + name_base = "video"; + break; + case VFL_TYPE_VTX: + base=192; + end=224; + name_base = "vtx"; + break; + case VFL_TYPE_VBI: + base=224; + end=240; + name_base = "vbi"; + break; + case VFL_TYPE_RADIO: + base=64; + end=128; + name_base = "radio"; + break; + default: + return -1; + } + + for(i=base;iminor=i; + /* The init call may sleep so we book the slot out + then call */ + MOD_INC_USE_COUNT; + if(vfd->initialize) + { + err=vfd->initialize(vfd); + if(err<0) + { + video_device[i]=NULL; + MOD_DEC_USE_COUNT; + return err; + } + } + sprintf (name, "v4l/%s%d", name_base, i - base); + /* + * Start the device root only. Anything else + * has serious privacy issues. + */ + vfd->devfs_handle = + devfs_register (NULL, name, DEVFS_FL_DEFAULT, + VIDEO_MAJOR, vfd->minor, + S_IFCHR | S_IRUSR | S_IWUSR, + &video_fops, NULL); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + sprintf (name, "%s%d", name_base, i - base); + videodev_proc_create_dev (vfd, name); +#endif + + + return 0; + } + } + return -ENFILE; +} + +/** + * video_unregister_device - unregister a video4linux device + * @vfd: the device to unregister + * + * This unregisters the passed device and deassigns the minor + * number. Future open calls will be met with errors. + */ + +void video_unregister_device(struct video_device *vfd) +{ + if(video_device[vfd->minor]!=vfd) + panic("vfd: bad unregister"); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + videodev_proc_destroy_dev (vfd); +#endif + + devfs_unregister (vfd->devfs_handle); + video_device[vfd->minor]=NULL; + MOD_DEC_USE_COUNT; +} + + +static struct file_operations video_fops= +{ + owner: THIS_MODULE, + llseek: video_lseek, + read: video_read, + write: video_write, + ioctl: video_ioctl, + mmap: video_mmap, + open: video_open, + release: video_release, + poll: video_poll, +}; + +/* + * Initialise video for linux + */ + +int __init videodev_init(void) +{ + struct video_init *vfli = video_init_list; + + printk(KERN_INFO "Linux video capture interface: v1.00\n"); + if(devfs_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 + */ + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + videodev_proc_create (); +#endif + + while(vfli->init!=NULL) + { + vfli->init(vfli); + vfli++; + } + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return videodev_init(); +} + +void cleanup_module(void) +{ +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + videodev_proc_destroy (); +#endif + + devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture"); +} + +#endif + +EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(video_unregister_device); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/vino.c linux/drivers/media/video/vino.c --- v2.4.0-test6/linux/drivers/media/video/vino.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/vino.c Fri Feb 25 10:26:42 2000 @@ -0,0 +1,275 @@ +/* $Id: vino.c,v 1.5 1999/10/09 00:01:14 ralf Exp $ + * drivers/char/vino.c + * + * (incomplete) Driver for the Vino Video input system found in SGI Indys. + * + * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) + * + * This isn't complete yet, please don't expect any video until I've written + * some more code. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vino.h" + +struct vino_device { + struct video_device vdev; + + unsigned long chan; +#define VINO_CHAN_A 0 +#define VINO_CHAN_B 1 + + unsigned long flags; +#define VINO_DMA_ACTIVE (1<<0) +}; + +/* We can actually receive TV and IndyCam input at the same time. Believe it or + * not.. + */ +static struct vino_device vino[2]; + +/* Those registers have to be accessed by either *one* 64 bit write or *one* 64 + * bit read. We need some asm to fix this. We can't use mips3 as standard + * because we just save 32 bits at context switch. + */ + +static __inline__ unsigned long long vino_reg_read(unsigned long addr) +{ + unsigned long long ret __attribute__ ((aligned (64))); + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "sd\t$1,(%1)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (virt_addr), + "r" (&ret) + :"$1"); + restore_flags(flags); + + return ret; +} + +static __inline__ void vino_reg_write(unsigned long long value, + unsigned long addr) +{ + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + /* we might lose the upper parts of the registers which are not saved + * if there comes an interrupt in our way, play safe */ + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "sd\t$1,(%1)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (&value), + "r" (virt_addr) + :"$1"); + restore_flags(flags); +} + +static __inline__ void vino_reg_and(unsigned long long value, + unsigned long addr) +{ + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "ld\t$2,(%1)\n\t" + "and\t$1,$1,$2\n\t" + "sd\t$1,(%0)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (virt_addr), + "r" (&value) + :"$1","$2"); + restore_flags(flags); +} + +static __inline__ void vino_reg_or(unsigned long long value, + unsigned long addr) +{ + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "ld\t$2,(%1)\n\t" + "or\t$1,$1,$2\n\t" + "sd\t$1,(%0)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (virt_addr), + "r" (&value) + :"$1","$2"); + restore_flags(flags); +} + +static int vino_dma_setup(void) +{ + return 0; +} + +static void vino_dma_stop(void) +{ + +} + +static int vino_init(void) +{ + unsigned long ret; + unsigned short rev, id; + unsigned long long foo; + unsigned long *bar; + + bar = (unsigned long *) &foo; + + ret = vino_reg_read(VINO_REVID); + + rev = (ret & VINO_REVID_REV_MASK); + id = (ret & VINO_REVID_ID_MASK) >> 4; + + printk("Vino: ID:%02hx Rev:%02hx\n", id, rev); + + foo = vino_reg_read(VINO_A_DESC_DATA0); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_A_DESC_DATA1); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_A_DESC_DATA2); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_A_DESC_DATA3); + printk("0x%lx", bar[0]); + printk("%lx\n", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA0); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA1); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA2); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA3); + printk("0x%lx", bar[0]); + printk("%lx\n", bar[1]); + + return 0; +} + +static void vino_dma_go(struct vino_device *v) +{ + +} + +/* Reset the vino back to default state */ + +static void vino_setup(struct vino_device *v) +{ + +} + +static int vino_open(struct video_device *dev, int flags) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void vino_close(struct video_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + return 0; +} + +static int vino_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + return 0; +} + +static struct video_device vino_dev = { + "Vino IndyCam/TV", + VID_TYPE_CAPTURE, + VID_HARDWARE_VINO, + vino_open, + vino_close, + NULL, /* vino_read */ + NULL, /* vino_write */ + NULL, /* vino_poll */ + vino_ioctl, + vino_mmap, + NULL, /* vino_init */ + NULL, + 0, + 0 +}; + +int __init init_vino(struct video_device *dev) +{ + int err; + + err = vino_init(); + if (err) + return err; + +#if 0 + if (video_register_device(&vinodev, VFL_TYPE_GRABBER) == -1) { + return -ENODEV; + } +#endif + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + int err; + + err = vino_init(); + if (err) + return err; + + return 0; +} + +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/zr36057.h linux/drivers/media/video/zr36057.h --- v2.4.0-test6/linux/drivers/media/video/zr36057.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36057.h Mon Jul 5 20:09:40 1999 @@ -0,0 +1,168 @@ +/* + zr36057.h - zr36057 register offsets + + Copyright (C) 1998 Dave Perks + + 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 _ZR36057_H_ +#define _ZR36057_H_ + + +/* Zoran ZR36057 registers */ + +#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ +#define ZR36057_VFEHCR_HSPol (1<<30) +#define ZR36057_VFEHCR_HStart 10 +#define ZR36057_VFEHCR_HEnd 0 +#define ZR36057_VFEHCR_Hmask 0x3ff + +#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ +#define ZR36057_VFEVCR_VSPol (1<<30) +#define ZR36057_VFEVCR_VStart 10 +#define ZR36057_VFEVCR_VEnd 0 +#define ZR36057_VFEVCR_Vmask 0x3ff + +#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ +#define ZR36057_VFESPFR_ExtFl (1<<26) +#define ZR36057_VFESPFR_TopField (1<<25) +#define ZR36057_VFESPFR_VCLKPol (1<<24) +#define ZR36057_VFESPFR_HFilter 21 +#define ZR36057_VFESPFR_HorDcm 14 +#define ZR36057_VFESPFR_VerDcm 8 +#define ZR36057_VFESPFR_DispMode 6 +#define ZR36057_VFESPFR_YUV422 (0<<3) +#define ZR36057_VFESPFR_RGB888 (1<<3) +#define ZR36057_VFESPFR_RGB565 (2<<3) +#define ZR36057_VFESPFR_RGB555 (3<<3) +#define ZR36057_VFESPFR_ErrDif (1<<2) +#define ZR36057_VFESPFR_Pack24 (1<<1) +#define ZR36057_VFESPFR_LittleEndian (1<<0) + +#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ + +#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ + +#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ +#define ZR36057_VSSFGR_DispStride 16 +#define ZR36057_VSSFGR_VidOvf (1<<8) +#define ZR36057_VSSFGR_SnapShot (1<<1) +#define ZR36057_VSSFGR_FrameGrab (1<<0) + +#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ +#define ZR36057_VDCR_VidEn (1<<31) +#define ZR36057_VDCR_MinPix 24 +#define ZR36057_VDCR_Triton (1<<24) +#define ZR36057_VDCR_VidWinHt 12 +#define ZR36057_VDCR_VidWinWid 0 + +#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ + +#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ + +#define ZR36057_OCR 0x024 /* Overlay Control Register */ +#define ZR36057_OCR_OvlEnable (1 << 15) +#define ZR36057_OCR_MaskStride 0 + +#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ +#define ZR36057_SPGPPCR_SoftReset (1<<24) + +#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ + +#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ + +#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ +#define ZR36057_MCTCR_CodTime (1 << 30) +#define ZR36057_MCTCR_CEmpty (1 << 29) +#define ZR36057_MCTCR_CFlush (1 << 28) +#define ZR36057_MCTCR_CodGuestID 20 +#define ZR36057_MCTCR_CodGuestReg 16 + +#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ + +#define ZR36057_ISR 0x03c /* Interrupt Status Register */ +#define ZR36057_ISR_GIRQ1 (1<<30) +#define ZR36057_ISR_GIRQ0 (1<<29) +#define ZR36057_ISR_CodRepIRQ (1<<28) +#define ZR36057_ISR_JPEGRepIRQ (1<<27) + +#define ZR36057_ICR 0x040 /* Interrupt Control Register */ +#define ZR36057_ICR_GIRQ1 (1<<30) +#define ZR36057_ICR_GIRQ0 (1<<29) +#define ZR36057_ICR_CodRepIRQ (1<<28) +#define ZR36057_ICR_JPEGRepIRQ (1<<27) +#define ZR36057_ICR_IntPinEn (1<<24) + +#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ +#define ZR36057_I2CBR_SDA (1<<1) +#define ZR36057_I2CBR_SCL (1<<0) + +#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ +#define ZR36057_JMC_JPG (1 << 31) +#define ZR36057_JMC_JPGExpMode (0 << 29) +#define ZR36057_JMC_JPGCmpMode (1 << 29) +#define ZR36057_JMC_MJPGExpMode (2 << 29) +#define ZR36057_JMC_MJPGCmpMode (3 << 29) +#define ZR36057_JMC_RTBUSY_FB (1 << 6) +#define ZR36057_JMC_Go_en (1 << 5) +#define ZR36057_JMC_SyncMstr (1 << 4) +#define ZR36057_JMC_Fld_per_buff (1 << 3) +#define ZR36057_JMC_VFIFO_FB (1 << 2) +#define ZR36057_JMC_CFIFO_FB (1 << 1) +#define ZR36057_JMC_Stll_LitEndian (1 << 0) + +#define ZR36057_JPC 0x104 /* JPEG Process Control */ +#define ZR36057_JPC_P_Reset (1 << 7) +#define ZR36057_JPC_CodTrnsEn (1 << 5) +#define ZR36057_JPC_Active (1 << 0) + +#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ +#define ZR36057_VSP_VsyncSize 16 +#define ZR36057_VSP_FrmTot 0 + +#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ +#define ZR36057_HSP_HsyncStart 16 +#define ZR36057_HSP_LineTot 0 + +#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ +#define ZR36057_FHAP_NAX 16 +#define ZR36057_FHAP_PAX 0 + +#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ +#define ZR36057_FVAP_NAY 16 +#define ZR36057_FVAP_PAY 0 + +#define ZR36057_FPP 0x118 /* Field Process Parameters */ +#define ZR36057_FPP_Odd_Even (1 << 0) + +#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ + +#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ + +#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ +#define ZR36057_JCGI_JPEGuestID 4 +#define ZR36057_JCGI_JPEGuestReg 0 + +#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ + +#define ZR36057_POR 0x200 /* Post Office Register */ +#define ZR36057_POR_POPen (1<<25) +#define ZR36057_POR_POTime (1<<24) +#define ZR36057_POR_PODir (1<<23) + +#define ZR36057_STR 0x300 /* "Still" Transfer Register */ + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/zr36060.h linux/drivers/media/video/zr36060.h --- v2.4.0-test6/linux/drivers/media/video/zr36060.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36060.h Mon Jul 5 20:09:40 1999 @@ -0,0 +1,35 @@ +/* + zr36060.h - zr36060 register offsets + + Copyright (C) 1998 Dave Perks + + 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 _ZR36060_H_ +#define _ZR36060_H_ + + +/* Zoran ZR36060 registers */ + +#define ZR36060_LoadParameters 0x000 +#define ZR36060_Load (1<<7) +#define ZR36060_SyncRst (1<<0) + +#define ZR36060_CodeFifoStatus 0x001 +#define ZR36060_Load (1<<7) +#define ZR36060_SyncRst (1<<0) + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- v2.4.0-test6/linux/drivers/media/video/zr36120.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36120.c Wed Jul 5 10:56:13 2000 @@ -0,0 +1,2086 @@ +/* + zr36120.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tuner.h" +#include "zr36120.h" +#include "zr36120_mem.h" + +/* mark an required function argument unused - lintism */ +#define UNUSED(x) (void)(x) + +/* sensible default */ +#ifndef CARDTYPE +#define CARDTYPE 0 +#endif + +/* Anybody who uses more than four? */ +#define ZORAN_MAX 4 + +static unsigned int triton1=0; /* triton1 chipset? */ +static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; + +MODULE_AUTHOR("Pauline Middelink "); +MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); +MODULE_PARM(triton1,"i"); +MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i"); + +static int zoran_cards; +static struct zoran zorans[ZORAN_MAX]; + +/* + * the meaning of each element can be found in zr36120.h + * Determining the value of gpdir/gpval can be tricky. The + * best way is to run the card under the original software + * and read the values from the general purpose registers + * 0x28 and 0x2C. How you do that is left as an exercise + * to the impatient reader :) + */ +#define T 1 /* to seperate the bools from the ints */ +#define F 0 +static struct tvcard tvcards[] = { + /* reported working by */ +/*0*/ { "Trust Victor II", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by */ +/*1*/ { "Aitech WaveWatcher TV-PCI", + 3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } }, + /* reported working by ? */ +/*2*/ { "Genius Video Wonder PCI Video Capture Card", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by */ +/*3*/ { "Guillemot Maxi-TV PCI", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by "Craig Whitmore */ +/*4*/ { "Quadrant Buster", + 3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } }, + /* a debug entry which has all inputs mapped */ +/*5*/ { "ZR36120 based framegrabber (all inputs enabled)", + 6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } } +}; +#undef T +#undef F +#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0])) + +#ifdef __sparc__ +#define ENDIANESS 0 +#else +#define ENDIANESS ZORAN_VFEC_LE +#endif + +static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = { +/* n/a */ { "n/a", 0, 0 }, +/* GREY */ { "GRAY", 0, 0 }, +/* HI240 */ { "HI240", 0, 0 }, +/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 }, +/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 }, +/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 }, +/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 }, +/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 }, +/* YUYV */ { "YUYV", 0, 0 }, +/* UYVY */ { "UYVY", 0, 0 }, +/* YUV420 */ { "YUV420", 0, 0 }, +/* YUV411 */ { "YUV411", 0, 0 }, +/* RAW */ { "RAW", 0, 0 }, +/* YUV422P */ { "YUV422P", 0, 0 }, +/* YUV411P */ { "YUV411P", 0, 0 }}; +#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0])) +#undef ENDIANESS + +/* ----------------------------------------------------------------------- */ +/* ZORAN chipset detector */ +/* shamelessly stolen from bttv.c */ +/* Reason for beeing here: we need to detect if we are running on a */ +/* Triton based chipset, and if so, enable a certain bit */ +/* ----------------------------------------------------------------------- */ +static +void __init handle_chipset(void) +{ + struct pci_dev *dev = NULL; + + /* Just in case some nut set this to something dangerous */ + if (triton1) + triton1 = ZORAN_VDC_TRICOM; + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) + { + printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n"); + triton1 = ZORAN_VDC_TRICOM; + } +} + +/* ----------------------------------------------------------------------- */ +/* ZORAN functions */ +/* ----------------------------------------------------------------------- */ + +static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i); + +#if 0 /* unused */ +static +void zoran_dump(struct zoran *ztv) +{ + char str[256]; + char *p=str; /* shut up, gcc! */ + int i; + + for (i=0; i<0x60; i+=4) { + if ((i % 16) == 0) { + if (i) printk("%s\n",str); + p = str; + p+= sprintf(str, KERN_DEBUG " %04x: ",i); + } + p += sprintf(p, "%08x ",zrread(i)); + } +} +#endif /* unused */ + +static +void reap_states(struct zoran* ztv) +{ + /* count frames */ + ztv->fieldnr++; + + /* + * Are we busy at all? + * This depends on if there is a workqueue AND the + * videotransfer is enabled on the chip... + */ + if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) + { + struct vidinfo* newitem; + + /* did we get a complete frame? */ + if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) + return; + +DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); + + /* we are done with this buffer, tell everyone */ + ztv->workqueue->status = FBUFFER_DONE; + ztv->workqueue->fieldnr = ztv->fieldnr; + /* not good, here for BTTV_FIELDNR reasons */ + ztv->lastfieldnr = ztv->fieldnr; + + switch (ztv->workqueue->kindof) { + case FBUFFER_GRAB: + wake_up_interruptible(&ztv->grabq); + break; + case FBUFFER_VBI: + wake_up_interruptible(&ztv->vbiq); + break; + default: + printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof); + } + + /* item completed, skip to next item in queue */ + write_lock(&ztv->lock); + newitem = ztv->workqueue->next; + ztv->workqueue->next = 0; /* mark completed */ + ztv->workqueue = newitem; + write_unlock(&ztv->lock); + } + + /* + * ok, so it seems we have nothing in progress right now. + * Lets see if we can find some work. + */ + if (ztv->workqueue) + { + struct vidinfo* newitem; +again: + +DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); + + /* loadup the frame settings */ + read_lock(&ztv->lock); + zoran_set_geo(ztv,ztv->workqueue); + read_unlock(&ztv->lock); + + switch (ztv->workqueue->kindof) { + case FBUFFER_GRAB: + case FBUFFER_VBI: + zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); + zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + + /* start single-shot grab */ + zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); + break; + default: + printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof); + write_lock(&ztv->lock); + newitem = ztv->workqueue->next; + ztv->workqueue->next = 0; + ztv->workqueue = newitem; + write_unlock(&ztv->lock); + if (newitem) + goto again; /* yeah, sure.. */ + } + /* bye for now */ + return; + } +DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD)); + + /* + * What? Even the workqueue is empty? Am i really here + * for nothing? Did i come all that way to... do nothing? + */ + + /* do we need to overlay? */ + if (test_bit(STATE_OVERLAY, &ztv->state)) + { + /* are we already overlaying? */ + if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) || + !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) + { +DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD)); + + read_lock(&ztv->lock); + zoran_set_geo(ztv,&ztv->overinfo); + read_unlock(&ztv->lock); + + zror(ZORAN_OCR_OVLEN, ZORAN_OCR); + zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + } + + /* + * leave overlaying on, but turn interrupts off. + */ + zrand(~ZORAN_ICR_EN,ZORAN_ICR); + return; + } + + /* do we have any VBI idle time processing? */ + if (test_bit(STATE_VBI, &ztv->state)) + { + struct vidinfo* item; + struct vidinfo* lastitem; + + /* protect the workqueue */ + write_lock(&ztv->lock); + lastitem = ztv->workqueue; + if (lastitem) + while (lastitem->next) lastitem = lastitem->next; + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + if (item->next == 0 && item->status == FBUFFER_FREE) + { +DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item)); + item->status = FBUFFER_BUSY; + if (!lastitem) + ztv->workqueue = item; + else + lastitem->next = item; + lastitem = item; + } + write_unlock(&ztv->lock); + if (ztv->workqueue) + goto again; /* hey, _i_ graduated :) */ + } + + /* + * Then we must be realy IDLE + */ +DEBUG(printk(CARD_DEBUG "turning off\n",CARD)); + /* nothing further to do, disable DMA and further IRQs */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_ICR_EN,ZORAN_ICR); +} + +static +void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,estat; + int count = 0; + struct zoran *ztv = (struct zoran *)dev_id; + + UNUSED(irq); UNUSED(regs); + for (;;) { + /* get/clear interrupt status bits */ + stat=zrread(ZORAN_ISR); + estat=stat & zrread(ZORAN_ICR); + if (!estat) + return; + zrwrite(estat,ZORAN_ISR); + IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat)); + IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat)); + + if (estat & ZORAN_ISR_CODE) + { + IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD)); + } + if (estat & ZORAN_ISR_GIRQ0) + { + IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD)); + if (!ztv->card->usegirq1) + reap_states(ztv); + } + if (estat & ZORAN_ISR_GIRQ1) + { + IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD)); + if (ztv->card->usegirq1) + reap_states(ztv); + } + + count++; + if (count > 10) + printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat); + if (count > 20) + { + zrwrite(0, ZORAN_ICR); + printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD); + } + } +} + +static +int zoran_muxsel(struct zoran* ztv, int channel, int norm) +{ + int rv; + + /* set the new video norm */ + rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + if (rv) + return rv; + ztv->norm = norm; + + /* map the given channel to the cards decoder's channel */ + channel = ztv->card->video_mux[channel] & CHANNEL_MASK; + + /* set the new channel */ + rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel); + return rv; +} + +/* Tell the interrupt handler what to to. */ +static +void zoran_cap(struct zoran* ztv, int on) +{ +DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state)); + + if (on) { + ztv->running = 1; + + /* + * turn interrupts (back) on. The DMA will be enabled + * inside the irq handler when it detects a restart. + */ + zror(ZORAN_ICR_EN,ZORAN_ICR); + } + else { + /* + * turn both interrupts and DMA off + */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_ICR_EN,ZORAN_ICR); + + ztv->running = 0; + } +} + +static ulong dmask[] = { + 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, + 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, + 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, + 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, + 0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000, + 0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000, + 0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000, + 0xF0000000, 0xE0000000, 0xC0000000, 0x80000000 +}; + +static +void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp) +{ + ulong* mtop; + int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */ + int i; + +DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); + + for (i=0; ix,vp->y,vp->width,vp->height)); + } + + /* + * activate the visible portion of the screen + * Note we take some shortcuts here, because we + * know the width can never be < 32. (I.e. a DWORD) + * We also assume the overlay starts somewhere in + * the FIRST dword. + */ + { + int start = ztv->vidXshift; + ulong firstd = dmask[start]; + ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31]; + mtop = ztv->overinfo.overlay; + for (i=0; ioverinfo.h; i++) { + int w = ztv->vidWidth; + ulong* line = mtop; + if (start & 31) { + *line++ = firstd; + w -= 32-(start&31); + } + memset(line, ~0, w/8); + if (w & 31) + line[w/32] = lastd; + mtop += ystep; + } + } + + /* process clipping regions */ + for (i=0; ix < 0 || (uint)vcp->x > ztv->overinfo.w || + vcp->y < 0 || vcp->y > ztv->overinfo.h || + vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w || + vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h) + { + DEBUG(printk(CARD_DEBUG "illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); + if (vcp->x < 0) vcp->x = 0; + if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; + if (vcp->y < 0) vcp->y = 0; + if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h; + if (vcp->width < 0) vcp->width = 0; + if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; + if (vcp->height < 0) vcp->height = 0; + if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y; +// continue; + } + + mtop = &ztv->overinfo.overlay[vcp->y*ystep]; + for (h=0; h<=vcp->height; h++) { + int w; + int x = ztv->vidXshift + vcp->x; + for (w=0; w<=vcp->width; w++) { + clear_bit(x&31, &mtop[x/32]); + x++; + } + mtop += ystep; + } + ++vcp; + } + + mtop = ztv->overinfo.overlay; + zrwrite(virt_to_bus(mtop), ZORAN_MTOP); + zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT); + zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); +} + +struct tvnorm +{ + u16 Wt, Wa, Ht, Ha, HStart, VStart; +}; + +static struct tvnorm tvnorms[] = { + /* PAL-BDGHI */ +/* { 864, 720, 625, 576, 131, 21 },*/ +/*00*/ { 864, 768, 625, 576, 81, 17 }, + /* NTSC */ +/*01*/ { 858, 720, 525, 480, 121, 10 }, + /* SECAM */ +/*02*/ { 864, 720, 625, 576, 131, 21 }, + /* BW50 */ +/*03*/ { 864, 720, 625, 576, 131, 21 }, + /* BW60 */ +/*04*/ { 858, 720, 525, 480, 121, 10 } +}; +#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) + +/* + * Program the chip for a setup as described in the vidinfo struct. + * + * Side-effects: calculates vidXshift, vidInterlace, + * vidHeight, vidWidth which are used in a later stage + * to calculate the overlay mask + * + * This is an internal function, as such it does not check the + * validity of the struct members... Spectaculair crashes will + * follow /very/ quick when you're wrong and the chip right :) + */ +static +void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) +{ + ulong top, bot; + int stride; + int winWidth, winHeight; + int maxWidth, maxHeight, maxXOffset, maxYOffset; + long vfec; + +DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay)); + + /* + * make sure the DMA transfers are inhibited during our + * reprogramming of the chip + */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + + maxWidth = tvnorms[ztv->norm].Wa; + maxHeight = tvnorms[ztv->norm].Ha/2; + maxXOffset = tvnorms[ztv->norm].HStart; + maxYOffset = tvnorms[ztv->norm].VStart; + + /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */ + vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) | + (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24)); + + /* + * Set top, bottom ptrs. Since these must be DWORD aligned, + * possible adjust the x and the width of the window. + * so the endposition stay the same. The vidXshift will make + * sure we are not writing pixels before the requested x. + */ + ztv->vidXshift = 0; + winWidth = i->w; + if (winWidth < 0) + winWidth = -winWidth; + top = i->busadr + i->x*i->bpp + i->y*i->bpl; + if (top & 3) { + ztv->vidXshift = (top & 3) / i->bpp; + winWidth += ztv->vidXshift; + DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift)); + top &= ~3; + } + + /* + * bottom points to next frame but in interleaved mode we want + * to 'mix' the 2 frames to one capture, so 'bot' points to one + * (physical) line below the top line. + */ + bot = top + i->bpl; + zrwrite(top,ZORAN_VTOP); + zrwrite(bot,ZORAN_VBOT); + + /* + * Make sure the winWidth is DWORD aligned too, + * thereby automaticly making sure the stride to the + * next line is DWORD aligned too (as required by spec). + */ + if ((winWidth*i->bpp) & 3) { +DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); + winWidth += (winWidth*i->bpp) & 3; + } + + /* determine the DispMode and stride */ + if (i->h >= 0 && i->h <= maxHeight) { + /* single frame grab suffices for this height. */ + vfec |= ZORAN_VFEC_DISPMOD; + ztv->vidInterlace = 0; + stride = i->bpl - (winWidth*i->bpp); + winHeight = i->h; + } + else { + /* interleaving needed for this height */ + ztv->vidInterlace = 1; + stride = i->bpl*2 - (winWidth*i->bpp); + winHeight = i->h/2; + } + if (winHeight < 0) /* can happen for VBI! */ + winHeight = -winHeight; + + /* safety net, sometimes bpl is too short??? */ + if (stride<0) { +DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride)); + stride = 0; + } + + zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC); + zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR); + + /* remember vidWidth, vidHeight for overlay calculations */ + ztv->vidWidth = winWidth; + ztv->vidHeight = winHeight; +DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot)); +DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight)); +DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight)); +DEBUG(printk(KERN_DEBUG " stride=%d\n",stride)); + + /* + * determine horizontal scales and crops + */ + if (i->w < 0) { + int Hstart = 1; + int Hend = Hstart + winWidth; +DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend)); + zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); + } + else { + int Wa = maxWidth; + int X = (winWidth*64+Wa-1)/Wa; + int We = winWidth*64/X; + int HorDcm = 64-X; + int hcrop1 = 2*(Wa-We)/4; + /* + * BUGFIX: Juha Nurmela + * found the solution to the color phase shift. + * See ChangeLog for the full explanation) + */ + int Hstart = (maxXOffset + hcrop1) | 1; + int Hend = Hstart + We - 1; + +DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); + + zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); + vfec |= HorDcm<<14; + + if (HorDcm<16) + vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */ + else if (HorDcm<32) + vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ + else if (HorDcm<48) + vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ + else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ + } + + /* + * Determine vertical scales and crops + * + * when height is negative, we want to read starting at line 0 + * One day someone might need access to these lines... + */ + if (i->h < 0) { + int Vstart = 0; + int Vend = Vstart + winHeight; +DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend)); + zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); + } + else { + int Ha = maxHeight; + int Y = (winHeight*64+Ha-1)/Ha; + int He = winHeight*64/Y; + int VerDcm = 64-Y; + int vcrop1 = 2*(Ha-He)/4; + int Vstart = maxYOffset + vcrop1; + int Vend = Vstart + He - 1; + +DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); + zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); + vfec |= VerDcm<<8; + } + +DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); + + /* setup the requested format */ + zrwrite(vfec, ZORAN_VFEC); +} + +static +void zoran_common_open(struct zoran* ztv, int flags) +{ + UNUSED(flags); + + /* already opened? */ + if (ztv->users++ != 0) + return; + + /* unmute audio */ + /* /what/ audio? */ + + ztv->state = 0; + + /* setup the encoder to the initial values */ + ztv->picture.colour=254<<7; + ztv->picture.brightness=128<<8; + ztv->picture.hue=128<<8; + ztv->picture.contrast=216<<7; + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); + + /* default to the composite input since my camera is there */ + zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); +} + +static +void zoran_common_close(struct zoran* ztv) +{ + if (--ztv->users != 0) + return; + + /* mute audio */ + /* /what/ audio? */ + + /* stop the chip */ + zoran_cap(ztv, 0); +} + +/* + * Open a zoran card. Right now the flags are just a hack + */ +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *ztv = (struct zoran*)dev; + struct vidinfo* item; + char* pos; + + DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags)); + + /********************************************* + * We really should be doing lazy allocing... + *********************************************/ + /* allocate a frame buffer */ + if (!ztv->fbuffer) + ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); + if (!ztv->fbuffer) { + /* could not get a buffer, bail out */ + return -ENOBUFS; + } + /* at this time we _always_ have a framebuffer */ + memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); + + if (!ztv->overinfo.overlay) + ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); + if (!ztv->overinfo.overlay) { + /* could not get an overlay buffer, bail out */ + bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); + return -ENOBUFS; + } + /* at this time we _always_ have a overlay */ + + /* clear buffer status, and give them a DMAable address */ + pos = ztv->fbuffer; + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + { + item->status = FBUFFER_FREE; + item->memadr = pos; + item->busadr = virt_to_bus(pos); + pos += ZORAN_MAX_FBUFFER; + } + + /* do the common part of all open's */ + zoran_common_open(ztv, flags); + + MOD_INC_USE_COUNT; + return 0; +} + +static +void zoran_close(struct video_device* dev) +{ + struct zoran *ztv = (struct zoran*)dev; + + DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD)); + + /* driver specific closure */ + clear_bit(STATE_OVERLAY, &ztv->state); + + zoran_common_close(ztv); + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + /* free the allocated framebuffer */ + if (ztv->fbuffer) + bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE ); + ztv->fbuffer = 0; + if (ztv->overinfo.overlay) + kfree( ztv->overinfo.overlay ); + ztv->overinfo.overlay = 0; + + MOD_DEC_USE_COUNT; +} + +/* + * This read function could be used reentrant in a SMP situation. + * + * This is made possible by the spinlock which is kept till we + * found and marked a buffer for our own use. The lock must + * be released as soon as possible to prevent lock contention. + */ +static +long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran*)dev; + unsigned long max; + struct vidinfo* unused = 0; + struct vidinfo* done = 0; + + DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock)); + + /* find ourself a free or completed buffer */ + for (;;) { + struct vidinfo* item; + + write_lock_irq(&ztv->lock); + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + { + if (!unused && item->status == FBUFFER_FREE) + unused = item; + if (!done && item->status == FBUFFER_DONE) + done = item; + } + if (done || unused) + break; + + /* no more free buffers, wait for them. */ + write_unlock_irq(&ztv->lock); + if (nonblock) + return -EWOULDBLOCK; + interruptible_sleep_on(&ztv->grabq); + if (signal_pending(current)) + return -EINTR; + } + + /* Do we have 'ready' data? */ + if (!done) { + /* no? than this will take a while... */ + if (nonblock) { + write_unlock_irq(&ztv->lock); + return -EWOULDBLOCK; + } + + /* mark the unused buffer as wanted */ + unused->status = FBUFFER_BUSY; + unused->w = 320; + unused->h = 240; + unused->format = VIDEO_PALETTE_RGB24; + unused->bpp = palette2fmt[unused->format].bpp; + unused->bpl = unused->w * unused->bpp; + unused->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = unused; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = unused; + } + } + write_unlock_irq(&ztv->lock); + + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); + + /* wait till this buffer gets grabbed */ + while (unused->status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->grabq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + done = unused; + } + else + write_unlock_irq(&ztv->lock); + + /* Yes! we got data! */ + max = done->bpl * done->h; + if (count > max) + count = max; + if (copy_to_user((void*)buf, done->memadr, count)) + count = -EFAULT; + + /* keep the engine running */ + done->status = FBUFFER_FREE; +// zoran_cap(ztv,1); + + /* tell listeners this buffer became free */ + wake_up_interruptible(&ztv->grabq); + + /* goodbye */ + DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count)); + return count; +} + +static +long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran *)dev; + UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock); + DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD)); + return -EINVAL; +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran *)dev; + struct vidinfo* item; + unsigned int mask = 0; + + poll_wait(file, &ztv->grabq, wait); + + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + if (item->status == FBUFFER_DONE) + { + mask |= (POLLIN | POLLRDNORM); + break; + } + + DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask)); + + return mask; +} +#endif + +/* append a new clipregion to the vector of video_clips */ +static +void new_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++; +} + +static +int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) +{ + struct zoran* ztv = (struct zoran*)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability c; + DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD)); + + strcpy(c.name,ztv->video_dev.name); + c.type = VID_TYPE_CAPTURE| + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + if (ztv->have_tuner) + c.type |= VID_TYPE_TUNER; + if (ztv->have_decoder) { + c.channels = ztv->card->video_inputs; + c.audios = ztv->card->audio_inputs; + } else + /* no decoder -> no channels */ + c.channels = c.audios = 0; + c.maxwidth = 768; + c.maxheight = 576; + c.minwidth = 32; + c.minheight = 32; + if (copy_to_user(arg,&c,sizeof(c))) + return -EFAULT; + break; + } + + case VIDIOCGCHAN: + { + struct video_channel v; + int mux; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel)); + v.flags=VIDEO_VC_AUDIO +#ifdef VIDEO_VC_NORM + |VIDEO_VC_NORM +#endif + ; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; +#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API + v.norm=VIDEO_MODE_PAL| + VIDEO_MODE_NTSC| + VIDEO_MODE_SECAM; +#else + v.norm=VIDEO_MODE_PAL; +#endif + /* too many inputs? no decoder -> no channels */ + if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) + return -EINVAL; + + /* now determine the name of the channel */ + mux = ztv->card->video_mux[v.channel]; + if (mux & IS_TUNER) { + /* lets assume only one tuner, yes? */ + strcpy(v.name,"Television"); + v.type = VIDEO_TYPE_TV; + if (ztv->have_tuner) { + v.flags |= VIDEO_VC_TUNER; + v.tuners = 1; + } + } + else if (mux & IS_SVHS) + sprintf(v.name,"S-Video-%d",v.channel); + else + sprintf(v.name,"CVBS-%d",v.channel); + + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + break; + } + case VIDIOCSCHAN: + { /* set video channel */ + struct video_channel v; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm)); + + /* too many inputs? no decoder -> no channels */ + if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) + return -EINVAL; + + if (v.norm != VIDEO_MODE_PAL && + v.norm != VIDEO_MODE_NTSC && + v.norm != VIDEO_MODE_SECAM && + v.norm != VIDEO_MODE_AUTO) + return -EOPNOTSUPP; + + /* make it happen, nr1! */ + return zoran_muxsel(ztv,v.channel,v.norm); + } + + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner)); + + /* Only no or one tuner for now */ + if (!ztv->have_tuner || v.tuner) + return -EINVAL; + + strcpy(v.name,"Television"); + v.rangelow = 0; + v.rangehigh = ~0; + v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = ztv->norm; + v.signal = 0xFFFF; /* unknown */ + + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + break; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode)); + + /* Only no or one tuner for now */ + if (!ztv->have_tuner || v.tuner) + return -EINVAL; + + /* and it only has certain valid modes */ + if( v.mode != VIDEO_MODE_PAL && + v.mode != VIDEO_MODE_NTSC && + v.mode != VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + + /* engage! */ + return zoran_muxsel(ztv,v.tuner,v.mode); + } + + case VIDIOCGPICT: + { + struct video_picture p = ztv->picture; + DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD)); + p.depth = ztv->depth; + switch (p.depth) { + case 8: p.palette=VIDEO_PALETTE_YUV422; + break; + case 15: p.palette=VIDEO_PALETTE_RGB555; + break; + case 16: p.palette=VIDEO_PALETTE_RGB565; + break; + case 24: p.palette=VIDEO_PALETTE_RGB24; + break; + case 32: p.palette=VIDEO_PALETTE_RGB32; + break; + } + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + break; + } + case VIDIOCSPICT: + { + struct video_picture p; + if (copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette)); + + /* depth must match with framebuffer */ + if (p.depth != ztv->depth) + return -EINVAL; + + /* check if palette matches this bpp */ + if (p.palette>NRPALETTES || + palette2fmt[p.palette].bpp != ztv->overinfo.bpp) + return -EINVAL; + + write_lock_irq(&ztv->lock); + ztv->overinfo.format = p.palette; + ztv->picture = p; + write_unlock_irq(&ztv->lock); + + /* tell the decoder */ + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); + break; + } + + case VIDIOCGWIN: + { + struct video_window vw; + DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD)); + read_lock(&ztv->lock); + vw.x = ztv->overinfo.x; + vw.y = ztv->overinfo.y; + vw.width = ztv->overinfo.w; + vw.height = ztv->overinfo.h; + vw.chromakey= 0; + vw.flags = 0; + if (ztv->vidInterlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + read_unlock(&ztv->lock); + if (copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + break; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp; + int on; + if (copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); + + if (vw.flags) + return -EINVAL; + + 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; + + on = ztv->running; + if (on) + zoran_cap(ztv, 0); + + /* + * strange, it seems xawtv sometimes calls us with 0 + * width and/or height. Ignore these values + */ + if (vw.x == 0) + vw.x = ztv->overinfo.x; + if (vw.y == 0) + vw.y = ztv->overinfo.y; + + /* by now we are committed to the new data... */ + write_lock_irq(&ztv->lock); + ztv->overinfo.x = vw.x; + ztv->overinfo.y = vw.y; + ztv->overinfo.w = vw.width; + ztv->overinfo.h = vw.height; + write_unlock_irq(&ztv->lock); + + /* + * Impose display clips + */ + if (vw.x+vw.width > ztv->swidth) + new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); + if (vw.y+vw.height > ztv->sheight) + new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1); + + /* built the requested clipping zones */ + zoran_set_geo(ztv, &ztv->overinfo); + zoran_built_overlay(ztv, vw.clipcount, vcp); + vfree(vcp); + + /* if we were on, restart the video engine */ + if (on) + zoran_cap(ztv, 1); + break; + } + + case VIDIOCCAPTURE: + { + int v; + get_user_ret(v,(int*)arg, -EFAULT); + DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); + + if (v==0) { + clear_bit(STATE_OVERLAY, &ztv->state); + zoran_cap(ztv, 1); + } + else { + /* is VIDIOCSFBUF, VIDIOCSWIN done? */ + if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) + return -EINVAL; + + set_bit(STATE_OVERLAY, &ztv->state); + zoran_cap(ztv, 1); + } + break; + } + + case VIDIOCGFBUF: + { + struct video_buffer v; + DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD)); + read_lock(&ztv->lock); + v.base = (void *)ztv->overinfo.busadr; + v.height = ztv->sheight; + v.width = ztv->swidth; + v.depth = ztv->depth; + v.bytesperline = ztv->overinfo.bpl; + read_unlock(&ztv->lock); + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + break; + } + case VIDIOCSFBUF: + { + struct video_buffer v; +#if LINUX_VERSION_CODE >= 0x020100 + if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) +#else + if(!suser()) +#endif + return -EPERM; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline)); + + if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) + return -EINVAL; + if (v.bytesperline<1) + return -EINVAL; + if (ztv->running) + return -EBUSY; + write_lock_irq(&ztv->lock); + ztv->overinfo.busadr = (ulong)v.base; + ztv->sheight = v.height; + ztv->swidth = v.width; + ztv->depth = v.depth; /* bits per pixel */ + ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ + ztv->overinfo.bpl = v.bytesperline; /* bytes per line */ + write_unlock_irq(&ztv->lock); + break; + } + + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + break; + } + + case VIDIOCSYNC: + { + int i; + get_user_ret(i,(int*)arg, -EFAULT); + DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); + if (i<0 || i>ZORAN_MAX_FBUFFERS) + return -EINVAL; + switch (ztv->grabinfo[i].status) { + case FBUFFER_FREE: + return -EINVAL; + case FBUFFER_BUSY: + /* wait till this buffer gets grabbed */ + while (ztv->grabinfo[i].status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->grabq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + /* don't fall through; a DONE buffer is not UNUSED */ + break; + case FBUFFER_DONE: + ztv->grabinfo[i].status = FBUFFER_FREE; + /* tell ppl we have a spare buffer */ + wake_up_interruptible(&ztv->grabq); + break; + } + DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i)); + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + struct vidinfo* frame; + if (copy_from_user(&vm,arg,sizeof(vm))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format)); + if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || + vm.width<32 || vm.width>768 || + vm.height<32 || vm.height>576 || + vm.format>NRPALETTES || + palette2fmt[vm.format].mode == 0) + return -EINVAL; + + /* we are allowed to take over UNUSED and DONE buffers */ + frame = &ztv->grabinfo[vm.frame]; + if (frame->status == FBUFFER_BUSY) + return -EBUSY; + + /* setup the other parameters if they are given */ + write_lock_irq(&ztv->lock); + frame->w = vm.width; + frame->h = vm.height; + frame->format = vm.format; + frame->bpp = palette2fmt[frame->format].bpp; + frame->bpl = frame->w*frame->bpp; + frame->status = FBUFFER_BUSY; + frame->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = frame; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = frame; + } + } + write_unlock_irq(&ztv->lock); + zoran_cap(ztv, 1); + break; + } + + case VIDIOCGMBUF: + { + struct video_mbuf mb; + int i; + DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD)); + mb.size = ZORAN_MAX_FBUFSIZE; + mb.frames = ZORAN_MAX_FBUFFERS; + for (i=0; ivideo_dev.minor; + vu.vbi = ztv->vbi_dev.minor; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if(copy_to_user(arg, &vu,sizeof(vu))) + return -EFAULT; + break; + } + + case VIDIOCGFREQ: + { + unsigned long v = ztv->tuner_freq; + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD)); + break; + } + case VIDIOCSFREQ: + { + unsigned long v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD)); + + if (ztv->have_tuner) { + int fixme = v; + if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0) + return -EAGAIN; + } + ztv->tuner_freq = v; + break; + } + + /* Why isn't this in the API? + * And why doesn't it take a buffer number? + case BTTV_FIELDNR: + { + unsigned long v = ztv->lastfieldnr; + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD)); + break; + } + */ + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static +int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) +{ + struct zoran* ztv = (struct zoran*)dev; + unsigned long start = (unsigned long)adr; + unsigned long pos; + + DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size)); + + /* sanity checks */ + if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) + return -EINVAL; + + /* start mapping the whole shabang to user memory */ + pos = (unsigned long)ztv->fbuffer; + while (size>0) { + unsigned long page = virt_to_phys((void*)pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +static struct video_device zr36120_template= +{ + "UNSET", + VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, + VID_HARDWARE_ZR36120, + + zoran_open, + zoran_close, + zoran_read, + zoran_write, +#if LINUX_VERSION_CODE >= 0x020100 + zoran_poll, /* poll */ +#endif + zoran_ioctl, + zoran_mmap, + NULL, /* initialize */ + NULL, + 0, + -1 +}; + +static +int vbi_open(struct video_device *dev, int flags) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + + DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags)); + + /* + * During VBI device open, we continiously grab VBI-like + * data in the vbi buffer when we have nothing to do. + * Only when there is an explicit request for VBI data + * (read call) we /force/ a read. + */ + + /* allocate buffers */ + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + { + item->status = FBUFFER_FREE; + + /* alloc */ + if (!item->memadr) { + item->memadr = bmalloc(ZORAN_VBI_BUFSIZE); + if (!item->memadr) { + /* could not get a buffer, bail out */ + while (item != ztv->readinfo) { + item--; + bfree(item->memadr, ZORAN_VBI_BUFSIZE); + item->memadr = 0; + item->busadr = 0; + } + return -ENOBUFS; + } + } + + /* determine the DMAable address */ + item->busadr = virt_to_bus(item->memadr); + } + + /* do the common part of all open's */ + zoran_common_open(ztv, flags); + + set_bit(STATE_VBI, &ztv->state); + /* start read-ahead */ + zoran_cap(ztv, 1); + + MOD_INC_USE_COUNT; + return 0; +} + +static +void vbi_close(struct video_device *dev) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + + DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD)); + + /* driver specific closure */ + clear_bit(STATE_VBI, &ztv->state); + + zoran_common_close(ztv); + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + { + if (item->memadr) + bfree(item->memadr, ZORAN_VBI_BUFSIZE); + item->memadr = 0; + } + + MOD_DEC_USE_COUNT; +} + +/* + * This read function could be used reentrant in a SMP situation. + * + * This is made possible by the spinlock which is kept till we + * found and marked a buffer for our own use. The lock must + * be released as soon as possible to prevent lock contention. + */ +static +long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + unsigned long max; + struct vidinfo* unused = 0; + struct vidinfo* done = 0; + + DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock)); + + /* find ourself a free or completed buffer */ + for (;;) { + struct vidinfo* item; + + write_lock_irq(&ztv->lock); + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { + if (!unused && item->status == FBUFFER_FREE) + unused = item; + if (!done && item->status == FBUFFER_DONE) + done = item; + } + if (done || unused) + break; + + /* no more free buffers, wait for them. */ + write_unlock_irq(&ztv->lock); + if (nonblock) + return -EWOULDBLOCK; + interruptible_sleep_on(&ztv->vbiq); + if (signal_pending(current)) + return -EINTR; + } + + /* Do we have 'ready' data? */ + if (!done) { + /* no? than this will take a while... */ + if (nonblock) { + write_unlock_irq(&ztv->lock); + return -EWOULDBLOCK; + } + + /* mark the unused buffer as wanted */ + unused->status = FBUFFER_BUSY; + unused->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = unused; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = unused; + } + } + write_unlock_irq(&ztv->lock); + + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); + + /* wait till this buffer gets grabbed */ + while (unused->status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->vbiq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + done = unused; + } + else + write_unlock_irq(&ztv->lock); + + /* Yes! we got data! */ + max = done->bpl * -done->h; + if (count > max) + count = max; + + /* check if the user gave us enough room to write the data */ + if (!access_ok(VERIFY_WRITE, buf, count)) { + count = -EFAULT; + goto out; + } + + /* + * Now transform/strip the data from YUV to Y-only + * NB. Assume the Y is in the LSB of the YUV data. + */ + { + unsigned char* optr = buf; + unsigned char* eptr = buf+count; + + /* are we beeing accessed from an old driver? */ + if (count == 2*19*2048) { + /* + * Extreme HACK, old VBI programs expect 2048 points + * of data, and we only got 864 orso. Double each + * datapoint and clear the rest of the line. + * This way we have appear to have a + * sample_frequency of 29.5 Mc. + */ + int x,y; + unsigned char* iptr = done->memadr+1; + for (y=done->h; optrw; x++) + { + unsigned char a = iptr[x*2]; + *optr++ = a; + *optr++ = a; + } + /* and clear the rest of the line */ + for (x*=2; optrbpl; x++) + *optr++ = 0; + /* next line */ + iptr += done->bpl; + } + } + else { + /* + * Other (probably newer) programs asked + * us what geometry we are using, and are + * reading the correct size. + */ + int x,y; + unsigned char* iptr = done->memadr+1; + for (y=done->h; optrw; x++) + *optr++ = iptr[x*2]; + /* and clear the rest of the line */ + for (;optrbpl; x++) + *optr++ = 0; + /* next line */ + iptr += done->bpl; + } + } + + /* API compliance: + * place the framenumber (half fieldnr) in the last long + */ + ((ulong*)eptr)[-1] = done->fieldnr/2; + } + + /* keep the engine running */ + done->status = FBUFFER_FREE; + zoran_cap(ztv, 1); + + /* tell listeners this buffer just became free */ + wake_up_interruptible(&ztv->vbiq); + + /* goodbye */ +out: + DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count)); + return count; +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + unsigned int mask = 0; + + poll_wait(file, &ztv->vbiq, wait); + + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + if (item->status == FBUFFER_DONE) + { + mask |= (POLLIN | POLLRDNORM); + break; + } + + DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask)); + + return mask; +} +#endif + +static +int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran* ztv = (struct zoran*)dev->priv; + + switch (cmd) { + case VIDIOCGVBIFMT: + { + struct vbi_format f; + DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD)); + f.sampling_rate = 14750000UL; + f.samples_per_line = -ztv->readinfo[0].w; + f.sample_format = VIDEO_PALETTE_RAW; + f.start[0] = f.start[1] = ztv->readinfo[0].y; + f.start[1] += 312; + f.count[0] = f.count[1] = -ztv->readinfo[0].h; + f.flags = VBI_INTERLACED; + if (copy_to_user(arg,&f,sizeof(f))) + return -EFAULT; + break; + } + case VIDIOCSVBIFMT: + { + struct vbi_format f; + int i; + if (copy_from_user(&f, arg,sizeof(f))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags)); + + /* lots of parameters are fixed... (PAL) */ + if (f.sampling_rate != 14750000UL || + f.samples_per_line > 864 || + f.sample_format != VIDEO_PALETTE_RAW || + f.start[0] < 0 || + f.start[0] != f.start[1]-312 || + f.count[0] != f.count[1] || + f.start[0]+f.count[0] >= 288 || + f.flags != VBI_INTERLACED) + return -EINVAL; + + write_lock_irq(&ztv->lock); + ztv->readinfo[0].y = f.start[0]; + ztv->readinfo[0].w = -f.samples_per_line; + ztv->readinfo[0].h = -f.count[0]; + ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp; + for (i=1; ireadinfo[i] = ztv->readinfo[i]; + write_unlock_irq(&ztv->lock); + break; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct video_device vbi_template= +{ + "UNSET", + VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + VID_HARDWARE_ZR36120, + + vbi_open, + vbi_close, + vbi_read, + zoran_write, +#if LINUX_VERSION_CODE >= 0x020100 + vbi_poll, /* poll */ +#endif + vbi_ioctl, + NULL, /* no mmap */ + NULL, /* no initialize */ + NULL, /* priv */ + 0, /* busy */ + -1 /* minor */ +}; + +/* + * Scan for a Zoran chip, request the irq and map the io memory + */ +static +int __init find_zoran(void) +{ + int result; + struct zoran *ztv; + struct pci_dev *dev = NULL; + unsigned char revision; + int zoran_num=0; + + while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) + { + /* Ok, a ZR36120/ZR36125 found! */ + ztv = &zorans[zoran_num]; + ztv->dev = dev; + + if (pci_enable_device(dev)) + return -EIO; + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); + printk(KERN_INFO "zoran: Zoran %x (rev %d) ", + dev->device, revision); + printk("bus: %d, devfn: %d, irq: %d, ", + dev->bus->number, dev->devfn, dev->irq); + printk("memory: 0x%08lx.\n", ztv->zoran_adr); + + ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); + DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); + + result = request_irq(dev->irq, zoran_irq, + SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); + if (result==-EINVAL) + { + printk(KERN_ERR "zoran: Bad irq number or handler\n"); + return -EINVAL; + } + if (result==-EBUSY) + printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); + if (result < 0) + return result; + + /* Enable bus-mastering */ + pci_set_master(dev); + + zoran_num++; + } + if(zoran_num) + printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); + return zoran_num; +} + +static +int __init init_zoran(int card) +{ + struct zoran *ztv = &zorans[card]; + int i; + + /* if the given cardtype valid? */ + if (cardtype[card]>=NRTVCARDS) { + printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); + return -1; + } + + /* reset the zoran */ + zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); + udelay(10); + zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); + udelay(10); + + /* zoran chip specific details */ + ztv->card = tvcards+cardtype[card]; /* point to the selected card */ + ztv->norm = 0; /* PAL */ + ztv->tuner_freq = 0; + + /* videocard details */ + ztv->swidth = 800; + ztv->sheight = 600; + ztv->depth = 16; + + /* State details */ + ztv->fbuffer = 0; + ztv->overinfo.kindof = FBUFFER_OVERLAY; + ztv->overinfo.status = FBUFFER_FREE; + ztv->overinfo.x = 0; + ztv->overinfo.y = 0; + ztv->overinfo.w = 768; /* 640 */ + ztv->overinfo.h = 576; /* 480 */ + ztv->overinfo.format = VIDEO_PALETTE_RGB565; + ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; + ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; + ztv->overinfo.busadr = 0; + ztv->overinfo.memadr = 0; + ztv->overinfo.overlay = 0; + for (i=0; igrabinfo[i] = ztv->overinfo; + ztv->grabinfo[i].kindof = FBUFFER_GRAB; + } + init_waitqueue_head(&ztv->grabq); + + /* VBI details */ + ztv->readinfo[0] = ztv->overinfo; + ztv->readinfo[0].kindof = FBUFFER_VBI; + ztv->readinfo[0].w = -864; + ztv->readinfo[0].h = -38; + ztv->readinfo[0].format = VIDEO_PALETTE_YUV422; + ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp; + ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp; + for (i=1; ireadinfo[i] = ztv->readinfo[0]; + init_waitqueue_head(&ztv->vbiq); + + /* maintenance data */ + ztv->have_decoder = 0; + ztv->have_tuner = 0; + ztv->tuner_type = 0; + ztv->running = 0; + ztv->users = 0; + ztv->lock = RW_LOCK_UNLOCKED; + ztv->workqueue = 0; + ztv->fieldnr = 0; + ztv->lastfieldnr = 0; + + if (triton1) + zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); + + /* external FL determines TOP frame */ + zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); + + /* set HSpol */ + if (ztv->card->hsync_pos) + zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH); + /* set VSpol */ + if (ztv->card->vsync_pos) + zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV); + + /* Set the proper General Purpuse register bits */ + /* implicit: no softreset, 0 waitstates */ + zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); + /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ + zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); + + /* clear interrupt status */ + zrwrite(~0, ZORAN_ISR); + + /* + * i2c template + */ + ztv->i2c = zoran_i2c_bus_template; + sprintf(ztv->i2c.name,"zoran-%d",card); + ztv->i2c.data = ztv; + + /* + * Now add the template and register the device unit + */ + ztv->video_dev = zr36120_template; + strcpy(ztv->video_dev.name, ztv->i2c.name); + ztv->video_dev.priv = ztv; + if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0) + return -1; + + ztv->vbi_dev = vbi_template; + strcpy(ztv->vbi_dev.name, ztv->i2c.name); + ztv->vbi_dev.priv = ztv; + if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) { + video_unregister_device(&ztv->video_dev); + return -1; + } + i2c_register_bus(&ztv->i2c); + + /* set interrupt mask - the PIN enable will be set later */ + zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); + + printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name); + return 0; +} + +static +void __exit release_zoran(int max) +{ + struct zoran *ztv; + int i; + + for (i=0;idev->irq,ztv); + + /* unregister i2c_bus */ + i2c_unregister_bus((&ztv->i2c)); + + /* unmap and free memory */ + if (ztv->zoran_mem) + iounmap(ztv->zoran_mem); + + video_unregister_device(&ztv->video_dev); + video_unregister_device(&ztv->vbi_dev); + } +} + +void __exit zr36120_exit(void) +{ + release_zoran(zoran_cards); +} + +int __init zr36120_init(void) +{ + int card; + + handle_chipset(); + zoran_cards = find_zoran(); + if (zoran_cards<0) + /* no cards found, no need for a driver */ + return -EIO; + + /* initialize Zorans */ + for (card=0; card +#include + +#include +#include + +#include + +/* + * Debug macro's, place an x behind the ) for actual debug-compilation + * E.g. #define DEBUG(x...) x + */ +#define DEBUG(x...) /* Debug driver */ +#define IDEBUG(x...) /* Debug interrupt handler */ +#define PDEBUG 0 /* Debug PCI writes */ + +/* defined in zr36120_i2c */ +extern struct i2c_bus zoran_i2c_bus_template; + +#define ZORAN_MAX_FBUFFERS 2 +#define ZORAN_MAX_FBUFFER (768*576*2) +#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) + +#define ZORAN_VBI_BUFFERS 2 +#define ZORAN_VBI_BUFSIZE (22*1024*2) + +struct tvcard { + char* name; /* name of the cardtype */ + int video_inputs; /* number of channels defined in video_mux */ + int audio_inputs; /* number of channels defined in audio_mux */ + __u32 swapi2c:1, /* need to swap i2c wires SDA/SCL? */ + usegirq1:1, /* VSYNC at GIRQ1 instead of GIRQ0? */ + vsync_pos:1, /* positive VSYNC signal? */ + hsync_pos:1, /* positive HSYNC signal? */ + gpdir:8, /* General Purpose Direction register */ + gpval:8; /* General Purpose Value register */ + int video_mux[6]; /* mapping channel number to physical input */ +#define IS_TUNER 0x80 +#define IS_SVHS 0x40 +#define CHANNEL_MASK 0x3F + int audio_mux[6]; /* mapping channel number to physical input */ +}; +#define TUNER(x) ((x)|IS_TUNER) +#define SVHS(x) ((x)|IS_SVHS) + +struct vidinfo { + struct vidinfo* next; /* next active buffer */ + uint kindof; +#define FBUFFER_OVERLAY 0 +#define FBUFFER_GRAB 1 +#define FBUFFER_VBI 2 + uint status; +#define FBUFFER_FREE 0 +#define FBUFFER_BUSY 1 +#define FBUFFER_DONE 2 + ulong fieldnr; /* # of field, not framer! */ + uint x,y; + int w,h; /* w,h can be negative! */ + uint format; /* index in palette2fmt[] */ + uint bpp; /* lookup from palette2fmt[] */ + uint bpl; /* calc: width * bpp */ + ulong busadr; /* bus addr for DMA engine */ + char* memadr; /* kernel addr for making copies */ + ulong* overlay; /* kernel addr of overlay mask */ +}; + +struct zoran +{ + struct video_device video_dev; +#define CARD_DEBUG KERN_DEBUG "%s(%lu): " +#define CARD_INFO KERN_INFO "%s(%lu): " +#define CARD_ERR KERN_ERR "%s(%lu): " +#define CARD ztv->video_dev.name,ztv->fieldnr + + /* zoran chip specific details */ + struct i2c_bus i2c; /* i2c registration data */ + struct pci_dev* dev; /* ptr to PCI device */ + ulong zoran_adr; /* bus address of IO memory */ + char* zoran_mem; /* kernel address of IO memory */ + struct tvcard* card; /* the cardtype */ + uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */ + uint tuner_freq; /* Current freq in kHz */ + struct video_picture picture; /* Current picture params */ + + /* videocard details */ + uint swidth; /* screen width */ + uint sheight; /* screen height */ + uint depth; /* depth in bits */ + + /* State details */ + char* fbuffer; /* framebuffers for mmap */ + struct vidinfo overinfo; /* overlay data */ + struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/ + wait_queue_head_t grabq; /* grabbers queue */ + + /* VBI details */ + struct video_device vbi_dev; + struct vidinfo readinfo[2]; /* VBI data - flip buffers */ + wait_queue_head_t vbiq; /* vbi queue */ + + /* maintenance data */ + int have_decoder; /* did we detect a mux? */ + int have_tuner; /* did we detect a tuner? */ + int users; /* howmany video/vbi open? */ + int tuner_type; /* tuner type, when found */ + int running; /* are we rolling? */ + rwlock_t lock; + int state; /* what is requested of us? */ +#define STATE_OVERLAY 0 +#define STATE_VBI 1 + struct vidinfo* workqueue; /* buffers to grab, head is active */ + ulong fieldnr; /* #field, ticked every VSYNC */ + ulong lastfieldnr; /* #field, ticked every GRAB */ + + int vidInterlace; /* calculated */ + int vidXshift; /* calculated */ + uint vidWidth; /* calculated */ + uint vidHeight; /* calculated */ +}; + +#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr))) +#define zrread(adr) readl(ztv->zoran_mem+(adr)) + +#if PDEBUG == 0 +#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr) +#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr) +#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr) +#else +#define zrand(dat, adr) \ +do { \ + ulong data = (dat) & zrread((adr)); \ + zrwrite(data, (adr)); \ + if (0 != (~(dat) & zrread((adr)))) \ + printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \ +} while(0) + +#define zror(dat, adr) \ +do { \ + ulong data = (dat) | zrread((adr)); \ + zrwrite(data, (adr)); \ + if ((dat) != ((dat) & zrread(adr))) \ + printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \ +} while(0) + +#define zraor(dat, mask, adr) \ +do { \ + ulong data; \ + if ((dat) & (mask)) \ + printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ + data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \ + zrwrite(data,(adr)); \ + if ( (dat) != (~(mask) & zrread((adr))) ) \ + printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ +} while(0) +#endif + +#endif + +/* zoran PCI address space */ +#define ZORAN_VFEH 0x000 /* Video Front End Horizontal Conf. */ +#define ZORAN_VFEH_HSPOL (1<<30) +#define ZORAN_VFEH_HSTART (0x3FF<<10) +#define ZORAN_VFEH_HEND (0x3FF<<0) + +#define ZORAN_VFEV 0x004 /* Video Front End Vertical Conf. */ +#define ZORAN_VFEV_VSPOL (1<<30) +#define ZORAN_VFEV_VSTART (0x3FF<<10) +#define ZORAN_VFEV_VEND (0x3FF<<0) + +#define ZORAN_VFEC 0x008 /* Video Front End Scaler and Pixel */ +#define ZORAN_VFEC_EXTFL (1<<26) +#define ZORAN_VFEC_TOPFIELD (1<<25) +#define ZORAN_VFEC_VCLKPOL (1<<24) +#define ZORAN_VFEC_HFILTER (7<<21) +#define ZORAN_VFEC_HFILTER_1 (0<<21) /* no lumi, 3-tap chromo */ +#define ZORAN_VFEC_HFILTER_2 (1<<21) /* 3-tap lumi, 3-tap chromo */ +#define ZORAN_VFEC_HFILTER_3 (2<<21) /* 4-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_HFILTER_4 (3<<21) /* 5-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_HFILTER_5 (4<<21) /* 4-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_DUPFLD (1<<20) +#define ZORAN_VFEC_HORDCM (63<<14) +#define ZORAN_VFEC_VERDCM (63<<8) +#define ZORAN_VFEC_DISPMOD (1<<6) +#define ZORAN_VFEC_RGB (3<<3) +#define ZORAN_VFEC_RGB_YUV422 (0<<3) +#define ZORAN_VFEC_RGB_RGB888 (1<<3) +#define ZORAN_VFEC_RGB_RGB565 (2<<3) +#define ZORAN_VFEC_RGB_RGB555 (3<<3) +#define ZORAN_VFEC_ERRDIF (1<<2) +#define ZORAN_VFEC_PACK24 (1<<1) +#define ZORAN_VFEC_LE (1<<0) + +#define ZORAN_VTOP 0x00C /* Video Display "Top" */ + +#define ZORAN_VBOT 0x010 /* Video Display "Bottom" */ + +#define ZORAN_VSTR 0x014 /* Video Display Stride */ +#define ZORAN_VSTR_DISPSTRIDE (0xFFFF<<16) +#define ZORAN_VSTR_VIDOVF (1<<8) +#define ZORAN_VSTR_SNAPSHOT (1<<1) +#define ZORAN_VSTR_GRAB (1<<0) + +#define ZORAN_VDC 0x018 /* Video Display Conf. */ +#define ZORAN_VDC_VIDEN (1<<31) +#define ZORAN_VDC_MINPIX (0x1F<<25) +#define ZORAN_VDC_TRICOM (1<<24) +#define ZORAN_VDC_VIDWINHT (0x3FF<<12) +#define ZORAN_VDC_VIDWINWID (0x3FF<<0) + +#define ZORAN_MTOP 0x01C /* Masking Map "Top" */ + +#define ZORAN_MBOT 0x020 /* Masking Map "Bottom" */ + +#define ZORAN_OCR 0x024 /* Overlay Control */ +#define ZORAN_OCR_OVLEN (1<<15) +#define ZORAN_OCR_MASKSTRIDE (0xFF<<0) + +#define ZORAN_PCI 0x028 /* System, PCI and GPP Control */ +#define ZORAN_PCI_SOFTRESET (1<<24) +#define ZORAN_PCI_WAITSTATE (3<<16) +#define ZORAN_PCI_GENPURDIR (0xFF<<0) + +#define ZORAN_GUEST 0x02C /* GuestBus Control */ + +#define ZORAN_CSOURCE 0x030 /* Code Source Address */ + +#define ZORAN_CTRANS 0x034 /* Code Transfer Control */ + +#define ZORAN_CMEM 0x038 /* Code Memory Pointer */ + +#define ZORAN_ISR 0x03C /* Interrupt Status Register */ +#define ZORAN_ISR_CODE (1<<28) +#define ZORAN_ISR_GIRQ0 (1<<29) +#define ZORAN_ISR_GIRQ1 (1<<30) + +#define ZORAN_ICR 0x040 /* Interrupt Control Register */ +#define ZORAN_ICR_EN (1<<24) +#define ZORAN_ICR_CODE (1<<28) +#define ZORAN_ICR_GIRQ0 (1<<29) +#define ZORAN_ICR_GIRQ1 (1<<30) + +#define ZORAN_I2C 0x044 /* I2C-Bus */ +#define ZORAN_I2C_SCL (1<<1) +#define ZORAN_I2C_SDA (1<<0) + +#define ZORAN_POST 0x48 /* PostOffice */ +#define ZORAN_POST_PEN (1<<25) +#define ZORAN_POST_TIME (1<<24) +#define ZORAN_POST_DIR (1<<23) +#define ZORAN_POST_GUESTID (3<<20) +#define ZORAN_POST_GUEST (7<<16) +#define ZORAN_POST_DATA (0xFF<<0) + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/zr36120_i2c.c linux/drivers/media/video/zr36120_i2c.c --- v2.4.0-test6/linux/drivers/media/video/zr36120_i2c.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36120_i2c.c Wed Dec 29 17:08:55 1999 @@ -0,0 +1,133 @@ +/* + zr36120_i2c.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + 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. +*/ + +#include +#include +#include + +#include +#include +#include + +#include "tuner.h" +#include "zr36120.h" + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ +/* ----------------------------------------------------------------------- */ + +/* software I2C functions */ + +#define I2C_DELAY 10 + +static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) +{ + struct zoran *ztv = (struct zoran*)bus->data; + unsigned int b = 0; + if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA; + if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL; + zrwrite(b, ZORAN_I2C); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *ztv = (struct zoran*)bus->data; + if (ztv->card->swapi2c) + return zrread(ZORAN_I2C) & ZORAN_I2C_SCL; + return zrread(ZORAN_I2C) & ZORAN_I2C_SDA; +} + +static +void attach_inform(struct i2c_bus *bus, int id) +{ + struct zoran *ztv = (struct zoran*)bus->data; + struct video_decoder_capability dc; + int rv; + + switch (id) { + case I2C_DRIVERID_VIDEODECODER: + DEBUG(printk(CARD_INFO "decoder attached\n",CARD)); + + /* fetch the capabilites of the decoder */ + rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); + if (rv) { + DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD)); + break; + } + DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); + + /* Test if the decoder can de VBI transfers */ + if (dc.flags & 16 /*VIDEO_DECODER_VBI*/) + ztv->have_decoder = 2; + else + ztv->have_decoder = 1; + break; + case I2C_DRIVERID_TUNER: + ztv->have_tuner = 1; + DEBUG(printk(CARD_INFO "tuner attached\n",CARD)); + if (ztv->tuner_type >= 0) + { + if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0) + DEBUG(printk(CARD_INFO "attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type)); + } + break; + default: + DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id)); + break; + } +} + +static +void detach_inform(struct i2c_bus *bus, int id) +{ + struct zoran *ztv = (struct zoran*)bus->data; + + switch (id) { + case I2C_DRIVERID_VIDEODECODER: + ztv->have_decoder = 0; + DEBUG(printk(CARD_INFO "decoder detached\n",CARD)); + break; + case I2C_DRIVERID_TUNER: + ztv->have_tuner = 0; + DEBUG(printk(CARD_INFO "tuner detached\n",CARD)); + break; + default: + DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id)); + break; + } +} + +struct i2c_bus zoran_i2c_bus_template = +{ + "ZR36120", + I2C_BUSID_ZORAN, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL +}; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/zr36120_mem.c linux/drivers/media/video/zr36120_mem.c --- v2.4.0-test6/linux/drivers/media/video/zr36120_mem.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36120_mem.c Mon Aug 7 21:01:36 2000 @@ -0,0 +1,77 @@ +/* + zr36120_mem.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BIGPHYS_AREA +#include +#endif + +#include "zr36120.h" +#include "zr36120_mem.h" + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +void* bmalloc(unsigned long size) +{ + void* mem; +#ifdef CONFIG_BIGPHYS_AREA + mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL); +#else + /* + * The following function got a lot of memory at boottime, + * so we know its always there... + */ + mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size)); +#endif + if (mem) { + unsigned long adr = (unsigned long)mem; + while (size > 0) { + mem_map_reserve(virt_to_page(phys_to_virt(adr))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +void bfree(void* mem, unsigned long size) +{ + if (mem) { + unsigned long adr = (unsigned long)mem; + unsigned long siz = size; + while (siz > 0) { + mem_map_unreserve(virt_to_page(phys_to_virt(adr))); + adr += PAGE_SIZE; + siz -= PAGE_SIZE; + } +#ifdef CONFIG_BIGPHYS_AREA + bigphysarea_free_pages(mem); +#else + free_pages((unsigned long)mem,get_order(size)); +#endif + } +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/media/video/zr36120_mem.h linux/drivers/media/video/zr36120_mem.h --- v2.4.0-test6/linux/drivers/media/video/zr36120_mem.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36120_mem.h Wed Dec 29 17:08:55 1999 @@ -0,0 +1,3 @@ +/* either kmalloc() or bigphysarea() alloced memory - continuous */ +void* bmalloc(unsigned long size); +void bfree(void* mem, unsigned long size); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/mtd/Config.in linux/drivers/mtd/Config.in --- v2.4.0-test6/linux/drivers/mtd/Config.in Fri Jul 14 12:12:10 2000 +++ linux/drivers/mtd/Config.in Sun Aug 13 10:21:20 2000 @@ -20,7 +20,7 @@ fi fi dep_tristate ' Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD - dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD + dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI if [ "$CONFIG_MTD_PMC551" != "n" ]; then bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX fi diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v2.4.0-test6/linux/drivers/net/3c501.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/3c501.c Fri Aug 11 15:57:57 2000 @@ -280,6 +280,13 @@ int i; /* + * Reserve I/O resource for exclusive use by this driver + */ + + if (!request_region(ioaddr, EL1_IO_EXTENT, dev->name)) + return -ENODEV; + + /* * Read the station address PROM data from the special port. */ @@ -302,15 +309,10 @@ { mname = "NP943"; } - else - return -ENODEV; - - /* - * Grab the region so we can find the another board if autoIRQ fails. - */ - - if (!request_region(ioaddr, EL1_IO_EXTENT,"3c501")) + else { + release_region(ioaddr, EL1_IO_EXTENT); return -ENODEV; + } /* * We auto-IRQ by shutting off the interrupt line and letting it float @@ -332,6 +334,7 @@ { printk("%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); + release_region(ioaddr, EL1_IO_EXTENT); return -EAGAIN; } } @@ -360,8 +363,10 @@ */ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + if (dev->priv == NULL) { + release_region(ioaddr, EL1_IO_EXTENT); return -ENOMEM; + } memset(dev->priv, 0, sizeof(struct net_local)); lp=dev->priv; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.4.0-test6/linux/drivers/net/3c59x.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/net/3c59x.c Sun Aug 13 19:27:39 2000 @@ -77,7 +77,29 @@ - Print a warning on out-of-memory (rate limited to 1 per 10 secs) - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland) + LK1.1.7 2 Jul 2000 andrewm + - Better handling of shared IRQs + - Reset the transmitter on a Tx reclaim error + - Fixed crash under OOM during vortex_open() (Mark Hemment) + - Fix Rx cessation problem during OOM (help from Mark Hemment) + - The spinlocks around the mdio access were blocking interrupts for 300uS. + Fix all this to use spin_lock_bh() within mdio_read/write + - Only write to TxFreeThreshold if it's a boomerang - other NICs don't + have one. + - Added 802.3x MAC-layer flow control support + + LK1.1.8 13 Aug 2000 andrewm + - Ignore request_region() return value - already reserved if Cardbus. + - Merged some additional Cardbus flags from Don's 0.99Qk + - Some fixes for 3c556 (Fred Maciel) + - Fix for EISA initialisation (Jan Rkorajski) + - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers + - Fixed MII_XCVR_PWR for 3CCFE575CT + - Added INVERT_LED_PWR, used it. + - Backed out the extra_reset stuff + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. + - Also see Documentation/networking/vortex.txt */ /* @@ -103,8 +125,6 @@ static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 32; -/* Give the NIC an extra reset at the end of vortex_up() */ -static int extra_reset = 0; /* Tx timeout interval (millisecs) */ static int watchdog = 400; @@ -163,16 +183,16 @@ #include static char version[] __devinitdata = -"3c59x.c:v0.99L+LK1.1.6 28 May 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.97 $\n"; +"3c59x.c:LK1.1.8 13 Aug 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.25 $\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(extra_reset, "i"); MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); @@ -281,8 +301,9 @@ }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, - EEPROM_230=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ - HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, }; + EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ + HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, + INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400 }; enum vortex_chips { @@ -312,14 +333,16 @@ CH_3CSOHO100_TX, CH_3C555, + CH_3C556, CH_3C575, CH_3C575_1, - CH_3CCFE575, + CH_3CCFE575, CH_3CCFE575CT, CH_3CCFE656, CH_3CCFEM656, CH_3CCFEM656_1, + CH_3C450, }; @@ -383,24 +406,26 @@ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, {"3c555 Laptop Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + {"3c556 10/100 Mini PCI Adapter", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, }, {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3c575 Boomerang CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, }, - {"3CCFE575 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, + {"3CCFE575BT Cyclone CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, }, {"3CCFE575CT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFEM656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, - {"3CCFEM656 Cyclone CardBus(0x6564)", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + {"3CCFEM656B Cyclone+Winmodem CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + {"3CCFE656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, + {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, - {0,}, /* 0 terminated list. */ }; @@ -432,16 +457,17 @@ { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, + { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 }, { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 }, { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, - { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, + { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, - { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, + { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, {0,} /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); @@ -612,16 +638,20 @@ /* The remainder are related to chip state, mostly media selection. */ struct timer_list timer; /* Media selection timer. */ + struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ int options; /* User-settable misc. driver options. */ unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ full_duplex:1, force_fd:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ + flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ + partner_flow_ctrl:1, /* Partner supports flow control */ tx_full:1, has_nway:1, - open:1; + open:1, + must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ + int drv_flags; int tx_reset_resume; /* Flag to retart timer after vortex_error handling */ u16 status_enable; u16 intr_enable; @@ -632,7 +662,8 @@ u16 deferred; /* Resend these interrupts when we * bale from the ISR */ u16 io_size; /* Size of PCI region (for release_region) */ - spinlock_t lock; + spinlock_t lock; /* Serialise access to device & its vortex_private */ + spinlock_t mdio_lock; /* Serialise access to mdio hardware */ }; /* The action to take with a media selection timer tick. @@ -669,9 +700,10 @@ static void vortex_down(struct net_device *dev); static int vortex_open(struct net_device *dev); static void mdio_sync(long ioaddr, int bits); -static int mdio_read(long ioaddr, int phy_id, int location); -static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *vp, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); +static void rx_oom_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); @@ -692,7 +724,9 @@ #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* #define dev_alloc_skb dev_alloc_skb_debug */ /* A list of all installed Vortex EISA devices, for removing the driver module. */ static struct net_device *root_vortex_eisa_dev = NULL; @@ -746,7 +780,7 @@ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { int device_id; - if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL) + if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "3c59x") == NULL) continue; /* Check the standard EISA ID register for an encoded '3Com'. */ @@ -780,7 +814,6 @@ return vortex_cards_found - orig_cards_found; } - /* returns count (>= 0), or negative on error */ static int __devinit vortex_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -815,6 +848,7 @@ if (!printed_version) { printk (KERN_INFO "%s", version); + printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); printed_version = 1; } @@ -836,6 +870,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; + vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; @@ -848,11 +883,9 @@ /* PCI-only startup logic */ if (pdev) { /* EISA resources already marked, so only PCI needs to do this here */ - if (!request_region (ioaddr, vci->io_size, dev->name)) { - printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", - dev->name, vci->io_size, ioaddr); - retval = -EBUSY; - goto free_dev; + /* Ignore return value, because Cardbus drivers already allocate for us */ + if (request_region(ioaddr, vci->io_size, dev->name) != NULL) { + vp->must_free_region = 1; } /* wake up and enable device */ @@ -866,15 +899,15 @@ pci_set_master (pdev); } - vp->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&vp->lock); + spin_lock_init(&vp->mdio_lock); vp->pdev = pdev; /* Makes sure rings are at least 16 byte aligned. */ vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); - if (vp->rx_ring == 0) - { + if (vp->rx_ring == 0) { retval = -ENOMEM; goto free_region; } @@ -888,8 +921,8 @@ pdev->driver_data = dev; /* The lower four bits are the media type. */ - if (dev->mem_start) - { /* + if (dev->mem_start) { + /* * AKPM: ewww.. The 'options' param is passed in as the third arg to the * LILO 'ether=' argument for non-modular use */ @@ -900,24 +933,26 @@ else option = -1; + vp->media_override = 7; if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 15; vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; - } else { - vp->media_override = 7; - vp->full_duplex = 0; - vp->bus_master = 0; } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - vp->full_duplex = 1; + + if (card_idx < MAX_UNITS) { + if (full_duplex[card_idx] > 0) + vp->full_duplex = 1; + if (flow_ctrl[card_idx] > 0) + vp->flow_ctrl = 1; + } vp->force_fd = vp->full_duplex; vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); { - int base = (vci->drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read; + int base = (vci->drv_flags & EEPROM_8BIT) ? 0x230 : EEPROM_Read; for (i = 0; i < 0x40; i++) { int timer; outw(base + i, ioaddr + Wn0EepromCmd); @@ -960,17 +995,21 @@ if (pdev && vci->drv_flags & HAS_CB_FNS) { unsigned long fn_st_addr; /* Cardbus function status space */ + unsigned short n; + fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) vp->cb_fn_base = ioremap(fn_st_addr, 128); printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", dev->name, fn_st_addr, vp->cb_fn_base); -#if 1 /* AKPM: the 575_cb and 905B LEDs seem OK without this */ - if (vortex_pci_tbl[chip_idx].device != 0x5257) { - EL3WINDOW(2); - outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } -#endif + EL3WINDOW(2); + + n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + if (vp->drv_flags & INVERT_LED_PWR) + n |= 0x10; + if (vp->drv_flags & INVERT_MII_PWR) + n |= 0x4000; + outw(n, ioaddr + Wn2_ResetOptions); } /* Extract our information from the EEPROM data. */ @@ -978,8 +1017,7 @@ vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if (vp->info1 & 0x8000) - { + if (vp->info1 & 0x8000) { vp->full_duplex = 1; printk(KERN_INFO "Full duplex capable\n"); } @@ -1018,10 +1056,10 @@ EL3WINDOW(4); mii_preamble_required++; mii_preamble_required++; - mdio_read(ioaddr, 24, 1); + mdio_read(dev, 24, 1); for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { int mii_status, phyx = phy & 0x1f; - mii_status = mdio_read(ioaddr, phyx, 1); + mii_status = mdio_read(dev, phyx, 1); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; printk(KERN_INFO " MII transceiver found at address %d," @@ -1035,11 +1073,11 @@ printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { - vp->advertising = mdio_read(ioaddr, vp->phys[0], 4); + vp->advertising = mdio_read(dev, vp->phys[0], 4); if (vp->full_duplex) { /* Only advertise the FD media types. */ vp->advertising &= ~0x02A0; - mdio_write(ioaddr, vp->phys[0], 4, vp->advertising); + mdio_write(dev, vp->phys[0], 4, vp->advertising); } } } @@ -1056,20 +1094,21 @@ } /* The 3c59x-specific entries in the device structure. */ - dev->open = &vortex_open; - dev->hard_start_xmit = &vortex_start_xmit; - dev->stop = &vortex_close; - dev->get_stats = &vortex_get_stats; - dev->do_ioctl = &vortex_ioctl; - dev->set_multicast_list = &set_rx_mode; - dev->tx_timeout = &vortex_tx_timeout; + dev->open = vortex_open; + dev->hard_start_xmit = vp->full_bus_master_tx ? + boomerang_start_xmit : vortex_start_xmit; + dev->stop = vortex_close; + dev->get_stats = vortex_get_stats; + dev->do_ioctl = vortex_ioctl; + dev->set_multicast_list = set_rx_mode; + dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; return 0; free_region: - release_region (ioaddr, vci->io_size); -free_dev: + if (vp->must_free_region) + release_region(ioaddr, vci->io_size); unregister_netdev(dev); kfree (dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1082,8 +1121,7 @@ int i = 4000; outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - { + while (--i > 0) { if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) return; } @@ -1136,9 +1174,13 @@ init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ + vp->timer.function = vortex_timer; /* timer handler */ add_timer(&vp->timer); + init_timer(&vp->rx_oom_timer); + vp->rx_oom_timer.data = (unsigned long)dev; + vp->rx_oom_timer.function = rx_oom_timer; + if (vortex_debug > 1) printk(KERN_DEBUG "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1157,13 +1199,14 @@ int mii_reg1, mii_reg5; EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); - mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + mii_reg1 = mdio_read(dev, vp->phys[0], 1); + mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; + vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," " setting %s-duplex.\n", dev->name, vp->phys[0], @@ -1172,8 +1215,10 @@ } /* Set the full-duplex bit. */ - outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) { printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", @@ -1199,15 +1244,10 @@ outw(0, ioaddr + i); if (vp->cb_fn_base) { - u_short n = inw(ioaddr + Wn2_ResetOptions); -#if 0 /* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */ - /* Inverted LED polarity */ - if (device_id != 0x5257) - n |= 0x0010; -#endif - /* Inverted polarity of MII power bit */ - if ((device_id == 0x6560) || (device_id == 0x6562) || - (device_id == 0x5257)) + unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + if (vp->drv_flags & INVERT_LED_PWR) + n |= 0x10; + if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } @@ -1245,9 +1285,9 @@ outl(vp->rx_ring_dma, ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ - dev->hard_start_xmit = &boomerang_start_xmit; vp->cur_tx = vp->dirty_tx = 0; - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ + if (vp->drv_flags & IS_BOOMERANG) + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Rx, Tx rings. */ for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ vp->rx_ring[i].status = 0; @@ -1277,17 +1317,6 @@ outw(vp->intr_enable, ioaddr + EL3_CMD); if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); - - if (extra_reset) - { - /* AKPM: unjam the 3CCFE575CT */ - wait_for_completion(dev, TxReset); - if (vp->full_bus_master_tx) { - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - outw(DownUnstall, ioaddr + EL3_CMD); - } - outw(TxEnable, ioaddr + EL3_CMD); - } netif_start_queue (dev); } @@ -1301,9 +1330,9 @@ MOD_INC_USE_COUNT; /* Use the now-standard shared IRQ implementation. */ - if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, - SA_SHIRQ, dev->name, dev)) { - retval = -EAGAIN; + if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? + &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto out; } @@ -1323,6 +1352,17 @@ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } + if (i != RX_RING_SIZE) { + int j; + for (j = 0; j < RX_RING_SIZE; j++) { + if (vp->rx_skbuff[j]) { + dev_kfree_skb(vp->rx_skbuff[j]); + vp->rx_skbuff[j] = 0; + } + } + retval = -ENOMEM; + goto out_free_irq; + } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); } @@ -1330,10 +1370,13 @@ vortex_up(dev); vp->open = 1; return 0; + +out_free_irq: + free_irq(dev->irq, dev); out: - MOD_DEC_USE_COUNT; if (vortex_debug > 1) - printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval); + printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); + MOD_DEC_USE_COUNT; return retval; } @@ -1346,7 +1389,7 @@ int ok = 0; int media_status, mii_status, old_window; - if (vortex_debug > 1) { + if (vortex_debug > 2) { printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); @@ -1369,16 +1412,13 @@ break; case XCVR_MII: case XCVR_NWAY: { - unsigned long flags; - spin_lock_irqsave(&vp->lock, flags); /* AKPM: protect mdio state */ - - mii_status = mdio_read(ioaddr, vp->phys[0], 1); + mii_status = mdio_read(dev, vp->phys[0], 1); ok = 1; - if (vortex_debug > 1) + if (vortex_debug > 2) printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", dev->name, mii_status); if (mii_status & 0x0004) { - int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + int mii_reg5 = mdio_read(dev, vp->phys[0], 5); if (! vp->force_fd && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; @@ -1390,17 +1430,16 @@ vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */ - outb((vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), - ioaddr + Wn3_MAC_Ctrl); + outw( (vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n"); /* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */ } - next_tick = 60*HZ; } } - spin_unlock_irqrestore(&vp->lock, flags); } break; default: /* Other media types handled by Tx timeouts. */ @@ -1445,7 +1484,7 @@ EL3WINDOW(old_window); enable_irq(dev->irq); - if (vortex_debug > 1) + if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1506,7 +1545,8 @@ } if (vp->tx_full) netif_stop_queue (dev); - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); + if (vp->drv_flags & IS_BOOMERANG) + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); } else { vp->stats.tx_dropped++; @@ -1549,8 +1589,8 @@ if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; outb(0, ioaddr + TxStatus); - if (tx_status & 0x38) /* AKPM: tx reset after 16 collisions, despite what the manual says */ - do_tx_reset = 1; + if (tx_status & 0x3a) /* TxReset after 16 collisions, despite what the manual says */ + do_tx_reset = 1; /* Also reset on reclaim errors */ else /* Merely re-enable the transmitter. */ outw(TxEnable, ioaddr + EL3_CMD); } @@ -1592,7 +1632,7 @@ /* In this case, blow the card away */ vortex_down(dev); wait_for_completion(dev, TotalReset | 0xff); - vortex_up(dev); + vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */ } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { @@ -1706,12 +1746,13 @@ struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; - if (vortex_debug > 6) + if (vortex_debug > 6) { printk(KERN_DEBUG "boomerang_start_xmit()\n"); + if (vortex_debug > 3) + printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", + dev->name, vp->cur_tx); + } - if (vortex_debug > 3) - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); if (vp->tx_full) { if (vortex_debug > 0) printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", @@ -1765,15 +1806,18 @@ long ioaddr; int status; int work_done = max_interrupt_work; - - spin_lock(&vp->lock); ioaddr = dev->base_addr; + spin_lock(&vp->lock); + status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk("vortex_interrupt(). status=0x%4x\n", status); + if ((status & IntLatch) == 0) + goto handler_exit; /* No interrupt: shared IRQs cause this */ + if (status & IntReq) { status |= vp->deferred; vp->deferred = 0; @@ -1785,6 +1829,7 @@ if (vortex_debug > 4) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, inb(ioaddr + Timer)); + do { if (vortex_debug > 5) printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", @@ -1841,9 +1886,6 @@ } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); if (vortex_debug > 4) @@ -1866,14 +1908,22 @@ int status; int work_done = max_interrupt_work; - spin_lock(&vp->lock); - ioaddr = dev->base_addr; + + /* + * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout + * and boomerang_start_xmit + */ + spin_lock(&vp->lock); + status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); + if ((status & IntLatch) == 0) + goto handler_exit; /* No interrupt: shared IRQs can cause this */ + if (status == 0xffff) { /* AKPM: h/w no longer present (hotplug)? */ if (vortex_debug > 1) printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); @@ -2120,6 +2170,8 @@ printk(KERN_WARNING "%s: memory shortage\n", dev->name); last_jif = jiffies; } + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) + mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1)); break; /* Bad news! */ } skb->dev = dev; /* Mark as being used by this device. */ @@ -2133,6 +2185,26 @@ return 0; } +/* + * If we've hit a total OOM refilling the Rx ring we poll once a second + * for some memory. Otherwise there is no way to restart the rx process. + */ +static void +rx_oom_timer(unsigned long arg) +{ + struct net_device *dev = (struct net_device *)arg; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + + spin_lock_irq(&vp->lock); + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ + boomerang_rx(dev); + if (vortex_debug > 1) { + printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); + } + spin_unlock_irq(&vp->lock); +} + static void vortex_down(struct net_device *dev) { @@ -2141,6 +2213,7 @@ netif_stop_queue (dev); + del_timer_sync(&vp->rx_oom_timer); del_timer_sync(&vp->timer); /* Turn off statistics ASAP. We update vp->stats below. */ @@ -2311,16 +2384,13 @@ u16 *data = (u16 *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; int retval; - unsigned long flags; - - spin_lock_irqsave(&vp->lock, flags); switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ EL3WINDOW(4); - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); retval = 0; break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ @@ -2328,7 +2398,7 @@ retval = -EPERM; } else { EL3WINDOW(4); - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); retval = 0; } break; @@ -2337,7 +2407,6 @@ break; } - spin_unlock_irqrestore(&vp->lock, flags); return retval; } @@ -2393,13 +2462,17 @@ } } -static int mdio_read(long ioaddr, int phy_id, int location) +static int mdio_read(struct net_device *dev, int phy_id, int location) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; int i; + long ioaddr = dev->base_addr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; + spin_lock_bh(&vp->mdio_lock); + if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2419,15 +2492,20 @@ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } + spin_unlock_bh(&vp->mdio_lock); return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; } -static void mdio_write(long ioaddr, int phy_id, int location, int value) +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; + spin_lock_bh(&vp->mdio_lock); + if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2446,7 +2524,7 @@ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } - + spin_unlock_bh(&vp->mdio_lock); return; } @@ -2458,7 +2536,7 @@ long ioaddr = dev->base_addr; /* AKPM: This kills the 905 */ - if (vortex_debug > 0) { + if (vortex_debug > 1) { printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n"); } return; @@ -2493,7 +2571,8 @@ */ unregister_netdev(dev); outw(TotalReset, dev->base_addr + EL3_CMD); - release_region(dev->base_addr, vp->io_size); + if (vp->must_free_region) + release_region(dev->base_addr, vp->io_size); kfree(dev); } @@ -2516,21 +2595,15 @@ { int rc; - rc = pci_module_init (&vortex_driver); - if (rc < 0) - goto out; - - if (rc >= 0) /* AKPM: had "> 0" */ + rc = pci_module_init(&vortex_driver); + if (rc < 0) { + rc = vortex_eisa_init(); + if (rc > 0) + vortex_have_eisa = 1; + } else { vortex_have_pci = 1; + } - rc = vortex_eisa_init (); - if (rc < 0) - goto out; - - if (rc > 0) - vortex_have_eisa = 1; - -out: return rc; } @@ -2575,8 +2648,6 @@ /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.0-test6/linux/drivers/net/Config.in Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/Config.in Wed Aug 23 09:30:13 2000 @@ -8,9 +8,10 @@ tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER +tristate 'Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP + tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP fi fi @@ -143,15 +144,18 @@ bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM fi tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 - tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi + dep_tristate ' National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI - # tristate ' Sundance Alta support' CONFIG_ALTA + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 fi tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 + # tristate ' Sundance Alta support' CONFIG_ALTA tristate ' TI ThunderLAN support' CONFIG_TLAN tristate ' VIA Rhine support' CONFIG_VIA_RHINE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.0-test6/linux/drivers/net/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/Makefile Wed Aug 23 09:30:13 2000 @@ -136,7 +136,7 @@ obj-$(CONFIG_DM9102) += dmfe.o obj-$(CONFIG_YELLOWFIN) += yellowfin.o obj-$(CONFIG_ACENIC) += acenic.o - +obj-$(CONFIG_NATSEMI) += natsemi.o obj-$(CONFIG_STNIC) += stnic.o 8390.o ifeq ($(CONFIG_SK98LIN),y) @@ -273,7 +273,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o - +obj-$(CONFIG_TUN) += tun.o # # HIPPI adapters # diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.4.0-test6/linux/drivers/net/Space.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/net/Space.c Wed Aug 23 09:30:13 2000 @@ -102,11 +102,10 @@ extern int mac8390_probe(struct net_device *dev); extern int mac89x0_probe(struct net_device *dev); - /* Gigabit Ethernet adapters */ - extern int yellowfin_probe(struct net_device *dev); +/* Gigabit Ethernet adapters */ +extern int yellowfin_probe(struct net_device *dev); /* Detachable devices ("pocket adaptors") */ -extern int atp_init(struct net_device *); extern int de600_probe(struct net_device *); extern int de620_probe(struct net_device *); @@ -310,9 +309,6 @@ #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ {de620_probe, 0}, #endif -#ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */ - {atp_init, 0}, -#endif {NULL, 0}, }; @@ -681,8 +677,15 @@ #undef NEXT_DEV #define NEXT_DEV (&escon0_dev) #endif - - + +#ifdef CONFIG_TUN + extern int tun_init(struct net_device *dev); + static struct net_device tun_dev = { + "tun", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, tun_init }; +# undef NEXT_DEV +# define NEXT_DEV (&tun_dev) +#endif + /* * The loopback device is global so it can be directly referenced * by the network code. Also, it must be first on device list. diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.4.0-test6/linux/drivers/net/atp.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/net/atp.c Fri Aug 11 15:57:57 2000 @@ -154,7 +154,7 @@ (detachable devices only). */ -int __init atp_init(struct net_device *dev) +static int __init atp_init(struct net_device *dev) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; int base_addr = dev->base_addr; @@ -336,6 +336,9 @@ return -EAGAIN; } hardware_init(dev); + + MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -702,6 +705,8 @@ /* Leave the hardware in a reset state. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET); + MOD_DEC_USE_COUNT; + return 0; } @@ -735,35 +740,27 @@ lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; write_reg_high(ioaddr, CMR2, lp->addr_mode); } - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c atp.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ - -#ifdef MODULE -static int io = 0; -static struct net_device atp_dev = { - "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_init }; - +/* module stuff */ +static int io; +static struct net_device atp_dev = { init: atp_init }; +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Realtek 8002/8012 Pocket Lan Adapter"); MODULE_PARM(io, "I/O port of the pocket adapter"); -int init_module(void) -{ +static int __init atp_init_module(void) { atp_dev.base_addr = io; + if (register_netdev(&atp_dev) != 0) return -EIO; + return 0; } -void cleanup_module(void) -{ +static void __exit atp_cleanup_module(void) { unregister_netdev(&atp_dev); } -#endif +module_init(atp_init_module); +module_exit(atp_cleanup_module); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.4.0-test6/linux/drivers/net/eepro100.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/eepro100.c Fri Aug 11 19:14:46 2000 @@ -23,6 +23,8 @@ Convert to new PCI driver interface 2000 Mar 24 Dragan Stancevic Disabled FC and ER, to avoid lockups when when we get FCP interrupts. + 2000 Jul 17 Goutham Rao + PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary */ static const char *version = @@ -515,6 +517,7 @@ spinlock_t lock; /* Group with Tx control cache line. */ u32 tx_threshold; /* The value for txdesc.count. */ struct RxFD *last_rxf; /* Last filled RX buffer. */ + dma_addr_t last_rxf_dma; unsigned int cur_rx, dirty_rx; /* The next free ring entry */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ const char *product_name; @@ -1213,19 +1216,24 @@ sp->rx_ring_dma[i] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb_reserve(skb, sizeof(struct RxFD)); - if (last_rxf) + if (last_rxf) { last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); + } last_rxf = rxf; rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = last_rxf; + sp->last_rxf_dma = sp->rx_ring_dma[RX_RING_SIZE-1]; } static void speedo_purge_tx(struct net_device *dev) @@ -1660,6 +1668,7 @@ skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; } @@ -1672,7 +1681,9 @@ rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); sp->last_rxf->link = cpu_to_le32(rxf_dma); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); + pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = rxf; + sp->last_rxf_dma = rxf_dma; } static int speedo_refill_rx_buf(struct net_device *dev, int force) @@ -1738,9 +1749,17 @@ if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ - while (sp->rx_ringp[entry] != NULL && - (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) { - int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; + while (sp->rx_ringp[entry] != NULL) { + int pkt_len; + + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + + if(!((status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete)) { + break; + } + + pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; if (--rx_work_limit < 0) break; @@ -1782,7 +1801,8 @@ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE); + #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -2165,6 +2185,8 @@ /* Set the link in the setup frame. */ mc_setup_frm->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); + + pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, mc_blk->len, PCI_DMA_TODEVICE); wait_for_cmd_done(ioaddr + SCBCmd); clear_suspend(last_cmd); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.0-test6/linux/drivers/net/epic100.c Mon Jul 10 16:47:23 2000 +++ linux/drivers/net/epic100.c Fri Aug 11 15:57:57 2000 @@ -19,17 +19,30 @@ Information and updates available at http://www.scyld.com/network/epic100.html + + --------------------------------------------------------------------- Linux kernel-specific changes: LK1.1.2 (jgarzik): - * Merge becker version 1.09 + * Merge becker version 1.09 (4/08/2000) LK1.1.3: * Major bugfix to 1.09 driver (Francis Romieu) + + LK1.1.4 (jgarzik): + * Merge becker test version 1.09 (5/29/2000) */ +/* These identify the driver base version and may not be removed. */ +static const char version[] = +"epic100.c:v1.09 5/29/2000 Written by Donald Becker \n"; +static const char version2[] = +" http://www.scyld.com/network/epic100.html\n"; +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -44,11 +57,12 @@ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 200; +static int rx_copybreak = 0; /* Operational parameters that are set at compile time. */ -/* Keep the ring sizes a power of two for efficiency. +/* Keep the ring sizes a power of two for operational efficiency. + The compiler will convert '%'<2^N> into a bit mask. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ @@ -73,7 +87,12 @@ #error You must compile this driver with "-O". #endif +#include #include +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include +#endif + #include #include #include @@ -91,15 +110,6 @@ #include #include -/* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = -"epic100.c:v1.09+LK1.1.3 6/17/2000 Written by Donald Becker \n"; -static char version2[] __devinitdata = -" http://www.scyld.com/network/epic100.html\n"; - -#define EPIC100_MODULE_NAME "epic100" -#define PFX EPIC100_MODULE_NAME ": " - MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); MODULE_PARM(debug, "i"); @@ -133,7 +143,7 @@ http://www.smsc.com/main/datasheets/83c171.pdf http://www.smsc.com/main/datasheets/83c175.pdf -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://scyld.com/expert/NWay.html http://www.national.com/pf/DP/DP83840A.html IVc. Errata @@ -149,10 +159,8 @@ PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, }; - enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; - #define EPIC_TOTAL_SIZE 0x100 #ifdef USE_IO_OPS #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0 @@ -289,6 +297,7 @@ int tx_threshold; unsigned char mc_filter[8]; signed char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ int mii_phy_cnt; unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Current duplex setting. */ @@ -332,7 +341,8 @@ card_idx++; if (!printed_version++) - printk (KERN_INFO "%s" KERN_INFO "%s", version, version2); + printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version, version2, version3); if ((pci_resource_len(pdev, 0) < ci->io_size) || (pci_resource_len(pdev, 1) < ci->io_size)) { @@ -357,12 +367,12 @@ * to them */ if (!request_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx); + printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); goto err_out_free_netdev; } if (!request_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR PFX "card %d: I/O region busy\n", card_idx); + printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); goto err_out_free_pio; } @@ -372,7 +382,7 @@ ioaddr = pci_resource_start (pdev, 1); ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { - printk (KERN_ERR PFX "card %d: ioremap failed\n", card_idx); + printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx); goto err_out_free_mmio; } #endif @@ -387,7 +397,7 @@ duplex = full_duplex[card_idx]; } - pdev->driver_data = dev; + pdev->driver_data = dev; dev->base_addr = ioaddr; dev->irq = pdev->irq; @@ -426,25 +436,26 @@ /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ + takes much time and no cards have external MII. */ { - int phy, phy_idx; - for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys); - phy++) { + int phy, phy_idx = 0; + for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { + if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; printk(KERN_INFO "%s: MII transceiver #%d control " - "%4.4x status %4.4x.\n" - KERN_INFO "%s: Autonegotiation advertising %4.4x " - "link partner %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status, - dev->name, mdio_read(ioaddr, phy, 4), - mdio_read(ioaddr, phy, 5)); + "%4.4x status %4.4x.\n", + dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status); } } ep->mii_phy_cnt = phy_idx; - if (phy_idx == 0 && (ep->chip_flags & NO_MII) == 0) { + if (phy_idx != 0) { + phy = ep->phys[0]; + ep->advertising = mdio_read(ioaddr, phy, 4); + printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link " + "partner %4.4x.\n", + dev->name, ep->advertising, mdio_read(ioaddr, phy, 5)); + } else if ( ! (ep->chip_flags & NO_MII)) { printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", dev->name); /* Use the known PHY address of the EPII. */ @@ -668,7 +679,7 @@ if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " "%s-duplex.\n", - dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL), + dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), ep->full_duplex ? "full" : "half"); /* Set the timer to switch to check for link beat and perhaps switch @@ -752,8 +763,8 @@ ioaddr + INTMASK); printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", - dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL), - inl(ioaddr + INTSTAT)); + dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), + (int)inl(ioaddr + INTSTAT)); return; } @@ -764,18 +775,19 @@ long ioaddr = dev->base_addr; int next_tick = 60*HZ; int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0; + int negotiated = mii_reg5 & ep->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", - dev->name, inl(ioaddr + TxSTAT)); + dev->name, (int)inl(ioaddr + TxSTAT)); printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x " "IntStatus %4.4x RxStatus %4.4x.\n", - dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT), - inl(ioaddr + RxSTAT)); + dev->name, (int)inl(ioaddr + INTMASK), + (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); } - if (! ep->force_fd && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + if (! ep->force_fd) { if (ep->full_duplex != duplex) { ep->full_duplex = duplex; printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" @@ -797,7 +809,7 @@ if (debug > 0) { printk(KERN_WARNING "%s: Transmit timeout using MII device, " "Tx status %4.4x.\n", - dev->name, inw(ioaddr + TxSTAT)); + dev->name, (int)inw(ioaddr + TxSTAT)); if (debug > 1) { printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n", dev->name, ep->dirty_tx, ep->cur_tx); @@ -880,11 +892,11 @@ ep->tx_skbuff[entry] = skb; ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); - if (free_count < TX_RING_SIZE/2) {/* Typical path */ + if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ - } else if (free_count == TX_RING_SIZE/2) { + } else if (free_count == TX_QUEUE_LEN/2) { ctrl_word = cpu_to_le32(0x140000); /* Tx-done intr. */ - } else if (free_count < TX_RING_SIZE - 1) { + } else if (free_count < TX_QUEUE_LEN - 1) { ctrl_word = cpu_to_le32(0x100000); /* No Tx-done intr. */ } else { /* Leave room for an additional entry. */ @@ -910,7 +922,7 @@ printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, " "flag %2.2x Tx status %8.8x.\n", dev->name, (int)skb->len, entry, ctrl_word, - inl(dev->base_addr + TxSTAT)); + (int)inl(dev->base_addr + TxSTAT)); return 0; } @@ -924,7 +936,8 @@ long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - spin_lock(&ep->lock); + if (!spin_trylock(&ep->lock)) + return; do { status = inl(ioaddr + INTSTAT); @@ -932,9 +945,9 @@ outl(status & 0x00007fff, ioaddr + INTSTAT); if (debug > 4) - printk(KERN_DEBUG "%s: interrupt interrupt=%#8.8x new " + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " "intstat=%#8.8x.\n", - dev->name, status, inl(ioaddr + INTSTAT)); + dev->name, status, (int)inl(ioaddr + INTSTAT)); if ((status & IntrSummary) == 0) break; @@ -995,7 +1008,7 @@ #endif ep->dirty_tx = dirty_tx; if (ep->tx_full - && cur_tx - dirty_tx < TX_RING_SIZE + 2) { + && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; netif_wake_queue(dev); @@ -1044,7 +1057,7 @@ if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + INTSTAT)); + dev->name, status); spin_unlock(&ep->lock); } @@ -1144,7 +1157,7 @@ if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl(ioaddr + INTSTAT)); + dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); epic_pause(dev); @@ -1333,7 +1346,7 @@ static struct pci_driver epic_driver = { - name: EPIC100_MODULE_NAME, + name: "epic100", id_table: epic_pci_tbl, probe: epic_init_one, remove: epic_remove_one, @@ -1356,14 +1369,3 @@ module_init(epic_init); module_exit(epic_cleanup); - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia/include/" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.4.0-test6/linux/drivers/net/ewrk3.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/ewrk3.c Fri Aug 11 15:57:57 2000 @@ -843,6 +843,7 @@ } } + lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb(skb); } else { /* return unused page to the free memory queue */ @@ -1010,6 +1011,7 @@ ** Update stats */ lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { if (pkt_len < i * EWRK3_PKT_BIN_SZ) { lp->pktStats.bins[i]++; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/fc/Makefile linux/drivers/net/fc/Makefile --- v2.4.0-test6/linux/drivers/net/fc/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/fc/Makefile Sat Aug 12 12:13:10 2000 @@ -1,27 +1,15 @@ - +# # Makefile for linux/drivers/net/fc # -# 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). +# 9 Aug 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. # -L_TARGET := fc.a -L_OBJS := -M_OBJS := -MX_OBJS := -FC_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) +O_TARGET := fc.o -ifeq ($(CONFIG_IPHASE5526),y) -L_OBJS += iph5526.o -else - ifeq ($(CONFIG_IPHASE5526),m) - M_OBJS += iph5526.o - endif -endif +obj-$(CONFIG_IPHASE5526) += iph5526.o -include $(TOPDIR)/Rules.make - -clean: - rm *.o +O_OBJS := $(obj-y) +M_OBJS := $(obj-m) +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile --- v2.4.0-test6/linux/drivers/net/hamradio/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/hamradio/Makefile Sat Aug 12 12:13:10 2000 @@ -1,153 +1,55 @@ -# File: drivers/hamradio/Makefile # # Makefile for the Linux AX.25 and HFMODEM device drivers. # +# # 19971130 Moved the amateur radio related network drivers from # drivers/net/ to drivers/hamradio for easier maintainance. # Joerg Reuter DL1BKE +# +# 20000806 Rewritten to use lists instead of if-statements. +# Christoph Hellwig +# SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) soundmodem O_TARGET := hamradio.o -O_OBJS := -M_OBJS := - -# Need these to keep track of whether the hdlc module should -# really go in the kernel or a module. -CONFIG_HDLCDRV_BUILTIN := -CONFIG_HDLCDRV_MODULE := - -ifeq ($(CONFIG_DMASCC),y) -O_OBJS += dmascc.o -else - ifeq ($(CONFIG_DMASCC),m) - M_OBJS += dmascc.o - endif -endif - -ifeq ($(CONFIG_SCC),y) -O_OBJS += scc.o -else - ifeq ($(CONFIG_SCC),m) - M_OBJS += scc.o - endif -endif - -ifeq ($(CONFIG_MKISS),y) -O_OBJS += mkiss.o -else - ifeq ($(CONFIG_MKISS),m) - M_OBJS += mkiss.o - endif -endif - -ifeq ($(CONFIG_6PACK),y) -O_OBJS += 6pack.o -else - ifeq ($(CONFIG_6PACK),m) - M_OBJS += 6pack.o - endif -endif - -ifeq ($(CONFIG_YAM),y) -O_OBJS += yam.o -else - ifeq ($(CONFIG_YAM),m) - M_OBJS += yam.o - endif -endif - -ifeq ($(CONFIG_PI),y) -O_OBJS += pi2.o -else - ifeq ($(CONFIG_PI),m) - M_OBJS += pi2.o - endif -endif -ifeq ($(CONFIG_PT),y) -O_OBJS += pt.o -else - ifeq ($(CONFIG_PT),m) - M_OBJS += pt.o - endif -endif - -ifeq ($(CONFIG_BPQETHER),y) -O_OBJS += bpqether.o -else - ifeq ($(CONFIG_BPQETHER),m) - M_OBJS += bpqether.o - endif -endif +export-objs = hdlcdrv.o -ifeq ($(CONFIG_BAYCOM_SER_FDX),y) -O_OBJS += baycom_ser_fdx.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_SER_FDX),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_ser_fdx.o - endif -endif -ifeq ($(CONFIG_BAYCOM_SER_HDX),y) -O_OBJS += baycom_ser_hdx.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_SER_HDX),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_ser_hdx.o - endif -endif - -ifeq ($(CONFIG_BAYCOM_PAR),y) -O_OBJS += baycom_par.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_PAR),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_par.o - endif -endif - -ifeq ($(CONFIG_BAYCOM_EPP),y) -O_OBJS += baycom_epp.o -CONFIG_HDLCDRV_BUILTIN = y -else - ifeq ($(CONFIG_BAYCOM_EPP),m) - CONFIG_HDLCDRV_MODULE = y - M_OBJS += baycom_epp.o - endif -endif +obj-$(CONFIG_DMASCC) += dmascc.o +obj-$(CONFIG_SCC) += scc.o +obj-$(CONFIG_MKISS) += mkiss.o +obj-$(CONFIG_6PACK) += 6pack.o +obj-$(CONFIG_YAM) += yam.o +obj-$(CONFIG_PI) += pi2.o +obj-$(CONFIG_PT) += pt.o +obj-$(CONFIG_BPQETHER) += bpqether.o +obj-$(CONFIG_BAYCOM_SER_FDX) += baycom_ser_fdx.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o +obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o +obj-$(CONFIG_SOUNDMODEM) += hdlcdrv.o ifeq ($(CONFIG_SOUNDMODEM),y) -ALL_SUB_DIRS += soundmodem SUB_DIRS += soundmodem O_OBJS += soundmodem/soundmodem.o -CONFIG_HDLCDRV_BUILTIN = y else ifeq ($(CONFIG_SOUNDMODEM),m) - CONFIG_HDLCDRV_MODULE = y - ALL_SUB_DIRS += soundmodem MOD_SUB_DIRS += soundmodem endif endif -# If anything built-in uses the hdlcdrv, then build it into the kernel also. -# If not, but a module uses it, build as a module. -ifdef CONFIG_HDLCDRV_BUILTIN -OX_OBJS += hdlcdrv.o -else - ifdef CONFIG_HDLCDRV_MODULE - MX_OBJS += hdlcdrv.o - endif -endif +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) -include $(TOPDIR)/Rules.make +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -clean: - rm -f core *.o *.a *.s +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.4.0-test6/linux/drivers/net/hamradio/scc.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/hamradio/scc.c Mon Aug 21 08:57:35 2000 @@ -120,8 +120,8 @@ please (!) contact me first. New versions of the driver will be announced on the linux-hams - mailing list on vger.rutgers.edu. To subscribe send an e-mail - to majordomo@vger.rutgers.edu with the following line in + mailing list on vger.kernel.org. To subscribe send an e-mail + to majordomo@vger.kernel.org with the following line in the body of the mail: subscribe linux-hams diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile --- v2.4.0-test6/linux/drivers/net/irda/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/irda/Makefile Sat Aug 12 12:13:10 2000 @@ -1,121 +1,40 @@ -# File: drivers/irda/Makefile # # Makefile for the Linux IrDA infrared port device drivers. # +# 9 Aug 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := irda_drivers.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_IRTTY_SIR),y) -L_OBJS += irtty.o -else - ifeq ($(CONFIG_IRTTY_SIR),m) - M_OBJS += irtty.o - endif -endif - -ifeq ($(CONFIG_IRPORT_SIR),y) -LX_OBJS += irport.o -else - ifeq ($(CONFIG_IRPORT_SIR),m) - MX_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_NSC_FIR),y) -L_OBJS += nsc-ircc.o -else - ifeq ($(CONFIG_NSC_FIR),m) - M_OBJS += nsc-ircc.o - endif -endif - -ifeq ($(CONFIG_WINBOND_FIR),y) -L_OBJS += w83977af_ir.o -else - ifeq ($(CONFIG_WINBOND_FIR),m) - M_OBJS += w83977af_ir.o - endif -endif - -ifeq ($(CONFIG_TOSHIBA_FIR),y) -L_OBJS += toshoboe.o -else - ifeq ($(CONFIG_TOSHIBA_FIR),m) - M_OBJS += toshoboe.o - endif -endif - -ifeq ($(CONFIG_SMC_IRCC_FIR),y) -L_OBJS += smc-ircc.o -LX_OBJS += irport.o -else - ifeq ($(CONFIG_SMC_IRCC_FIR),m) - M_OBJS += smc-ircc.o - MX_OBJS += irport.o - endif -endif - -ifeq ($(CONFIG_ESI_DONGLE),y) -L_OBJS += esi.o -else - ifeq ($(CONFIG_ESI_DONGLE),m) - M_OBJS += esi.o - endif -endif - -ifeq ($(CONFIG_TEKRAM_DONGLE),y) -L_OBJS += tekram.o -else - ifeq ($(CONFIG_TEKRAM_DONGLE),m) - M_OBJS += tekram.o - endif -endif - -ifeq ($(CONFIG_ACTISYS_DONGLE),y) -L_OBJS += actisys.o -else - ifeq ($(CONFIG_ACTISYS_DONGLE),m) - M_OBJS += actisys.o - endif -endif - -ifeq ($(CONFIG_GIRBIL_DONGLE),y) -L_OBJS += girbil.o -else - ifeq ($(CONFIG_GIRBIL_DONGLE),m) - M_OBJS += girbil.o - endif -endif - -ifeq ($(CONFIG_LITELINK_DONGLE),y) -L_OBJS += litelink.o -else - ifeq ($(CONFIG_LITELINK_DONGLE),m) - M_OBJS += litelink.o - endif -endif - -ifeq ($(CONFIG_OLD_BELKIN_DONGLE),y) -L_OBJS += old_belkin.o -else - ifeq ($(CONFIG_OLD_BELKIN_DONGLE),m) - M_OBJS += old_belkin.o - endif -endif - -include $(TOPDIR)/Rules.make - -clean: - rm -f core *.o *.a *.s - - +O_TARGET := irda.o +export-objs = irport.o +obj-$(CONFIG_IRTTY_SIR) += irtty.o +obj-$(CONFIG_IRPORT_SIR) += irport.o +obj-$(CONFIG_NSC_FIR) += nsc-ircc.o +obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o +obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o +obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o +obj-$(CONFIG_ESI_DONGLE) += esi.o +obj-$(CONFIG_TEKRAM_DONGLE) += tekram.o +obj-$(CONFIG_ACTISYS_DONGLE) += actisys.o +obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o +obj-$(CONFIG_LITELINK_DONGLE) += litelink.o +obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o + + +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) + +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c --- v2.4.0-test6/linux/drivers/net/natsemi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/natsemi.c Fri Aug 11 17:56:52 2000 @@ -0,0 +1,1186 @@ +/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP83810 series. */ +/* + Written/copyright 1999-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. License for under other terms may be + available. Contact the original author for details. + + The original author may be reached as becker@scyld.com, or at + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support information and updates available at + http://www.scyld.com/network/netsemi.html +*/ + +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"natsemi.c:v1.05 8/7/2000 Written by Donald Becker \n"; +static const char version2[] = +" http://www.scyld.com/network/natsemi.html\n"; +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.0.0, August 10, 2000)\n"; +/* Updated to recommendations in pci-skeleton v2.03. */ + +/* Automatically extracted configuration info: +probe-func: natsemi_probe +config-in: tristate 'National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI + +c-help-name: National Semiconductor DP83810 series PCI Ethernet support +c-help-symbol: CONFIG_NATSEMI +c-help: This driver is for the National Semiconductor DP83810 series, +c-help: including the 83815 chip. +c-help: More specific information and updates are available from +c-help: http://www.scyld.com/network/natsemi.html +*/ + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + This chip uses a 512 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 100; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 32 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("National Semiconductor DP83810 series PCI Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is designed for National Semiconductor DP83815 PCI Ethernet NIC. +It also works with other chips in in the DP83810 series. + +II. Board-specific settings + +This driver requires the PCI interrupt line to be valid. +It honors the EEPROM-set values. + +III. Driver operation + +IIIa. Ring buffers + +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. +The NatSemi design uses a 'next descriptor' pointer that the driver forms +into a list. + +IIIb/c. Transmit/Receive Structure + +This driver uses a zero-copy receive and transmit scheme. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the chip as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack. Buffers consumed this way are replaced by newly allocated +skbuffs in a later phase of receives. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. New boards are typically used in generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. When copying is done, the cost is usually mitigated by using +a combined copy/checksum routine. Copying also preloads the cache, which is +most useful with small frames. + +A subtle aspect of the operation is that unaligned buffers are not permitted +by the hardware. Thus the IP header at offset 14 in an ethernet frame isn't +longword aligned for further processing. On copies frames are put into the +skbuff at an offset of "+2", 16-byte aligning the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +NatSemi PCI network controllers are very uncommon. + +IVb. References + +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html +No NatSemi datasheet was publically available at the initial release date. + +IVc. Errata + +None characterised. +*/ + + + +enum pcistuff { + PCI_USES_IO = 0x01, + PCI_USES_MEM = 0x02, + PCI_USES_MASTER = 0x04, + PCI_ADDR0 = 0x08, + PCI_ADDR1 = 0x10, +}; + +/* MMIO operations required */ +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) + + +/* array of board data directly indexed by pci_tbl[x].driver_data */ +static struct { + const char *name; + unsigned long flags; +} natsemi_pci_info[] __devinitdata = { + { "NatSemi DP83815", PCI_IOTYPE }, +}; + +static struct pci_device_id natsemi_pci_tbl[] __devinitdata = { + { 0x100B, 0x0020, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. +*/ +enum register_offsets { + ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C, + IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18, + TxRingPtr=0x20, TxConfig=0x24, + RxRingPtr=0x30, RxConfig=0x34, + WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, + BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, + RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, +}; + +/* Bit in ChipCmd. */ +enum ChipCmdBits { + ChipReset=0x100, RxReset=0x20, TxReset=0x10, RxOff=0x08, RxOn=0x04, + TxOff=0x02, TxOn=0x01, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, + IntrRxIdle=0x0010, IntrRxOverrun=0x0020, + IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, + IntrTxIdle=0x0200, IntrTxOverrun=0x0400, + StatsMax=0x0800, LinkChange=0x4000, + WOLPkt=0x2000, + RxResetDone=0x1000000, TxResetDone=0x2000000, + IntrPCIErr=0x00f00000, + IntrNormalSummary=0x0251, IntrAbnormalSummary=0xCD20, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptErr=0x20, AcceptRunt=0x10, + AcceptBroadcast=0xC0000000, + AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, + AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, +}; + +/* The Rx and Tx buffer descriptors. */ +/* Note that using only 32 bit fields simplifies conversion to big-endian + architectures. */ +struct netdev_desc { + u32 next_desc; + s32 cmd_status; + u32 addr; + u32 software_use; +}; + +/* Bits in network_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000, + DescNoCRC=0x10000000, + DescPktOK=0x08000000, RxTooLong=0x00400000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc rx_ring[RX_RING_SIZE]; + struct netdev_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + struct pci_dev *pci_dev; + struct netdev_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* Rx filter. */ + u32 cur_rx_mode; + u32 rx_filter[16]; + /* FIFO and PCI burst thresholds. */ + int tx_config, rx_config; + /* MII transceiver section. */ + u16 advertising; /* NWay media advertisement */ + + unsigned int iosize; + spinlock_t lock; +}; + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + +static int __devinit natsemi_probe1 (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + int i, option, irq = pdev->irq, chip_idx = ent->driver_data; + static int find_cnt = -1; + static int printed_version; + unsigned long ioaddr; + const int pcibar = 1; /* PCI base address register */ + + if ((debug <= 1) && !printed_version++) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + find_cnt++; + option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; + ioaddr = pci_resource_start(pdev, pcibar); + + if (pci_enable_device(pdev)) + return -EIO; + if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) + pci_set_master(pdev); + + dev = init_etherdev(NULL, sizeof (struct netdev_private)); + if (!dev) + return -ENOMEM; + + { + void *mmio; + if (request_mem_region(ioaddr, pci_resource_len (pdev, pcibar), + dev->name) == NULL) { + unregister_netdev(dev); + kfree(dev); + return -EBUSY; + } + mmio = ioremap (ioaddr, pci_resource_len (pdev, pcibar)); + if (!mmio) { + release_mem_region(ioaddr, pci_resource_len (pdev, pcibar)); + unregister_netdev(dev); + kfree(dev); + return -ENOMEM; + } + ioaddr = (unsigned long) mmio; + } + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = be16_to_cpu(eeprom_read(ioaddr, i + 7)); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + +#if ! defined(final_version) /* Dump the EEPROM contents during development. */ + if (debug > 4) + for (i = 0; i < 64; i++) + printk("%4.4x%s", + eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n"); +#endif + + /* Reset the chip to erase previous misconfiguration. */ + writel(ChipReset, ioaddr + ChipCmd); + + dev->base_addr = ioaddr; + dev->irq = irq; + + np = dev->priv; + + np->pci_dev = pdev; + pdev->driver_data = dev; + np->iosize = pci_resource_len(pdev, pcibar); + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = &tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (mtu) + dev->mtu = mtu; + + np->advertising = readl(ioaddr + 0x90); + printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", + dev->name, (int)readl(ioaddr + 0x84), np->advertising); + + return 0; +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. + The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that + made udelay() unreliable. + The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is + depricated. +*/ +#define eeprom_delay(ee_addr) readl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02, +}; +#define EE_Write0 (EE_ChipSelect) +#define EE_Write1 (EE_ChipSelect | EE_DataIn) + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + +static int eeprom_read(long addr, int location) +{ + int i; + int retval = 0; + int ee_addr = addr + EECtrl; + int read_cmd = location | EE_ReadCmd; + writel(EE_Write0, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; + writel(dataval, ee_addr); + eeprom_delay(ee_addr); + writel(dataval | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + } + writel(EE_ChipSelect, ee_addr); + + for (i = 16; i > 0; i--) { + writel(EE_ChipSelect | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + retval = (retval << 1) | ((readl(ee_addr) & EE_DataOut) ? 1 : 0); + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + } + + /* Terminate the EEPROM access. */ + writel(EE_Write0, ee_addr); + writel(0, ee_addr); + return retval; +} + +/* MII transceiver control section. + The 83815 series has an internal transceiver, and we present the + management registers as if they were MII connected. */ + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + if (phy_id == 1 && location < 32) + return readl(dev->base_addr + 0x80 + (location<<2)) & 0xffff; + else + return 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + if (phy_id == 1 && location < 32) + writew(value, dev->base_addr + 0x80 + (location<<2)); +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); + writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + + for (i = 0; i < 6; i += 2) { + writel(i, ioaddr + RxFilterAddr); + writew(dev->dev_addr[i] + (dev->dev_addr[i+1] << 8), + ioaddr + RxFilterData); + } + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + /* Configure for standard, in-spec Ethernet. */ + np->tx_config = 0x10800802; + writel(np->tx_config, ioaddr + TxConfig); + np->rx_config = 0x0020; + writel(np->rx_config, ioaddr + RxConfig); + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + netif_start_queue(dev); + + check_duplex(dev); + set_rx_mode(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); + + writel(RxOn | TxOn, ioaddr + ChipCmd); + writel(4, ioaddr + StatsCtrl); /* Clear Stats */ + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = jiffies + 3*HZ; + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int duplex; + + if (np->duplex_lock) + return; + duplex = readl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" + " capability.\n", dev->name, + duplex ? "full" : "half"); + if (duplex) { + np->rx_config |= 0x10000000; + np->tx_config |= 0xC0000000; + } else { + np->rx_config &= ~0x10000000; + np->tx_config &= ~0xC0000000; + } + writew(np->tx_config, ioaddr + TxConfig); + writew(np->rx_config, ioaddr + RxConfig); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (debug > 3) + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + check_duplex(dev); + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].cmd_status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); + np->rx_ring[i].cmd_status = DescOwn; + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[i].addr = virt_to_le32desc(skb->tail); + np->rx_ring[i].cmd_status = + cpu_to_le32(DescIntr | np->rx_buf_sz); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]); + np->tx_ring[i].cmd_status = 0; + } + np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]); + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + unsigned entry; + + /* Note: Ordering is important here, set the field with the + "ownership" bit last, and only then increment cur_tx. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + + np->tx_skbuff[entry] = skb; + + np->tx_ring[entry].addr = virt_to_le32desc(skb->data); + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len); + np->cur_tx++; + + /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ + + if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) { + np->tx_full = 1; + netif_stop_queue(dev); + } + /* Wake the potentially-idle transmit channel. */ + writel(TxOn, dev->base_addr + ChipCmd); + + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr; + int boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown " + "device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + np = (struct netdev_private *)dev->priv; + + if (!spin_trylock(&np->lock)) + return; + + do { + u32 intr_status = readl(ioaddr + IntrStatus); + + /* Acknowledge all of the current interrupt sources ASAP. */ + writel(intr_status & 0x000ffff, ioaddr + IntrStatus); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & (IntrRxDone | IntrRxIntr)) + netdev_rx(dev); + + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) + break; + if (np->tx_ring[entry].cmd_status & cpu_to_le32(0x08000000)) { + np->stats.tx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + np->stats.tx_bytes += np->tx_skbuff[entry]->len; +#endif + } else { /* Various Tx errors */ + int tx_status = le32_to_cpu(np->tx_ring[entry].cmd_status); + if (tx_status & 0x04010000) np->stats.tx_aborted_errors++; + if (tx_status & 0x02000000) np->stats.tx_fifo_errors++; + if (tx_status & 0x01000000) np->stats.tx_carrier_errors++; + if (tx_status & 0x00200000) np->stats.tx_window_errors++; + np->stats.tx_errors++; + } + /* Free the original skb. */ + dev_kfree_skb(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full + && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, wake queue. */ + np->tx_full = 0; + netif_wake_queue(dev); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & IntrAbnormalSummary) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (!netif_running(dev) && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + + spin_unlock(&np->lock); +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + + /* If the driver owns the next entry it's a new packet. Send it up. */ + while (desc_status < 0) { /* e.g. & DescOwn */ + if (debug > 4) + printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", + entry, desc_status); + if (--boguscnt < 0) + break; + if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { + if (desc_status & DescMore) { + printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " + "multiple buffers, entry %#x status %x.\n", + dev->name, np->cur_rx, desc_status); + np->stats.rx_length_errors++; + } else { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + desc_status); + np->stats.rx_errors++; + if (desc_status & 0x06000000) np->stats.rx_over_errors++; + if (desc_status & 0x00600000) np->stats.rx_length_errors++; + if (desc_status & 0x00140000) np->stats.rx_frame_errors++; + if (desc_status & 0x00080000) np->stats.rx_crc_errors++; + } + } else { + struct sk_buff *skb; + int pkt_len = (desc_status & 0x0fff) - 4; /* Omit CRC size. */ + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if HAS_IP_COPYSUM + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { + char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (le32desc_to_virt(np->rx_ring[entry].addr) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in netdev_rx: %p vs. %p / %p.\n", + dev->name, + le32desc_to_virt(np->rx_ring[entry].addr), + skb->head, temp); +#endif + } +#ifndef final_version /* Remove after testing. */ + /* You will want this info for the initial debug. */ + if (debug > 5) + printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" + "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " + "%d.%d.%d.%d.\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5], skb->data[6], skb->data[7], + skb->data[8], skb->data[9], skb->data[10], + skb->data[11], skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], + skb->data[17]); +#endif + skb->protocol = eth_type_trans(skb, dev); + /* W/ hardware checksum: skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + np->stats.rx_bytes += pkt_len; +#endif + } + entry = (++np->cur_rx) % RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[entry]; + desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + } + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); + } + np->rx_ring[entry].cmd_status = + cpu_to_le32(DescIntr | np->rx_buf_sz); + } + + /* Restart Rx engine if stopped. */ + writel(RxOn, dev->base_addr + ChipCmd); + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (intr_status & LinkChange) { + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" + " %4.4x partner %4.4x.\n", dev->name, + (int)readl(ioaddr + 0x90), (int)readl(ioaddr + 0x94)); + check_duplex(dev); + } + if (intr_status & StatsMax) { + get_stats(dev); + } + if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0x83ff)) + && debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from PCI faults. */ + if (intr_status & IntrPCIErr) { + np->stats.tx_fifo_errors++; + np->stats.rx_fifo_errors++; + } +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ + /* The chip only need report frame silently dropped. */ + np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs); + np->stats.rx_missed_errors += readl(ioaddr + RxMissed); + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + u16 mc_filter[32]; /* Multicast hash filter */ + u32 rx_mode; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys + | AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + rx_mode = AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys; + } else { + struct dev_mc_list *mclist; + int i; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + mc_filter); + } + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + for (i = 0; i < 32; i++) { + writew(0x200 + (i<<1), ioaddr + RxFilterAddr); + writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData); + } + } + writel(rx_mode, ioaddr + RxFilterAddr); + np->cur_rx_mode = rx_mode; +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = 1; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x " + "Int %2.2x.\n", + dev->name, (int)readl(ioaddr + ChipCmd), + (int)readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts using the mask. */ + writel(0, ioaddr + IntrMask); + writel(0, ioaddr + IntrEnable); + writel(2, ioaddr + StatsCtrl); /* Freeze Stats */ + + /* Stop the chip's Tx and Rx processes. */ + writel(RxOff | TxOff, ioaddr + ChipCmd); + + del_timer_sync(&np->timer); + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(np->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" #%d desc. %8.8x %8.8x.\n", + i, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(np->rx_ring)); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n", + i, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].cmd_status = 0; + np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + if (np->rx_skbuff[i]) { +#if LINUX_VERSION_CODE < 0x20100 + np->rx_skbuff[i]->free = 1; +#endif + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + +#if 0 + writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */ +#endif + + MOD_DEC_USE_COUNT; + + return 0; +} + + +static void __devexit natsemi_remove1 (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + unregister_netdev (dev); + release_mem_region(dev->base_addr, np->iosize); + iounmap ((char *) dev->base_addr); + kfree (dev); +} + +static struct pci_driver natsemi_driver = { + name: "natsemi", + id_table: natsemi_pci_tbl, + probe: natsemi_probe1, + remove: natsemi_remove1, +}; + +static int __init natsemi_init_mod (void) +{ + if (debug > 1) + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); + + return pci_module_init (&natsemi_driver); +} + +static void __exit natsemi_exit_mod (void) +{ + pci_unregister_driver (&natsemi_driver); +} + +module_init(natsemi_init_mod); +module_exit(natsemi_exit_mod); + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.4.0-test6/linux/drivers/net/pcmcia/Config.in Fri Jun 23 21:55:09 2000 +++ linux/drivers/net/pcmcia/Config.in Sun Aug 13 10:21:20 2000 @@ -15,7 +15,9 @@ dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA - dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA + if [ "$CONFIG_IBMTR" != "y" ]; then + dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA + fi if [ "$CONFIG_CARDBUS" = "y" ]; then tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.4.0-test6/linux/drivers/net/pcmcia/xircom_tulip_cb.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Mon Aug 21 07:54:43 2000 @@ -2714,6 +2714,8 @@ long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; + del_timer_sync(&tp->timer); + /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ @@ -2739,12 +2741,12 @@ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); + del_timer_sync(&tp->timer); + netif_stop_queue(dev); if (netif_device_present(dev)) tulip_down(dev); - - del_timer(&tp->timer); free_irq(dev->irq, dev); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c --- v2.4.0-test6/linux/drivers/net/pppoe.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/pppoe.c Tue Aug 22 08:59:00 2000 @@ -5,19 +5,22 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.1 + * Version: 0.6.2 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against * simultaneous invocation of ppp_input * and ppp_unregister_channel. * 040800 : Respect reference count mechanisms on net-devices. + * 200800 : fix kfree(skb) in pppoe_rcv (acme) * * Module reference count is decremented in the right spot now, * guards against sock_put not actually freeing the sk * in pppoe_release. * * Author: Michal Ostrowski + * Contributors: + * Arnaldo Carvalho de Melo * * License: * This program is free software; you can redistribute it and/or @@ -353,7 +356,7 @@ po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); if(!po){ - kfree(skb); + kfree_skb(skb); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.4.0-test6/linux/drivers/net/smc9194.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/net/smc9194.c Tue Aug 22 08:59:00 2000 @@ -18,6 +18,8 @@ . . author: . Erik Stahlman ( erik@vt.edu ) + . contributors: + . Arnaldo Carvalho de Melo . . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) . @@ -47,6 +49,7 @@ . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory . allocation + . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ----------------------------------------------------------------------------*/ static const char *version = @@ -623,7 +626,7 @@ if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); - kfree(skb); + kfree_skb(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.4.0-test6/linux/drivers/net/starfire.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/net/starfire.c Fri Aug 11 15:57:58 2000 @@ -17,6 +17,8 @@ Support and updates available at http://www.scyld.com/network/starfire.html + ----------------------------------------------------------- + Linux kernel-specific changes: LK1.1.1 (jgarzik): @@ -29,8 +31,20 @@ LK1.1.3 (Andrew Morton) - Timer cleanups + + LK1.1.4 (jgarzik): + - Merge Becker version 1.03 */ +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"starfire.c:v1.03 7/26/2000 Written by Donald Becker \n"; +static const char version2[] = +" Updates and info at http://www.scyld.com/network/starfire.html\n"; + +static const char version3[] = +" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n"; + /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -74,8 +88,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#define PFX "starfire: " - #if !defined(__OPTIMIZE__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -85,6 +97,10 @@ /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include #include +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include +#endif + #include #include #include @@ -101,12 +117,6 @@ #include #include -/* These identify the driver base version and may not be removed. */ -static char version1[] __devinitdata = -"starfire.c:v0.15+LK1.1.3 6/17/2000 Written by Donald Becker \n"; -static char version2[] __devinitdata = -" Updates and info at http://www.scyld.com/network/starfire.html\n"; - MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -187,18 +197,18 @@ IVb. References -The Adaptec Starfire manuals. -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - +The Adaptec Starfire manuals, available only from Adaptec. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata */ + enum chip_capability_flags {CanHaveMII=1, }; - +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0) #define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ #if 0 @@ -211,14 +221,12 @@ CH_6915 = 0, }; - static struct pci_device_id starfire_pci_tbl[] __devinitdata = { { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 }, { 0, } }; MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); - /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ static struct chip_info { const char *name; @@ -309,6 +317,7 @@ #endif }; +#define PRIV_ALIGN 15 /* Required alignment mask */ struct ring_info { struct sk_buff *skb; dma_addr_t mapping; @@ -333,7 +342,6 @@ dma_addr_t tx_done_q_dma; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - int chip_id, drv_flags; struct pci_dev *pci_dev; /* Frequently used values: keep some adjacent for cache effect. */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ @@ -341,11 +349,10 @@ unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int tx_full:1; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ - unsigned int duplex_lock:1; unsigned int full_duplex:1, /* Full-duplex operation requested. */ + medialock:1, /* Xcvr set to fixed speed/duplex. */ rx_flowctrl:1, tx_flowctrl:1; /* Use 802.3x flow control. */ - unsigned int medialock:1; /* Do not sense media. */ unsigned int default_port:4; /* Last dev->if_port value. */ u32 tx_mode; u8 tx_threshold; @@ -383,30 +390,31 @@ static int card_idx = -1; static int printed_version = 0; long ioaddr; - int io_size = netdrv_tbl[chip_idx].io_size; + int drv_flags, io_size = netdrv_tbl[chip_idx].io_size; card_idx++; option = card_idx < MAX_UNITS ? options[card_idx] : 0; if (!printed_version++) - printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); ioaddr = pci_resource_start (pdev, 0); if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { - printk (KERN_ERR PFX "card %d: no PCI MEM resources, aborting\n", card_idx); + printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx); return -ENODEV; } dev = init_etherdev(NULL, sizeof(*np)); if (!dev) { - printk (KERN_ERR PFX "card %d: cannot alloc etherdev, aborting\n", card_idx); + printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } irq = pdev->irq; if (request_mem_region (ioaddr, io_size, dev->name) == NULL) { - printk (KERN_ERR PFX "card %d: resource 0x%x @ 0x%lx busy, aborting\n", + printk (KERN_ERR "starfire %d: resource 0x%x @ 0x%lx busy, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_netdev; } @@ -416,7 +424,7 @@ ioaddr = (long) ioremap (ioaddr, io_size); if (!ioaddr) { - printk (KERN_ERR PFX "card %d: cannot remap 0x%x @ 0x%lx, aborting\n", + printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n", card_idx, io_size, ioaddr); goto err_out_free_res; } @@ -436,7 +444,7 @@ #if ! defined(final_version) /* Dump the EEPROM contents during development. */ if (debug > 4) for (i = 0; i < 0x20; i++) - printk("%2.2x%s", readb(ioaddr + EEPROMCtrl + i), + printk("%2.2x%s", (unsigned int)readb(ioaddr + EEPROMCtrl + i), i % 16 != 15 ? " " : "\n"); #endif @@ -446,16 +454,11 @@ dev->base_addr = ioaddr; dev->irq = irq; - pdev->driver_data = dev; - - /* private struct aligned and zeroed by init_etherdev */ np = dev->priv; + pdev->driver_data = dev; np->pci_dev = pdev; - np->chip_id = chip_idx; - - /* save useful data, netdrv_tbl is __devinitdata and might be dropped */ - np->drv_flags = netdrv_tbl[chip_idx].drv_flags; + drv_flags = netdrv_tbl[chip_idx].drv_flags; if (dev->mem_start) option = dev->mem_start; @@ -472,7 +475,7 @@ np->full_duplex = 1; if (np->full_duplex) - np->duplex_lock = 1; + np->medialock = 1; /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; @@ -487,7 +490,7 @@ if (mtu) dev->mtu = mtu; - if (np->drv_flags & CanHaveMII) { + if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); @@ -611,17 +614,18 @@ /* Fill both the unused Tx SA register and the Rx perfect filter. */ for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + 6-i); + writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i); for (i = 0; i < 16; i++) { u16 *eaddrs = (u16 *)dev->dev_addr; long setup_frm = ioaddr + 0x56000 + i*16; - writew(eaddrs[0], setup_frm); setup_frm += 4; - writew(eaddrs[1], setup_frm); setup_frm += 4; - writew(eaddrs[2], setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; + writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ + np->tx_mode = 0; /* Initialized when TxMode set. */ np->tx_threshold = 4; writel(np->tx_threshold, ioaddr + TxThreshold); writel(interrupt_mitigation, ioaddr + IntrTimerCtrl); @@ -635,6 +639,7 @@ printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); set_rx_mode(dev); + np->advertising = mdio_read(dev, np->phys[0], 4); check_duplex(dev, 1); /* Set the interrupt mask and enable PCI interrupts. */ @@ -666,23 +671,26 @@ { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; - int mii_reg5 = mdio_read(dev, np->phys[0], 5); - int negotiated = mii_reg5 & np->advertising; - int duplex, new_tx_mode ; - - new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0); - if (np->duplex_lock) - duplex = 1; - else - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (duplex) - new_tx_mode |= 2; - if (np->full_duplex != duplex) { - np->full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" - " negotiated capability %4.4x.\n", dev->name, - duplex ? "full" : "half", np->phys[0], negotiated); + int new_tx_mode ; + + new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) + | (np->rx_flowctrl ? 0x0400:0); + if (np->medialock) { + if (np->full_duplex) + new_tx_mode |= 2; + } else { + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (duplex) + new_tx_mode |= 2; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug > 1) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d" + " negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + } } if (new_tx_mode != np->tx_mode) { np->tx_mode = new_tx_mode; @@ -700,7 +708,7 @@ if (debug > 3) { printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", - dev->name, readl(ioaddr + IntrStatus)); + dev->name, (int)readl(ioaddr + IntrStatus)); } check_duplex(dev, 0); #if ! defined(final_version) @@ -710,7 +718,7 @@ /* Bogus hardware IRQ: Fake an interrupt handler call. */ if (new_status & 1) { printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n", - dev->name, new_status, readl(ioaddr + IntrStatus)); + dev->name, new_status, (int)readl(ioaddr + IntrStatus)); intr_handler(dev->irq, dev, 0); } } @@ -726,7 +734,7 @@ long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", dev->name, readl(ioaddr + IntrStatus)); + " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus)); #ifndef __alpha__ { @@ -743,15 +751,13 @@ /* Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - /* XXX todo */ /* Trigger an immediate transmit demand. */ - /* XXX todo */ dev->trans_start = jiffies; np->stats.tx_errors++; + return; } @@ -952,7 +958,7 @@ if (debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); + dev->name, (int)readl(ioaddr + IntrStatus)); #ifndef final_version /* Code that should never be run! Remove after testing.. */ @@ -1104,7 +1110,7 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; if (intr_status & LinkChange) { - printk(KERN_ERR "%s: Link changed: Autonegotiation advertising" + printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising" " %4.4x partner %4.4x.\n", dev->name, mdio_read(dev, np->phys[0], 4), mdio_read(dev, np->phys[0], 5)); @@ -1132,9 +1138,7 @@ long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; - /* We should lock this segment of code for SMP eventually, although - the vulnerability window is very small and statistics are - non-critical. */ + /* This adapter architecture needs no SMP locks. */ np->stats.tx_bytes = readl(ioaddr + 0x57010); np->stats.rx_bytes = readl(ioaddr + 0x57044); np->stats.tx_packets = readl(ioaddr + 0x57000); @@ -1201,9 +1205,9 @@ for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count; i++, mclist = mclist->next) { u16 *eaddrs = (u16 *)mclist->dmi_addr; - writew(*eaddrs++, filter_addr); filter_addr += 4; - writew(*eaddrs++, filter_addr); filter_addr += 4; - writew(*eaddrs++, filter_addr); filter_addr += 8; + writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; + writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; } while (i++ < 16) { writew(0xffff, filter_addr); filter_addr += 4; @@ -1232,16 +1236,17 @@ writew(mc_filter[i], filter_addr); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } - writel(rx_mode|AcceptAll, ioaddr + RxFilterMode); + writel(rx_mode, ioaddr + RxFilterMode); } static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct netdev_private *np = (struct netdev_private *)dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + data[0] = np->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); @@ -1249,6 +1254,21 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (data[0] == np->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + if (value & 0x9000) /* Autonegotiation. */ + np->medialock = 0; + else { + np->full_duplex = (value & 0x0100) ? 1 : 0; + np->medialock = 1; + } + break; + case 4: np->advertising = value; break; + } + check_duplex(dev, 0); + } mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; default: @@ -1267,8 +1287,8 @@ del_timer_sync(&np->timer); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n", - dev->name, readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.4.0-test6/linux/drivers/net/sunlance.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/net/sunlance.c Sun Aug 13 12:01:54 2000 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.102 2000/06/30 10:18:35 davem Exp $ +/* $Id: sunlance.c,v 1.103 2000/08/12 19:23:38 anton Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -108,8 +108,6 @@ #include #include #include - -#include /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ #ifndef LANCE_LOG_TX_BUFFERS diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.4.0-test6/linux/drivers/net/tlan.c Fri Jun 23 21:55:09 2000 +++ linux/drivers/net/tlan.c Mon Aug 21 12:57:48 2000 @@ -97,6 +97,12 @@ * * v1.8a May 28, 2000 - Minor updates. * + * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues. + * - Updated with timer fixes from Andrew Morton. + * - Fixed module race in TLan_Open. + * - Added routine to monitor PHY status. + * - Added activity led support for Proliant devices. + * *******************************************************************************/ @@ -138,7 +144,7 @@ static int bbuf = 0; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static const char *tlan_banner = "ThunderLAN driver v1.8a\n"; +static const char *tlan_banner = "ThunderLAN driver v1.9\n"; const char *media[] = { "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", @@ -181,7 +187,7 @@ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT, "Compaq Netelligent Integrated 10/100 TX UTP", - TLAN_ADAPTER_NONE, + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { PCI_VENDOR_ID_COMPAQ, @@ -272,6 +278,7 @@ static void TLan_PhyReset( struct net_device * ); static void TLan_PhyStartLink( struct net_device * ); static void TLan_PhyFinishAutoNeg( struct net_device * ); +static void TLan_PhyMonitor( struct net_device * ); /* static int TLan_PhyNop( struct net_device * ); static int TLan_PhyInternalCheck( struct net_device * ); @@ -701,7 +708,8 @@ if ( err ) { printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); - return -EAGAIN; + MOD_DEC_USE_COUNT; + return err; } netif_start_queue(dev); @@ -942,7 +950,7 @@ TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); if ( priv->timer.function != NULL ) { - del_timer( &priv->timer ); + del_timer_sync( &priv->timer ); priv->timer.function = NULL; } free_irq( dev->irq, dev ); @@ -1590,6 +1598,9 @@ priv->timer.function = NULL; switch ( priv->timerType ) { + case TLAN_TIMER_LINK_BEAT: + TLan_PhyMonitor( dev ); + break; case TLAN_TIMER_PHY_PDOWN: TLan_PhyPowerDown( dev ); break; @@ -2041,6 +2052,12 @@ } TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + + /* We have link beat..for now anyway */ + priv->link = 1; + /*Enabling link beat monitoring */ + TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT ); + } } @@ -2062,7 +2079,8 @@ } 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 ); - } else { + + } else { printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; @@ -2329,12 +2347,14 @@ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); } else if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); } else { @@ -2418,9 +2438,9 @@ TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; if ( mode & 0x0100 ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { - priv->tlanFullDuplex = TRUE; + priv->tlanFullDuplex = TRUE; } if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) { @@ -2448,6 +2468,61 @@ } /* TLan_PhyFinishAutoNeg */ + + + /********************************************************************* + * + * TLan_PhyMonitor + * + * Returns: + * None + * + * Params: + * dev The device structure of this device. + * + * + * This function monitors PHY condition by reading the status + * register via the MII bus. This can be used to give info + * about link changes (up/down), and possible switch to alternate + * media. + * + * ******************************************************************/ + +void TLan_PhyMonitor( struct net_device *dev ) +{ + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 phy; + u16 phy_status; + + phy = priv->phy[priv->phyNum]; + + /* Get PHY status register */ + TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); + + /* Check if link has been lost */ + if (!(phy_status & MII_GS_LINK)) { + if (priv->link) { + priv->link = 0; + printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); + dev->flags &= ~IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + return; + } + } + + /* Link restablished? */ + if ((phy_status & MII_GS_LINK) && !priv->link) { + priv->link = 1; + printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); + dev->flags |= IFF_RUNNING; + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + } + + /* Setup a new monitor */ + TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + +} + /***************************************************************************** diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.4.0-test6/linux/drivers/net/tlan.h Fri Jun 23 21:55:09 2000 +++ linux/drivers/net/tlan.h Mon Aug 21 12:57:48 2000 @@ -187,6 +187,7 @@ u8 tlanFullDuplex; char devName[8]; spinlock_t lock; + u8 link; } TLanPrivateInfo; @@ -197,7 +198,7 @@ * ****************************************************************/ -#define TLAN_TIMER_LINK 1 +#define TLAN_TIMER_LINK_BEAT 1 #define TLAN_TIMER_ACTIVITY 2 #define TLAN_TIMER_PHY_PDOWN 3 #define TLAN_TIMER_PHY_PUP 4 @@ -381,9 +382,9 @@ #define MII_GIL_OUI 0xFC00 #define MII_GIL_MODEL 0x03F0 #define MII_GIL_REVISION 0x000F -#define MII_AN_ADV 0x04 -#define MII_AN_LPA 0x05 -#define MII_AN_EXP 0x06 +#define MII_AN_ADV 0x0004 +#define MII_AN_LPA 0x0005 +#define MII_AN_EXP 0x0006 /* ThunderLAN Specific MII/PHY Registers */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.0-test6/linux/drivers/net/tulip/tulip_core.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/net/tulip/tulip_core.c Fri Aug 11 15:57:58 2000 @@ -28,7 +28,7 @@ #include static char version[] __devinitdata = - "Linux Tulip driver version 0.9.8 (July 13, 2000)\n"; + "Linux Tulip driver version 0.9.9 (August 11, 2000)\n"; /* A few user-configurable values. */ @@ -165,6 +165,8 @@ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x13D1, 0xAB02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x13D1, 0xAB03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/tun.c linux/drivers/net/tun.c --- v2.4.0-test6/linux/drivers/net/tun.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tun.c Wed Aug 23 09:30:13 2000 @@ -0,0 +1,535 @@ +/* + * TUN - Universal TUN/TAP device driver. + * Copyright (C) 1999-2000 Maxim Krasnyansky + * + * 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. + * + * $Id: tun.c,v 1.1 2000/08/23 05:59:28 davem Exp $ + */ + +/* + * Daniel Podlejski + * Modifications for 2.3.99-pre5 kernel. + */ + +#define TUN_VER "1.1" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#ifdef TUN_DEBUG +static int debug=0; +#endif + +/* Network device part of the driver */ + +/* Net device open. */ +static int tun_net_open(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_open\n", tun->name); +#endif + + netif_start_queue(dev); + + return 0; +} + +/* Net device close. */ +static int tun_net_close(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_close\n", tun->name); +#endif + + netif_stop_queue(dev); + + return 0; +} + +/* Net device start xmit */ +static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->name, skb->len); + + + if (netif_queue_stopped(dev)) + return 1; + + tun->stats.tx_packets++; + + /* Queue frame */ + skb_queue_tail(&tun->txq, skb); + if (skb_queue_len(&tun->txq) >= TUN_TXQ_SIZE) + netif_stop_queue(dev); + + if (tun->flags & TUN_FASYNC) + kill_fasync(&tun->fasync, SIGIO, POLL_IN); + + /* Wake up process */ + wake_up_interruptible(&tun->read_wait); + + return 0; +} + +static void tun_net_mclist(struct net_device *dev) +{ +#ifdef TUN_DEBUG + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_mclist\n", tun->name); +#endif + + /* Nothing to do for multicast filters. + * We always accept all frames. + */ + return; +} + +static struct net_device_stats *tun_net_stats(struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + return &tun->stats; +} + +/* Initialize net device. */ +int tun_net_init(struct net_device *dev) +{ + struct tun_struct *tun = (struct tun_struct *)dev->priv; + + DBG(KERN_INFO "%s: tun_net_init\n", tun->name); + + dev->open = tun_net_open; + dev->hard_start_xmit = tun_net_xmit; + dev->stop = tun_net_close; + dev->get_stats = tun_net_stats; + + switch (tun->flags & TUN_TYPE_MASK) { + case TUN_TUN_DEV: + /* Point-to-Point TUN Device */ + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->mtu = 1500; + + /* Type PPP seems most suitable */ + dev->type = ARPHRD_PPP; + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->tx_queue_len = 10; + + dev_init_buffers(dev); + break; + + case TUN_TAP_DEV: + /* Ethernet TAP Device */ + dev->set_multicast_list = tun_net_mclist; + + /* Generate random Ethernet address. */ + *(u16 *)dev->dev_addr = htons(0x00FF); + get_random_bytes(dev->dev_addr + sizeof(u16), 4); + + ether_setup(dev); + break; + }; + + return 0; +} + +/* Character device part */ + +/* Poll */ +static unsigned int tun_chr_poll(struct file *file, poll_table * wait) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_poll\n", tun->name); + + poll_wait(file, &tun->read_wait, wait); + + if (skb_queue_len(&tun->txq)) + return POLLIN | POLLRDNORM; + + return POLLOUT | POLLWRNORM; +} + +/* Get packet from user space buffer(already verified) */ +static __inline__ ssize_t tun_get_user(struct tun_struct *tun, const char *buf, size_t count) +{ + struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; + register const char *ptr = buf; + register int len = count; + struct sk_buff *skb; + + if (len > TUN_MAX_FRAME) + return -EINVAL; + + if (!(tun->flags & TUN_NO_PI)) { + if ((len -= sizeof(pi)) < 0) + return -EINVAL; + + copy_from_user(&pi, ptr, sizeof(pi)); + ptr += sizeof(pi); + } + + if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { + tun->stats.rx_dropped++; + return -ENOMEM; + } + + skb_reserve(skb, 2); + copy_from_user(skb_put(skb, count), ptr, len); + + skb->dev = &tun->dev; + switch (tun->flags & TUN_TYPE_MASK) { + case TUN_TUN_DEV: + skb->mac.raw = skb->data; + skb->protocol = pi.proto; + break; + case TUN_TAP_DEV: + skb->protocol = eth_type_trans(skb, &tun->dev); + break; + }; + + if (tun->flags & TUN_NOCHECKSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); + + tun->stats.rx_packets++; + return count; +} + +/* Write */ +static ssize_t tun_chr_write(struct file * file, const char * buf, + size_t count, loff_t *pos) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count); + + if (!(tun->flags & TUN_IFF_SET)) + return -EBUSY; + + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + + return tun_get_user(tun, buf, count); +} + +/* Put packet to user space buffer(already verified) */ +static __inline__ ssize_t tun_put_user(struct tun_struct *tun, + struct sk_buff *skb, + char *buf, int count) +{ + struct tun_pi pi = { 0, skb->protocol }; + int len = count, total = 0; + char *ptr = buf; + + if (!(tun->flags & TUN_NO_PI)) { + if ((len -= sizeof(pi)) < 0) + return -EINVAL; + + if (len < skb->len) { + /* Packet will be striped */ + pi.flags |= TUN_PKT_STRIP; + } + + copy_to_user(ptr, &pi, sizeof(pi)); + + total += sizeof(pi); + ptr += sizeof(pi); + } + + len = MIN(skb->len, len); + copy_to_user(ptr, skb->data, len); + total += len; + + return total; +} + +/* Read */ +static ssize_t tun_chr_read(struct file * file, char * buf, + size_t count, loff_t *pos) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + DECLARE_WAITQUEUE(wait, current); + struct sk_buff *skb; + ssize_t ret = 0; + + DBG(KERN_INFO "%s: tun_chr_read\n", tun->name); + + add_wait_queue(&tun->read_wait, &wait); + while (count) { + current->state = TASK_INTERRUPTIBLE; + + /* Read frames from device queue */ + if (!(skb=skb_dequeue(&tun->txq))) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + /* Nothing to read, let's sleep */ + schedule(); + continue; + } + netif_start_queue(&tun->dev); + + if (!verify_area(VERIFY_WRITE, buf, count)) + ret = tun_put_user(tun, skb, buf, count); + else + ret = -EFAULT; + + kfree_skb(skb); + break; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&tun->read_wait, &wait); + + return ret; +} + +static loff_t tun_chr_lseek(struct file * file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int tun_set_iff(struct tun_struct *tun, unsigned long arg) +{ + struct ifreq ifr; + char *mask; + + if (copy_from_user(&ifr, (void *)arg, sizeof(ifr))) + return -EFAULT; + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + if (tun->flags & TUN_IFF_SET) + return -EEXIST; + + /* Set dev type */ + if (ifr.ifr_flags & IFF_TUN) { + /* TUN device */ + tun->flags |= TUN_TUN_DEV; + mask = "tun%d"; + } else if (ifr.ifr_flags & IFF_TAP) { + /* TAP device */ + tun->flags |= TUN_TAP_DEV; + mask = "tap%d"; + } else + return -EINVAL; + + if (ifr.ifr_flags & IFF_NO_PI) + tun->flags |= TUN_NO_PI; + + if (*ifr.ifr_name) + strcpy(tun->dev.name, ifr.ifr_name); + else + strcpy(tun->dev.name, mask); + + /* Register net device */ + if (register_netdev(&tun->dev)) + return -EBUSY; + + tun->flags |= TUN_IFF_SET; + strcpy(tun->name, tun->dev.name); + + /* Return iface info to the user space */ + strcpy(ifr.ifr_name, tun->dev.name); + copy_to_user((void *)arg, &ifr, sizeof(ifr)); + + return 0; +} + +static int tun_chr_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_ioctl\n", tun->name); + + switch (cmd) { + case TUNSETIFF: + return tun_set_iff(tun, arg); + + case TUNSETNOCSUM: + /* Disable/Enable checksum on net iface */ + if (arg) + tun->flags |= TUN_NOCHECKSUM; + else + tun->flags &= ~TUN_NOCHECKSUM; + + DBG(KERN_INFO "%s: checksum %s\n", + tun->name, arg ? "disabled" : "enabled"); + break; + +#ifdef TUN_DEBUG + case TUNSETDEBUG: + tun->debug = arg; + break; +#endif + + default: + return -EINVAL; + }; + + return 0; +} + +static int tun_chr_fasync(int fd, struct file *file, int on) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + int ret; + + DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->name, on); + + if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0) + return ret; + + if (on) + tun->flags |= TUN_FASYNC; + else + tun->flags &= ~TUN_FASYNC; + + return 0; +} + +static int tun_chr_open(struct inode *inode, struct file * file) +{ + struct tun_struct *tun = NULL; + + DBG1(KERN_INFO "tunX: tun_chr_open\n"); + + tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL); + if (tun == NULL) + return -ENOMEM; + + memset(tun, 0, sizeof(struct tun_struct)); + file->private_data = tun; + + skb_queue_head_init(&tun->txq); + init_waitqueue_head(&tun->read_wait); + + sprintf(tun->name, "tunX"); + + tun->dev.init = tun_net_init; + tun->dev.priv = tun; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int tun_chr_close(struct inode *inode, struct file *file) +{ + struct tun_struct *tun = (struct tun_struct *)file->private_data; + + DBG(KERN_INFO "%s: tun_chr_close\n", tun->name); + + if (tun->flags & TUN_IFF_SET) { + rtnl_lock(); + dev_close(&tun->dev); + rtnl_unlock(); + + /* Drop TX queue */ + skb_queue_purge(&tun->txq); + + unregister_netdev(&tun->dev); + } + + kfree(tun); + file->private_data = NULL; + + MOD_DEC_USE_COUNT; + return 0; +} + +static struct file_operations tun_fops = { + owner: THIS_MODULE, + llseek: tun_chr_lseek, + read: tun_chr_read, + write: tun_chr_write, + poll: tun_chr_poll, + ioctl: tun_chr_ioctl, + open: tun_chr_open, + release:tun_chr_close, + fasync: tun_chr_fasync +}; + +static devfs_handle_t devfs_handle = NULL; + +int __init tun_init(void) +{ + printk(KERN_INFO "Universal TUN/TAP device driver %s " + "(C)1999-2000 Maxim Krasnyansky\n", TUN_VER); + + if (devfs_register_chrdev(TUN_MAJOR, "tun", &tun_fops)) { + printk(KERN_ERR "tun: Can't register char device %d\n", + TUN_MAJOR); + return -EIO; + } + + devfs_handle = devfs_register(NULL, "net/tun", DEVFS_FL_DEFAULT, + TUN_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &tun_fops, NULL); + +#ifdef MODULE + return 0; +#else + /* If driver is not module, tun_init will be called from Space.c. + * Return non-zero not to register fake device. + */ + return 1; +#endif +} + +void tun_cleanup(void) +{ + devfs_unregister_chrdev(TUN_MAJOR,"tun"); + devfs_unregister(devfs_handle); +} + +module_init(tun_init); +module_exit(tun_cleanup); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.4.0-test6/linux/drivers/net/via-rhine.c Tue May 23 15:31:35 2000 +++ linux/drivers/net/via-rhine.c Fri Aug 11 15:57:58 2000 @@ -51,8 +51,13 @@ - Urban Widmark: mdio locking, bounce buffer changes merges from Beckers 1.05 version added netif_running_on/off support + + LK1.1.6: + - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio) + set netif_running_on/off on startup, del_timer_sync */ + /* A few user-configurable values. These may be modified when a driver module is loaded. */ @@ -85,7 +90,7 @@ bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 16 @@ -122,7 +127,7 @@ /* These identify the driver base version and may not be removed. */ static char version1[] __devinitdata = -"via-rhine.c:v1.05-LK1.1.5 5/2/2000 Written by Donald Becker\n"; +"via-rhine.c:v1.08b-LK1.1.6 8/9/2000 Written by Donald Becker\n"; static char version2[] __devinitdata = " http://www.scyld.com/network/via-rhine.html\n"; @@ -233,13 +238,13 @@ IVb. References Preliminary VT86C100A manual from http://www.via.com.tw/ -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata The VT86C100A manual is not reliable information. -The chip does not handle unaligned transmit or receive buffers, resulting +The 3043 chip does not handle unaligned transmit or receive buffers, resulting in significant performance degradation for bounce buffer copies on transmit and unaligned IP headers on receive. The chip does not pad to minimum transmit length. @@ -261,6 +266,7 @@ enum via_rhine_chips { VT86C100A = 0, + VT6102, VT3043, }; @@ -272,24 +278,33 @@ }; -enum chip_capability_flags {CanHaveMII=1, HasESIPhy=2 }; +enum chip_capability_flags { + CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, + ReqTxAlign=0x10, HasWOL=0x20, }; #if defined(VIA_USE_MEMORY) #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) +#define RHINEII_IOSIZE 4096 #else #define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) +#define RHINEII_IOSIZE 256 #endif /* directly indexed by enum via_rhine_chips, above */ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { - { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII }, - { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII } + { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, + CanHaveMII | ReqTxAlign }, + { "VIA VT6102 Rhine-II", RHINE_IOTYPE, RHINEII_IOSIZE, + CanHaveMII | HasWOL }, + { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, + CanHaveMII | ReqTxAlign } }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, + {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043}, {0,} /* terminate list */ }; @@ -304,7 +319,8 @@ RxRingPtr=0x18, TxRingPtr=0x1C, MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, - Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E, + Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, + StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; /* Bits in the interrupt status/mask registers. */ @@ -585,6 +601,12 @@ "0x%4.4x advertising %4.4x Link %4.4x.\n", dev->name, phy, mii_status, np->advertising, mdio_read(dev, phy, 5)); + + /* set IFF_RUNNING */ + if (mii_status & MIILink) + netif_carrier_on(dev); + else + netif_carrier_off(dev); } } } @@ -641,8 +663,20 @@ long ioaddr = dev->base_addr; int boguscnt = 1024; - if (phy_id == np->phys[0] && regnum == 4) - np->advertising = value; + if (phy_id == np->phys[0]) { + switch (regnum) { + case 0: /* Is user forcing speed/duplex? */ + if (value & 0x9000) /* Autonegotiation. */ + np->duplex_lock = 0; + else + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: + np->advertising = value; + break; + } + } + /* Wait for a previous command to complete. */ while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) ; @@ -900,7 +934,8 @@ np->tx_skbuff[entry] = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ + if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) { + /* Must use alignment buffer. */ memcpy(np->tx_buf[entry], skb->data, skb->len); np->tx_skbuff_dma[entry] = 0; np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma + @@ -1154,10 +1189,11 @@ spin_lock (&np->lock); if (intr_status & (IntrMIIChange | IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) + if (readb(ioaddr + MIIStatus) & 0x02) { /* Link failed, restart autonegotiation. */ - mdio_write(dev, np->phys[0], 0, 0x3300); - else + if (np->drv_flags & HasDavicomPhy) + mdio_write(dev, np->phys[0], 0, 0x3300); + } else via_rhine_check_duplex(dev); if (debug) printk(KERN_ERR "%s: MII status changed: Autonegotiation " @@ -1309,6 +1345,8 @@ int i; unsigned long flags; + del_timer_sync(&np->timer); + spin_lock_irqsave(&np->lock, flags); netif_stop_queue(dev); @@ -1317,13 +1355,14 @@ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, readw(ioaddr + ChipCmd)); + /* Switch to loopback mode to avoid hardware races. */ + writeb(np->tx_thresh | 0x01, ioaddr + TxConfig); + /* Disable interrupts by clearing the interrupt mask. */ writew(0x0000, ioaddr + IntrEnable); /* Stop the chip's Tx and Rx processes. */ writew(CmdStop, ioaddr + ChipCmd); - - del_timer(&np->timer); spin_unlock_irqrestore(&np->lock, flags); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.4.0-test6/linux/drivers/net/wan/Config.in Fri Jul 14 12:12:11 2000 +++ linux/drivers/net/wan/Config.in Fri Aug 11 17:14:23 2000 @@ -7,86 +7,87 @@ bool 'Wan interfaces support' CONFIG_WAN if [ "$CONFIG_WAN" = "y" ]; then +# There is no way to detect a comtrol sv11 - force it modular for now. - # There is no way to detect a comtrol sv11 - force it modular for now. - - dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m - - # The COSA/SRP driver has not been tested as non-modular yet. - - dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m - - # - # COMX drivers - # - - tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX - - # - # Lan Media's board. Currently 1000, 1200, 5200, 5245 - # - tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA - - if [ "$CONFIG_COMX" != "n" ]; then - dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX - dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX - dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX - dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX - if [ "$CONFIG_LAPB" = "y" ]; then - dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX - fi - if [ "$CONFIG_LAPB" = "m" ]; then - dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB - fi - dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX - fi - - # There is no way to detect a Sealevel board. Force it modular - - dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m - - dep_tristate 'SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m - - tristate 'Frame relay DLCI support' CONFIG_DLCI - if [ "$CONFIG_DLCI" != "n" ]; then - int 'Max open DLCI' CONFIG_DLCI_COUNT 24 - int 'Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI - fi - - # Wan router core. - - if [ "$CONFIG_WAN_ROUTER" != "n" ]; then - bool 'WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then - dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 - bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 - fi - bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS - if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then - bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 - fi - fi - fi - fi - - # X.25 network drivers - - dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 - dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 - - if [ "$CONFIG_X86" = "y" ]; then - tristate 'SBNI12-xx support' CONFIG_SBNI - fi + dep_tristate ' Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m + +# The COSA/SRP driver has not been tested as non-modular yet. + + dep_tristate ' COSA/SRP sync serial boards support' CONFIG_COSA m + +# +# COMX drivers +# + + tristate ' MultiGate (COMX) synchronous serial boards support' CONFIG_COMX + if [ "$CONFIG_COMX" != "n" ]; then + dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX + dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX + dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX + dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX + if [ "$CONFIG_LAPB" = "y" ]; then + dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX + fi + if [ "$CONFIG_LAPB" = "m" ]; then + dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_LAPB + fi + dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX + fi + +# +# Lan Media's board. Currently 1000, 1200, 5200, 5245 +# + + tristate ' LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA + +# There is no way to detect a Sealevel board. Force it modular + + dep_tristate ' Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + + dep_tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m + + tristate ' Frame relay DLCI support' CONFIG_DLCI + if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI + fi + +# Wan router core. + + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then + bool ' WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then + dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then + int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' WANPIPE Frame Relay support (OBSOLETE)' CONFIG_WANPIPE_FR + bool ' WANPIPE X.25 support (OBSOLETE)' CONFIG_WANPIPE_X25 + fi + bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS + if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then + bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25 + fi + fi + fi + fi + + +# X.25 network drivers + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' LAPB over Ethernet driver (EXPERIMENTAL)' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25 + dep_tristate ' X.25 async driver (EXPERIMENTAL)' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25 + fi + + if [ "$CONFIG_X86" = "y" ]; then + tristate ' SBNI12-xx support' CONFIG_SBNI + fi fi endmenu - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile --- v2.4.0-test6/linux/drivers/net/wan/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/wan/Makefile Mon Aug 14 10:19:03 2000 @@ -1,269 +1,86 @@ -# File: drivers/net/wan/Makefile # # Makefile for the Linux network (wan) device 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 definition is now inherited from the -# parent makefile. +# 3 Aug 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. # SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) lmc -L_TARGET := wan.a -L_OBJS := -M_OBJS := - -# Need these to keep track of whether the 82530 or SYNCPPP -# modules should really go in the kernel or a module. -CONFIG_85230_BUILTIN := -CONFIG_85230_MODULE := -CONFIG_SYNCPPP_BUILTIN := -CONFIG_SYNCPPP_MODULE := - -ifeq ($(CONFIG_HOSTESS_SV11),y) -L_OBJS += hostess_sv11.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_HOSTESS_SV11),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += hostess_sv11.o - endif -endif - -ifeq ($(CONFIG_SEALEVEL_4021),y) -L_OBJS += sealevel.o -CONFIG_85230_BUILTIN = y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SEALEVEL_4021),m) - CONFIG_85230_MODULE = y - CONFIG_SYNCPPP_MODULE = y - M_OBJS += sealevel.o - endif -endif - -ifeq ($(CONFIG_SYNCLINK_SYNCPPP),y) -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_SYNCLINK_SYNCPPP),m) - CONFIG_SYNCPPP_MODULE = y - endif -endif - -ifeq ($(CONFIG_COMX),y) -LX_OBJS += comx.o -else - ifeq ($(CONFIG_COMX),m) - MX_OBJS += comx.o - endif -endif +O_TARGET := wan.o -ifeq ($(CONFIG_COMX_HW_COMX),y) -L_OBJS += comx-hw-comx.o -else - ifeq ($(CONFIG_COMX_HW_COMX),m) - M_OBJS += comx-hw-comx.o - endif -endif +export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o +list-multi = wanpipe.o cyclomx.o -ifeq ($(CONFIG_COMX_HW_LOCOMX),y) -L_OBJS += comx-hw-locomx.o -CONFIG_85230_BUILTIN=y -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COMX_HW_LOCOMX),m) - M_OBJS += comx-hw-locomx.o - CONFIG_85230_MODULE=y - CONFIG_SYNCPPP_MODULE = y - endif -endif - -ifeq ($(CONFIG_COMX_HW_MIXCOM),y) -L_OBJS += comx-hw-mixcom.o -else - ifeq ($(CONFIG_COMX_HW_MIXCOM),m) - M_OBJS += comx-hw-mixcom.o - endif -endif - -ifeq ($(CONFIG_COMX_PROTO_PPP),y) -L_OBJS += comx-proto-ppp.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COMX_PROTO_PPP),m) - M_OBJS += comx-proto-ppp.o - CONFIG_SYNCPPP_MODULE = y - endif -endif - -ifeq ($(CONFIG_COMX_PROTO_LAPB),y) -L_OBJS += comx-proto-lapb.o -else - ifeq ($(CONFIG_COMX_PROTO_LAPB),m) - M_OBJS += comx-proto-lapb.o - endif -endif - -ifeq ($(CONFIG_COMX_PROTO_FR),y) -L_OBJS += comx-proto-fr.o -else - ifeq ($(CONFIG_COMX_PROTO_FR),m) - M_OBJS += comx-proto-fr.o - endif -endif - -ifeq ($(CONFIG_COSA),y) -L_OBJS += cosa.o -CONFIG_SYNCPPP_BUILTIN = y -else - ifeq ($(CONFIG_COSA),m) - CONFIG_SYNCPPP_MODULE = y - M_OBJS += cosa.o - endif -endif +wanpipe-objs = sdlamain.o $(wanpipe-y) +wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o +wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o +wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o +wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o + +cyclomx-objs = cycx_main.o $(cyclomx-y) +cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o + + +obj-$(CONFIG_HOSTESS_SV11) += z85230.o syncppp.o hostess_sv11.o +obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o +obj-$(CONFIG_COMX) += comx.o +obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o +obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o +obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o +obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o +obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o +obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o +obj-$(CONFIG_COSA) += syncppp.o cosa.o +obj-$(CONFIG_LANMEDIA) += syncppp.o ifeq ($(CONFIG_LANMEDIA),y) SUB_DIRS += lmc MOD_IN_SUB_DIRS += lmc - L_OBJS += lmc/lmc.o - CONFIG_SYNCPPP_BUILTIN = y + obj-y += lmc/lmc.o else ifeq ($(CONFIG_LANMEDIA),m) - CONFIG_SYNCPPP_MODULE = y MOD_IN_SUB_DIRS += lmc endif endif - -# If anything built-in uses syncppp, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_SYNCPPP_BUILTIN -LX_OBJS += syncppp.o -else - ifdef CONFIG_SYNCPPP_MODULE - MX_OBJS += syncppp.o - endif -endif - -# If anything built-in uses Z85230, then build it into the kernel also. -# If not, but a module uses it, build as a module. - -ifdef CONFIG_85230_BUILTIN -LX_OBJS += z85230.o -else - ifdef CONFIG_85230_MODULE - MX_OBJS += z85230.o - endif -endif - -ifeq ($(CONFIG_DLCI),y) -L_OBJS += dlci.o -else - ifeq ($(CONFIG_DLCI),m) - M_OBJS += dlci.o - endif -endif - -ifeq ($(CONFIG_SDLA),y) - L_OBJS += sdla.o -else - ifeq ($(CONFIG_SDLA),m) - M_OBJS += sdla.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),y) - LX_OBJS += sdladrv.o - L_OBJS += sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - L_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_CHDLC),y) - L_OBJS += sdla_chdlc.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - L_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - L_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_VENDOR_SANGOMA),m) - MX_OBJS += sdladrv.o - M_OBJS += wanpipe.o - WANPIPE_OBJS = sdlamain.o - ifeq ($(CONFIG_WANPIPE_X25),y) - WANPIPE_OBJS += sdla_x25.o - endif - ifeq ($(CONFIG_WANPIPE_FR),y) - WANPIPE_OBJS += sdla_fr.o - endif - ifeq ($(CONFIG_WANPIPE_CHDLC),y) - WANPIPE_OBJS += sdla_chdlc.o - endif - ifeq ($(CONFIG_WANPIPE_PPP),y) - WANPIPE_OBJS += sdla_ppp.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),y) - LX_OBJS += cycx_drv.o - L_OBJS += cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - L_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_CYCLADES_SYNC),m) - MX_OBJS += cycx_drv.o - M_OBJS += cyclomx.o - CYCLOMX_OBJS = cycx_main.o - ifeq ($(CONFIG_CYCLOMX_X25),y) - CYCLOMX_OBJS += cycx_x25.o - endif -endif - -ifeq ($(CONFIG_X25_ASY),y) -L_OBJS += x25_asy.o -else - ifeq ($(CONFIG_X25_ASY),m) - M_OBJS += x25_asy.o - endif -endif - -ifeq ($(CONFIG_LAPBETHER),y) -L_OBJS += lapbether.o -else - ifeq ($(CONFIG_LAPBETHER),m) - M_OBJS += lapbether.o - endif -endif - -ifeq ($(CONFIG_SBNI),y) -L_OBJS += sbni.o -else - ifeq ($(CONFIG_SBNI),m) - M_OBJS += sbni.o - endif -endif +obj-$(CONFIG_DLCI) += dlci.o +obj-$(CONFIG_SDLA) += sdla.o +obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o +obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o +obj-$(CONFIG_LAPBETHER) += lapbether.o +obj-$(CONFIG_SBNI) += sbni.o + + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) include $(TOPDIR)/Rules.make -clean: - rm -f core *.o *.a *.s - -wanpipe.o: $(WANPIPE_OBJS) - $(LD) -r -o $@ $(WANPIPE_OBJS) +wanpipe.o: $(wanpipe-objs) + $(LD) -r -o $@ $(wanpipe-objs) -cyclomx.o: $(CYCLOMX_OBJS) - $(LD) -r -o $@ $(CYCLOMX_OBJS) +cyclomx.o: $(cyclomx-objs) + $(LD) -r -o $@ $(cyclomx-objs) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c --- v2.4.0-test6/linux/drivers/net/wan/cycx_main.c Thu Jul 27 17:38:00 2000 +++ linux/drivers/net/wan/cycx_main.c Sun Aug 13 10:21:20 2000 @@ -101,7 +101,7 @@ * < 0 error. * Context: process */ -static int __init cyclomx_init (void) +int __init cyclomx_init (void) { int cnt, err = 0; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/hostess_sv11.c linux/drivers/net/wan/hostess_sv11.c --- v2.4.0-test6/linux/drivers/net/wan/hostess_sv11.c Fri Jul 14 12:12:11 2000 +++ linux/drivers/net/wan/hostess_sv11.c Sun Aug 13 14:57:35 2000 @@ -305,6 +305,7 @@ if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); + restore_flags(flags); goto dmafail2; } z8530_channel_load(&dev->chanB, z8530_dead_port); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c --- v2.4.0-test6/linux/drivers/net/wan/sbni.c Fri Jul 14 12:12:11 2000 +++ linux/drivers/net/wan/sbni.c Sat Aug 12 20:45:48 2000 @@ -448,6 +448,7 @@ if(dev->priv == NULL) { DP( printk("%s: cannot allocate memory\n", dev->name); ) + free_irq(dev->irq, dev); return -ENOMEM; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c --- v2.4.0-test6/linux/drivers/net/wan/sealevel.c Fri Jul 14 12:12:11 2000 +++ linux/drivers/net/wan/sealevel.c Sun Aug 13 14:57:35 2000 @@ -323,6 +323,7 @@ if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); + restore_flags(flags); goto dmafail2; } if(dev->type==Z85C30) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c --- v2.4.0-test6/linux/drivers/net/wan/syncppp.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/net/wan/syncppp.c Fri Aug 11 14:31:45 2000 @@ -866,7 +866,7 @@ * * Close down any existing synchronous session and commence * from scratch. In the PPP case this means negotiating LCP/IPCP - * and friends, while for Cisco HDLC we simply need to staet sending + * and friends, while for Cisco HDLC we simply need to start sending * keepalives */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.4.0-test6/linux/drivers/pci/pci.ids Wed Aug 9 19:19:50 2000 +++ linux/drivers/pci/pci.ids Sun Aug 13 19:37:15 2000 @@ -1468,6 +1468,7 @@ 10b7 3590 TokenLink Velocity XL Adapter 4500 3c450 Cyclone/unknown 5055 3c555 Laptop Hurricane + 6055 3c556 Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card 5157 3c575 [Megahertz] 10/100 LAN CardBus @@ -1934,7 +1935,7 @@ 1106 0686 VT82C686/A PCI to ISA Bridge 0691 VT82C693A/694x [Apollo PRO133x] 1458 0691 VT82C691 Apollo Pro System Controller - 0698 VT82C693A [Ppollo Pro133 AGP] + 0698 VT82C693A [Apollo Pro133 AGP] 0693 VT82C693 [Apollo Pro Plus] 0926 VT82C926 [Amazon] 1000 VT82C570MV @@ -1964,8 +1965,8 @@ 6100 VT85C100A [Rhine II] 8231 VT8231 [PCI-to-ISA Bridge] 8235 VT8235 Power Management - 8305 VT8365 [KM133 AGP] - 8391 VT8363/8371 [KT133/KX133 AGP] + 8305 VT8363/8365 [KT133/KM133 AGP] + 8391 VT8371 [KX133 AGP] 8501 VT8501 [Apollo MVP4 AGP] 8596 VT82C596 [Apollo PRO AGP] 8597 VT82C597 [Apollo VP3 AGP] @@ -4635,7 +4636,12 @@ 84c4 450KX/GX [Orion] - 82454KX/GX PCI bridge 84c5 450KX/GX [Orion] - 82453KX/GX Memory controller 84ca 450NX - 82451NX Memory & I/O Controller - 84cb 450NX - 82454NX PCI Expander Bridge + 84cb 450NX - 82454NX/84460GX PCI Expander Bridge + 84e0 460GX - 84460GX System Address Controller (SAC) + 84e1 460GX - 84460GX System Data Controller (SDC) + 84e2 460GX - 84460GX AGP Bridge (GXB) + 84e3 460GX - 84460GX Memory Address Controller (MAC) + 84e4 460GX - 84460GX Memory Data Controller (MDC) ffff 450NX/GX [Orion] - 82453KX/GX Memory controller [BUG] 8800 Trigem Computer Inc. 2008 Video assistent component diff -u --recursive --new-file v2.4.0-test6/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.4.0-test6/linux/drivers/pci/proc.c Thu May 11 15:30:07 2000 +++ linux/drivers/pci/proc.c Mon Aug 21 09:07:15 2000 @@ -238,6 +238,13 @@ } else cnt += len; buf += len; + if (cnt >= count) + /* + * proc_file_read() gives us 1KB of slack so it's OK if the + * above printfs write a little beyond the buffer end (we + * never write more than 1KB beyond the buffer end). + */ + break; } } return (count > cnt) ? cnt : count; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c --- v2.4.0-test6/linux/drivers/pci/setup-res.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/pci/setup-res.c Thu Aug 10 15:19:40 2000 @@ -60,7 +60,8 @@ struct resource *res, unsigned long size, unsigned long min, - unsigned int type_mask) + unsigned int type_mask, + int resno) { int i; @@ -83,7 +84,7 @@ continue; /* Update PCI config space. */ - pcibios_update_resource(dev, r, res, i); + pcibios_update_resource(dev, r, res, resno); return 0; } return -EBUSY; @@ -100,14 +101,14 @@ min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; /* First, try exact prefetching match.. */ - if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH) < 0) { + if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) { /* * That failed. * * But a prefetching area can handle a non-prefetching * window (it will just not perform as well). */ - if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0) < 0) { + if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) { printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name); return -EBUSY; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.4.0-test6/linux/drivers/pcmcia/cs.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/pcmcia/cs.c Wed Aug 23 09:37:21 2000 @@ -596,9 +596,11 @@ s->state &= ~SOCKET_SETUP_PENDING; } else { send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); - s->reset_handle->event_callback_args.info = NULL; - EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE, - CS_EVENT_PRI_LOW); + if (s->reset_handle) { + s->reset_handle->event_callback_args.info = NULL; + EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE, + CS_EVENT_PRI_LOW); + } s->state &= ~EVENT_MASK; } } /* unreset_socket */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.4.0-test6/linux/drivers/sbus/char/rtc.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/sbus/char/rtc.c Wed Aug 23 09:30:13 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.21 2000/07/13 08:06:40 davem Exp $ +/* $Id: rtc.c,v 1.22 2000/08/22 06:56:33 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -8,7 +8,7 @@ * use the modified clock utility. * * Get the modified clock utility from: - * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c + * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c */ #include diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.4.0-test6/linux/drivers/sbus/char/sab82532.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/sbus/char/sab82532.c Fri Aug 18 10:26:25 2000 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.46 2000/07/06 01:41:37 davem Exp $ +/* $Id: sab82532.c,v 1.47 2000/08/16 21:12:14 ecd Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -412,10 +412,6 @@ *tty->flip.flag_buf_ptr++ = TTY_FRAME; info->icount.frame++; } -#ifdef CMSPAR - else if (status & SAB82532_RSTAT_PARITY) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; -#endif else *tty->flip.flag_buf_ptr++ = TTY_NORMAL; } @@ -2173,7 +2169,7 @@ static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.46 $"; + char *revision = "$Revision: 1.47 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/README.tmscsim linux/drivers/scsi/README.tmscsim --- v2.4.0-test6/linux/drivers/scsi/README.tmscsim Fri Dec 25 16:41:39 1998 +++ linux/drivers/scsi/README.tmscsim Mon Aug 21 08:57:36 2000 @@ -382,7 +382,7 @@ maybe the DC390 log messages to the report. Bug reports should be send to me (Kurt Garloff ) as well -as to the linux-scsi list (), as sometimes bugs +as to the linux-scsi list (), as sometimes bugs are caused by the SCSI mid-level code. I will ask you for some more details and probably I will also ask you to diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.4.0-test6/linux/drivers/scsi/aic7xxx.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/scsi/aic7xxx.c Thu Aug 10 13:14:40 2000 @@ -283,7 +283,7 @@ # define FALSE 0 #endif -#if defined(__powerpc__) || defined(__i386) +#if defined(__powerpc__) || defined(__i386__) # define MMAPIO #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/imm.h linux/drivers/scsi/imm.h --- v2.4.0-test6/linux/drivers/scsi/imm.h Thu Jul 27 17:38:01 2000 +++ linux/drivers/scsi/imm.h Wed Aug 23 11:37:03 2000 @@ -10,7 +10,7 @@ #ifndef _IMM_H #define _IMM_H -#define IMM_VERSION "2.03 (for Linux 2.0.0)" +#define IMM_VERSION "2.04 (for Linux 2.4.0)" /* * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega. @@ -59,6 +59,7 @@ * CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16 * added CONFIG_SCSI_IZIP_SLOW_CTR option * [2.03] + * Fix kernel panic on scsi timeout. 20Aug00 [2.04] */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ @@ -171,6 +172,7 @@ eh_device_reset_handler: NULL, \ eh_bus_reset_handler: imm_reset, \ eh_host_reset_handler: imm_reset, \ + use_new_eh_code: 1, \ bios_param: imm_biosparam, \ this_id: 7, \ sg_tablesize: SG_ALL, \ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h --- v2.4.0-test6/linux/drivers/scsi/ppa.h Thu Jul 27 17:38:01 2000 +++ linux/drivers/scsi/ppa.h Wed Aug 23 11:37:03 2000 @@ -10,7 +10,7 @@ #ifndef _PPA_H #define _PPA_H -#define PPA_VERSION "2.04 (for Linux 2.2.x)" +#define PPA_VERSION "2.05 (for Linux 2.2.x)" /* * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) @@ -57,6 +57,7 @@ * by Peter Cherriman and * Tim Waugh * [2.04] + * Fix kernel panic on scsi timeout, 2000-08-18 [2.05] */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ @@ -169,6 +170,7 @@ eh_device_reset_handler: NULL, \ eh_bus_reset_handler: ppa_reset, \ eh_host_reset_handler: ppa_reset, \ + use_new_eh_code: 1, \ bios_param: ppa_biosparam, \ this_id: -1, \ sg_tablesize: SG_ALL, \ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.4.0-test6/linux/drivers/scsi/qlogicfc.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/scsi/qlogicfc.c Fri Aug 11 14:30:35 2000 @@ -1312,7 +1312,7 @@ } sg_count -= n; } - } else if (Cmnd->request_bufflen) { + } else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) { dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); @@ -1569,7 +1569,7 @@ pci64_unmap_sg(hostdata->pci_dev, (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); - else if (Cmnd->request_bufflen) + else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.4.0-test6/linux/drivers/scsi/scsi_error.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/scsi/scsi_error.c Mon Aug 21 07:37:13 2000 @@ -280,24 +280,7 @@ STATIC void scsi_eh_times_out(Scsi_Cmnd * SCpnt) { - unsigned long flags; - int rtn = FAILED; - SCpnt->eh_state = SCSI_STATE_TIMEOUT; - SCpnt->owner = SCSI_OWNER_LOWLEVEL; - - /* - * As far as the low level driver is concerned, this command is still - * active, so we must give the low level driver a chance to abort it. (DB) - */ - spin_lock_irqsave(&io_request_lock, flags); - if (SCpnt->host->hostt->eh_abort_handler) - rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - - SCpnt->request.rq_status = RQ_SCSI_DONE; - SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; - SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt)); if (SCpnt->host->eh_action != NULL) @@ -651,6 +634,26 @@ * In other words, we don't want a callback any more. */ if (SCpnt->eh_state == SCSI_STATE_TIMEOUT) { + SCpnt->owner = SCSI_OWNER_LOWLEVEL; + + /* + * As far as the low level driver is + * concerned, this command is still active, so + * we must give the low level driver a chance + * to abort it. (DB) + * + * FIXME(eric) - we are not tracking whether we could + * abort a timed out command or not. Not sure how + * we should treat them differently anyways. + */ + spin_lock_irqsave(&io_request_lock, flags); + if (SCpnt->host->hostt->eh_abort_handler) + SCpnt->host->hostt->eh_abort_handler(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + + SCpnt->request.rq_status = RQ_SCSI_DONE; + SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; + SCpnt->eh_state = FAILED; } SCSI_LOG_ERROR_RECOVERY(5, printk("send_eh_cmnd: %p eh_state:%x\n", diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v2.4.0-test6/linux/drivers/scsi/scsi_ioctl.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/scsi/scsi_ioctl.c Mon Aug 21 09:20:16 2000 @@ -24,6 +24,7 @@ #define START_STOP_TIMEOUT (60 * HZ) #define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ) #define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ) +#define READ_DEFECT_DATA_TIMEOUT (60 * HZ ) /* ZIP-250 on parallel port takes as long! */ #define MAX_BUF PAGE_SIZE @@ -283,6 +284,10 @@ case READ_ELEMENT_STATUS: timeout = READ_ELEMENT_STATUS_TIMEOUT; retries = NORMAL_RETRIES; + break; + case READ_DEFECT_DATA: + timeout = READ_DEFECT_DATA_TIMEOUT; + retries = 1; break; default: timeout = IOCTL_NORMAL_TIMEOUT; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.4.0-test6/linux/drivers/scsi/st.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/scsi/st.c Mon Aug 21 09:13:08 2000 @@ -12,7 +12,7 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Aug 6 23:02:13 2000 by makisara@kai.makisara.local + Last modified: Tue Aug 15 16:56:35 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support @@ -2909,6 +2909,8 @@ i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || + mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || + mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || mtc.mt_op == MTCOMPRESSION; } i = flush_buffer(STp, i); @@ -3148,7 +3150,7 @@ priority = GFP_KERNEL; i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = (ST_buffer *) kmalloc(i, priority); + tb = kmalloc(i, priority); if (tb) { if (need_dma) priority |= GFP_DMA; @@ -3479,10 +3481,8 @@ return 1; } - tmp_da = (Scsi_Tape **) kmalloc(tmp_dev_max * sizeof(Scsi_Tape *), - GFP_ATOMIC); - tmp_ba = (ST_buffer **) kmalloc(tmp_dev_max * sizeof(ST_buffer *), - GFP_ATOMIC); + tmp_da = kmalloc(tmp_dev_max * sizeof(Scsi_Tape *), GFP_ATOMIC); + tmp_ba = kmalloc(tmp_dev_max * sizeof(ST_buffer *), GFP_ATOMIC); if (tmp_da == NULL || tmp_ba == NULL) { if (tmp_da != NULL) kfree(tmp_da); @@ -3517,7 +3517,7 @@ if (i >= st_template.dev_max) panic("scsi_devices corrupt (st)"); - tpnt = (Scsi_Tape *)kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC); + tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC); if (tpnt == NULL) { SDp->attached--; write_unlock_irqrestore(&st_dev_arr_lock, flags); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.4.0-test6/linux/drivers/sound/Config.in Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/Config.in Tue Aug 22 11:31:05 2000 @@ -15,6 +15,7 @@ fi fi dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND +dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND @@ -85,7 +86,7 @@ bool ' Persistent DMA buffers' CONFIG_SOUND_DMAP if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND + dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND_OSS fi dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS dep_tristate ' Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.4.0-test6/linux/drivers/sound/Makefile Wed Aug 9 19:19:50 2000 +++ linux/drivers/sound/Makefile Tue Aug 22 11:31:05 2000 @@ -78,6 +78,7 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o +obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/aci.c linux/drivers/sound/aci.c --- v2.4.0-test6/linux/drivers/sound/aci.c Fri Mar 10 16:40:43 2000 +++ linux/drivers/sound/aci.c Fri Aug 11 08:26:43 2000 @@ -537,10 +537,10 @@ static struct mixer_operations aci_mixer_operations = { - "ACI", - "ACI mixer", - aci_mixer_ioctl, - NULL + owner: THIS_MODULE, + id: "ACI", + name: "ACI mixer", + ioctl: aci_mixer_ioctl }; static unsigned char diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/ad1816.c linux/drivers/sound/ad1816.c --- v2.4.0-test6/linux/drivers/sound/ad1816.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/ad1816.c Fri Aug 11 08:26:43 2000 @@ -36,7 +36,6 @@ #include #include -#include "soundmodule.h" #include "sound_config.h" #define DEBUGNOISE(x) @@ -248,13 +247,6 @@ restore_flags (flags); } - -static int ad1816_ioctl (int dev, unsigned int cmd, caddr_t arg) -{ - return -(EINVAL); -} - - static int ad1816_prepare_for_input (int dev, int bsize, int bcount) { unsigned long flags; @@ -535,24 +527,20 @@ static struct audio_driver ad1816_audio_driver = { - ad1816_open, - ad1816_close, - ad1816_output_block, - ad1816_start_input, - ad1816_ioctl, - ad1816_prepare_for_input, - ad1816_prepare_for_output, - ad1816_halt, - NULL, - NULL, - ad1816_halt_input, - ad1816_halt_output, - ad1816_trigger, - ad1816_set_speed, - ad1816_set_bits, - ad1816_set_channels, - NULL, - NULL + owner: THIS_MODULE, + open: ad1816_open, + close: ad1816_close, + output_block: ad1816_output_block, + start_input: ad1816_start_input, + prepare_for_input: ad1816_prepare_for_input, + prepare_for_output: ad1816_prepare_for_output, + halt_io: ad1816_halt, + halt_input: ad1816_halt_input, + halt_output: ad1816_halt_output, + trigger: ad1816_trigger, + set_speed: ad1816_set_speed, + set_bits: ad1816_set_bits, + set_channels: ad1816_set_channels, }; @@ -992,9 +980,10 @@ /* Mixer structure */ static struct mixer_operations ad1816_mixer_operations = { - "AD1816", - "AD1816 Mixer", - ad1816_mixer_ioctl + owner: THIS_MODULE, + id: "AD1816", + name: "AD1816 Mixer", + ioctl: ad1816_mixer_ioctl }; @@ -1424,7 +1413,6 @@ } attach_ad1816(&cfg); - SOUND_LOCK; return 0; } @@ -1441,7 +1429,6 @@ } nr_ad1816_devs=0; - SOUND_LOCK_END; #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(activated) if(ad1816_dev) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.4.0-test6/linux/drivers/sound/ad1848.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/ad1848.c Fri Aug 11 08:26:43 2000 @@ -39,8 +39,6 @@ #include #include -#include "soundmodule.h" - #define DEB(x) #define DEB1(x) #include "sound_config.h" @@ -892,29 +890,28 @@ static struct audio_driver ad1848_audio_driver = { - ad1848_open, - ad1848_close, - ad1848_output_block, - ad1848_start_input, - NULL, - 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 + owner: THIS_MODULE, + open: ad1848_open, + close: ad1848_close, + output_block: ad1848_output_block, + start_input: ad1848_start_input, + prepare_for_input: ad1848_prepare_for_input, + prepare_for_output: ad1848_prepare_for_output, + halt_io: ad1848_halt, + halt_input: ad1848_halt_input, + halt_output: ad1848_halt_output, + trigger: ad1848_trigger, + set_speed: ad1848_set_speed, + set_bits: ad1848_set_bits, + set_channels: ad1848_set_channels }; static struct mixer_operations ad1848_mixer_operations = { - "SOUNDPORT", - "AD1848/CS4248/CS4231", - ad1848_mixer_ioctl + owner: THIS_MODULE, + id: "SOUNDPORT", + name: "AD1848/CS4248/CS4231", + ioctl: ad1848_mixer_ioctl }; static int ad1848_open(int dev, int mode) @@ -1849,7 +1846,8 @@ return 1; } -int 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, struct module *owner) { /* * NOTE! If irq < 0, there is another driver which has allocated the IRQ @@ -1901,7 +1899,10 @@ portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL); if(portc==NULL) return -1; - + + if (owner) + ad1848_audio_driver.owner = owner; + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &ad1848_audio_driver, @@ -2498,7 +2499,7 @@ return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); } -void attach_ms_sound(struct address_info *hw_config) +void attach_ms_sound(struct address_info *hw_config, struct module *owner) { static signed char interrupt_bits[12] = { @@ -2523,7 +2524,8 @@ hw_config->irq, hw_config->dma, hw_config->dma2, 0, - hw_config->osp); + hw_config->osp, + owner); request_region(hw_config->io_base, 4, "WSS config"); return; } @@ -2581,7 +2583,8 @@ hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, dma, dma2, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); request_region(hw_config->io_base, 4, "WSS config"); } @@ -2829,17 +2832,15 @@ if(!probe_ms_sound(&cfg)) return -ENODEV; - attach_ms_sound(&cfg); + attach_ms_sound(&cfg, THIS_MODULE); loaded = 1; } - SOUND_LOCK; return 0; } static void __exit cleanup_ad1848(void) { - SOUND_LOCK_END; if(loaded) unload_ms_sound(&cfg); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/ad1848.h linux/drivers/sound/ad1848.h --- v2.4.0-test6/linux/drivers/sound/ad1848.h Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/ad1848.h Fri Aug 11 08:26:43 2000 @@ -15,14 +15,14 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, - int dma_capture, int share_dma, int *osp); + int dma_capture, int share_dma, int *osp, struct module *owner); 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); int ad1848_control(int cmd, int arg); void adintr(int irq, void *dev_id, struct pt_regs * dummy); -void attach_ms_sound(struct address_info * hw_config); +void attach_ms_sound(struct address_info * hw_config, struct module * owner); int probe_ms_sound(struct address_info *hw_config); void unload_ms_sound(struct address_info *hw_info); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.4.0-test6/linux/drivers/sound/adlib_card.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/adlib_card.c Fri Aug 11 08:26:43 2000 @@ -14,13 +14,12 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "opl3.h" static void __init attach_adlib_card(struct address_info *hw_config) { - hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp); + hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp, THIS_MODULE); request_region(hw_config->io_base, 4, "OPL3/OPL2"); } @@ -50,7 +49,7 @@ if (probe_adlib(&cfg) == 0) return -ENODEV; attach_adlib_card(&cfg); - SOUND_LOCK; + return 0; } @@ -59,7 +58,6 @@ release_region(cfg.io_base, 4); sound_unload_synthdev(cfg.slots[0]); - SOUND_LOCK_END; } module_init(init_adlib); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c --- v2.4.0-test6/linux/drivers/sound/aedsp16.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/aedsp16.c Fri Aug 11 08:26:43 2000 @@ -28,7 +28,6 @@ #include #include #include "sound_config.h" -#include "soundmodule.h" /* * Sanity checks @@ -1357,13 +1356,11 @@ */ return -EINVAL; } - SOUND_LOCK; return 0; } static void __exit cleanup_aedsp16(void) { uninit_aedsp16(); - SOUND_LOCK_END; } module_init(do_init_aedsp16); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.4.0-test6/linux/drivers/sound/audio.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/audio.c Fri Aug 11 08:26:43 2000 @@ -82,14 +82,15 @@ if (dev < 0 || dev >= num_audiodevs) return -ENXIO; + if (audio_devs[dev]->d->owner) + __MOD_INC_USE_COUNT (audio_devs[dev]->d->owner); + if ((ret = DMAbuf_open(dev, mode)) < 0) return ret; - if (audio_devs[dev]->coproc) - { + if (audio_devs[dev]->coproc) { if ((ret = audio_devs[dev]->coproc-> - open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) - { + open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) { audio_release(dev, file); printk(KERN_WARNING "Sound: Can't access coprocessor device\n"); return ret; @@ -178,6 +179,9 @@ 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]->d->owner) + __MOD_DEC_USE_COUNT (audio_devs[dev]->d->owner); } static void translate_bytes(const unsigned char *table, unsigned char *buff, int n) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/awe_wave.c linux/drivers/sound/awe_wave.c --- v2.4.0-test6/linux/drivers/sound/awe_wave.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/awe_wave.c Fri Aug 11 08:26:43 2000 @@ -31,7 +31,6 @@ #endif #include "sound_config.h" -#include "soundmodule.h" #include "awe_wave.h" #include "awe_hw.h" @@ -496,27 +495,28 @@ static struct synth_operations awe_operations = { - "EMU8K", - &awe_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_AWE32, - awe_open, - awe_close, - awe_ioctl, - awe_kill_note, - awe_start_note, - awe_set_instr_2, - awe_reset, - awe_hw_control, - awe_load_patch, - awe_aftertouch, - awe_controller, - awe_panning, - awe_volume_method, - awe_bender, - awe_alloc, - awe_setup_voice + owner: THIS_MODULE, + id: "EMU8K", + info: &awe_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: SAMPLE_TYPE_AWE32, + open: awe_open, + close: awe_close, + ioctl: awe_ioctl, + kill_note: awe_kill_note, + start_note: awe_start_note, + set_instr: awe_set_instr_2, + reset: awe_reset, + hw_control: awe_hw_control, + load_patch: awe_load_patch, + aftertouch: awe_aftertouch, + controller: awe_controller, + panning: awe_panning, + volume_method: awe_volume_method, + bender: awe_bender, + alloc_voice: awe_alloc, + setup_voice: awe_setup_voice }; @@ -575,8 +575,6 @@ awe_present = TRUE; - SOUND_LOCK; - return 1; } @@ -608,7 +606,6 @@ #endif sound_unload_synthdev(my_dev); awe_present = FALSE; - SOUND_LOCK_END; } } @@ -4293,8 +4290,10 @@ static int my_mixerdev = -1; static struct mixer_operations awe_mixer_operations = { - "AWE32 Equalizer", - awe_mixer_ioctl, + owner: THIS_MODULE, + id: "AWE", + name: "AWE32 Equalizer", + ioctl: awe_mixer_ioctl, }; static void __init attach_mixer(void) @@ -5225,17 +5224,13 @@ static struct midi_operations awe_midi_operations = { - {"AWE Midi Emu", 0, 0, SNDCARD_SB}, - NULL /*&std_midi_synth*/, - {0}, /* input_info */ - awe_midi_open, /*open*/ - awe_midi_close, /*close*/ - awe_midi_ioctl, /*ioctl*/ - awe_midi_outputc, /*outputc*/ - NULL /*start_read*/, - NULL /*end_read*/, - NULL, /* kick */ - NULL, /* command */ + owner: THIS_MODULE, + info: {"AWE Midi Emu", 0, 0, SNDCARD_SB}, + in_info: {0}, + open: awe_midi_open, /*open*/ + close: awe_midi_close, /*close*/ + ioctl: awe_midi_ioctl, /*ioctl*/ + outputc: awe_midi_outputc, /*outputc*/ }; static int my_mididev = -1; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.4.0-test6/linux/drivers/sound/cmpci.c Wed Aug 9 19:19:50 2000 +++ linux/drivers/sound/cmpci.c Sat Aug 12 19:51:52 2000 @@ -238,8 +238,6 @@ #define FMODE_DMFM 0x10 -#define SND_DEV_DSP16 5 - /* --------------------------------------------------------------------- */ struct cm_state { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.4.0-test6/linux/drivers/sound/cs4232.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/cs4232.c Fri Aug 11 08:26:43 2000 @@ -46,7 +46,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "cs4232.h" #include "ad1848.h" @@ -229,7 +228,8 @@ dma1, /* Playback DMA */ dma2, /* Capture DMA */ 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); if (hw_config->slots[0] != -1 && audio_devs[hw_config->slots[0]]->mixer_dev!=-1) @@ -258,7 +258,7 @@ if (probe_uart401(&hw_config2)) { mpu_detected = 1; - attach_uart401(&hw_config2); + attach_uart401(&hw_config2, THIS_MODULE); } else { @@ -266,7 +266,6 @@ } hw_config->slots[1] = hw_config2.slots[1]; } - SOUND_LOCK; } void unload_cs4232(struct address_info *hw_config) @@ -376,7 +375,6 @@ static void __exit cleanup_cs4232(void) { unload_cs4232(&cfg); /* unloads MPU as well, if needed */ - SOUND_LOCK_END; } module_init(init_cs4232); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/cs461x.h linux/drivers/sound/cs461x.h --- v2.4.0-test6/linux/drivers/sound/cs461x.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs461x.h Tue Aug 22 11:31:05 2000 @@ -0,0 +1,1617 @@ +#ifndef __CS461X_H +#define __CS461X_H + +/* + * Copyright (c) by Jaroslav Kysela + * Definitions for Cirrus Logic CS461x 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 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 PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4610 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4612 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_4615 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 +#endif + +/* + * Direct registers + */ + +/* + * The following define the offsets of the registers accessed via base address + * register zero on the CS461x part. + */ +#define BA0_HISR 0x00000000 +#define BA0_HSR0 0x00000004 +#define BA0_HICR 0x00000008 +#define BA0_DMSR 0x00000100 +#define BA0_HSAR 0x00000110 +#define BA0_HDAR 0x00000114 +#define BA0_HDMR 0x00000118 +#define BA0_HDCR 0x0000011C +#define BA0_PFMC 0x00000200 +#define BA0_PFCV1 0x00000204 +#define BA0_PFCV2 0x00000208 +#define BA0_PCICFG00 0x00000300 +#define BA0_PCICFG04 0x00000304 +#define BA0_PCICFG08 0x00000308 +#define BA0_PCICFG0C 0x0000030C +#define BA0_PCICFG10 0x00000310 +#define BA0_PCICFG14 0x00000314 +#define BA0_PCICFG18 0x00000318 +#define BA0_PCICFG1C 0x0000031C +#define BA0_PCICFG20 0x00000320 +#define BA0_PCICFG24 0x00000324 +#define BA0_PCICFG28 0x00000328 +#define BA0_PCICFG2C 0x0000032C +#define BA0_PCICFG30 0x00000330 +#define BA0_PCICFG34 0x00000334 +#define BA0_PCICFG38 0x00000338 +#define BA0_PCICFG3C 0x0000033C +#define BA0_CLKCR1 0x00000400 +#define BA0_CLKCR2 0x00000404 +#define BA0_PLLM 0x00000408 +#define BA0_PLLCC 0x0000040C +#define BA0_FRR 0x00000410 +#define BA0_CFL1 0x00000414 +#define BA0_CFL2 0x00000418 +#define BA0_SERMC1 0x00000420 +#define BA0_SERMC2 0x00000424 +#define BA0_SERC1 0x00000428 +#define BA0_SERC2 0x0000042C +#define BA0_SERC3 0x00000430 +#define BA0_SERC4 0x00000434 +#define BA0_SERC5 0x00000438 +#define BA0_SERBSP 0x0000043C +#define BA0_SERBST 0x00000440 +#define BA0_SERBCM 0x00000444 +#define BA0_SERBAD 0x00000448 +#define BA0_SERBCF 0x0000044C +#define BA0_SERBWP 0x00000450 +#define BA0_SERBRP 0x00000454 +#ifndef NO_CS4612 +#define BA0_ASER_FADDR 0x00000458 +#endif +#define BA0_ACCTL 0x00000460 +#define BA0_ACSTS 0x00000464 +#define BA0_ACOSV 0x00000468 +#define BA0_ACCAD 0x0000046C +#define BA0_ACCDA 0x00000470 +#define BA0_ACISV 0x00000474 +#define BA0_ACSAD 0x00000478 +#define BA0_ACSDA 0x0000047C +#define BA0_JSPT 0x00000480 +#define BA0_JSCTL 0x00000484 +#define BA0_JSC1 0x00000488 +#define BA0_JSC2 0x0000048C +#define BA0_MIDCR 0x00000490 +#define BA0_MIDSR 0x00000494 +#define BA0_MIDWP 0x00000498 +#define BA0_MIDRP 0x0000049C +#define BA0_JSIO 0x000004A0 +#ifndef NO_CS4612 +#define BA0_ASER_MASTER 0x000004A4 +#endif +#define BA0_CFGI 0x000004B0 +#define BA0_SSVID 0x000004B4 +#define BA0_GPIOR 0x000004B8 +#ifndef NO_CS4612 +#define BA0_EGPIODR 0x000004BC +#define BA0_EGPIOPTR 0x000004C0 +#define BA0_EGPIOTR 0x000004C4 +#define BA0_EGPIOWR 0x000004C8 +#define BA0_EGPIOSR 0x000004CC +#define BA0_SERC6 0x000004D0 +#define BA0_SERC7 0x000004D4 +#define BA0_SERACC 0x000004D8 +#define BA0_ACCTL2 0x000004E0 +#define BA0_ACSTS2 0x000004E4 +#define BA0_ACOSV2 0x000004E8 +#define BA0_ACCAD2 0x000004EC +#define BA0_ACCDA2 0x000004F0 +#define BA0_ACISV2 0x000004F4 +#define BA0_ACSAD2 0x000004F8 +#define BA0_ACSDA2 0x000004FC +#define BA0_IOTAC0 0x00000500 +#define BA0_IOTAC1 0x00000504 +#define BA0_IOTAC2 0x00000508 +#define BA0_IOTAC3 0x0000050C +#define BA0_IOTAC4 0x00000510 +#define BA0_IOTAC5 0x00000514 +#define BA0_IOTAC6 0x00000518 +#define BA0_IOTAC7 0x0000051C +#define BA0_IOTAC8 0x00000520 +#define BA0_IOTAC9 0x00000524 +#define BA0_IOTAC10 0x00000528 +#define BA0_IOTAC11 0x0000052C +#define BA0_IOTFR0 0x00000540 +#define BA0_IOTFR1 0x00000544 +#define BA0_IOTFR2 0x00000548 +#define BA0_IOTFR3 0x0000054C +#define BA0_IOTFR4 0x00000550 +#define BA0_IOTFR5 0x00000554 +#define BA0_IOTFR6 0x00000558 +#define BA0_IOTFR7 0x0000055C +#define BA0_IOTFIFO 0x00000580 +#define BA0_IOTRRD 0x00000584 +#define BA0_IOTFP 0x00000588 +#define BA0_IOTCR 0x0000058C +#define BA0_DPCID 0x00000590 +#define BA0_DPCIA 0x00000594 +#define BA0_DPCIC 0x00000598 +#define BA0_PCPCIR 0x00000600 +#define BA0_PCPCIG 0x00000604 +#define BA0_PCPCIEN 0x00000608 +#define BA0_EPCIPMC 0x00000610 +#endif + +/* + * The following define the offsets of the registers and memories accessed via + * base address register one on the CS461x part. + */ +#define BA1_SP_DMEM0 0x00000000 +#define BA1_SP_DMEM1 0x00010000 +#define BA1_SP_PMEM 0x00020000 +#define BA1_SP_REG 0x00030000 +#define BA1_SPCR 0x00030000 +#define BA1_DREG 0x00030004 +#define BA1_DSRWP 0x00030008 +#define BA1_TWPR 0x0003000C +#define BA1_SPWR 0x00030010 +#define BA1_SPIR 0x00030014 +#define BA1_FGR1 0x00030020 +#define BA1_SPCS 0x00030028 +#define BA1_SDSR 0x0003002C +#define BA1_FRMT 0x00030030 +#define BA1_FRCC 0x00030034 +#define BA1_FRSC 0x00030038 +#define BA1_OMNI_MEM 0x000E0000 + +/* + * The following defines are for the flags in the host interrupt status + * register. + */ +#define HISR_VC_MASK 0x0000FFFF +#define HISR_VC0 0x00000001 +#define HISR_VC1 0x00000002 +#define HISR_VC2 0x00000004 +#define HISR_VC3 0x00000008 +#define HISR_VC4 0x00000010 +#define HISR_VC5 0x00000020 +#define HISR_VC6 0x00000040 +#define HISR_VC7 0x00000080 +#define HISR_VC8 0x00000100 +#define HISR_VC9 0x00000200 +#define HISR_VC10 0x00000400 +#define HISR_VC11 0x00000800 +#define HISR_VC12 0x00001000 +#define HISR_VC13 0x00002000 +#define HISR_VC14 0x00004000 +#define HISR_VC15 0x00008000 +#define HISR_INT0 0x00010000 +#define HISR_INT1 0x00020000 +#define HISR_DMAI 0x00040000 +#define HISR_FROVR 0x00080000 +#define HISR_MIDI 0x00100000 +#ifdef NO_CS4612 +#define HISR_RESERVED 0x0FE00000 +#else +#define HISR_SBINT 0x00200000 +#define HISR_RESERVED 0x0FC00000 +#endif +#define HISR_H0P 0x40000000 +#define HISR_INTENA 0x80000000 + +/* + * The following defines are for the flags in the host signal register 0. + */ +#define HSR0_VC_MASK 0xFFFFFFFF +#define HSR0_VC16 0x00000001 +#define HSR0_VC17 0x00000002 +#define HSR0_VC18 0x00000004 +#define HSR0_VC19 0x00000008 +#define HSR0_VC20 0x00000010 +#define HSR0_VC21 0x00000020 +#define HSR0_VC22 0x00000040 +#define HSR0_VC23 0x00000080 +#define HSR0_VC24 0x00000100 +#define HSR0_VC25 0x00000200 +#define HSR0_VC26 0x00000400 +#define HSR0_VC27 0x00000800 +#define HSR0_VC28 0x00001000 +#define HSR0_VC29 0x00002000 +#define HSR0_VC30 0x00004000 +#define HSR0_VC31 0x00008000 +#define HSR0_VC32 0x00010000 +#define HSR0_VC33 0x00020000 +#define HSR0_VC34 0x00040000 +#define HSR0_VC35 0x00080000 +#define HSR0_VC36 0x00100000 +#define HSR0_VC37 0x00200000 +#define HSR0_VC38 0x00400000 +#define HSR0_VC39 0x00800000 +#define HSR0_VC40 0x01000000 +#define HSR0_VC41 0x02000000 +#define HSR0_VC42 0x04000000 +#define HSR0_VC43 0x08000000 +#define HSR0_VC44 0x10000000 +#define HSR0_VC45 0x20000000 +#define HSR0_VC46 0x40000000 +#define HSR0_VC47 0x80000000 + +/* + * The following defines are for the flags in the host interrupt control + * register. + */ +#define HICR_IEV 0x00000001 +#define HICR_CHGM 0x00000002 + +/* + * The following defines are for the flags in the DMA status register. + */ +#define DMSR_HP 0x00000001 +#define DMSR_HR 0x00000002 +#define DMSR_SP 0x00000004 +#define DMSR_SR 0x00000008 + +/* + * The following defines are for the flags in the host DMA source address + * register. + */ +#define HSAR_HOST_ADDR_MASK 0xFFFFFFFF +#define HSAR_DSP_ADDR_MASK 0x0000FFFF +#define HSAR_MEMID_MASK 0x000F0000 +#define HSAR_MEMID_SP_DMEM0 0x00000000 +#define HSAR_MEMID_SP_DMEM1 0x00010000 +#define HSAR_MEMID_SP_PMEM 0x00020000 +#define HSAR_MEMID_SP_DEBUG 0x00030000 +#define HSAR_MEMID_OMNI_MEM 0x000E0000 +#define HSAR_END 0x40000000 +#define HSAR_ERR 0x80000000 + +/* + * The following defines are for the flags in the host DMA destination address + * register. + */ +#define HDAR_HOST_ADDR_MASK 0xFFFFFFFF +#define HDAR_DSP_ADDR_MASK 0x0000FFFF +#define HDAR_MEMID_MASK 0x000F0000 +#define HDAR_MEMID_SP_DMEM0 0x00000000 +#define HDAR_MEMID_SP_DMEM1 0x00010000 +#define HDAR_MEMID_SP_PMEM 0x00020000 +#define HDAR_MEMID_SP_DEBUG 0x00030000 +#define HDAR_MEMID_OMNI_MEM 0x000E0000 +#define HDAR_END 0x40000000 +#define HDAR_ERR 0x80000000 + +/* + * The following defines are for the flags in the host DMA control register. + */ +#define HDMR_AC_MASK 0x0000F000 +#define HDMR_AC_8_16 0x00001000 +#define HDMR_AC_M_S 0x00002000 +#define HDMR_AC_B_L 0x00004000 +#define HDMR_AC_S_U 0x00008000 + +/* + * The following defines are for the flags in the host DMA control register. + */ +#define HDCR_COUNT_MASK 0x000003FF +#define HDCR_DONE 0x00004000 +#define HDCR_OPT 0x00008000 +#define HDCR_WBD 0x00400000 +#define HDCR_WBS 0x00800000 +#define HDCR_DMS_MASK 0x07000000 +#define HDCR_DMS_LINEAR 0x00000000 +#define HDCR_DMS_16_DWORDS 0x01000000 +#define HDCR_DMS_32_DWORDS 0x02000000 +#define HDCR_DMS_64_DWORDS 0x03000000 +#define HDCR_DMS_128_DWORDS 0x04000000 +#define HDCR_DMS_256_DWORDS 0x05000000 +#define HDCR_DMS_512_DWORDS 0x06000000 +#define HDCR_DMS_1024_DWORDS 0x07000000 +#define HDCR_DH 0x08000000 +#define HDCR_SMS_MASK 0x70000000 +#define HDCR_SMS_LINEAR 0x00000000 +#define HDCR_SMS_16_DWORDS 0x10000000 +#define HDCR_SMS_32_DWORDS 0x20000000 +#define HDCR_SMS_64_DWORDS 0x30000000 +#define HDCR_SMS_128_DWORDS 0x40000000 +#define HDCR_SMS_256_DWORDS 0x50000000 +#define HDCR_SMS_512_DWORDS 0x60000000 +#define HDCR_SMS_1024_DWORDS 0x70000000 +#define HDCR_SH 0x80000000 +#define HDCR_COUNT_SHIFT 0 + +/* + * The following defines are for the flags in the performance monitor control + * register. + */ +#define PFMC_C1SS_MASK 0x0000001F +#define PFMC_C1EV 0x00000020 +#define PFMC_C1RS 0x00008000 +#define PFMC_C2SS_MASK 0x001F0000 +#define PFMC_C2EV 0x00200000 +#define PFMC_C2RS 0x80000000 +#define PFMC_C1SS_SHIFT 0 +#define PFMC_C2SS_SHIFT 16 +#define PFMC_BUS_GRANT 0 +#define PFMC_GRANT_AFTER_REQ 1 +#define PFMC_TRANSACTION 2 +#define PFMC_DWORD_TRANSFER 3 +#define PFMC_SLAVE_READ 4 +#define PFMC_SLAVE_WRITE 5 +#define PFMC_PREEMPTION 6 +#define PFMC_DISCONNECT_RETRY 7 +#define PFMC_INTERRUPT 8 +#define PFMC_BUS_OWNERSHIP 9 +#define PFMC_TRANSACTION_LAG 10 +#define PFMC_PCI_CLOCK 11 +#define PFMC_SERIAL_CLOCK 12 +#define PFMC_SP_CLOCK 13 + +/* + * The following defines are for the flags in the performance counter value 1 + * register. + */ +#define PFCV1_PC1V_MASK 0xFFFFFFFF +#define PFCV1_PC1V_SHIFT 0 + +/* + * The following defines are for the flags in the performance counter value 2 + * register. + */ +#define PFCV2_PC2V_MASK 0xFFFFFFFF +#define PFCV2_PC2V_SHIFT 0 + +/* + * The following defines are for the flags in the clock control register 1. + */ +#define CLKCR1_OSCS 0x00000001 +#define CLKCR1_OSCP 0x00000002 +#define CLKCR1_PLLSS_MASK 0x0000000C +#define CLKCR1_PLLSS_SERIAL 0x00000000 +#define CLKCR1_PLLSS_CRYSTAL 0x00000004 +#define CLKCR1_PLLSS_PCI 0x00000008 +#define CLKCR1_PLLSS_RESERVED 0x0000000C +#define CLKCR1_PLLP 0x00000010 +#define CLKCR1_SWCE 0x00000020 +#define CLKCR1_PLLOS 0x00000040 + +/* + * The following defines are for the flags in the clock control register 2. + */ +#define CLKCR2_PDIVS_MASK 0x0000000F +#define CLKCR2_PDIVS_1 0x00000001 +#define CLKCR2_PDIVS_2 0x00000002 +#define CLKCR2_PDIVS_4 0x00000004 +#define CLKCR2_PDIVS_7 0x00000007 +#define CLKCR2_PDIVS_8 0x00000008 +#define CLKCR2_PDIVS_16 0x00000000 + +/* + * The following defines are for the flags in the PLL multiplier register. + */ +#define PLLM_MASK 0x000000FF +#define PLLM_SHIFT 0 + +/* + * The following defines are for the flags in the PLL capacitor coefficient + * register. + */ +#define PLLCC_CDR_MASK 0x00000007 +#ifndef NO_CS4610 +#define PLLCC_CDR_240_350_MHZ 0x00000000 +#define PLLCC_CDR_184_265_MHZ 0x00000001 +#define PLLCC_CDR_144_205_MHZ 0x00000002 +#define PLLCC_CDR_111_160_MHZ 0x00000003 +#define PLLCC_CDR_87_123_MHZ 0x00000004 +#define PLLCC_CDR_67_96_MHZ 0x00000005 +#define PLLCC_CDR_52_74_MHZ 0x00000006 +#define PLLCC_CDR_45_58_MHZ 0x00000007 +#endif +#ifndef NO_CS4612 +#define PLLCC_CDR_271_398_MHZ 0x00000000 +#define PLLCC_CDR_227_330_MHZ 0x00000001 +#define PLLCC_CDR_167_239_MHZ 0x00000002 +#define PLLCC_CDR_150_215_MHZ 0x00000003 +#define PLLCC_CDR_107_154_MHZ 0x00000004 +#define PLLCC_CDR_98_140_MHZ 0x00000005 +#define PLLCC_CDR_73_104_MHZ 0x00000006 +#define PLLCC_CDR_63_90_MHZ 0x00000007 +#endif +#define PLLCC_LPF_MASK 0x000000F8 +#ifndef NO_CS4610 +#define PLLCC_LPF_23850_60000_KHZ 0x00000000 +#define PLLCC_LPF_7960_26290_KHZ 0x00000008 +#define PLLCC_LPF_4160_10980_KHZ 0x00000018 +#define PLLCC_LPF_1740_4580_KHZ 0x00000038 +#define PLLCC_LPF_724_1910_KHZ 0x00000078 +#define PLLCC_LPF_317_798_KHZ 0x000000F8 +#endif +#ifndef NO_CS4612 +#define PLLCC_LPF_25580_64530_KHZ 0x00000000 +#define PLLCC_LPF_14360_37270_KHZ 0x00000008 +#define PLLCC_LPF_6100_16020_KHZ 0x00000018 +#define PLLCC_LPF_2540_6690_KHZ 0x00000038 +#define PLLCC_LPF_1050_2780_KHZ 0x00000078 +#define PLLCC_LPF_450_1160_KHZ 0x000000F8 +#endif + +/* + * The following defines are for the flags in the feature reporting register. + */ +#define FRR_FAB_MASK 0x00000003 +#define FRR_MASK_MASK 0x0000001C +#ifdef NO_CS4612 +#define FRR_CFOP_MASK 0x000000E0 +#else +#define FRR_CFOP_MASK 0x00000FE0 +#endif +#define FRR_CFOP_NOT_DVD 0x00000020 +#define FRR_CFOP_A3D 0x00000040 +#define FRR_CFOP_128_PIN 0x00000080 +#ifndef NO_CS4612 +#define FRR_CFOP_CS4280 0x00000800 +#endif +#define FRR_FAB_SHIFT 0 +#define FRR_MASK_SHIFT 2 +#define FRR_CFOP_SHIFT 5 + +/* + * The following defines are for the flags in the configuration load 1 + * register. + */ +#define CFL1_CLOCK_SOURCE_MASK 0x00000003 +#define CFL1_CLOCK_SOURCE_CS423X 0x00000000 +#define CFL1_CLOCK_SOURCE_AC97 0x00000001 +#define CFL1_CLOCK_SOURCE_CRYSTAL 0x00000002 +#define CFL1_CLOCK_SOURCE_DUAL_AC97 0x00000003 +#define CFL1_VALID_DATA_MASK 0x000000FF + +/* + * The following defines are for the flags in the configuration load 2 + * register. + */ +#define CFL2_VALID_DATA_MASK 0x000000FF + +/* + * The following defines are for the flags in the serial port master control + * register 1. + */ +#define SERMC1_MSPE 0x00000001 +#define SERMC1_PTC_MASK 0x0000000E +#define SERMC1_PTC_CS423X 0x00000000 +#define SERMC1_PTC_AC97 0x00000002 +#define SERMC1_PTC_DAC 0x00000004 +#define SERMC1_PLB 0x00000010 +#define SERMC1_XLB 0x00000020 + +/* + * The following defines are for the flags in the serial port master control + * register 2. + */ +#define SERMC2_LROE 0x00000001 +#define SERMC2_MCOE 0x00000002 +#define SERMC2_MCDIV 0x00000004 + +/* + * The following defines are for the flags in the serial port 1 configuration + * register. + */ +#define SERC1_SO1EN 0x00000001 +#define SERC1_SO1F_MASK 0x0000000E +#define SERC1_SO1F_CS423X 0x00000000 +#define SERC1_SO1F_AC97 0x00000002 +#define SERC1_SO1F_DAC 0x00000004 +#define SERC1_SO1F_SPDIF 0x00000006 + +/* + * The following defines are for the flags in the serial port 2 configuration + * register. + */ +#define SERC2_SI1EN 0x00000001 +#define SERC2_SI1F_MASK 0x0000000E +#define SERC2_SI1F_CS423X 0x00000000 +#define SERC2_SI1F_AC97 0x00000002 +#define SERC2_SI1F_ADC 0x00000004 +#define SERC2_SI1F_SPDIF 0x00000006 + +/* + * The following defines are for the flags in the serial port 3 configuration + * register. + */ +#define SERC3_SO2EN 0x00000001 +#define SERC3_SO2F_MASK 0x00000006 +#define SERC3_SO2F_DAC 0x00000000 +#define SERC3_SO2F_SPDIF 0x00000002 + +/* + * The following defines are for the flags in the serial port 4 configuration + * register. + */ +#define SERC4_SO3EN 0x00000001 +#define SERC4_SO3F_MASK 0x00000006 +#define SERC4_SO3F_DAC 0x00000000 +#define SERC4_SO3F_SPDIF 0x00000002 + +/* + * The following defines are for the flags in the serial port 5 configuration + * register. + */ +#define SERC5_SI2EN 0x00000001 +#define SERC5_SI2F_MASK 0x00000006 +#define SERC5_SI2F_ADC 0x00000000 +#define SERC5_SI2F_SPDIF 0x00000002 + +/* + * The following defines are for the flags in the serial port backdoor sample + * pointer register. + */ +#define SERBSP_FSP_MASK 0x0000000F +#define SERBSP_FSP_SHIFT 0 + +/* + * The following defines are for the flags in the serial port backdoor status + * register. + */ +#define SERBST_RRDY 0x00000001 +#define SERBST_WBSY 0x00000002 + +/* + * The following defines are for the flags in the serial port backdoor command + * register. + */ +#define SERBCM_RDC 0x00000001 +#define SERBCM_WRC 0x00000002 + +/* + * The following defines are for the flags in the serial port backdoor address + * register. + */ +#ifdef NO_CS4612 +#define SERBAD_FAD_MASK 0x000000FF +#else +#define SERBAD_FAD_MASK 0x000001FF +#endif +#define SERBAD_FAD_SHIFT 0 + +/* + * The following defines are for the flags in the serial port backdoor + * configuration register. + */ +#define SERBCF_HBP 0x00000001 + +/* + * The following defines are for the flags in the serial port backdoor write + * port register. + */ +#define SERBWP_FWD_MASK 0x000FFFFF +#define SERBWP_FWD_SHIFT 0 + +/* + * The following defines are for the flags in the serial port backdoor read + * port register. + */ +#define SERBRP_FRD_MASK 0x000FFFFF +#define SERBRP_FRD_SHIFT 0 + +/* + * The following defines are for the flags in the async FIFO address register. + */ +#ifndef NO_CS4612 +#define ASER_FADDR_A1_MASK 0x000001FF +#define ASER_FADDR_EN1 0x00008000 +#define ASER_FADDR_A2_MASK 0x01FF0000 +#define ASER_FADDR_EN2 0x80000000 +#define ASER_FADDR_A1_SHIFT 0 +#define ASER_FADDR_A2_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the AC97 control register. + */ +#define ACCTL_RSTN 0x00000001 +#define ACCTL_ESYN 0x00000002 +#define ACCTL_VFRM 0x00000004 +#define ACCTL_DCV 0x00000008 +#define ACCTL_CRW 0x00000010 +#define ACCTL_ASYN 0x00000020 +#ifndef NO_CS4612 +#define ACCTL_TC 0x00000040 +#endif + +/* + * The following defines are for the flags in the AC97 status register. + */ +#define ACSTS_CRDY 0x00000001 +#define ACSTS_VSTS 0x00000002 +#ifndef NO_CS4612 +#define ACSTS_WKUP 0x00000004 +#endif + +/* + * The following defines are for the flags in the AC97 output slot valid + * register. + */ +#define ACOSV_SLV3 0x00000001 +#define ACOSV_SLV4 0x00000002 +#define ACOSV_SLV5 0x00000004 +#define ACOSV_SLV6 0x00000008 +#define ACOSV_SLV7 0x00000010 +#define ACOSV_SLV8 0x00000020 +#define ACOSV_SLV9 0x00000040 +#define ACOSV_SLV10 0x00000080 +#define ACOSV_SLV11 0x00000100 +#define ACOSV_SLV12 0x00000200 + +/* + * The following defines are for the flags in the AC97 command address + * register. + */ +#define ACCAD_CI_MASK 0x0000007F +#define ACCAD_CI_SHIFT 0 + +/* + * The following defines are for the flags in the AC97 command data register. + */ +#define ACCDA_CD_MASK 0x0000FFFF +#define ACCDA_CD_SHIFT 0 + +/* + * The following defines are for the flags in the AC97 input slot valid + * register. + */ +#define ACISV_ISV3 0x00000001 +#define ACISV_ISV4 0x00000002 +#define ACISV_ISV5 0x00000004 +#define ACISV_ISV6 0x00000008 +#define ACISV_ISV7 0x00000010 +#define ACISV_ISV8 0x00000020 +#define ACISV_ISV9 0x00000040 +#define ACISV_ISV10 0x00000080 +#define ACISV_ISV11 0x00000100 +#define ACISV_ISV12 0x00000200 + +/* + * The following defines are for the flags in the AC97 status address + * register. + */ +#define ACSAD_SI_MASK 0x0000007F +#define ACSAD_SI_SHIFT 0 + +/* + * The following defines are for the flags in the AC97 status data register. + */ +#define ACSDA_SD_MASK 0x0000FFFF +#define ACSDA_SD_SHIFT 0 + +/* + * The following defines are for the flags in the joystick poll/trigger + * register. + */ +#define JSPT_CAX 0x00000001 +#define JSPT_CAY 0x00000002 +#define JSPT_CBX 0x00000004 +#define JSPT_CBY 0x00000008 +#define JSPT_BA1 0x00000010 +#define JSPT_BA2 0x00000020 +#define JSPT_BB1 0x00000040 +#define JSPT_BB2 0x00000080 + +/* + * The following defines are for the flags in the joystick control register. + */ +#define JSCTL_SP_MASK 0x00000003 +#define JSCTL_SP_SLOW 0x00000000 +#define JSCTL_SP_MEDIUM_SLOW 0x00000001 +#define JSCTL_SP_MEDIUM_FAST 0x00000002 +#define JSCTL_SP_FAST 0x00000003 +#define JSCTL_ARE 0x00000004 + +/* + * The following defines are for the flags in the joystick coordinate pair 1 + * readback register. + */ +#define JSC1_Y1V_MASK 0x0000FFFF +#define JSC1_X1V_MASK 0xFFFF0000 +#define JSC1_Y1V_SHIFT 0 +#define JSC1_X1V_SHIFT 16 + +/* + * The following defines are for the flags in the joystick coordinate pair 2 + * readback register. + */ +#define JSC2_Y2V_MASK 0x0000FFFF +#define JSC2_X2V_MASK 0xFFFF0000 +#define JSC2_Y2V_SHIFT 0 +#define JSC2_X2V_SHIFT 16 + +/* + * The following defines are for the flags in the MIDI control register. + */ +#define MIDCR_TXE 0x00000001 /* Enable transmitting. */ +#define MIDCR_RXE 0x00000002 /* Enable receiving. */ +#define MIDCR_RIE 0x00000004 /* Interrupt upon tx ready. */ +#define MIDCR_TIE 0x00000008 /* Interrupt upon rx ready. */ +#define MIDCR_MLB 0x00000010 /* Enable midi loopback. */ +#define MIDCR_MRST 0x00000020 /* Reset interface. */ + +/* + * The following defines are for the flags in the MIDI status register. + */ +#define MIDSR_TBF 0x00000001 /* Tx FIFO is full. */ +#define MIDSR_RBE 0x00000002 /* Rx FIFO is empty. */ + +/* + * The following defines are for the flags in the MIDI write port register. + */ +#define MIDWP_MWD_MASK 0x000000FF +#define MIDWP_MWD_SHIFT 0 + +/* + * The following defines are for the flags in the MIDI read port register. + */ +#define MIDRP_MRD_MASK 0x000000FF +#define MIDRP_MRD_SHIFT 0 + +/* + * The following defines are for the flags in the joystick GPIO register. + */ +#define JSIO_DAX 0x00000001 +#define JSIO_DAY 0x00000002 +#define JSIO_DBX 0x00000004 +#define JSIO_DBY 0x00000008 +#define JSIO_AXOE 0x00000010 +#define JSIO_AYOE 0x00000020 +#define JSIO_BXOE 0x00000040 +#define JSIO_BYOE 0x00000080 + +/* + * The following defines are for the flags in the master async/sync serial + * port enable register. + */ +#ifndef NO_CS4612 +#define ASER_MASTER_ME 0x00000001 +#endif + +/* + * The following defines are for the flags in the configuration interface + * register. + */ +#define CFGI_CLK 0x00000001 +#define CFGI_DOUT 0x00000002 +#define CFGI_DIN_EEN 0x00000004 +#define CFGI_EELD 0x00000008 + +/* + * The following defines are for the flags in the subsystem ID and vendor ID + * register. + */ +#define SSVID_VID_MASK 0x0000FFFF +#define SSVID_SID_MASK 0xFFFF0000 +#define SSVID_VID_SHIFT 0 +#define SSVID_SID_SHIFT 16 + +/* + * The following defines are for the flags in the GPIO pin interface register. + */ +#define GPIOR_VOLDN 0x00000001 +#define GPIOR_VOLUP 0x00000002 +#define GPIOR_SI2D 0x00000004 +#define GPIOR_SI2OE 0x00000008 + +/* + * The following defines are for the flags in the extended GPIO pin direction + * register. + */ +#ifndef NO_CS4612 +#define EGPIODR_GPOE0 0x00000001 +#define EGPIODR_GPOE1 0x00000002 +#define EGPIODR_GPOE2 0x00000004 +#define EGPIODR_GPOE3 0x00000008 +#define EGPIODR_GPOE4 0x00000010 +#define EGPIODR_GPOE5 0x00000020 +#define EGPIODR_GPOE6 0x00000040 +#define EGPIODR_GPOE7 0x00000080 +#define EGPIODR_GPOE8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO pin polarity/ + * type register. + */ +#ifndef NO_CS4612 +#define EGPIOPTR_GPPT0 0x00000001 +#define EGPIOPTR_GPPT1 0x00000002 +#define EGPIOPTR_GPPT2 0x00000004 +#define EGPIOPTR_GPPT3 0x00000008 +#define EGPIOPTR_GPPT4 0x00000010 +#define EGPIOPTR_GPPT5 0x00000020 +#define EGPIOPTR_GPPT6 0x00000040 +#define EGPIOPTR_GPPT7 0x00000080 +#define EGPIOPTR_GPPT8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO pin sticky + * register. + */ +#ifndef NO_CS4612 +#define EGPIOTR_GPS0 0x00000001 +#define EGPIOTR_GPS1 0x00000002 +#define EGPIOTR_GPS2 0x00000004 +#define EGPIOTR_GPS3 0x00000008 +#define EGPIOTR_GPS4 0x00000010 +#define EGPIOTR_GPS5 0x00000020 +#define EGPIOTR_GPS6 0x00000040 +#define EGPIOTR_GPS7 0x00000080 +#define EGPIOTR_GPS8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO ping wakeup + * register. + */ +#ifndef NO_CS4612 +#define EGPIOWR_GPW0 0x00000001 +#define EGPIOWR_GPW1 0x00000002 +#define EGPIOWR_GPW2 0x00000004 +#define EGPIOWR_GPW3 0x00000008 +#define EGPIOWR_GPW4 0x00000010 +#define EGPIOWR_GPW5 0x00000020 +#define EGPIOWR_GPW6 0x00000040 +#define EGPIOWR_GPW7 0x00000080 +#define EGPIOWR_GPW8 0x00000100 +#endif + +/* + * The following defines are for the flags in the extended GPIO pin status + * register. + */ +#ifndef NO_CS4612 +#define EGPIOSR_GPS0 0x00000001 +#define EGPIOSR_GPS1 0x00000002 +#define EGPIOSR_GPS2 0x00000004 +#define EGPIOSR_GPS3 0x00000008 +#define EGPIOSR_GPS4 0x00000010 +#define EGPIOSR_GPS5 0x00000020 +#define EGPIOSR_GPS6 0x00000040 +#define EGPIOSR_GPS7 0x00000080 +#define EGPIOSR_GPS8 0x00000100 +#endif + +/* + * The following defines are for the flags in the serial port 6 configuration + * register. + */ +#ifndef NO_CS4612 +#define SERC6_ASDO2EN 0x00000001 +#endif + +/* + * The following defines are for the flags in the serial port 7 configuration + * register. + */ +#ifndef NO_CS4612 +#define SERC7_ASDI2EN 0x00000001 +#define SERC7_POSILB 0x00000002 +#define SERC7_SIPOLB 0x00000004 +#define SERC7_SOSILB 0x00000008 +#define SERC7_SISOLB 0x00000010 +#endif + +/* + * The following defines are for the flags in the serial port AC link + * configuration register. + */ +#ifndef NO_CS4612 +#define SERACC_CODEC_TYPE_MASK 0x00000001 +#define SERACC_CODEC_TYPE_1_03 0x00000000 +#define SERACC_CODEC_TYPE_2_0 0x00000001 +#define SERACC_TWO_CODECS 0x00000002 +#define SERACC_MDM 0x00000004 +#define SERACC_HSP 0x00000008 +#endif + +/* + * The following defines are for the flags in the AC97 control register 2. + */ +#ifndef NO_CS4612 +#define ACCTL2_RSTN 0x00000001 +#define ACCTL2_ESYN 0x00000002 +#define ACCTL2_VFRM 0x00000004 +#define ACCTL2_DCV 0x00000008 +#define ACCTL2_CRW 0x00000010 +#define ACCTL2_ASYN 0x00000020 +#endif + +/* + * The following defines are for the flags in the AC97 status register 2. + */ +#ifndef NO_CS4612 +#define ACSTS2_CRDY 0x00000001 +#define ACSTS2_VSTS 0x00000002 +#endif + +/* + * The following defines are for the flags in the AC97 output slot valid + * register 2. + */ +#ifndef NO_CS4612 +#define ACOSV2_SLV3 0x00000001 +#define ACOSV2_SLV4 0x00000002 +#define ACOSV2_SLV5 0x00000004 +#define ACOSV2_SLV6 0x00000008 +#define ACOSV2_SLV7 0x00000010 +#define ACOSV2_SLV8 0x00000020 +#define ACOSV2_SLV9 0x00000040 +#define ACOSV2_SLV10 0x00000080 +#define ACOSV2_SLV11 0x00000100 +#define ACOSV2_SLV12 0x00000200 +#endif + +/* + * The following defines are for the flags in the AC97 command address + * register 2. + */ +#ifndef NO_CS4612 +#define ACCAD2_CI_MASK 0x0000007F +#define ACCAD2_CI_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the AC97 command data register + * 2. + */ +#ifndef NO_CS4612 +#define ACCDA2_CD_MASK 0x0000FFFF +#define ACCDA2_CD_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the AC97 input slot valid + * register 2. + */ +#ifndef NO_CS4612 +#define ACISV2_ISV3 0x00000001 +#define ACISV2_ISV4 0x00000002 +#define ACISV2_ISV5 0x00000004 +#define ACISV2_ISV6 0x00000008 +#define ACISV2_ISV7 0x00000010 +#define ACISV2_ISV8 0x00000020 +#define ACISV2_ISV9 0x00000040 +#define ACISV2_ISV10 0x00000080 +#define ACISV2_ISV11 0x00000100 +#define ACISV2_ISV12 0x00000200 +#endif + +/* + * The following defines are for the flags in the AC97 status address + * register 2. + */ +#ifndef NO_CS4612 +#define ACSAD2_SI_MASK 0x0000007F +#define ACSAD2_SI_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the AC97 status data register 2. + */ +#ifndef NO_CS4612 +#define ACSDA2_SD_MASK 0x0000FFFF +#define ACSDA2_SD_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the I/O trap address and control + * registers (all 12). + */ +#ifndef NO_CS4612 +#define IOTAC_SA_MASK 0x0000FFFF +#define IOTAC_MSK_MASK 0x000F0000 +#define IOTAC_IODC_MASK 0x06000000 +#define IOTAC_IODC_16_BIT 0x00000000 +#define IOTAC_IODC_10_BIT 0x02000000 +#define IOTAC_IODC_12_BIT 0x04000000 +#define IOTAC_WSPI 0x08000000 +#define IOTAC_RSPI 0x10000000 +#define IOTAC_WSE 0x20000000 +#define IOTAC_WE 0x40000000 +#define IOTAC_RE 0x80000000 +#define IOTAC_SA_SHIFT 0 +#define IOTAC_MSK_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the I/O trap fast read registers + * (all 8). + */ +#ifndef NO_CS4612 +#define IOTFR_D_MASK 0x0000FFFF +#define IOTFR_A_MASK 0x000F0000 +#define IOTFR_R_MASK 0x0F000000 +#define IOTFR_ALL 0x40000000 +#define IOTFR_VL 0x80000000 +#define IOTFR_D_SHIFT 0 +#define IOTFR_A_SHIFT 16 +#define IOTFR_R_SHIFT 24 +#endif + +/* + * The following defines are for the flags in the I/O trap FIFO register. + */ +#ifndef NO_CS4612 +#define IOTFIFO_BA_MASK 0x00003FFF +#define IOTFIFO_S_MASK 0x00FF0000 +#define IOTFIFO_OF 0x40000000 +#define IOTFIFO_SPIOF 0x80000000 +#define IOTFIFO_BA_SHIFT 0 +#define IOTFIFO_S_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the I/O trap retry read data + * register. + */ +#ifndef NO_CS4612 +#define IOTRRD_D_MASK 0x0000FFFF +#define IOTRRD_RDV 0x80000000 +#define IOTRRD_D_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the I/O trap FIFO pointer + * register. + */ +#ifndef NO_CS4612 +#define IOTFP_CA_MASK 0x00003FFF +#define IOTFP_PA_MASK 0x3FFF0000 +#define IOTFP_CA_SHIFT 0 +#define IOTFP_PA_SHIFT 16 +#endif + +/* + * The following defines are for the flags in the I/O trap control register. + */ +#ifndef NO_CS4612 +#define IOTCR_ITD 0x00000001 +#define IOTCR_HRV 0x00000002 +#define IOTCR_SRV 0x00000004 +#define IOTCR_DTI 0x00000008 +#define IOTCR_DFI 0x00000010 +#define IOTCR_DDP 0x00000020 +#define IOTCR_JTE 0x00000040 +#define IOTCR_PPE 0x00000080 +#endif + +/* + * The following defines are for the flags in the direct PCI data register. + */ +#ifndef NO_CS4612 +#define DPCID_D_MASK 0xFFFFFFFF +#define DPCID_D_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the direct PCI address register. + */ +#ifndef NO_CS4612 +#define DPCIA_A_MASK 0xFFFFFFFF +#define DPCIA_A_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the direct PCI command register. + */ +#ifndef NO_CS4612 +#define DPCIC_C_MASK 0x0000000F +#define DPCIC_C_IOREAD 0x00000002 +#define DPCIC_C_IOWRITE 0x00000003 +#define DPCIC_BE_MASK 0x000000F0 +#endif + +/* + * The following defines are for the flags in the PC/PCI request register. + */ +#ifndef NO_CS4612 +#define PCPCIR_RDC_MASK 0x00000007 +#define PCPCIR_C_MASK 0x00007000 +#define PCPCIR_REQ 0x00008000 +#define PCPCIR_RDC_SHIFT 0 +#define PCPCIR_C_SHIFT 12 +#endif + +/* + * The following defines are for the flags in the PC/PCI grant register. + */ +#ifndef NO_CS4612 +#define PCPCIG_GDC_MASK 0x00000007 +#define PCPCIG_VL 0x00008000 +#define PCPCIG_GDC_SHIFT 0 +#endif + +/* + * The following defines are for the flags in the PC/PCI master enable + * register. + */ +#ifndef NO_CS4612 +#define PCPCIEN_EN 0x00000001 +#endif + +/* + * The following defines are for the flags in the extended PCI power + * management control register. + */ +#ifndef NO_CS4612 +#define EPCIPMC_GWU 0x00000001 +#define EPCIPMC_FSPC 0x00000002 +#endif + +/* + * The following defines are for the flags in the SP control register. + */ +#define SPCR_RUN 0x00000001 +#define SPCR_STPFR 0x00000002 +#define SPCR_RUNFR 0x00000004 +#define SPCR_TICK 0x00000008 +#define SPCR_DRQEN 0x00000020 +#define SPCR_RSTSP 0x00000040 +#define SPCR_OREN 0x00000080 +#ifndef NO_CS4612 +#define SPCR_PCIINT 0x00000100 +#define SPCR_OINTD 0x00000200 +#define SPCR_CRE 0x00008000 +#endif + +/* + * The following defines are for the flags in the debug index register. + */ +#define DREG_REGID_MASK 0x0000007F +#define DREG_DEBUG 0x00000080 +#define DREG_RGBK_MASK 0x00000700 +#define DREG_TRAP 0x00000800 +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_TRAPX 0x00001000 +#endif +#endif +#define DREG_REGID_SHIFT 0 +#define DREG_RGBK_SHIFT 8 +#define DREG_RGBK_REGID_MASK 0x0000077F +#define DREG_REGID_R0 0x00000010 +#define DREG_REGID_R1 0x00000011 +#define DREG_REGID_R2 0x00000012 +#define DREG_REGID_R3 0x00000013 +#define DREG_REGID_R4 0x00000014 +#define DREG_REGID_R5 0x00000015 +#define DREG_REGID_R6 0x00000016 +#define DREG_REGID_R7 0x00000017 +#define DREG_REGID_R8 0x00000018 +#define DREG_REGID_R9 0x00000019 +#define DREG_REGID_RA 0x0000001A +#define DREG_REGID_RB 0x0000001B +#define DREG_REGID_RC 0x0000001C +#define DREG_REGID_RD 0x0000001D +#define DREG_REGID_RE 0x0000001E +#define DREG_REGID_RF 0x0000001F +#define DREG_REGID_RA_BUS_LOW 0x00000020 +#define DREG_REGID_RA_BUS_HIGH 0x00000038 +#define DREG_REGID_YBUS_LOW 0x00000050 +#define DREG_REGID_YBUS_HIGH 0x00000058 +#define DREG_REGID_TRAP_0 0x00000100 +#define DREG_REGID_TRAP_1 0x00000101 +#define DREG_REGID_TRAP_2 0x00000102 +#define DREG_REGID_TRAP_3 0x00000103 +#define DREG_REGID_TRAP_4 0x00000104 +#define DREG_REGID_TRAP_5 0x00000105 +#define DREG_REGID_TRAP_6 0x00000106 +#define DREG_REGID_TRAP_7 0x00000107 +#define DREG_REGID_INDIRECT_ADDRESS 0x0000010E +#define DREG_REGID_TOP_OF_STACK 0x0000010F +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_REGID_TRAP_8 0x00000110 +#define DREG_REGID_TRAP_9 0x00000111 +#define DREG_REGID_TRAP_10 0x00000112 +#define DREG_REGID_TRAP_11 0x00000113 +#define DREG_REGID_TRAP_12 0x00000114 +#define DREG_REGID_TRAP_13 0x00000115 +#define DREG_REGID_TRAP_14 0x00000116 +#define DREG_REGID_TRAP_15 0x00000117 +#define DREG_REGID_TRAP_16 0x00000118 +#define DREG_REGID_TRAP_17 0x00000119 +#define DREG_REGID_TRAP_18 0x0000011A +#define DREG_REGID_TRAP_19 0x0000011B +#define DREG_REGID_TRAP_20 0x0000011C +#define DREG_REGID_TRAP_21 0x0000011D +#define DREG_REGID_TRAP_22 0x0000011E +#define DREG_REGID_TRAP_23 0x0000011F +#endif +#endif +#define DREG_REGID_RSA0_LOW 0x00000200 +#define DREG_REGID_RSA0_HIGH 0x00000201 +#define DREG_REGID_RSA1_LOW 0x00000202 +#define DREG_REGID_RSA1_HIGH 0x00000203 +#define DREG_REGID_RSA2 0x00000204 +#define DREG_REGID_RSA3 0x00000205 +#define DREG_REGID_RSI0_LOW 0x00000206 +#define DREG_REGID_RSI0_HIGH 0x00000207 +#define DREG_REGID_RSI1 0x00000208 +#define DREG_REGID_RSI2 0x00000209 +#define DREG_REGID_SAGUSTATUS 0x0000020A +#define DREG_REGID_RSCONFIG01_LOW 0x0000020B +#define DREG_REGID_RSCONFIG01_HIGH 0x0000020C +#define DREG_REGID_RSCONFIG23_LOW 0x0000020D +#define DREG_REGID_RSCONFIG23_HIGH 0x0000020E +#define DREG_REGID_RSDMA01E 0x0000020F +#define DREG_REGID_RSDMA23E 0x00000210 +#define DREG_REGID_RSD0_LOW 0x00000211 +#define DREG_REGID_RSD0_HIGH 0x00000212 +#define DREG_REGID_RSD1_LOW 0x00000213 +#define DREG_REGID_RSD1_HIGH 0x00000214 +#define DREG_REGID_RSD2_LOW 0x00000215 +#define DREG_REGID_RSD2_HIGH 0x00000216 +#define DREG_REGID_RSD3_LOW 0x00000217 +#define DREG_REGID_RSD3_HIGH 0x00000218 +#define DREG_REGID_SRAR_HIGH 0x0000021A +#define DREG_REGID_SRAR_LOW 0x0000021B +#define DREG_REGID_DMA_STATE 0x0000021C +#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021D +#define DREG_REGID_NEXT_DMA_STREAM 0x0000021E +#define DREG_REGID_CPU_STATUS 0x00000300 +#define DREG_REGID_MAC_MODE 0x00000301 +#define DREG_REGID_STACK_AND_REPEAT 0x00000302 +#define DREG_REGID_INDEX0 0x00000304 +#define DREG_REGID_INDEX1 0x00000305 +#define DREG_REGID_DMA_STATE_0_3 0x00000400 +#define DREG_REGID_DMA_STATE_4_7 0x00000404 +#define DREG_REGID_DMA_STATE_8_11 0x00000408 +#define DREG_REGID_DMA_STATE_12_15 0x0000040C +#define DREG_REGID_DMA_STATE_16_19 0x00000410 +#define DREG_REGID_DMA_STATE_20_23 0x00000414 +#define DREG_REGID_DMA_STATE_24_27 0x00000418 +#define DREG_REGID_DMA_STATE_28_31 0x0000041C +#define DREG_REGID_DMA_STATE_32_35 0x00000420 +#define DREG_REGID_DMA_STATE_36_39 0x00000424 +#define DREG_REGID_DMA_STATE_40_43 0x00000428 +#define DREG_REGID_DMA_STATE_44_47 0x0000042C +#define DREG_REGID_DMA_STATE_48_51 0x00000430 +#define DREG_REGID_DMA_STATE_52_55 0x00000434 +#define DREG_REGID_DMA_STATE_56_59 0x00000438 +#define DREG_REGID_DMA_STATE_60_63 0x0000043C +#define DREG_REGID_DMA_STATE_64_67 0x00000440 +#define DREG_REGID_DMA_STATE_68_71 0x00000444 +#define DREG_REGID_DMA_STATE_72_75 0x00000448 +#define DREG_REGID_DMA_STATE_76_79 0x0000044C +#define DREG_REGID_DMA_STATE_80_83 0x00000450 +#define DREG_REGID_DMA_STATE_84_87 0x00000454 +#define DREG_REGID_DMA_STATE_88_91 0x00000458 +#define DREG_REGID_DMA_STATE_92_95 0x0000045C +#define DREG_REGID_TRAP_SELECT 0x00000500 +#define DREG_REGID_TRAP_WRITE_0 0x00000500 +#define DREG_REGID_TRAP_WRITE_1 0x00000501 +#define DREG_REGID_TRAP_WRITE_2 0x00000502 +#define DREG_REGID_TRAP_WRITE_3 0x00000503 +#define DREG_REGID_TRAP_WRITE_4 0x00000504 +#define DREG_REGID_TRAP_WRITE_5 0x00000505 +#define DREG_REGID_TRAP_WRITE_6 0x00000506 +#define DREG_REGID_TRAP_WRITE_7 0x00000507 +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_REGID_TRAP_WRITE_8 0x00000510 +#define DREG_REGID_TRAP_WRITE_9 0x00000511 +#define DREG_REGID_TRAP_WRITE_10 0x00000512 +#define DREG_REGID_TRAP_WRITE_11 0x00000513 +#define DREG_REGID_TRAP_WRITE_12 0x00000514 +#define DREG_REGID_TRAP_WRITE_13 0x00000515 +#define DREG_REGID_TRAP_WRITE_14 0x00000516 +#define DREG_REGID_TRAP_WRITE_15 0x00000517 +#define DREG_REGID_TRAP_WRITE_16 0x00000518 +#define DREG_REGID_TRAP_WRITE_17 0x00000519 +#define DREG_REGID_TRAP_WRITE_18 0x0000051A +#define DREG_REGID_TRAP_WRITE_19 0x0000051B +#define DREG_REGID_TRAP_WRITE_20 0x0000051C +#define DREG_REGID_TRAP_WRITE_21 0x0000051D +#define DREG_REGID_TRAP_WRITE_22 0x0000051E +#define DREG_REGID_TRAP_WRITE_23 0x0000051F +#endif +#endif +#define DREG_REGID_MAC0_ACC0_LOW 0x00000600 +#define DREG_REGID_MAC0_ACC1_LOW 0x00000601 +#define DREG_REGID_MAC0_ACC2_LOW 0x00000602 +#define DREG_REGID_MAC0_ACC3_LOW 0x00000603 +#define DREG_REGID_MAC1_ACC0_LOW 0x00000604 +#define DREG_REGID_MAC1_ACC1_LOW 0x00000605 +#define DREG_REGID_MAC1_ACC2_LOW 0x00000606 +#define DREG_REGID_MAC1_ACC3_LOW 0x00000607 +#define DREG_REGID_MAC0_ACC0_MID 0x00000608 +#define DREG_REGID_MAC0_ACC1_MID 0x00000609 +#define DREG_REGID_MAC0_ACC2_MID 0x0000060A +#define DREG_REGID_MAC0_ACC3_MID 0x0000060B +#define DREG_REGID_MAC1_ACC0_MID 0x0000060C +#define DREG_REGID_MAC1_ACC1_MID 0x0000060D +#define DREG_REGID_MAC1_ACC2_MID 0x0000060E +#define DREG_REGID_MAC1_ACC3_MID 0x0000060F +#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610 +#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611 +#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612 +#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613 +#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614 +#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615 +#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616 +#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617 +#define DREG_REGID_RSHOUT_LOW 0x00000620 +#define DREG_REGID_RSHOUT_MID 0x00000628 +#define DREG_REGID_RSHOUT_HIGH 0x00000630 + +/* + * The following defines are for the flags in the DMA stream requestor write + */ +#define DSRWP_DSR_MASK 0x0000000F +#define DSRWP_DSR_BG_RQ 0x00000001 +#define DSRWP_DSR_PRIORITY_MASK 0x00000006 +#define DSRWP_DSR_PRIORITY_0 0x00000000 +#define DSRWP_DSR_PRIORITY_1 0x00000002 +#define DSRWP_DSR_PRIORITY_2 0x00000004 +#define DSRWP_DSR_PRIORITY_3 0x00000006 +#define DSRWP_DSR_RQ_PENDING 0x00000008 + +/* + * The following defines are for the flags in the trap write port register. + */ +#define TWPR_TW_MASK 0x0000FFFF +#define TWPR_TW_SHIFT 0 + +/* + * The following defines are for the flags in the stack pointer write + * register. + */ +#define SPWR_STKP_MASK 0x0000000F +#define SPWR_STKP_SHIFT 0 + +/* + * The following defines are for the flags in the SP interrupt register. + */ +#define SPIR_FRI 0x00000001 +#define SPIR_DOI 0x00000002 +#define SPIR_GPI2 0x00000004 +#define SPIR_GPI3 0x00000008 +#define SPIR_IP0 0x00000010 +#define SPIR_IP1 0x00000020 +#define SPIR_IP2 0x00000040 +#define SPIR_IP3 0x00000080 + +/* + * The following defines are for the flags in the functional group 1 register. + */ +#define FGR1_F1S_MASK 0x0000FFFF +#define FGR1_F1S_SHIFT 0 + +/* + * The following defines are for the flags in the SP clock status register. + */ +#define SPCS_FRI 0x00000001 +#define SPCS_DOI 0x00000002 +#define SPCS_GPI2 0x00000004 +#define SPCS_GPI3 0x00000008 +#define SPCS_IP0 0x00000010 +#define SPCS_IP1 0x00000020 +#define SPCS_IP2 0x00000040 +#define SPCS_IP3 0x00000080 +#define SPCS_SPRUN 0x00000100 +#define SPCS_SLEEP 0x00000200 +#define SPCS_FG 0x00000400 +#define SPCS_ORUN 0x00000800 +#define SPCS_IRQ 0x00001000 +#define SPCS_FGN_MASK 0x0000E000 +#define SPCS_FGN_SHIFT 13 + +/* + * The following defines are for the flags in the SP DMA requestor status + * register. + */ +#define SDSR_DCS_MASK 0x000000FF +#define SDSR_DCS_SHIFT 0 +#define SDSR_DCS_NONE 0x00000007 + +/* + * The following defines are for the flags in the frame timer register. + */ +#define FRMT_FTV_MASK 0x0000FFFF +#define FRMT_FTV_SHIFT 0 + +/* + * The following defines are for the flags in the frame timer current count + * register. + */ +#define FRCC_FCC_MASK 0x0000FFFF +#define FRCC_FCC_SHIFT 0 + +/* + * The following defines are for the flags in the frame timer save count + * register. + */ +#define FRSC_FCS_MASK 0x0000FFFF +#define FRSC_FCS_SHIFT 0 + +/* + * The following define the various flags stored in the scatter/gather + * descriptors. + */ +#define DMA_SG_NEXT_ENTRY_MASK 0x00000FF8 +#define DMA_SG_SAMPLE_END_MASK 0x0FFF0000 +#define DMA_SG_SAMPLE_END_FLAG 0x10000000 +#define DMA_SG_LOOP_END_FLAG 0x20000000 +#define DMA_SG_SIGNAL_END_FLAG 0x40000000 +#define DMA_SG_SIGNAL_PAGE_FLAG 0x80000000 +#define DMA_SG_NEXT_ENTRY_SHIFT 3 +#define DMA_SG_SAMPLE_END_SHIFT 16 + +/* + * The following define the offsets of the fields within the on-chip generic + * DMA requestor. + */ +#define DMA_RQ_CONTROL1 0x00000000 +#define DMA_RQ_CONTROL2 0x00000004 +#define DMA_RQ_SOURCE_ADDR 0x00000008 +#define DMA_RQ_DESTINATION_ADDR 0x0000000C +#define DMA_RQ_NEXT_PAGE_ADDR 0x00000010 +#define DMA_RQ_NEXT_PAGE_SGDESC 0x00000014 +#define DMA_RQ_LOOP_START_ADDR 0x00000018 +#define DMA_RQ_POST_LOOP_ADDR 0x0000001C +#define DMA_RQ_PAGE_MAP_ADDR 0x00000020 + +/* + * The following defines are for the flags in the first control word of the + * on-chip generic DMA requestor. + */ +#define DMA_RQ_C1_COUNT_MASK 0x000003FF +#define DMA_RQ_C1_DESTINATION_SCATTER 0x00001000 +#define DMA_RQ_C1_SOURCE_GATHER 0x00002000 +#define DMA_RQ_C1_DONE_FLAG 0x00004000 +#define DMA_RQ_C1_OPTIMIZE_STATE 0x00008000 +#define DMA_RQ_C1_SAMPLE_END_STATE_MASK 0x00030000 +#define DMA_RQ_C1_FULL_PAGE 0x00000000 +#define DMA_RQ_C1_BEFORE_SAMPLE_END 0x00010000 +#define DMA_RQ_C1_PAGE_MAP_ERROR 0x00020000 +#define DMA_RQ_C1_AT_SAMPLE_END 0x00030000 +#define DMA_RQ_C1_LOOP_END_STATE_MASK 0x000C0000 +#define DMA_RQ_C1_NOT_LOOP_END 0x00000000 +#define DMA_RQ_C1_BEFORE_LOOP_END 0x00040000 +#define DMA_RQ_C1_2PAGE_LOOP_BEGIN 0x00080000 +#define DMA_RQ_C1_LOOP_BEGIN 0x000C0000 +#define DMA_RQ_C1_PAGE_MAP_MASK 0x00300000 +#define DMA_RQ_C1_PM_NONE_PENDING 0x00000000 +#define DMA_RQ_C1_PM_NEXT_PENDING 0x00100000 +#define DMA_RQ_C1_PM_RESERVED 0x00200000 +#define DMA_RQ_C1_PM_LOOP_NEXT_PENDING 0x00300000 +#define DMA_RQ_C1_WRITEBACK_DEST_FLAG 0x00400000 +#define DMA_RQ_C1_WRITEBACK_SRC_FLAG 0x00800000 +#define DMA_RQ_C1_DEST_SIZE_MASK 0x07000000 +#define DMA_RQ_C1_DEST_LINEAR 0x00000000 +#define DMA_RQ_C1_DEST_MOD16 0x01000000 +#define DMA_RQ_C1_DEST_MOD32 0x02000000 +#define DMA_RQ_C1_DEST_MOD64 0x03000000 +#define DMA_RQ_C1_DEST_MOD128 0x04000000 +#define DMA_RQ_C1_DEST_MOD256 0x05000000 +#define DMA_RQ_C1_DEST_MOD512 0x06000000 +#define DMA_RQ_C1_DEST_MOD1024 0x07000000 +#define DMA_RQ_C1_DEST_ON_HOST 0x08000000 +#define DMA_RQ_C1_SOURCE_SIZE_MASK 0x70000000 +#define DMA_RQ_C1_SOURCE_LINEAR 0x00000000 +#define DMA_RQ_C1_SOURCE_MOD16 0x10000000 +#define DMA_RQ_C1_SOURCE_MOD32 0x20000000 +#define DMA_RQ_C1_SOURCE_MOD64 0x30000000 +#define DMA_RQ_C1_SOURCE_MOD128 0x40000000 +#define DMA_RQ_C1_SOURCE_MOD256 0x50000000 +#define DMA_RQ_C1_SOURCE_MOD512 0x60000000 +#define DMA_RQ_C1_SOURCE_MOD1024 0x70000000 +#define DMA_RQ_C1_SOURCE_ON_HOST 0x80000000 +#define DMA_RQ_C1_COUNT_SHIFT 0 + +/* + * The following defines are for the flags in the second control word of the + * on-chip generic DMA requestor. + */ +#define DMA_RQ_C2_VIRTUAL_CHANNEL_MASK 0x0000003F +#define DMA_RQ_C2_VIRTUAL_SIGNAL_MASK 0x00000300 +#define DMA_RQ_C2_NO_VIRTUAL_SIGNAL 0x00000000 +#define DMA_RQ_C2_SIGNAL_EVERY_DMA 0x00000100 +#define DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG 0x00000200 +#define DMA_RQ_C2_SIGNAL_DEST_PINGPONG 0x00000300 +#define DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000 +#define DMA_RQ_C2_AC_NONE 0x00000000 +#define DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000 +#define DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000 +#define DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000 +#define DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000 +#define DMA_RQ_C2_LOOP_END_MASK 0x0FFF0000 +#define DMA_RQ_C2_LOOP_MASK 0x30000000 +#define DMA_RQ_C2_NO_LOOP 0x00000000 +#define DMA_RQ_C2_ONE_PAGE_LOOP 0x10000000 +#define DMA_RQ_C2_TWO_PAGE_LOOP 0x20000000 +#define DMA_RQ_C2_MULTI_PAGE_LOOP 0x30000000 +#define DMA_RQ_C2_SIGNAL_LOOP_BACK 0x40000000 +#define DMA_RQ_C2_SIGNAL_POST_BEGIN_PAGE 0x80000000 +#define DMA_RQ_C2_VIRTUAL_CHANNEL_SHIFT 0 +#define DMA_RQ_C2_LOOP_END_SHIFT 16 + +/* + * The following defines are for the flags in the source and destination words + * of the on-chip generic DMA requestor. + */ +#define DMA_RQ_SD_ADDRESS_MASK 0x0000FFFF +#define DMA_RQ_SD_MEMORY_ID_MASK 0x000F0000 +#define DMA_RQ_SD_SP_PARAM_ADDR 0x00000000 +#define DMA_RQ_SD_SP_SAMPLE_ADDR 0x00010000 +#define DMA_RQ_SD_SP_PROGRAM_ADDR 0x00020000 +#define DMA_RQ_SD_SP_DEBUG_ADDR 0x00030000 +#define DMA_RQ_SD_OMNIMEM_ADDR 0x000E0000 +#define DMA_RQ_SD_END_FLAG 0x40000000 +#define DMA_RQ_SD_ERROR_FLAG 0x80000000 +#define DMA_RQ_SD_ADDRESS_SHIFT 0 + +/* + * The following defines are for the flags in the page map address word of the + * on-chip generic DMA requestor. + */ +#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_MASK 0x00000FF8 +#define DMA_RQ_PMA_PAGE_TABLE_MASK 0xFFFFF000 +#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_SHIFT 3 +#define DMA_RQ_PMA_PAGE_TABLE_SHIFT 12 + +#define BA1_VARIDEC_BUF_1 0x000 + +#define BA1_PDTC 0x0c0 /* BA1_PLAY_DMA_TRANSACTION_COUNT_REG */ +#define BA1_PFIE 0x0c4 /* BA1_PLAY_FORMAT_&_INTERRUPT_ENABLE_REG */ +#define BA1_PBA 0x0c8 /* BA1_PLAY_BUFFER_ADDRESS */ +#define BA1_PVOL 0x0f8 /* BA1_PLAY_VOLUME_REG */ +#define BA1_PSRC 0x288 /* BA1_PLAY_SAMPLE_RATE_CORRECTION_REG */ +#define BA1_PCTL 0x2a4 /* BA1_PLAY_CONTROL_REG */ +#define BA1_PPI 0x2b4 /* BA1_PLAY_PHASE_INCREMENT_REG */ + +#define BA1_CCTL 0x064 /* BA1_CAPTURE_CONTROL_REG */ +#define BA1_CIE 0x104 /* BA1_CAPTURE_INTERRUPT_ENABLE_REG */ +#define BA1_CBA 0x10c /* BA1_CAPTURE_BUFFER_ADDRESS */ +#define BA1_CSRC 0x2c8 /* BA1_CAPTURE_SAMPLE_RATE_CORRECTION_REG */ +#define BA1_CCI 0x2d8 /* BA1_CAPTURE_COEFFICIENT_INCREMENT_REG */ +#define BA1_CD 0x2e0 /* BA1_CAPTURE_DELAY_REG */ +#define BA1_CPI 0x2f4 /* BA1_CAPTURE_PHASE_INCREMENT_REG */ +#define BA1_CVOL 0x2f8 /* BA1_CAPTURE_VOLUME_REG */ + +#define BA1_CFG1 0x134 /* BA1_CAPTURE_FRAME_GROUP_1_REG */ +#define BA1_CFG2 0x138 /* BA1_CAPTURE_FRAME_GROUP_2_REG */ +#define BA1_CCST 0x13c /* BA1_CAPTURE_CONSTANT_REG */ +#define BA1_CSPB 0x340 /* BA1_CAPTURE_SPB_ADDRESS */ + +/* + * + */ + +#define CS461X_MODE_OUTPUT (1<<0) /* MIDI UART - output */ +#define CS461X_MODE_INPUT (1<<1) /* MIDI UART - input */ + +#endif /* __CS461X_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/cs461x_image.h linux/drivers/sound/cs461x_image.h --- v2.4.0-test6/linux/drivers/sound/cs461x_image.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs461x_image.h Tue Aug 22 11:31:05 2000 @@ -0,0 +1,3459 @@ +struct BA1struct BA1Struct = { +{{ 0x00000000, 0x00003000 },{ 0x00010000, 0x00003800 },{ 0x00020000, 0x00007000 }}, +{0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000163,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00200040,0x00008010,0x00000000, +0x00000000,0x80000001,0x00000001,0x00060000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00900080,0x00000173,0x00000000, +0x00000000,0x00000010,0x00800000,0x00900000, +0xf2c0000f,0x00000200,0x00000000,0x00010600, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000163,0x330300c2, +0x06000000,0x00000000,0x80008000,0x80008000, +0x3fc0000f,0x00000301,0x00010400,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00b00000,0x00d0806d,0x330480c3, +0x04800000,0x00000001,0x00800001,0x0000ffff, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x066a0600,0x06350070,0x0000929d,0x929d929d, +0x00000000,0x0000735a,0x00000600,0x00000000, +0x929d735a,0x8734abfe,0x00010000,0x735a735a, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x0000804f,0x000000c3, +0x05000000,0x00a00010,0x00000000,0x80008000, +0x00000000,0x00000000,0x00000700,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000080,0x00a00000,0x0000809a,0x000000c2, +0x07400000,0x00000000,0x80008000,0xffffffff, +0x00c80028,0x00005555,0x00000000,0x000107a0, +0x00c80028,0x000000c2,0x06800000,0x00000000, +0x06e00080,0x00300000,0x000080bb,0x000000c9, +0x07a00000,0x04000000,0x80008000,0xffffffff, +0x00c80028,0x00005555,0x00000000,0x00000780, +0x00c80028,0x000000c5,0xff800000,0x00000000, +0x00640080,0x00c00000,0x00008197,0x000000c9, +0x07800000,0x04000000,0x80008000,0xffffffff, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x0000805e,0x000000c1, +0x00000000,0x00800000,0x80008000,0x80008000, +0x00020000,0x0000ffff,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x929d0600,0x929d929d,0x929d929d,0x929d0000, +0x929d929d,0x929d929d,0x929d929d,0x929d929d, +0x929d929d,0x00100635,0x060b013f,0x00000004, +0x00000001,0x007a0002,0x00000000,0x066e0610, +0x0105929d,0x929d929d,0x929d929d,0x929d929d, +0x929d929d,0xa431ac75,0x0001735a,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051, +0x00000000,0x929d929d,0x929d929d,0x929d929d, +0x929d929d,0x929d929d,0x929d929d,0x929d929d, +0x929d929d,0x929d929d,0x00000000,0x06400136, +0x0000270f,0x00010000,0x007a0000,0x00000000, +0x068e0645,0x0105929d,0x929d929d,0x929d929d, +0x929d929d,0x929d929d,0xa431ac75,0x0001735a, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, +0x735a0100,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00010004, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00001705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00009705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00011705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00019705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00021705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00029705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00031705,0x00001400,0x000a411e,0x00001003, +0x00040730,0x00001002,0x000f619e,0x00001003, +0x00039705,0x00001400,0x000a411e,0x00001003, +0x000fe19e,0x00001003,0x0009c730,0x00001003, +0x0008e19c,0x00001003,0x000083c1,0x00093040, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00009705,0x00001400,0x000a211e,0x00001003, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00011705,0x00001400,0x000a211e,0x00001003, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00019705,0x00001400,0x000a211e,0x00001003, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00021705,0x00001400,0x000a211e,0x00001003, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00029705,0x00001400,0x000a211e,0x00001003, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00031705,0x00001400,0x000a211e,0x00001003, +0x00098730,0x00001002,0x000ee19e,0x00001003, +0x00039705,0x00001400,0x000a211e,0x00001003, +0x0000a730,0x00001008,0x000e2730,0x00001002, +0x0000a731,0x00001002,0x0000a731,0x00001002, +0x0000a731,0x00001002,0x0000a731,0x00001002, +0x0000a731,0x00001002,0x0000a731,0x00001002, +0x00000000,0x00000000,0x000f619c,0x00001003, +0x0007f801,0x000c0000,0x00000037,0x00001000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x000c0000,0x00000000,0x00000000, +0x0000373c,0x00001000,0x00000000,0x00000000, +0x000ee19c,0x00001003,0x0007f801,0x000c0000, +0x00000037,0x00001000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x0000273c,0x00001000, +0x00000033,0x00001000,0x000e679e,0x00001003, +0x00007705,0x00001400,0x000ac71e,0x00001003, +0x00087fc1,0x000c3be0,0x0007f801,0x000c0000, +0x00000037,0x00001000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x0000a730,0x00001003, +0x00000033,0x00001000,0x0007f801,0x000c0000, +0x00000037,0x00001000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x000c0000, +0x00000032,0x00001000,0x0000273d,0x00001000, +0x0004a730,0x00001003,0x00000f41,0x00097140, +0x0000a841,0x0009b240,0x0000a0c1,0x0009f040, +0x0001c641,0x00093540,0x0001cec1,0x0009b5c0, +0x00000000,0x00000000,0x0001bf05,0x0003fc40, +0x00002725,0x000aa400,0x00013705,0x00093a00, +0x0000002e,0x0009d6c0,0x00038630,0x00001004, +0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000, +0x00000000,0x000c70e0,0x0007d182,0x0002c640, +0x00000630,0x00001004,0x000799b8,0x0002c6c0, +0x00031705,0x00092240,0x00039f05,0x000932c0, +0x0003520a,0x00000000,0x00040731,0x0000100b, +0x00010705,0x000b20c0,0x00000000,0x000eba44, +0x00032108,0x000c60c4,0x00065208,0x000c2917, +0x000406b0,0x00001007,0x00012f05,0x00036880, +0x0002818e,0x000c0000,0x0004410a,0x00000000, +0x00040630,0x00001007,0x00029705,0x000c0000, +0x00000000,0x00000000,0x00003fc1,0x0003fc40, +0x000037c1,0x00091b40,0x00003fc1,0x000911c0, +0x000037c1,0x000957c0,0x00003fc1,0x000951c0, +0x000037c1,0x00000000,0x00003fc1,0x000991c0, +0x000037c1,0x00000000,0x00003fc1,0x0009d1c0, +0x000037c1,0x00000000,0x0001ccc1,0x000915c0, +0x0001c441,0x0009d800,0x0009cdc1,0x00091240, +0x0001c541,0x00091d00,0x0009cfc1,0x00095240, +0x0001c741,0x00095c80,0x000e8ca9,0x00099240, +0x000e85ad,0x00095640,0x00069ca9,0x00099d80, +0x000e952d,0x00099640,0x000eaca9,0x0009d6c0, +0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80, +0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0, +0x000ec5ad,0x0009da40,0x000edca9,0x0009d300, +0x000a6e0a,0x00001000,0x000ed52d,0x00091e40, +0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40, +0x0006fca9,0x00002500,0x000fb208,0x000c59a0, +0x000ef52d,0x0009de40,0x00068ca9,0x000912c1, +0x000683ad,0x00095241,0x00020f05,0x000991c1, +0x00000000,0x00000000,0x00086f88,0x00001000, +0x0009cf81,0x000b5340,0x0009c701,0x000b92c0, +0x0009de81,0x000bd300,0x0009d601,0x000b1700, +0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0, +0x000a0f81,0x000bd740,0x00020701,0x000b5c80, +0x000a1681,0x000b97c0,0x00021601,0x00002500, +0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0, +0x00021681,0x00002d00,0x00020f81,0x000bd800, +0x000a0701,0x000b5bc0,0x00021601,0x00003500, +0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0, +0x00021681,0x00003d00,0x00020f81,0x000b1d00, +0x000a0701,0x000b1fc0,0x00021601,0x00020500, +0x00020f81,0x000b1341,0x000a0701,0x000b9fc0, +0x00021681,0x00020d00,0x00020f81,0x000bde80, +0x000a0701,0x000bdfc0,0x00021601,0x00021500, +0x00020f81,0x000b9341,0x00020701,0x000b53c1, +0x00021681,0x00021d00,0x000a0f81,0x000d0380, +0x0000b601,0x000b15c0,0x00007b01,0x00000000, +0x00007b81,0x000bd1c0,0x00007b01,0x00000000, +0x00007b81,0x000b91c0,0x00007b01,0x000b57c0, +0x00007b81,0x000b51c0,0x00007b01,0x000b1b40, +0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0, +0x0007e488,0x000d7e45,0x00000000,0x000d7a44, +0x0007e48a,0x00000000,0x00011f05,0x00084080, +0x00000000,0x00000000,0x00001705,0x000b3540, +0x00008a01,0x000bf040,0x00007081,0x000bb5c0, +0x00055488,0x00000000,0x0000d482,0x0003fc40, +0x0003fc88,0x00000000,0x0001e401,0x000b3a00, +0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784, +0x000c86b0,0x00001007,0x00008281,0x000bb240, +0x0000b801,0x000b7140,0x00007888,0x00000000, +0x0000073c,0x00001000,0x0007f188,0x000c0000, +0x00000000,0x00000000,0x00055288,0x000c555c, +0x0005528a,0x000c0000,0x0009fa88,0x000c5d00, +0x0000fa88,0x00000000,0x00000032,0x00001000, +0x0000073d,0x00001000,0x0007f188,0x000c0000, +0x00000000,0x00000000,0x0008c01c,0x00001003, +0x00002705,0x00001008,0x0008b201,0x000c1392, +0x0000ba01,0x00000000,0x00008731,0x00001400, +0x0004c108,0x000fe0c4,0x00057488,0x00000000, +0x000a6388,0x00001001,0x0008b334,0x000bc141, +0x0003020e,0x00000000,0x000886b0,0x00001008, +0x00003625,0x000c5dfa,0x000a638a,0x00001001, +0x0008020e,0x00001002,0x0008a6b0,0x00001008, +0x0007f301,0x00000000,0x00000000,0x00000000, +0x00002725,0x000a8c40,0x000000ae,0x00000000, +0x000d8630,0x00001008,0x00000000,0x000c74e0, +0x0007d182,0x0002d640,0x000a8630,0x00001008, +0x000799b8,0x0002d6c0,0x0000748a,0x000c3ec5, +0x0007420a,0x000c0000,0x00062208,0x000c4117, +0x00070630,0x00001009,0x00000000,0x000c0000, +0x0001022e,0x00000000,0x0003a630,0x00001009, +0x00000000,0x000c0000,0x00000036,0x00001000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x0002a730,0x00001008,0x0007f801,0x000c0000, +0x00000037,0x00001000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x0002a730,0x00001008, +0x00000033,0x00001000,0x0002a705,0x00001008, +0x00007a01,0x000c0000,0x000e6288,0x000d550a, +0x0006428a,0x00000000,0x00060730,0x0000100a, +0x00000000,0x000c0000,0x00000000,0x00000000, +0x0007aab0,0x00034880,0x00078fb0,0x0000100b, +0x00057488,0x00000000,0x00033b94,0x00081140, +0x000183ae,0x00000000,0x000786b0,0x0000100b, +0x00022f05,0x000c3545,0x0000eb8a,0x00000000, +0x00042731,0x00001003,0x0007aab0,0x00034880, +0x00048fb0,0x0000100a,0x00057488,0x00000000, +0x00033b94,0x00081140,0x000183ae,0x00000000, +0x000806b0,0x0000100b,0x00022f05,0x00000000, +0x00007401,0x00091140,0x00048f05,0x000951c0, +0x00042731,0x00001003,0x0000473d,0x00001000, +0x000f19b0,0x000bbc47,0x00080000,0x000bffc7, +0x000fe19e,0x00001003,0x00000000,0x00000000, +0x0008e19c,0x00001003,0x000083c1,0x00093040, +0x00000f41,0x00097140,0x0000a841,0x0009b240, +0x0000a0c1,0x0009f040,0x0001c641,0x00093540, +0x0001cec1,0x0009b5c0,0x00000000,0x000fdc44, +0x00055208,0x00000000,0x00010705,0x000a2880, +0x0000a23a,0x00093a00,0x0003fc8a,0x000df6c5, +0x0004ef0a,0x000c0000,0x00012f05,0x00036880, +0x00065308,0x000c2997,0x000d86b0,0x0000100a, +0x0004410a,0x000d40c7,0x00000000,0x00000000, +0x00080730,0x00001004,0x00056f0a,0x000ea105, +0x00000000,0x00000000,0x0000473d,0x00001000, +0x000f19b0,0x000bbc47,0x00080000,0x000bffc7, +0x0000273d,0x00001000,0x00000000,0x000eba44, +0x00048f05,0x0000f440,0x00007401,0x0000f7c0, +0x00000734,0x00001000,0x00010705,0x000a6880, +0x00006a88,0x000c75c4,0x00000000,0x000e5084, +0x00000000,0x000eba44,0x00087401,0x000e4782, +0x00000734,0x00001000,0x00010705,0x000a6880, +0x00006a88,0x000c75c4,0x0007c108,0x000c0000, +0x0007e721,0x000bed40,0x00005f25,0x000badc0, +0x0003ba97,0x000beb80,0x00065590,0x000b2e00, +0x00033217,0x00003ec0,0x00065590,0x000b8e40, +0x0003ed80,0x000491c0,0x00073fb0,0x00074c80, +0x000283a0,0x0000100c,0x000ee388,0x00042970, +0x00008301,0x00021ef2,0x000b8f14,0x0000000f, +0x000c4d8d,0x0000001b,0x000d6dc2,0x000e06c6, +0x000032ac,0x000c3916,0x0004edc2,0x00074c80, +0x00078898,0x00001000,0x00038894,0x00000032, +0x000c4d8d,0x00092e1b,0x000d6dc2,0x000e06c6, +0x0004edc2,0x000c1956,0x0000722c,0x00034a00, +0x00041705,0x0009ed40,0x00058730,0x00001400, +0x000d7488,0x000c3a00,0x00048f05,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000, +0x00000000,0x00000000,0x00000000,0x00000000} + }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.4.0-test6/linux/drivers/sound/cs46xx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs46xx.c Tue Aug 22 11:31:05 2000 @@ -0,0 +1,2751 @@ +/* + * Crystal SoundFusion CS46xx driver + * + * Copyright 1999-2000 Jaroslav Kysela + * Copyright 2000 Alan Cox + * + * The core of this code is taken from the ALSA project driver by + * Jaroslav. Please send Jaroslav the credit for the driver and + * report bugs in this port to + * + * 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. + * + * Changes: + * 20000815 Updated driver to kernel 2.4, some cleanups/fixes + * Nils Faerber + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs461x.h" + +#define ADC_RUNNING 1 +#define DAC_RUNNING 2 + +#define CS_FMT_16BIT 1 /* These are fixed in fact */ +#define CS_FMT_STEREO 2 +#define CS_FMT_MASK 3 + +/* + * CS461x definitions + */ + +#define CS461X_BA0_SIZE 0x2000 +#define CS461X_BA1_DATA0_SIZE 0x3000 +#define CS461X_BA1_DATA1_SIZE 0x3800 +#define CS461X_BA1_PRG_SIZE 0x7000 +#define CS461X_BA1_REG_SIZE 0x0100 + +#define GOF_PER_SEC 200 + +/* + * Define this to enable recording, + * this is curently broken and using it will cause data corruption + * in kernel- and user-space! + */ +/* #define CS46XX_ENABLE_RECORD */ + +static int external_amp = 0; +static int thinkpad = 0; + + +/* an instance of the 4610 channel */ + +struct cs_channel +{ + int used; + int num; + void *state; +}; + +#define DRIVER_VERSION "0.09" + +/* magic numbers to protect our data structures */ +#define CS_CARD_MAGIC 0x46524F4D /* "FROM" */ +#define CS_STATE_MAGIC 0x414c5341 /* "ALSA" */ +#define NR_HW_CH 3 + +/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ +#define NR_AC97 2 + +/* minor number of /dev/dspW */ +#define SND_DEV_DSP8 1 + +/* minor number of /dev/dspW */ +#define SND_DEV_DSP16 1 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +/* "software" or virtual channel, an instance of opened /dev/dsp */ +struct cs_state { + unsigned int magic; + struct cs_card *card; /* Card info */ + + /* single open lock mechanism, only used for recording */ + struct semaphore open_sem; + wait_queue_head_t open_wait; + + /* file mode */ + mode_t open_mode; + + /* virtual channel number */ + int virt; + + struct dmabuf { + /* wave sample stuff */ + unsigned int rate; + unsigned char fmt, enable; + + /* hardware channel */ + struct cs_channel *channel; + int pringbuf; /* Software ring slot */ + int ppingbuf; /* Hardware ring slot */ + void *pbuf; /* 4K hardware DMA buffer */ + + /* OSS buffer management stuff */ + void *rawbuf; + dma_addr_t dma_handle; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + + /* our buffer acts like a circular ring */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ + unsigned swptr; /* where driver last clear/filled, updated by read/write */ + int count; /* bytes to be comsumed or been generated by dma machine */ + unsigned total_bytes; /* total bytes dmaed by hardware */ + + unsigned error; /* number of over/underruns */ + wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ + + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned update_flag; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dmabuf; +}; + + +struct cs_card { + struct cs_channel channel[2]; + unsigned int magic; + + /* We keep cs461x cards in a linked list */ + struct cs_card *next; + + /* The cs461x has a certain amount of cross channel interaction + so we use a single per card lock */ + spinlock_t lock; + + /* PCI device stuff */ + struct pci_dev * pci_dev; + + unsigned int pctl, cctl; /* Hardware DMA flag sets */ + + /* soundcore stuff */ + int dev_audio; + + /* structures for abstraction of hardware facilities, codecs, banks and channels*/ + struct ac97_codec *ac97_codec[NR_AC97]; + struct cs_state *states[NR_HW_CH]; + + u16 ac97_features; + + int amplifier; /* Amplifier control */ + void (*amplifier_ctrl)(struct cs_card *, int); + + int active; /* Active clocking */ + void (*active_ctrl)(struct cs_card *, int); + + /* hardware resources */ + unsigned long ba0_addr; + unsigned long ba1_addr; + u32 irq; + + /* mappings */ + void *ba0; + union + { + struct + { + u8 *data0; + u8 *data1; + u8 *pmem; + u8 *reg; + } name; + u8 *idx[4]; + } ba1; + + /* Function support */ + struct cs_channel *(*alloc_pcm_channel)(struct cs_card *); + struct cs_channel *(*alloc_rec_pcm_channel)(struct cs_card *); + void (*free_pcm_channel)(struct cs_card *, int chan); +}; + +static struct cs_card *devs = NULL; + +static int cs_open_mixdev(struct inode *inode, struct file *file); +static int cs_release_mixdev(struct inode *inode, struct file *file); +static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); +static loff_t cs_llseek(struct file *file, loff_t offset, int origin); + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + + +/* + * common I/O routines + */ + +static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val) +{ + writel(val, codec->ba1.idx[(reg >> 16) & 3]+(reg&0xffff)); +} + +static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg) +{ + return readl(codec->ba1.idx[(reg >> 16) & 3]+(reg&0xffff)); +} + +static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val) +{ + writel(val, codec->ba0+reg); +} + +static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg) +{ + return readl(codec->ba0+reg); +} + + +static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg); +static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); + +static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card) +{ + if(card->channel[1].used==1) + return NULL; + card->channel[1].used=1; + card->channel[1].num=1; + return &card->channel[1]; +} + +static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card) +{ + if(card->channel[0].used==1) + return NULL; + card->channel[0].used=1; + card->channel[0].num=0; + return &card->channel[0]; +} + +static void cs_free_pcm_channel(struct cs_card *card, int channel) +{ + card->channel[channel].state = NULL; + card->channel[channel].used=0; +} + +/* set playback sample rate */ +static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned int tmp1, tmp2; + unsigned int phiIncr; + unsigned int correctionPerGOF, correctionPerSec; + + /* + * Compute the values used to drive the actual sample rate conversion. + * The following formulas are being computed, using inline assembly + * since we need to use 64 bit arithmetic to compute the values: + * + * phiIncr = floor((Fs,in * 2^26) / Fs,out) + * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) / + * GOF_PER_SEC) + * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M + * GOF_PER_SEC * correctionPerGOF + * + * i.e. + * + * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out) + * correctionPerGOF:correctionPerSec = + * dividend:remainder(ulOther / GOF_PER_SEC) + */ + tmp1 = rate << 16; + phiIncr = tmp1 / 48000; + tmp1 -= phiIncr * 48000; + tmp1 <<= 10; + phiIncr <<= 10; + tmp2 = tmp1 / 48000; + phiIncr += tmp2; + tmp1 -= tmp2 * 48000; + correctionPerGOF = tmp1 / GOF_PER_SEC; + tmp1 -= correctionPerGOF * GOF_PER_SEC; + correctionPerSec = tmp1; + + /* + * Fill in the SampleRateConverter control block. + */ + + spin_lock_irq(&state->card->lock); + cs461x_poke(state->card, BA1_PSRC, + ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); + cs461x_poke(state->card, BA1_PPI, phiIncr); + spin_unlock_irq(&state->card->lock); + dmabuf->rate = rate; + + return rate; +} + +/* set recording sample rate */ +static unsigned int cs_set_adc_rate(struct cs_state * state, unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int phiIncr, coeffIncr, tmp1, tmp2; + unsigned int correctionPerGOF, correctionPerSec, initialDelay; + unsigned int frameGroupLength, cnt; + + /* + * We can only decimate by up to a factor of 1/9th the hardware rate. + * Correct the value if an attempt is made to stray outside that limit. + */ + if ((rate * 9) < 48000) + rate = 48000 / 9; + + /* + * We can not capture at at rate greater than the Input Rate (48000). + * Return an error if an attempt is made to stray outside that limit. + */ + if (rate > 48000) + rate = 48000; + + /* + * Compute the values used to drive the actual sample rate conversion. + * The following formulas are being computed, using inline assembly + * since we need to use 64 bit arithmetic to compute the values: + * + * coeffIncr = -floor((Fs,out * 2^23) / Fs,in) + * phiIncr = floor((Fs,in * 2^26) / Fs,out) + * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) / + * GOF_PER_SEC) + * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - + * GOF_PER_SEC * correctionPerGOF + * initialDelay = ceil((24 * Fs,in) / Fs,out) + * + * i.e. + * + * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) + * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) + * correctionPerGOF:correctionPerSec = + * dividend:remainder(ulOther / GOF_PER_SEC) + * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) + */ + + tmp1 = rate << 16; + coeffIncr = tmp1 / 48000; + tmp1 -= coeffIncr * 48000; + tmp1 <<= 7; + coeffIncr <<= 7; + coeffIncr += tmp1 / 48000; + coeffIncr ^= 0xFFFFFFFF; + coeffIncr++; + tmp1 = 48000 << 16; + phiIncr = tmp1 / rate; + tmp1 -= phiIncr * rate; + tmp1 <<= 10; + phiIncr <<= 10; + tmp2 = tmp1 / rate; + phiIncr += tmp2; + tmp1 -= tmp2 * rate; + correctionPerGOF = tmp1 / GOF_PER_SEC; + tmp1 -= correctionPerGOF * GOF_PER_SEC; + correctionPerSec = tmp1; + initialDelay = ((48000 * 24) + rate - 1) / rate; + + /* + * Fill in the VariDecimate control block. + */ + spin_lock_irq(&card->lock); + cs461x_poke(card, BA1_CSRC, + ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); + cs461x_poke(card, BA1_CCI, coeffIncr); + cs461x_poke(card, BA1_CD, + (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); + cs461x_poke(card, BA1_CPI, phiIncr); + spin_unlock_irq(&card->lock); + + /* + * Figure out the frame group length for the write back task. Basically, + * this is just the factors of 24000 (2^6*3*5^3) that are not present in + * the output sample rate. + */ + frameGroupLength = 1; + for (cnt = 2; cnt <= 64; cnt *= 2) { + if (((rate / cnt) * cnt) != rate) + frameGroupLength *= 2; + } + if (((rate / 3) * 3) != rate) { + frameGroupLength *= 3; + } + for (cnt = 5; cnt <= 125; cnt *= 5) { + if (((rate / cnt) * cnt) != rate) + frameGroupLength *= 5; + } + + /* + * Fill in the WriteBack control block. + */ + spin_lock_irq(&card->lock); + cs461x_poke(card, BA1_CFG1, frameGroupLength); + cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength)); + cs461x_poke(card, BA1_CCST, 0x0000FFFF); + cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000)); + cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF); + spin_unlock_irq(&card->lock); + dmabuf->rate = rate; + return rate; +} + +/* prepare channel attributes for playback */ +static void cs_play_setup(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int tmp, tmp1; + + tmp1=16; + if (!(dmabuf->fmt & CS_FMT_STEREO)) + tmp1>>=1; + cs461x_poke(card, BA1_PVOL, 0x80008000); + cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf)); + + tmp=cs461x_peek(card, BA1_PDTC); + tmp&=~0x000003FF; + tmp|=tmp1-1; + cs461x_poke(card, BA1_PDTC, tmp); + + tmp=cs461x_peek(card, BA1_PFIE); + tmp&=~0x0000F03F; + if(!(dmabuf->fmt & CS_FMT_STEREO)) + { + tmp|=0x00002000; + } + cs461x_poke(card, BA1_PFIE, tmp); + +} + +/* prepare channel attributes for recording */ +static void cs_rec_setup(struct cs_state *state) +{ + struct cs_card *card = state->card; + struct dmabuf *dmabuf = &state->dmabuf; + /* set the attenuation to 0dB */ + cs461x_poke(card, BA1_CVOL, 0x80008000); + cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->pbuf)); +} + + +/* get current playback/recording dma buffer pointer (byte offset from LBA), + called with spinlock held! */ + +extern __inline__ unsigned cs_get_dma_addr(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u32 offset; + + if (!dmabuf->enable) + return 0; + + offset = dmabuf->pringbuf * 2048; + return offset; +} + +static void resync_dma_ptrs(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + int offset; + + offset = 0; + dmabuf->hwptr=dmabuf->swptr = 0; + dmabuf->ppingbuf = dmabuf->pringbuf = 0; + dmabuf->ppingbuf = 1; + if(dmabuf->fmt&CS_FMT_16BIT) + memset(dmabuf->pbuf, 0, PAGE_SIZE); + else + memset(dmabuf->pbuf, 0x80, PAGE_SIZE); +} + +/* Stop recording (lock held) */ +extern __inline__ void __stop_adc(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int tmp; + + dmabuf->enable &= ~ADC_RUNNING; + + tmp=cs461x_peek(card, BA1_CCTL); + tmp&=0xFFFF; + cs461x_poke(card, BA1_CCTL, tmp); + +} + +static void stop_adc(struct cs_state *state) +{ + struct cs_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_adc(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void start_adc(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned long flags; + unsigned int tmp; + + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + dmabuf->enable |= ADC_RUNNING; + tmp=cs461x_peek(card, BA1_CCTL); + tmp&=0xFFFF; + tmp|=card->cctl; + cs461x_poke(card, BA1_CCTL, tmp); + } + spin_unlock_irqrestore(&card->lock, flags); +} + +/* stop playback (lock held) */ +extern __inline__ void __stop_dac(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned int tmp; + + dmabuf->enable &= ~DAC_RUNNING; + + tmp=cs461x_peek(card, BA1_PCTL); + tmp&=0xFFFF; + cs461x_poke(card, BA1_PCTL, tmp); +} + +static void stop_dac(struct cs_state *state) +{ + struct cs_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __stop_dac(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static void start_dac(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct cs_card *card = state->card; + unsigned long flags; + int tmp; + + spin_lock_irqsave(&card->lock, flags); + if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { + if(!(dmabuf->enable&DAC_RUNNING)) + { + dmabuf->enable |= DAC_RUNNING; + tmp = cs461x_peek(card, BA1_PCTL); + tmp &= 0xFFFF; + tmp |= card->pctl; + cs461x_poke(card, BA1_PCTL, tmp); + } + } + spin_unlock_irqrestore(&card->lock, flags); +} + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +/* allocate DMA buffer, playback and recording buffer should be allocated seperately */ +static int alloc_dmabuf(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + void *rawbuf = NULL; + int order; + struct page *page, *pend; + + /* alloc as big a chunk as we can */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order))) + break; + + if (!rawbuf) + return -ENOMEM; + +#ifdef DEBUG + printk("cs461x: allocated %ld (order = %d) bytes at %p\n", + PAGE_SIZE << order, order, rawbuf); +#endif + + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->rawbuf = rawbuf; + dmabuf->buforder = order; + + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); + for (page = virt_to_page(rawbuf); page <= pend; page++) + mem_map_reserve(page); + + return 0; +} + +/* free DMA buffer */ +static void dealloc_dmabuf(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct page *page, *pend; + + if (dmabuf->rawbuf) { + /* undo marking the pages as reserved */ + pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); + for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) + mem_map_unreserve(page); + pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_handle); + } + dmabuf->rawbuf = NULL; + dmabuf->mapped = dmabuf->ready = 0; +} + +static int prog_dmabuf(struct cs_state *state, unsigned rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned bytepersec; + unsigned bufsize; + unsigned long flags; + int ret; + + spin_lock_irqsave(&state->card->lock, flags); + resync_dma_ptrs(state); + dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + /* allocate DMA buffer if not allocated yet */ + if (!dmabuf->rawbuf) + if ((ret = alloc_dmabuf(state))) + return ret; + + /* FIXME: figure out all this OSS fragment stuff */ + bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; + bufsize = PAGE_SIZE << dmabuf->buforder; + if (dmabuf->ossfragshift) { + if ((1000 << dmabuf->ossfragshift) < bytepersec) + dmabuf->fragshift = ld2(bytepersec/1000); + else + dmabuf->fragshift = dmabuf->ossfragshift; + } else { + /* lets hand out reasonable big ass buffers by default */ + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + } + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { + dmabuf->fragshift--; + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + } + dmabuf->fragsize = 1 << dmabuf->fragshift; + if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) + dmabuf->numfrag = dmabuf->ossmaxfrags; + dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; + dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; + + memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, + dmabuf->dmasize); + + /* + * Now set up the ring + */ + + spin_lock_irqsave(&state->card->lock, flags); + if (rec) { + cs_rec_setup(state); + } else { + cs_play_setup(state); + } + spin_unlock_irqrestore(&state->card->lock, flags); + + /* set the ready flag for the dma buffer */ + dmabuf->ready = 1; + +#ifdef DEBUG + printk("cs461x: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, " + "fragsize = %d dmasize = %d\n", + dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, + dmabuf->fragsize, dmabuf->dmasize); +#endif + + return 0; +} + +static void cs_clear_tail(struct cs_state *state) +{ +} + +static int drain_dac(struct cs_state *state, int nonblock) +{ + DECLARE_WAITQUEUE(wait, current); + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned long tmo; + int count; + + if (dmabuf->mapped || !dmabuf->ready) + return 0; + + add_wait_queue(&dmabuf->wait, &wait); + for (;;) { + /* It seems that we have to set the current state to TASK_INTERRUPTIBLE + every time to make the process really go to sleep */ + current->state = TASK_INTERRUPTIBLE; + + spin_lock_irqsave(&state->card->lock, flags); + count = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (count <= 0) + break; + + if (signal_pending(current)) + break; + + if (nonblock) { + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + + tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; + tmo >>= sample_shift[dmabuf->fmt]; + tmo += (4096*HZ)/dmabuf->rate; + + if (!schedule_timeout(tmo ? tmo : 1) && tmo){ + printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count); + break; + } + } + remove_wait_queue(&dmabuf->wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + + return 0; +} + +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ +static void cs_update_ptr(struct cs_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned hwptr, swptr; + int clear_cnt = 0; + int diff; + unsigned char silence; + + /* update hardware pointer */ + hwptr = cs_get_dma_addr(state); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count -= diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count += diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_adc(state); + dmabuf->error++; + } + else if (!dmabuf->endcleared) { + swptr = dmabuf->swptr; + silence = (dmabuf->fmt & CS_FMT_16BIT ? 0 : 0x80); + if (dmabuf->count < (signed) dmabuf->fragsize) + { + clear_cnt = dmabuf->fragsize; + if ((swptr + clear_cnt) > dmabuf->dmasize) + clear_cnt = dmabuf->dmasize - swptr; + memset (dmabuf->rawbuf + swptr, silence, clear_cnt); + dmabuf->endcleared = 1; + } + } + wake_up(&dmabuf->wait); + } + } + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count += diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count -= diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_dac(state); + dmabuf->error++; + } + wake_up(&dmabuf->wait); + } + } +} + +static void cs_record_interrupt(struct cs_state *state) +{ + memcpy(state->dmabuf.rawbuf + (2048*state->dmabuf.pringbuf++), + state->dmabuf.pbuf+2048*state->dmabuf.ppingbuf++, 2048); + state->dmabuf.ppingbuf&=1; + if(state->dmabuf.pringbuf > (PAGE_SIZE<dmabuf.buforder)/2048) + state->dmabuf.pringbuf=0; + cs_update_ptr(state); +} + +static void cs_play_interrupt(struct cs_state *state) +{ + memcpy(state->dmabuf.pbuf+2048*state->dmabuf.ppingbuf++, + state->dmabuf.rawbuf + (2048*state->dmabuf.pringbuf++), 2048); + state->dmabuf.ppingbuf&=1; + if(state->dmabuf.pringbuf >= (PAGE_SIZE<dmabuf.buforder)/2048) + state->dmabuf.pringbuf=0; + cs_update_ptr(state); +} + +static void cs_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cs_card *card = (struct cs_card *)dev_id; + /* Single channel card */ + struct cs_state *recstate = card->channel[0].state; + struct cs_state *playstate = card->channel[1].state; + u32 status; + + spin_lock(&card->lock); + + status = cs461x_peekBA0(card, BA0_HISR); + + if((status&0x7fffffff)==0) + { + cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); + spin_unlock(&card->lock); + return; + } + + if((status & HISR_VC0) && playstate && playstate->dmabuf.ready) + cs_play_interrupt(playstate); + if((status & HISR_VC1) && recstate && recstate->dmabuf.ready) + cs_record_interrupt(recstate); + + /* clear 'em */ + cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); + spin_unlock(&card->lock); +} + +static loff_t cs_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to + the user's buffer. it is filled by the dma machine and drained by this loop. */ +static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + +#ifdef DEBUG + printk("cs461x: cs_read called, count = %d\n", count); +#endif + + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count > (signed) dmabuf->dmasize) { + /* buffer overrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr, make process flush the buffer */ + dmabuf->count = dmabuf->dmasize; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count < cnt) + cnt = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (cnt > count) + cnt = count; + if (cnt <= 0) { + unsigned long tmo; + /* buffer is empty, start the dma machine and wait for data to be + recorded */ + start_adc(state); + if (file->f_flags & O_NONBLOCK) { + if (!ret) ret = -EAGAIN; + return ret; + } + /* This isnt strictly right for the 810 but it'll do */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer overrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "cs461x: recording schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer overrun, we delay the recovery untill next time the + while loop begin and we REALLY have space to record */ + } + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + return ret; + } + continue; + } + + if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr = swptr; + dmabuf->count -= cnt; + spin_unlock_irqrestore(&state->card->lock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(state); + } + return ret; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to + the soundcard. it is drained by the dma machine and filled by this loop. */ +static ssize_t cs_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + +#ifdef DEBUG + printk("cs461x: cs_write called, count = %d\n", count); +#endif + + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + + while (count > 0) { + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count < 0) { + /* buffer underrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr */ + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + } + swptr = dmabuf->swptr; + cnt = dmabuf->dmasize - swptr; + if (dmabuf->count + cnt > dmabuf->dmasize) + cnt = dmabuf->dmasize - dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + + if (cnt > count) + cnt = count; + if (cnt <= 0) { + unsigned long tmo; + /* buffer is full, start the dma machine and wait for data to be + played */ + start_dac(state); + if (file->f_flags & O_NONBLOCK) { + if (!ret) ret = -EAGAIN; + return ret; + } + /* Not strictly correct but works */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer underrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "cs461x: playback schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, + dmabuf->hwptr, dmabuf->swptr); +#endif + /* a buffer underrun, we delay the recovery untill next time the + while loop begin and we REALLY have data to play */ + } + if (signal_pending(current)) { + if (!ret) ret = -ERESTARTSYS; + return ret; + } + continue; + } + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr = swptr; + dmabuf->count += cnt; + dmabuf->endcleared = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(state); + } + return ret; +} + +static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned int mask = 0; + + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &dmabuf->wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &dmabuf->wait, wait); + + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + if (file->f_mode & FMODE_READ) { + if (dmabuf->count >= (signed)dmabuf->fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (dmabuf->mapped) { + if (dmabuf->count >= (signed)dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&state->card->lock, flags); + + return mask; +} + +static int cs_mmap(struct file *file, struct vm_area_struct *vma) +{ + return -EINVAL; +#if 0 + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + int ret; + unsigned long size; + + + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(state, 0)) != 0) + return ret; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(state, 1)) != 0) + return ret; + } else + return -EINVAL; + + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << dmabuf->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), + size, vma->vm_page_prot)) + return -EAGAIN; + dmabuf->mapped = 1; + + return 0; +#endif +} + +static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + + mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || + ((file->f_mode & FMODE_READ) && dmabuf->mapped); +#ifdef DEBUG + printk("cs461x: cs_ioctl, command = %2d, arg = 0x%08x\n", + _IOC_NR(cmd), arg ? *(int *)arg : 0); +#endif + + switch (cmd) + { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_RESET: + /* FIXME: spin_lock ? */ + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + synchronize_irq(); + dmabuf->ready = 0; + resync_dma_ptrs(state); + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + synchronize_irq(); + resync_dma_ptrs(state); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(state, file->f_flags & O_NONBLOCK); + return 0; + + case SNDCTL_DSP_SPEED: /* set smaple rate */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + cs_set_dac_rate(state, val); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + cs_set_adc_rate(state, val); + } + } + return put_user(dmabuf->rate, (int *)arg); + + case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + if(val) + dmabuf->fmt |= CS_FMT_STEREO; + else + dmabuf->fmt &= ~CS_FMT_STEREO; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + if(val) + { + dmabuf->fmt |= CS_FMT_STEREO; + return put_user(1, (int *)arg); + } +#if 0 + /* Needs extra work to support this */ + + else + dmabuf->fmt &= ~CS_FMT_STEREO; +#endif + } + return 0; + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(state, 0))) + return val; + return put_user(dmabuf->fragsize, (int *)arg); + } + if (file->f_mode & FMODE_READ) { + if ((val = prog_dmabuf(state, 1))) + return val; + return put_user(dmabuf->fragsize, (int *)arg); + } + + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Select sample format */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + if(val==AFMT_S16_LE/* || val==AFMT_U8*/) + { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + } + if(val==AFMT_S16_LE) + dmabuf->fmt |= CS_FMT_16BIT; + else + dmabuf->fmt &= ~CS_FMT_16BIT; + } + } + if(dmabuf->fmt&CS_FMT_16BIT) + return put_user(AFMT_S16_LE, (int *)arg); + else + return put_user(AFMT_U8, (int *)arg); + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dmabuf->ready = 0; + if (val > 1) + dmabuf->fmt |= CS_FMT_STEREO; + else + dmabuf->fmt &= ~CS_FMT_STEREO; + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + } + } + return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1, + (int *)arg); + + case SNDCTL_DSP_POST: + /* FIXME: the same as RESET ?? */ + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if (dmabuf->subdivision) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2) + return -EINVAL; + dmabuf->subdivision = val; + return 0; + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + + dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossmaxfrags = (val >> 16) & 0xffff; + switch(dmabuf->ossmaxfrags) + { + case 1: + dmabuf->ossfragshift=12; + return 0; + default: + /* Fragments must be 2K long */ + dmabuf->ossfragshift = 11; + dmabuf->ossmaxfrags=2; + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, + (int *)arg); + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && dmabuf->enable) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && dmabuf->enable) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + start_adc(state); + } else + stop_adc(state); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + start_dac(state); + } else + stop_dac(state); + } + return 0; + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; + spin_unlock_irqrestore(&state->card->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_SETDUPLEX: + return -EINVAL; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + cs_update_ptr(state); + val = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + return put_user(val, (int *)arg); + + case SOUND_PCM_READ_RATE: + return put_user(dmabuf->rate, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1, + (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user(AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + return -EINVAL; +} + + +/* + * AMP control - null AMP + */ + +static void amp_none(struct cs_card *card, int change) +{ +} + +/* + * Crystal EAPD mode + */ + +static void amp_voyetra(struct cs_card *card, int change) +{ + /* Manage the EAPD bit on the Crystal 4297 */ + int old=card->amplifier; + + card->amplifier+=change; + if(card->amplifier && !old) + { + /* Turn the EAPD amp on */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, + cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) | + 0x8000); + } + else if(old && !card->amplifier) + { + /* Turn the EAPD amp off */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, + cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & + ~0x8000); + } +} + + + +/* + * Untested + */ +#if 0 +static void amp_voyetra_4294(struct cs_card *card, int change) +{ + struct ac97_codec *c=card->ac97_codec[0]; + int old = card->amplifier; + + card->amplifier+=change; + + if(card->amplifier) + { + /* Switch the GPIO pins 7 and 8 to open drain */ + cs_ac97_set(c, 0x4C, cs_ac97_get(c, 0x4C) & 0xFE7F); + cs_ac97_set(c, 0x4E, cs_ac97_get(c, 0x4E) | 0x0180); + /* Now wake the AMP (this might be backwards) */ + cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) & ~0x0180); + } + else + { + cs_ac97_set(c, 0x54, cs_ac97_get(c, 0x54) | 0x0180); + } +} +#endif + +/* + * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support + * whenever we need to beat on the chip. + * + * The original idea and code for this hack comes from David Kaiser at + * Linuxcare. Perhaps one day Crystal will document their chips well + * enough to make them useful. + */ + +static void clkrun_hack(struct cs_card *card, int change) +{ + struct pci_dev *acpi_dev; + u16 control; + u8 pp; + unsigned long port; + int old=card->amplifier; + + card->amplifier += change; + + acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if(acpi_dev == NULL) + return; /* Not a thinkpad thats for sure */ + + + /* Find the control port */ + pci_read_config_byte(acpi_dev, 0x41, &pp); + port = pp<<8; + + /* Read ACPI port */ + control = inw(port+0x10); + + /* Flip CLKRUN off while running */ + if(!card->amplifier && old) + outw(control|0x2000, port+0x10); + else if(card->amplifier && !old) + outw(control&~0x2000, port+0x10); +} + + +static int cs_open(struct inode *inode, struct file *file) +{ + int i = 0; + struct cs_card *card = devs; + struct cs_state *state = NULL; + struct dmabuf *dmabuf = NULL; + +#ifndef CS46XX_ENABLE_RECORD + if (file->f_mode & FMODE_READ) + return -ENODEV; +#endif + + /* find an avaiable virtual channel (instance of /dev/dsp) */ + while (card != NULL) { + for (i = 0; i < NR_HW_CH; i++) { + if (card->states[i] == NULL) { + state = card->states[i] = (struct cs_state *) + kmalloc(sizeof(struct cs_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + memset(state, 0, sizeof(struct cs_state)); + dmabuf = &state->dmabuf; + dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL); + if(dmabuf->pbuf==NULL) + { + kfree(state); + card->states[i]=NULL; + return -ENOMEM; + } + goto found_virt; + } + } + card = card->next; + } + /* no more virtual channel avaiable */ + if (!state) + return -ENODEV; + + found_virt: + /* found a free virtual channel, allocate hardware channels */ + if(file->f_mode & FMODE_READ) + dmabuf->channel = card->alloc_rec_pcm_channel(card); + else + dmabuf->channel = card->alloc_pcm_channel(card); + + if (dmabuf->channel == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } + + /* Now turn on external AMP if needed */ + state->card = card; + state->card->active_ctrl(state->card,1); + state->card->amplifier_ctrl(state->card,1); + + dmabuf->channel->state = state; + /* initialize the virtual channel */ + state->virt = i; + state->magic = CS_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + file->private_data = state; + + down(&state->open_sem); + + /* set default sample format. According to OSS Programmer's Guide /dev/dsp + should be default to unsigned 8-bits, mono, with sample rate 8kHz and + /dev/dspW will accept 16-bits sample */ + if (file->f_mode & FMODE_WRITE) { + /* Output is 16bit only mono or stereo */ + dmabuf->fmt &= ~CS_FMT_MASK; + dmabuf->fmt |= CS_FMT_16BIT; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + cs_set_dac_rate(state, 8000); + } + + if (file->f_mode & FMODE_READ) { + /* Input is 16bit stereo only */ + dmabuf->fmt &= ~CS_FMT_MASK; + dmabuf->fmt |= CS_FMT_16BIT|CS_FMT_STEREO; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + cs_set_adc_rate(state, 8000); + } + + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&state->open_sem); + + + MOD_INC_USE_COUNT; + return 0; +} + +static int cs_release(struct inode *inode, struct file *file) +{ + struct cs_state *state = (struct cs_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + + if (file->f_mode & FMODE_WRITE) { + /* FIXME :.. */ + cs_clear_tail(state); + drain_dac(state, file->f_flags & O_NONBLOCK); + } + + /* stop DMA state machine and free DMA buffers/channels */ + down(&state->open_sem); + + if (file->f_mode & FMODE_WRITE) { + stop_dac(state); + dealloc_dmabuf(state); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dealloc_dmabuf(state); + state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + + free_page((unsigned long)state->dmabuf.pbuf); + + /* we're covered by the open_sem */ + up(&state->open_sem); + state->card->states[state->virt] = NULL; + state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + + /* Now turn off external AMP if needed */ + state->card->amplifier_ctrl(state->card, -1); + state->card->active_ctrl(state->card, -1); + + kfree(state); + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations cs461x_fops = { + llseek: cs_llseek, + read: cs_read, + write: cs_write, + poll: cs_poll, + ioctl: cs_ioctl, + mmap: cs_mmap, + open: cs_open, + release: cs_release, +}; + +/* Write AC97 codec registers */ + + +static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct cs_card *card = dev->private_data; + int count; + + /* + * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address + * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 + * 3. Write ACCTL = Control Register = 460h for initiating the write + * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h + * 5. if DCV not cleared, break and return error + * 6. Read ACSTS = Status Register = 464h, check VSTS bit + */ + + + cs461x_peekBA0(card, BA0_ACSDA); + + /* + * Setup the AC97 control registers on the CS461x to send the + * appropriate command to the AC97 to perform the read. + * ACCAD = Command Address Register = 46Ch + * ACCDA = Command Data Register = 470h + * ACCTL = Control Register = 460h + * set DCV - will clear when process completed + * set CRW - Read command + * set VFRM - valid frame enabled + * set ESYN - ASYNC generation enabled + * set RSTN - ARST# inactive, AC97 codec not reset + */ + + cs461x_pokeBA0(card, BA0_ACCAD, reg); + cs461x_pokeBA0(card, BA0_ACCDA, 0); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | + ACCTL_VFRM | ACCTL_ESYN | + ACCTL_RSTN); + + + /* + * Wait for the read to occur. + */ + for (count = 0; count < 500; count++) { + /* + * First, we want to wait for a short time. + */ + udelay(10); + /* + * Now, check to see if the read has completed. + * ACCTL = 460h, DCV should be reset by now and 460h = 17h + */ + if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) + break; + } + + /* + * Make sure the read completed. + */ + if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) { + printk(KERN_WARNING "cs461x: AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); + return 0xffff; + } + + /* + * Wait for the valid status bit to go active. + */ + for (count = 0; count < 100; count++) { + /* + * Read the AC97 status register. + * ACSTS = Status Register = 464h + * VSTS - Valid Status + */ + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS) + break; + udelay(10); + } + + /* + * Make sure we got valid status. + */ + if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)) { + printk(KERN_WARNING "cs461x: AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg); + return 0xffff; + } + + /* + * Read the data returned from the AC97 register. + * ACSDA = Status Data Register = 474h + */ +#if 0 + printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg, + cs461x_peekBA0(card, BA0_ACSDA), + cs461x_peekBA0(card, BA0_ACCAD)); +#endif + return cs461x_peekBA0(card, BA0_ACSDA); +} + +static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) +{ + struct cs_card *card = dev->private_data; + int count; + + /* + * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address + * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 + * 3. Write ACCTL = Control Register = 460h for initiating the write + * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h + * 5. if DCV not cleared, break and return error + */ + + /* + * Setup the AC97 control registers on the CS461x to send the + * appropriate command to the AC97 to perform the read. + * ACCAD = Command Address Register = 46Ch + * ACCDA = Command Data Register = 470h + * ACCTL = Control Register = 460h + * set DCV - will clear when process completed + * reset CRW - Write command + * set VFRM - valid frame enabled + * set ESYN - ASYNC generation enabled + * set RSTN - ARST# inactive, AC97 codec not reset + */ + cs461x_pokeBA0(card, BA0_ACCAD, reg); + cs461x_pokeBA0(card, BA0_ACCDA, val); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM | + ACCTL_ESYN | ACCTL_RSTN); + for (count = 0; count < 1000; count++) { + /* + * First, we want to wait for a short time. + */ + udelay(10); + /* + * Now, check to see if the write has completed. + * ACCTL = 460h, DCV should be reset by now and 460h = 07h + */ + if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)) + break; + } + /* + * Make sure the write completed. + */ + if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) + printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val); +} + + +/* OSS /dev/mixer file operation methods */ + +static int cs_open_mixdev(struct inode *inode, struct file *file) +{ + int i; + int minor = MINOR(inode->i_rdev); + struct cs_card *card = devs; + + for (card = devs; card != NULL; card = card->next) + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL && + card->ac97_codec[i]->dev_mixer == minor) + goto match; + + if (!card) + return -ENODEV; + + match: + file->private_data = card->ac97_codec[i]; + + card->active_ctrl(card,1); + MOD_INC_USE_COUNT; + return 0; +} + +static int cs_release_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs_card *card = devs; + int i; + + for (card = devs; card != NULL; card = card->next) + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL && + card->ac97_codec[i]->dev_mixer == minor) + goto match; + + if (!card) + return -ENODEV; +match: + card->active_ctrl(card, -1); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const*/ struct file_operations cs_mixer_fops = { + llseek: cs_llseek, + ioctl: cs_ioctl_mixdev, + open: cs_open_mixdev, + release: cs_release_mixdev, +}; + +/* AC97 codec initialisation. */ +static int __init cs_ac97_init(struct cs_card *card) +{ + int num_ac97 = 0; + int ready_2nd = 0; + struct ac97_codec *codec; + u16 eid; + + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct ac97_codec)); + + /* initialize some basic codec information, other fields will be filled + in ac97_probe_codec */ + codec->private_data = card; + codec->id = num_ac97; + + codec->codec_read = cs_ac97_get; + codec->codec_write = cs_ac97_set; + + if (ac97_probe_codec(codec) == 0) + break; + + eid = cs_ac97_get(codec, AC97_EXTENDED_ID); + + if(eid==0xFFFFFF) + { + printk(KERN_WARNING "cs461x: no codec attached ?\n"); + kfree(codec); + break; + } + + card->ac97_features = eid; + + + if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) { + printk(KERN_ERR "cs461x: couldn't register mixer!\n"); + kfree(codec); + break; + } + + card->ac97_codec[num_ac97] = codec; + + /* if there is no secondary codec at all, don't probe any more */ + if (!ready_2nd) + return num_ac97+1; + } + return num_ac97; +} + +/* Boot the card + */ + +static void cs461x_download(struct cs_card *card, u32 *src, unsigned long offset, unsigned long len) +{ + unsigned long counter; + void *dst; + + dst = card->ba1.idx[(offset>>16)&3]; + dst += (offset&0xFFFF)<<2; + for(counter=0;counter> 2; + } +} + +/* + * Chip reset + */ + +static void cs461x_reset(struct cs_card *card) +{ + int idx; + + /* + * Write the reset bit of the SP control register. + */ + cs461x_poke(card, BA1_SPCR, SPCR_RSTSP); + + /* + * Write the control register. + */ + cs461x_poke(card, BA1_SPCR, SPCR_DRQEN); + + /* + * Clear the trap registers. + */ + for (idx = 0; idx < 8; idx++) { + cs461x_poke(card, BA1_DREG, DREG_REGID_TRAP_SELECT + idx); + cs461x_poke(card, BA1_TWPR, 0xFFFF); + } + cs461x_poke(card, BA1_DREG, 0); + + /* + * Set the frame timer to reflect the number of cycles per frame. + */ + cs461x_poke(card, BA1_FRMT, 0xadf); +} + +static void cs461x_clear_serial_FIFOs(struct cs_card *card) +{ + int idx, loop, powerdown = 0; + unsigned int tmp; + + /* + * See if the devices are powered down. If so, we must power them up first + * or they will not respond. + */ + if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) { + cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE); + powerdown = 1; + } + + /* + * We want to clear out the serial port FIFOs so we don't end up playing + * whatever random garbage happens to be in them. We fill the sample FIFOS + * with zero (silence). + */ + cs461x_pokeBA0(card, BA0_SERBWP, 0); + + /* + * Fill all 256 sample FIFO locations. + */ + for (idx = 0; idx < 256; idx++) { + /* + * Make sure the previous FIFO write operation has completed. + */ + for (loop = 0; loop < 5; loop++) { + udelay(50); + if (!(cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY)) + break; + } + if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) { + if (powerdown) + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + } + /* + * Write the serial port FIFO index. + */ + cs461x_pokeBA0(card, BA0_SERBAD, idx); + /* + * Tell the serial port to load the new value into the FIFO location. + */ + cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC); + } + /* + * Now, if we powered up the devices, then power them back down again. + * This is kinda ugly, but should never happen. + */ + if (powerdown) + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); +} + +static void cs461x_powerup_dac(struct cs_card *card) +{ + int count; + unsigned int tmp; + + /* + * Power on the DACs on the AC97 card. We turn off the DAC + * powerdown bit and write the new value of the power control + * register. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & 2) /* already */ + return; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfdff); + + /* + * Now, we wait until we sample a DAC ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(50); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 2)) + printk(KERN_WARNING "cs461x: powerup DAC failed\n"); +} + +static void cs461x_powerup_adc(struct cs_card *card) +{ + int count; + unsigned int tmp; + + /* + * Power on the ADCs on the AC97 card. We turn off the DAC + * powerdown bit and write the new value of the power control + * register. + */ + tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL); + if (tmp & 1) /* already */ + return; + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp & 0xfeff); + + /* + * Now, we wait until we sample a ADC ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(50); + + /* + * Read the current state of the power control register. + */ + if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1) + break; + } + + /* + * Check the status.. + */ + if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) & 1)) + printk(KERN_WARNING "cs461x: powerup ADC failed\n"); +} + +static void cs461x_proc_start(struct cs_card *card) +{ + int cnt; + + /* + * Set the frame timer to reflect the number of cycles per frame. + */ + cs461x_poke(card, BA1_FRMT, 0xadf); + /* + * Turn on the run, run at frame, and DMA enable bits in the local copy of + * the SP control register. + */ + cs461x_poke(card, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN); + /* + * Wait until the run at frame bit resets itself in the SP control + * register. + */ + for (cnt = 0; cnt < 25; cnt++) { + udelay(50); + if (!(cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)) + break; + } + + if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR) + printk(KERN_WARNING "cs461x: SPCR_RUNFR never reset\n"); +} + +static void cs461x_proc_stop(struct cs_card *card) +{ + /* + * Turn off the run, run at frame, and DMA enable bits in the local copy of + * the SP control register. + */ + cs461x_poke(card, BA1_SPCR, 0); +} + + + +static int cs_hardware_init(struct cs_card *card) +{ + unsigned long end_time; + unsigned int tmp; + + /* + * First, blast the clock control register to zero so that the PLL starts + * out in a known state, and blast the master serial port control register + * to zero so that the serial ports also start out in a known state. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, 0); + cs461x_pokeBA0(card, BA0_SERMC1, 0); + + /* + * If we are in AC97 mode, then we must set the part to a host controlled + * AC-link. Otherwise, we won't be able to bring up the link. + */ + cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 card */ + /* cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); */ /* 2.00 card */ + + /* + * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97 + * spec) and then drive it high. This is done for non AC97 modes since + * there might be logic external to the CS461x that uses the ARST# line + * for a reset. + */ + cs461x_pokeBA0(card, BA0_ACCTL, 0); + udelay(500); + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN); + + /* + * The first thing we do here is to enable sync generation. As soon + * as we start receiving bit clock, we'll start producing the SYNC + * signal. + */ + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN); + + /* + * Now wait for a short while to allow the AC97 part to start + * generating bit clock (so we don't try to start the PLL without an + * input clock). + */ + mdelay(10); /* 1 should be enough ?? */ + + /* + * Set the serial port timing configuration, so that + * the clock control circuit gets its clock from the correct place. + */ + cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97); + + /* + * Write the selected clock control setup to the hardware. Do not turn on + * SWCE yet (if requested), so that the devices clocked by the output of + * PLL are not clocked until the PLL is stable. + */ + cs461x_pokeBA0(card, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ); + cs461x_pokeBA0(card, BA0_PLLM, 0x3a); + cs461x_pokeBA0(card, BA0_CLKCR2, CLKCR2_PDIVS_8); + + /* + * Power up the PLL. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, CLKCR1_PLLP); + + /* + * Wait until the PLL has stabilized. + */ + mdelay(100); /* Again 1 should be enough ?? */ + + /* + * Turn on clocking of the core so that we can setup the serial ports. + */ + tmp = cs461x_peekBA0(card, BA0_CLKCR1) | CLKCR1_SWCE; + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + + /* + * Fill the serial port FIFOs with silence. + */ + cs461x_clear_serial_FIFOs(card); + + /* + * Set the serial port FIFO pointer to the first sample in the FIFO. + */ + /* cs461x_pokeBA0(card, BA0_SERBSP, 0); */ + + /* + * Write the serial port configuration to the part. The master + * enable bit is not set until all other values have been written. + */ + cs461x_pokeBA0(card, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN); + cs461x_pokeBA0(card, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN); + cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE); + + + mdelay(5); /* Shouldnt be needed ?? */ + + /* + * Wait for the card ready signal from the AC97 card. + */ + end_time = jiffies + 3 * (HZ >> 2); + do { + /* + * Read the AC97 status register to see if we've seen a CODEC READY + * signal from the AC97 card. + */ + if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + + /* + * Make sure CODEC is READY. + */ + if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) { + printk(KERN_WARNING "cs461x: create - never read card ready from AC'97\n"); + printk(KERN_WARNING "cs461x: it is probably not a bug, try using the CS4232 driver\n"); + return -EIO; + } + + /* + * Assert the vaid frame signal so that we can start sending commands + * to the AC97 card. + */ + cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN); + + /* + * Wait until we've sampled input slots 3 and 4 as valid, meaning that + * the card is pumping ADC data across the AC-link. + */ + end_time = jiffies + 3 * (HZ >> 2); + do { + /* + * Read the input slot valid register and see if input slots 3 and + * 4 are valid yet. + */ + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4)) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } while (time_before(jiffies, end_time)); + + /* + * Make sure input slots 3 and 4 are valid. If not, then return + * an error. + */ + if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) { + printk(KERN_WARNING "cs461x: create - never read ISV3 & ISV4 from AC'97\n"); + return -EIO; + } + + /* + * Now, assert valid frame and the slot 3 and 4 valid bits. This will + * commense the transfer of digital audio data to the AC97 card. + */ + cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4); + + /* + * Power down the DAC and ADC. We will power them up (if) when we need + * them. + */ + /* cs461x_pokeBA0(card, BA0_AC97_POWERDOWN, 0x300); */ + + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + /* tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; */ + /* cs461x_pokeBA0(card, BA0_CLKCR1, tmp); */ + + /* + * Reset the processor. + */ + cs461x_reset(card); + + /* + * Download the image to the processor. + */ + + cs461x_download_image(card); + + /* + * Stop playback DMA. + */ + tmp = cs461x_peek(card, BA1_PCTL); + card->pctl = tmp & 0xffff0000; + cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff); + + /* + * Stop capture DMA. + */ + tmp = cs461x_peek(card, BA1_CCTL); + card->cctl = tmp & 0x0000ffff; + cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); + + /* initialize AC97 codec and register /dev/mixer */ + if (cs_ac97_init(card) <= 0) + return -EIO; + + mdelay(5); /* Do we need this ?? */ + + cs461x_powerup_adc(card); + cs461x_powerup_dac(card); + + cs461x_proc_start(card); + + /* + * Enable interrupts on the part. + */ + cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); + + tmp = cs461x_peek(card, BA1_PFIE); + tmp &= ~0x0000f03f; + cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt enable */ + + tmp = cs461x_peek(card, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000001; + cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */ + return 0; +} + +/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered + until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + + +/* + * Card subid table + */ + +struct cs_card_type +{ + u16 vendor; + u16 id; + char *name; + void (*amp)(struct cs_card *, int); + void (*active)(struct cs_card *, int); +}; + +static struct cs_card_type __init cards[]={ + {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL}, + {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL}, + /* MI6020/21 use the same chipset as the Thinkpads, maybe needed */ + {0x1071, 0x6003, "Mitac MI6020/21", amp_none, clkrun_hack}, + /* Not sure if the 570 needs the clkrun hack */ + {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack}, + {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL}, + {0, 0, NULL, NULL} +}; + +static int __init cs_install(struct pci_dev *pci_dev) +{ + struct cs_card *card; + struct cs_card_type *cp = &cards[0]; + u16 ss_card, ss_vendor; + + + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor); + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card); + + if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "cs461x: out of memory\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(*card)); + + card->ba0_addr = pci_dev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK; + card->ba1_addr = pci_dev->resource[1].start&PCI_BASE_ADDRESS_MEM_MASK; + card->pci_dev = pci_dev; + card->irq = pci_dev->irq; + card->magic = CS_CARD_MAGIC; + spin_lock_init(&card->lock); + + pci_set_master(pci_dev); + + printk(KERN_INFO "cs461x: Card found at 0x%08lx and 0x%08lx, IRQ %d\n", + card->ba0_addr, card->ba1_addr, card->irq); + + card->alloc_pcm_channel = cs_alloc_pcm_channel; + card->alloc_rec_pcm_channel = cs_alloc_rec_pcm_channel; + card->free_pcm_channel = cs_free_pcm_channel; + card->amplifier_ctrl = amp_none; + card->active_ctrl = amp_none; + + while(cp->name) + { + if(cp->vendor == ss_vendor && cp->id == ss_card) + { + card->amplifier_ctrl = cp->amp; + if(cp->active) + card->active_ctrl = cp->active; + break; + } + cp++; + } + if(cp->name==NULL) + { + printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n", + ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq); + } + else + { + printk(KERN_INFO "cs461x: %s at 0x%08lx/0x%08lx, IRQ %d\n", + cp->name, card->ba0_addr, card->ba1_addr, card->irq); + } + + if(card->amplifier_ctrl==NULL) + { + printk(KERN_ERR "cs461x: Unsupported configuration due to lack of documentation.\n"); + kfree(card); + return -EINVAL; + } + + if(external_amp == 1) + { + printk(KERN_INFO "cs461x: Crystal EAPD support forced on.\n"); + card->amplifier_ctrl = amp_voyetra; + } + + if(thinkpad == 1) + { + card->active_ctrl = clkrun_hack; + printk(KERN_INFO "cs461x: Activating CLKRUN hack for Thinkpad.\n"); + } + + card->active_ctrl(card, 1); + + /* claim our iospace and irq */ + + card->ba0 = ioremap(card->ba0_addr, CS461X_BA0_SIZE); + card->ba1.name.data0 = ioremap(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE); + card->ba1.name.data1 = ioremap(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE); + card->ba1.name.pmem = ioremap(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE); + card->ba1.name.reg = ioremap(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE); + + if(card->ba0 == 0 || card->ba1.name.data0 == 0 || + card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 || + card->ba1.name.reg == 0) + goto fail2; + + if (request_irq(card->irq, &cs_interrupt, SA_SHIRQ, "cs461x", card)) { + printk(KERN_ERR "cs461x: unable to allocate irq %d\n", card->irq); + goto fail2; + } + /* register /dev/dsp */ + if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) { + printk(KERN_ERR "cs461x: unable to register dsp\n"); + goto fail; + } + + if (cs_hardware_init(card)<0) + { + unregister_sound_dsp(card->dev_audio); + goto fail; + } + card->next = devs; + devs = card; + + card->active_ctrl(card, -1); + return 0; + +fail: + free_irq(card->irq, card); +fail2: + if(card->ba0) + iounmap(card->ba0); + if(card->ba1.name.data0) + iounmap(card->ba1.name.data0); + if(card->ba1.name.data1) + iounmap(card->ba1.name.data1); + if(card->ba1.name.pmem) + iounmap(card->ba1.name.pmem); + if(card->ba1.name.reg) + iounmap(card->ba1.name.reg); + kfree(card); + return -ENODEV; + +} + +static void cs_remove(struct cs_card *card) +{ + int i; + unsigned int tmp; + + card->active_ctrl(card,1); + + tmp = cs461x_peek(card, BA1_PFIE); + tmp &= ~0x0000f03f; + tmp |= 0x00000010; + cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */ + + tmp = cs461x_peek(card, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000011; + cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */ + + /* + * Stop playback DMA. + */ + tmp = cs461x_peek(card, BA1_PCTL); + cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff); + + /* + * Stop capture DMA. + */ + tmp = cs461x_peek(card, BA1_CCTL); + cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000); + + /* + * Reset the processor. + */ + cs461x_reset(card); + + cs461x_proc_stop(card); + + /* + * Power down the DAC and ADC. We will power them up (if) when we need + * them. + */ + cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x300); + + /* + * Power down the PLL. + */ + cs461x_pokeBA0(card, BA0_CLKCR1, 0); + + /* + * Turn off the Processor by turning off the software clock enable flag in + * the clock control register. + */ + tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; + cs461x_pokeBA0(card, BA0_CLKCR1, tmp); + + card->active_ctrl(card,-1); + + /* free hardware resources */ + free_irq(card->irq, card); + iounmap(card->ba0); + iounmap(card->ba1.name.data0); + iounmap(card->ba1.name.data1); + iounmap(card->ba1.name.pmem); + iounmap(card->ba1.name.reg); + + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree (card->ac97_codec[i]); + } + unregister_sound_dsp(card->dev_audio); + kfree(card); +} + +MODULE_AUTHOR("Alan Cox , Jaroslav Kysela"); +MODULE_DESCRIPTION("Crystal SoundFusion Audio Support"); + +int __init cs_probe(void) +{ + struct pci_dev *pcidev = NULL; + int foundone=0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + + printk(KERN_INFO "Crystal 4280/461x + AC97 Audio, version " + DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) { + if (cs_install(pcidev)==0) + foundone++; + } + while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) { + if (cs_install(pcidev)==0) + foundone++; + } + while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) { + if (cs_install(pcidev)==0) + foundone++; + } + + printk(KERN_INFO "cs461x: Found %d audio device(s).\n", + foundone); + return foundone; +} + +#ifdef MODULE + +int init_module(void) +{ + if(cs_probe()==0) + printk(KERN_ERR "cs461x: No devices found.\n"); + return 0; +} + +void cleanup_module (void) +{ + struct cs_card *next; + while(devs) + { + next=devs->next; + cs_remove(devs); + devs=next; + } +} + +MODULE_PARM(external_amp, "i"); +MODULE_PARM(thinkpad, "i"); + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.4.0-test6/linux/drivers/sound/dev_table.h Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/dev_table.h Fri Aug 11 08:26:43 2000 @@ -160,6 +160,7 @@ struct audio_driver { + struct module *owner; int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, @@ -239,6 +240,7 @@ struct mixer_operations { + struct module *owner; char id[16]; char name[64]; int (*ioctl) (int dev, unsigned int cmd, caddr_t arg); @@ -249,6 +251,7 @@ struct synth_operations { + struct module *owner; char *id; /* Unique identifier (ASCII) max 29 char */ struct synth_info *info; int midi_dev; @@ -301,6 +304,7 @@ struct midi_operations { + struct module *owner; struct midi_info info; struct synth_operations *converter; struct midi_input_info in_info; @@ -332,6 +336,7 @@ struct sound_timer_operations { + struct module *owner; struct sound_timer_info info; int priority; int devlink; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/8010.h linux/drivers/sound/emu10k1/8010.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/8010.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/8010.h Mon Aug 14 08:32:48 2000 @@ -37,18 +37,23 @@ #ifndef _8010_H #define _8010_H -/* ------------------- DEFINES -------------------- */ - -#define EMUPAGESIZE 4096 /* don't change */ -#define RESERVED 0 -#define NUM_G 64 /* use all channels */ -#define NUM_FXSENDS 4 /* don't change */ -#define MAXPAGES (32768 * NUM_G / EMUPAGESIZE) /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */ +#include -#define TMEMSIZE 256*1024 -#define TMEMSIZEREG 4 +/* ------------------- DEFINES -------------------- */ -#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) +#define CMD_WRITEFN0 0x0 +#define CMD_READFN0 0x1 +#define CMD_WRITEPTR 0x2 +#define CMD_READPTR 0x3 +#define CMD_SETRECSRC 0x4 +#define CMD_GETRECSRC 0x5 +#define CMD_GETVOICEPARAM 0x6 +#define CMD_SETVOICEPARAM 0x7 + +struct mixer_private_ioctl { + u32 cmd; + u32 val[10]; +}; /************************************************************************************************/ /* PCI function 0 registers, address = + PCIBASE0 */ @@ -174,14 +179,16 @@ #define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */ #define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */ #define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */ +#define HCFG_AC3ENABLE_GPSPDIF 0x00000020 /* Channels 0 and 1 replace GPSPDIF */ #define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */ /* will automatically mute their output when */ /* they are not rate-locked to the external */ /* async audio source */ #define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ /* NOTE: This should generally never be used. */ -#define HCFG_LOCKTANKCACHE 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ +#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ /* NOTE: This should generally never be used. */ +#define HCFG_LOCKTANKCACHE 0x01020014 #define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */ /* NOTE: This is a 'cheap' way to implement a */ /* master mute function on the mute button, and */ @@ -256,7 +263,7 @@ #define AC97_RECORDSELECT 0x1a #define AC97_RECORDGAIN 0x1c #define AC97_RECORDGAINMIC 0x1e -#define AC97_GENERALPUPOSE 0x20 +#define AC97_GENERALPURPOSE 0x20 #define AC97_3DCONTROL 0x22 #define AC97_MODEMRATE 0x24 #define AC97_POWERDOWN 0x26 @@ -335,10 +342,12 @@ #define CCCA_CURRADDR 0x18000008 #define CCR 0x09 /* Cache control register */ -#define CCR_CACHEINVALIDSIZE 0xfe000000 /* Number of invalid samples cache for this channel */ +#define CCR_CACHEINVALIDSIZE 0x07190009 +#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ #define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ #define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ #define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ +#define CCR_READADDRESS 0x06100009 #define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */ #define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ /* NOTE: This is valid only if CACHELOOPFLAG is set */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/Makefile linux/drivers/sound/emu10k1/Makefile --- v2.4.0-test6/linux/drivers/sound/emu10k1/Makefile Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/Makefile Mon Aug 14 08:32:48 2000 @@ -4,20 +4,18 @@ ifeq ($(CONFIG_SOUND_EMU10K1),y) O_TARGET := emu10k1.o - O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \ emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ - osutils.o recmgr.o timer.o voicemgr.o + recmgr.o timer.o voicemgr.o else ifeq ($(CONFIG_SOUND_EMU10K1),m) M_OBJS := emu10k1.o O_TARGET := emu10k1.o - O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \ + O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \ emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \ - osutils.o recmgr.o timer.o voicemgr.o + recmgr.o timer.o voicemgr.o endif endif - -EXTRA_CFLAGS += -I. ifdef DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/audio.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/emu10k1/audio.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * audio.c -- /dev/dsp interface for emu10k1 driver @@ -31,20 +30,30 @@ ********************************************************************** */ +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + #include "hwaccess.h" #include "cardwo.h" #include "cardwi.h" #include "recmgr.h" +#include "irqmgr.h" #include "audio.h" -#include -#include -#include static void calculate_ofrag(struct woinst *); static void calculate_ifrag(struct wiinst *); /* Audio file operations */ -static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin) +static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } @@ -53,11 +62,10 @@ { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in; ssize_t ret = 0; unsigned long flags; - DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count); + DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count); if (ppos != &file->f_pos) return -ESPIPE; @@ -67,23 +75,21 @@ spin_lock_irqsave(&wiinst->lock, flags); - if (wiinst->mapped) { + if (wiinst->mmapped) { spin_unlock_irqrestore(&wiinst->lock, flags); return -ENXIO; } - if (!wiinst->wave_in) { + if (wiinst->state == WAVE_STATE_CLOSED) { calculate_ifrag(wiinst); - while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + while (emu10k1_wavein_open(wave_dev) < 0) { spin_unlock_irqrestore(&wiinst->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&wave_dev->card->open_wait); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return -ERESTARTSYS; @@ -92,26 +98,25 @@ } } - wave_in = wiinst->wave_in; - spin_unlock_irqrestore(&wiinst->lock, flags); while (count > 0) { - u32 bytestocopy, dummy; + u32 bytestocopy; spin_lock_irqsave(&wiinst->lock, flags); - if ((wave_in->state != CARDWAVE_STATE_STARTED) + if (!(wiinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_INPUT)) emu10k1_wavein_start(wave_dev); - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); + emu10k1_wavein_update(wave_dev->card, wiinst); + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(4, "bytestocopy --> %x\n", bytestocopy); + DPD(3, "bytestocopy --> %d\n", bytestocopy); - if ((bytestocopy >= wiinst->fragment_size) + if ((bytestocopy >= wiinst->buffer.fragment_size) || (bytestocopy >= count)) { bytestocopy = min(bytestocopy, count); @@ -127,9 +132,7 @@ || (!(wave_dev->enablebits & PCM_ENABLE_INPUT))) return (ret ? ret : -EAGAIN); - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&wiinst->wait_queue); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return (ret ? ret : -ERESTARTSYS); @@ -137,7 +140,7 @@ } } - DPD(4, "bytes copied -> %x\n", (u32) ret); + DPD(3, "bytes copied -> %d\n", (u32) ret); return ret; } @@ -146,13 +149,10 @@ { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; ssize_t ret; unsigned long flags; - GET_INODE_STRUCT(); - - DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count); + DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count); if (ppos != &file->f_pos) return -ESPIPE; @@ -162,23 +162,21 @@ spin_lock_irqsave(&woinst->lock, flags); - if (woinst->mapped) { + if (woinst->mmapped) { spin_unlock_irqrestore(&woinst->lock, flags); return -ENXIO; } - if (!woinst->wave_out) { + if (woinst->state == WAVE_STATE_CLOSED) { calculate_ofrag(woinst); - while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + while (emu10k1_waveout_open(wave_dev) < 0) { spin_unlock_irqrestore(&woinst->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&wave_dev->card->open_wait); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return -ERESTARTSYS; @@ -187,23 +185,20 @@ } } - wave_out = woinst->wave_out; - spin_unlock_irqrestore(&woinst->lock, flags); ret = 0; while (count > 0) { - u32 bytestocopy, pending, dummy; + u32 bytestocopy; spin_lock_irqsave(&woinst->lock, flags); - - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); spin_unlock_irqrestore(&woinst->lock, flags); - DPD(4, "bytestocopy --> %x\n", bytestocopy); + DPD(3, "bytestocopy --> %d\n", bytestocopy); - if ((bytestocopy >= woinst->fragment_size) + if ((bytestocopy >= woinst->buffer.fragment_size) || (bytestocopy >= count)) { bytestocopy = min(bytestocopy, count); @@ -217,16 +212,11 @@ spin_lock_irqsave(&woinst->lock, flags); woinst->total_copied += bytestocopy; - if ((wave_out->state != CARDWAVE_STATE_STARTED) + if (!(woinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) - && (woinst->total_copied >= woinst->fragment_size)) { + && (woinst->total_copied >= woinst->buffer.fragment_size)) + emu10k1_waveout_start(wave_dev); - if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) { - spin_unlock_irqrestore(&woinst->lock, flags); - ERROR(); - return -EFAULT; - } - } spin_unlock_irqrestore(&woinst->lock, flags); } @@ -235,16 +225,14 @@ || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT))) return (ret ? ret : -EAGAIN); - UP_INODE_SEM(&inode->i_sem); interruptible_sleep_on(&woinst->wait_queue); - DOWN_INODE_SEM(&inode->i_sem); if (signal_pending(current)) return (ret ? ret : -ERESTARTSYS); } } - DPD(4, "bytes copied -> %x\n", (u32) ret); + DPD(3, "bytes copied -> %d\n", (u32) ret); return ret; } @@ -252,29 +240,19 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; - int val = 0; struct woinst *woinst = NULL; - struct wave_out *wave_out = NULL; struct wiinst *wiinst = NULL; - struct wave_in *wave_in = NULL; - u32 pending, bytestocopy, dummy; + int val = 0; + u32 bytestocopy; unsigned long flags; DPF(4, "emu10k1_audio_ioctl()\n"); - if (file->f_mode & FMODE_WRITE) { + if (file->f_mode & FMODE_WRITE) woinst = wave_dev->woinst; - spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - spin_unlock_irqrestore(&woinst->lock, flags); - } - if (file->f_mode & FMODE_READ) { + if (file->f_mode & FMODE_READ) wiinst = wave_dev->wiinst; - spin_lock_irqsave(&wiinst->lock, flags); - wave_in = wiinst->wave_in; - spin_unlock_irqrestore(&wiinst->lock, flags); - } switch (cmd) { case OSS_GETVERSION: @@ -288,13 +266,22 @@ if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); - if (wave_out) + if (woinst->state & WAVE_STATE_OPEN) { + if (woinst->mmapped) { + int i; + + /* Undo marking the pages as reserved */ + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + } + emu10k1_waveout_close(wave_dev); + } + woinst->mmapped = 0; woinst->total_copied = 0; woinst->total_played = 0; woinst->blocks = 0; - woinst->curpos = 0; spin_unlock_irqrestore(&woinst->lock, flags); } @@ -302,12 +289,12 @@ if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); + wiinst->mmapped = 0; wiinst->total_recorded = 0; wiinst->blocks = 0; - wiinst->curpos = 0; spin_unlock_irqrestore(&wiinst->lock, flags); } @@ -318,10 +305,11 @@ if (file->f_mode & FMODE_WRITE) { - if (wave_out) { - spin_lock_irqsave(&woinst->lock, flags); + spin_lock_irqsave(&woinst->lock, flags); - if (wave_out->state == CARDWAVE_STATE_STARTED) + if (woinst->state & WAVE_STATE_OPEN) { + + if (woinst->state & WAVE_STATE_STARTED) while ((woinst->total_played < woinst->total_copied) && !signal_pending(current)) { spin_unlock_irqrestore(&woinst->lock, flags); @@ -329,25 +317,34 @@ spin_lock_irqsave(&woinst->lock, flags); } - emu10k1_waveout_close(wave_dev); - woinst->total_copied = 0; - woinst->total_played = 0; - woinst->blocks = 0; - woinst->curpos = 0; + if (woinst->mmapped) { + int i; - spin_unlock_irqrestore(&woinst->lock, flags); + /* Undo marking the pages as reserved */ + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); + } + + emu10k1_waveout_close(wave_dev); } + + woinst->mmapped = 0; + woinst->total_copied = 0; + woinst->total_played = 0; + woinst->blocks = 0; + + spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); + wiinst->mmapped = 0; wiinst->total_recorded = 0; wiinst->blocks = 0; - wiinst->curpos = 0; spin_unlock_irqrestore(&wiinst->lock, flags); } @@ -367,43 +364,49 @@ get_user_ret(val, (int *) arg, -EFAULT); DPD(2, "val is %d\n", val); - if (val >= 0) { - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (val > 0) { + if (file->f_mode & FMODE_READ) { + struct wave_format format; + + spin_lock_irqsave(&wiinst->lock, flags); - woinst->wave_fmt.samplingrate = val; + format = wiinst->format; + format.samplingrate = val; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.samplingrate; + val = wiinst->format.samplingrate; - spin_unlock_irqrestore(&woinst->lock, flags); + spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set playback sampling rate -> %d\n", val); + DPD(2, "set recording sampling rate -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; + + spin_lock_irqsave(&woinst->lock, flags); - wiinst->wave_fmt.samplingrate = val; + format = woinst->format; + format.samplingrate = val; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.samplingrate; + val = woinst->format.samplingrate; - spin_unlock_irqrestore(&wiinst->lock, flags); + spin_unlock_irqrestore(&woinst->lock, flags); - DPD(2, "set recording sampling rate -> %d\n", val); + DPD(2, "set playback sampling rate -> %d\n", val); } return put_user(val, (int *) arg); } else { if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.samplingrate; + val = wiinst->format.samplingrate; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.samplingrate; + val = woinst->format.samplingrate; return put_user(val, (int *) arg); } @@ -415,33 +418,39 @@ get_user_ret(val, (int *) arg, -EFAULT); DPD(2, " val is %d\n", val); - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (file->f_mode & FMODE_READ) { + struct wave_format format; - woinst->wave_fmt.channels = val ? 2 : 1; + spin_lock_irqsave(&wiinst->lock, flags); + + format = wiinst->format; + format.channels = val ? 2 : 1; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.channels - 1; + val = wiinst->format.channels - 1; - spin_unlock_irqrestore(&woinst->lock, flags); - - DPD(2, "set playback stereo -> %d\n", val); + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording stereo -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; + + spin_lock_irqsave(&woinst->lock, flags); - wiinst->wave_fmt.channels = val ? 2 : 1; + format = woinst->format; + format.channels = val ? 2 : 1; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.channels - 1; + val = woinst->format.channels - 1; - spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set recording stereo -> %d\n", val); + spin_unlock_irqrestore(&woinst->lock, flags); + + DPD(2, "set playback stereo -> %d\n", val); } return put_user(val, (int *) arg); @@ -454,41 +463,47 @@ get_user_ret(val, (int *) arg, -EFAULT); DPD(2, " val is %d\n", val); - if (val != 0) { - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (val > 0) { + if (file->f_mode & FMODE_READ) { + struct wave_format format; + + spin_lock_irqsave(&wiinst->lock, flags); - woinst->wave_fmt.channels = val; + format = wiinst->format; + format.channels = val; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.channels; + val = wiinst->format.channels; - spin_unlock_irqrestore(&woinst->lock, flags); - DPD(2, "set playback number of channels -> %d\n", val); + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording number of channels -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; - wiinst->wave_fmt.channels = val; + spin_lock_irqsave(&woinst->lock, flags); + + format = woinst->format; + format.channels = val; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.channels; + val = woinst->format.channels; - spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set recording number of channels -> %d\n", val); + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback number of channels -> %d\n", val); } return put_user(val, (int *) arg); } else { if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.channels; + val = wiinst->format.channels; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.channels; + val = woinst->format.channels; return put_user(val, (int *) arg); } @@ -511,40 +526,46 @@ DPD(2, " val is %d\n", val); if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_WRITE) { - spin_lock_irqsave(&woinst->lock, flags); + if (file->f_mode & FMODE_READ) { + struct wave_format format; - woinst->wave_fmt.bitsperchannel = val; + spin_lock_irqsave(&wiinst->lock, flags); + + format = wiinst->format; + format.bitsperchannel = val; - if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; - val = woinst->wave_fmt.bitsperchannel; + val = wiinst->format.bitsperchannel; - spin_unlock_irqrestore(&woinst->lock, flags); - DPD(2, "set playback sample size -> %d\n", val); + spin_unlock_irqrestore(&wiinst->lock, flags); + DPD(2, "set recording sample size -> %d\n", val); } - if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&wiinst->lock, flags); + if (file->f_mode & FMODE_WRITE) { + struct wave_format format; + + spin_lock_irqsave(&woinst->lock, flags); - wiinst->wave_fmt.bitsperchannel = val; + format = woinst->format; + format.bitsperchannel = val; - if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS) + if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; - val = wiinst->wave_fmt.bitsperchannel; + val = woinst->format.bitsperchannel; - spin_unlock_irqrestore(&wiinst->lock, flags); - DPD(2, "set recording sample size -> %d\n", val); + spin_unlock_irqrestore(&woinst->lock, flags); + DPD(2, "set playback sample size -> %d\n", val); } return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); } else { if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.bitsperchannel; + val = wiinst->format.bitsperchannel; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.bitsperchannel; + val = woinst->format.bitsperchannel; return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); } @@ -553,27 +574,27 @@ case SOUND_PCM_READ_BITS: if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.bitsperchannel; + val = wiinst->format.bitsperchannel; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.bitsperchannel; + val = woinst->format.bitsperchannel; return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg); case SOUND_PCM_READ_RATE: if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.samplingrate; + val = wiinst->format.samplingrate; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.samplingrate; + val = woinst->format.samplingrate; return put_user(val, (int *) arg); case SOUND_PCM_READ_CHANNELS: if (file->f_mode & FMODE_READ) - val = wiinst->wave_fmt.channels; + val = wiinst->format.channels; else if (file->f_mode & FMODE_WRITE) - val = woinst->wave_fmt.channels; + val = woinst->format.channels; return put_user(val, (int *) arg); @@ -594,6 +615,7 @@ if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)) val |= PCM_ENABLE_OUTPUT; + if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT)) val |= PCM_ENABLE_INPUT; @@ -609,11 +631,11 @@ if (val & PCM_ENABLE_OUTPUT) { wave_dev->enablebits |= PCM_ENABLE_OUTPUT; - if (wave_out) + if (woinst->state & WAVE_STATE_OPEN) emu10k1_waveout_start(wave_dev); } else { wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT; - if (wave_out) + if (woinst->state & WAVE_STATE_STARTED) emu10k1_waveout_stop(wave_dev); } @@ -625,11 +647,11 @@ if (val & PCM_ENABLE_INPUT) { wave_dev->enablebits |= PCM_ENABLE_INPUT; - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_start(wave_dev); } else { wave_dev->enablebits &= ~PCM_ENABLE_INPUT; - if (wave_in) + if (wiinst->state & WAVE_STATE_STARTED) emu10k1_wavein_stop(wave_dev); } @@ -646,23 +668,21 @@ if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (wave_out) { - spin_lock_irqsave(&woinst->lock, flags); - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - spin_unlock_irqrestore(&woinst->lock, flags); + spin_lock_irqsave(&woinst->lock, flags); + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); info.bytes = bytestocopy; } else { - spin_lock_irqsave(&woinst->lock, flags); calculate_ofrag(woinst); - spin_unlock_irqrestore(&woinst->lock, flags); - - info.bytes = woinst->numfrags * woinst->fragment_size; + info.bytes = woinst->buffer.size; } + spin_unlock_irqrestore(&woinst->lock, flags); - info.fragstotal = woinst->numfrags; - info.fragments = info.bytes / woinst->fragment_size; - info.fragsize = woinst->fragment_size; + info.fragstotal = woinst->buffer.numfrags; + info.fragments = info.bytes / woinst->buffer.fragment_size; + info.fragsize = woinst->buffer.fragment_size; if (copy_to_user((int *) arg, &info, sizeof(info))) return -EFAULT; @@ -678,23 +698,20 @@ if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (wave_in) { - spin_lock_irqsave(&wiinst->lock, flags); - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); - spin_unlock_irqrestore(&wiinst->lock, flags); - + spin_lock_irqsave(&wiinst->lock, flags); + if (wiinst->state & WAVE_STATE_OPEN) { + emu10k1_wavein_update(wave_dev->card, wiinst); + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); info.bytes = bytestocopy; } else { - spin_lock_irqsave(&wiinst->lock, flags); calculate_ifrag(wiinst); - spin_unlock_irqrestore(&wiinst->lock, flags); - info.bytes = 0; } + spin_unlock_irqrestore(&wiinst->lock, flags); - info.fragstotal = wiinst->numfrags; - info.fragments = info.bytes / wiinst->fragment_size; - info.fragsize = wiinst->fragment_size; + info.fragstotal = wiinst->buffer.numfrags; + info.fragments = info.bytes / wiinst->buffer.fragment_size; + info.fragsize = wiinst->buffer.fragment_size; if (copy_to_user((int *) arg, &info, sizeof(info))) return -EFAULT; @@ -713,15 +730,16 @@ if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (wave_out) { - spin_lock_irqsave(&woinst->lock, flags); - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - spin_unlock_irqrestore(&woinst->lock, flags); - - val = pending; + spin_lock_irqsave(&woinst->lock, flags); + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); + val = woinst->buffer.size - bytestocopy; } else val = 0; + spin_unlock_irqrestore(&woinst->lock, flags); + return put_user(val, (int *) arg); case SNDCTL_DSP_GETIPTR: @@ -735,17 +753,16 @@ spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in) { - emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr); - cinfo.bytes = - cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags); - cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks; - wiinst->blocks = cinfo.bytes / wiinst->fragment_size; + if (wiinst->state & WAVE_STATE_OPEN) { + emu10k1_wavein_update(wave_dev->card, wiinst); + cinfo.ptr = wiinst->buffer.hw_pos; + cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % wiinst->buffer.size; + cinfo.blocks = cinfo.bytes / wiinst->buffer.fragment_size - wiinst->blocks; + wiinst->blocks = cinfo.bytes / wiinst->buffer.fragment_size; } else { cinfo.ptr = 0; cinfo.bytes = 0; cinfo.blocks = 0; - wiinst->blocks = 0; } spin_unlock_irqrestore(&wiinst->lock, flags); @@ -766,17 +783,19 @@ spin_lock_irqsave(&woinst->lock, flags); - if (wave_out) { - emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr); - cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags); - cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks; - woinst->blocks = cinfo.bytes / woinst->fragment_size; + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + cinfo.ptr = woinst->buffer.hw_pos; + cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % woinst->buffer.size; + cinfo.blocks = cinfo.bytes / woinst->buffer.fragment_size - woinst->blocks; + woinst->blocks = cinfo.bytes / woinst->buffer.fragment_size; } else { cinfo.ptr = 0; cinfo.bytes = 0; cinfo.blocks = 0; - woinst->blocks = 0; } + if(woinst->mmapped) + woinst->buffer.bytestocopy %= woinst->buffer.fragment_size; spin_unlock_irqrestore(&woinst->lock, flags); @@ -792,7 +811,7 @@ spin_lock_irqsave(&woinst->lock, flags); calculate_ofrag(woinst); - val = woinst->fragment_size; + val = woinst->buffer.fragment_size; spin_unlock_irqrestore(&woinst->lock, flags); } @@ -801,7 +820,7 @@ spin_lock_irqsave(&wiinst->lock, flags); calculate_ifrag(wiinst); - val = wiinst->fragment_size; + val = wiinst->buffer.fragment_size; spin_unlock_irqrestore(&wiinst->lock, flags); } @@ -811,7 +830,17 @@ break; case SNDCTL_DSP_POST: - DPF(2, "SNDCTL_DSP_POST: not implemented\n"); + if (file->f_mode & FMODE_WRITE) { + spin_lock_irqsave(&woinst->lock, flags); + + if (!(woinst->state & WAVE_STATE_STARTED) + && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) + && (woinst->total_copied > 0)) + emu10k1_waveout_start(wave_dev); + + spin_unlock_irqrestore(&woinst->lock, flags); + } + break; case SNDCTL_DSP_SUBDIVIDE: @@ -823,25 +852,25 @@ get_user_ret(val, (int *) arg, -EFAULT); - DPD(2, "val is %x\n", val); + DPD(2, "val is 0x%x\n", val); if (val == 0) return -EIO; if (file->f_mode & FMODE_WRITE) { - if (wave_out) + if (woinst->state & WAVE_STATE_OPEN) return -EINVAL; /* too late to change */ - woinst->ossfragshift = val & 0xffff; - woinst->numfrags = (val >> 16) & 0xffff; + woinst->buffer.ossfragshift = val & 0xffff; + woinst->buffer.numfrags = (val >> 16) & 0xffff; } if (file->f_mode & FMODE_READ) { - if (wave_in) + if (wiinst->state & WAVE_STATE_OPEN) return -EINVAL; /* too late to change */ - wiinst->ossfragshift = val & 0xffff; - wiinst->numfrags = (val >> 16) & 0xffff; + wiinst->buffer.ossfragshift = val & 0xffff; + wiinst->buffer.numfrags = (val >> 16) & 0xffff; } break; @@ -859,15 +888,15 @@ if ((buf.command != 1) && (buf.command != 2)) return -EINVAL; - if (((buf.offs < 0x100) && (buf.command == 2)) + if ((buf.offs < 0x100) || (buf.offs < 0x000) || (buf.offs + buf.len > 0x800) || (buf.len > 1000)) return -EINVAL; if (buf.command == 1) { for (i = 0; i < buf.len; i++) - ((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0); + if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf))) return -EFAULT; } else { @@ -878,7 +907,7 @@ } default: /* Default is unrecognized command */ - DPD(2, "default: %x\n", cmd); + DPD(2, "default: 0x%x\n", cmd); return -EINVAL; } return 0; @@ -894,51 +923,46 @@ return -ENXIO; lock_kernel(); + if (vma->vm_flags & VM_WRITE) { struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; u32 size; unsigned long flags; int i; spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - - if (!wave_out) { + if (woinst->state == WAVE_STATE_CLOSED) { calculate_ofrag(woinst); - if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { + if (emu10k1_waveout_open(wave_dev) < 0) { spin_unlock_irqrestore(&woinst->lock, flags); ERROR(); unlock_kernel(); return -EINVAL; } - wave_out = woinst->wave_out; - /* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */ - for (i = 0; i < wave_out->wavexferbuf->numpages; i++) - mem_map_reserve(virt_to_page(wave_out->pagetable[i])); + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); } size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) { + if (size > (PAGE_SIZE * woinst->buffer.pages)) { spin_unlock_irqrestore(&woinst->lock, flags); unlock_kernel(); return -EINVAL; } - for (i = 0; i < wave_out->wavexferbuf->numpages; i++) { - if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) { + for (i = 0; i < woinst->buffer.pages; i++) { + if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(woinst->buffer.addr[i]), PAGE_SIZE, vma->vm_page_prot)) { spin_unlock_irqrestore(&woinst->lock, flags); - unlock_kernel(); return -EAGAIN; } } - woinst->mapped = 1; + woinst->mmapped = 1; spin_unlock_irqrestore(&woinst->lock, flags); } @@ -948,9 +972,10 @@ unsigned long flags; spin_lock_irqsave(&wiinst->lock, flags); - wiinst->mapped = 1; + wiinst->mmapped = 1; spin_unlock_irqrestore(&wiinst->lock, flags); } + unlock_kernel(); return 0; @@ -970,7 +995,7 @@ list_for_each(entry, &emu10k1_devs) { card = list_entry(entry, struct emu10k1_card, list); - if (card->audio1_num == minor || card->audio2_num == minor) + if (!((card->audio_num ^ minor) & ~0xf) || !((card->audio1_num ^ minor) & ~0xf)) break; } @@ -988,6 +1013,56 @@ wave_dev->woinst = NULL; wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */ + if (file->f_mode & FMODE_READ) { + /* Recording */ + struct wiinst *wiinst; + + if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { + ERROR(); + return -ENODEV; + } + + wiinst->recsrc = card->wavein.recsrc; + wiinst->fxwc = card->wavein.fxwc; + + switch (wiinst->recsrc) { + case WAVERECORD_AC97: + wiinst->format.samplingrate = 8000; + wiinst->format.bitsperchannel = 16; + wiinst->format.channels = 1; + break; + case WAVERECORD_MIC: + wiinst->format.samplingrate = 8000; + wiinst->format.bitsperchannel = 16; + wiinst->format.channels = 1; + break; + case WAVERECORD_FX: + wiinst->format.samplingrate = 48000; + wiinst->format.bitsperchannel = 16; + wiinst->format.channels = hweight32(wiinst->fxwc); + break; + default: + BUG(); + break; + } + + wiinst->state = WAVE_STATE_CLOSED; + + wiinst->buffer.ossfragshift = 0; + wiinst->buffer.fragment_size = 0; + wiinst->buffer.numfrags = 0; + + init_waitqueue_head(&wiinst->wait_queue); + + wiinst->mmapped = 0; + wiinst->total_recorded = 0; + wiinst->blocks = 0; + wiinst->lock = SPIN_LOCK_UNLOCKED; + tasklet_init(&wiinst->timer.tasklet, emu10k1_wavein_bh, (unsigned long) wave_dev); + wave_dev->wiinst = wiinst; + emu10k1_wavein_setformat(wave_dev, &wiinst->format); + } + if (file->f_mode & FMODE_WRITE) { struct woinst *woinst; @@ -996,24 +1071,31 @@ return -ENODEV; } - woinst->wave_fmt.samplingrate = 8000; - woinst->wave_fmt.bitsperchannel = 8; - woinst->wave_fmt.channels = 1; - woinst->ossfragshift = 0; - woinst->fragment_size = 0; - woinst->numfrags = 0; - woinst->device = (card->audio2_num == minor); - woinst->wave_out = NULL; + if (wave_dev->wiinst != NULL) { + woinst->format = wave_dev->wiinst->format; + } else { + woinst->format.samplingrate = 8000; + woinst->format.bitsperchannel = 8; + woinst->format.channels = 1; + } + + woinst->state = WAVE_STATE_CLOSED; + + woinst->buffer.fragment_size = 0; + woinst->buffer.ossfragshift = 0; + woinst->buffer.numfrags = 0; + woinst->device = (card->audio1_num == minor); init_waitqueue_head(&woinst->wait_queue); - woinst->mapped = 0; + woinst->mmapped = 0; woinst->total_copied = 0; woinst->total_played = 0; woinst->blocks = 0; - woinst->curpos = 0; woinst->lock = SPIN_LOCK_UNLOCKED; + tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev); wave_dev->woinst = woinst; + emu10k1_waveout_setformat(wave_dev, &woinst->format); #ifdef PRIVATE_PCM_VOLUME { @@ -1038,69 +1120,27 @@ if (i == MAX_PCM_CHANNELS) { // add new entry if (j < 0) - printk("TOO MANY WRITTERS!!!\n"); + printk(KERN_WARNING "emu10k1: too many writters!\n"); i = (j >= 0) ? j : 0; DPD(2, "new pcm private %p\n", current->files); sblive_pcm_volume[i].files = current->files; - sblive_pcm_volume[i].mixer = 0x6464; // max + sblive_pcm_volume[i].mixer = pcm_last_mixer; sblive_pcm_volume[i].attn_l = 0; sblive_pcm_volume[i].attn_r = 0; sblive_pcm_volume[i].channel_l = NUM_G; sblive_pcm_volume[i].channel_r = NUM_G; - } + } else + DPD(2, "old pcm private %p 0x%x\n", current->files, + sblive_pcm_volume[i].mixer); + sblive_pcm_volume[i].opened++; } #endif } - if (file->f_mode & FMODE_READ) { - /* Recording */ - struct wiinst *wiinst; - - if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { - ERROR(); - return -ENODEV; - } - - switch (card->wavein->recsrc) { - case WAVERECORD_AC97: - wiinst->wave_fmt.samplingrate = 8000; - wiinst->wave_fmt.bitsperchannel = 8; - wiinst->wave_fmt.channels = 1; - break; - case WAVERECORD_MIC: - wiinst->wave_fmt.samplingrate = 8000; - wiinst->wave_fmt.bitsperchannel = 8; - wiinst->wave_fmt.channels = 1; - break; - case WAVERECORD_FX: - wiinst->wave_fmt.samplingrate = 48000; - wiinst->wave_fmt.bitsperchannel = 16; - wiinst->wave_fmt.channels = 2; - break; - default: - break; - } - - wiinst->recsrc = card->wavein->recsrc; - wiinst->ossfragshift = 0; - wiinst->fragment_size = 0; - wiinst->numfrags = 0; - wiinst->wave_in = NULL; - - init_waitqueue_head(&wiinst->wait_queue); - - wiinst->mapped = 0; - wiinst->total_recorded = 0; - wiinst->blocks = 0; - wiinst->curpos = 0; - wiinst->lock = SPIN_LOCK_UNLOCKED; - wave_dev->wiinst = wiinst; - } - file->private_data = (void *) wave_dev; - return 0; /* Success? */ + return 0; } static int emu10k1_audio_release(struct inode *inode, struct file *file) @@ -1111,37 +1151,35 @@ lock_kernel(); card = wave_dev->card; + DPF(2, "emu10k1_audio_release()\n"); if (file->f_mode & FMODE_WRITE) { struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - - if (wave_out) { - if ((wave_out->state == CARDWAVE_STATE_STARTED) - && !(file->f_flags & O_NONBLOCK)) { - while (!signal_pending(current) - && (woinst->total_played < woinst->total_copied)) { - DPF(4, "Buffer hasn't been totally played, sleep....\n"); - spin_unlock_irqrestore(&woinst->lock, flags); - interruptible_sleep_on(&woinst->wait_queue); - spin_lock_irqsave(&woinst->lock, flags); + if (woinst->state & WAVE_STATE_OPEN) { + if (woinst->state & WAVE_STATE_STARTED) { + if (!(file->f_flags & O_NONBLOCK)) { + while (!signal_pending(current) + && (woinst->total_played < woinst->total_copied)) { + DPF(4, "Buffer hasn't been totally played, sleep....\n"); + spin_unlock_irqrestore(&woinst->lock, flags); + interruptible_sleep_on(&woinst->wait_queue); + spin_lock_irqsave(&woinst->lock, flags); + } } } - if (woinst->mapped && wave_out->pagetable) { + if (woinst->mmapped) { int i; /* Undo marking the pages as reserved */ - for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++) - mem_map_reserve(virt_to_page(woinst->wave_out->pagetable[i])); + for (i = 0; i < woinst->buffer.pages; i++) + mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); } - woinst->mapped = 0; emu10k1_waveout_close(wave_dev); } #ifdef PRIVATE_PCM_VOLUME @@ -1159,22 +1197,21 @@ } #endif spin_unlock_irqrestore(&woinst->lock, flags); + /* wait for the tasklet (bottom-half) to finish */ + tasklet_unlock_wait(&woinst->timer.tasklet); kfree(wave_dev->woinst); } if (file->f_mode & FMODE_READ) { struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in; spin_lock_irqsave(&wiinst->lock, flags); - wave_in = wiinst->wave_in; - - if (wave_in) { - wiinst->mapped = 0; + if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); - } + spin_unlock_irqrestore(&wiinst->lock, flags); + tasklet_unlock_wait(&wiinst->timer.tasklet); kfree(wave_dev->wiinst); } @@ -1192,7 +1229,7 @@ struct woinst *woinst = wave_dev->woinst; struct wiinst *wiinst = wave_dev->wiinst; unsigned int mask = 0; - u32 bytestocopy, pending, dummy; + u32 bytestocopy; unsigned long flags; DPF(4, "emu10k1_audio_poll()\n"); @@ -1204,49 +1241,44 @@ poll_wait(file, &wiinst->wait_queue, wait); if (file->f_mode & FMODE_WRITE) { - struct wave_out *wave_out; - spin_lock_irqsave(&woinst->lock, flags); - wave_out = woinst->wave_out; - - if (wave_out) { + if (woinst->state & WAVE_STATE_OPEN) { + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy); - - if (bytestocopy >= woinst->fragment_size) + if (bytestocopy >= woinst->buffer.fragment_size) mask |= POLLOUT | POLLWRNORM; } else mask |= POLLOUT | POLLWRNORM; + if(woinst->mmapped) { + spin_unlock_irqrestore(&woinst->lock, flags); + return mask; + } + spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { - struct wave_in *wave_in; - spin_lock_irqsave(&wiinst->lock, flags); - wave_in = wiinst->wave_in; - - if (!wave_in) { + if (wiinst->state == WAVE_STATE_CLOSED) { calculate_ifrag(wiinst); - if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) { + if (emu10k1_wavein_open(wave_dev) < 0) { spin_unlock_irqrestore(&wiinst->lock, flags); return (mask |= POLLERR); } - - wave_in = wiinst->wave_in; } - if (wave_in->state != CARDWAVE_STATE_STARTED) { + if (!(wiinst->state & WAVE_STATE_STARTED)) { wave_dev->enablebits |= PCM_ENABLE_INPUT; emu10k1_wavein_start(wave_dev); } + emu10k1_wavein_update(wave_dev->card, wiinst); + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy); - - if (bytestocopy >= wiinst->fragment_size) + if (bytestocopy >= wiinst->buffer.fragment_size) mask |= POLLIN | POLLRDNORM; spin_unlock_irqrestore(&wiinst->lock, flags); @@ -1257,136 +1289,169 @@ static void calculate_ofrag(struct woinst *woinst) { - u32 fragsize, bytespersec; + struct waveout_buffer *buffer = &woinst->buffer; + u32 fragsize; - if (woinst->fragment_size) + if (buffer->fragment_size) return; - bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate; - - if (!woinst->ossfragshift) { - fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; + if (!buffer->ossfragshift) { + fragsize = (woinst->format.bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1; while (fragsize) { fragsize >>= 1; - woinst->ossfragshift++; + buffer->ossfragshift++; } } - if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT) - woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT; + if (buffer->ossfragshift < WAVEOUT_MINFRAGSHIFT) + buffer->ossfragshift = WAVEOUT_MINFRAGSHIFT; - woinst->fragment_size = 1 << woinst->ossfragshift; + buffer->fragment_size = 1 << buffer->ossfragshift; - if (!woinst->numfrags) { + if (!buffer->numfrags) { u32 numfrags; - numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1; + numfrags = (woinst->format.bytespersec * WAVEOUT_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1; - woinst->numfrags = 1; + buffer->numfrags = 1; while (numfrags) { numfrags >>= 1; - woinst->numfrags <<= 1; + buffer->numfrags <<= 1; } } - if (woinst->numfrags < MINFRAGS) - woinst->numfrags = MINFRAGS; + if (buffer->numfrags < MINFRAGS) + buffer->numfrags = MINFRAGS; - if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) { - woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size; + if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) { + buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size; - if (woinst->numfrags < MINFRAGS) { - woinst->numfrags = MINFRAGS; - woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS; + if (buffer->numfrags < MINFRAGS) { + buffer->numfrags = MINFRAGS; + buffer->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS; } - } else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE) - woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size; + } else if (buffer->numfrags * buffer->fragment_size < WAVEOUT_MINBUFSIZE) + buffer->numfrags = WAVEOUT_MINBUFSIZE / buffer->fragment_size; - DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size); - DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags); + buffer->size = buffer->fragment_size * buffer->numfrags; + buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0); + + DPD(2, " calculated playback fragment_size -> %d\n", buffer->fragment_size); + DPD(2, " calculated playback numfrags -> %d\n", buffer->numfrags); + + return; } static void calculate_ifrag(struct wiinst *wiinst) { - u32 fragsize, bytespersec; + struct wavein_buffer *buffer = &wiinst->buffer; + u32 fragsize, bufsize, size[4]; + int i, j; - if (wiinst->fragment_size) + if (buffer->fragment_size) return; - bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate; - - if (!wiinst->ossfragshift) { - fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; + if (!buffer->ossfragshift) { + fragsize = (wiinst->format.bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1; while (fragsize) { fragsize >>= 1; - wiinst->ossfragshift++; + buffer->ossfragshift++; } } - if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT) - wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT; + if (buffer->ossfragshift < WAVEIN_MINFRAGSHIFT) + buffer->ossfragshift = WAVEIN_MINFRAGSHIFT; - wiinst->fragment_size = 1 << wiinst->ossfragshift; + buffer->fragment_size = 1 << buffer->ossfragshift; - if (!wiinst->numfrags) - wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1; + if (!buffer->numfrags) + buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1; - if (wiinst->numfrags < MINFRAGS) - wiinst->numfrags = MINFRAGS; + if (buffer->numfrags < MINFRAGS) + buffer->numfrags = MINFRAGS; - if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) { - wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size; + if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) { + buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size; - if (wiinst->numfrags < MINFRAGS) { - wiinst->numfrags = MINFRAGS; - wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS; + if (buffer->numfrags < MINFRAGS) { + buffer->numfrags = MINFRAGS; + buffer->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS; } - } else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE) - wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size; + } else if (buffer->numfrags * buffer->fragment_size < WAVEIN_MINBUFSIZE) + buffer->numfrags = WAVEIN_MINBUFSIZE / buffer->fragment_size; - DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size); - DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags); + bufsize = buffer->fragment_size * buffer->numfrags; + + if (bufsize >= 0x10000) { + buffer->size = 0x10000; + buffer->sizeregval = 0x1f; + } else { + buffer->size = 0; + size[0] = 384; + size[1] = 448; + size[2] = 512; + size[3] = 640; + + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + if (bufsize >= size[j]) { + buffer->size = size[j]; + size[j] *= 2; + buffer->sizeregval = i * 4 + j + 1; + } else + goto exitloop; + exitloop: + if (buffer->size == 0) { + buffer->size = 384; + buffer->sizeregval = 0x01; + } + } + + buffer->numfrags = buffer->size / buffer->fragment_size; + + if (buffer->size % buffer->fragment_size) + BUG(); + + DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size); + DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags); + DPD(2, " buffer size register -> 0x%2x\n", buffer->sizeregval); + + return; } void emu10k1_wavein_bh(unsigned long refdata) { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in = wiinst->wave_in; - u32 bytestocopy, curpos; + u32 bytestocopy; unsigned long flags; spin_lock_irqsave(&wiinst->lock, flags); - if (wave_in->state == CARDWAVE_STATE_STOPPED) { + if (!(wiinst->state & WAVE_STATE_STARTED)) { spin_unlock_irqrestore(&wiinst->lock, flags); return; } - emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos); - - wiinst->total_recorded += curpos - wiinst->curpos; - - if (curpos < wiinst->curpos) - wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags; - - wiinst->curpos = curpos; + emu10k1_wavein_update(wave_dev->card, wiinst); - if (wiinst->mapped) { + if (wiinst->mmapped) { spin_unlock_irqrestore(&wiinst->lock, flags); return; } + emu10k1_wavein_getxfersize(wiinst, &bytestocopy); + spin_unlock_irqrestore(&wiinst->lock, flags); - if (bytestocopy >= wiinst->fragment_size) + if (bytestocopy >= wiinst->buffer.fragment_size) wake_up_interruptible(&wiinst->wait_queue); else - DPD(4, "Not enough transfer size, %d\n", bytestocopy); + DPD(3, "Not enough transfer size, %d\n", bytestocopy); return; } @@ -1395,53 +1460,41 @@ { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out = woinst->wave_out; - u32 bytestocopy, pending, curpos; + u32 bytestocopy; unsigned long flags; spin_lock_irqsave(&woinst->lock, flags); - if (wave_out->state == CARDWAVE_STATE_STOPPED) { + if (!(woinst->state & WAVE_STATE_STARTED)) { spin_unlock_irqrestore(&woinst->lock, flags); return; } - emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos); - - woinst->total_played += curpos - woinst->curpos; - - if (curpos < woinst->curpos) - woinst->total_played += woinst->fragment_size * woinst->numfrags; - - woinst->curpos = curpos; - - if (woinst->mapped) { - spin_unlock_irqrestore(&woinst->lock, flags); - return; - } + emu10k1_waveout_update(woinst); + emu10k1_waveout_getxfersize(woinst, &bytestocopy); - if (wave_out->fill_silence) { + if (woinst->buffer.fill_silence) { spin_unlock_irqrestore(&woinst->lock, flags); emu10k1_waveout_fillsilence(woinst); } else spin_unlock_irqrestore(&woinst->lock, flags); - if (bytestocopy >= woinst->fragment_size) + if (bytestocopy >= woinst->buffer.fragment_size) wake_up_interruptible(&woinst->wait_queue); else - DPD(4, "Not enough transfer size -> %x\n", bytestocopy); + DPD(3, "Not enough transfer size -> %d\n", bytestocopy); return; } struct file_operations emu10k1_audio_fops = { - owner:THIS_MODULE, - llseek:emu10k1_audio_llseek, - read:emu10k1_audio_read, - write:emu10k1_audio_write, - poll:emu10k1_audio_poll, - ioctl:emu10k1_audio_ioctl, - mmap:emu10k1_audio_mmap, - open:emu10k1_audio_open, - release:emu10k1_audio_release, + owner: THIS_MODULE, + llseek: emu10k1_audio_llseek, + read: emu10k1_audio_read, + write: emu10k1_audio_write, + poll: emu10k1_audio_poll, + ioctl: emu10k1_audio_ioctl, + mmap: emu10k1_audio_mmap, + open: emu10k1_audio_open, + release: emu10k1_audio_release, }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/audio.h linux/drivers/sound/emu10k1/audio.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/audio.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/audio.h Mon Aug 14 08:32:48 2000 @@ -33,12 +33,15 @@ #ifndef _AUDIO_H #define _AUDIO_H -#define __NO_VERSION__ -#include -#include -#include - #define MINFRAGS 2 /* _don't_ got bellow 2 */ + +struct emu10k1_wavedevice +{ + struct emu10k1_card *card; + struct wiinst *wiinst; + struct woinst *woinst; + u16 enablebits; +}; void emu10k1_waveout_bh(unsigned long); void emu10k1_wavein_bh(unsigned long); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardmi.c linux/drivers/sound/emu10k1/cardmi.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardmi.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardmi.c Mon Aug 14 08:32:48 2000 @@ -31,8 +31,13 @@ ********************************************************************** */ +#include +#include + #include "hwaccess.h" +#include "8010.h" #include "cardmi.h" +#include "irqmgr.h" static struct { int (*Fn) (struct emu10k1_mpuin *, u8); @@ -76,7 +81,7 @@ DPF(2, "emu10k1_mpuin_open\n"); if (!(card_mpuin->status & FLAGS_AVAILABLE)) - return CTSTATUS_INUSE; + return -1; /* Copy open info and mark channel as in use */ card_mpuin->openinfo = *openinfo; @@ -93,7 +98,7 @@ emu10k1_mpu_reset(card); emu10k1_mpu_acquire(card); - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpuin_close(struct emu10k1_card *card) @@ -105,7 +110,7 @@ /* Check if there are pending input SysEx buffers */ if (card_mpuin->firstmidiq != NULL) { ERROR(); - return CTSTATUS_ERROR; + return -1; } /* Disable RX interrupt */ @@ -116,7 +121,7 @@ card_mpuin->status |= FLAGS_AVAILABLE; /* set */ card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ - return CTSTATUS_SUCCESS; + return 0; } /* Adds MIDI buffer to local queue list */ @@ -134,7 +139,7 @@ if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) { /* Message lost */ - return CTSTATUS_ERROR; + return -1; } midiq->next = NULL; @@ -156,7 +161,7 @@ spin_unlock_irqrestore(&card_mpuin->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } /* First set the Time Stamp if MIDI IN has not started. */ @@ -174,7 +179,7 @@ if (card_mpuin->status & FLAGS_MIDM_STARTED) { DPF(2, "Time Stamp not changed\n"); } else { - while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS); + while (!emu10k1_mpu_read_data(card, &dummy)); card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */ @@ -188,7 +193,7 @@ emu10k1_irq_enable(card, INTE_MIDIRXENABLE); } - return CTSTATUS_SUCCESS; + return 0; } /* Disable the RX Irq. If a partial recorded buffer */ @@ -229,7 +234,7 @@ } } - return CTSTATUS_SUCCESS; + return 0; } /* Disable the RX Irq. If any buffer */ @@ -259,7 +264,7 @@ card_mpuin->lastmidiq = NULL; card_mpuin->status &= ~FLAGS_MIDM_STARTED; - return CTSTATUS_SUCCESS; + return 0; } /* Passes the message with the data back to the client */ @@ -302,7 +307,7 @@ /* Notify client that Sysex buffer has been sent */ emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg); - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_mpuin_bh(unsigned long refdata) @@ -344,13 +349,13 @@ idx = card_mpuin->qtail; while (1) { - if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) { + if (emu10k1_mpu_read_data(card, &MPUIvalue) < 0) { + break; + } else { ++count; card_mpuin->midiq[idx].data = MPUIvalue; card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ; idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE; - } else { - break; } } @@ -360,7 +365,7 @@ tasklet_hi_schedule(&card_mpuin->tasklet); } - return CTSTATUS_SUCCESS; + return 0; } /*****************************************************************************/ @@ -380,7 +385,7 @@ card_mpuin->timestart = 0; card_mpuin->timein = 0; - return CTSTATUS_SUCCESS; + return 0; } /* FIXME: This should be a macro */ @@ -425,7 +430,7 @@ case 0x7: emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0); - return CTSTATUS_ERROR; + return -1; case 0x2: card_mpuin->laststate = card_mpuin->curstate; @@ -447,7 +452,7 @@ default: DPF(2, "BUG: default case hit\n"); - return CTSTATUS_ERROR; + return -1; } return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data); @@ -489,7 +494,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->data = data; @@ -520,7 +525,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = STIN_3BYTE; @@ -532,7 +537,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -573,7 +578,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = STIN_2BYTE; @@ -583,7 +588,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -615,7 +620,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = card_mpuin->laststate; @@ -625,7 +630,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -657,7 +662,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->data = data; @@ -689,7 +694,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0); - return CTSTATUS_ERROR; + return -1; } card_mpuin->curstate = card_mpuin->laststate; @@ -701,7 +706,7 @@ emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3); - return CTSTATUS_SUCCESS; + return 0; } int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data) @@ -739,7 +744,7 @@ kfree(midiq); } - return CTSTATUS_ERROR; + return -1; } if (card_mpuin->firstmidiq) { @@ -775,7 +780,7 @@ kfree(midiq); } - return CTSTATUS_SUCCESS; + return 0; } if (card_mpuin->firstmidiq) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardmi.h linux/drivers/sound/emu10k1/cardmi.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardmi.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardmi.h Mon Aug 14 08:32:48 2000 @@ -34,6 +34,7 @@ #define _CARDMI_H #include "icardmid.h" +#include typedef enum { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardmo.c linux/drivers/sound/emu10k1/cardmo.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardmo.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardmo.c Mon Aug 14 08:32:48 2000 @@ -31,8 +31,12 @@ ********************************************************************** */ +#include + #include "hwaccess.h" +#include "8010.h" #include "cardmo.h" +#include "irqmgr.h" /* Installs the IRQ handler for the MPU out port * * and initialize parameters */ @@ -44,7 +48,7 @@ DPF(2, "emu10k1_mpuout_open()\n"); if (!(card_mpuout->status & FLAGS_AVAILABLE)) - return CTSTATUS_INUSE; + return -1; /* Copy open info and mark channel as in use */ card_mpuout->intr = 0; @@ -57,7 +61,7 @@ emu10k1_mpu_reset(card); emu10k1_mpu_acquire(card); - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpuout_close(struct emu10k1_card *card) @@ -92,7 +96,7 @@ spin_unlock_irqrestore(&card_mpuout->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } /* If there isn't enough buffer space, reject Midi Buffer. * @@ -109,14 +113,14 @@ DPF(2, "emu10k1_mpuout_add_buffer()\n"); if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND) - return CTSTATUS_SUCCESS; + return 0; midihdr->flags |= MIDIBUF_INQUEUE; midihdr->flags &= ~MIDIBUF_DONE; if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) { /* Message lost */ - return CTSTATUS_NOMEMORY; + return -1; } midiq->next = NULL; @@ -143,7 +147,7 @@ spin_unlock_irqrestore(&card_mpuout->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_mpuout_bh(unsigned long refdata) @@ -151,7 +155,6 @@ struct emu10k1_card *card = (struct emu10k1_card *) refdata; struct emu10k1_mpuout *card_mpuout = card->mpuout; int cByteSent = 0; - int status; struct midi_queue *midiq; struct midi_queue *doneq = NULL; unsigned long flags; @@ -162,14 +165,12 @@ midiq = card_mpuout->firstmidiq; while (cByteSent < 4 && midiq->sizeLeft) { - status = emu10k1_mpu_write_data(card, *midiq->midibyte); - - if (status == CTSTATUS_SUCCESS) { + if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) { + DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); + } else { ++cByteSent; --midiq->sizeLeft; ++midiq->midibyte; - } else { - DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); } } @@ -225,5 +226,5 @@ tasklet_hi_schedule(&card_mpuout->tasklet); - return CTSTATUS_SUCCESS; + return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardmo.h linux/drivers/sound/emu10k1/cardmo.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardmo.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardmo.h Mon Aug 14 08:32:48 2000 @@ -34,6 +34,7 @@ #define _CARDMO_H #include "icardmid.h" +#include #define CARDMIDIOUT_STATE_DEFAULT 0x00000000 #define CARDMIDIOUT_STATE_SUSPEND 0x00000001 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardwi.c linux/drivers/sound/emu10k1/cardwi.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardwi.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardwi.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * cardwi.c - PCM input HAL for emu10k1 driver @@ -30,7 +29,9 @@ ********************************************************************** */ +#include #include "hwaccess.h" +#include "timer.h" #include "recmgr.h" #include "audio.h" #include "cardwi.h" @@ -41,7 +42,7 @@ switch (recsrc) { case WAVERECORD_AC97: - if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1)) + if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) wave_fmt->channels = 2; if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2) @@ -61,110 +62,41 @@ else wave_fmt->samplingrate = 0x1F40; - if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8)) + if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16)) wave_fmt->bitsperchannel = 16; break; + /* these can't be changed from the original values */ case WAVERECORD_MIC: - wave_fmt->channels = 1; - wave_fmt->samplingrate = 0x1F40; - wave_fmt->bitsperchannel = 8; - break; - case WAVERECORD_FX: - wave_fmt->channels = 2; - wave_fmt->samplingrate = 0xBB80; - wave_fmt->bitsperchannel = 16; break; default: + BUG(); break; } + wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; + wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel; + wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate; + return; } -static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer) +static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) { - u32 reqsize; - int i, j; - u32 size[4]; - - /* NOTE: record buffer size only can be certain sizes. If the requested - * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */ - if (!wave_in->rec_ptr->is_16bit) - *bufsize <<= 1; - - if (*bufsize >= 0x10000) { - *bufsize = reqsize = 0x10000; - wave_in->rec_ptr->bufsize = 31; - } else { - reqsize = 0; - size[0] = 384; - size[1] = 448; - size[2] = 512; - size[3] = 640; - - for (i = 0; i < 8; i++) - for (j = 0; j < 4; j++) - if (*bufsize >= size[j]) { - reqsize = size[j]; - size[j] = size[j] * 2; - wave_in->rec_ptr->bufsize = i * 4 + j + 1; - } else - goto exitloop; - exitloop: - if (reqsize == 0) { - reqsize = 384; - wave_in->rec_ptr->bufsize = 1; - } - - *bufsize = reqsize; - } - - DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize); + if ((buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov, &buffer->dma_handle)) == NULL) + return -1; - /* Recording buffer must be continuous and page-aligned */ - if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL) - return CTSTATUS_ERROR; - - DPD(2, "recbufsize: %x\n", *bufsize); - - *buffer = (u8 *) wave_in->memhandle->virtaddx; - - return CTSTATUS_SUCCESS; + return 0; } -static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size) +static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) { - u8 *buffer; + if (buffer->addr != NULL) + pci_free_consistent(card->pci_dev, buffer->size * buffer->cov, buffer->addr, buffer->dma_handle); - wave_in->rec_ptr->card = card; - wave_in->rec_ptr->recpos = 0; - wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate; - wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0; - wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0; - - /* Allocate buffer here */ - if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) { - ERROR(); - return CTSTATUS_ERROR; - } - - /* recbufsize contains actual record buffer size */ - /* for 8 bit samples the size is twice the requested */ - /* value since we only make use of one in every two bytes */ - wave_in->rec_ptr->recbufsize = *size; - wave_in->rec_ptr->recbuffer = buffer; - wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx; - - return CTSTATUS_SUCCESS; -} - -static void dealloc_recbuffer(struct wave_in *wave_in) -{ - emu10k1_free_memphysical(wave_in->memhandle); return; } @@ -172,301 +104,264 @@ { struct emu10k1_card *card = wave_dev->card; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in; - struct wave_in **wave_in_tmp = NULL; - u32 buffsize, bytespersec, delay; + struct wiinst **wiinst_tmp = NULL; + u32 delay; unsigned long flags; DPF(2, "emu10k1_wavein_open()\n"); - if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) { - ERROR(); - return CTSTATUS_ERROR; - } - - wave_in->state = CARDWAVE_STATE_STOPPED; - wave_in->wave_fmt = wiinst->wave_fmt; - wave_in->memhandle = NULL; - wave_in->timer = NULL; - switch (wiinst->recsrc) { case WAVERECORD_AC97: - wave_in_tmp = &card->wavein->ac97; + wiinst_tmp = &card->wavein.ac97; break; case WAVERECORD_MIC: - wave_in_tmp = &card->wavein->mic; + wiinst_tmp = &card->wavein.mic; break; case WAVERECORD_FX: - wave_in_tmp = &card->wavein->fx; + wiinst_tmp = &card->wavein.fx; break; default: + BUG(); break; } spin_lock_irqsave(&card->lock, flags); - if (*wave_in_tmp != NULL) { + if (*wiinst_tmp != NULL) { spin_unlock_irqrestore(&card->lock, flags); - kfree(wave_in); - return CTSTATUS_ERROR; + return -1; } - *wave_in_tmp = wave_in; + *wiinst_tmp = wiinst; spin_unlock_irqrestore(&card->lock, flags); - wiinst->wave_in = wave_in; + /* handle 8 bit recording */ + if (wiinst->format.bytesperchannel == 1) { + if (wiinst->buffer.size > 0x8000) { + wiinst->buffer.size = 0x8000; + wiinst->buffer.sizeregval = 0x1f; + } else + wiinst->buffer.sizeregval += 4; + + wiinst->buffer.cov = 2; + } else + wiinst->buffer.cov = 1; - if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) { + if (alloc_buffer(card, &wiinst->buffer) < 0) { ERROR(); emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - buffsize = wiinst->fragment_size * wiinst->numfrags; + emu10k1_set_record_src(card, wiinst); - if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) { - ERROR(); - emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; - } + delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; - wiinst->fragment_size = buffsize / wiinst->numfrags; + emu10k1_timer_install(card, &wiinst->timer, delay / 2); - /* This callback size returned is the size in the play buffer. - * For 8-bit samples, callbacksize of user buffer should be - * half of the callbacksize in play buffer. */ - if (wave_in->wave_fmt.bitsperchannel == 8) - wiinst->fragment_size >>= 1; + wiinst->state = WAVE_STATE_OPEN; - wave_in->callbacksize = wiinst->fragment_size; - - emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc); - - bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); - delay = (48000 * wave_in->callbacksize) / bytespersec; - - if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; - } - - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_in *wave_in = wave_dev->wiinst->wave_in; + struct wiinst *wiinst = wave_dev->wiinst; unsigned long flags; - if (wave_in->state != CARDWAVE_STATE_STOPPED) - emu10k1_wavein_stop(wave_dev); + DPF(2, "emu10k1_wavein_close()\n"); - if (wave_in->timer != NULL) - emu10k1_timer_uninstall(card, wave_in->timer); + emu10k1_wavein_stop(wave_dev); - if (wave_in->memhandle != NULL) - dealloc_recbuffer(wave_in); + emu10k1_timer_uninstall(card, &wiinst->timer); - if (wave_in->rec_ptr != NULL) - kfree(wave_in->rec_ptr); + free_buffer(card, &wiinst->buffer); spin_lock_irqsave(&card->lock, flags); switch (wave_dev->wiinst->recsrc) { case WAVERECORD_AC97: - card->wavein->ac97 = NULL; + card->wavein.ac97 = NULL; break; case WAVERECORD_MIC: - card->wavein->mic = NULL; + card->wavein.mic = NULL; break; case WAVERECORD_FX: - card->wavein->fx = NULL; + card->wavein.fx = NULL; break; default: + BUG(); break; } spin_unlock_irqrestore(&card->lock, flags); - kfree(wave_in); - wave_dev->wiinst->wave_in = NULL; + wiinst->state = WAVE_STATE_CLOSED; return; } void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev) { - struct wave_in *wave_in = wave_dev->wiinst->wave_in; + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; DPF(2, "emu10k1_wavein_start()\n"); - if (wave_in->state == CARDWAVE_STATE_STARTED) - return; + emu10k1_start_record(card, &wiinst->buffer); + emu10k1_timer_enable(wave_dev->card, &wiinst->timer); - emu10k1_start_record(wave_in->rec_ptr); - wave_in->state = CARDWAVE_STATE_STARTED; + wiinst->buffer.hw_pos = 0; + wiinst->buffer.pos = 0; + wiinst->buffer.bytestocopy = 0; - emu10k1_timer_enable(wave_dev->card, wave_in->timer); + wiinst->state |= WAVE_STATE_STARTED; return; } void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev) { - struct wave_in *wave_in = wave_dev->wiinst->wave_in; + struct emu10k1_card *card = wave_dev->card; + struct wiinst *wiinst = wave_dev->wiinst; DPF(2, "emu10k1_wavein_stop()\n"); - emu10k1_stop_record(wave_in->rec_ptr); - emu10k1_timer_disable(wave_dev->card, wave_in->timer); + if (!(wiinst->state & WAVE_STATE_STARTED)) + return; + + emu10k1_timer_disable(card, &wiinst->timer); + emu10k1_stop_record(card, &wiinst->buffer); - wave_in->rec_ptr->recpos = 0; - wave_in->state = CARDWAVE_STATE_STOPPED; + wiinst->state &= ~WAVE_STATE_STARTED; return; } -int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev) +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format) { struct emu10k1_card *card = wave_dev->card; struct wiinst *wiinst = wave_dev->wiinst; - struct wave_in *wave_in = wiinst->wave_in; - u32 bytespersec, delay; + u32 delay; DPF(2, "emu10k1_wavein_setformat()\n"); - query_format(wiinst->recsrc, &wiinst->wave_fmt); + if (wiinst->state & WAVE_STATE_STARTED) + return -1; - if (!wave_in) - return CTSTATUS_SUCCESS; + query_format(wiinst->recsrc, format); - if (wave_in->state == CARDWAVE_STATE_STARTED) { - wiinst->wave_fmt = wave_in->wave_fmt; - return CTSTATUS_SUCCESS; - } + if ((wiinst->format.samplingrate != format->samplingrate) + || (wiinst->format.bitsperchannel != format->bitsperchannel) + || (wiinst->format.channels != format->channels)) { - if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate) - || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel) - || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) { + wiinst->format = *format; - emu10k1_timer_uninstall(card, wave_in->timer); + if (wiinst->state == WAVE_STATE_CLOSED) + return 0; - wave_in->wave_fmt = wiinst->wave_fmt; + wiinst->buffer.size *= wiinst->buffer.cov; - bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate); - delay = (48000 * wave_in->callbacksize) / bytespersec; + if (wiinst->format.bytesperchannel == 1) { + wiinst->buffer.cov = 2; + wiinst->buffer.size /= wiinst->buffer.cov; + } else + wiinst->buffer.cov = 1; - if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_wavein_close(wave_dev); - return CTSTATUS_ERROR; - } + emu10k1_timer_uninstall(card, &wiinst->timer); + + delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; + + emu10k1_timer_install(card, &wiinst->timer, delay / 2); } - return CTSTATUS_SUCCESS; + return 0; } -void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos) +void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size) { - struct record *rec_ptr = wave_in->rec_ptr; - - /* Get position of current address, this is in no. of bytes in play buffer */ - emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos); - - *size = *curpos - rec_ptr->recpos; + struct wavein_buffer *buffer = &wiinst->buffer; - /* Recpos is the actual position in user buffer and play buffer */ - if (*curpos < rec_ptr->recpos) - *size += rec_ptr->recbufsize; + *size = buffer->bytestocopy; - if (!rec_ptr->is_16bit) - *size >>= 1; + if (*size > buffer->size) { + *size = buffer->size; + buffer->pos = buffer->hw_pos; + buffer->bytestocopy = buffer->size; + DPF(1, "buffer overrun\n"); + } return; } -static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size) +static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov) { - u16 sample; - u8 byte; - - while (size--) { - sample = (*srcbuf) + 32767; - byte = (u8) (sample >> 8); - copy_to_user(dstbuf, &byte, 1); - dstbuf++; - srcbuf++; + if (cov == 1) + copy_to_user(dst, src + str, len); + else { + u8 byte; + u32 i; + + src += 1 + 2 * str; + + for (i = 0; i < len; i++) { + byte = src[2 * i] ^ 0x80; + copy_to_user(dst + i, &byte, 1); + } } + + return; } -/* transfer the data from the wave device. */ void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size) { - struct wave_in *wave_in = wiinst->wave_in; - struct record *rec_ptr = wave_in->rec_ptr; + struct wavein_buffer *buffer = &wiinst->buffer; u32 sizetocopy, sizetocopy_now, start; unsigned long flags; - sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size); + sizetocopy = min(buffer->size, *size); *size = sizetocopy; if (!sizetocopy) return; spin_lock_irqsave(&wiinst->lock, flags); + start = buffer->pos; + buffer->pos += sizetocopy; + buffer->pos %= buffer->size; + buffer->bytestocopy -= sizetocopy; + sizetocopy_now = buffer->size - start; - sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2; - - start = rec_ptr->recpos; + spin_unlock_irqrestore(&wiinst->lock, flags); if (sizetocopy > sizetocopy_now) { sizetocopy -= sizetocopy_now; - rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1); - - spin_unlock_irqrestore(&wiinst->lock, flags); - if (rec_ptr->is_16bit) { - copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now); - copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy); - } else { - copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now); - copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy); - } + copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov); + copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov); } else { - if (sizetocopy == sizetocopy_now) - rec_ptr->recpos = 0; - else - rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1); - - spin_unlock_irqrestore(&wiinst->lock, flags); - - if (rec_ptr->is_16bit) - copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy); - else - copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy); + copy_block(data, buffer->addr, start, sizetocopy, buffer->cov); } return; } -/* get the specified control value of the wave device. */ - -int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value) +void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst) { - switch (ctrlid) { - case WAVECURPOS: - /* There is no actual start yet */ - if (wave_in->state == CARDWAVE_STATE_STOPPED) { - *value = 0; - } else { - /* value is in byte units */ - *value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0); - } - - break; + u32 hw_pos; + u32 diff; - default: - return CTSTATUS_ERROR; + /* There is no actual start yet */ + if (!(wiinst->state & WAVE_STATE_STARTED)) { + hw_pos = wiinst->buffer.hw_pos; + } else { + /* hw_pos in byte units */ + hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov; } - return CTSTATUS_SUCCESS; + diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size; + wiinst->total_recorded += diff; + wiinst->buffer.bytestocopy += diff; + + wiinst->buffer.hw_pos = hw_pos; + + return; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardwi.h linux/drivers/sound/emu10k1/cardwi.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardwi.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardwi.h Mon Aug 14 08:32:48 2000 @@ -32,45 +32,42 @@ #define _CARDWI_H #include "icardwav.h" +#include "audio.h" +#include "timer.h" -struct wave_in -{ - struct list_head list; - - u32 state; - struct record *rec_ptr; - struct memhandle *memhandle; - struct emu_timer *timer; - u32 callbacksize; - struct wave_format wave_fmt; +struct wavein_buffer { + u16 ossfragshift; + u32 fragment_size; + u32 numfrags; + u32 hw_pos; /* hardware cursor position */ + u32 pos; /* software cursor position */ + u32 bytestocopy; /* bytes of recorded data available */ + u32 size; + u32 sizereg; + u32 sizeregval; + u32 addrreg; + u32 idxreg; + u32 adcctl; + void *addr; + u8 cov; + dma_addr_t dma_handle; }; struct wiinst { - struct wave_in *wave_in; - struct wave_format wave_fmt; - u16 ossfragshift; - u32 fragment_size; - u32 numfrags; + u8 state; + struct emu_timer timer; + struct wave_format format; + struct wavein_buffer buffer; wait_queue_head_t wait_queue; - int mapped; - u32 total_recorded; + u8 mmapped; + u32 total_recorded; /* total bytes read() from device */ u32 blocks; - u32 curpos; spinlock_t lock; u8 recsrc; + u16 fxwc; }; -struct emu10k1_wavein -{ - struct wave_in *ac97; - struct wave_in *mic; - struct wave_in *fx; - - u8 recsrc; -}; - - #define WAVEIN_MAXBUFSIZE 65536 #define WAVEIN_MINBUFSIZE 368 @@ -83,10 +80,10 @@ void emu10k1_wavein_close(struct emu10k1_wavedevice *); void emu10k1_wavein_start(struct emu10k1_wavedevice *); void emu10k1_wavein_stop(struct emu10k1_wavedevice *); -void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *); +void emu10k1_wavein_getxfersize(struct wiinst *, u32 *); void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *); -int emu10k1_wavein_setformat(struct emu10k1_wavedevice *); -int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *); +int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *); +void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *); #endif /* _CARDWI_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardwo.c linux/drivers/sound/emu10k1/cardwo.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardwo.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardwo.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * cardwo.c - PCM output HAL for emu10k1 driver @@ -30,47 +29,17 @@ ********************************************************************** */ +#include #include "hwaccess.h" +#include "8010.h" +#include "voicemgr.h" #include "cardwo.h" #include "audio.h" -/* Volume calcs */ - -static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left) +static u32 samplerate_to_linearpitch(u32 samplingrate) { - /* only applicable for playback */ - u32 volL, volR, vol = 0; - - volL = (wave_out->localvol & 0xffff); - volR = ((wave_out->localvol >> 16) & 0xffff); - - if (wave_out->globalvolFactor) { - volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff; - volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff; - } - - /* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */ - /* New volume and pan */ - - if (volL == volR) { - vol = volL; - left->send_c = 0xff; - left->send_b = 0xff; - } else { - if (volL > volR) { - vol = volL; - left->send_c = 0xff; - left->send_b = (char) ((volR * 255) / vol); - } else { - vol = volR; - left->send_b = 0xff; - left->send_c = (char) ((volL * 255) / vol); - } - } - - left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); - - return vol; + samplingrate = (samplingrate << 8) / 375; + return (samplingrate >> 1) + (samplingrate & 1); } static void query_format(struct wave_format *wave_fmt) @@ -78,593 +47,404 @@ if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) wave_fmt->channels = 2; - if (wave_fmt->samplingrate >= 0x2EE00) - wave_fmt->samplingrate = 0x2EE00; + if (wave_fmt->samplingrate >= 0x2ee00) + wave_fmt->samplingrate = 0x2ee00; if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16)) wave_fmt->bitsperchannel = 16; + wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; + wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel; + wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate; + return; } -static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer) +static int alloc_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer) { - u32 numpages, reqsize, pageindex, pagecount; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + u32 pageindex, pagecount; unsigned long busaddx; int i; - reqsize = *size; - numpages = reqsize / PAGE_SIZE; - - /* If size is not a multiple of PAGE_SIZE then we need to round up */ - if (reqsize % PAGE_SIZE) - numpages += 1; - - DPD(2, "requested pages is: %d\n", numpages); - - wavexferbuf->numpages = numpages; - - /* Only for playback, request for emu address space */ - /* Support non page-aligned buffer, don't need interpolation page */ + DPD(2, "requested pages is: %d\n", buffer->pages); - if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0) - return CTSTATUS_ERROR; - - if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL) - return CTSTATUS_ERROR; + if ((buffer->emupageindex = emu10k1_addxmgr_alloc(buffer->pages * PAGE_SIZE, card)) < 0) + return -1; /* Fill in virtual memory table */ - for (pagecount = 0; pagecount < numpages; pagecount++) { - if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) { - wavexferbuf->numpages = pagecount; - return CTSTATUS_ERROR; + for (pagecount = 0; pagecount < buffer->pages; pagecount++) { + if ((buffer->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &buffer->dma_handle[pagecount])) == NULL) { + buffer->pages = pagecount; + return -1; } - DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]); + DPD(2, "Virtual Addx: %p\n", buffer->addr[pagecount]); for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { - busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE); + busaddx = buffer->dma_handle[pagecount] + i * EMUPAGESIZE; DPD(3, "Bus Addx: %lx\n", busaddx); - pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; - ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex; + ((u32 *) card->virtualpagetable.addr)[pageindex] = (busaddx * 2) | pageindex; } } - *buffer = wave_out->pagetable; - - return CTSTATUS_SUCCESS; -} - -static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size) -{ - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - void **buffer; - - wavexferbuf->xferpos = 0; - wavexferbuf->silence_xferpos = 0; - wavexferbuf->stopposition = 0; - wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; - wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; - wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); - - if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS) - return CTSTATUS_ERROR; - - /* xferbufsize contains actual transfer buffer size */ - wavexferbuf->xferbufsize = *size; - wavexferbuf->xferbuffer = buffer; - - return CTSTATUS_SUCCESS; + return 0; } -static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out) +static void free_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer) { u32 pagecount, pageindex; int i; - if (wave_out->pagetable != NULL) { - for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) { - free_page((unsigned long) wave_out->pagetable[pagecount]); - - for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { - pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; - ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex; - } + if (buffer->emupageindex < 0) + return; + + for (pagecount = 0; pagecount < buffer->pages; pagecount++) { + pci_free_consistent(card->pci_dev, PAGE_SIZE, buffer->addr[pagecount], buffer->dma_handle[pagecount]); + + for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) { + pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i; + ((u32 *) card->virtualpagetable.addr)[pageindex] = (card->silentpage.dma_handle * 2) | pageindex; } - kfree(wave_out->pagetable); } - emu10k1_addxmgr_free(card, wave_out->emupageindex); + emu10k1_addxmgr_free(card, buffer->emupageindex); + buffer->emupageindex = -1; return; } -static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device) +static int get_voice(struct emu10k1_card *card, struct woinst *woinst) { - struct emu10k1_waveout *card_waveout = card->waveout; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - struct voice_allocdesc voice_allocdesc; - struct voice_param *left, *right; - u32 size; - + struct emu_voice *voice = &woinst->voice; /* Allocate voices here, if no voices available, return error. * Init voice_allocdesc first.*/ - voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK; - - voice_allocdesc.flags = 0; - - if (device == 1) - voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2; - - if (wave_out->wave_fmt.channels == 1) - voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO; + voice->usage = VOICE_USAGE_PLAYBACK; - if (wave_out->wave_fmt.bitsperchannel == 16) - voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT; + voice->flags = 0; - if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL) - return CTSTATUS_ERROR; + if (woinst->format.channels == 2) + voice->flags |= VOICE_FLAGS_STEREO; - /* voice initialization */ + if (woinst->format.bitsperchannel == 16) + voice->flags |= VOICE_FLAGS_16BIT; - left = &wave_out->voice->params; + if (emu10k1_voice_alloc(card, voice) < 0) + return -1; /* Calculate pitch */ - left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8); + voice->initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8); + voice->pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate); - DPD(2, "Initial pitch --> %x\n", left->initial_pitch); + DPD(2, "Initial pitch --> 0x%x\n", voice->initial_pitch); - /* Easy way out.. gotta calculate value */ - left->pitch_target = 0; - left->volume_target = 0; - left->FC_target = 0; + voice->startloop = (woinst->buffer.emupageindex << 12) / woinst->format.bytespersample; + voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespersample; + voice->start = voice->startloop; + + if (voice->flags & VOICE_FLAGS_STEREO) { + voice->params[0].send_a = card->waveout.send_a[1]; + voice->params[0].send_b = card->waveout.send_b[1]; + voice->params[0].send_c = card->waveout.send_c[1]; + voice->params[0].send_d = card->waveout.send_d[1]; - left->byampl_env_sustain = 0x7f; - left->byampl_env_decay = 0x7f; + if (woinst->device) + voice->params[0].send_routing = 0xd23c; + else + voice->params[0].send_routing = card->waveout.send_routing[1]; - if (wave_out->globalreverbFactor) { - u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff); + voice->params[0].volume_target = 0xffff; + voice->params[0].initial_fc = 0xff; + voice->params[0].initial_attn = 0x00; + voice->params[0].byampl_env_sustain = 0x7f; + voice->params[0].byampl_env_decay = 0x7f; + + voice->params[1].send_a = card->waveout.send_a[2]; + voice->params[1].send_b = card->waveout.send_b[2]; + voice->params[1].send_c = card->waveout.send_c[2]; + voice->params[1].send_d = card->waveout.send_d[2]; - left->send_a = (t > 255) ? 255 : t; - } else { - left->send_a = 0; - } - - if (wave_out->globalchorusFactor) { - u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff); + if (woinst->device) + voice->params[1].send_routing = 0xd23c; + else + voice->params[1].send_routing = card->waveout.send_routing[2]; - left->send_d = (t > 255) ? 255 : t; + voice->params[1].volume_target = 0xffff; + voice->params[1].initial_fc = 0xff; + voice->params[1].initial_attn = 0x00; + voice->params[1].byampl_env_sustain = 0x7f; + voice->params[1].byampl_env_decay = 0x7f; } else { - left->send_d = 0; - } - - set_volume_instance(card_waveout, wave_out, left); - - left->pan_target = left->send_c; - left->aux_target = left->send_b; - - size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample; - left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample; - left->end = left->start + size; - left->startloop = left->start; - left->endloop = left->end; - - if (wave_out->voice->linked_voice) { - DPF(2, "is stereo\n"); - right = &wave_out->voice->linked_voice->params; - - right->initial_pitch = left->initial_pitch; - - /* Easy way out.. gotta calculate value */ - right->pitch_target = 0; - right->volume_target = 0; - right->FC_target = 0; - - right->byampl_env_sustain = 0x7f; - right->byampl_env_decay = 0x7f; - - right->send_d = left->send_d; - right->send_a = left->send_a; - - /* Left output of right channel is always zero */ - right->send_c = 0; - - /* Update right channel aux */ - right->pan_target = 0; - right->send_b = left->send_b; - right->aux_target = right->send_b; - - /* Zero out right output of left channel */ - left->send_b = 0; - left->aux_target = 0; + voice->params[0].send_a = card->waveout.send_a[0]; + voice->params[0].send_b = card->waveout.send_b[0]; + voice->params[0].send_c = card->waveout.send_c[0]; + voice->params[0].send_d = card->waveout.send_d[0]; - /* Update right channel attenuation */ - right->initial_attn = left->initial_attn; - - right->start = left->start; - right->end = left->end; - right->startloop = left->startloop; - right->endloop = left->endloop; + if (woinst->device) + voice->params[0].send_routing = 0xd23c; + else + voice->params[0].send_routing = card->waveout.send_routing[0]; + voice->params[0].volume_target = 0xffff; + voice->params[0].initial_fc = 0xff; + voice->params[0].initial_attn = 0x00; + voice->params[0].byampl_env_sustain = 0x7f; + voice->params[0].byampl_env_decay = 0x7f; } - DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop); + DPD(2, "voice: startloop=0x%x, endloop=0x%x\n", voice->startloop, voice->endloop); + + emu10k1_voice_playback_setup(voice); - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out; - u32 bytespersec, delay; - u32 buffsize; + u32 delay; DPF(2, "emu10k1_waveout_open()\n"); - if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } - - woinst->wave_out = wave_out; - - /* Init channel object */ - wave_out->state = CARDWAVE_STATE_STOPPED; - wave_out->wave_fmt = woinst->wave_fmt; - wave_out->voice = NULL; - wave_out->emupageindex = -1; - wave_out->wavexferbuf = NULL; - wave_out->pagetable = NULL; - wave_out->timer = NULL; - - /* Assign default local volume */ - /* FIXME: Should we be maxing the initial values like this? */ - wave_out->localvol = 0xffffffff; - wave_out->localreverb = 0xffffffff; - wave_out->localchorus = 0xffffffff; - wave_out->globalvolFactor = 0xffff; - wave_out->globalreverbFactor = 0xffff; - wave_out->globalchorusFactor = 0xffff; - - wave_out->setpos = 0; - wave_out->position = 0; - - wave_out->fill_silence = 0; - - if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) { + if (alloc_buffer(card, &woinst->buffer) < 0) { ERROR(); emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - buffsize = woinst->fragment_size * woinst->numfrags; + woinst->buffer.fill_silence = 0; + woinst->buffer.silence_bytes = 0; + woinst->buffer.silence_pos = 0; + woinst->buffer.hw_pos = 0; + woinst->buffer.bytestocopy = woinst->buffer.size; - if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) { + if (get_voice(card, woinst) < 0) { ERROR(); emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - woinst->fragment_size = buffsize / woinst->numfrags; - wave_out->callbacksize = woinst->fragment_size; + delay = (48000 * woinst->buffer.fragment_size) / woinst->format.bytespersec; - if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } + emu10k1_timer_install(card, &woinst->timer, delay / 2); - bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); - delay = (48000 * wave_out->callbacksize) / bytespersec; + woinst->state = WAVE_STATE_OPEN; - if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } - - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_out *wave_out = wave_dev->woinst->wave_out; + struct woinst *woinst = wave_dev->woinst; DPF(2, "emu10k1_waveout_close()\n"); - if (wave_out->state != CARDWAVE_STATE_STOPPED) - emu10k1_waveout_stop(wave_dev); - - if (wave_out->timer != NULL) - emu10k1_timer_uninstall(card, wave_out->timer); + emu10k1_waveout_stop(wave_dev); - if (wave_out->voice != NULL) - emu10k1_voice_free(&card->voicemgr, wave_out->voice); + emu10k1_timer_uninstall(card, &woinst->timer); - if (wave_out->emupageindex >= 0) - dealloc_xferbuffer(card, wave_out); + emu10k1_voice_free(&woinst->voice); - if (wave_out->wavexferbuf != NULL) - kfree(wave_out->wavexferbuf); + free_buffer(card, &woinst->buffer); - kfree(wave_out); - wave_dev->woinst->wave_out = NULL; + woinst->state = WAVE_STATE_CLOSED; return; } -int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) +void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_out *wave_out = wave_dev->woinst->wave_out; - u32 start, startPosition; + struct woinst *woinst = wave_dev->woinst; DPF(2, "emu10k1_waveout_start()\n"); - - /* If already started, return success */ - if (wave_out->state == CARDWAVE_STATE_STARTED) - return CTSTATUS_SUCCESS; - - if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos) - startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample); - else - startPosition = wave_out->wavexferbuf->stopposition; - - start = wave_out->voice->params.start; - wave_out->voice->params.start += startPosition; - - DPD(2, "CA is %x\n", wave_out->voice->params.start); - - emu10k1_voice_playback_setup(wave_out->voice); - - wave_out->voice->params.start = start; - /* Actual start */ - emu10k1_voice_start(wave_out->voice); - wave_out->state = CARDWAVE_STATE_STARTED; - wave_out->setpos = 0; + emu10k1_voice_start(&woinst->voice, woinst->total_played); + + emu10k1_timer_enable(card, &woinst->timer); - emu10k1_timer_enable(card, wave_out->timer); + woinst->state |= WAVE_STATE_STARTED; - return CTSTATUS_SUCCESS; + return; } -int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev) +int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format) { struct emu10k1_card *card = wave_dev->card; struct woinst *woinst = wave_dev->woinst; - struct wave_out *wave_out = woinst->wave_out; - u32 bytespersec, delay; + u32 delay; DPF(2, "emu10k1_waveout_setformat()\n"); - query_format(&woinst->wave_fmt); - - if (wave_out == NULL) - return CTSTATUS_SUCCESS; - - if (wave_out->state == CARDWAVE_STATE_STARTED) { - woinst->wave_fmt = wave_out->wave_fmt; - return CTSTATUS_SUCCESS; - } + if (woinst->state & WAVE_STATE_STARTED) + return -1; - if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate) - || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel) - || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) { - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + query_format(format); - emu10k1_timer_uninstall(card, wave_out->timer); + if (woinst->format.samplingrate != format->samplingrate || + woinst->format.channels != format->channels || + woinst->format.bitsperchannel != format->bitsperchannel) { - emu10k1_voice_free(&card->voicemgr, wave_out->voice); + woinst->format = *format; - wave_out->wave_fmt = woinst->wave_fmt; - wave_out->timer = NULL; + if (woinst->state == WAVE_STATE_CLOSED) + return 0; - wavexferbuf->xferpos = 0; - wavexferbuf->silence_xferpos = 0; - wavexferbuf->stopposition = 0; - wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0; - wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0; - wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1); + emu10k1_timer_uninstall(card, &woinst->timer); + emu10k1_voice_free(&woinst->voice); - if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) { + if (get_voice(card, woinst) < 0) { ERROR(); emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; + return -1; } - bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate); - delay = (48000 * wave_out->callbacksize) / bytespersec; + delay = (48000 * woinst->buffer.fragment_size) / woinst->format.bytespersec; - if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) { - ERROR(); - emu10k1_waveout_close(wave_dev); - return CTSTATUS_ERROR; - } + emu10k1_timer_install(card, &woinst->timer, delay / 2); } - return CTSTATUS_SUCCESS; + return 0; } void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev) { struct emu10k1_card *card = wave_dev->card; - struct wave_out *wave_out = wave_dev->woinst->wave_out; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - u32 samples = 32; - u32 position; + struct woinst *woinst = wave_dev->woinst; DPF(2, "emu10k1_waveout_stop()\n"); - if (wave_out->state == CARDWAVE_STATE_STOPPED) + if (!(woinst->state & WAVE_STATE_STARTED)) return; - emu10k1_timer_disable(card, wave_out->timer); + emu10k1_timer_disable(card, &woinst->timer); /* Stop actual voice */ - emu10k1_voice_stop(wave_out->voice); - - /* Save the stop position */ - emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition); - - wavexferbuf->stopposition -= wave_out->voice->params.start; - - /* Refer to voicemgr.c, CA is not started at zero. We need to take this into account. */ - position = wavexferbuf->stopposition * wavexferbuf->bytespersample; - - if (!wavexferbuf->is_16bit) - samples <<= 1; + emu10k1_voice_stop(&woinst->voice); - if (wavexferbuf->is_stereo) - samples <<= 1; + emu10k1_waveout_update(woinst); - samples -= 4; - - if (position >= samples * (wavexferbuf->is_16bit + 1)) - position -= samples * (wavexferbuf->is_16bit + 1); - else - position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1); - - wavexferbuf->stopposition = position / wavexferbuf->bytespersample; - - DPD(2, "position is %x\n", wavexferbuf->stopposition); - - wave_out->state = CARDWAVE_STATE_STOPPED; - wave_out->setpos = 0; - wave_out->position = 0; + woinst->state &= ~WAVE_STATE_STARTED; return; } -void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos) +void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 * size) { - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; - - /* Get position of current address, this is in no. of bytes in play buffer */ - emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos); + struct waveout_buffer *buffer = &woinst->buffer; + int pending; - if ((*curpos > wavexferbuf->silence_xferpos) - || ((*curpos == wavexferbuf->silence_xferpos) - && (wave_out->state == CARDWAVE_STATE_STARTED)) - || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0) - && (wave_out->state == CARDWAVE_STATE_STOPPED))) { - *size = *curpos - wavexferbuf->silence_xferpos; - *pending = wavexferbuf->xferbufsize - *size; - } else { - *pending = wavexferbuf->silence_xferpos - *curpos; - *size = wavexferbuf->xferbufsize - *pending; + if (woinst->mmapped) { + *size = buffer->bytestocopy; + return; } - if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) { - if (*pending < wave_out->callbacksize) { - wave_out->fill_silence = 2; - *pending = 0; - *size = wavexferbuf->xferbufsize; - wavexferbuf->xferpos = *curpos; - } else { - if (wave_out->fill_silence == 2) { - *pending = 0; - *size = wavexferbuf->xferbufsize; - wavexferbuf->xferpos = *curpos; - } else { - *pending -= wave_out->callbacksize; - *size += wave_out->callbacksize; - } - } + pending = buffer->size - buffer->bytestocopy; + + buffer->fill_silence = (pending < (signed) buffer->fragment_size) ? 1 : 0; + + if (pending > (signed) buffer->silence_bytes) { + *size = buffer->bytestocopy + buffer->silence_bytes; } else { - if (*pending < wave_out->callbacksize) - wave_out->fill_silence = 1; - else - wave_out->fill_silence = 0; + *size = buffer->size; + buffer->silence_bytes = pending; + if (pending < 0) { + buffer->silence_pos = buffer->hw_pos; + buffer->silence_bytes = 0; + buffer->bytestocopy = buffer->size; + DPF(1, "buffer underrun\n"); + } } return; } -static void copy_block(u32 dst, u8 * src, u32 len, void **pt) +static void copy_block(void **dst, u32 str, u8 *src, u32 len) { int i, j, k; - i = dst / PAGE_SIZE; - j = dst % PAGE_SIZE; - k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; - copy_from_user(pt[i] + j, src, k); - len -= k; - while (len >= PAGE_SIZE) { - copy_from_user(pt[++i], src + k, PAGE_SIZE); - k += PAGE_SIZE; - len -= PAGE_SIZE; - } - copy_from_user(pt[++i], src + k, len); + i = str / PAGE_SIZE; + j = str % PAGE_SIZE; + + if (len > PAGE_SIZE - j) { + k = PAGE_SIZE - j; + copy_from_user(dst[i] + j, src, k); + len -= k; + while (len > PAGE_SIZE) { + copy_from_user(dst[++i], src + k, PAGE_SIZE); + k += PAGE_SIZE; + len -= PAGE_SIZE; + } + copy_from_user(dst[++i], src + k, len); + + } else + copy_from_user(dst[i] + j, src, len); return; } -static void fill_block(u32 dst, u8 val, u32 len, void **pt) +static void fill_block(void **dst, u32 str, u8 src, u32 len) { int i, j, k; - i = dst / PAGE_SIZE; - j = dst % PAGE_SIZE; - k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len; - memset(pt[i] + j, val, k); - len -= k; - while (len >= PAGE_SIZE) { - memset(pt[++i], val, PAGE_SIZE); - len -= PAGE_SIZE; - } - memset(pt[++i], val, len); + i = str / PAGE_SIZE; + j = str % PAGE_SIZE; + + if (len > PAGE_SIZE - j) { + k = PAGE_SIZE - j; + memset(dst[i] + j, src, k); + len -= k; + while (len > PAGE_SIZE) { + memset(dst[++i], src, PAGE_SIZE); + len -= PAGE_SIZE; + } + memset(dst[++i], src, len); + + } else + memset(dst[i] + j, src, len); return; } -void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size) +void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size) { - struct wave_out *wave_out = woinst->wave_out; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + struct waveout_buffer *buffer = &woinst->buffer; u32 sizetocopy, sizetocopy_now, start; unsigned long flags; - sizetocopy = min(wavexferbuf->xferbufsize, *size); + sizetocopy = min(buffer->size, *size); *size = sizetocopy; if (!sizetocopy) return; spin_lock_irqsave(&woinst->lock, flags); + start = (buffer->size + buffer->silence_pos - buffer->silence_bytes) % buffer->size; - sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos; + if(sizetocopy > buffer->silence_bytes) { + buffer->silence_pos += sizetocopy - buffer->silence_bytes; + buffer->bytestocopy -= sizetocopy - buffer->silence_bytes; + buffer->silence_bytes = 0; + } else + buffer->silence_bytes -= sizetocopy; - start = wavexferbuf->xferpos; + sizetocopy_now = buffer->size - start; + + spin_unlock_irqrestore(&woinst->lock, flags); if (sizetocopy > sizetocopy_now) { sizetocopy -= sizetocopy_now; - wavexferbuf->xferpos = sizetocopy; - wavexferbuf->silence_xferpos = wavexferbuf->xferpos; - spin_unlock_irqrestore(&woinst->lock, flags); - - copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer); - copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer); + copy_block(buffer->addr, start, data, sizetocopy_now); + copy_block(buffer->addr, 0, data + sizetocopy_now, sizetocopy); } else { - if (sizetocopy == sizetocopy_now) - wavexferbuf->xferpos = 0; - else - wavexferbuf->xferpos += sizetocopy; - - wavexferbuf->silence_xferpos = wavexferbuf->xferpos; - spin_unlock_irqrestore(&woinst->lock, flags); - - copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer); + copy_block(buffer->addr, start, data, sizetocopy); } return; @@ -672,84 +452,63 @@ void emu10k1_waveout_fillsilence(struct woinst *woinst) { - struct wave_out *wave_out = woinst->wave_out; - struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf; + struct waveout_buffer *buffer = &woinst->buffer; u16 filldata; u32 sizetocopy, sizetocopy_now, start; unsigned long flags; - sizetocopy = wave_out->callbacksize; + sizetocopy = woinst->buffer.fragment_size; - if (wave_out->wave_fmt.bitsperchannel == 8) - filldata = 0x8080; - else + if (woinst->format.bitsperchannel == 16) filldata = 0x0000; + else + filldata = 0x8080; spin_lock_irqsave(&woinst->lock, flags); + buffer->silence_bytes += sizetocopy; + buffer->bytestocopy -= sizetocopy; + buffer->silence_pos %= buffer->size; + start = buffer->silence_pos; + buffer->silence_pos += sizetocopy; + sizetocopy_now = buffer->size - start; - sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos; - start = wavexferbuf->silence_xferpos; + spin_unlock_irqrestore(&woinst->lock, flags); if (sizetocopy > sizetocopy_now) { sizetocopy -= sizetocopy_now; - wavexferbuf->silence_xferpos = sizetocopy; - spin_unlock_irqrestore(&woinst->lock, flags); - fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer); - fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer); + fill_block(buffer->addr, start, filldata, sizetocopy_now); + fill_block(buffer->addr, 0, filldata, sizetocopy); } else { - if (sizetocopy == sizetocopy_now) - wavexferbuf->silence_xferpos = 0; - else - wavexferbuf->silence_xferpos += sizetocopy; - - spin_unlock_irqrestore(&woinst->lock, flags); - - fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer); + fill_block(buffer->addr, start, filldata, sizetocopy); } return; } -/* get the specified control value of the wave device. */ - -int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value) +void emu10k1_waveout_update(struct woinst *woinst) { - switch (ctrl_id) { - case WAVECURPOS: - /* There is no actual start yet */ - if (wave_out->state == CARDWAVE_STATE_STOPPED) { - if (wave_out->setpos) - *value = wave_out->position; - else - *value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample; - } else { - emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value); - - *value -= wave_out->voice->params.start; + u32 hw_pos; + u32 diff; - /* Get number of bytes in play buffer per channel. - * If 8 bit mode is enabled, this needs to be changed. */ - { - u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1); - - *value *= wave_out->wavexferbuf->bytespersample; - - /* Refer to voicemgr.c, CA is not started at zero. - * We need to take this into account. */ - - samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1); + /* There is no actual start yet */ + if (!(woinst->state & WAVE_STATE_STARTED)) { + hw_pos = woinst->buffer.hw_pos; + } else { + /* hw_pos in sample units */ + hw_pos = sblive_readptr(woinst->voice.card, CCCA_CURRADDR, woinst->voice.num); - if (*value >= samples) - *value -= samples; - else - *value += wave_out->wavexferbuf->xferbufsize - samples; - } - } + if(hw_pos < woinst->voice.start) + hw_pos += woinst->buffer.size / woinst->format.bytespersample - woinst->voice.start; + else + hw_pos -= woinst->voice.start; - break; - default: - return CTSTATUS_ERROR; + hw_pos *= woinst->format.bytespersample; } - return CTSTATUS_SUCCESS; + diff = (woinst->buffer.size + hw_pos - woinst->buffer.hw_pos) % woinst->buffer.size; + woinst->total_played += diff; + woinst->buffer.bytestocopy += diff; + woinst->buffer.hw_pos = hw_pos; + + return; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/cardwo.h linux/drivers/sound/emu10k1/cardwo.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/cardwo.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/cardwo.h Mon Aug 14 08:32:48 2000 @@ -33,86 +33,59 @@ #define _CARDWO_H #include "icardwav.h" +#include "audio.h" +#include "voicemgr.h" +#include "timer.h" -struct wave_xferbuf -{ - u32 xferpos; - u32 silence_xferpos; - u32 xferbufsize; /* transfer buffer size */ - u32 numpages; /* number of pages in transfer buffer */ - void **xferbuffer; /* pointer to the transfer buffer */ - int is_stereo; - int is_16bit; - int bytespersample; - u32 stopposition; -}; - -struct wave_out -{ - u32 state; - struct emu_voice *voice; - int emupageindex; - struct emu_timer *timer; - struct wave_xferbuf *wavexferbuf; - void **pagetable; - u32 callbacksize; - u32 localvol; - u32 localreverb; - u32 localchorus; - u32 globalvolFactor; - u32 globalreverbFactor; - u32 globalchorusFactor; - int setpos; - u32 position; - struct wave_format wave_fmt; - int fill_silence; -}; +/* setting this to other than a power of two may break some applications */ +#define WAVEOUT_MAXBUFSIZE MAXBUFSIZE +#define WAVEOUT_MINBUFSIZE 64 -/* setting this to other than a power of two - may break some applications */ -#define WAVEOUT_MAXBUFSIZE 32768 -#define WAVEOUT_MINBUFSIZE 64 +#define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */ +#define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */ -#define WAVEOUT_DEFAULTFRAGLEN 100 /* Time to play a fragment in ms (latency) */ -#define WAVEOUT_DEFAULTBUFLEN 1000 /* Time to play the entire buffer in ms */ +#define WAVEOUT_MINFRAGSHIFT 6 -#define WAVEOUT_MINFRAGSHIFT 4 +struct waveout_buffer { + u16 ossfragshift; + u32 numfrags; + u32 fragment_size; /* in bytes units */ + u32 size; /* in bytes units */ + u32 pages; /* buffer size in page units*/ + int emupageindex; + void *addr[BUFMAXPAGES]; + dma_addr_t dma_handle[BUFMAXPAGES]; + u32 silence_pos; /* software cursor position (including silence) */ + u32 hw_pos; /* hardware cursor position */ + u32 bytestocopy; /* free space on buffer (including silence) */ + u8 fill_silence; + u32 silence_bytes; /* silence bytes in buffer */ +}; struct woinst { - struct wave_out *wave_out; - struct wave_format wave_fmt; - u16 ossfragshift; - u32 fragment_size; - u32 numfrags; + u8 state; + struct emu_voice voice; + struct emu_timer timer; + struct wave_format format; + struct waveout_buffer buffer; wait_queue_head_t wait_queue; - int mapped; - u32 total_copied; - u32 total_played; + u8 mmapped; + u32 total_copied; /* total number of bytes written() to the buffer (excluding silence) */ + u32 total_played; /* total number of bytes played including silence */ u32 blocks; - u32 curpos; - u32 device; + u8 device; spinlock_t lock; }; -struct emu10k1_waveout -{ - u32 globalvol; - u32 mute; - u32 left; - u32 right; - u32 globalreverb; - u32 globalchorus; -}; - int emu10k1_waveout_open(struct emu10k1_wavedevice *); void emu10k1_waveout_close(struct emu10k1_wavedevice *); -int emu10k1_waveout_start(struct emu10k1_wavedevice *); +void emu10k1_waveout_start(struct emu10k1_wavedevice *); void emu10k1_waveout_stop(struct emu10k1_wavedevice *); -void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *); +void emu10k1_waveout_getxfersize(struct woinst*, u32 *); void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *); void emu10k1_waveout_fillsilence(struct woinst*); -int emu10k1_waveout_setformat(struct emu10k1_wavedevice*); -int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *); +int emu10k1_waveout_setformat(struct emu10k1_wavedevice*, struct wave_format*); +void emu10k1_waveout_update(struct woinst*); #endif /* _CARDWO_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/ecard.c linux/drivers/sound/emu10k1/ecard.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/ecard.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/ecard.c Mon Aug 14 08:32:48 2000 @@ -0,0 +1,155 @@ +/* + ********************************************************************** + * ecard.c - E-card initialization code + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * Date Author Summary of changes + * ---- ------ ------------------ + * October 20, 1999 Bertrand Lee base code release + * + ********************************************************************** + * + * 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. + * + ********************************************************************** + */ + +#include "ecard.h" +#include "hwaccess.h" + +/* Private routines */ +static void ecard_setadcgain(struct emu10k1_card *, struct ecard_state *, u16); +static void ecard_write(struct emu10k1_card *, u32); + +/************************************************************************** + * @func Set the gain of the ECARD's CS3310 Trim/gain controller. The + * trim value consists of a 16bit value which is composed of two + * 8 bit gain/trim values, one for the left channel and one for the + * right channel. The following table maps from the Gain/Attenuation + * value in decibels into the corresponding bit pattern for a single + * channel. + */ + +static void ecard_setadcgain(struct emu10k1_card *card, struct ecard_state *ecard, u16 gain) +{ + u32 currbit; + ecard->adc_gain = gain; + + /* Enable writing to the TRIM registers */ + ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN); + + /* Do it again to insure that we meet hold time requirements */ + ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN); + + for (currbit = (1L << 15); currbit; currbit >>= 1) { + + u32 value = ecard->control_bits & ~(EC_TRIM_CSN|EC_TRIM_SDATA); + + if (gain & currbit) + value |= EC_TRIM_SDATA; + + /* Clock the bit */ + ecard_write(card, value); + ecard_write(card, value | EC_TRIM_SCLK); + ecard_write(card, value); + } + + ecard_write(card, ecard->control_bits); +} + +/************************************************************************** + * @func Clock bits into the Ecard's control latch. The Ecard uses a + * control latch will is loaded bit-serially by toggling the Modem control + * lines from function 2 on the E8010. This function hides these details + * and presents the illusion that we are actually writing to a distinct + * register. + */ +static void ecard_write(struct emu10k1_card *card, u32 value) +{ + u16 count; + u32 data, hcvalue; + + hcvalue = emu10k1_readfn0(card, HCFG) & ~(HOOKN_BIT|HANDN_BIT|PULSEN_BIT); + + emu10k1_writefn0(card, HCFG, hcvalue); + + for (count = 0 ; count < EC_NUM_CONTROL_BITS; count++) { + + /* Set up the value */ + data = ((value & 0x1) ? PULSEN_BIT : 0); + value >>= 1; + + emu10k1_writefn0(card, HCFG, hcvalue | data); + + /* Clock the shift register */ + emu10k1_writefn0(card, HCFG, hcvalue | data | HANDN_BIT); + emu10k1_writefn0(card, HCFG, hcvalue | data); + } + + /* Latch the bits */ + emu10k1_writefn0(card, HCFG, hcvalue | HOOKN_BIT); + emu10k1_writefn0(card, HCFG, hcvalue); +} + +int __devinit emu10k1_ecard_init(struct emu10k1_card *card) +{ + u32 hcvalue; + struct ecard_state ecard; + + /* Set up the initial settings */ + ecard.mux0_setting = EC_DEFAULT_SPDIF0_SEL; + ecard.mux1_setting = EC_DEFAULT_SPDIF1_SEL; + ecard.mux2_setting = 0; + ecard.adc_gain = EC_DEFAULT_ADC_GAIN; + ecard.control_bits = EC_RAW_RUN_MODE | + EC_SPDIF0_SELECT(ecard.mux0_setting) | + EC_SPDIF1_SELECT(ecard.mux1_setting); + + + /* Step 0: Set the codec type in the hardware control register + * and enable audio output */ + hcvalue = emu10k1_readfn0(card, HCFG); + emu10k1_writefn0(card, HCFG, hcvalue | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S); + emu10k1_readfn0(card, HCFG); + + /* Step 1: Turn off the led and deassert TRIM_CS */ + ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN); + + /* Step 2: Calibrate the ADC and DAC */ + ecard_write(card, EC_DACCAL | EC_LEDN | EC_TRIM_CSN); + + /* Step 3: Wait for awhile; FIXME: Is this correct? */ + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + + /* Step 4: Switch off the DAC and ADC calibration. Note + * That ADC_CAL is actually an inverted signal, so we assert + * it here to stop calibration. */ + ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN); + + /* Step 4: Switch into run mode */ + ecard_write(card, ecard.control_bits); + + /* Step 5: Set the analog input gain */ + ecard_setadcgain(card, &ecard, ecard.adc_gain); + + return 0; +} + + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/ecard.h linux/drivers/sound/emu10k1/ecard.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/ecard.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/emu10k1/ecard.h Mon Aug 14 08:32:48 2000 @@ -0,0 +1,113 @@ +/* + ********************************************************************** + * ecard.h + * Copyright 1999, 2000 Creative Labs, Inc. + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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 _ECARD_H +#define _ECARD_H + +#include "8010.h" +#include "hwaccess.h" +#include + +/* In A1 Silicon, these bits are in the HC register */ +#define HOOKN_BIT (1L << 12) +#define HANDN_BIT (1L << 11) +#define PULSEN_BIT (1L << 10) + +#define EC_GDI1 (1 << 13) +#define EC_GDI0 (1 << 14) + +#define EC_NUM_CONTROL_BITS 20 + +#define EC_AC3_DATA_SELN 0x0001L +#define EC_EE_DATA_SEL 0x0002L +#define EC_EE_CNTRL_SELN 0x0004L +#define EC_EECLK 0x0008L +#define EC_EECS 0x0010L +#define EC_EESDO 0x0020L +#define EC_TRIM_CSN 0x0040L +#define EC_TRIM_SCLK 0x0080L +#define EC_TRIM_SDATA 0x0100L +#define EC_TRIM_MUTEN 0x0200L +#define EC_ADCCAL 0x0400L +#define EC_ADCRSTN 0x0800L +#define EC_DACCAL 0x1000L +#define EC_DACMUTEN 0x2000L +#define EC_LEDN 0x4000L + +#define EC_SPDIF0_SEL_SHIFT 15 +#define EC_SPDIF1_SEL_SHIFT 17 +#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT) +#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT) +#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK) +#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK) +#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should + * be incremented any time the EEPROM's + * format is changed. */ + +#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */ + +/* Addresses for special values stored in to EEPROM */ +#define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */ +#define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */ +#define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */ + +#define EC_LAST_PROMFILE_ADDR 0x2f + +#define EC_SERIALNUM_ADD 0x30 /* First word of serial number. The number + * can be up to 30 characters in length + * and is stored as a NULL-terminated + * ASCII string. Any unused bytes must be + * filled with zeros */ +#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */ + + + +/* Most of this stuff is pretty self-evident. According to the hardware + * dudes, we need to leave the ADCCAL bit low in order to avoid a DC + * offset problem. Weird. + */ +#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | EC_TRIM_CSN) + + +#define EC_DEFAULT_ADC_GAIN 0xC4C4 +#define EC_DEFAULT_SPDIF0_SEL 0x0 +#define EC_DEFAULT_SPDIF1_SEL 0x4 + +#define HC_EA 0x01L + +/* ECARD state structure. This structure maintains the state + * for various portions of the the ECARD's onboard hardware. + */ +struct ecard_state { + u32 control_bits; + u16 adc_gain; + u16 mux0_setting; + u16 mux1_setting; + u16 mux2_setting; +}; + +int emu10k1_ecard_init(struct emu10k1_card *) __devinit; + +#endif /* _ECARD_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/efxmgr.c linux/drivers/sound/emu10k1/efxmgr.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/efxmgr.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/efxmgr.c Wed Dec 31 16:00:00 1969 @@ -1,34 +0,0 @@ - -/* - ********************************************************************** - * sblive_fx.c - * Copyright 1999, 2000 Creative Labs, Inc. - * - ********************************************************************** - * - * Date Author Summary of changes - * ---- ------ ------------------ - * October 20, 1999 Bertrand Lee base code release - * - ********************************************************************** - * - * 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. - * - ********************************************************************** - */ - -#include "hwaccess.h" -#include "efxmgr.h" diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/emu_wrapper.h linux/drivers/sound/emu10k1/emu_wrapper.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/emu_wrapper.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/emu_wrapper.h Mon Aug 14 08:32:48 2000 @@ -3,9 +3,11 @@ #include -#define UP_INODE_SEM(a) -#define DOWN_INODE_SEM(a) +#define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask)) -#define GET_INODE_STRUCT() +#ifndef PCI_GET_DRIVER_DATA + #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) + #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) +#endif /* PCI_GET_DRIVER_DATA */ #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/emuadxmg.c linux/drivers/sound/emu10k1/emuadxmg.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/emuadxmg.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/emuadxmg.c Mon Aug 14 08:32:48 2000 @@ -44,14 +44,15 @@ /* Convert bytes to pages */ numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0); - while (index < (MAXPAGES - RESERVED - 1)) { + spin_lock_irqsave(&card->lock, flags); + + while (index < (MAXPAGES - 1)) { if (pagetable[index] & 0x8000) { /* This block of pages is in use, jump to the start of the next block. */ index += (pagetable[index] & 0x7fff); } else { /* Found free block */ if (pagetable[index] >= numpages) { - spin_lock_irqsave(&card->lock, flags); /* Block is large enough */ @@ -71,6 +72,8 @@ } } } + + spin_unlock_irqrestore(&card->lock, flags); return -1; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/hwaccess.c linux/drivers/sound/emu10k1/hwaccess.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/hwaccess.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/hwaccess.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * hwaccess.c -- Hardware access layer @@ -31,7 +30,10 @@ ********************************************************************** */ +#include + #include "hwaccess.h" +#include "8010.h" #include "icardmid.h" /************************************************************************* @@ -86,7 +88,7 @@ }; if (sampleRate == 0) - return (0); /* Bail out if no leading "1" */ + return 0; /* Bail out if no leading "1" */ sampleRate *= 11185; /* Scale 48000 to 0x20002380 */ @@ -131,51 +133,58 @@ /******************************************* * write/read PCI function 0 registers * ********************************************/ -void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data) +void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data) { unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - outl(data, card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); - - return; -} - -void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data) -{ - unsigned long flags; + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; - data &= mask; + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + data = (data << offset) & mask; + reg &= 0x7f; - spin_lock_irqsave(&card->lock, flags); - data |= inl(card->iobase + reg) & ~mask; - outl(data, card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); + spin_lock_irqsave(&card->lock, flags); + data |= inl(card->iobase + reg) & ~mask; + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + } else { + spin_lock_irqsave(&card->lock, flags); + outl(data, card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + } return; } -u32 sblive_readfn0(struct emu10k1_card * card, u8 reg) +u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg) { u32 val; unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - val = inl(card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); - return val; -} + if (reg & 0xff000000) { + u32 mask; + u8 size, offset; -u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask) -{ - u32 val; - unsigned long flags; + size = (reg >> 24) & 0x3f; + offset = (reg >> 16) & 0x1f; + mask = ((1 << size) - 1) << offset; + reg &= 0x7f; - spin_lock_irqsave(&card->lock, flags); - val = inl(card->iobase + reg); - spin_unlock_irqrestore(&card->lock, flags); - return val & mask; + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + + return (val & mask) >> offset; + } else { + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + reg); + spin_unlock_irqrestore(&card->lock, flags); + return val; + } } /************************************************************************ @@ -209,6 +218,37 @@ outl(data, card->iobase + DATA); spin_unlock_irqrestore(&card->lock, flags); } +} + +/* ... : data, reg, ... , TAGLIST_END */ +void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...) +{ + va_list args; + + unsigned long flags; + u32 reg; + + va_start(args, channel); + + spin_lock_irqsave(&card->lock, flags); + while ((reg = va_arg(args, u32)) != TAGLIST_END) { + u32 data = va_arg(args, u32); + u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK) + | (channel & PTR_CHANNELNUM_MASK)); + outl(regptr, card->iobase + PTR); + if (reg & 0xff000000) { + int size = (reg >> 24) & 0x3f; + int offset = (reg >> 16) & 0x1f; + u32 mask = ((1 << size) - 1) << offset; + data = (data << offset) & mask; + + data |= inl(card->iobase + DATA) & ~mask; + } + outl(data, card->iobase + DATA); + } + spin_unlock_irqrestore(&card->lock, flags); + + va_end(args); return; } @@ -244,6 +284,34 @@ } } +void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask) +{ + u32 val; + unsigned long flags; + + DPF(2,"emu10k1_irq_enable()\n"); + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + INTE) | irq_mask; + outl(val, card->iobase + INTE); + spin_unlock_irqrestore(&card->lock, flags); + return; +} + +void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask) +{ + u32 val; + unsigned long flags; + + DPF(2,"emu10k1_irq_disable()\n"); + + spin_lock_irqsave(&card->lock, flags); + val = inl(card->iobase + INTE) & ~irq_mask; + outl(val, card->iobase + INTE); + spin_unlock_irqrestore(&card->lock, flags); + return; +} + void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum) { /* Voice interrupt */ @@ -271,11 +339,11 @@ volatile unsigned uCount; u32 newtime = 0, curtime; - curtime = READ_FN0(card, WC_SAMPLECOUNTER); + curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); while (wait--) { uCount = 0; while (uCount++ < TIMEOUT) { - newtime = READ_FN0(card, WC_SAMPLECOUNTER); + newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER); if (newtime != curtime) break; } @@ -293,12 +361,12 @@ spin_lock_irqsave(&card->lock, flags); - outb(index, card->mixeraddx + 2); - *data = inw(card->mixeraddx); + outb(index, card->iobase + AC97ADDRESS); + *data = inw(card->iobase + AC97DATA); spin_unlock_irqrestore(&card->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data) @@ -307,12 +375,12 @@ spin_lock_irqsave(&card->lock, flags); - outb(index, card->mixeraddx + 2); - outw(data, card->mixeraddx); + outb(index, card->iobase + AC97ADDRESS); + outw(data, card->iobase + AC97DATA); spin_unlock_irqrestore(&card->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask) @@ -322,16 +390,16 @@ spin_lock_irqsave(&card->lock, flags); - outb(index, card->mixeraddx + 2); - temp = inw(card->mixeraddx); + outb(index, card->iobase + AC97ADDRESS); + temp = inw(card->iobase + AC97DATA); temp &= ~mask; data &= mask; temp |= data; - outw(temp, card->mixeraddx); + outw(temp, card->iobase + AC97DATA); spin_unlock_irqrestore(&card->lock, flags); - return CTSTATUS_SUCCESS; + return 0; } /********************************************************* @@ -347,9 +415,9 @@ if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) { outb(data, card->iobase + MUDATA); - ret = CTSTATUS_SUCCESS; + ret = 0; } else - ret = CTSTATUS_BUSY; + ret = -1; spin_unlock_irqrestore(&card->lock, flags); @@ -365,9 +433,9 @@ if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) { *data = inb(card->iobase + MUDATA); - ret = CTSTATUS_SUCCESS; + ret = 0; } else - ret = CTSTATUS_NODATA; + ret = -1; spin_unlock_irqrestore(&card->lock, flags); @@ -405,12 +473,12 @@ spin_unlock_irqrestore(&card->lock, flags); if (status == 0xfe) - return CTSTATUS_SUCCESS; + return 0; else - return CTSTATUS_ERROR; + return -1; } - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpu_acquire(struct emu10k1_card *card) @@ -418,7 +486,7 @@ /* FIXME: This should be a macro */ ++card->mpuacqcount; - return CTSTATUS_SUCCESS; + return 0; } int emu10k1_mpu_release(struct emu10k1_card *card) @@ -426,5 +494,5 @@ /* FIXME: this should be a macro */ --card->mpuacqcount; - return CTSTATUS_SUCCESS; + return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/hwaccess.h linux/drivers/sound/emu10k1/hwaccess.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/hwaccess.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/hwaccess.h Mon Aug 14 08:32:48 2000 @@ -32,28 +32,20 @@ #ifndef _HWACCESS_H #define _HWACCESS_H -#include -#include #include -#include #include -#include #include #include -#include -#include -#include +#include "emu_wrapper.h" -#include - -enum GlobalErrorCode -{ - CTSTATUS_SUCCESS = 0x0000, - CTSTATUS_ERROR, - CTSTATUS_NOMEMORY, - CTSTATUS_INUSE, -}; +#define EMUPAGESIZE 4096 /* don't change */ +#define NUM_G 64 /* use all channels */ +#define NUM_FXSENDS 4 /* don't change */ +/* setting this to other than a power of two may break some applications */ +#define MAXBUFSIZE 65536 +#define MAXPAGES 8192 +#define BUFMAXPAGES (MAXBUFSIZE / PAGE_SIZE) #define FLAGS_AVAILABLE 0x0001 #define FLAGS_READY 0x0002 @@ -62,50 +54,57 @@ struct memhandle { - unsigned long busaddx; - void *virtaddx; - u32 order; + dma_addr_t dma_handle; + void *addr; + u32 size; }; -struct memhandle *emu10k1_alloc_memphysical(u32); -void emu10k1_free_memphysical(struct memhandle *); - #define DEBUG_LEVEL 2 #ifdef EMU10K1_DEBUG # define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0) # define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0) -#define ERROR() DPF(1,"error\n"); #else -# define DPD(level,x,y...) /* not debugging: nothing */ -# define DPF(level,x) -#define ERROR() +# define DPD(level,x,y...) do { } while (0) /* not debugging: nothing */ +# define DPF(level,x) do { } while (0) #endif /* EMU10K1_DEBUG */ -#include "8010.h" -#include "voicemgr.h" +#define ERROR() DPF(1,"error\n") -int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); -void emu10k1_addxmgr_free(struct emu10k1_card *, int); +/* DATA STRUCTURES */ -#include "timer.h" -#include "irqmgr.h" +struct emu10k1_waveout +{ + u16 send_routing[3]; + + u8 send_a[3]; + u8 send_b[3]; + u8 send_c[3]; + u8 send_d[3]; +}; + +struct emu10k1_wavein +{ + struct wiinst *ac97; + struct wiinst *mic; + struct wiinst *fx; + + u8 recsrc; + u32 fxwc; +}; -/* DATA STRUCTURES */ struct emu10k1_card { struct list_head list; - struct memhandle *virtualpagetable; - - struct memhandle *tankmem; - u32 tmemsize; - struct memhandle *silentpage; + struct memhandle virtualpagetable; + struct memhandle tankmem; + struct memhandle silentpage; spinlock_t lock; - struct voice_manager voicemgr; + u8 voicetable[NUM_G]; u16 emupagetable[MAXPAGES]; struct list_head timers; @@ -114,22 +113,23 @@ struct pci_dev *pci_dev; unsigned long iobase; - unsigned long mixeraddx; - u32 irq; - - unsigned long audio1_num; - unsigned long audio2_num; - unsigned long mixer_num; - unsigned long midi_num; + unsigned long length; + unsigned short model; + unsigned int irq; + + int audio_num; + int audio1_num; + int mixer_num; + int midi_num; - struct emu10k1_waveout *waveout; - struct emu10k1_wavein *wavein; + struct emu10k1_waveout waveout; + struct emu10k1_wavein wavein; struct emu10k1_mpuout *mpuout; struct emu10k1_mpuin *mpuin; u16 arrwVol[SOUND_MIXER_NRDEVICES + 1]; /* array is used from the member 1 to save (-1) operation */ - u32 digmix[96]; + u32 digmix[9 * 6 * 2]; unsigned int modcnt; struct semaphore open_sem; mode_t open_mode; @@ -139,8 +139,13 @@ u32 has_toslink; // TOSLink detection u8 chiprev; /* Chip revision */ + + int isaps; }; +int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); +void emu10k1_addxmgr_free(struct emu10k1_card *, int); + #ifdef PRIVATE_PCM_VOLUME #define MAX_PCM_CHANNELS NUM_G @@ -154,16 +159,9 @@ int opened; // counter - locks element }; extern struct sblive_pcm_volume_rec sblive_pcm_volume[]; - +extern u16 pcm_last_mixer; #endif - -#define ENABLE 0xffffffff -#define DISABLE 0x00000000 - -#define ENV_ON 0x80 -#define ENV_OFF 0x00 - #define TIMEOUT 16384 u32 srToPitch(u32); @@ -173,19 +171,17 @@ /* Hardware Abstraction Layer access functions */ -#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f)) - -#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f) - -void sblive_writefn0(struct emu10k1_card *, u8 , u32 ); -void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 ); - -u32 sblive_readfn0(struct emu10k1_card *, u8 ); -u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 ); +void emu10k1_writefn0(struct emu10k1_card *, u32 , u32 ); +u32 emu10k1_readfn0(struct emu10k1_card *, u32 ); void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 ); +void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...); +#define TAGLIST_END 0 + u32 sblive_readptr(struct emu10k1_card *, u32 , u32 ); +void emu10k1_irq_enable(struct emu10k1_card *, u32); +void emu10k1_irq_disable(struct emu10k1_card *, u32); void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32); void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/icardwav.h linux/drivers/sound/emu10k1/icardwav.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/icardwav.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/icardwav.h Mon Aug 14 08:32:48 2000 @@ -32,21 +32,19 @@ #ifndef _ICARDWAV_H #define _ICARDWAV_H -/* Enumeration for SetControl */ -enum -{ - WAVECURPOS = 0x10, -}; - struct wave_format { - u32 samplingrate; - u32 bitsperchannel; - u32 channels; /* 1 = Mono, 2 = Stereo */ + int samplingrate; + u8 bitsperchannel; + u8 channels; /* 1 = Mono, 2 = Stereo */ + u8 bytesperchannel; + u8 bytespersample; + int bytespersec; }; /* emu10k1_wave states */ -#define CARDWAVE_STATE_STOPPED 0x0001 -#define CARDWAVE_STATE_STARTED 0x0002 +#define WAVE_STATE_OPEN 0x01 +#define WAVE_STATE_STARTED 0x02 +#define WAVE_STATE_CLOSED 0x04 #endif /* _ICARDWAV_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/irqmgr.c linux/drivers/sound/emu10k1/irqmgr.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/irqmgr.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/irqmgr.c Mon Aug 14 08:32:48 2000 @@ -31,6 +31,7 @@ */ #include "hwaccess.h" +#include "8010.h" #include "cardmi.h" #include "cardmo.h" #include "irqmgr.h" @@ -40,16 +41,13 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct emu10k1_card *card = (struct emu10k1_card *) dev_id; - u32 irqstatus, ptr, tmp; + u32 irqstatus, tmp; - if (!(irqstatus = sblive_readfn0(card, IPR))) + if (!(irqstatus = emu10k1_readfn0(card, IPR))) return; DPD(4, "emu10k1_interrupt called, irq = %u\n", irq); - /* Preserve PTR register */ - ptr = sblive_readfn0(card, PTR); - /* ** NOTE : ** We do a 'while loop' here cos on certain machines, with both @@ -85,43 +83,10 @@ if (irqstatus) emu10k1_irq_disable(card, irqstatus); - sblive_writefn0(card, IPR, tmp); - - } while ((irqstatus = sblive_readfn0(card, IPR))); + emu10k1_writefn0(card, IPR, tmp); - sblive_writefn0(card, PTR, ptr); + } while ((irqstatus = emu10k1_readfn0(card, IPR))); return; } -/* Enables the specified irq service */ - -int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype) -{ - /* - * TODO : - * put protection here so that we don't accidentally - * screw-up another cardxxx objects irqs - */ - - DPD(4, "emu10k1_irq_enable %x\n", irqtype); - sblive_wrtmskfn0(card, INTE, irqtype, ENABLE); - - return CTSTATUS_SUCCESS; -} - -/* Disables the specified irq service */ - -int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype) -{ - /* - * TODO : - * put protection here so that we don't accidentally - * screw-up another cardxxx objects irqs - */ - - DPD(4, "emu10k1_irq_disable %x\n", irqtype); - sblive_wrtmskfn0(card, INTE, irqtype, DISABLE); - - return CTSTATUS_SUCCESS; -} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/irqmgr.h linux/drivers/sound/emu10k1/irqmgr.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/irqmgr.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/irqmgr.h Mon Aug 14 08:32:48 2000 @@ -43,17 +43,6 @@ #define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE) #define IRQTYPE_DSP IPR_FXDSP -struct emu10k1_wavedevice -{ - struct emu10k1_card *card; - struct wiinst *wiinst; - struct woinst *woinst; - u16 enablebits; -}; - void emu10k1_timer_irqhandler(struct emu10k1_card *); - -int emu10k1_irq_enable(struct emu10k1_card *, u32); -int emu10k1_irq_disable(struct emu10k1_card *, u32); #endif /* _IRQ_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/main.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/emu10k1/main.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * main.c - Creative EMU10K1 audio driver @@ -42,24 +41,35 @@ * 0.4 Added rear-channel, SPDIF support. * 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes, * moved bh's to tasklets, moved to the new PCI driver initialization style. + * 0.6 Make use of pci_alloc_consistent, improve compatibility layer for 2.2 kernels, + * code reorganization and cleanup. + * 0.7 Support for the Emu-APS. Bug fixes for voice cache setup, mmaped sound + poll(). + * Support for setting external TRAM size. + * ********************************************************************** */ /* These are only included once per module */ +#include #include +#include #include +#include #include "hwaccess.h" +#include "8010.h" #include "efxmgr.h" #include "cardwo.h" #include "cardwi.h" #include "cardmo.h" #include "cardmi.h" #include "recmgr.h" +#include "ecard.h" -#define DRIVER_VERSION "0.5" +#define DRIVER_VERSION "0.7" /* FIXME: is this right? */ +/* does the card support 32 bit bus master?*/ #define EMU10K1_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ #ifndef PCI_VENDOR_ID_CREATIVE @@ -70,8 +80,8 @@ #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 #endif -#define EMU10K1_EXTENT 0x20 /* 32 byte I/O space */ - +#define EMU_APS_SUBID 0x40011102 + enum { EMU10K1 = 0, }; @@ -80,7 +90,7 @@ "EMU10K1", }; -static struct pci_device_id emu10k1_pci_tbl[] __devinitdata = { +static struct pci_device_id emu10k1_pci_tbl[] = { {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1}, {0,} @@ -99,32 +109,38 @@ extern void emu10k1_interrupt(int, void *, struct pt_regs *s); extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int); -static int __devinit audio_init(struct emu10k1_card *card) +static void __devinit audio_init(struct emu10k1_card *card) { - if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) { - printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n"); - return CTSTATUS_ERROR; - } - memset(card->waveout, 0, sizeof(struct emu10k1_waveout)); - - /* Assign default global volume, reverb, chorus */ - card->waveout->globalvol = 0xffffffff; - card->waveout->left = 0xffff; - card->waveout->right = 0xffff; - card->waveout->mute = 0; - card->waveout->globalreverb = 0xffffffff; - card->waveout->globalchorus = 0xffffffff; + /* Assign default playback voice parameters */ + /* mono voice */ + card->waveout.send_a[0] = 0x00; + card->waveout.send_b[0] = 0xff; + card->waveout.send_c[0] = 0xff; + card->waveout.send_d[0] = 0x00; + card->waveout.send_routing[0] = 0xd01c; + + /* stereo voice */ + card->waveout.send_a[1] = 0x00; + card->waveout.send_b[1] = 0xff; + card->waveout.send_c[1] = 0x00; + card->waveout.send_d[1] = 0x00; + card->waveout.send_routing[1] = 0xd01c; + + card->waveout.send_a[2] = 0x00; + card->waveout.send_b[2] = 0x00; + card->waveout.send_c[2] = 0xff; + card->waveout.send_d[2] = 0x00; + card->waveout.send_routing[2] = 0xd01c; + + /* Assign default recording parameters */ + if(card->isaps) + card->wavein.recsrc = WAVERECORD_FX; + else + card->wavein.recsrc = WAVERECORD_AC97; - if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL)) - == NULL) { - printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n"); - return CTSTATUS_ERROR; - } - memset(card->wavein, 0, sizeof(struct emu10k1_wavein)); + card->wavein.fxwc = 0x0003; - card->wavein->recsrc = WAVERECORD_AC97; - - return CTSTATUS_SUCCESS; + return; } static void __devinit mixer_init(struct emu10k1_card *card) @@ -141,61 +157,64 @@ SOUND_MIXER_PHONEIN, 0x3232}, { SOUND_MIXER_MIC, 0x0000}, { SOUND_MIXER_LINE, 0x0000}, { - SOUND_MIXER_CD, 0x3232}, { - SOUND_MIXER_LINE1, 0x3232}, { + SOUND_MIXER_CD, 0x4b4b}, { + SOUND_MIXER_LINE1, 0x4b4b}, { SOUND_MIXER_LINE3, 0x3232}, { SOUND_MIXER_DIGITAL1, 0x6464}, { SOUND_MIXER_DIGITAL2, 0x6464}, { SOUND_MIXER_PCM, 0x6464}, { - SOUND_MIXER_RECLEV, 0x3232}, { + SOUND_MIXER_RECLEV, 0x0404}, { SOUND_MIXER_TREBLE, 0x3232}, { SOUND_MIXER_BASS, 0x3232}, { - SOUND_MIXER_LINE2, 0x4b4b}}; + SOUND_MIXER_LINE2, 0x4b4b}}; - int initdig[] = { 0, 1, 2, 3, 6, 7, 16, 17, 18, 19, 22, 23, 64, 65, 66, 67, 70, 71, - 84, 85 + int initdig[] = { 0, 1, 2, 3, 6, 7, 18, 19, 20, 21, 24, 25, 72, 73, 74, 75, 78, 79, + 94, 95 }; - /* Reset */ - sblive_writeac97(card, AC97_RESET, 0); - -#if 0 - /* Check status word */ - { - u16 reg; - - sblive_readac97(card, AC97_RESET, ®); - DPD(2, "RESET 0x%x\n", reg); - sblive_readac97(card, AC97_MASTERTONE, ®); - DPD(2, "MASTER_TONE 0x%x\n", reg); + for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) { + card->digmix[count] = 0x80000000; + sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0); } -#endif - /* Set default recording source to mic in */ - sblive_writeac97(card, AC97_RECORDSELECT, 0); + card->modcnt = 0; // Should this be here or in open() ? - /* Set default AC97 "PCM" volume to acceptable max */ - //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); - //sblive_writeac97(card, AC97_LINE2, 0); + if (!card->isaps) { - /* Set default volumes for all mixer channels */ + for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) { + card->digmix[initdig[count]] = 0x7fffffff; + sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff); + } - for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) { - card->digmix[count] = 0x80000000; - sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0); - } + /* Reset */ + sblive_writeac97(card, AC97_RESET, 0); - for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) { - card->digmix[initdig[count]] = 0x7fffffff; - sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff); +#if 0 + /* Check status word */ + { + u16 reg; + + sblive_readac97(card, AC97_RESET, ®); + DPD(2, "RESET 0x%x\n", reg); + sblive_readac97(card, AC97_MASTERTONE, ®); + DPD(2, "MASTER_TONE 0x%x\n", reg); + } +#endif + + /* Set default recording source to mic in */ + sblive_writeac97(card, AC97_RECORDSELECT, 0); + + /* Set default AC97 "PCM" volume to acceptable max */ + //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); + //sblive_writeac97(card, AC97_LINE2, 0); } + /* Set default volumes for all mixer channels */ + for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) { emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol); } - card->modcnt = 0; // Should this be here or in open() ? - return; } @@ -204,7 +223,7 @@ if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); - return CTSTATUS_ERROR; + return -1; } memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout)); @@ -220,7 +239,7 @@ if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) { kfree(card->mpuout); printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n"); - return CTSTATUS_ERROR; + return -1; } memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin)); @@ -232,31 +251,20 @@ spin_lock_init(&card->mpuin->lock); /* Reset the MPU port */ - if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) { + if (emu10k1_mpu_reset(card) < 0) { ERROR(); - return CTSTATUS_ERROR; + return -1; } - return CTSTATUS_SUCCESS; + return 0; } static void __devinit voice_init(struct emu10k1_card *card) { - struct voice_manager *voicemgr = &card->voicemgr; - struct emu_voice *voice; int i; - voicemgr->card = card; - voicemgr->lock = SPIN_LOCK_UNLOCKED; - - voice = voicemgr->voice; - for (i = 0; i < NUM_G; i++) { - voice->card = card; - voice->usage = VOICEMGR_USAGE_FREE; - voice->num = i; - voice->linked_voice = NULL; - voice++; - } + for (i = 0; i < NUM_G; i++) + card->voicetable[i] = VOICE_USAGE_FREE; return; } @@ -280,21 +288,27 @@ /* Mark first page as used */ /* This page is reserved by the driver */ card->emupagetable[0] = 0x8001; - card->emupagetable[1] = MAXPAGES - RESERVED - 1; + card->emupagetable[1] = MAXPAGES - 1; return; } static void __devinit fx_init(struct emu10k1_card *card) { - int i, j, k, l; + int i, j, k; +#ifdef TONE_CONTROL + int l; +#endif u32 pc = 0; for (i = 0; i < 512; i++) OP(6, 0x40, 0x40, 0x40, 0x40); for (i = 0; i < 256; i++) - sblive_writeptr(card, FXGPREGBASE + i, 0, 0); + sblive_writeptr_tag(card, 0, + FXGPREGBASE + i, 0, + TANKMEMADDRREGBASE + i, 0, + TAGLIST_END); pc = 0; @@ -304,7 +318,7 @@ OP(4, 0x101, 0x40, j + 2, 0x44); for (i = 0; i < 6; i++) { - k = i * 16 + j; + k = i * 18 + j; OP(0, 0x102, 0x40, 0x110 + k, 0x100); OP(0, 0x102, 0x102, 0x112 + k, 0x101); OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j); @@ -313,25 +327,32 @@ OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j); OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j); OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j); +#ifdef TONE_CONTROL + OP(0, 0x102, 0x102, 0x120 + k, 0x1c + j); - k = 0x190 + i * 8 + j * 4; - OP(0, 0x40, 0x40, 0x102, 0x170 + j); - OP(7, k + 1, k, k + 1, 0x174 + j); - OP(7, k, 0x102, k, 0x172 + j); - OP(7, k + 3, k + 2, k + 3, 0x178 + j); - OP(0, k + 2, 0x56, k + 2, 0x176 + j); + k = 0x1a0 + i * 8 + j * 4; + OP(0, 0x40, 0x40, 0x102, 0x180 + j); + OP(7, k + 1, k, k + 1, 0x184 + j); + OP(7, k, 0x102, k, 0x182 + j); + OP(7, k + 3, k + 2, k + 3, 0x188 + j); + OP(0, k + 2, 0x56, k + 2, 0x186 + j); OP(6, k + 2, k + 2, k + 2, 0x40); - l = 0x1c0 + i * 8 + j * 4; - OP(0, 0x40, 0x40, k + 2, 0x180 + j); - OP(7, l + 1, l, l + 1, 0x184 + j); - OP(7, l, k + 2, l, 0x182 + j); - OP(7, l + 3, l + 2, l + 3, 0x188 + j); - OP(0, l + 2, 0x56, l + 2, 0x186 + j); + l = 0x1d0 + i * 8 + j * 4; + OP(0, 0x40, 0x40, k + 2, 0x190 + j); + OP(7, l + 1, l, l + 1, 0x194 + j); + OP(7, l, k + 2, l, 0x192 + j); + OP(7, l + 3, l + 2, l + 3, 0x198 + j); + OP(0, l + 2, 0x56, l + 2, 0x196 + j); OP(4, l + 2, 0x40, l + 2, 0x46); - OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40); - + if ((i == 0) && !card->isaps) + OP(4, 0x20 + (i * 2) + j, 0x40, l + 2, 0x50); /* FIXME: Is this really needed? */ + else + OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40); +#else + OP(0, 0x20 + (i * 2) + j, 0x102, 0x120 + k, 0x1c + j); +#endif } } sblive_writeptr(card, DBG, 0, 0); @@ -342,63 +363,64 @@ static int __devinit hw_init(struct emu10k1_card *card) { int nCh; - -#ifdef TANKMEM - u32 size = 0; -#endif - u32 sizeIdx = 0; - u32 pagecount, tmp; + u32 pagecount; /* tmp */ /* Disable audio and lock cache */ - sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); + emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE); /* Reset recording buffers */ - sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, MICBA, 0, 0); - sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, FXBA, 0, 0); - sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, ADCBA, 0, 0); + sblive_writeptr_tag(card, 0, + MICBS, ADCBS_BUFSIZE_NONE, + MICBA, 0, + FXBS, ADCBS_BUFSIZE_NONE, + FXBA, 0, + ADCBS, ADCBS_BUFSIZE_NONE, + ADCBA, 0, + TAGLIST_END); /* Disable channel interrupt */ - sblive_writefn0(card, INTE, DISABLE); - sblive_writeptr(card, CLIEL, 0, 0); - sblive_writeptr(card, CLIEH, 0, 0); - sblive_writeptr(card, SOLEL, 0, 0); - sblive_writeptr(card, SOLEH, 0, 0); + emu10k1_writefn0(card, INTE, 0); + sblive_writeptr_tag(card, 0, + CLIEL, 0, + CLIEH, 0, + SOLEL, 0, + SOLEH, 0, + TAGLIST_END); /* Init envelope engine */ for (nCh = 0; nCh < NUM_G; nCh++) { - sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF); - sblive_writeptr(card, IP, nCh, 0); - sblive_writeptr(card, VTFT, nCh, 0xffff); - sblive_writeptr(card, CVCF, nCh, 0xffff); - sblive_writeptr(card, PTRX, nCh, 0); - sblive_writeptr(card, CPF, nCh, 0); - sblive_writeptr(card, CCR, nCh, 0); - - sblive_writeptr(card, PSST, nCh, 0); - sblive_writeptr(card, DSL, nCh, 0x10); - sblive_writeptr(card, CCCA, nCh, 0); - sblive_writeptr(card, Z1, nCh, 0); - sblive_writeptr(card, Z2, nCh, 0); - sblive_writeptr(card, FXRT, nCh, 0xd01c0000); - - sblive_writeptr(card, ATKHLDM, nCh, 0); - sblive_writeptr(card, DCYSUSM, nCh, 0); - sblive_writeptr(card, IFATN, nCh, 0xffff); - sblive_writeptr(card, PEFE, nCh, 0); - sblive_writeptr(card, FMMOD, nCh, 0); - sblive_writeptr(card, TREMFRQ, nCh, 24); /* 1 Hz */ - sblive_writeptr(card, FM2FRQ2, nCh, 24); /* 1 Hz */ - sblive_writeptr(card, TEMPENV, nCh, 0); - - /*** These are last so OFF prevents writing ***/ - sblive_writeptr(card, LFOVAL2, nCh, 0); - sblive_writeptr(card, LFOVAL1, nCh, 0); - sblive_writeptr(card, ATKHLDV, nCh, 0); - sblive_writeptr(card, ENVVOL, nCh, 0); - sblive_writeptr(card, ENVVAL, nCh, 0); + sblive_writeptr_tag(card, nCh, + DCYSUSV, 0, + IP, 0, + VTFT, 0xffff, + CVCF, 0xffff, + PTRX, 0, + CPF, 0, + CCR, 0, + + PSST, 0, + DSL, 0x10, + CCCA, 0, + Z1, 0, + Z2, 0, + FXRT, 0xd01c0000, + + ATKHLDM, 0, + DCYSUSM, 0, + IFATN, 0xffff, + PEFE, 0, + FMMOD, 0, + TREMFRQ, 24, /* 1 Hz */ + FM2FRQ2, 24, /* 1 Hz */ + TEMPENV, 0, + + /*** These are last so OFF prevents writing ***/ + LFOVAL2, 0, + LFOVAL1, 0, + ATKHLDV, 0, + ENVVOL, 0, + ENVVAL, 0, + TAGLIST_END); } /* @@ -416,73 +438,57 @@ ** P = 0 (Consumer) */ - /* SPDIF0 */ - sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - - /* SPDIF1 */ - sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - - /* SPDIF2 & SPDIF3 */ - sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + sblive_writeptr_tag(card, 0, - fx_init(card); /* initialize effects engine */ + /* SPDIF0 */ + SPCS0, (SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT), - card->tankmem = NULL; + /* SPDIF1 */ + SPCS1, (SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT), -#ifdef TANKMEM - size = TMEMSIZE; - sizeIdx = TMEMSIZEREG; - while (size > 16384) { - if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL) - break; + /* SPDIF2 & SPDIF3 */ + SPCS2, (SPCS_CLKACCY_1000PPM | 0x002000000 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT), - size /= 2; - sizeIdx -= 1; - } + TAGLIST_END); - if (card->tankmem == NULL) { - card->tmemsize = 0; - return CTSTATUS_ERROR; - } + fx_init(card); /* initialize effects engine */ + + card->tankmem.size = 0; - card->tmemsize = size; -#else /* !TANKMEM */ - card->tmemsize = 0; -#endif /* TANKMEM */ + card->virtualpagetable.size = MAXPAGES * sizeof(u32); - if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) { + if ((card->virtualpagetable.addr = pci_alloc_consistent(card->pci_dev, card->virtualpagetable.size, &card->virtualpagetable.dma_handle)) == + NULL) { ERROR(); - emu10k1_free_memphysical(card->tankmem); - return CTSTATUS_ERROR; + return -1; } - if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) { - ERROR(); - emu10k1_free_memphysical(card->tankmem); - emu10k1_free_memphysical(card->virtualpagetable); - return CTSTATUS_ERROR; - } else - memset(card->silentpage->virtaddx, 0, EMUPAGESIZE); + card->silentpage.size = EMUPAGESIZE; - for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++) + if ((card->silentpage.addr = pci_alloc_consistent(card->pci_dev, card->silentpage.size, &card->silentpage.dma_handle)) == NULL) { + ERROR(); + pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle); + return -1; + } - ((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount; + for (pagecount = 0; pagecount < MAXPAGES; pagecount++) + ((u32 *) card->virtualpagetable.addr)[pagecount] = (card->silentpage.dma_handle * 2) | pagecount; /* Init page table & tank memory base register */ - sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx); -#ifdef TANKMEM - sblive_writeptr(card, TCB, 0, card->tankmem->busaddx); -#else - sblive_writeptr(card, TCB, 0, 0); -#endif - sblive_writeptr(card, TCBS, 0, sizeIdx); + sblive_writeptr_tag(card, 0, + PTB, card->virtualpagetable.dma_handle, + TCB, 0, + TCBS, 0, + TAGLIST_END); for (nCh = 0; nCh < NUM_G; nCh++) { - sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); - sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + sblive_writeptr_tag(card, nCh, + MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + TAGLIST_END); } /* Hokay, now enable the AUD bit */ @@ -497,12 +503,16 @@ sblive_writeac97(card, AC97_MASTERVOLUME, 0); sblive_writeac97(card, AC97_PCMOUTVOLUME, 0); - sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE); + if(card->model == 0x20 || card->model == 0xc400 || + (card->model == 0x21 && card->chiprev < 6)) + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE); + else + emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE); - /* TOSLink detection */ + /* FIXME: TOSLink detection */ card->has_toslink = 0; - tmp = sblive_readfn0(card, HCFG); +/* tmp = sblive_readfn0(card, HCFG); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { sblive_writefn0(card, HCFG, tmp | 0x800); @@ -513,30 +523,23 @@ sblive_writefn0(card, HCFG, tmp); } } - - return CTSTATUS_SUCCESS; +*/ + return 0; } static int __devinit emu10k1_init(struct emu10k1_card *card) { /* Init Card */ - if (hw_init(card) != CTSTATUS_SUCCESS) - return CTSTATUS_ERROR; + if (hw_init(card) < 0) + return -1; voice_init(card); timer_init(card); addxmgr_init(card); - DPD(2, " hw control register -> %x\n", sblive_readfn0(card, HCFG)); - - return CTSTATUS_SUCCESS; -} + DPD(2, " hw control register -> 0x%x\n", emu10k1_readfn0(card, HCFG)); -static void __devexit audio_exit(struct emu10k1_card *card) -{ - kfree(card->waveout); - kfree(card->wavein); - return; + return 0; } static void __devexit midi_exit(struct emu10k1_card *card) @@ -550,50 +553,57 @@ return; } -static void __devexit emu10k1_exit(struct emu10k1_card *card) +static void __devinit emu10k1_exit(struct emu10k1_card *card) { int ch; - sblive_writefn0(card, INTE, DISABLE); + emu10k1_writefn0(card, INTE, 0); /** Shutdown the chip **/ for (ch = 0; ch < NUM_G; ch++) - sblive_writeptr(card, DCYSUSV, ch, ENV_OFF); + sblive_writeptr(card, DCYSUSV, ch, 0); for (ch = 0; ch < NUM_G; ch++) { - sblive_writeptr(card, VTFT, ch, 0); - sblive_writeptr(card, CVCF, ch, 0); - sblive_writeptr(card, PTRX, ch, 0); - sblive_writeptr(card, CPF, ch, 0); + sblive_writeptr_tag(card, ch, + VTFT, 0, + CVCF, 0, + PTRX, 0, + CPF, 0, + TAGLIST_END); } - /* Reset recording buffers */ - sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, MICBA, 0, 0); - sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, FXBA, 0, 0); - sblive_writeptr(card, FXWC, 0, 0); - sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE); - sblive_writeptr(card, ADCBA, 0, 0); - sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K); - sblive_writeptr(card, TCB, 0, 0); - sblive_writeptr(card, DBG, 0, 0x8000); + /* Disable audio and lock cache */ + emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE); - /* Disable channel interrupt */ - sblive_writeptr(card, CLIEL, 0, 0); - sblive_writeptr(card, CLIEH, 0, 0); - sblive_writeptr(card, SOLEL, 0, 0); - sblive_writeptr(card, SOLEH, 0, 0); + sblive_writeptr_tag(card, 0, + PTB, 0, - /* Disable audio and lock cache */ - sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE); - sblive_writeptr(card, PTB, 0, 0); + /* Reset recording buffers */ + MICBS, ADCBS_BUFSIZE_NONE, + MICBA, 0, + FXBS, ADCBS_BUFSIZE_NONE, + FXBA, 0, + FXWC, 0, + ADCBS, ADCBS_BUFSIZE_NONE, + ADCBA, 0, + TCBS, 0, + TCB, 0, + DBG, 0x8000, + + /* Disable channel interrupt */ + CLIEL, 0, + CLIEH, 0, + SOLEL, 0, + SOLEH, 0, + TAGLIST_END); + + + pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle); + pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle); + + if(card->tankmem.size != 0) + pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle); - emu10k1_free_memphysical(card->silentpage); - emu10k1_free_memphysical(card->virtualpagetable); -#ifdef TANKMEM - emu10k1_free_memphysical(card->tankmem); -#endif return; } @@ -601,6 +611,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct emu10k1_card *card; + u32 subsysvid; if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "emu10k1: out of memory\n"); @@ -608,7 +619,6 @@ } memset(card, 0, sizeof(struct emu10k1_card)); -#if LINUX_VERSION_CODE > 0x020320 if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) { printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); kfree(card); @@ -623,27 +633,17 @@ pci_set_master(pci_dev); card->iobase = pci_resource_start(pci_dev, 0); + card->length = pci_resource_len(pci_dev, 0); - if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) { + if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) { printk(KERN_ERR "emu10k1: IO space in use\n"); kfree(card); return -ENODEV; } - pci_dev->driver_data = card; - pci_dev->dma_mask = EMU10K1_DMA_MASK; -#else - pci_set_master(pci_dev); - - card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - if (check_region(card->iobase, EMU10K1_EXTENT)) { - printk(KERN_ERR "emu10k1: IO space in use\n"); - kfree(card); - return -ENODEV; - } + PCI_SET_DRIVER_DATA(pci_dev, card); + PCI_SET_DMA_MASK(pci_dev, EMU10K1_DMA_MASK); - request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]); -#endif card->irq = pci_dev->irq; card->pci_dev = pci_dev; @@ -654,22 +654,27 @@ } pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev); + pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &card->model); + + printk(KERN_INFO "emu10k1: %s rev %d model 0x%x found, IO at 0x%04lx-0x%04lx, IRQ %d\n", + card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase, + card->iobase + card->length - 1, card->irq); - printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq); + pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid); + card->isaps = (subsysvid == EMU_APS_SUBID); spin_lock_init(&card->lock); - card->mixeraddx = card->iobase + AC97DATA; init_MUTEX(&card->open_sem); card->open_mode = 0; init_waitqueue_head(&card->open_wait); /* Register devices */ - if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + if ((card->audio_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); goto err_dev0; } - if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { + if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register second audio device!\n"); goto err_dev1; } @@ -684,33 +689,27 @@ goto err_dev3; } - if (emu10k1_init(card) != CTSTATUS_SUCCESS) { + if (emu10k1_init(card) < 0) { printk(KERN_ERR "emu10k1: cannot initialize device!\n"); goto err_emu10k1_init; } - if (audio_init(card) != CTSTATUS_SUCCESS) { - printk(KERN_ERR "emu10k1: cannot initialize audio!\n"); - goto err_audio_init; - } - - if (midi_init(card) != CTSTATUS_SUCCESS) { + if (midi_init(card) < 0) { printk(KERN_ERR "emu10k1: cannot initialize midi!\n"); goto err_midi_init; } + audio_init(card); mixer_init(card); - DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize); + if (card->isaps) + emu10k1_ecard_init(card); list_add(&card->list, &emu10k1_devs); return 0; err_midi_init: - audio_exit(card); - - err_audio_init: emu10k1_exit(card); err_emu10k1_init: @@ -720,16 +719,16 @@ unregister_sound_mixer(card->mixer_num); err_dev2: - unregister_sound_dsp(card->audio2_num); + unregister_sound_dsp(card->audio1_num); err_dev1: - unregister_sound_dsp(card->audio1_num); + unregister_sound_dsp(card->audio_num); err_dev0: free_irq(card->irq, card); err_irq: - release_region(card->iobase, EMU10K1_EXTENT); + release_region(card->iobase, card->length); kfree(card); return -ENODEV; @@ -737,26 +736,25 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev) { -#if LINUX_VERSION_CODE > 0x020320 - struct emu10k1_card *card = pci_dev->driver_data; -#else - struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); -#endif + struct emu10k1_card *card = PCI_GET_DRIVER_DATA(pci_dev); + midi_exit(card); - audio_exit(card); emu10k1_exit(card); unregister_sound_midi(card->midi_num); + unregister_sound_mixer(card->mixer_num); - unregister_sound_dsp(card->audio2_num); + unregister_sound_dsp(card->audio1_num); + unregister_sound_dsp(card->audio_num); free_irq(card->irq, card); - release_region(card->iobase, EMU10K1_EXTENT); + release_region(card->iobase, card->length); list_del(&card->list); kfree(card); + return; } @@ -770,7 +768,6 @@ remove:emu10k1_remove, }; -#if LINUX_VERSION_CODE > 0x020320 static int __init emu10k1_init_module(void) { printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); @@ -781,44 +778,9 @@ static void __exit emu10k1_cleanup_module(void) { pci_unregister_driver(&emu10k1_pci_driver); - return; -} - -#else - -static int __init emu10k1_init_module(void) -{ - struct pci_dev *dev = NULL; - const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table; - - printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); - - if (!pci_present()) - return -ENODEV; - - while (pci_id->vendor) { - while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev))) - emu10k1_probe(dev, pci_id); - - pci_id++; - } - return 0; -} - -static void __exit emu10k1_cleanup_module(void) -{ - struct emu10k1_card *card; - - while (!list_empty(&emu10k1_devs)) { - card = list_entry(emu10k1_devs.next, struct emu10k1_card, list); - - emu10k1_remove(card->pci_dev); - } return; } - -#endif module_init(emu10k1_init_module); module_exit(emu10k1_cleanup_module); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/midi.c Fri Jul 14 12:12:12 2000 +++ linux/drivers/sound/emu10k1/midi.c Mon Aug 14 08:32:48 2000 @@ -32,6 +32,8 @@ #define __NO_VERSION__ #include +#include +#include #include #include #include @@ -64,20 +66,20 @@ if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) { ERROR(); kfree(midihdr); - return CTSTATUS_ERROR; + return -1; } - if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) { + if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) { ERROR(); kfree(midihdr->data); kfree(midihdr); - return CTSTATUS_ERROR; + return -1; } *midihdrptr = midihdr; list_add_tail(&midihdr->list, &midi_dev->mid_hdrs); - return CTSTATUS_SUCCESS; + return 0; } static int emu10k1_midi_open(struct inode *inode, struct file *file) @@ -138,20 +140,19 @@ dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; - if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) - != CTSTATUS_SUCCESS) { + if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) { ERROR(); kfree(midi_dev); return -ENODEV; } /* Add two buffers to receive sysex buffer */ - if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) { + if (midiin_add_buffer(midi_dev, &midihdr1) < 0) { kfree(midi_dev); return -ENODEV; } - if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) { + if (midiin_add_buffer(midi_dev, &midihdr2) < 0) { list_del(&midihdr1->list); kfree(midihdr1->data); kfree(midihdr1); @@ -165,8 +166,7 @@ dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev; - if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) - != CTSTATUS_SUCCESS) { + if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) { ERROR(); kfree(midi_dev); return -ENODEV; @@ -188,6 +188,7 @@ struct emu10k1_card *card; lock_kernel(); + card = midi_dev->card; DPF(2, "emu10k1_midi_release()\n"); @@ -231,6 +232,7 @@ card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE)); up(&card->open_sem); wake_up_interruptible(&card->open_wait); + unlock_kernel(); return 0; @@ -252,8 +254,7 @@ return -EFAULT; if (midi_dev->mistate == MIDIIN_STATE_STOPPED) { - if (emu10k1_mpuin_start(midi_dev->card) - != CTSTATUS_SUCCESS) { + if (emu10k1_mpuin_start(midi_dev->card) < 0) { ERROR(); return -EINVAL; } @@ -348,7 +349,7 @@ spin_lock_irqsave(&midi_spinlock, flags); - if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) { + if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) { ERROR(); kfree(midihdr->data); kfree(midihdr); @@ -422,20 +423,20 @@ break; default: /* Unknown message */ - return CTSTATUS_ERROR; + return -1; } spin_unlock_irqrestore(&midi_spinlock, flags); - return CTSTATUS_SUCCESS; + return 0; } /* MIDI file operations */ struct file_operations emu10k1_midi_fops = { - owner:THIS_MODULE, - read:emu10k1_midi_read, - write:emu10k1_midi_write, - poll:emu10k1_midi_poll, - open:emu10k1_midi_open, - release:emu10k1_midi_release, + owner: THIS_MODULE, + read: emu10k1_midi_read, + write: emu10k1_midi_write, + poll: emu10k1_midi_poll, + open: emu10k1_midi_open, + release: emu10k1_midi_release, }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/mixer.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/emu10k1/mixer.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * mixer.c - /dev/mixer interface for emu10k1 driver @@ -36,9 +35,13 @@ #define __NO_VERSION__ /* Kernel version only defined once */ #include +#include +#include #include #include "hwaccess.h" +#include "8010.h" +#include "recmgr.h" #define AC97_PESSIMISTIC #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -49,31 +52,13 @@ #define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31) #define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15) +#define DM_MUTE 0x80000000 + #ifdef PRIVATE_PCM_VOLUME struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS]; +u16 pcm_last_mixer = 0x6464; #endif -/* --------------------------------------------------------------------- */ - -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ - -#ifdef hweight32 -#undef hweight32 -#endif - -extern __inline__ unsigned int hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - /* Mapping arrays */ static const unsigned int recsrc[] = { SOUND_MASK_MIC, @@ -84,10 +69,10 @@ SOUND_MASK_VOLUME, SOUND_MASK_OGAIN, /* Used to be PHONEOUT */ SOUND_MASK_PHONEIN, +#ifdef TONE_CONTROL SOUND_MASK_TREBLE, SOUND_MASK_BASS, - SOUND_MASK_MONITOR, - SOUND_MASK_PCM, +#endif }; static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { @@ -115,7 +100,7 @@ /* 4 bit mono */ [SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC, /* test code */ - [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE, + [SOUND_MIXER_BASS] = AC97_GENERALPURPOSE, [SOUND_MIXER_TREBLE] = AC97_MASTERTONE, [SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME, [SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME @@ -134,12 +119,25 @@ int nL, nR; switch (ch) { + case SOUND_MIXER_PCM: + case SOUND_MIXER_VOLUME: +#ifdef TONE_CONTROL + case SOUND_MIXER_TREBLE: + case SOUND_MIXER_BASS: +#endif + return put_user(0x0000, (int *) arg); + default: + break; + } + + if(card->isaps) + return -EINVAL; + + switch (ch) { case SOUND_MIXER_LINE: case SOUND_MIXER_CD: case SOUND_MIXER_VIDEO: case SOUND_MIXER_LINE1: - case SOUND_MIXER_PCM: - case SOUND_MIXER_VOLUME: sblive_readac97(card, volreg[ch], ®); nL = ((~(reg >> 8) & 0x1f) * 100) / 32; nR = (~(reg & 0x1f) * 100) / 32; @@ -165,9 +163,6 @@ nR = (~(reg & 0x1f) * 100) / 16; return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg); - case SOUND_MIXER_TREBLE: - case SOUND_MIXER_BASS: - return put_user(0x0000, (int *) arg); default: return -EINVAL; } @@ -204,7 +199,9 @@ [SOUND_MIXER_DIGITAL2] = 19 }; -u32 bass_table[41][5] = { +#ifdef TONE_CONTROL + +static const u32 bass_table[41][5] = { { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 }, { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d }, { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee }, @@ -248,7 +245,7 @@ { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 } }; -u32 treble_table[41][5] = { +static const u32 treble_table[41][5] = { { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 }, { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 }, { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 }, @@ -299,8 +296,8 @@ l = (l * 40 + 50) / 100; r = (r * 40 + 50) / 100; for (i = 0; i < 5; i++) { - sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]); - sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]); + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, bass_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, bass_table[r][i]); } } @@ -311,12 +308,14 @@ l = (l * 40 + 50) / 100; r = (r * 40 + 50) / 100; for (i = 0; i < 5; i++) { - sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]); - sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]); + sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2), 0, treble_table[l][i]); + sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2) + 1, 0, treble_table[r][i]); } } -u32 db_table[101] = { +#endif + +static const u32 db_table[101] = { 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1, @@ -340,6 +339,29 @@ 0x7fffffff, }; +static void aps_update_digital(struct emu10k1_card *card) +{ + int i, l1, r1, l2, r2; + + i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]]; + l1 = (i & 0xff); + r1 = ((i >> 8) & 0xff); + + i = card->arrwVol[volidx[SOUND_MIXER_PCM]]; + l2 = (i & 0xff); + r2 = ((i >> 8) & 0xff); + + for (i = 0; i < 108; i++) { + if (card->digmix[i] != DM_MUTE) { + if ((i % 18 >= 0) && (i % 18 < 4)) + card->digmix[i] = ((i & 1) ? ((u64) db_table[r1] * (u64) db_table[r2]) : ((u64) db_table[l1] * (u64) db_table[l2])) >> 31; + else + card->digmix[i] = (i & 1) ? db_table[r1] : db_table[l1]; + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]); + } + } +} + static void update_digital(struct emu10k1_card *card) { int i, k, l1, r1, l2, r2, l3, r3, l4, r4; @@ -376,11 +398,11 @@ l1 = i; } - for (i = 0; i < 16; i++) { - if (card->digmix[i] != 0x80000000) { - if ((i >= 0) && (i < 4)) + for (i = 0; i < 36; i++) { + if (card->digmix[i] != DM_MUTE) { + if (((i >= 0) && (i < 4)) || ((i >= 18) && (i < 22))) j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]); - else if ((i == 6) || (i == 7)) + else if ((i == 6) || (i == 7) || (i == 24) || (i == 25)) j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]); else j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31; @@ -389,11 +411,11 @@ } } - for (i = 64; i < 80; i++) { - if (card->digmix[i] != 0x80000000) { - if ((i >= 64) && (i < 68)) + for (i = 72; i < 90; i++) { + if (card->digmix[i] != DM_MUTE) { + if ((i >= 72) && (i < 76)) j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]); - else if ((i == 70) || (i == 71)) + else if ((i == 78) || (i == 79)) j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]); else j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31; @@ -402,18 +424,18 @@ } } - for (i = 16; i <= 80; i += 16) { - if (i != 64) { + for (i = 36; i <= 90; i += 18) { + if (i != 72) { for (k = 0; k < 4; k++) - if (card->digmix[i + k] != 0x80000000) { + if (card->digmix[i + k] != DM_MUTE) { card->digmix[i + k] = db_table[l3]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]); } - if (card->digmix[i + 6] != 0x80000000) { + if (card->digmix[i + 6] != DM_MUTE) { card->digmix[i + 6] = db_table[l4]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]); } - if (card->digmix[i + 7] != 0x80000000) { + if (card->digmix[i + 7] != DM_MUTE) { card->digmix[i + 7] = db_table[r4]; sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]); } @@ -428,9 +450,9 @@ static int set_pcm_attn(struct emu10k1_card *card, int ch, int l) { #ifndef PCMLEVEL -#define PCMLEVEL 140 // almost silence +#define PCMLEVEL 110 /* almost silence */ #endif - int vol = IFATN_ATTENUATION_MASK; // silence + int vol = IFATN_ATTENUATION_MASK; /* silence */ if (l > 0) vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100); @@ -454,29 +476,29 @@ for (i = 0; i < MAX_PCM_CHANNELS; i++) { if (sblive_pcm_volume[i].files == current->files) { - sblive_pcm_volume[i].mixer = mixer; + sblive_pcm_volume[i].mixer = pcm_last_mixer = mixer; if (sblive_pcm_volume[i].opened) { if (sblive_pcm_volume[i].channel_r < NUM_G) { + sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1); if (sblive_pcm_volume[i].channel_l < NUM_G) sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1); - sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1); } else { - // mono voice + /* mono voice */ if (sblive_pcm_volume[i].channel_l < NUM_G) sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1); - // to correctly handle mono voice here we would need - // to go into stereo mode and move the voice to the right & left - // looks a bit overcomlicated... + /* to correctly handle mono voice here we would need + to go into stereo mode and move the voice to the right & left + looks a bit overcomplicated... */ } - } + return 1; + } } - if (i == MAX_PCM_CHANNELS) - card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; + card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer; return 0; } #endif @@ -505,10 +527,11 @@ switch (ch) { case SOUND_MIXER_VOLUME: - case SOUND_MIXER_DIGITAL1: - case SOUND_MIXER_LINE3: - DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3"); - update_digital(card); + DPF(4, "SOUND_MIXER_VOLUME:\n"); + if (card->isaps) + aps_update_digital(card); + else + update_digital(card); return 0; case SOUND_MIXER_PCM: DPF(4, "SOUND_MIXER_PCM\n"); @@ -516,6 +539,34 @@ if (update_pcm_attn(card, l1, r1)) return 0; #endif + if (card->isaps) + aps_update_digital(card); + else + update_digital(card); + return 0; +#ifdef TONE_CONTROL + case SOUND_MIXER_TREBLE: + DPF(4, "SOUND_MIXER_TREBLE:\n"); + set_treble(card, l1, r1); + return 0; + + case SOUND_MIXER_BASS: + DPF(4, "SOUND_MIXER_BASS:\n"); + set_bass(card, l1, r1); + return 0; +#endif + default: + break; + } + + + if (card->isaps) + return -EINVAL; + + switch (ch) { + case SOUND_MIXER_DIGITAL1: + case SOUND_MIXER_LINE3: + DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3"); update_digital(card); return 0; case SOUND_MIXER_DIGITAL2: @@ -549,7 +600,7 @@ DPF(4, "SOUND_MIXER_MIC:\n"); i = 0; if (l1 >= 30) - // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 + /* 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 */ { l1 -= 30; i = 0x40; @@ -572,16 +623,6 @@ sblive_writeac97(card, volreg[ch], wval); return 0; - case SOUND_MIXER_TREBLE: - DPF(4, "SOUND_MIXER_TREBLE:\n"); - set_treble(card, l1, r1); - return 0; - - case SOUND_MIXER_BASS: - DPF(4, "SOUND_MIXER_BASS:\n"); - set_bass(card, l1, r1); - return 0; - default: DPF(2, "Got unknown SOUND_MIXER ioctl\n"); return -EINVAL; @@ -597,6 +638,10 @@ /* Mixer file operations */ /* FIXME: Do we need spinlocks in here? */ +/* WARNING! not all the ioctl's are supported by the emu-APS + (anything AC97 related). As a general rule keep the AC97 related ioctls + separate from the rest. This will make it easier to rewrite the mixer + using the kernel AC97 interface. */ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { static const char id[] = "SBLive"; @@ -658,10 +703,201 @@ return -EFAULT; for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++) - sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]); + sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & DM_MUTE) ? 0 : card->digmix[i]); return 0; break; + case SOUND_MIXER_PRIVATE3: { + struct mixer_private_ioctl ctl; + + if (copy_from_user(&ctl, (void *) arg, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + switch (ctl.cmd) { +#ifdef EMU10K1_DEBUG + case CMD_WRITEFN0: + emu10k1_writefn0(card, ctl.val[0], ctl.val[1]); + return 0; + break; + + case CMD_WRITEPTR: + if(ctl.val[1] >= 0x40) + return -EINVAL; + + if(ctl.val[0] > 0xff) + return -EINVAL; + + if((ctl.val[0] & 0x7ff) > 0x3f) + ctl.val[1] = 0x00; + + sblive_writeptr(card, ctl.val[0], ctl.val[1], ctl.val[2]); + + return 0; + break; +#endif + case CMD_READFN0: + ctl.val[2] = emu10k1_readfn0(card, ctl.val[0]); + + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_READPTR: + if(ctl.val[1] >= 0x40) + return -EINVAL; + + if((ctl.val[0] & 0x7ff) > 0xff) + return -EINVAL; + + if((ctl.val[0] & 0x7ff) > 0x3f) + ctl.val[1] = 0x00; + + ctl.val[2] = sblive_readptr(card, ctl.val[0], ctl.val[1]); + + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_SETRECSRC: + switch(ctl.val[0]){ + case WAVERECORD_AC97: + if(card->isaps) + return -EINVAL; + card->wavein.recsrc = WAVERECORD_AC97; + break; + case WAVERECORD_MIC: + card->wavein.recsrc = WAVERECORD_MIC; + break; + case WAVERECORD_FX: + card->wavein.recsrc = WAVERECORD_FX; + card->wavein.fxwc = ctl.val[1] & 0xffff; + if(!card->wavein.fxwc) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; + break; + + case CMD_GETRECSRC: + ctl.val[0] = card->wavein.recsrc; + ctl.val[1] = card->wavein.fxwc; + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_GETVOICEPARAM: + + ctl.val[0] = card->waveout.send_routing[0]; + ctl.val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 | + card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24; + + ctl.val[2] = card->waveout.send_routing[1]; + ctl.val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 | + card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24; + + ctl.val[4] = card->waveout.send_routing[2]; + ctl.val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 | + card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24; + + if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl))) + return -EFAULT; + + return 0; + break; + + case CMD_SETVOICEPARAM: + card->waveout.send_routing[0] = ctl.val[0] & 0xffff; + card->waveout.send_a[0] = ctl.val[1] & 0xff; + card->waveout.send_b[0] = (ctl.val[1] >> 8) & 0xff; + card->waveout.send_c[0] = (ctl.val[1] >> 16) & 0xff; + card->waveout.send_d[0] = (ctl.val[1] >> 24) & 0xff; + + card->waveout.send_routing[1] = ctl.val[2] & 0xffff; + card->waveout.send_a[1] = ctl.val[3] & 0xff; + card->waveout.send_b[1] = (ctl.val[3] >> 8) & 0xff; + card->waveout.send_c[1] = (ctl.val[3] >> 16) & 0xff; + card->waveout.send_d[1] = (ctl.val[3] >> 24) & 0xff; + + card->waveout.send_routing[2] = ctl.val[4] & 0xffff; + card->waveout.send_a[2] = ctl.val[5] & 0xff; + card->waveout.send_b[2] = (ctl.val[5] >> 8) & 0xff; + card->waveout.send_c[2] = (ctl.val[5] >> 16) & 0xff; + card->waveout.send_d[2] = (ctl.val[5] >> 24) & 0xff; + + return 0; + break; + + default: + return -EINVAL; + break; + } + } + break; + + case SOUND_MIXER_PRIVATE4:{ + u32 size; + int size_reg = 0; + + if (copy_from_user(&size, (void *) arg, sizeof(size))) + return -EFAULT; + + DPD(2,"External tram size 0x%x\n", size); + + if(size > 0x1fffff) + return -EINVAL; + + if (size != 0) { + size = (size - 1) >> 14; + + while (size) { + size >>= 1; + size_reg++; + } + + size = 0x4000 << size_reg; + } + + DPD(2,"External tram size 0x%x 0x%x\n", size, size_reg); + + if (size != card->tankmem.size) { + if (card->tankmem.size > 0) { + emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1); + + sblive_writeptr_tag(card, 0, TCB, 0, + TCBS, 0, + TAGLIST_END); + + pci_free_consistent(card->pci_dev, card->tankmem.size, + card->tankmem.addr, card->tankmem.dma_handle); + + card->tankmem.size = 0; + } + + if (size != 0) { + if ((card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size, + &card->tankmem.dma_handle)) == NULL) + return -ENOMEM; + + card->tankmem.size = size; + + sblive_writeptr_tag(card, 0, TCB, card->tankmem.dma_handle, + TCBS, size_reg, + TAGLIST_END); + + emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0); + } + } + return 0; + } + break; default: break; @@ -672,57 +908,107 @@ if (_IOC_DIR(cmd) == _IOC_READ) { switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - DPF(2, "SOUND_MIXER_READ_RECSRC\n"); - sblive_readac97(card, AC97_RECORDSELECT, ®); - return put_user(recsrc[reg & 7], (int *) arg); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - DPF(4, "SOUND_MIXER_READ_DEVMASK\n"); + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + DPF(4, "SOUND_MIXER_READ_DEVMASK\n"); + if (card->isaps) +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_BASS | SOUND_MASK_TREBLE, + (int *) arg); +#else + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME, + (int *) arg); +#endif + +#ifdef TONE_CONTROL return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_PHONEIN | SOUND_MASK_MIC | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | + SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); +#else + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | + SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_PHONEIN | SOUND_MASK_MIC | + SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | + SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); +#endif + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + DPF(2, "SOUND_MIXER_READ_RECMASK\n"); + if (card->isaps) + return put_user(0, (int *) arg); + + return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | + SOUND_MASK_LINE1 | SOUND_MASK_LINE | + SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | + SOUND_MASK_PHONEIN, (int *) arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + DPF(2, "SOUND_MIXER_READ_STEREODEVS\n"); + + if (card->isaps) +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME | + SOUND_MASK_BASS | SOUND_MASK_TREBLE, + (int *) arg); +#else + return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME, + (int *) arg); +#endif + +#ifdef TONE_CONTROL + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME | - SOUND_MASK_PHONEIN | SOUND_MASK_MIC | SOUND_MASK_BASS | SOUND_MASK_TREBLE | - SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | - SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | - SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - DPF(2, "SOUND_MIXER_READ_RECMASK\n"); - return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | - SOUND_MASK_LINE1 | SOUND_MASK_LINE | - SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | - SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR | - SOUND_MASK_PCM, (int *) arg); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - DPF(2, "SOUND_MIXER_READ_STEREODEVS\n"); - return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | + SOUND_MASK_RECLEV | SOUND_MASK_LINE3 | + SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | + SOUND_MASK_LINE2, (int *) arg); +#else + return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME | - SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | SOUND_MASK_LINE3 | - SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | + SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg); +#endif - case SOUND_MIXER_CAPS: - DPF(2, "SOUND_MIXER_READ_CAPS\n"); - return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); - + case SOUND_MIXER_CAPS: + DPF(2, "SOUND_MIXER_READ_CAPS\n"); + return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg); #ifdef PRIVATE_PCM_VOLUME - case SOUND_MIXER_PCM: - // needs to be before default: !! - { - int i; - - for (i = 0; i < MAX_PCM_CHANNELS; i++) { - if (sblive_pcm_volume[i].files == current->files) { - return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg); - } - } - } + case SOUND_MIXER_PCM: + /* needs to be before default: !!*/ + { + int i; + + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg); + } + } + } #endif default: + break; + } + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + DPF(2, "SOUND_MIXER_READ_RECSRC\n"); + if (card->isaps) + return put_user(0, (int *) arg); + + sblive_readac97(card, AC97_RECORDSELECT, ®); + return put_user(recsrc[reg & 7], (int *) arg); + + default: i = _IOC_NR(cmd); DPD(4, "SOUND_MIXER_READ(%d)\n", i); if (i >= SOUND_MIXER_NRDEVICES) @@ -737,6 +1023,7 @@ #endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } + /* End of _IOC_READ */ if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) return -EINVAL; @@ -748,10 +1035,13 @@ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ DPF(2, "SOUND_MIXER_WRITE_RECSRC\n"); + if (card->isaps) + return -EINVAL; + get_user_ret(val, (int *) arg, -EFAULT); i = hweight32(val); if (i == 0) - return 0; /*val = mixer_recmask(s); */ + return 0; /* val = mixer_recmask(s); */ else if (i > 1) { sblive_readac97(card, AC97_RECORDSELECT, ®); val &= ~recsrc[reg & 7]; @@ -809,14 +1099,14 @@ static int emu10k1_mixer_release(struct inode *inode, struct file *file) { - DPF(3, "emu10k1_mixer_release()\n"); + DPF(4, "emu10k1_mixer_release()\n"); return 0; } struct file_operations emu10k1_mixer_fops = { - owner:THIS_MODULE, - llseek:emu10k1_mixer_llseek, - ioctl:emu10k1_mixer_ioctl, - open:emu10k1_mixer_open, - release:emu10k1_mixer_release, + owner: THIS_MODULE, + llseek: emu10k1_mixer_llseek, + ioctl: emu10k1_mixer_ioctl, + open: emu10k1_mixer_open, + release: emu10k1_mixer_release, }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/osutils.c linux/drivers/sound/emu10k1/osutils.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/osutils.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/osutils.c Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ - -/* - ********************************************************************** - * osutils.c - OS Services layer for emu10k1 driver - * Copyright 1999, 2000 Creative Labs, Inc. - * - ********************************************************************** - * - * Date Author Summary of changes - * ---- ------ ------------------ - * October 20, 1999 Bertrand Lee base code release - * November 2, 1999 Alan Cox cleaned up - * - ********************************************************************** - * - * 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. - * - ********************************************************************** - */ - -#include "hwaccess.h" - -struct memhandle *emu10k1_alloc_memphysical(u32 size) -{ - struct memhandle *handle; - u32 reqpage, order; - - if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL) - return handle; - - DPD(3, "kmalloc: [%p]\n", handle); - - order = 0; - reqpage = size / PAGE_SIZE; - - if (size % PAGE_SIZE) - reqpage++; - - if (reqpage != 0) { - reqpage--; - while (reqpage > 0) { - reqpage >>= 1; - order++; - } - } - - if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) { - kfree(handle); - - DPD(3, "kfree: [%p]\n", handle); - return (void *) NULL; - } - - /* in linux, we can directly access physical address, don't need to do - * phys_to_virt. - * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages - * returns physical address. But in kernel 2.2.1 upwards, - * get_free_pages returns virtual address, we need to convert it - * to physical address. Then this physical address can be used to - * program hardware registers. */ - handle->busaddx = virt_to_bus(handle->virtaddx); - handle->order = order; - - DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx); - - return handle; -} - -void emu10k1_free_memphysical(struct memhandle *handle) -{ - free_pages((unsigned long) handle->virtaddx, handle->order); - kfree(handle); - - DPD(3, "free_pages: [%p]\n", handle->virtaddx); - DPD(3, "kfree: [%p]\n", handle); - - return; -} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/recmgr.c linux/drivers/sound/emu10k1/recmgr.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/recmgr.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/recmgr.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * recmgr.c -- Recording manager for emu10k1 driver @@ -30,110 +29,110 @@ ********************************************************************** */ -#include "hwaccess.h" +#include "8010.h" #include "recmgr.h" -void emu10k1_start_record(struct record *rec_ptr) +void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer) { - struct emu10k1_card *hw_ptr = rec_ptr->card; - DPF(2, "emu10k1_start_record()\n"); - DPD(2, "bus addx: %lx\n", rec_ptr->busaddx); - sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx); - sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize); + sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval); - if (rec_ptr->adcctl) - sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl); + if (buffer->adcctl) + sblive_writeptr(card, ADCCR, 0, buffer->adcctl); return; } -void emu10k1_stop_record(struct record *rec_ptr) +void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer) { - struct emu10k1_card *hw_ptr = rec_ptr->card; - DPF(2, "emu10k1_stop_record()\n"); /* Disable record transfer */ - if (rec_ptr->adcctl) - sblive_writeptr(hw_ptr, ADCCR, 0, 0); + if (buffer->adcctl) + sblive_writeptr(card, ADCCR, 0, 0); - sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE); + sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE); return; } -void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc) +void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst) { + struct wavein_buffer *buffer = &wiinst->buffer; + DPF(2, "emu10k1_set_record_src()\n"); - switch (recsrc) { + switch (wiinst->recsrc) { case WAVERECORD_AC97: DPF(2, "recording source: AC97\n"); - rec_ptr->bufsizereg = ADCBS; - rec_ptr->bufaddrreg = ADCBA; - rec_ptr->bufidxreg = ADCIDX_IDX; + buffer->sizereg = ADCBS; + buffer->addrreg = ADCBA; + buffer->idxreg = ADCIDX_IDX; - switch (rec_ptr->samplingrate) { + switch (wiinst->format.samplingrate) { case 0xBB80: - rec_ptr->adcctl = ADCCR_SAMPLERATE_48; + buffer->adcctl = ADCCR_SAMPLERATE_48; break; case 0xAC44: - rec_ptr->adcctl = ADCCR_SAMPLERATE_44; + buffer->adcctl = ADCCR_SAMPLERATE_44; break; case 0x7D00: - rec_ptr->adcctl = ADCCR_SAMPLERATE_32; + buffer->adcctl = ADCCR_SAMPLERATE_32; break; case 0x5DC0: - rec_ptr->adcctl = ADCCR_SAMPLERATE_24; + buffer->adcctl = ADCCR_SAMPLERATE_24; break; case 0x5622: - rec_ptr->adcctl = ADCCR_SAMPLERATE_22; + buffer->adcctl = ADCCR_SAMPLERATE_22; break; case 0x3E80: - rec_ptr->adcctl = ADCCR_SAMPLERATE_16; + buffer->adcctl = ADCCR_SAMPLERATE_16; break; case 0x2B11: - rec_ptr->adcctl = ADCCR_SAMPLERATE_11; + buffer->adcctl = ADCCR_SAMPLERATE_11; break; case 0x1F40: - rec_ptr->adcctl = ADCCR_SAMPLERATE_8; + buffer->adcctl = ADCCR_SAMPLERATE_8; break; default: + BUG(); break; } - rec_ptr->adcctl |= ADCCR_LCHANENABLE; + buffer->adcctl |= ADCCR_LCHANENABLE; - if (rec_ptr->is_stereo) - rec_ptr->adcctl |= ADCCR_RCHANENABLE; - - // rec_ptr->fxwc = 0; + if (wiinst->format.channels == 2) + buffer->adcctl |= ADCCR_RCHANENABLE; break; case WAVERECORD_MIC: DPF(2, "recording source: MIC\n"); - rec_ptr->bufsizereg = MICBS; - rec_ptr->bufaddrreg = MICBA; - rec_ptr->bufidxreg = MICIDX_IDX; - rec_ptr->adcctl = 0; - // rec_ptr->fxwc = 0; + buffer->sizereg = MICBS; + buffer->addrreg = MICBA; + buffer->idxreg = MICIDX_IDX; + buffer->adcctl = 0; break; case WAVERECORD_FX: DPF(2, "recording source: FX\n"); - rec_ptr->bufsizereg = FXBS; - rec_ptr->bufaddrreg = FXBA; - rec_ptr->bufidxreg = FXIDX_IDX; - rec_ptr->adcctl = 0; - // rec_ptr->fxwc = 0x000ffff; + buffer->sizereg = FXBS; + buffer->addrreg = FXBA; + buffer->idxreg = FXIDX_IDX; + buffer->adcctl = 0; + + sblive_writeptr(card, FXWC, 0, wiinst->fxwc); break; default: + BUG(); break; } + + DPD(2, "bus addx: %x\n", buffer->dma_handle); + + sblive_writeptr(card, buffer->addrreg, 0, buffer->dma_handle); return; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/recmgr.h linux/drivers/sound/emu10k1/recmgr.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/recmgr.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/recmgr.h Mon Aug 14 08:32:48 2000 @@ -32,31 +32,17 @@ #ifndef _RECORDMGR_H #define _RECORDMGR_H -struct record -{ - struct emu10k1_card *card; - u8 *recbuffer; - u32 recpos; - int is_stereo; - int is_16bit; - u32 recbufsize; - u32 bufsize; - u32 bufsizereg; - u32 bufaddrreg; - u32 bufidxreg; - u32 adcctl; - unsigned long busaddx; - u32 samplingrate; -}; +#include "hwaccess.h" +#include "cardwi.h" /* Recording resources */ #define WAVERECORD_AC97 0x01 #define WAVERECORD_MIC 0x02 #define WAVERECORD_FX 0x03 -void emu10k1_start_record(struct record *); -void emu10k1_stop_record(struct record *); -void emu10k1_set_record_src(struct record *, u8); +void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *); +void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *); +void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst); #endif /* _RECORDMGR_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/timer.c linux/drivers/sound/emu10k1/timer.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/timer.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/timer.c Mon Aug 14 08:32:48 2000 @@ -29,6 +29,9 @@ /* 4/3/2000 Implemented timer list using list.h Rui Sousa */ #include "hwaccess.h" +#include "8010.h" +#include "irqmgr.h" +#include "timer.h" /* Try to schedule only once per fragment */ @@ -42,7 +45,7 @@ list_for_each(entry, &card->timers) { t = list_entry(entry, struct emu_timer, list); - if (t->active) { + if (t->state & TIMER_STATE_ACTIVE) { t->count++; if (t->count == t->count_max) { t->count = 0; @@ -56,22 +59,17 @@ return; } -struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay) +void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u32 delay) { - struct emu_timer *timer; struct emu_timer *t; struct list_head *entry; unsigned long flags; - if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL) - return timer; - if (delay < 5) delay = 5; timer->delay = delay; - tasklet_init(&timer->tasklet, func, data); - timer->active = 0; + timer->state = TIMER_STATE_INSTALLED; spin_lock_irqsave(&card->timer_lock, flags); @@ -87,7 +85,7 @@ card->timer_delay = delay; delay = (delay < 1024 ? delay : 1024); - WRITE_FN0(card, TIMER_RATE, delay); + emu10k1_writefn0(card, TIMER_RATE, delay); list_for_each(entry, &card->timers) { t = list_entry(entry, struct emu_timer, list); @@ -103,7 +101,7 @@ spin_unlock_irqrestore(&card->timer_lock, flags); - return timer; + return; } void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) @@ -113,6 +111,9 @@ u32 delay = TIMER_STOPPED; unsigned long flags; + if (timer->state == TIMER_STATE_UNINSTALLED) + return; + spin_lock_irqsave(&card->timer_lock, flags); list_del(&timer->list); @@ -132,7 +133,7 @@ else { delay = (delay < 1024 ? delay : 1024); - WRITE_FN0(card, TIMER_RATE, delay); + emu10k1_writefn0(card, TIMER_RATE, delay); list_for_each(entry, &card->timers) { t = list_entry(entry, struct emu_timer, list); @@ -147,8 +148,7 @@ spin_unlock_irqrestore(&card->timer_lock, flags); - tasklet_unlock_wait(&timer->tasklet); - kfree(timer); + timer->state = TIMER_STATE_UNINSTALLED; return; } @@ -158,7 +158,7 @@ unsigned long flags; spin_lock_irqsave(&card->timer_lock, flags); - timer->active = 1; + timer->state |= TIMER_STATE_ACTIVE; spin_unlock_irqrestore(&card->timer_lock, flags); return; @@ -169,7 +169,7 @@ unsigned long flags; spin_lock_irqsave(&card->timer_lock, flags); - timer->active = 0; + timer->state &= ~TIMER_STATE_ACTIVE; spin_unlock_irqrestore(&card->timer_lock, flags); return; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/timer.h linux/drivers/sound/emu10k1/timer.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/timer.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/timer.h Mon Aug 14 08:32:48 2000 @@ -27,21 +27,27 @@ #ifndef _TIMER_H #define _TIMER_H +#include +#include "hwaccess.h" + struct emu_timer { struct list_head list; struct tasklet_struct tasklet; - int active; + u8 state; u32 count; /* current number of interrupts */ u32 count_max; /* number of interrupts needed to schedule the bh */ u32 delay; /* timer delay */ }; -struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32); +void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u32); void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *); -#define TIMER_STOPPED 0xffffffff +#define TIMER_STOPPED 0xffffffff +#define TIMER_STATE_INSTALLED 0x01 +#define TIMER_STATE_ACTIVE 0x02 +#define TIMER_STATE_UNINSTALLED 0x04 #endif /* _TIMER_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/voicemgr.c linux/drivers/sound/emu10k1/voicemgr.c --- v2.4.0-test6/linux/drivers/sound/emu10k1/voicemgr.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/voicemgr.c Mon Aug 14 08:32:48 2000 @@ -1,4 +1,3 @@ - /* ********************************************************************** * voicemgr.c - Voice manager for emu10k1 driver @@ -30,320 +29,288 @@ ********************************************************************** */ -#include "hwaccess.h" +#include "voicemgr.h" +#include "8010.h" -struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc) +int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice) { - struct emu10k1_card *card = voicemgr->card; - struct emu_voice *voice_tmp = voicemgr->voice; - struct emu_voice *voice = NULL; + u8 *voicetable = card->voicetable; int i; unsigned long flags; DPF(2, "emu10k1_voice_alloc()\n"); - spin_lock_irqsave(&voicemgr->lock, flags); + spin_lock_irqsave(&card->lock, flags); - if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) { - for (i = 0; i < NUM_G; i++) - if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) { - voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; - voice_tmp[i].usage = voiceallocdesc->usage; - voice = &voice_tmp[i]; + if (voice->flags & VOICE_FLAGS_STEREO) { + for (i = 0; i < NUM_G; i += 2) + if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) { + voicetable[i] = voice->usage; + voicetable[i + 1] = voice->usage; break; } } else { - for (i = 0; i < NUM_G; i += 2) - if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE) - && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) { - voice_tmp[i].linked_voice = &voice_tmp[i + 1]; - voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags; - voice_tmp[i].usage = voiceallocdesc->usage; - voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags; - voice_tmp[i + 1].usage = voiceallocdesc->usage; - voice = &voice_tmp[i]; + for (i = 0; i < NUM_G; i++) + if (voicetable[i] == VOICE_USAGE_FREE) { + voicetable[i] = voice->usage; break; } } - spin_unlock_irqrestore(&voicemgr->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); - voice_tmp = voice; + if (i >= NUM_G) + return -1; - while (voice_tmp != NULL) { + voice->card = card; + voice->num = i; - DPD(2, " voice allocated -> %d\n", voice_tmp->num); +#ifdef PRIVATE_PCM_VOLUME - sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff); - sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF); - sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff); - sblive_writeptr(card, PTRX, voice_tmp->num, 0); + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + sblive_pcm_volume[i].channel_l = voice->num; + DPD(2, "preset left: %d\n", voice->num); + if (voice->flags & VOICE_FLAGS_STEREO) { + sblive_pcm_volume[i].channel_r = voice->num + 1; + DPD(2, "preset right: %d\n", voice->num + 1); + } + break; + } + } +#endif + + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + DPD(2, " voice allocated -> %d\n", voice->num + i); - voice_tmp = voice_tmp->linked_voice; + sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff, + DCYSUSV, 0, + VTFT, 0x0000ffff, + PTRX, 0, + TAGLIST_END); } - return voice; + return 0; } -void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice) +void emu10k1_voice_free(struct emu_voice *voice) { struct emu10k1_card *card = voice->card; - struct emu_voice *voice_tmp; - unsigned dcysusv; - u32 cra, sample; int i; unsigned long flags; DPF(2, "emu10k1_voice_free()\n"); - voice_tmp = voice; - - while (voice_tmp != NULL) { - - DPD(2, " voice freed -> %d\n", voice_tmp->num); + if (voice->usage == VOICE_USAGE_FREE) + return; - sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK); - sblive_writeptr(card, IP, voice_tmp->num, 0); +#ifdef PRIVATE_PCM_VOLUME + for (i = 0; i < MAX_PCM_CHANNELS; i++) { + if (sblive_pcm_volume[i].files == current->files) { + if (voice->num == sblive_pcm_volume[i].channel_l) + sblive_pcm_volume[i].channel_l = NUM_G; + if ((voice->flags & VOICE_FLAGS_STEREO) + && (voice->num + 1) == sblive_pcm_volume[i].channel_r) { + sblive_pcm_volume[i].channel_r = NUM_G; + } + break; + } + } +#endif - dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK); - sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF); + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + DPD(2, " voice released -> %d\n", voice->num + i); - sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK); - sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0); - sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK); - sblive_writeptr(card, CPF, voice_tmp->num, 0); + sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0, + VTFT, 0x0000ffff, + PTRX_PITCHTARGET, 0, + CVCF, 0x0000ffff, + CPF, 0, + TAGLIST_END); + } - sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080; - cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK; - sblive_writeptr(card, CCR, voice_tmp->num, cra); - cra = (cra >> 18) & 0xf; - sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); - cra = (cra + 0x1) & 0xf; - sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample); + voice->usage = VOICE_USAGE_FREE; - for (i = 0; i < NUM_FXSENDS; i++) - voice_tmp->sendhandle[i] = 0; + spin_lock_irqsave(&card->lock, flags); - voice_tmp->flags = 0; + card->voicetable[voice->num] = VOICE_USAGE_FREE; - spin_lock_irqsave(&voicemgr->lock, flags); - voice_tmp->usage = VOICEMGR_USAGE_FREE; + if (voice->flags & VOICE_FLAGS_STEREO) + card->voicetable[voice->num + 1] = VOICE_USAGE_FREE; - voice_tmp = voice_tmp->linked_voice; - voice->linked_voice = NULL; - spin_unlock_irqrestore(&voicemgr->lock, flags); - } + spin_unlock_irqrestore(&card->lock, flags); return; } -/* Sets up a voices for Wave Playback */ - void emu10k1_voice_playback_setup(struct emu_voice *voice) { struct emu10k1_card *card = voice->card; - u32 sample, cra = 0, start = 0; + u32 start; + int i; DPF(2, "emu10k1_voice_playback_setup()\n"); - while (voice != NULL) { - sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF); - sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK); - sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK); - sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000); - - /* Stop CA */ - /* Assumption that PT is alreadt 0 so no harm overwriting */ - sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b); - - if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) { - if (voice->linked_voice != NULL) { - /* Set stereo bit */ - cra = 64; - sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK); - sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK); - } else { - cra = 32; - sblive_writeptr(card, CPF, voice->num, 0); - } - - if (voice->flags & VOICEMGR_FLAGS_16BIT) - sample = 0; - else { - cra = cra * 2; - sample = 0x80808080; - } - cra -= 4; - - if (voice->linked_voice != NULL) { - /* CCR_READADDRESS_MASK */ - sblive_writeptr(card, CCR, voice->num, 0x3c << 16); - sblive_writeptr(card, CCR, voice->num + 1, cra << 16); - sblive_writeptr(card, CDE, voice->num + 1, sample); - sblive_writeptr(card, CDF, voice->num + 1, sample); - start = voice->params.start + cra / 2; - } else { - sblive_writeptr(card, CCR, voice->num, 0x1c << 16); /* FIXME: Is 0x1c correct? */ - sblive_writeptr(card, CDE, voice->num, sample); - sblive_writeptr(card, CDF, voice->num, sample); - start = voice->params.start + cra; - } - - if (start > voice->params.endloop) { - start -= voice->params.endloop; + if (voice->flags & VOICE_FLAGS_STEREO) { + /* Set stereo bit */ + start = 28; + sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK); + sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK); + } else { + start = 30; + sblive_writeptr(card, CPF, voice->num, 0); + } - if (voice->linked_voice != NULL) - cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9); - else - cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9); - - start += voice->params.startloop; - - if (start >= voice->params.endloop) - start = voice->params.endloop - 1; - } else if (voice->linked_voice != NULL) - cra = (cra << 25) | (0x3c << 16); - else - cra = (cra << 25) | (0x1c << 16); + if(!(voice->flags & VOICE_FLAGS_16BIT)) + start *= 2; - start |= CCCA_INTERPROM_0; - } + voice->start += start; - /* CSL, ST, CA */ - sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24)); - sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24)); - - if (voice->flags & VOICEMGR_FLAGS_16BIT) - sblive_writeptr(card, CCCA, voice->num, start); - else - sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT); - - /* Clear filter delay memory */ - sblive_writeptr(card, Z1, voice->num, 0); - sblive_writeptr(card, Z2, voice->num, 0); - - /* Invalidate maps */ - sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); - sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2)); + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16); - /* Fill cache */ - if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) - sblive_writeptr(card, CCR, voice->num, cra); + /* Stop CA */ + /* Assumption that PT is already 0 so no harm overwriting */ + sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b); - sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK); - sblive_writeptr(card, LFOVAL1, voice->num, 0x8000); - sblive_writeptr(card, ATKHLDM, voice->num, 0); - sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK); - sblive_writeptr(card, LFOVAL2, voice->num, 0x8000); - sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch); - sblive_writeptr(card, PEFE, voice->num, 0x7f); - sblive_writeptr(card, FMMOD, voice->num, 0); - sblive_writeptr(card, TREMFRQ, voice->num, 0); - sblive_writeptr(card, FM2FRQ2, voice->num, 0); - sblive_writeptr(card, ENVVAL, voice->num, 0xbfff); - sblive_writeptr(card, ENVVOL, voice->num, 0xbfff); + sblive_writeptr_tag(card, voice->num + i, + /* CSL, ST, CA */ + DSL, voice->endloop | (voice->params[i].send_d << 24), + PSST, voice->startloop | (voice->params[i].send_c << 24), + CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT), + /* Clear filter delay memory */ + Z1, 0, + Z2, 0, + /* Invalidate maps */ + MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), + /* modulation envelope */ + CVCF, 0x0000ffff, + VTFT, 0x0000ffff, + ATKHLDM, 0, + DCYSUSM, 0x007f, + LFOVAL1, 0x8000, + LFOVAL2, 0x8000, + FMMOD, 0, + TREMFRQ, 0, + FM2FRQ2, 0, + ENVVAL, 0x8000, + /* volume envelope */ + ATKHLDV, 0x7f7f, + ENVVOL, 0x8000, + /* filter envelope */ + PEFE_FILTERAMOUNT, 0x7f, + /* pitch envelope */ + PEFE_PITCHAMOUNT, 0, TAGLIST_END); #ifdef PRIVATE_PCM_VOLUME - { - int i; - - for (i = 0; i < MAX_PCM_CHANNELS; i++) { - if (sblive_pcm_volume[i].channel_l == voice->num) { - voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l : - // test for mono channel (reverse logic is correct here!) - (sblive_pcm_volume[i].attn_r > - sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r; - DPD(2, "set left volume %d\n", voice->params.initial_attn); - break; - } else if (sblive_pcm_volume[i].channel_r == voice->num) { - voice->params.initial_attn = sblive_pcm_volume[i].attn_r; - DPD(2, "set right volume %d\n", voice->params.initial_attn); - break; - } - } - } +{ +int j; + for (j = 0; j < MAX_PCM_CHANNELS; j++) { + if (sblive_pcm_volume[j].channel_l == voice->num + i) { + voice->params[i].initial_attn = (sblive_pcm_volume[j].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l : + // test for mono channel (reverse logic is correct here!) + (sblive_pcm_volume[j].attn_r > + sblive_pcm_volume[j].attn_l) ? sblive_pcm_volume[j].attn_l : sblive_pcm_volume[j].attn_r; + DPD(2, "set left volume %d\n", voice->params[i].initial_attn); + break; + } else if (sblive_pcm_volume[j].channel_r == voice->num + i) { + voice->params[i].initial_attn = sblive_pcm_volume[j].attn_r; + DPD(2, "set right volume %d\n", voice->params[i].initial_attn); + break; + } + } + } #endif - sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn); - voice->params.FC_target = 0xffff; - voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16); - - voice = voice->linked_voice; + voice->params[i].fc_target = 0xffff; } return; } -void emu10k1_voice_start(struct emu_voice *voice) +void emu10k1_voice_start(struct emu_voice *voice, int set) { struct emu10k1_card *card = voice->card; + int i; DPF(2, "emu10k1_voice_start()\n"); - while (voice != NULL) { - sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target); - - if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) - sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target); + if (!set) { + u32 cra, ccis, cs, sample; + if (voice->flags & VOICE_FLAGS_STEREO) { + cra = 64; + ccis = 28; + cs = 4; + } else { + cra = 64; + ccis = 30; + cs = 2; + } - sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16) - | voice->params.FC_target); - sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16) - | voice->params.FC_target); - sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8) - | ENV_ON | voice->params.byampl_env_decay); - - /* Using StopOnLoop for MIDI stops the playback - too early, which may cause a DC level to be played - until the note is released. */ - - if (voice->usage == VOICEMGR_USAGE_MIDI) - emu10k1_clear_stop_on_loop(card, voice->num); - else { - if (voice->params.startloop > voice->params.end) - emu10k1_set_stop_on_loop(card, voice->num); - else - emu10k1_clear_stop_on_loop(card, voice->num); + if(voice->flags & VOICE_FLAGS_16BIT) { + sample = 0x00000000; + } else { + sample = 0x80808080; + ccis *= 2; } - voice = voice->linked_voice; - } - return; -} + for(i = 0; i < cs; i++) + sblive_writeptr(card, CD0 + i, voice->num, sample); -void emu10k1_voice_stop(struct emu_voice *voice) -{ - struct emu10k1_card *card = voice->card; + /* Reset cache */ + sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0); + if (voice->flags & VOICE_FLAGS_STEREO) + sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0); - DPF(2, "emu10k1_voice_stop()\n"); + sblive_writeptr(card, CCR_READADDRESS, voice->num, cra); + + if (voice->flags & VOICE_FLAGS_STEREO) + sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra); - while (voice != NULL) { - sblive_writeptr(card, IFATN, voice->num, 0xffff); - sblive_writeptr(card, IP, voice->num, 0); - sblive_writeptr(card, VTFT, voice->num, 0xffff); - sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0); - voice = voice->linked_voice; + /* Fill cache */ + sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis); } - return; -} + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + sblive_writeptr_tag(card, voice->num + i, + IFATN, (voice->params[i].initial_fc << 8) | voice->params[i].initial_attn, + VTFT, (voice->params[i].volume_target << 16) | voice->params[i].fc_target, + CVCF, (voice->params[i].volume_target << 16) | voice->params[i].fc_target, + DCYSUSV, (voice->params[i].byampl_env_sustain << 8) | voice->params[i].byampl_env_decay, + TAGLIST_END); -void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam) -{ - struct emu10k1_card *card = voice->card; - int count; + emu10k1_clear_stop_on_loop(card, voice->num + i); + + sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + i, voice->pitch_target); - for (count = 0; count < numparam; count++) - sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value); + if (i == 0) + sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target); + + sblive_writeptr(card, IP, voice->num + i, voice->initial_pitch); + } return; } -void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value) +void emu10k1_voice_stop(struct emu_voice *voice) { struct emu10k1_card *card = voice->card; + int i; - *value = sblive_readptr(card, controlid, voice->num); + DPF(2, "emu10k1_voice_stop()\n"); + + for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) { + sblive_writeptr_tag(card, voice->num + i, + PTRX_PITCHTARGET, 0, + CPF_CURRENTPITCH, 0, + IFATN, 0xffff, + VTFT, 0x0000ffff, + CVCF, 0x0000ffff, + IP, 0, + TAGLIST_END); + } return; } + diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/emu10k1/voicemgr.h linux/drivers/sound/emu10k1/voicemgr.h --- v2.4.0-test6/linux/drivers/sound/emu10k1/voicemgr.h Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/emu10k1/voicemgr.h Mon Aug 14 08:32:48 2000 @@ -31,120 +31,61 @@ #ifndef _VOICEMGR_H #define _VOICEMGR_H + +#include "hwaccess.h" + /* struct emu_voice.usage flags */ -#define VOICEMGR_USAGE_FREE 0x00000000 -#define VOICEMGR_USAGE_MIDI 0x00000001 -#define VOICEMGR_USAGE_PLAYBACK 0x00000002 +#define VOICE_USAGE_FREE 0x01 +#define VOICE_USAGE_MIDI 0x02 +#define VOICE_USAGE_PLAYBACK 0x04 /* struct emu_voice.flags flags */ -#define VOICEMGR_FLAGS_MONO 0x00000002 -#define VOICEMGR_FLAGS_16BIT 0x00000004 -#define VOICEMGR_FLAGS_STEREOSLAVE 0x00000008 -#define VOICEMGR_FLAGS_VOICEMASTER 0x80000000 -#define VOICEMGR_FLAGS_FXRT2 0x00000010 +#define VOICE_FLAGS_STEREO 0x02 +#define VOICE_FLAGS_16BIT 0x04 struct voice_param { - /* Sound engine */ - u32 start; - u32 startloop; - u32 endloop; - u32 end; - - u16 current_pitch; - u16 pitch_target; - - u16 current_volume; - u16 volume_target; - - u16 current_FC; - u16 FC_target; - - u8 pan_target; - u8 aux_target; - /* FX bus amount send */ + u32 send_routing; + u32 send_a; u32 send_b; u32 send_c; u32 send_d; - /* Envelope engine */ - u16 ampl_env_delay; - u8 byampl_env_attack; - u8 byampl_env_hold; - u8 byampl_env_decay; - u8 byampl_env_sustain; - u8 byampl_env_release; - - u16 aux_env_delay; - u8 byaux_env_attack; - u8 byaux_env_hold; - u8 byaux_env_decay; - u8 byaux_env_sustain; - u8 byaux_env_release; - - u16 mod_LFO_delay; /* LFO1 */ - u16 vib_LFO_delay; /* LFO2 */ - u8 mod_LFO_freq; /* LFO1 */ - u8 vib_LFO_freq; /* LFO2 */ - - s8 aux_env_to_pitch; - s8 aux_env_to_FC; - s8 mod_LFO_to_pitch; - s8 vib_LFO_to_pitch; - s8 mod_LFO_to_FC; - s8 mod_LFO_to_volume; - - u16 sample_pitch; - u16 initial_pitch; - u8 initial_attn; - u8 initial_FC; -}; + u32 initial_fc; + u32 fc_target; -struct voice_allocdesc -{ - u32 usage; /* playback, Midi */ - u32 flags; /* stereo/mono rec/playback 8/16 bit*/ + u32 initial_attn; + u32 volume_target; + + u32 byampl_env_sustain; + u32 byampl_env_decay; }; + struct emu_voice { - struct list_head list; - struct emu10k1_card *card; - u32 usage; /* Free, MIDI, playback */ - u32 num; /* Voice ID */ - u32 flags; /* Stereo/mono, rec/playback, 8/16 bit */ - - struct voice_param params; - - struct emu_voice *linked_voice; /*for stereo voice*/ - - u32 sendhandle[NUM_FXSENDS]; -}; + u8 usage; /* Free, MIDI, playback */ + u8 num; /* Voice ID */ + u8 flags; /* Stereo/mono, 8/16 bit */ -struct voice_manager -{ - struct emu10k1_card *card; - spinlock_t lock; + u32 startloop; + u32 endloop; + u32 start; - struct emu_voice voice[NUM_G]; -}; + u32 initial_pitch; + u32 pitch_target; -struct voice_cntlset -{ - u32 paramID; - u32 value; + struct voice_param params[2]; }; -struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *); -void emu10k1_voice_free(struct voice_manager *, struct emu_voice *); +int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *); +void emu10k1_voice_free(struct emu_voice *); void emu10k1_voice_playback_setup(struct emu_voice *); -void emu10k1_voice_start(struct emu_voice *); +void emu10k1_voice_start(struct emu_voice *, int); void emu10k1_voice_stop(struct emu_voice *); -void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32); -void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *); #endif /* _VOICEMGR_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.0-test6/linux/drivers/sound/es1370.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/es1370.c Sat Aug 12 19:51:52 2000 @@ -302,8 +302,6 @@ #define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) #define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) -#define SND_DEV_DSP16 5 - /* --------------------------------------------------------------------- */ struct es1370_state { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.0-test6/linux/drivers/sound/es1371.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/es1371.c Sat Aug 12 19:51:52 2000 @@ -364,8 +364,6 @@ #define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) #define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) -#define SND_DEV_DSP16 5 - #define ES1371_MODULE_NAME "es1371" #define PFX ES1371_MODULE_NAME ": " diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.4.0-test6/linux/drivers/sound/gus_card.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/gus_card.c Fri Aug 11 08:26:43 2000 @@ -20,7 +20,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "gus.h" #include "gus_hw.h" @@ -184,7 +183,8 @@ hw_config->irq, hw_config->dma, hw_config->dma, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); } static void __exit unload_gus_db16(struct address_info *hw_config) @@ -259,7 +259,7 @@ if (!probe_gus(&cfg)) return -ENODEV; attach_gus(&cfg); - SOUND_LOCK; + return 0; } @@ -270,7 +270,6 @@ unload_gus_db16(&cfg); #endif unload_gus(&cfg); - SOUND_LOCK_END; } module_init(init_gus); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.4.0-test6/linux/drivers/sound/gus_midi.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/gus_midi.c Fri Aug 11 08:26:43 2000 @@ -186,23 +186,17 @@ static struct midi_operations gus_midi_operations = { - { - "Gravis UltraSound Midi", 0, 0, SNDCARD_GUS - }, - &std_midi_synth, - {0}, - gus_midi_open, - gus_midi_close, - NULL, /* ioctl */ - gus_midi_out, - gus_midi_start_read, - gus_midi_end_read, - gus_midi_kick, - NULL, /* - * command - */ - gus_midi_buffer_status, - NULL + owner: THIS_MODULE, + info: {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + converter: &std_midi_synth, + in_info: {0}, + open: gus_midi_open, + close: gus_midi_close, + outputc: gus_midi_out, + start_read: gus_midi_start_read, + end_read: gus_midi_end_read, + kick: gus_midi_kick, + buffer_status: gus_midi_buffer_status, }; void gus_midi_init(struct address_info *hw_config) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.4.0-test6/linux/drivers/sound/gus_wave.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/gus_wave.c Fri Aug 11 08:26:43 2000 @@ -2613,16 +2613,16 @@ 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 + owner: THIS_MODULE, + open: gus_audio_open, + close: gus_audio_close, + output_block: gus_audio_output_block, + start_input: gus_audio_start_input, + ioctl: gus_audio_ioctl, + prepare_for_input: gus_audio_prepare_for_input, + prepare_for_output: gus_audio_prepare_for_output, + halt_io: gus_audio_reset, + local_qlen: gus_local_qlen, }; static void guswave_setup_voice(int dev, int voice, int chn) @@ -2702,27 +2702,28 @@ 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 + owner: THIS_MODULE, + id: "GUS", + info: &gus_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: SAMPLE_TYPE_GUS, + open: guswave_open, + close: guswave_close, + ioctl: guswave_ioctl, + kill_note: guswave_kill_note, + start_note: guswave_start_note, + set_instr: guswave_set_instr, + reset: guswave_reset, + hw_control: guswave_hw_control, + load_patch: guswave_load_patch, + aftertouch: guswave_aftertouch, + controller: guswave_controller, + panning: guswave_panning, + volume_method: guswave_volume_method, + bender: guswave_bender, + alloc_voice: guswave_alloc, + setup_voice: guswave_setup_voice }; static void set_input_volumes(void) @@ -2894,9 +2895,10 @@ static struct mixer_operations gus_mixer_operations = { - "GUS", - "Gravis Ultrasound", - gus_default_mixer_ioctl + owner: THIS_MODULE, + id: "GUS", + name: "Gravis Ultrasound", + ioctl: gus_default_mixer_ioctl }; static int gus_default_mixer_init(void) @@ -3050,7 +3052,8 @@ -irq, gus_dma2, /* Playback DMA */ gus_dma, /* Capture DMA */ 1, /* Share DMA channels with GF1 */ - hw_config->osp); + hw_config->osp, + THIS_MODULE); if (num_mixers > old_num_mixers) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.0-test6/linux/drivers/sound/i810_audio.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/i810_audio.c Sat Aug 12 19:51:52 2000 @@ -189,12 +189,6 @@ /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ #define NR_AC97 2 -/* minor number of /dev/dspW */ -#define SND_DEV_DSP8 1 - -/* minor number of /dev/dspW */ -#define SND_DEV_DSP16 1 - static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.4.0-test6/linux/drivers/sound/ics2101.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/ics2101.c Fri Aug 11 08:26:43 2000 @@ -206,9 +206,10 @@ static struct mixer_operations ics2101_mixer_operations = { - "ICS2101", - "ICS2101 Multimedia Mixer", - ics2101_mixer_ioctl + owner: THIS_MODULE, + id: "ICS2101", + name: "ICS2101 Multimedia Mixer", + ioctl: ics2101_mixer_ioctl }; int diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.4.0-test6/linux/drivers/sound/mad16.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/mad16.c Fri Aug 11 08:26:43 2000 @@ -73,7 +73,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "ad1848.h" #include "sb.h" @@ -710,7 +709,8 @@ hw_config->irq, dma, dma2, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); request_region(hw_config->io_base, 4, "MAD16 WSS config"); } @@ -724,7 +724,7 @@ hw_config->io_base = 0x220; hw_config->name = "Mad16/Mozart"; - sb_dsp_init(hw_config); + sb_dsp_init(hw_config, THIS_MODULE); return; #endif @@ -733,7 +733,7 @@ hw_config->driver_use_1 = SB_MIDI_ONLY; hw_config->name = "Mad16/Mozart"; - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); } static int __init probe_mad16_mpu(struct address_info *hw_config) @@ -1094,7 +1094,6 @@ if (found_mpu) attach_mad16_mpu(&cfg_mpu); - SOUND_LOCK; return 0; } @@ -1103,7 +1102,6 @@ if (found_mpu) unload_mad16_mpu(&cfg_mpu); unload_mad16(&cfg); - SOUND_LOCK_END; } module_init(init_mad16); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.4.0-test6/linux/drivers/sound/maestro.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/maestro.c Sat Aug 12 19:51:52 2000 @@ -301,8 +301,6 @@ #define NR_DSPS (1<irq *= -1; hw_config->name = "Maui"; - attach_mpu401(hw_config); + attach_mpu401(hw_config, THIS_MODULE); if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { struct synth_operations *synth; @@ -443,7 +442,7 @@ if (probe_maui(&cfg) == 0) return -ENODEV; attach_maui(&cfg); - SOUND_LOCK; + return 0; } @@ -452,7 +451,6 @@ if (fw_load && maui_os) vfree(maui_os); unload_maui(&cfg); - SOUND_LOCK_END; } module_init(init_maui); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v2.4.0-test6/linux/drivers/sound/midi_synth.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/midi_synth.c Fri Aug 11 08:26:43 2000 @@ -431,9 +431,6 @@ 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); @@ -461,9 +458,6 @@ midi_devs[orig_dev]->outputc(orig_dev, 0xfe); midi_devs[orig_dev]->close(orig_dev); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif } void diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/midi_synth.h linux/drivers/sound/midi_synth.h --- v2.4.0-test6/linux/drivers/sound/midi_synth.h Tue Sep 30 08:46:45 1997 +++ linux/drivers/sound/midi_synth.h Fri Aug 11 08:26:43 2000 @@ -22,27 +22,26 @@ static struct synth_operations std_midi_synth = { - "MIDI", - &std_synth_info, - 0, - SYNTH_TYPE_MIDI, - 0, - midi_synth_open, - midi_synth_close, - midi_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_voice */ - midi_synth_setup_voice, - midi_synth_send_sysex + owner: THIS_MODULE, + id: "MIDI", + info: &std_synth_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_MIDI, + synth_subtype: 0, + open: midi_synth_open, + close: midi_synth_close, + ioctl: midi_synth_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + hw_control: midi_synth_hw_control, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice, + send_sysex: midi_synth_send_sysex }; #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.4.0-test6/linux/drivers/sound/midibuf.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/midibuf.c Fri Aug 11 08:26:43 2000 @@ -172,6 +172,9 @@ * Interrupts disabled. Be careful */ + if (midi_devs[dev]->owner) + __MOD_INC_USE_COUNT (midi_devs[dev]->owner); + if ((err = midi_devs[dev]->open(dev, mode, midi_input_intr, midi_output_intr)) < 0) return err; @@ -257,6 +260,9 @@ if (open_devs < 2) del_timer(&poll_timer);; open_devs--; + + if (midi_devs[dev]->owner) + __MOD_DEC_USE_COUNT (midi_devs[dev]->owner); } int MIDIbuf_write(int dev, struct file *file, const char *buf, int count) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.4.0-test6/linux/drivers/sound/mpu401.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sound/mpu401.c Fri Aug 11 08:26:43 2000 @@ -15,14 +15,13 @@ * Alan Cox modularisation, use normal request_irq, use dev_id */ -#include #include +#include #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS #include "sound_config.h" -#include "soundmodule.h" #include "coproc.h" #include "mpu401.h" @@ -866,47 +865,45 @@ 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 + owner: THIS_MODULE, + id: "MPU401", + info: NULL, + midi_dev: 0, + synth_type: SYNTH_TYPE_MIDI, + synth_subtype: 0, + open: mpu_synth_open, + close: mpu_synth_close, + ioctl: mpu_synth_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + hw_control: midi_synth_hw_control, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice, + send_sysex: 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 + owner: THIS_MODULE, + info: {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + in_info: {0}, + open: mpu401_open, + close: mpu401_close, + ioctl: mpu401_ioctl, + outputc: mpu401_out, + start_read: mpu401_start_read, + end_read: mpu401_end_read, + kick: mpu401_kick, + buffer_status: mpu401_buffer_status, + prefix_cmd: mpu401_prefix_cmd }; static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; @@ -942,7 +939,7 @@ restore_flags(flags); } -void __init attach_mpu401(struct address_info *hw_config) +void __init attach_mpu401(struct address_info *hw_config, struct module *owner) { unsigned long flags; char revision_char; @@ -1089,6 +1086,10 @@ hw_config->slots[2] = mpu_timer_init(m); midi_devs[m] = &mpu401_midi_operations[devc->devno]; + + if (owner) + midi_devs[m]->owner = owner; + hw_config->slots[1] = m; sequencer_init(); } @@ -1574,15 +1575,16 @@ 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 + owner: THIS_MODULE, + info: {"MPU-401 Timer", 0}, + priority: 10, /* Priority */ + devlink: 0, /* Local device link */ + open: mpu_timer_open, + close: mpu_timer_close, + event: mpu_timer_event, + get_time: mpu_timer_get_time, + ioctl: mpu_timer_ioctl, + arm_timer: mpu_timer_arm }; static void mpu_timer_interrupt(void) @@ -1731,10 +1733,9 @@ cfg.io_base = io; if (probe_mpu401(&cfg) == 0) return -ENODEV; - attach_mpu401(&cfg); + attach_mpu401(&cfg, THIS_MODULE); } - SOUND_LOCK; return 0; } @@ -1744,7 +1745,6 @@ /* Check for use by, for example, sscape driver */ unload_mpu401(&cfg); } - SOUND_LOCK_END; } module_init(init_mpu401); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/mpu401.h linux/drivers/sound/mpu401.h --- v2.4.0-test6/linux/drivers/sound/mpu401.h Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/mpu401.h Fri Aug 11 08:26:43 2000 @@ -7,14 +7,14 @@ /* From uart401.c */ int probe_uart401 (struct address_info *hw_config); -void attach_uart401 (struct address_info *hw_config); +void attach_uart401 (struct address_info *hw_config, struct module *owner); void unload_uart401 (struct address_info *hw_config); void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); /* From mpu401.c */ int probe_mpu401(struct address_info *hw_config); -void attach_mpu401(struct address_info * hw_config); +void attach_mpu401(struct address_info * hw_config, struct module *owner); void unload_mpu401(struct address_info *hw_info); int intchk_mpu401(void *dev_id); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.4.0-test6/linux/drivers/sound/nm256_audio.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/sound/nm256_audio.c Fri Aug 11 08:26:43 2000 @@ -20,7 +20,6 @@ #include #include #include "sound_config.h" -#include "soundmodule.h" #include "nm256.h" #include "nm256_coeff.h" @@ -926,9 +925,10 @@ } static struct mixer_operations nm256_mixer_operations = { - "NeoMagic", - "NM256AC97Mixer", - nm256_default_mixer_ioctl + owner: THIS_MODULE, + id: "NeoMagic", + name: "NM256AC97Mixer", + ioctl: nm256_default_mixer_ioctl }; /* @@ -1621,22 +1621,16 @@ static struct audio_driver nm256_audio_driver = { - nm256_audio_open, /* open */ - nm256_audio_close, /* close */ - nm256_audio_output_block, /* output_block */ - nm256_audio_start_input, /* start_input */ - nm256_audio_ioctl, /* ioctl */ - nm256_audio_prepare_for_input, /* prepare_for_input */ - nm256_audio_prepare_for_output, /* prepare_for_output */ - nm256_audio_reset, /* reset */ - nm256_audio_local_qlen, /*+local_qlen */ - NULL, /*+copy_from_user */ - NULL, /*+halt_input */ - NULL, /* halt_output */ - NULL, /*+trigger */ - NULL, /*+set_speed */ - NULL, /*+set_bits */ - NULL, /*+set_channels */ + owner: THIS_MODULE, + open: nm256_audio_open, + close: nm256_audio_close, + output_block: nm256_audio_output_block, + start_input: nm256_audio_start_input, + ioctl: nm256_audio_ioctl, + prepare_for_input: nm256_audio_prepare_for_input, + prepare_for_output:nm256_audio_prepare_for_output, + halt_io: nm256_audio_reset, + local_qlen: nm256_audio_local_qlen, }; EXPORT_SYMBOL(init_nm256); @@ -1654,7 +1648,6 @@ printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n"); if (init_nm256 () == 0) { - SOUND_LOCK; loaded = 1; return 0; } @@ -1667,8 +1660,6 @@ if (loaded) { struct nm256_info *card; struct nm256_info *next_card; - - SOUND_LOCK_END; for (card = nmcard_list; card != NULL; card = next_card) { stopPlay (card); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.4.0-test6/linux/drivers/sound/opl3.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/opl3.c Fri Aug 11 08:26:43 2000 @@ -31,7 +31,6 @@ */ #include "sound_config.h" -#include "soundmodule.h" #include "opl3.h" #include "opl3_hw.h" @@ -769,7 +768,6 @@ 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; @@ -798,7 +796,6 @@ devc->fm_info.perc_mode = 0; opl3_reset(dev); - MOD_DEC_USE_COUNT; } static void opl3_hw_control(int dev, unsigned char *event) @@ -1061,30 +1058,31 @@ 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 + owner: THIS_MODULE, + id: "OPL", + info: NULL, + midi_dev: 0, + synth_type: SYNTH_TYPE_FM, + synth_subtype: FM_TYPE_ADLIB, + open: opl3_open, + close: opl3_close, + ioctl: opl3_ioctl, + kill_note: opl3_kill_note, + start_note: opl3_start_note, + set_instr: opl3_set_instr, + reset: opl3_reset, + hw_control: opl3_hw_control, + load_patch: opl3_load_patch, + aftertouch: opl3_aftertouch, + controller: opl3_controller, + panning: opl3_panning, + volume_method: opl3_volume_method, + bender: opl3_bender, + alloc_voice: opl3_alloc_voice, + setup_voice: opl3_setup_voice }; -int opl3_init(int ioaddr, int *osp) +int opl3_init(int ioaddr, int *osp, struct module *owner) { int i; int me; @@ -1131,6 +1129,10 @@ opl3_operations.info = &devc->fm_info; synth_devs[me] = &opl3_operations; + + if (owner) + synth_devs[me]->owner = owner; + sequencer_init(); devc->v_alloc = &opl3_operations.alloc; devc->chn_info = &opl3_operations.chn_info[0]; @@ -1198,11 +1200,11 @@ { return -ENODEV; } - me = opl3_init(io, NULL); + me = opl3_init(io, NULL, THIS_MODULE); request_region(io, 4, devc->fm_info.name); } - SOUND_LOCK; + return 0; } @@ -1216,7 +1218,6 @@ devc = NULL; sound_unload_synthdev(me); } - SOUND_LOCK_END; } module_init(init_opl3); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h --- v2.4.0-test6/linux/drivers/sound/opl3.h Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/opl3.h Fri Aug 11 08:26:43 2000 @@ -6,6 +6,6 @@ */ int opl3_detect (int ioaddr, int *osp); -int opl3_init(int ioaddr, int *osp); +int opl3_init(int ioaddr, int *osp, struct module *owner); void enable_opl3_mode(int left, int right, int both); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c --- v2.4.0-test6/linux/drivers/sound/opl3sa.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/opl3sa.c Fri Aug 11 08:26:43 2000 @@ -25,7 +25,6 @@ #undef SB_OK #include "sound_config.h" -#include "soundmodule.h" #include "ad1848.h" #include "mpu401.h" @@ -167,7 +166,7 @@ int nm = num_mixers; /* FIXME */ - attach_ms_sound(hw_config); + attach_ms_sound(hw_config, THIS_MODULE); if (num_mixers > nm) /* A mixer was installed */ { AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); @@ -180,7 +179,7 @@ static void __init attach_opl3sa_mpu(struct address_info *hw_config) { hw_config->name = "OPL3-SA (MPU401)"; - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); } static int __init probe_opl3sa_mpu(struct address_info *hw_config) @@ -313,7 +312,7 @@ attach_opl3sa_wss(&cfg); if(found_mpu) attach_opl3sa_mpu(&cfg_mpu); - SOUND_LOCK; + return 0; } @@ -322,7 +321,6 @@ if(found_mpu) unload_opl3sa_mpu(&cfg_mpu); unload_opl3sa_wss(&cfg); - SOUND_LOCK_END; } module_init(init_opl3sa); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c --- v2.4.0-test6/linux/drivers/sound/opl3sa2.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/opl3sa2.c Fri Aug 11 08:26:43 2000 @@ -41,7 +41,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "ad1848.h" #include "mpu401.h" @@ -436,9 +435,10 @@ static struct mixer_operations opl3sa2_mixer_operations = { - "Yamaha", - "", - opl3sa2_mixer_ioctl + owner: THIS_MODULE, + id: "Yamaha", + name: "", /* hmm? */ + ioctl: opl3sa2_mixer_ioctl }; /* End of mixer-related stuff */ @@ -452,7 +452,7 @@ static inline void __init attach_opl3sa2_mpu(struct address_info *hw_config) { - attach_mpu401(hw_config); + attach_mpu401(hw_config, THIS_MODULE); } @@ -493,7 +493,7 @@ opl3sa2_mixer_reset(devc); - attach_ms_sound(hw_config); /* Slot 0 */ + attach_ms_sound(hw_config, THIS_MODULE); /* Slot 0 */ if(hw_config->slots[0] != -1) { /* Did the MSS driver install? */ @@ -699,7 +699,7 @@ attach_opl3sa2_mpu(&cfg_mpu); } } - SOUND_LOCK; + return 0; } @@ -711,7 +711,6 @@ } unload_opl3sa2_mss(&cfg2); unload_opl3sa2(&cfg); - SOUND_LOCK_END; } module_init(init_opl3sa2); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.4.0-test6/linux/drivers/sound/pas2_card.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/pas2_card.c Fri Aug 11 08:26:43 2000 @@ -8,7 +8,6 @@ #include #include #include "sound_config.h" -#include "soundmodule.h" #include "pas2.h" #include "sb.h" @@ -426,14 +425,13 @@ if (!probe_pas(&cfg)) return -ENODEV; attach_pas_card(&cfg); - SOUND_LOCK; + return 0; } static void __exit cleanup_pas2(void) { unload_pas(&cfg); - SOUND_LOCK_END; } module_init(init_pas2); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v2.4.0-test6/linux/drivers/sound/pas2_midi.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/pas2_midi.c Fri Aug 11 08:26:43 2000 @@ -191,19 +191,17 @@ static struct midi_operations pas_midi_operations = { - {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, - &std_midi_synth, - {0}, - pas_midi_open, - pas_midi_close, - NULL, - pas_midi_out, - pas_midi_start_read, - pas_midi_end_read, - pas_midi_kick, - NULL, - pas_buffer_status, - NULL + owner: THIS_MODULE, + info: {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, + converter: &std_midi_synth, + in_info: {0}, + open: pas_midi_open, + close: pas_midi_close, + outputc: pas_midi_out, + start_read: pas_midi_start_read, + end_read: pas_midi_end_read, + kick: pas_midi_kick, + buffer_status: pas_buffer_status, }; void pas_midi_init(void) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.4.0-test6/linux/drivers/sound/pas2_mixer.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/pas2_mixer.c Fri Aug 11 08:26:43 2000 @@ -309,9 +309,10 @@ static struct mixer_operations pas_mixer_operations = { - "PAS16", - "Pro Audio Spectrum 16", - pas_mixer_ioctl + owner: THIS_MODULE, + id: "PAS16", + name: "Pro Audio Spectrum 16", + ioctl: pas_mixer_ioctl }; int diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v2.4.0-test6/linux/drivers/sound/pas2_pcm.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/pas2_pcm.c Fri Aug 11 08:26:43 2000 @@ -373,19 +373,16 @@ 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 + owner: THIS_MODULE, + open: pas_audio_open, + close: pas_audio_close, + output_block: pas_audio_output_block, + start_input: pas_audio_start_input, + ioctl: pas_audio_ioctl, + prepare_for_input: pas_audio_prepare_for_input, + prepare_for_output: pas_audio_prepare_for_output, + halt_io: pas_audio_reset, + trigger: pas_audio_trigger }; void pas_pcm_init(struct address_info *hw_config) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.4.0-test6/linux/drivers/sound/pss.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/pss.c Fri Aug 11 08:26:43 2000 @@ -35,7 +35,6 @@ #include "sound_config.h" #include "sound_firmware.h" -#include "soundmodule.h" #include "ad1848.h" #include "mpu401.h" @@ -569,9 +568,10 @@ static struct mixer_operations pss_mixer_operations = { - "SOUNDPORT", - "PSS-AD1848", - pss_mixer_ioctl + owner: THIS_MODULE, + id: "SOUNDPORT", + name: "PSS-AD1848", + ioctl: pss_mixer_ioctl }; void attach_pss(struct address_info *hw_config) @@ -918,7 +918,7 @@ static void __init attach_pss_mpu(struct address_info *hw_config) { - attach_mpu401(hw_config); /* Slot 1 */ + attach_mpu401(hw_config, THIS_MODULE); /* Slot 1 */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; } @@ -987,7 +987,7 @@ } } pss_mixer_reset(devc); - attach_ms_sound(hw_config); /* Slot 0 */ + attach_ms_sound(hw_config, THIS_MODULE); /* Slot 0 */ if (hw_config->slots[0] != -1) { @@ -1087,7 +1087,7 @@ pssmss = 1; attach_pss_mss(&cfg2); } - SOUND_LOCK; + return 0; } @@ -1100,7 +1100,6 @@ if (pssmpu) unload_pss_mpu(&cfg_mpu); unload_pss(&cfg); - SOUND_LOCK_END; } module_init(init_pss); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.4.0-test6/linux/drivers/sound/sb.h Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/sb.h Fri Aug 11 08:26:43 2000 @@ -158,14 +158,14 @@ void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo); -int sb_dsp_init (struct address_info *hw_config); +int sb_dsp_init (struct address_info *hw_config, struct module *owner); void sb_dsp_unload(struct address_info *hw_config, int sbmpu); -int sb_mixer_init(sb_devc *devc); +int sb_mixer_init(sb_devc *devc, struct module *owner); void sb_mixer_unload(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); void smw_mixer_init(sb_devc *devc); -void sb_dsp_midi_init (sb_devc *devc); -void sb_audio_init (sb_devc *devc, char *name); +void sb_dsp_midi_init (sb_devc *devc, struct module *owner); +void sb_audio_init (sb_devc *devc, char *name, struct module *owner); void sb_midi_interrupt (sb_devc *devc); void sb_chgmixer (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val); int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right); @@ -178,7 +178,7 @@ /* From sb_common.c */ void sb_dsp_disable_midi(int port); void sb_dsp_disable_recording(int port); -void attach_sbmpu (struct address_info *hw_config); +void attach_sbmpu (struct address_info *hw_config, struct module *owner); int probe_sbmpu (struct address_info *hw_config); void unload_sbmpu (struct address_info *hw_config); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.4.0-test6/linux/drivers/sound/sb_audio.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sb_audio.c Fri Aug 11 08:26:43 2000 @@ -933,128 +933,103 @@ static struct audio_driver sb1_audio_driver = /* SB1.x */ { - sb_audio_open, - sb_audio_close, - sb_set_output_parms, - sb_set_input_parms, - NULL, /* 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 + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb1_audio_prepare_for_input, + prepare_for_output: sb1_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb1_audio_trigger, + set_speed: sb1_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: 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, - NULL, - 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 + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb1_audio_prepare_for_input, + prepare_for_output: sb1_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: sb1_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: 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, - NULL, - 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 + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb1_audio_prepare_for_input, + prepare_for_output: sb1_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: sb201_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: 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, - NULL, - 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 + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sbpro_audio_prepare_for_input, + prepare_for_output: sbpro_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: sbpro_audio_set_speed, + set_bits: sb1_audio_set_bits, + set_channels: 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, - NULL, - 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 + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sbpro_audio_prepare_for_input, + prepare_for_output: sbpro_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + trigger: sb20_audio_trigger, + set_speed: jazz16_audio_set_speed, + set_bits: sb16_audio_set_bits, + set_channels: 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, - NULL, - sb16_audio_prepare_for_input, - sb16_audio_prepare_for_output, - sb1_audio_halt_xfer, - NULL, /* local_qlen */ - sb16_copy_from_user, /* copy_from_user */ - NULL, - NULL, - sb16_audio_trigger, - sb16_audio_set_speed, - sb16_audio_set_bits, - sbpro_audio_set_channels, - NULL, - NULL, - sb16_audio_mmap + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: sb_set_output_parms, + start_input: sb_set_input_parms, + prepare_for_input: sb16_audio_prepare_for_input, + prepare_for_output: sb16_audio_prepare_for_output, + halt_io: sb1_audio_halt_xfer, + copy_user: sb16_copy_from_user, + trigger: sb16_audio_trigger, + set_speed: sb16_audio_set_speed, + set_bits: sb16_audio_set_bits, + set_channels: sbpro_audio_set_channels, + mmap: sb16_audio_mmap }; -void sb_audio_init(sb_devc * devc, char *name) +void sb_audio_init(sb_devc * devc, char *name, struct module *owner) { int audio_flags = 0; int format_mask = AFMT_U8; @@ -1111,6 +1086,9 @@ driver = &sbpro_audio_driver; } + if (owner) + driver->owner = owner; + if ((devc->dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,driver, sizeof(struct audio_driver), audio_flags, format_mask, devc, diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.4.0-test6/linux/drivers/sound/sb_card.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/sb_card.c Mon Aug 21 09:44:05 2000 @@ -44,7 +44,9 @@ * * 25-05-2000 Added Creative SB AWE64 Gold (CTL00B2). * Pål-Kristian Engstad - * + * + * 12-08-2000 Added Creative SB32 PnP (CTL009F). + * Kasatenko Ivan Alex. */ #include @@ -54,7 +56,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "sb_mixer.h" #include "sb.h" @@ -88,7 +89,7 @@ static void __init attach_sb_card(struct address_info *hw_config) { - if(!sb_dsp_init(hw_config)) + if(!sb_dsp_init(hw_config, THIS_MODULE)) hw_config->slots[0] = -1; } @@ -189,7 +190,7 @@ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE static int isapnp = 1; static int isapnpjump = 0; -static int multiple = 0; +static int multiple = 1; static int reverse = 0; static int uart401 = 0; @@ -198,7 +199,7 @@ static int opl_activated[SB_CARDS_MAX] = {0}; #else static int isapnp = 0; -static int multiple = 1; +static int multiple = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); @@ -277,7 +278,7 @@ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, 0,1,1,-1}, - {"Sound Blaster 16", + {"Sound Blaster 16", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002a), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, @@ -342,6 +343,11 @@ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0,0,0,0, 0,1,1,-1}, + {"Creative SB32 PnP", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009F), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), + 0,0,0,0, + 0,1,1,-1}, {"Sound Blaster AWE 64", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), @@ -436,7 +442,7 @@ ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0,-1,0,0}, {"ALS100", - ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), + ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001), ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), @@ -468,10 +474,6 @@ {0} }; -/* That's useful. */ - -#define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start) - static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev) { int err; @@ -636,7 +638,7 @@ return 0; } } - i += reverse ? -1 : 1; + i += reverse ? -1 : 1; } return -ENODEV; @@ -679,16 +681,14 @@ if(cfg[card].slots[0]==-1) return -ENODEV; - if (!isapnp) + if (!isapnp) cfg_mpu[card].io_base = mpu_io; if (probe_sbmpu(&cfg_mpu[card])) sbmpu[card] = 1; if (sbmpu[card]) - attach_sbmpu(&cfg_mpu[card]); + attach_sbmpu(&cfg_mpu[card], THIS_MODULE); } - SOUND_LOCK; - if(isapnp) printk(KERN_NOTICE "sb: %d Soundblaster PnP card(s) found.\n", sb_cards_num); @@ -718,7 +718,6 @@ opl_dev[i]->deactivate(opl_dev[i]); #endif } - SOUND_LOCK_END; } module_init(init_sb); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.4.0-test6/linux/drivers/sound/sb_common.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/sound/sb_common.c Fri Aug 11 08:26:43 2000 @@ -634,7 +634,7 @@ return 1; } -int sb_dsp_init(struct address_info *hw_config) +int sb_dsp_init(struct address_info *hw_config, struct module *owner) { sb_devc *devc; char name[100]; @@ -812,10 +812,10 @@ if (!(devc->caps & SB_NO_MIXER)) if (devc->major == 3 || devc->major == 4) - sb_mixer_init(devc); + sb_mixer_init(devc, owner); if (!(devc->caps & SB_NO_MIDI)) - sb_dsp_midi_init(devc); + sb_dsp_midi_init(devc, owner); if (hw_config->name == NULL) hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; @@ -861,7 +861,7 @@ if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) printk(KERN_WARNING "Sound Blaster: can't allocate 16 bit DMA channel %d.\n", devc->dma16); } - sb_audio_init(devc, name); + sb_audio_init(devc, name, owner); hw_config->slots[0]=devc->dev; } else @@ -1190,18 +1190,18 @@ return 1; } -void attach_sbmpu(struct address_info *hw_config) +void attach_sbmpu(struct address_info *hw_config, struct module *owner) { if (last_sb->model == MDL_ESS) { #if defined(CONFIG_SOUND_MPU401) - attach_mpu401(hw_config); + attach_mpu401(hw_config, owner); if (last_sb->irq == -hw_config->irq) { last_sb->midi_irq_cookie=(void *)hw_config->slots[1]; } #endif return; } - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c --- v2.4.0-test6/linux/drivers/sound/sb_ess.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/sb_ess.c Fri Aug 11 08:26:43 2000 @@ -707,22 +707,18 @@ static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ { - sb_audio_open, - sb_audio_close, - ess_set_output_parms, - ess_set_input_parms, - NULL, - ess_audio_prepare_for_input, - ess_audio_prepare_for_output, - ess_audio_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - ess_audio_trigger, - ess_audio_set_speed, - ess_audio_set_bits, - ess_audio_set_channels + owner: THIS_MODULE, + open: sb_audio_open, + close: sb_audio_close, + output_block: ess_set_output_parms, + start_input: ess_set_input_parms, + prepare_for_input: ess_audio_prepare_for_input, + prepare_for_output: ess_audio_prepare_for_output, + halt_io: ess_audio_halt_xfer, + trigger: ess_audio_trigger, + set_speed: ess_audio_set_speed, + set_bits: ess_audio_set_bits, + set_channels: ess_audio_set_channels }; /* diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v2.4.0-test6/linux/drivers/sound/sb_midi.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sb_midi.c Fri Aug 11 08:26:43 2000 @@ -147,24 +147,19 @@ 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 + owner: THIS_MODULE, + info: {"Sound Blaster", 0, 0, SNDCARD_SB}, + converter: &std_midi_synth, + in_info: {0}, + open: sb_midi_open, + close: sb_midi_close, + ioctl: sb_midi_ioctl, + outputc: sb_midi_out, + start_read: sb_midi_start_read, + end_read: sb_midi_end_read, }; -void sb_dsp_midi_init(sb_devc * devc) +void sb_dsp_midi_init(sb_devc * devc, struct module *owner) { int dev; @@ -189,6 +184,9 @@ memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, sizeof(struct midi_operations)); + if (owner) + midi_devs[dev]->owner = owner; + midi_devs[dev]->devc = devc; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.4.0-test6/linux/drivers/sound/sb_mixer.c Tue Apr 11 15:09:19 2000 +++ linux/drivers/sound/sb_mixer.c Fri Aug 11 08:26:43 2000 @@ -626,16 +626,18 @@ static struct mixer_operations sb_mixer_operations = { - "SB", - "Sound Blaster", - sb_mixer_ioctl + owner: THIS_MODULE, + id: "SB", + name: "Sound Blaster", + ioctl: sb_mixer_ioctl }; static struct mixer_operations als007_mixer_operations = { - "ALS007", - "Avance ALS-007", - sb_mixer_ioctl + owner: THIS_MODULE, + id: "ALS007", + name: "Avance ALS-007", + ioctl: sb_mixer_ioctl }; static void sb_mixer_reset(sb_devc * devc) @@ -658,7 +660,7 @@ }; } -int sb_mixer_init(sb_devc * devc) +int sb_mixer_init(sb_devc * devc, struct module *owner) { int mixer_type = 0; int m; @@ -735,6 +737,10 @@ memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); mixer_devs[m]->devc = devc; + + if (owner) + mixer_devs[m]->owner = owner; + devc->my_mixerdev = m; sb_mixer_reset(devc); return 1; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.4.0-test6/linux/drivers/sound/sequencer.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/sound/sequencer.c Fri Aug 11 08:26:44 2000 @@ -1068,6 +1068,9 @@ if (synth_devs[i]==NULL) continue; + if (synth_devs[i]->owner) + __MOD_INC_USE_COUNT (synth_devs[i]->owner); + if ((tmp = synth_devs[i]->open(i, mode)) < 0) { printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); @@ -1101,6 +1104,9 @@ for (i = 0; i < max_mididev; i++) if (!midi_opened[i] && midi_devs[i]) { + if (midi_devs[i]->owner) + __MOD_INC_USE_COUNT (midi_devs[i]->owner); + if ((retval = midi_devs[i]->open(i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) { @@ -1108,8 +1114,12 @@ } } } - if (seq_mode == SEQ_2) + + if (seq_mode == SEQ_2) { + if (tmr->owner) + __MOD_INC_USE_COUNT (tmr->owner); tmr->open(tmr_no, seq_mode); + } init_waitqueue_head(&seq_sleeper); init_waitqueue_head(&midi_sleeper); @@ -1191,6 +1201,9 @@ { synth_devs[i]->close(i); + if (synth_devs[i]->owner) + __MOD_DEC_USE_COUNT (synth_devs[i]->owner); + if (synth_devs[i]->midi_dev) midi_opened[synth_devs[i]->midi_dev] = 0; } @@ -1198,12 +1211,18 @@ for (i = 0; i < max_mididev; i++) { - if (midi_opened[i]) + if (midi_opened[i]) { midi_devs[i]->close(i); + if (midi_devs[i]->owner) + __MOD_DEC_USE_COUNT (midi_devs[i]->owner); + } } - if (seq_mode == SEQ_2) + if (seq_mode == SEQ_2) { tmr->close(tmr_no); + if (tmr->owner) + __MOD_DEC_USE_COUNT (tmr->owner); + } if (obsolete_api_used) printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c --- v2.4.0-test6/linux/drivers/sound/sgalaxy.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/sgalaxy.c Fri Aug 11 08:26:44 2000 @@ -22,8 +22,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" - #include "ad1848.h" static void sleep( unsigned howlong ) @@ -115,7 +113,7 @@ request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB" ); - attach_ms_sound( ai ); + attach_ms_sound(ai, THIS_MODULE); n=ai->slots[0]; if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) { @@ -163,14 +161,12 @@ attach_sgalaxy(&cfg); - SOUND_LOCK; return 0; } static void __exit cleanup_sgalaxy(void) { unload_sgalaxy(&cfg); - SOUND_LOCK_END; } module_init(init_sgalaxy); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/skeleton.c linux/drivers/sound/skeleton.c --- v2.4.0-test6/linux/drivers/sound/skeleton.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/skeleton.c Fri Aug 11 08:26:44 2000 @@ -27,7 +27,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" /* * Define our PCI vendor ID here @@ -137,7 +136,13 @@ */ mss_data[cards].slots[3] = ad1848_init("MyCard MSS 16bit", - mssbase, mss_data[cards].irq); + mssbase, + mss_data[cards].irq, + mss_data[cards].dma, + mss_data[cards].dma, + 0, + 0, + THIS_MODULE); cards++; return 1; @@ -187,17 +192,13 @@ printk(KERN_ERR "No "CARD_NAME" cards found.\n"); return -ENODEV; } - /* - * Binds us to the sound subsystem - */ - SOUND_LOCK; + return 0; } /* * This is called when it is removed. It will only be removed - * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK - * macros hide the entire work for this. + * when its use count is 0. */ void cleanup_module(void) @@ -218,9 +219,5 @@ */ sound_unload_audiodevice(mss_data[i].slots[3]); } - /* - * Final clean up with the sound layer - */ - SOUND_LOCK_END; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.4.0-test6/linux/drivers/sound/softoss.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/softoss.c Fri Aug 11 08:26:44 2000 @@ -32,7 +32,6 @@ #define NO_SAMPLE 0xffff #include "sound_config.h" -#include "soundmodule.h" #include "softoss.h" #include @@ -1394,27 +1393,28 @@ 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 + owner: THIS_MODULE, + id: "SoftOSS", + info: &softsyn_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: 0, + open: softsyn_open, + close: softsyn_close, + ioctl: softsyn_ioctl, + kill_note: softsyn_kill_note, + start_note: softsyn_start_note, + set_instr: softsyn_set_instr, + reset: softsyn_reset, + hw_control: softsyn_hw_control, + load_patch: softsyn_load_patch, + aftertouch: softsyn_aftertouch, + controller: softsyn_controller, + panning: softsyn_panning, + volume_method: softsyn_volume_method, + bender: softsyn_bender, + alloc_voice: softsyn_alloc_voice, + setup_voice: softsyn_setup_voice }; /* @@ -1517,7 +1517,7 @@ if (!probe_softsyn(&cfg)) return -ENODEV; attach_softsyn_card(&cfg); - SOUND_LOCK; + return 0; } @@ -1526,7 +1526,6 @@ unload_softsyn(&cfg); sound_unload_synthdev(devc->synthdev); sound_unload_timerdev(devc->timerdev); - SOUND_LOCK_END; } module_init(init_softoss); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.4.0-test6/linux/drivers/sound/sonicvibes.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/sonicvibes.c Sat Aug 12 19:51:52 2000 @@ -282,8 +282,6 @@ #define FMODE_DMFM 0x10 -#define SND_DEV_DSP16 5 - /* --------------------------------------------------------------------- */ struct sv_state { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v2.4.0-test6/linux/drivers/sound/sound_config.h Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/sound_config.h Sat Aug 12 19:53:27 2000 @@ -53,28 +53,7 @@ #define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */ /* 128 instruments for general MIDI setup and 16 unassigned */ -/* - * Minor numbers for the sound driver. - * - * Unfortunately Creative called the codec chip of SB as a DSP. For this - * reason the /dev/dsp is reserved for digitized audio use. There is a - * device for true DSP processors but it will be called something else. - * In v3.0 it's /dev/sndproc but this could be a temporary solution. - */ - #define SND_NDEVS 256 /* Number of supported devices */ -#define SND_DEV_CTL 0 /* Control port /dev/mixer */ -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - synthesizer and MIDI output) */ -#define SND_DEV_MIDIN 2 /* Raw midi access */ -#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ -#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ -#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ -#define SND_DEV_STATUS 6 /* /dev/sndstat */ -#define SND_DEV_AWFM 7 /* Reserved */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ -#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ -#define SND_DEV_PSS SND_DEV_SNDPROC #define DSP_DEFAULT_SPEED 8000 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.4.0-test6/linux/drivers/sound/sound_syms.c Mon Jul 10 16:47:24 2000 +++ linux/drivers/sound/sound_syms.c Fri Aug 11 08:26:44 2000 @@ -52,11 +52,5 @@ extern int softoss_dev; EXPORT_SYMBOL(softoss_dev); -/* Locking */ -extern struct notifier_block *sound_locker; -extern void sound_notifier_chain_register(struct notifier_block *); -EXPORT_SYMBOL(sound_locker); -EXPORT_SYMBOL(sound_notifier_chain_register); - MODULE_DESCRIPTION("OSS Sound subsystem"); MODULE_AUTHOR("Hannu Savolainen, et al."); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.4.0-test6/linux/drivers/sound/sound_timer.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sound_timer.c Fri Aug 11 08:26:44 2000 @@ -264,15 +264,16 @@ 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 + owner: THIS_MODULE, + info: {"Sound Timer", 0}, + priority: 1, /* Priority */ + devlink: 0, /* Local device link */ + open: timer_open, + close: timer_close, + event: timer_event, + get_time: timer_get_time, + ioctl: timer_ioctl, + arm_timer: timer_arm }; void sound_timer_interrupt(void) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.4.0-test6/linux/drivers/sound/soundcard.c Fri Jul 14 12:12:13 2000 +++ linux/drivers/sound/soundcard.c Fri Aug 11 08:26:44 2000 @@ -43,11 +43,6 @@ #include #include #include -#include - - -struct notifier_block *sound_locker=(struct notifier_block *)0; -static int lock_depth = 0; /* * This ought to be moved into include/asm/dma.h @@ -78,7 +73,6 @@ #define DMA_MAP_BUSY 2 -static int in_use = 0; /* Total # of open devices */ unsigned long seq_time = 0; /* Time for /dev/sequencer */ /* @@ -221,7 +215,7 @@ DEB(printk("sound_open(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) { - /* printk(KERN_ERR "Invalid minor device %d\n", dev);*/ + printk(KERN_ERR "Invalid minor device %d\n", dev); return -ENXIO; } switch (dev & 0x0f) { @@ -234,6 +228,9 @@ } if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) return -ENXIO; + + if (mixer_devs[dev]->owner) + __MOD_INC_USE_COUNT (mixer_devs[dev]->owner); break; case SND_DEV_SEQ: @@ -258,10 +255,6 @@ printk(KERN_ERR "Invalid minor device %d\n", dev); return -ENXIO; } - in_use++; - - notifier_call_chain(&sound_locker, 1, 0); - lock_depth++; return 0; } @@ -274,6 +267,8 @@ DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_CTL: + if (mixer_devs[dev]->owner) + __MOD_DEC_USE_COUNT (mixer_devs[dev]->owner); break; case SND_DEV_SEQ: @@ -294,10 +289,6 @@ default: printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); } - in_use--; - - notifier_call_chain(&sound_locker, 0, 0); - lock_depth--; unlock_kernel(); return 0; @@ -810,28 +801,4 @@ } printk("\n"); #endif -} - -/* - * Module and lock management - */ - -/* - * When a sound module is registered we need to bring it to the current - * lock level... - */ - -void sound_notifier_chain_register(struct notifier_block *bl) -{ - int ct=0; - - notifier_chain_register(&sound_locker, bl); - /* - * Normalise the lock count by calling the entry directly. We - * have to call the module as it owns its own use counter - */ - while(ctnotifier_call(bl, 1, 0); - ct++; - } } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h --- v2.4.0-test6/linux/drivers/sound/soundmodule.h Thu May 11 15:30:08 2000 +++ linux/drivers/sound/soundmodule.h Wed Dec 31 16:00:00 1969 @@ -1,29 +0,0 @@ -#ifndef _SOUNDMODULE_H -#define _SOUNDMODULE_H - -#include -#include - -extern struct notifier_block *sound_locker; -extern void sound_notifier_chain_register(struct notifier_block *); - -#define SOUND_LOCK sound_notifier_chain_register(&sound_notifier); -#define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier) - -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 /* _SOUNDMODULE_H */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.4.0-test6/linux/drivers/sound/sscape.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/sscape.c Fri Aug 11 08:26:44 2000 @@ -20,7 +20,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "sound_firmware.h" #include @@ -728,7 +727,7 @@ hw_config->name = "SoundScape"; hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401(hw_config); + attach_mpu401(hw_config, THIS_MODULE); hw_config->irq *= -1; /* Restore it */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ @@ -1378,21 +1377,16 @@ if (hw_config->irq == devc->irq) printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); - if (! sscape_is_pnp ) - hw_config->slots[0] = ad1848_init("SoundScape", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); - - else - hw_config->slots[0] = ad1848_init("SoundScape PNP", hw_config->io_base, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp); + hw_config->slots[0] = ad1848_init( + sscape_is_pnp ? "SoundScape" : "SoundScape PNP", + hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma, + 0, + devc->osp, + THIS_MODULE); + if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ { @@ -1497,7 +1491,7 @@ if (mss) attach_ss_ms_sound(&cfg); - SOUND_LOCK; + return 0; } @@ -1505,7 +1499,6 @@ { if (mss) unload_ss_ms_sound(&cfg); - SOUND_LOCK_END; unload_sscape(&cfg_mpu); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c --- v2.4.0-test6/linux/drivers/sound/sys_timer.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/sys_timer.c Fri Aug 11 08:26:44 2000 @@ -274,13 +274,14 @@ 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 + owner: THIS_MODULE, + info: {"System clock", 0}, + priority: 0, /* Priority */ + devlink: 0, /* Local device link */ + open: def_tmr_open, + close: def_tmr_close, + event: def_tmr_event, + get_time: def_tmr_get_time, + ioctl: def_tmr_ioctl, + arm_timer: def_tmr_arm }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.0-test6/linux/drivers/sound/trident.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/sound/trident.c Sat Aug 12 19:51:52 2000 @@ -130,12 +130,6 @@ have 2 SDATA_IN lines (currently) */ #define NR_AC97 2 -/* minor number of /dev/dspW */ -#define SND_DEV_DSP8 3 - -/* minor number of /dev/dspW */ -#define SND_DEV_DSP16 5 - /* minor number of /dev/swmodem (temporary, experimental) */ #define SND_DEV_SWMODEM 7 diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.4.0-test6/linux/drivers/sound/trix.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/trix.c Fri Aug 11 08:26:44 2000 @@ -21,7 +21,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "sb.h" #include "sound_firmware.h" @@ -259,7 +258,8 @@ dma1, dma2, 0, - hw_config->osp); + hw_config->osp, + THIS_MODULE); request_region(hw_config->io_base, 4, "MSS config"); if (num_mixers > old_num_mixers) /* Mixer got installed */ @@ -332,7 +332,7 @@ old_quiet = sb_be_quiet; sb_be_quiet = 1; - sb_dsp_init(hw_config); + sb_dsp_init(hw_config, THIS_MODULE); sb_be_quiet = old_quiet; } @@ -340,7 +340,7 @@ static void __init attach_trix_mpu(struct address_info *hw_config) { hw_config->name = "AudioTrix Pro"; - attach_uart401(hw_config); + attach_uart401(hw_config, THIS_MODULE); } static int __init probe_trix_mpu(struct address_info *hw_config) @@ -515,7 +515,7 @@ if (mpu) attach_trix_mpu(&cfg_mpu); } - SOUND_LOCK; + return 0; } @@ -528,7 +528,6 @@ if (mpu) unload_trix_mpu(&cfg_mpu); unload_trix_wss(&cfg); - SOUND_LOCK_END; } module_init(init_trix); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.4.0-test6/linux/drivers/sound/uart401.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/uart401.c Fri Aug 11 08:26:44 2000 @@ -24,7 +24,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "mpu401.h" @@ -206,21 +205,17 @@ static struct midi_operations uart401_operations = { - { - "MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401 - }, - &std_midi_synth, - {0}, - uart401_open, - uart401_close, - NULL, /* ioctl */ - uart401_out, - uart401_start_read, - uart401_end_read, - uart401_kick, - NULL, - uart401_buffer_status, - NULL + owner: THIS_MODULE, + info: {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + converter: &std_midi_synth, + in_info: {0}, + open: uart401_open, + close: uart401_close, + outputc: uart401_out, + start_read: uart401_start_read, + end_read: uart401_end_read, + kick: uart401_kick, + buffer_status: uart401_buffer_status, }; static void enter_uart_mode(uart401_devc * devc) @@ -246,7 +241,7 @@ restore_flags(flags); } -void attach_uart401(struct address_info *hw_config) +void attach_uart401(struct address_info *hw_config, struct module *owner) { uart401_devc *devc; char *name = "MPU-401 (UART) MIDI"; @@ -311,6 +306,9 @@ memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations, sizeof(struct midi_operations)); + if (owner) + midi_devs[devc->my_dev]->owner = owner; + midi_devs[devc->my_dev]->devc = devc; midi_devs[devc->my_dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL); if (midi_devs[devc->my_dev]->converter == NULL) @@ -473,9 +471,9 @@ printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); if (probe_uart401(&cfg_mpu) == 0) return -ENODEV; - attach_uart401(&cfg_mpu); + attach_uart401(&cfg_mpu, THIS_MODULE); } - SOUND_LOCK; + return 0; } @@ -483,7 +481,6 @@ { if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) unload_uart401(&cfg_mpu); - SOUND_LOCK_END; } module_init(init_uart401); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.4.0-test6/linux/drivers/sound/uart6850.c Thu May 11 15:30:08 2000 +++ linux/drivers/sound/uart6850.c Fri Aug 11 08:26:44 2000 @@ -26,7 +26,6 @@ */ #include "sound_config.h" -#include "soundmodule.h" static int uart6850_base = 0x330; @@ -148,7 +147,6 @@ return -EBUSY; }; - MOD_INC_USE_COUNT; uart6850_cmd(UART_RESET); uart6850_input_loop(); midi_input_intr = input; @@ -165,7 +163,6 @@ uart6850_cmd(UART_MODE_ON); del_timer(&uart6850_timer); uart6850_opened = 0; - MOD_DEC_USE_COUNT; } static int uart6850_out(int dev, unsigned char midi_byte) @@ -234,18 +231,18 @@ static struct midi_operations uart6850_operations = { - {"6850 UART", 0, 0, SNDCARD_UART6850}, - &std_midi_synth, - {0}, - uart6850_open, - uart6850_close, - NULL, /* ioctl */ - uart6850_out, - uart6850_start_read, - uart6850_end_read, - uart6850_kick, - uart6850_command, - uart6850_buffer_status + owner: THIS_MODULE, + info: {"6850 UART", 0, 0, SNDCARD_UART6850}, + converter: &std_midi_synth, + in_info: {0}, + open: uart6850_open, + close: uart6850_close, + outputc: uart6850_out, + start_read: uart6850_start_read, + end_read: uart6850_end_read, + kick: uart6850_kick, + command: uart6850_command, + buffer_status: uart6850_buffer_status }; @@ -338,14 +335,12 @@ if (probe_uart6850(&cfg_mpu)) return -ENODEV; - SOUND_LOCK; return 0; } static void __exit cleanup_uart6850(void) { unload_uart6850(&cfg_mpu); - SOUND_LOCK_END; } module_init(init_uart6850); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/v_midi.c linux/drivers/sound/v_midi.c --- v2.4.0-test6/linux/drivers/sound/v_midi.c Tue Mar 7 14:32:26 2000 +++ linux/drivers/sound/v_midi.c Fri Aug 11 08:26:44 2000 @@ -23,7 +23,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "v_midi.h" @@ -136,36 +135,30 @@ static struct midi_operations v_midi_operations = { - {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI}, - &std_midi_synth, - {0}, - v_midi_open, - v_midi_close, - v_midi_ioctl, - v_midi_out, - v_midi_start_read, - v_midi_end_read, - NULL, - NULL, - NULL, - NULL + owner: THIS_MODULE, + info: {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI}, + converter: &std_midi_synth, + in_info: {0}, + open: v_midi_open, + close: v_midi_close, + ioctl: v_midi_ioctl, + outputc: v_midi_out, + start_read: v_midi_start_read, + end_read: v_midi_end_read, }; static struct midi_operations v_midi_operations2 = { - {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI}, - &std_midi_synth, - {0}, - v_midi_open, - v_midi_close, - v_midi_ioctl, - v_midi_out, - v_midi_start_read, - v_midi_end_read, - NULL, - NULL, - NULL, - NULL + owner: THIS_MODULE, + info: {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI}, + converter: &std_midi_synth, + in_info: {0}, + open: v_midi_open, + close: v_midi_close, + ioctl: v_midi_ioctl, + outputc: v_midi_out, + start_read: v_midi_start_read, + end_read: v_midi_end_read, }; /* @@ -284,15 +277,12 @@ return -ENODEV; attach_v_midi(&cfg); - SOUND_LOCK; - return 0; } static void __exit cleanup_vmidi(void) { unload_v_midi(&cfg); - SOUND_LOCK_END; } module_init(init_vmidi); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.0-test6/linux/drivers/sound/via82cxxx_audio.c Fri Jul 14 12:12:13 2000 +++ linux/drivers/sound/via82cxxx_audio.c Sat Aug 12 19:51:52 2000 @@ -36,10 +36,6 @@ #include #include -/* much better to duplicate this value than include - * drivers/sound/sound_config.h just for this definition */ -#define SND_DEV_DSP16 5 - #undef VIA_DEBUG /* define to enable debugging output and checks */ #ifdef VIA_DEBUG diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c --- v2.4.0-test6/linux/drivers/sound/vidc.c Mon Jul 10 16:47:25 2000 +++ linux/drivers/sound/vidc.c Fri Aug 11 08:26:44 2000 @@ -26,7 +26,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "vidc.h" #ifndef _SIOC_TYPE @@ -362,6 +361,7 @@ static struct audio_driver vidc_audio_driver = { + owner: THIS_MODULE, open: vidc_audio_open, close: vidc_audio_close, output_block: vidc_audio_output_block, @@ -377,6 +377,7 @@ }; static struct mixer_operations vidc_mixer_operations = { + owner: THIS_MODULE, id: "VIDC", name: "VIDCsound", ioctl: vidc_mixer_ioctl @@ -519,16 +520,12 @@ } static struct address_info cfg; -/* - * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END - */ static int __init init_vidc(void) { if (probe_vidc(&cfg) == 0) return -ENODEV; - SOUND_LOCK; attach_vidc(&cfg); return 0; @@ -537,7 +534,6 @@ static void __exit cleanup_vidc(void) { unload_vidc(&cfg); - SOUND_LOCK_END; } module_init(init_vidc); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.4.0-test6/linux/drivers/sound/waveartist.c Tue Mar 14 19:10:40 2000 +++ linux/drivers/sound/waveartist.c Sun Aug 13 09:54:15 2000 @@ -40,9 +40,9 @@ #include #include +#include #include -#include "soundmodule.h" #include "sound_config.h" #include "waveartist.h" @@ -801,22 +801,21 @@ } static struct audio_driver waveartist_audio_driver = { - waveartist_open, - waveartist_close, - waveartist_output_block, - waveartist_start_input, - waveartist_ioctl, - waveartist_prepare_for_input, - waveartist_prepare_for_output, - waveartist_halt, - NULL, - NULL, - waveartist_halt_input, - waveartist_halt_output, - waveartist_trigger, - waveartist_set_speed, - waveartist_set_bits, - waveartist_set_channels + owner: THIS_MODULE, + open: waveartist_open, + close: waveartist_close, + output_block: waveartist_output_block, + start_input: waveartist_start_input, + ioctl: waveartist_ioctl, + prepare_for_input: waveartist_prepare_for_input, + prepare_for_output: waveartist_prepare_for_output, + halt_io: waveartist_halt, + halt_input: waveartist_halt_input, + halt_output: waveartist_halt_output, + trigger: waveartist_trigger, + set_speed: waveartist_set_speed, + set_bits: waveartist_set_bits, + set_channels: waveartist_set_channels }; @@ -1186,9 +1185,10 @@ static struct mixer_operations waveartist_mixer_operations = { - "WaveArtist", - "WaveArtist NetWinder", - waveartist_mixer_ioctl + owner: THIS_MODULE, + id: "WaveArtist", + name: "WaveArtist NetWinder", + ioctl: waveartist_mixer_ioctl }; static int @@ -1794,16 +1794,13 @@ attach_waveartist(&cfg); attached = 1; - SOUND_LOCK; return 0; } static void __exit cleanup_waveartist(void) { - if (attached) { - SOUND_LOCK_END; + if (attached) unload_waveartist(&cfg); - } } module_init(init_waveartist); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.4.0-test6/linux/drivers/sound/wavfront.c Fri Jul 14 12:12:13 2000 +++ linux/drivers/sound/wavfront.c Fri Aug 11 08:26:44 2000 @@ -78,7 +78,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include @@ -2115,28 +2114,25 @@ static struct synth_operations wavefront_operations = { - "WaveFront", - &wavefront_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_WAVEFRONT, - wavefront_oss_open, - wavefront_oss_close, - wavefront_oss_ioctl, - - midi_synth_kill_note, - midi_synth_start_note, - midi_synth_set_instr, - midi_synth_reset, - NULL, /* hw_control */ - midi_synth_load_patch, - midi_synth_aftertouch, - midi_synth_controller, - midi_synth_panning, - NULL, /* volume method */ - midi_synth_bender, - NULL, /* alloc voice */ - midi_synth_setup_voice + owner: THIS_MODULE, + id: "WaveFront", + info: &wavefront_info, + midi_dev: 0, + synth_type: SYNTH_TYPE_SAMPLE, + synth_subtype: SAMPLE_TYPE_WAVEFRONT, + open: wavefront_oss_open, + close: wavefront_oss_close, + ioctl: wavefront_oss_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice }; #endif OSS_SUPPORT_SEQ @@ -3569,14 +3565,12 @@ return -EIO; } - SOUND_LOCK; return 0; } static void __exit cleanup_wavfront (void) { uninstall_wavefront (); - SOUND_LOCK_END; } module_init(init_wavfront); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c --- v2.4.0-test6/linux/drivers/sound/wf_midi.c Fri Mar 10 16:40:44 2000 +++ linux/drivers/sound/wf_midi.c Fri Aug 11 08:26:44 2000 @@ -51,7 +51,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include @@ -550,19 +549,16 @@ static struct midi_operations wf_mpu_midi_proto = { - {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, - NULL, /*converter*/ - {0}, /* in_info */ - wf_mpu_open, - wf_mpu_close, - wf_mpu_ioctl, - wf_mpu_out, - wf_mpu_start_read, - wf_mpu_end_read, - NULL, - NULL, - wf_mpu_buffer_status, - NULL + owner: THIS_MODULE, + info: {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + in_info: {0}, /* in_info */ + open: wf_mpu_open, + close: wf_mpu_close, + ioctl: wf_mpu_ioctl, + outputc: wf_mpu_out, + start_read: wf_mpu_start_read, + end_read: wf_mpu_end_read, + buffer_status: wf_mpu_buffer_status, }; static struct synth_info wf_mpu_synth_info_proto = @@ -671,28 +667,27 @@ static struct synth_operations wf_mpu_synth_proto = { - "WaveFront (ICS2115)", - NULL, /* info field, filled in during configuration */ - 0, /* MIDI dev XXX should this be -1 ? */ - SYNTH_TYPE_MIDI, - SAMPLE_TYPE_WAVEFRONT, - wf_mpu_synth_open, - wf_mpu_synth_close, - wf_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 + owner: THIS_MODULE, + id: "WaveFront (ICS2115)", + info: NULL, /* info field, filled in during configuration */ + midi_dev: 0, /* MIDI dev XXX should this be -1 ? */ + synth_type: SYNTH_TYPE_MIDI, + synth_subtype: SAMPLE_TYPE_WAVEFRONT, + open: wf_mpu_synth_open, + close: wf_mpu_synth_close, + ioctl: wf_mpu_synth_ioctl, + kill_note: midi_synth_kill_note, + start_note: midi_synth_start_note, + set_instr: midi_synth_set_instr, + reset: midi_synth_reset, + hw_control: midi_synth_hw_control, + load_patch: midi_synth_load_patch, + aftertouch: midi_synth_aftertouch, + controller: midi_synth_controller, + panning: midi_synth_panning, + bender: midi_synth_bender, + setup_voice: midi_synth_setup_voice, + send_sysex: midi_synth_send_sysex }; static int diff -u --recursive --new-file v2.4.0-test6/linux/drivers/sound/ymf_sb.c linux/drivers/sound/ymf_sb.c --- v2.4.0-test6/linux/drivers/sound/ymf_sb.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/sound/ymf_sb.c Fri Aug 11 08:26:44 2000 @@ -54,7 +54,6 @@ #include #include "sound_config.h" -#include "soundmodule.h" #include "sb.h" #include "724hwmcode.h" @@ -64,11 +63,6 @@ /* ---------------------------------------------------------------------- */ -#ifndef SOUND_LOCK -#define SOUND_LOCK do {} while (0) -#define SOUND_LOCK_END do {} while (0) -#endif - #ifndef PCI_VENDOR_ID_YAMAHA #define PCI_VENDOR_ID_YAMAHA 0x1073 #endif @@ -641,7 +635,7 @@ static void __init ymf7xxsb_attach_sb(struct address_info *hw_config) { - if(!sb_dsp_init(hw_config)) + if(!sb_dsp_init(hw_config, THIS_MODULE)) hw_config->slots[0] = -1; } @@ -784,7 +778,7 @@ ymf7xxsb_unload_sb (&sb_data[cards], 0); return -ENODEV; } - ymf7xxsb_attach_midi (&mpu_data[cards]); + ymf7xxsb_attach_midi (&mpu_data[cards], THIS_MODULE); } #endif @@ -804,11 +798,6 @@ { int i; - /* - * Binds us to the sound subsystem - */ - SOUND_LOCK; - if ( master_vol < 0 ) master_vol = 50; if ( master_vol > 100 ) master_vol = 100; @@ -816,10 +805,8 @@ ymfbase[i] = NULL; i = pci_module_init (&ymf7xxsb_driver); - if (i < 0) { - SOUND_LOCK_END; + if (i < 0) return i; - } printk (KERN_INFO PFX YMFSB_CARD_NAME " loaded\n"); @@ -853,10 +840,6 @@ free_iomaps(); - /* - * Final clean up with the sound layer - */ - SOUND_LOCK_END; } MODULE_AUTHOR("Daisuke Nagano, breeze.nagano@nifty.ne.jp"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.4.0-test6/linux/drivers/usb/Config.in Thu Jul 27 17:38:01 2000 +++ linux/drivers/usb/Config.in Tue Aug 22 15:20:52 2000 @@ -68,31 +68,23 @@ dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET - dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET + dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB fi -comment 'USB HID' - dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB - if [ "$CONFIG_USB_HID" != "y" ]; then - dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB - dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB - fi - dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB - dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_USB - if [ "$CONFIG_INPUT_IFORCE_USB" != "n" ]; then - define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_USB + comment 'USB Human Interface Devices (HID)' + if [ "$CONFIG_INPUT" = "n" ]; then + comment ' Input core support is needed for USB HID' + else + dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT + if [ "$CONFIG_USB_HID" != "y" ]; then + dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT + dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT fi - dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB - dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB - if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then - int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 - int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 + dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT fi - dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB - dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB fi endmenu diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.4.0-test6/linux/drivers/usb/Makefile Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/Makefile Tue Aug 22 11:41:14 2000 @@ -17,7 +17,7 @@ # Objects that export symbols. -export-objs := usb.o input.o +export-objs := usb.o # Multipart objects. @@ -37,27 +37,6 @@ obj-n := obj- := -# Object files in subdirectories - -ifeq ($(CONFIG_USB_SERIAL),y) - SUB_DIRS += serial - obj-y += serial/usb-serial.o -else - ifeq ($(CONFIG_USB_SERIAL),m) - MOD_IN_SUB_DIRS += serial - endif -endif - -ifeq ($(CONFIG_USB_STORAGE),y) - SUB_DIRS += storage - obj-y += storage/usb-storage.o -else - ifeq ($(CONFIG_USB_STORAGE),m) - MOD_IN_SUB_DIRS += storage - endif -endif - - # Each configuration option enables a list of files. obj-$(CONFIG_USB) += usbcore.o @@ -65,15 +44,10 @@ obj-$(CONFIG_USB_UHCI_ALT) += uhci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o -obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o -obj-$(CONFIG_USB_HID) += hid.o input.o -obj-$(CONFIG_USB_KBD) += usbkbd.o input.o -obj-$(CONFIG_USB_WACOM) += wacom.o input.o -obj-$(CONFIG_INPUT_IFORCE) += iforce.o input.o -obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o input.o -obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o input.o -obj-$(CONFIG_INPUT_JOYDEV) += joydev.o input.o -obj-$(CONFIG_INPUT_EVDEV) += evdev.o input.o +obj-$(CONFIG_USB_MOUSE) += usbmouse.o +obj-$(CONFIG_USB_HID) += hid.o +obj-$(CONFIG_USB_KBD) += usbkbd.o +obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_SCANNER) += scanner.o obj-$(CONFIG_USB_ACM) += acm.o @@ -92,6 +66,26 @@ obj-$(CONFIG_USB_MICROTEK) += microtek.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o +# Object files in subdirectories + +ifeq ($(CONFIG_USB_SERIAL),y) + SUB_DIRS += serial + obj-y += serial/usb-serial.o +else + ifeq ($(CONFIG_USB_SERIAL),m) + MOD_IN_SUB_DIRS += serial + endif +endif + +ifeq ($(CONFIG_USB_STORAGE),y) + SUB_DIRS += storage + obj-y += storage/usb-storage.o +else + ifeq ($(CONFIG_USB_STORAGE),m) + MOD_IN_SUB_DIRS += storage + endif +endif + # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. @@ -111,8 +105,8 @@ # Translate to Rules.make lists. -O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) -OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c --- v2.4.0-test6/linux/drivers/usb/bluetooth.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/bluetooth.c Sun Aug 13 19:23:19 2000 @@ -1,5 +1,5 @@ /* - * bluetooth.c Version 0.3 + * bluetooth.c Version 0.4 * * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner @@ -7,6 +7,13 @@ * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * * + * (07/11/2000) Version 0.4 gkh + * Fixed bug in disconnect for when we call tty_hangup + * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not + * getting attached to the control urb properly. + * Fixed bug in bluetooth_write where we pay attention to the result + * of bluetooth_ctrl_msg. + * * (08/03/2000) Version 0.3 gkh mdc * Merged in Mark's changes to make the driver play nice with the Axis * stack. @@ -251,7 +258,7 @@ dr->length = cpu_to_le16p(&len); FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0), - (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, 0); + (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth); /* send it down the pipe */ status = usb_submit_urb(urb); @@ -400,7 +407,10 @@ else memcpy (new_buffer, buf+1, count-1); - bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1); + if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) { + kfree (new_buffer); + return 0; + } /* need to free new_buffer somehow... FIXME */ return count; @@ -1099,6 +1109,9 @@ int i; if (bluetooth) { + if ((bluetooth->active) && (bluetooth->tty)) + tty_hangup(bluetooth->tty); + bluetooth->active = 0; if (bluetooth->read_urb) { @@ -1116,9 +1129,6 @@ kfree (bluetooth->interrupt_in_buffer); tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor); - - if (bluetooth->tty) - tty_hangup(bluetooth->tty); for (i = 0; i < NUM_BULK_URBS; ++i) { if (bluetooth->write_urb_pool[i]) { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.4.0-test6/linux/drivers/usb/dc2xx.c Fri Jul 14 12:12:13 2000 +++ linux/drivers/usb/dc2xx.c Tue Aug 22 11:48:54 2000 @@ -43,6 +43,7 @@ * added timeouts to bulk_msg calls. Minor updates, docs. * 03 Nov, 1999 -- update for 2.3.25 kernel API changes. * 08 Jan, 2000 .. multiple camera support + * 12 Aug, 2000 .. add some real locking, remove an Oops * * Thanks to: the folk who've provided USB product IDs, sent in * patches, and shared their sucesses! @@ -60,7 +61,6 @@ #include #undef DEBUG #include -#include @@ -114,7 +114,7 @@ int outEP; /* write endpoint */ const struct camera *info; /* DC-240, etc */ int subminor; /* which minor dev #? */ - int isActive; /* I/O taking place? */ + struct semaphore sem; /* locks this struct */ /* this is non-null iff the device is open */ char *buf; /* buffer for I/O */ @@ -127,21 +127,25 @@ /* Support multiple cameras, possibly of different types. */ static struct camera_state *minor_data [MAX_CAMERAS]; +/* make this an rwlock if contention becomes an issue */ +static DECLARE_MUTEX (state_table_mutex); static ssize_t camera_read (struct file *file, char *buf, size_t len, loff_t *ppos) { struct camera_state *camera; int retries; + int retval = 0; if (len > MAX_PACKET_SIZE) return -EINVAL; camera = (struct camera_state *) file->private_data; - if (!camera->dev) + down (&camera->sem); + if (!camera->dev) { + up (&camera->sem); return -ENODEV; - if (camera->isActive++) - return -EBUSY; + } /* Big reads are common, for image downloading. Smaller ones * are also common (even "directory listing" commands don't @@ -150,37 +154,33 @@ */ for (retries = 0; retries < MAX_READ_RETRY; retries++) { int count; - int result; if (signal_pending (current)) { - camera->isActive = 0; - return -EINTR; - } - if (!camera->dev) { - camera->isActive = 0; - return -ENODEV; + retval = -EINTR; + break; } - result = usb_bulk_msg (camera->dev, + retval = usb_bulk_msg (camera->dev, usb_rcvbulkpipe (camera->dev, camera->inEP), camera->buf, len, &count, HZ*10); - dbg ("read (%d) - 0x%x %d", len, result, count); + dbg ("read (%d) - 0x%x %d", len, retval, count); - if (!result) { + if (!retval) { if (copy_to_user (buf, camera->buf, count)) - return -EFAULT; - camera->isActive = 0; - return count; + retval = -EFAULT; + else + retval = count; + break; } - if (result != USB_ST_TIMEOUT) + if (retval != USB_ST_TIMEOUT) break; interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT); dbg ("read (%d) - retry", len); } - camera->isActive = 0; - return -EIO; + up (&camera->sem); + return retval; } static ssize_t camera_write (struct file *file, @@ -193,10 +193,11 @@ return -EINVAL; camera = (struct camera_state *) file->private_data; - if (!camera->dev) + down (&camera->sem); + if (!camera->dev) { + up (&camera->sem); return -ENODEV; - if (camera->isActive++) - return -EBUSY; + } /* most writes will be small: simple commands, sometimes with * parameters. putting images (like borders) into the camera @@ -224,18 +225,13 @@ bytes_written = -EINTR; goto done; } - if (!camera->dev) { - if (!bytes_written) - bytes_written = -ENODEV; - goto done; - } result = usb_bulk_msg (camera->dev, usb_sndbulkpipe (camera->dev, camera->outEP), obuf, thistime, &count, HZ*10); if (result) - dbg ("write USB err - %x", result); + dbg ("write USB err - %d", result); if (count) { obuf += count; @@ -264,49 +260,69 @@ buf += copy_size; } done: - camera->isActive = 0; + up (&camera->sem); dbg ("wrote %d", bytes_written); return bytes_written; } static int camera_open (struct inode *inode, struct file *file) { - struct camera_state *camera; + struct camera_state *camera = NULL; int subminor; + int value = 0; + down (&state_table_mutex); subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE; if (subminor < 0 || subminor >= MAX_CAMERAS || !(camera = minor_data [subminor])) { + up (&state_table_mutex); return -ENODEV; } + down (&camera->sem); + up (&state_table_mutex); + + if (camera->buf) { + value = -EBUSY; + goto done; + } if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) { - return -ENOMEM; + value = -ENOMEM; + goto done; } - dbg ("open"); + dbg ("open #%d", subminor); - camera->isActive = 0; file->private_data = camera; - return 0; +done: + up (&camera->sem); + return value; } static int camera_release (struct inode *inode, struct file *file) { - struct camera_state *camera; + struct camera_state *camera; + int subminor; camera = (struct camera_state *) file->private_data; - kfree (camera->buf); + down (&state_table_mutex); + down (&camera->sem); + + if (camera->buf) { + kfree (camera->buf); + camera->buf = 0; + } + subminor = camera->subminor; /* If camera was unplugged with open file ... */ - lock_kernel(); if (!camera->dev) { - minor_data [camera->subminor] = NULL; + minor_data [subminor] = NULL; kfree (camera); } - unlock_kernel(); + up (&camera->sem); + up (&state_table_mutex); - dbg ("close"); + dbg ("close #%d", subminor); return 0; } @@ -333,7 +349,7 @@ struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; int direction, ep; - struct camera_state *camera; + struct camera_state *camera = NULL; /* Is it a supported camera? */ for (i = 0; i < sizeof (cameras) / sizeof (struct camera); i++) { @@ -368,27 +384,30 @@ /* select "subminor" number (part of a minor number) */ + down (&state_table_mutex); for (i = 0; i < MAX_CAMERAS; i++) { if (!minor_data [i]) break; } if (i >= MAX_CAMERAS) { info ("Ignoring additional USB Camera"); - return NULL; + up (&state_table_mutex); + goto bye; } /* allocate & init camera state */ camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL); if (!camera) { err ("no memory!"); - return NULL; + up (&state_table_mutex); + goto bye; } + + init_MUTEX (&camera->sem); camera->info = camera_info; camera->subminor = i; - camera->isActive = 0; camera->buf = NULL; init_waitqueue_head (&camera->wait); - info ("USB Camera #%d connected", camera->subminor); /* get input and output endpoints (either order) */ @@ -417,19 +436,19 @@ goto error; } - - if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) { - err ("Failed usb_set_configuration"); - goto error; - } + info ("USB Camera #%d connected", camera->subminor); camera->dev = dev; - return camera; + usb_inc_dev_use (dev); + goto bye; error: minor_data [camera->subminor] = NULL; kfree (camera); - return NULL; + camera = NULL; +bye: + up (&state_table_mutex); + return camera; } static void camera_disconnect(struct usb_device *dev, void *ptr) @@ -437,6 +456,9 @@ struct camera_state *camera = (struct camera_state *) ptr; int subminor = camera->subminor; + down (&state_table_mutex); + down (&camera->sem); + /* If camera's not opened, we can clean up right away. * Else apps see a disconnect on next I/O; the release cleans. */ @@ -447,6 +469,10 @@ camera->dev = NULL; info ("USB Camera #%d disconnected", subminor); + usb_dec_dev_use (dev); + + up (&camera->sem); + up (&state_table_mutex); } static /* const */ struct usb_driver camera_driver = { diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.0-test6/linux/drivers/usb/devio.c Mon Jul 10 16:47:25 2000 +++ linux/drivers/usb/devio.c Sun Aug 13 19:23:19 2000 @@ -733,8 +733,7 @@ else pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); - usb_clear_halt(ps->dev, pipe); - return 0; + return usb_clear_halt(ps->dev, pipe); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/evdev.c linux/drivers/usb/evdev.c --- v2.4.0-test6/linux/drivers/usb/evdev.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/evdev.c Wed Dec 31 16:00:00 1969 @@ -1,356 +0,0 @@ -/* - * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ - * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Event char devices, giving access to raw input device events. - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#define EVDEV_MINOR_BASE 64 -#define EVDEV_MINORS 32 -#define EVDEV_BUFFER_SIZE 64 - -#include -#include -#include -#include -#include -#include - -struct evdev { - int exist; - int open; - int minor; - struct input_handle handle; - wait_queue_head_t wait; - devfs_handle_t devfs; - struct evdev_list *list; -}; - -struct evdev_list { - struct input_event buffer[EVDEV_BUFFER_SIZE]; - int head; - int tail; - struct fasync_struct *fasync; - struct evdev *evdev; - struct evdev_list *next; -}; - -static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ }; - -static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) -{ - struct evdev *evdev = handle->private; - struct evdev_list *list = evdev->list; - - while (list) { - - get_fast_time(&list->buffer[list->head].time); - list->buffer[list->head].type = type; - list->buffer[list->head].code = code; - list->buffer[list->head].value = value; - list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); - - kill_fasync(&list->fasync, SIGIO, POLL_IN); - - list = list->next; - } - - wake_up_interruptible(&evdev->wait); -} - -static int evdev_fasync(int fd, struct file *file, int on) -{ - int retval; - struct evdev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &list->fasync); - return retval < 0 ? retval : 0; -} - -static int evdev_release(struct inode * inode, struct file * file) -{ - struct evdev_list *list = file->private_data; - struct evdev_list **listptr; - - lock_kernel(); - listptr = &list->evdev->list; - evdev_fasync(-1, file, 0); - - while (*listptr && (*listptr != list)) - listptr = &((*listptr)->next); - *listptr = (*listptr)->next; - - if (!--list->evdev->open) { - if (list->evdev->exist) { - input_close_device(&list->evdev->handle); - } else { - input_unregister_minor(list->evdev->devfs); - evdev_table[list->evdev->minor] = NULL; - kfree(list->evdev); - } - } - - kfree(list); - unlock_kernel(); - - return 0; -} - -static int evdev_open(struct inode * inode, struct file * file) -{ - struct evdev_list *list; - int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; - - if (i > EVDEV_MINORS || !evdev_table[i]) - return -ENODEV; - - if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) - return -ENOMEM; - memset(list, 0, sizeof(struct evdev_list)); - - list->evdev = evdev_table[i]; - list->next = evdev_table[i]->list; - evdev_table[i]->list = list; - - file->private_data = list; - - if (!list->evdev->open++) - if (list->evdev->exist) - input_open_device(&list->evdev->handle); - - return 0; -} - -static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - struct evdev_list *list = file->private_data; - int retval = 0; - - if (list->head == list->tail) { - - add_wait_queue(&list->evdev->wait, &wait); - current->state = TASK_INTERRUPTIBLE; - - while (list->head == list->tail) { - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - schedule(); - } - - current->state = TASK_RUNNING; - remove_wait_queue(&list->evdev->wait, &wait); - } - - if (retval) - return retval; - - while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { - if (copy_to_user(buffer + retval, list->buffer + list->tail, - sizeof(struct input_event))) return -EFAULT; - list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); - retval += sizeof(struct input_event); - } - - return retval; -} - -/* No kernel lock - fine */ -static unsigned int evdev_poll(struct file *file, poll_table *wait) -{ - struct evdev_list *list = file->private_data; - poll_wait(file, &list->evdev->wait, wait); - if (list->head != list->tail) - return POLLIN | POLLRDNORM; - return 0; -} - -static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct evdev_list *list = file->private_data; - struct evdev *evdev = list->evdev; - struct input_dev *dev = evdev->handle.dev; - int retval; - - switch (cmd) { - - case EVIOCGVERSION: - return put_user(EV_VERSION, (int *) arg); - - case EVIOCGID: - if ((retval = put_user(dev->idbus, ((short *) arg) + 0))) return retval; - if ((retval = put_user(dev->idvendor, ((short *) arg) + 1))) return retval; - if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval; - if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval; - return 0; - - default: - - if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) - return -EINVAL; - - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { - - long *bits; - int len; - - switch (_IOC_NR(cmd) & EV_MAX) { - case 0: bits = dev->evbit; len = EV_MAX; break; - case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; - case EV_REL: bits = dev->relbit; len = REL_MAX; break; - case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; - case EV_LED: bits = dev->ledbit; len = LED_MAX; break; - case EV_SND: bits = dev->sndbit; len = SND_MAX; break; - default: return -EINVAL; - } - len = NBITS(len) * sizeof(long); - if (len > _IOC_SIZE(cmd)) { - printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n", - len, _IOC_SIZE(cmd)); - len = _IOC_SIZE(cmd); - } - return copy_to_user((char *) arg, bits, len) ? -EFAULT : len; - } - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { - int len; - if (!dev->name) return 0; - len = strlen(dev->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len; - } - - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { - - int t = _IOC_NR(cmd) & ABS_MAX; - - if ((retval = put_user(dev->abs[t], ((int *) arg) + 0))) return retval; - if ((retval = put_user(dev->absmin[t], ((int *) arg) + 1))) return retval; - if ((retval = put_user(dev->absmax[t], ((int *) arg) + 2))) return retval; - if ((retval = put_user(dev->absfuzz[t], ((int *) arg) + 3))) return retval; - if ((retval = put_user(dev->absflat[t], ((int *) arg) + 4))) return retval; - - return 0; - } - } - return -EINVAL; -} - -static struct file_operations evdev_fops = { - owner: THIS_MODULE, - read: evdev_read, - write: evdev_write, - poll: evdev_poll, - open: evdev_open, - release: evdev_release, - ioctl: evdev_ioctl, - fasync: evdev_fasync, -}; - -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev) -{ - struct evdev *evdev; - int minor; - - for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); - if (evdev_table[minor]) { - printk(KERN_ERR "evdev: no more free evdev devices\n"); - return NULL; - } - - if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) - return NULL; - memset(evdev, 0, sizeof(struct evdev)); - - init_waitqueue_head(&evdev->wait); - - evdev->minor = minor; - evdev_table[minor] = evdev; - - evdev->handle.dev = dev; - evdev->handle.handler = handler; - evdev->handle.private = evdev; - - evdev->exist = 1; - - evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE); - - printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); - - return &evdev->handle; -} - -static void evdev_disconnect(struct input_handle *handle) -{ - struct evdev *evdev = handle->private; - - evdev->exist = 0; - - if (evdev->open) { - input_close_device(handle); - } else { - input_unregister_minor(evdev->devfs); - evdev_table[evdev->minor] = NULL; - kfree(evdev); - } -} - -static struct input_handler evdev_handler = { - event: evdev_event, - connect: evdev_connect, - disconnect: evdev_disconnect, - fops: &evdev_fops, - minor: EVDEV_MINOR_BASE, -}; - -static int __init evdev_init(void) -{ - input_register_handler(&evdev_handler); - return 0; -} - -static void __exit evdev_exit(void) -{ - input_unregister_handler(&evdev_handler); -} - -module_init(evdev_init); -module_exit(evdev_exit); - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Event character device driver"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.4.0-test6/linux/drivers/usb/hid.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/hid.c Tue Aug 22 09:06:31 2000 @@ -1,5 +1,5 @@ /* - * $Id: hid.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $ + * $Id: hid.c,v 1.14 2000/08/14 21:05:26 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -65,8 +65,8 @@ 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,unk,unk,124,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + 115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, @@ -149,7 +149,7 @@ usage = parser->local.usage[0]; - if (type == HID_COLLECTION_APPLICATION) + if (type == HID_COLLECTION_APPLICATION && !parser->device->application) parser->device->application = usage; if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */ @@ -197,7 +197,7 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage) { - if (parser->local.usage_index >= MAX_USAGES) { + if (parser->local.usage_index >= HID_MAX_USAGES) { dbg("usage index exceeded"); return -1; } @@ -346,7 +346,7 @@ return 0; case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - if ((parser->global.report_count = item_udata(item)) > MAX_USAGES) { + if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { dbg("invalid report_count %d", parser->global.report_count); return -1; } @@ -1224,10 +1224,31 @@ return -1; } +static int hid_submit_out(struct hid_device *hid) +{ + hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; + hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; + hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); + + if (usb_submit_urb(&hid->urbout)) { + err("usb_submit_urb(out) failed"); + return -1; + } + + return 0; +} + static void hid_ctrl(struct urb *urb) { + struct hid_device *hid = urb->context; + if (urb->status) - warn("ctrl urb status %d received", urb->status); + warn("ctrl urb status %d received", urb->status); + + hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + + if (hid->outhead != hid->outtail) + hid_submit_out(hid); } static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -1242,22 +1263,18 @@ } hid_set_field(field, offset, value); + hid_output_report(field->report, hid->out[hid->outhead].buffer); - if (hid->urbout.status == -EINPROGRESS) { - warn("had to kill output urb"); - usb_unlink_urb(&hid->urbout); - } + hid->out[hid->outhead].dr.value = 0x200 | field->report->id; + hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1; - hid_output_report(field->report, hid->bufout); + hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); - hid->dr.value = 0x200 | field->report->id; - hid->dr.length = ((field->report->size - 1) >> 3) + 1; - hid->urbout.transfer_buffer_length = hid->dr.length; + if (hid->outhead == hid->outtail) + hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (usb_submit_urb(&hid->urbout)) { - err("usb_submit_urb(out) failed"); - return -1; - } + if (hid->urbout.status != -EINPROGRESS) + hid_submit_out(hid); return 0; } @@ -1364,7 +1381,7 @@ if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT) rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); - if (!rsize || rsize > 1024) { + if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dbg("weird size of report descriptor (%u)", rsize); return NULL; } @@ -1420,11 +1437,11 @@ hid->dev = dev; hid->ifnum = interface->bInterfaceNumber; - hid->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - hid->dr.request = USB_REQ_SET_REPORT; - hid->dr.value = 0x200; - hid->dr.index = hid->ifnum; - hid->dr.length = 1; + for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { + hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + hid->out[n].dr.request = USB_REQ_SET_REPORT; + hid->out[n].dr.index = hid->ifnum; + } hid->input.name = hid->name; hid->input.idbus = BUS_USB; @@ -1441,7 +1458,7 @@ hid->input.idvendor, hid->input.idproduct); FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0), - (void*) &hid->dr, hid->bufout, 1, hid_ctrl, hid); + (void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid); if (interface->bInterfaceSubClass == 1) usb_set_protocol(dev, hid->ifnum, 1); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/hid.h linux/drivers/usb/hid.h --- v2.4.0-test6/linux/drivers/usb/hid.h Fri Jun 23 21:55:10 2000 +++ linux/drivers/usb/hid.h Tue Aug 22 09:06:31 2000 @@ -2,7 +2,7 @@ #define __HID_H /* - * $Id: hid.h,v 1.4 2000/05/29 09:01:52 vojtech Exp $ + * $Id: hid.h,v 1.7 2000/05/31 22:57:48 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -208,10 +208,11 @@ * This is the local enviroment. It is resistent up the the next main-item. */ -#define MAX_USAGES 1024 +#define HID_MAX_DESCRIPTOR_SIZE 4096 +#define HID_MAX_USAGES 1024 struct hid_local { - unsigned usage[MAX_USAGES]; /* usage array */ + unsigned usage[HID_MAX_USAGES]; /* usage array */ unsigned usage_index; unsigned usage_minimum; unsigned delimiter_depth; @@ -275,6 +276,14 @@ #define HID_REPORT_TYPES 3 +#define HID_BUFFER_SIZE 32 +#define HID_CONTROL_FIFO_SIZE 8 + +struct hid_control_fifo { + devrequest dr; + char buffer[HID_BUFFER_SIZE]; +}; + struct hid_device { /* device report descriptor */ __u8 *rdesc; unsigned rsize; @@ -286,11 +295,13 @@ struct usb_device *dev; /* USB device */ int ifnum; /* USB interface number */ - char buffer[32]; /* Receive buffer */ - char bufout[32]; /* Transmit buffer */ - devrequest dr; /* Startup packet */ struct urb urb; /* USB URB structure */ + char buffer[HID_BUFFER_SIZE]; /* Rx buffer */ + struct urb urbout; /* Output URB */ + struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */ + unsigned char outhead, outtail; /* Tx buffer head & tail */ + struct input_dev input; /* input device structure */ int open; /* is the device open by input? */ int quirks; /* Various nasty tricks the device can pull on us */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/iforce.c linux/drivers/usb/iforce.c --- v2.4.0-test6/linux/drivers/usb/iforce.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/iforce.c Wed Dec 31 16:00:00 1969 @@ -1,336 +0,0 @@ -/* - * $Id: iforce.c,v 1.7 2000/06/04 14:03:36 vojtech Exp $ - * - * Copyright (c) 2000 Vojtech Pavlik - * - * USB/RS232 I-Force joysticks and wheels. - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); - -#define USB_VENDOR_ID_LOGITECH 0x046d -#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281 - -#define IFORCE_MAX_LENGTH 16 - -#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE) -#define IFORCE_232 -#endif -#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE) -#define IFORCE_USB -#endif - -struct iforce { - signed char data[IFORCE_MAX_LENGTH]; - struct input_dev dev; - struct urb irq; - int open; - int idx, pkt, len, id; - unsigned char csum; -}; - -static struct { - __s32 x; - __s32 y; -} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -static char *iforce_name = "I-Force joystick/wheel"; - -static void iforce_process_packet(struct input_dev *dev, unsigned char id, int idx, unsigned char *data) -{ - switch (id) { - - case 1: /* joystick position data */ - case 3: /* wheel position data */ - - if (id == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } - - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - input_report_key(dev, BTN_TRIGGER, data[5] & 0x01); - input_report_key(dev, BTN_TOP, data[5] & 0x02); - input_report_key(dev, BTN_THUMB, data[5] & 0x04); - input_report_key(dev, BTN_TOP2, data[5] & 0x08); - input_report_key(dev, BTN_BASE, data[5] & 0x10); - input_report_key(dev, BTN_BASE2, data[5] & 0x20); - input_report_key(dev, BTN_BASE3, data[5] & 0x40); - input_report_key(dev, BTN_BASE4, data[5] & 0x80); - input_report_key(dev, BTN_BASE5, data[6] & 0x01); - input_report_key(dev, BTN_A, data[6] & 0x02); - input_report_key(dev, BTN_B, data[6] & 0x04); - input_report_key(dev, BTN_C, data[6] & 0x08); - break; - - case 2: /* force feedback effect status */ - break; - } -} - - -static int iforce_open(struct input_dev *dev) -{ - struct iforce *iforce = dev->private; - - if (dev->idbus == BUS_USB && !iforce->open++) - if (usb_submit_urb(&iforce->irq)) - return -EIO; - - return 0; -} - -static void iforce_close(struct input_dev *dev) -{ - struct iforce *iforce = dev->private; - - if (dev->idbus == BUS_USB && !--iforce->open) - usb_unlink_urb(&iforce->irq); -} - -static void iforce_input_setup(struct iforce *iforce) -{ - int i; - - iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - iforce->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) | - BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5); - iforce->dev.keybit[LONG(BTN_GAMEPAD)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C); - iforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) - | BIT(ABS_WHEEL) | BIT(ABS_GAS) | BIT(ABS_BRAKE); - - for (i = ABS_X; i <= ABS_Y; i++) { - iforce->dev.absmax[i] = 1920; - iforce->dev.absmin[i] = -1920; - iforce->dev.absflat[i] = 128; - iforce->dev.absfuzz[i] = 16; - } - - for (i = ABS_THROTTLE; i <= ABS_RUDDER; i++) { - iforce->dev.absmax[i] = 255; - iforce->dev.absmin[i] = 0; - } - - for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) { - iforce->dev.absmax[i] = 1; - iforce->dev.absmin[i] = -1; - } - - iforce->dev.private = iforce; - iforce->dev.open = iforce_open; - iforce->dev.close = iforce_close; - - input_register_device(&iforce->dev); -} - -#ifdef IFORCE_USB - -static void iforce_usb_irq(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1); -} - -static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum) -{ - struct usb_endpoint_descriptor *endpoint; - struct iforce *iforce; - - if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH || - dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE) - return NULL; - - endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; - - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return NULL; - memset(iforce, 0, sizeof(struct iforce)); - - iforce->dev.name = iforce_name; - iforce->dev.idbus = BUS_USB; - iforce->dev.idvendor = dev->descriptor.idVendor; - iforce->dev.idproduct = dev->descriptor.idProduct; - iforce->dev.idversion = dev->descriptor.bcdDevice; - - FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), - iforce->data, 8, iforce_usb_irq, iforce, endpoint->bInterval); - - iforce_input_setup(iforce); - - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - iforce->dev.number, iforce_name, dev->bus->busnum, dev->devnum, ifnum); - - return iforce; -} - -static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) -{ - struct iforce *iforce = ptr; - usb_unlink_urb(&iforce->irq); - input_unregister_device(&iforce->dev); - kfree(iforce); -} - -static struct usb_driver iforce_usb_driver = { - name: "iforce", - probe: iforce_usb_probe, - disconnect: iforce_usb_disconnect, -}; - -#endif - -#ifdef IFORCE_232 - -static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) -{ - struct iforce* iforce = serio->private; - - if (!iforce->pkt) { - if (data != 0x2b) { - return; - } - iforce->pkt = 1; - return; - } - - if (!iforce->id) { - if (data > 3) { - iforce->pkt = 0; - return; - } - iforce->id = data; - return; - } - - if (!iforce->len) { - if (data > IFORCE_MAX_LENGTH) { - iforce->pkt = 0; - iforce->id = 0; - return; - } - iforce->len = data; - return; - } - - if (iforce->idx < iforce->len) { - iforce->csum += iforce->data[iforce->idx++] = data; - return; - } - - if (iforce->idx == iforce->len) { - iforce_process_packet(&iforce->dev, iforce->id, iforce->idx, iforce->data); - iforce->pkt = 0; - iforce->id = 0; - iforce->len = 0; - iforce->idx = 0; - iforce->csum = 0; - } -} - -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) -{ - struct iforce *iforce; - - if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) - return; - - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; - memset(iforce, 0, sizeof(struct iforce)); - - iforce->dev.name = iforce_name; - iforce->dev.idbus = BUS_RS232; - iforce->dev.idvendor = SERIO_IFORCE; - iforce->dev.idproduct = 0x0001; - iforce->dev.idversion = 0x0100; - - serio->private = iforce; - - if (serio_open(serio, dev)) { - kfree(iforce); - return; - } - - iforce_input_setup(iforce); - - printk(KERN_INFO "input%d: %s on serio%d\n", - iforce->dev.number, iforce_name, serio->number); -} - -static void iforce_serio_disconnect(struct serio *serio) -{ - struct iforce* iforce = serio->private; - input_unregister_device(&iforce->dev); - serio_close(serio); - kfree(iforce); -} - -static struct serio_dev iforce_serio_dev = { - interrupt: iforce_serio_irq, - connect: iforce_serio_connect, - disconnect: iforce_serio_disconnect, -}; - -#endif - -static int __init iforce_init(void) -{ -#ifdef IFORCE_USB - usb_register(&iforce_usb_driver); -#endif -#ifdef IFORCE_232 - serio_register_device(&iforce_serio_dev); -#endif - return 0; -} - -static void __exit iforce_exit(void) -{ -#ifdef IFORCE_USB - usb_deregister(&iforce_usb_driver); -#endif -#ifdef IFORCE_232 - serio_unregister_device(&iforce_serio_dev); -#endif -} - -module_init(iforce_init); -module_exit(iforce_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/inode.c linux/drivers/usb/inode.c --- v2.4.0-test6/linux/drivers/usb/inode.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/inode.c Fri Aug 11 14:29:04 2000 @@ -290,14 +290,14 @@ i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, IROOT) < 0) + if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0) return 0; filp->f_pos++; i++; /* fall through */ case 1: - if (filldir(dirent, "..", 2, i, IROOT) < 0) + if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0) return 0; filp->f_pos++; i++; @@ -307,7 +307,7 @@ while (i >= 2 && i < 2+NRSPECIAL) { spec = &special[filp->f_pos-2]; - if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0) + if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0) return 0; filp->f_pos++; i++; @@ -323,7 +323,7 @@ } bus = list_entry(list, struct usb_bus, bus_list); sprintf(numbuf, "%03d", bus->busnum); - if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0) + if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0) break; filp->f_pos++; } @@ -343,7 +343,7 @@ if (pos > 0) pos--; else { - if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0) + if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0) return -1; filp->f_pos++; } @@ -368,13 +368,13 @@ return -EINVAL; switch ((unsigned int)filp->f_pos) { case 0: - if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0) + if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0) return 0; filp->f_pos++; /* fall through */ case 1: - if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0) + if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0) return 0; filp->f_pos++; /* fall through */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/input.c linux/drivers/usb/input.c --- v2.4.0-test6/linux/drivers/usb/input.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/input.c Wed Dec 31 16:00:00 1969 @@ -1,426 +0,0 @@ -/* - * $Id: input.c,v 1.7 2000/05/28 17:31:36 vojtech Exp $ - * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * The input layer module itself - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input layer module"); - -EXPORT_SYMBOL(input_register_device); -EXPORT_SYMBOL(input_unregister_device); -EXPORT_SYMBOL(input_register_handler); -EXPORT_SYMBOL(input_unregister_handler); -EXPORT_SYMBOL(input_register_minor); -EXPORT_SYMBOL(input_unregister_minor); -EXPORT_SYMBOL(input_open_device); -EXPORT_SYMBOL(input_close_device); -EXPORT_SYMBOL(input_event); - -#define INPUT_MAJOR 13 -#define INPUT_DEVICES 256 - -static struct input_dev *input_dev = NULL; -static struct input_handler *input_handler = NULL; -static struct input_handler *input_table[8] = { NULL, /* ... */ }; -static devfs_handle_t input_devfs_handle = NULL; -static int input_number = 0; -static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ }; - -void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct input_handle *handle = dev->handle; - -/* - * Filter non-events, and bad input values out. - */ - - if (type > EV_MAX || !test_bit(type, dev->evbit)) - return; - - switch (type) { - - case EV_KEY: - - if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) - return; - - if (value == 2) break; - - change_bit(code, dev->key); - - if (test_bit(EV_REP, dev->evbit) && dev->timer.function) { - if (value) { - mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]); - dev->repeat_key = code; - break; - } - if (dev->repeat_key == code) - del_timer(&dev->timer); - } - - break; - - case EV_ABS: - - if (code > ABS_MAX || !test_bit(code, dev->absbit)) - return; - - if (dev->absfuzz[code]) { - if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) && - (value < dev->abs[code] + (dev->absfuzz[code] >> 1))) - return; - - if ((value > dev->abs[code] - dev->absfuzz[code]) && - (value < dev->abs[code] + dev->absfuzz[code])) - value = (dev->abs[code] * 3 + value) >> 2; - - if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) && - (value < dev->abs[code] + (dev->absfuzz[code] << 1))) - value = (dev->abs[code] + value) >> 1; - } - - if (dev->abs[code] == value) - return; - - dev->abs[code] = value; - break; - - case EV_REL: - - if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) - return; - - break; - - case EV_LED: - - if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) - return; - - change_bit(code, dev->led); - if (dev->event) dev->event(dev, type, code, value); - - break; - - case EV_SND: - - if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value) - return; - - change_bit(code, dev->snd); - if (dev->event) dev->event(dev, type, code, value); - - break; - - case EV_REP: - - if (code > REP_MAX || dev->rep[code] == value) return; - - dev->rep[code] = value; - if (dev->event) dev->event(dev, type, code, value); - - break; - } -/* - * Add randomness. - */ - -#if 0 /* BUG */ - add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value); -#endif - -/* - * Distribute the event to handler modules. - */ - - while (handle) { - if (handle->open) - handle->handler->event(handle, type, code, value); - handle = handle->dnext; - } -} - -static void input_repeat_key(unsigned long data) -{ - struct input_dev *dev = (void *) data; - input_event(dev, EV_KEY, dev->repeat_key, 2); - mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); -} - -int input_open_device(struct input_handle *handle) -{ - handle->open++; - if (handle->dev->open) - return handle->dev->open(handle->dev); - return 0; -} - -void input_close_device(struct input_handle *handle) -{ - if (handle->dev->close) - handle->dev->close(handle->dev); - handle->open--; -} - -static void input_link_handle(struct input_handle *handle) -{ - handle->dnext = handle->dev->handle; - handle->hnext = handle->handler->handle; - handle->dev->handle = handle; - handle->handler->handle = handle; -} - -static void input_unlink_handle(struct input_handle *handle) -{ - struct input_handle **handleptr; - - handleptr = &handle->dev->handle; - while (*handleptr && (*handleptr != handle)) - handleptr = &((*handleptr)->dnext); - *handleptr = (*handleptr)->dnext; - - handleptr = &handle->handler->handle; - while (*handleptr && (*handleptr != handle)) - handleptr = &((*handleptr)->hnext); - *handleptr = (*handleptr)->hnext; -} - -void input_register_device(struct input_dev *dev) -{ - struct input_handler *handler = input_handler; - struct input_handle *handle; - -/* - * Initialize repeat timer to default values. - */ - - init_timer(&dev->timer); - dev->timer.data = (long) dev; - dev->timer.function = input_repeat_key; - dev->rep[REP_DELAY] = HZ/4; - dev->rep[REP_PERIOD] = HZ/33; - -/* - * Add the device. - */ - - if (input_number >= INPUT_DEVICES) { - printk(KERN_WARNING "input: ran out of input device numbers!\n"); - dev->number = input_number; - } else { - dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES); - set_bit(dev->number, input_devices); - } - - dev->next = input_dev; - input_dev = dev; - input_number++; - -/* - * Notify handlers. - */ - - while (handler) { - if ((handle = handler->connect(handler, dev))) - input_link_handle(handle); - handler = handler->next; - } -} - -void input_unregister_device(struct input_dev *dev) -{ - struct input_handle *handle = dev->handle; - struct input_dev **devptr = &input_dev; - struct input_handle *dnext; - -/* - * Kill any pending repeat timers. - */ - - del_timer(&dev->timer); - -/* - * Notify handlers. - */ - - while (handle) { - dnext = handle->dnext; - input_unlink_handle(handle); - handle->handler->disconnect(handle); - handle = dnext; - } - -/* - * Remove the device. - */ - - while (*devptr && (*devptr != dev)) - devptr = &((*devptr)->next); - *devptr = (*devptr)->next; - - input_number--; - - if (dev->number < INPUT_DEVICES) - clear_bit(dev->number, input_devices); -} - -void input_register_handler(struct input_handler *handler) -{ - struct input_dev *dev = input_dev; - struct input_handle *handle; - -/* - * Add minors if needed. - */ - - if (handler->fops != NULL) - input_table[handler->minor >> 5] = handler; - -/* - * Add the handler. - */ - - handler->next = input_handler; - input_handler = handler; - -/* - * Notify it about all existing devices. - */ - - while (dev) { - if ((handle = handler->connect(handler, dev))) - input_link_handle(handle); - dev = dev->next; - } -} - -void input_unregister_handler(struct input_handler *handler) -{ - struct input_handler **handlerptr = &input_handler; - struct input_handle *handle = handler->handle; - struct input_handle *hnext; - -/* - * Tell the handler to disconnect from all devices it keeps open. - */ - - while (handle) { - hnext = handle->hnext; - input_unlink_handle(handle); - handler->disconnect(handle); - handle = hnext; - } - -/* - * Remove it. - */ - - while (*handlerptr && (*handlerptr != handler)) - handlerptr = &((*handlerptr)->next); - - *handlerptr = (*handlerptr)->next; - -/* - * Remove minors. - */ - - if (handler->fops != NULL) - input_table[handler->minor >> 5] = NULL; -} - -static int input_open_file(struct inode *inode, struct file *file) -{ - struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5]; - struct file_operations *old_fops, *new_fops = NULL; - int err; - - /* No load-on-demand here? */ - if (!handler || !(new_fops = fops_get(handler->fops))) - return -ENODEV; - - /* - * That's _really_ odd. Usually NULL ->open means "nothing special", - * not "no device". Oh, well... - */ - if (!new_fops->open) { - fops_put(new_fops); - return -ENODEV; - } - old_fops = file->f_op; - file->f_op = new_fops; - err = new_fops->open(inode, file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - return err; -} - -static struct file_operations input_fops = { - owner: THIS_MODULE, - open: input_open_file, -}; - -devfs_handle_t input_register_minor(char *name, int minor, int minor_base) -{ - char devfs_name[16]; - sprintf(devfs_name, name, minor); - return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base, - S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL); -} - -void input_unregister_minor(devfs_handle_t handle) -{ - devfs_unregister(handle); -} - -static int __init input_init(void) -{ - if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) { - printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); - return -EBUSY; - } - input_devfs_handle = devfs_mk_dir(NULL, "input", NULL); - return 0; -} - -static void __exit input_exit(void) -{ - devfs_unregister(input_devfs_handle); - if (devfs_unregister_chrdev(INPUT_MAJOR, "input")) - printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR); -} - -module_init(input_init); -module_exit(input_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/joydev.c linux/drivers/usb/joydev.c --- v2.4.0-test6/linux/drivers/usb/joydev.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/joydev.c Wed Dec 31 16:00:00 1969 @@ -1,497 +0,0 @@ -/* - * $Id: joydev.c,v 1.11 2000/06/23 09:23:00 vojtech Exp $ - * - * Copyright (c) 1999-2000 Vojtech Pavlik - * Copyright (c) 1999 Colin Van Dyke - * - * Joystick device driver for the input driver suite. - * - * Sponsored by SuSE and Intel - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define JOYDEV_MINOR_BASE 0 -#define JOYDEV_MINORS 32 -#define JOYDEV_BUFFER_SIZE 64 - -struct joydev { - int exist; - int open; - int minor; - struct input_handle handle; - wait_queue_head_t wait; - devfs_handle_t devfs; - struct joydev *next; - struct joydev_list *list; - struct js_corr corr[ABS_MAX]; - struct JS_DATA_SAVE_TYPE glue; - int nabs; - int nkey; - __u16 keymap[KEY_MAX - BTN_MISC]; - __u16 keypam[KEY_MAX - BTN_MISC]; - __u8 absmap[ABS_MAX]; - __u8 abspam[ABS_MAX]; - __s16 abs[ABS_MAX]; -}; - -struct joydev_list { - struct js_event buffer[JOYDEV_BUFFER_SIZE]; - int head; - int tail; - int startup; - struct fasync_struct *fasync; - struct joydev *joydev; - struct joydev_list *next; -}; - -static struct joydev *joydev_table[JOYDEV_MINORS]; - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Joystick device driver"); -MODULE_SUPPORTED_DEVICE("input/js"); - -static int joydev_correct(int value, struct js_corr *corr) -{ - switch (corr->type) { - case JS_CORR_NONE: - break; - case JS_CORR_BROKEN: - value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : - ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : - ((corr->coef[2] * (value - corr->coef[0])) >> 14); - break; - default: - return 0; - } - - if (value < -32767) return -32767; - if (value > 32767) return 32767; - - return value; -} - -static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) -{ - struct joydev *joydev = handle->private; - struct joydev_list *list = joydev->list; - struct js_event event; - - switch (type) { - - case EV_KEY: - if (code < BTN_MISC || value == 2) return; - event.type = JS_EVENT_BUTTON; - event.number = joydev->keymap[code - BTN_MISC]; - event.value = value; - break; - - case EV_ABS: - event.type = JS_EVENT_AXIS; - event.number = joydev->absmap[code]; - event.value = joydev_correct(value, joydev->corr + event.number); - if (event.value == joydev->abs[event.number]) return; - joydev->abs[event.number] = event.value; - break; - - default: - return; - } - - event.time = jiffies * (1000 / HZ); - - while (list) { - - memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); - - if (list->startup == joydev->nabs + joydev->nkey) - if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) - list->startup = 0; - - kill_fasync(&list->fasync, SIGIO, POLL_IN); - - list = list->next; - } - - wake_up_interruptible(&joydev->wait); -} - -static int joydev_fasync(int fd, struct file *file, int on) -{ - int retval; - struct joydev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &list->fasync); - return retval < 0 ? retval : 0; -} - -static int joydev_release(struct inode * inode, struct file * file) -{ - struct joydev_list *list = file->private_data; - struct joydev_list **listptr; - - lock_kernel(); - listptr = &list->joydev->list; - joydev_fasync(-1, file, 0); - - while (*listptr && (*listptr != list)) - listptr = &((*listptr)->next); - *listptr = (*listptr)->next; - - if (!--list->joydev->open) { - if (list->joydev->exist) { - input_close_device(&list->joydev->handle); - } else { - input_unregister_minor(list->joydev->devfs); - joydev_table[list->joydev->minor] = NULL; - kfree(list->joydev); - } - } - - kfree(list); - unlock_kernel(); - - return 0; -} - -static int joydev_open(struct inode *inode, struct file *file) -{ - struct joydev_list *list; - int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE; - - if (i > JOYDEV_MINORS || !joydev_table[i]) - return -ENODEV; - - if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) - return -ENOMEM; - memset(list, 0, sizeof(struct joydev_list)); - - list->joydev = joydev_table[i]; - list->next = joydev_table[i]->list; - joydev_table[i]->list = list; - - file->private_data = list; - - if (!list->joydev->open++) - if (list->joydev->exist) - input_open_device(&list->joydev->handle); - - return 0; -} - -static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - struct joydev_list *list = file->private_data; - struct joydev *joydev = list->joydev; - struct input_dev *input = joydev->handle.dev; - int retval = 0; - - if (count < sizeof(struct js_event)) - return -EINVAL; - - if (count == sizeof(struct JS_DATA_TYPE)) { - - struct JS_DATA_TYPE data; - - data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) | - ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0); - data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; - data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; - - if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) - return -EFAULT; - - list->startup = 0; - list->tail = list->head; - - return sizeof(struct JS_DATA_TYPE); - } - - if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) { - - add_wait_queue(&list->joydev->wait, &wait); - current->state = TASK_INTERRUPTIBLE; - - while (list->head == list->tail) { - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - schedule(); - } - - current->state = TASK_RUNNING; - remove_wait_queue(&list->joydev->wait, &wait); - } - - if (retval) - return retval; - - while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { - - struct js_event event; - - event.time = jiffies * (1000/HZ); - - if (list->startup < joydev->nkey) { - event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; - event.number = list->startup; - event.value = !!test_bit(joydev->keypam[event.number], input->key); - } else { - event.type = JS_EVENT_AXIS | JS_EVENT_INIT; - event.number = list->startup - joydev->nkey; - event.value = joydev->abs[event.number]; - } - - if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) - return -EFAULT; - - list->startup++; - retval += sizeof(struct js_event); - } - - while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { - - if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) - return -EFAULT; - - list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); - retval += sizeof(struct js_event); - } - - return retval; -} - -/* No kernel lock - fine */ -static unsigned int joydev_poll(struct file *file, poll_table *wait) -{ - struct joydev_list *list = file->private_data; - poll_wait(file, &list->joydev->wait, wait); - if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) - return POLLIN | POLLRDNORM; - return 0; -} - -static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct joydev_list *list = file->private_data; - struct joydev *joydev = list->joydev; - struct input_dev *dev = joydev->handle.dev; - - - switch (cmd) { - - case JS_SET_CAL: - return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg, - sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; - case JS_GET_CAL: - return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR, - sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; - case JS_SET_TIMEOUT: - return get_user(joydev->glue.JS_TIMEOUT, (int *) arg); - case JS_GET_TIMEOUT: - return put_user(joydev->glue.JS_TIMEOUT, (int *) arg); - case JS_SET_TIMELIMIT: - return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg); - case JS_GET_TIMELIMIT: - return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg); - case JS_SET_ALL: - return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg, - sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; - case JS_GET_ALL: - return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue, - sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; - - case JSIOCGVERSION: - return put_user(JS_VERSION, (__u32 *) arg); - case JSIOCGAXES: - return put_user(joydev->nabs, (__u8 *) arg); - case JSIOCGBUTTONS: - return put_user(joydev->nkey, (__u8 *) arg); - case JSIOCSCORR: - return copy_from_user(joydev->corr, (struct js_corr *) arg, - sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; - case JSIOCGCORR: - return copy_to_user((struct js_corr *) arg, joydev->corr, - sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; - default: - if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { - int len; - if (!dev->name) return 0; - len = strlen(dev->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT; - return len; - } - } - return -EINVAL; -} - -static struct file_operations joydev_fops = { - owner: THIS_MODULE, - read: joydev_read, - write: joydev_write, - poll: joydev_poll, - open: joydev_open, - release: joydev_release, - ioctl: joydev_ioctl, - fasync: joydev_fasync, -}; - -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev) -{ - struct joydev *joydev; - int i, j, minor; - - if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && - test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) && - (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) - || test_bit(BTN_1, dev->keybit)))) return NULL; - - for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); - if (joydev_table[minor]) { - printk(KERN_ERR "joydev: no more free joydev devices\n"); - return NULL; - } - - if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) - return NULL; - memset(joydev, 0, sizeof(struct joydev)); - - init_waitqueue_head(&joydev->wait); - - joydev->minor = minor; - joydev_table[minor] = joydev; - - joydev->handle.dev = dev; - joydev->handle.handler = handler; - joydev->handle.private = joydev; - - joydev->exist = 1; - - for (i = 0; i < ABS_MAX; i++) - if (test_bit(i, dev->absbit)) { - joydev->absmap[i] = joydev->nabs; - joydev->abspam[joydev->nabs] = i; - joydev->nabs++; - } - - for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++) - if (test_bit(i + BTN_MISC, dev->keybit)) { - joydev->keymap[i] = joydev->nkey; - joydev->keypam[joydev->nkey] = i + BTN_MISC; - joydev->nkey++; - } - - for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) - if (test_bit(i + BTN_MISC, dev->keybit)) { - joydev->keymap[i] = joydev->nkey; - joydev->keypam[joydev->nkey] = i + BTN_MISC; - joydev->nkey++; - } - - for (i = 0; i < joydev->nabs; i++) { - j = joydev->abspam[i]; - if (dev->absmax[j] == dev->absmin[j]) { - joydev->corr[i].type = JS_CORR_NONE; - continue; - } - joydev->corr[i].type = JS_CORR_BROKEN; - joydev->corr[i].prec = dev->absfuzz[j]; - joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; - joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; - joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); - joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); - - joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); - } - - joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); - - printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); - - return &joydev->handle; -} - -static void joydev_disconnect(struct input_handle *handle) -{ - struct joydev *joydev = handle->private; - - joydev->exist = 0; - - if (joydev->open) { - input_close_device(handle); - } else { - input_unregister_minor(joydev->devfs); - joydev_table[joydev->minor] = NULL; - kfree(joydev); - } -} - -static struct input_handler joydev_handler = { - event: joydev_event, - connect: joydev_connect, - disconnect: joydev_disconnect, - fops: &joydev_fops, - minor: JOYDEV_MINOR_BASE, -}; - -static int __init joydev_init(void) -{ - input_register_handler(&joydev_handler); - return 0; -} - -static void __exit joydev_exit(void) -{ - input_unregister_handler(&joydev_handler); -} - -module_init(joydev_init); -module_exit(joydev_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.4.0-test6/linux/drivers/usb/keybdev.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/keybdev.c Wed Dec 31 16:00:00 1969 @@ -1,200 +0,0 @@ -/* - * $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $ - * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Input driver to keyboard driver binding. - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) - -static int x86_sysrq_alt = 0; - -static unsigned short x86_keycodes[256] = - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90, - 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339, - 367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349, - 360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355, - 103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361, - 291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114, - 118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269, - 271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307, - 308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330, - 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 }; - -static int emulate_raw(unsigned int keycode, int down) -{ - if (keycode > 255 || !x86_keycodes[keycode]) - return -1; - - if (keycode == KEY_PAUSE) { - handle_scancode(0xe1, 1); - handle_scancode(0x1d, down); - handle_scancode(0x45, down); - return 0; - } - - if (keycode == KEY_SYSRQ && x86_sysrq_alt) { - handle_scancode(0x54, down); - return 0; - } - - if (x86_keycodes[keycode] & 0x100) - handle_scancode(0xe0, 1); - - handle_scancode(x86_keycodes[keycode] & 0x7f, down); - - if (keycode == KEY_SYSRQ) { - handle_scancode(0xe0, 1); - handle_scancode(0x37, down); - } - - if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) - x86_sysrq_alt = down; - - return 0; -} - -#elif defined(CONFIG_ADB_KEYBOARD) - -static unsigned char mac_keycodes[128] = - { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, - 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, - 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 }; - -static int emulate_raw(unsigned int keycode, int down) -{ - if (keycode > 127 || !mac_keycodes[keycode]) - return -1; - - handle_scancode(mac_keycodes[keycode] & 0x7f, down); - - return 0; -} - -#endif - -static struct input_handler keybdev_handler; - -void keybdev_ledfunc(unsigned int led) -{ - struct input_handle *handle; - - for (handle = keybdev_handler.handle; handle; handle = handle->hnext) { - - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04)); - - } -} - -void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) -{ - if (type != EV_KEY) return; - - if (emulate_raw(code, down)) - printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code); - - tasklet_schedule(&keyboard_tasklet); -} - -static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev) -{ - struct input_handle *handle; - int i; - - if (!test_bit(EV_KEY, dev->evbit)) - return NULL; - - for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) break; - - if (i == BTN_MISC) - return NULL; - - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) - return NULL; - memset(handle, 0, sizeof(struct input_handle)); - - handle->dev = dev; - handle->handler = handler; - - input_open_device(handle); - - printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number); - - return handle; -} - -static void keybdev_disconnect(struct input_handle *handle) -{ - printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number); - input_close_device(handle); - kfree(handle); -} - -static struct input_handler keybdev_handler = { - event: keybdev_event, - connect: keybdev_connect, - disconnect: keybdev_disconnect, -}; - -static int __init keybdev_init(void) -{ - input_register_handler(&keybdev_handler); - kbd_ledfunc = keybdev_ledfunc; - return 0; -} - -static void __exit keybdev_exit(void) -{ - kbd_ledfunc = NULL; - input_unregister_handler(&keybdev_handler); -} - -module_init(keybdev_init); -module_exit(keybdev_exit); - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input driver to keyboard driver binding"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c --- v2.4.0-test6/linux/drivers/usb/mousedev.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/mousedev.c Wed Dec 31 16:00:00 1969 @@ -1,486 +0,0 @@ -/* - * $Id: mousedev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $ - * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Input driver to PS/2 or ImPS/2 device driver module. - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#define MOUSEDEV_MINOR_BASE 32 -#define MOUSEDEV_MINORS 32 -#define MOUSEDEV_MIX 31 - -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X -#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 -#endif -#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y -#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 -#endif - -struct mousedev { - int exist; - int open; - int minor; - wait_queue_head_t wait; - struct mousedev_list *list; - struct input_handle handle; - devfs_handle_t devfs; -}; - -struct mousedev_list { - struct fasync_struct *fasync; - struct mousedev *mousedev; - struct mousedev_list *next; - int dx, dy, dz, oldx, oldy; - char ps2[6]; - unsigned long buttons; - unsigned char ready, buffer, bufsiz; - unsigned char mode, genseq, impseq; -}; - -#define MOUSEDEV_GENIUS_LEN 5 -#define MOUSEDEV_IMPS_LEN 6 - -static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 }; -static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; - -static struct input_handler mousedev_handler; - -static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; -static struct mousedev mousedev_mix; - -static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) -{ - struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; - struct mousedev **mousedev = mousedevs; - struct mousedev_list *list; - int index, size; - - while (*mousedev) { - list = (*mousedev)->list; - while (list) { - switch (type) { - case EV_ABS: - switch (code) { - case ABS_X: - size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size; - list->oldx += list->dx * size; - break; - case ABS_Y: - size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size; - list->oldy -= list->dy * size; - break; - } - break; - case EV_REL: - switch (code) { - case REL_X: list->dx += value; break; - case REL_Y: list->dy -= value; break; - case REL_WHEEL: if (list->mode) list->dz -= value; break; - } - break; - - case EV_KEY: - switch (code) { - case BTN_0: - case BTN_TOUCH: - case BTN_LEFT: index = 0; break; - case BTN_4: - case BTN_EXTRA: if (list->mode > 1) { index = 4; break; } - case BTN_STYLUS: - case BTN_1: - case BTN_RIGHT: index = 1; break; - case BTN_3: - case BTN_SIDE: if (list->mode > 1) { index = 3; break; } - case BTN_2: - case BTN_STYLUS2: - case BTN_MIDDLE: index = 2; break; - default: return; - } - switch (value) { - case 0: clear_bit(index, &list->buttons); break; - case 1: set_bit(index, &list->buttons); break; - case 2: return; - } - break; - } - - list->ready = 1; - - kill_fasync(&list->fasync, SIGIO, POLL_IN); - - list = list->next; - } - - wake_up_interruptible(&((*mousedev)->wait)); - mousedev++; - } -} - -static int mousedev_fasync(int fd, struct file *file, int on) -{ - int retval; - struct mousedev_list *list = file->private_data; - retval = fasync_helper(fd, file, on, &list->fasync); - return retval < 0 ? retval : 0; -} - -static int mousedev_release(struct inode * inode, struct file * file) -{ - struct mousedev_list *list = file->private_data; - struct mousedev_list **listptr; - - lock_kernel(); - listptr = &list->mousedev->list; - mousedev_fasync(-1, file, 0); - - while (*listptr && (*listptr != list)) - listptr = &((*listptr)->next); - *listptr = (*listptr)->next; - - if (!--list->mousedev->open) { - if (list->mousedev->minor == MOUSEDEV_MIX) { - struct input_handle *handle = mousedev_handler.handle; - while (handle) { - struct mousedev *mousedev = handle->private; - if (!mousedev->open) { - if (mousedev->exist) { - input_close_device(&mousedev->handle); - } else { - input_unregister_minor(mousedev->devfs); - mousedev_table[mousedev->minor] = NULL; - kfree(mousedev); - } - } - handle = handle->hnext; - } - } else { - if (!mousedev_mix.open) { - if (list->mousedev->exist) { - input_close_device(&list->mousedev->handle); - } else { - input_unregister_minor(list->mousedev->devfs); - mousedev_table[list->mousedev->minor] = NULL; - kfree(list->mousedev); - } - } - } - } - - kfree(list); - unlock_kernel(); - - return 0; -} - -static int mousedev_open(struct inode * inode, struct file * file) -{ - struct mousedev_list *list; - int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; - - if (i > MOUSEDEV_MINORS || !mousedev_table[i]) - return -ENODEV; - - if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) - return -ENOMEM; - memset(list, 0, sizeof(struct mousedev_list)); - - list->mousedev = mousedev_table[i]; - list->next = mousedev_table[i]->list; - mousedev_table[i]->list = list; - file->private_data = list; - - if (!list->mousedev->open++) { - if (list->mousedev->minor == MOUSEDEV_MIX) { - struct input_handle *handle = mousedev_handler.handle; - while (handle) { - struct mousedev *mousedev = handle->private; - if (!mousedev->open) - if (mousedev->exist) - input_open_device(handle); - handle = handle->hnext; - } - } else { - if (!mousedev_mix.open) - if (list->mousedev->exist) - input_open_device(&list->mousedev->handle); - } - } - - return 0; -} - -static void mousedev_packet(struct mousedev_list *list, unsigned char off) -{ - list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); - list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); - list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); - list->dx -= list->ps2[off + 1]; - list->dy -= list->ps2[off + 2]; - list->bufsiz = off + 3; - - if (list->mode > 1) - list->ps2[off] |= ((list->buttons & 0x30) << 2); - - if (list->mode) { - list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); - list->bufsiz++; - list->dz -= list->ps2[off + 3]; - } - if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; - list->buffer = list->bufsiz; -} - - -static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - struct mousedev_list *list = file->private_data; - unsigned char c; - int i; - - for (i = 0; i < count; i++) { - - c = buffer[i]; - - if (c == mousedev_genius_seq[list->genseq]) { - if (++list->genseq == MOUSEDEV_GENIUS_LEN) { - list->genseq = 0; - list->ready = 1; - list->mode = 2; - } - } else list->genseq = 0; - - if (c == mousedev_imps_seq[list->impseq]) { - if (++list->impseq == MOUSEDEV_IMPS_LEN) { - list->impseq = 0; - list->ready = 1; - list->mode = 1; - } - } else list->impseq = 0; - - list->ps2[0] = 0xfa; - list->bufsiz = 1; - - switch (c) { - - case 0xeb: /* Poll */ - mousedev_packet(list, 1); - break; - - case 0xf2: /* Get ID */ - list->ps2[1] = (list->mode == 1) ? 3 : 0; - list->bufsiz = 2; - break; - - case 0xe9: /* Get info */ - if (list->mode == 2) { - list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55; - } else { - list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; - } - list->bufsiz = 4; - break; - } - - list->buffer = list->bufsiz; - } - - kill_fasync(&list->fasync, SIGIO, POLL_IN); - - wake_up_interruptible(&list->mousedev->wait); - - return count; -} - -static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - struct mousedev_list *list = file->private_data; - int retval = 0; - - if (!list->ready && !list->buffer) { - - add_wait_queue(&list->mousedev->wait, &wait); - current->state = TASK_INTERRUPTIBLE; - - while (!list->ready) { - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - schedule(); - } - - current->state = TASK_RUNNING; - remove_wait_queue(&list->mousedev->wait, &wait); - } - - if (retval) - return retval; - - if (!list->buffer) - mousedev_packet(list, 0); - - if (count > list->buffer) - count = list->buffer; - - if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count)) - return -EFAULT; - - list->buffer -= count; - - return count; -} - -/* No kernel lock - fine */ -static unsigned int mousedev_poll(struct file *file, poll_table *wait) -{ - struct mousedev_list *list = file->private_data; - poll_wait(file, &list->mousedev->wait, wait); - if (list->ready || list->buffer) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations mousedev_fops = { - owner: THIS_MODULE, - read: mousedev_read, - write: mousedev_write, - poll: mousedev_poll, - open: mousedev_open, - release: mousedev_release, - fasync: mousedev_fasync, -}; - -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev) -{ - struct mousedev *mousedev; - int minor = 0; - - if (!test_bit(EV_KEY, dev->evbit) || - (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit))) - return NULL; - - if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) && - (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit))) - return NULL; - - for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); - if (mousedev_table[minor]) { - printk(KERN_ERR "mousedev: no more free mousedev devices\n"); - return NULL; - } - - if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) - return NULL; - memset(mousedev, 0, sizeof(struct mousedev)); - init_waitqueue_head(&mousedev->wait); - - mousedev->exist = 1; - mousedev->minor = minor; - mousedev_table[minor] = mousedev; - - mousedev->handle.dev = dev; - mousedev->handle.handler = handler; - mousedev->handle.private = mousedev; - - mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE); - - if (mousedev_mix.open) - input_open_device(&mousedev->handle); - - printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); - - return &mousedev->handle; -} - -static void mousedev_disconnect(struct input_handle *handle) -{ - struct mousedev *mousedev = handle->private; - - mousedev->exist = 0; - - if (mousedev->open) { - input_close_device(handle); - } else { - if (mousedev_mix.open) - input_close_device(handle); - input_unregister_minor(mousedev->devfs); - mousedev_table[mousedev->minor] = NULL; - kfree(mousedev); - } -} - -static struct input_handler mousedev_handler = { - event: mousedev_event, - connect: mousedev_connect, - disconnect: mousedev_disconnect, - fops: &mousedev_fops, - minor: MOUSEDEV_MINOR_BASE, -}; - -static int __init mousedev_init(void) -{ - input_register_handler(&mousedev_handler); - - memset(&mousedev_mix, 0, sizeof(struct mousedev)); - init_waitqueue_head(&mousedev_mix.wait); - mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; - mousedev_mix.exist = 1; - mousedev_mix.minor = MOUSEDEV_MIX; - mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE); - - printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); - - return 0; -} - -static void __exit mousedev_exit(void) -{ - input_unregister_minor(mousedev_mix.devfs); - input_unregister_handler(&mousedev_handler); -} - -module_init(mousedev_init); -module_exit(mousedev_exit); - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c --- v2.4.0-test6/linux/drivers/usb/pegasus.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/pegasus.c Tue Aug 22 15:23:13 2000 @@ -1,7 +1,7 @@ /* ** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller ** -** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@spct.net) +** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg) ** ** ** ChangeLog: @@ -42,16 +42,26 @@ #include -static const char *version = __FILE__ ": v0.4.0 2000/06/15 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n"; +static const char *version = __FILE__ ": v0.4.3 2000/08/22 (C) 1999-2000 Petko Manolov (petkan@dce.bg)\n"; + + +#define PEGASUS_USE_WAITQ #define PEGASUS_MTU 1500 #define PEGASUS_MAX_MTU 1536 -#define SROM_WRITE 0x01 -#define SROM_READ 0x02 -#define PEGASUS_TX_TIMEOUT (HZ*5) -#define PEGASUS_CTRL_TIMEOUT 1000 -#define PEGASUS_RESET 1 +#define EPROM_WRITE 0x01 +#define EPROM_READ 0x02 +#define PEGASUS_TX_TIMEOUT (HZ*10) +#define PEGASUS_CTRL_TIMEOUT (HZ*5) +#define PEGASUS_CTRL_WAIT (1<<31) +#define PEGASUS_RUNNING 1 +#define PEGASUS_REQT_READ 0xc0 +#define PEGASUS_REQT_WRITE 0x40 +#define PEGASUS_REQ_GET_REGS 0xf0 +#define PEGASUS_REQ_SET_REGS 0xf1 +#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS +#define NUM_CTRL_URBS 0x10 #define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) @@ -75,16 +85,26 @@ }; +struct pegasus; +struct ctrl_urb_pool { + struct pegasus *pegasus; + struct urb urb; + devrequest dr; + __u8 busy; +}; + + struct pegasus { struct usb_device *usb; struct net_device *net; struct net_device_stats stats; int flags; - spinlock_t pegasus_lock, ctrl_lock; - struct urb rx_urb, tx_urb, intr_urb, ctrl_urb; - devrequest dr; - unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); - unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); + struct urb rx_urb, tx_urb, intr_urb; + struct ctrl_urb_pool ALIGN(ctrl[NUM_CTRL_URBS]); + wait_queue_head_t ctrl_wait; + struct semaphore ctrl_sem; + unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); + unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(intr_buff[8]); }; @@ -100,10 +120,11 @@ static int multicast_filter_limit = 32; -MODULE_AUTHOR("Petko Manolov "); +MODULE_AUTHOR("Petko Manolov "); MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver"); MODULE_PARM(loopback, "i"); -MODULE_PARM_DESC(loopback, "Enable loopback mode (Bit 0) and ??? (Bit 1)"); +MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); + static struct usb_eth_dev usb_dev_id[] = { {"Billionton USB-100", 0x08dd, 0x0986, NULL}, @@ -112,8 +133,10 @@ {"D-Link DSB-650TX", 0x2001, 0x4001, NULL}, {"D-Link DSB-650TX", 0x2001, 0x4002, NULL}, {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL}, + {"D-Link DSB-650", 0x2001, 0xabc1, NULL}, {"D-Link DU-E10", 0x07b8, 0xabc1, NULL}, {"D-Link DU-E100", 0x07b8, 0x4002, NULL}, + {"Linksys USB10TX", 0x066b, 0x2202, NULL}, {"Linksys USB100TX", 0x066b, 0x2203, NULL}, {"Linksys USB100TX", 0x066b, 0x2204, NULL}, {"Linksys USB Ethernet Adapter", 0x066b, 0x2206, NULL}, @@ -122,112 +145,149 @@ {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL}, {"IO DATA USB ET/TX", 0x04bb, 0x0904, NULL}, {"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, NULL}, + {"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, NULL}, {NULL, 0, 0, NULL} }; - -static void pegasus_ctrl_end( urb_t *urb ) +static void pegasus_unlink_ctrl_urbs( struct pegasus *pegasus ) { - if ( urb->status ) - warn("ctrl_urb end status %d", urb->status); + int i; + + for ( i=0; i < NUM_CTRL_URBS; i++ ) { + if ( pegasus->ctrl[i].urb.status == -EINPROGRESS ) + usb_unlink_urb( &pegasus->ctrl[i].urb ); + } } -static int pegasus_ctrl_timeout( urb_t *ctrl_urb ) +static int pegasus_find_ctrl_urb( struct pegasus *pegasus ) { - int timeout=0; - - while ( ctrl_urb->status == -EINPROGRESS ) { - if ( timeout++ < PEGASUS_CTRL_TIMEOUT ) { - udelay(100); - continue; - } - err("ctrl urb busy %d", ctrl_urb->status); - usb_unlink_urb( ctrl_urb ); - return ctrl_urb->status; - } - return 0; + int i=0; + + while( i < NUM_CTRL_URBS && (pegasus->ctrl[i].busy == 1 || + (pegasus->ctrl[i].urb.status == -EINPROGRESS)) ) + i++; + + return i; } -static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +static void pegasus_ctrl_end( urb_t *urb ) { - int ret; + struct ctrl_urb_pool *ctrl = urb->context; + struct pegasus *pegasus = ctrl->pegasus; - spin_lock( &pegasus->ctrl_lock ); - pegasus->dr.requesttype = 0xc0; - pegasus->dr.request = 0xf0; - pegasus->dr.value = 0x0; - pegasus->dr.index = indx; - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size; - - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, - usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, - data, size, pegasus_ctrl_end, pegasus ); - - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err("BAD CTRLs %d", ret); - else - ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); - - spin_unlock( &pegasus->ctrl_lock ); + if ( !pegasus ) + return; - return ret; + if ( urb->status ) + warn("ctrl_urb end status %d", urb->status); + ctrl->busy = 0; +#ifdef PEGASUS_USE_WAITQ + wake_up_interruptible( &pegasus->ctrl_wait ); +#endif } -static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) { - int ret; + int ret, i; + struct ctrl_urb_pool *ctrl; + + if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { + return -1; + } + ctrl = &pegasus->ctrl[i]; + ctrl->busy = 1; + ctrl->pegasus = pegasus; + + ctrl->dr.requesttype = PEGASUS_REQT_READ; + ctrl->dr.request = PEGASUS_REQ_GET_REGS; + ctrl->dr.value = 0; + ctrl->dr.index = cpu_to_le16p(&indx); + ctrl->dr.length = + ctrl->urb.transfer_buffer_length = cpu_to_le16p(&size); + + FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + usb_rcvctrlpipe(pegasus->usb,0), + (char *)&ctrl->dr, + data, size, pegasus_ctrl_end, ctrl ); + + if ( (ret = usb_submit_urb( &ctrl->urb )) ) + err( __FUNCTION__ " BAD CTRLs %d", ret); +#ifdef PEGASUS_USE_WAITQ + interruptible_sleep_on( &pegasus->ctrl_wait ); +#endif + return ret; +} - spin_lock( &pegasus->ctrl_lock ); - pegasus->dr.requesttype = 0x40; - pegasus->dr.request = 0xf1; - pegasus->dr.value = 0x0; - pegasus->dr.index = indx; - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size; - - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, - data, size, pegasus_ctrl_end, pegasus ); - - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err("BAD CTRL %d", ret); - else - ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); - spin_unlock( &pegasus->ctrl_lock ); +static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +{ + int ret, i; + struct ctrl_urb_pool *ctrl; + + if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { + return -1; + } + ctrl = &pegasus->ctrl[i]; + ctrl->busy = 1; + ctrl->pegasus = pegasus; + + ctrl->dr.requesttype = PEGASUS_REQT_WRITE; + ctrl->dr.request = PEGASUS_REQ_SET_REGS; + ctrl->dr.value = 0; + ctrl->dr.index = cpu_to_le16p( &indx ); + ctrl->dr.length = + ctrl->urb.transfer_buffer_length = cpu_to_le16p( &size ); + + FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), + (char *)&ctrl->dr, + data, size, pegasus_ctrl_end, ctrl ); + + if ( (ret = usb_submit_urb( &ctrl->urb )) ) + err( __FUNCTION__ " BAD CTRL %d", ret); +#ifdef PEGASUS_USE_WAITQ + interruptible_sleep_on( &pegasus->ctrl_wait ); +#endif return ret; } static int pegasus_set_register( struct pegasus *pegasus, __u16 indx,__u8 data ) { - int ret; - - - spin_lock( &pegasus->ctrl_lock ); - pegasus->dr.requesttype = 0x40; - pegasus->dr.request = 0xf1; - pegasus->dr.value = data; - pegasus->dr.index = indx; - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1; - - FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, - &data, 1, pegasus_ctrl_end, pegasus ); - - if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) - err("BAD CTRL %d", ret); - else - ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb ); - - spin_unlock( &pegasus->ctrl_lock ); + int ret, i; + struct ctrl_urb_pool *ctrl; + + if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { + return -1; + } + ctrl = &pegasus->ctrl[i]; + ctrl->busy = 1; + ctrl->pegasus = pegasus; + + ctrl->dr.requesttype = PEGASUS_REQT_WRITE; + ctrl->dr.request = PEGASUS_REQ_SET_REG; + ctrl->dr.value = cpu_to_le16p( &data ); + ctrl->dr.index = cpu_to_le16p( &indx ); + ctrl->dr.length = ctrl->urb.transfer_buffer_length = 1; + + FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), + (char *)&ctrl->dr, + &data, 1, pegasus_ctrl_end, ctrl ); + + if ( (ret = usb_submit_urb( &ctrl->urb )) ) + err( __FUNCTION__ " BAD CTRL %d", ret); +#ifdef PEGASUS_USE_WAITQ + interruptible_sleep_on( &pegasus->ctrl_wait ); +#endif return ret; } @@ -244,10 +304,9 @@ *regdata = *(__u16 *)(data); return 0; } - udelay(100); } - warn("read_phy_word() failed"); + return 1; } @@ -262,10 +321,9 @@ pegasus_get_registers(pegasus, PhyCtrl, 1, data); if (data[0] & 0x80) return 0; - udelay(100); } - warn("write_phy_word() failed"); + return 1; } @@ -284,8 +342,8 @@ return 0; } } - warn("pegasus_rw_eprom_word() failed"); + return 1; } @@ -294,7 +352,7 @@ { int i; for (i = 0; i < 3; i++) - if (pegasus_rw_eprom_word(pegasus,i,(__u16 *)&id[i*2],SROM_READ)) + if (pegasus_rw_eprom_word(pegasus, i, (__u16 *)&id[i*2], EPROM_READ)) return 1; return 0; } @@ -311,8 +369,6 @@ if (~data & 0x08) { if (loopback & 1) return 0; - if (loopback & 2) - pegasus_write_phy_word(pegasus, 0, 0x4000); pegasus_set_register(pegasus, Gpio0, 0x24); pegasus_set_register(pegasus, Gpio0, 0x27); return 0; @@ -348,7 +404,6 @@ if ((partmedia & 0x1f) != 1) { warn("party FAIL %x", partmedia); - /* return 5; FIXME */ } data[0] = 0xc9; @@ -361,15 +416,21 @@ } -static void pegasus_read_bulk(struct urb *urb) +static void pegasus_read_bulk_callback( struct urb *urb ) { struct pegasus *pegasus = urb->context; - struct net_device *net = pegasus->net; + struct net_device *net; /* = pegasus->net;*/ int count = urb->actual_length, res; - int rx_status = *(int *)(pegasus->rx_buff + count - 4); + int rx_status; /*= *(int *)(pegasus->rx_buff + count - 4);*/ struct sk_buff *skb; __u16 pkt_len; + if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) ) + return; + + net = pegasus->net; + rx_status = *(int *)(pegasus->rx_buff + count - 4); + if (urb->status) { dbg("%s: RX status %d", net->name, urb->status); goto goon; @@ -408,31 +469,30 @@ pegasus->stats.rx_bytes += pkt_len; goon: - if ((res = usb_submit_urb(&pegasus->rx_urb))) + if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) warn("(prb)failed rx_urb %d", res); } -static void pegasus_irq(urb_t *urb) +static void pegasus_irq_callback( urb_t *urb ) { __u8 *d = urb->transfer_buffer; - + + if ( d[0] ) dbg("txst0=0x%2x", d[0]); } -static void pegasus_write_bulk(struct urb *urb) +static void pegasus_write_bulk_callback(struct urb *urb) { struct pegasus *pegasus = urb->context; + if ( !pegasus ) + return; if (urb->status) info("%s: TX status %d", pegasus->net->name, urb->status); -#if 1 /* Should be fixed */ - if (urb->status == -ETIMEDOUT) - pegasus_reset_mac(pegasus); -#endif netif_wake_queue(pegasus->net); } @@ -440,10 +500,11 @@ { struct pegasus *pegasus = net->priv; + if ( !pegasus ) + return; usb_unlink_urb(&pegasus->tx_urb); - warn("%s: Tx timed out. Reseting...", net->name); - pegasus_reset_mac( pegasus ); + warn("%s: Tx timed out.", net->name); pegasus->stats.tx_errors++; net->trans_start = jiffies; @@ -457,13 +518,14 @@ int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3; int res; - spin_lock(&pegasus->pegasus_lock); - netif_stop_queue(net); + if ( !(pegasus->flags & PEGASUS_RUNNING) ) + return 0; ((__u16 *)pegasus->tx_buff)[0] = skb->len; memcpy(pegasus->tx_buff+2, skb->data, skb->len); - (&pegasus->tx_urb)->transfer_buffer_length = count; + pegasus->tx_urb.transfer_buffer_length = count; + pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; if ((res = usb_submit_urb(&pegasus->tx_urb))) { warn("failed tx_urb %d", res); @@ -477,8 +539,6 @@ dev_kfree_skb(skb); - spin_unlock(&pegasus->pegasus_lock); - return 0; } @@ -489,6 +549,15 @@ } +static inline void pegasus_stop_net( struct pegasus *pegasus ) +{ + int tmp; + + pegasus_get_registers( pegasus, EthCtrl0, 1, &tmp ); + pegasus_set_register( pegasus, EthCtrl0, tmp & 0x3f ); +} + + static int pegasus_open(struct net_device *net) { struct pegasus *pegasus = (struct pegasus *)net->priv; @@ -506,8 +575,7 @@ warn("(open)failed intr_urb %d", res); netif_start_queue(net); - - MOD_INC_USE_COUNT; + pegasus->flags |= PEGASUS_RUNNING; return 0; } @@ -517,18 +585,15 @@ { struct pegasus *pegasus = net->priv; + pegasus->flags &= ~PEGASUS_RUNNING; + pegasus_stop_net( pegasus ); + netif_stop_queue(net); - if ( pegasus->ctrl_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->ctrl_urb); - if ( pegasus->rx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->rx_urb); - if ( pegasus->tx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->tx_urb); - if ( pegasus->intr_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->intr_urb); - - MOD_DEC_USE_COUNT; + usb_unlink_urb(&pegasus->rx_urb); + usb_unlink_urb(&pegasus->tx_urb); + usb_unlink_urb(&pegasus->intr_urb); + pegasus_unlink_ctrl_urbs( pegasus ); return 0; } @@ -558,24 +623,32 @@ static void pegasus_set_rx_mode(struct net_device *net) { +#ifndef PEGASUS_USE_WAITQ struct pegasus *pegasus = net->priv; __u8 tmp; +#endif netif_stop_queue(net); if (net->flags & IFF_PROMISC) { - info("%s: Promiscuous mode enabled", net->name); +#ifndef PEGASUS_USE_WAITQ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); - pegasus_set_register(pegasus, EthCtrl2, tmp | 4); + pegasus_set_register(pegasus, EthCtrl2, tmp | 4); +#endif + info("%s: Promiscuous mode enabled", net->name); } else if ((net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI)) { +#ifndef PEGASUS_USE_WAITQ pegasus_set_register(pegasus, EthCtrl0, 0xfa); pegasus_set_register(pegasus, EthCtrl2, 0); +#endif info("%s set allmulti", net->name); } else { - info("%s: set Rx mode", net->name); +#ifndef PEGASUS_USE_WAITQ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); - pegasus_set_register(pegasus, EthCtrl2, tmp & ~4); + pegasus_set_register(pegasus, EthCtrl2, tmp & ~4); +#endif + info("%s: set Rx mode", net->name); } netif_wake_queue(net); @@ -629,27 +702,32 @@ net->get_stats = pegasus_netdev_stats; net->mtu = PEGASUS_MTU; + init_MUTEX( &pegasus-> ctrl_sem ); + init_waitqueue_head( &pegasus->ctrl_wait ); + pegasus->usb = dev; pegasus->net = net; - pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED; - pegasus->ctrl_lock = SPIN_LOCK_UNLOCKED; - FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1), - pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk, - pegasus); - FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2), - pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk, - pegasus); - FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), - pegasus->intr_buff, 8, pegasus_irq, pegasus, 500); + FILL_BULK_URB( &pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1), + pegasus->rx_buff, PEGASUS_MAX_MTU, + pegasus_read_bulk_callback, pegasus ); + FILL_BULK_URB( &pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2), + pegasus->tx_buff, PEGASUS_MAX_MTU, + pegasus_write_bulk_callback, pegasus ); + FILL_INT_URB( &pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), + pegasus->intr_buff, 8, pegasus_irq_callback, + pegasus, 128 ); if (pegasus_reset_mac(pegasus)) { err("can't reset MAC"); kfree(pegasus); + pegasus = NULL; return NULL; } - printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name); + info( "%s: %s\n", net->name, usb_dev_id[dev_indx].name ); + + MOD_INC_USE_COUNT; return pegasus; } @@ -664,21 +742,18 @@ return; } - if (pegasus->net->flags & IFF_UP) - dev_close(pegasus->net); - + pegasus->flags &= ~PEGASUS_RUNNING; unregister_netdev(pegasus->net); - - if ( pegasus->ctrl_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->ctrl_urb); - if ( pegasus->rx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->rx_urb); - if ( pegasus->tx_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->tx_urb); - if ( pegasus->intr_urb.status == -EINPROGRESS ) - usb_unlink_urb(&pegasus->intr_urb); + + usb_unlink_urb(&pegasus->rx_urb); + usb_unlink_urb(&pegasus->tx_urb); + usb_unlink_urb(&pegasus->intr_urb); + pegasus_unlink_ctrl_urbs( pegasus ); kfree(pegasus); + pegasus = NULL; + + MOD_DEC_USE_COUNT; } @@ -690,7 +765,7 @@ int __init pegasus_init(void) { - printk( version ); + info( "%s", version ); return usb_register(&pegasus_driver); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.4.0-test6/linux/drivers/usb/printer.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/printer.c Tue Aug 22 11:50:20 2000 @@ -1,10 +1,10 @@ /* - * printer.c Version 0.5 + * printer.c Version 0.6 * * Copyright (c) 1999 Michael Gee * Copyright (c) 1999 Pavel Machek - * Copyright (c) 2000 Vojtech Pavlik * Copyright (c) 2000 Randy Dunlap + * Copyright (c) 2000 Vojtech Pavlik * * USB Printer Device Class driver for USB printers and printer cables * @@ -16,6 +16,7 @@ * v0.3 - cleaner again, waitqueue fixes * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support + * v0.6 - never time out */ /* @@ -71,7 +72,7 @@ #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (60*60*HZ) /* 60 minutes */ +#define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */ struct usblp { struct usb_device *dev; /* USB device */ @@ -83,10 +84,10 @@ unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ - /* first 2 bytes are (big-endian) length */ + /* first 2 bytes are (big-endian) length */ }; -static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ }; +static struct usblp *usblp_table[USBLP_MINORS]; /* * Functions for usblp control messages. @@ -121,7 +122,8 @@ return; if (urb->status) - warn("nonzero read/write bulk status received: %d", urb->status); + warn("usblp%d: nonzero read/write bulk status received: %d", + usblp->minor, urb->status); wake_up_interruptible(&usblp->wait); } @@ -130,29 +132,27 @@ * Get and print printer errors. */ -static int usblp_check_status(struct usblp *usblp) +static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; + +static int usblp_check_status(struct usblp *usblp, int err) { - unsigned char status; + unsigned char status, newerr = 0; if (usblp_read_status(usblp, &status)) { - err("failed reading usblp status"); - return -EIO; + err("usblp%d: failed reading printer status", usblp->minor); + return 0; } if (~status & LP_PERRORP) { - if (status & LP_POUTPA) { - info("usblp%d: out of paper", usblp->minor); - return -ENOSPC; - } - if (~status & LP_PSELECD) { - info("usblp%d: off-line", usblp->minor); - return -EIO; - } - info("usblp%d: on fire", usblp->minor); - return -EIO; + newerr = 3; + if (status & LP_POUTPA) newerr = 1; + if (~status & LP_PSELECD) newerr = 2; } - return 0; + if (newerr != err) + info("usblp%d: %s", usblp->minor, usblp_messages[newerr]); + + return newerr; } /* @@ -179,8 +179,10 @@ if (usblp->used) goto out; - if ((retval = usblp_check_status(usblp))) + if ((retval = usblp_check_status(usblp, 0))) { + retval = retval > 1 ? -EIO : -ENOSPC; goto out; + } usblp->used = 1; file->private_data = usblp; @@ -228,27 +230,30 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int length; struct usblp *usblp = file->private_data; + int length; if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ)) return -EINVAL; switch (_IOC_NR(cmd)) { - case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ -#if 0 - dbg ("usblp_ioctl GET_DEVICE_ID: actlen=%d, user size=%d, string='%s'", - length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); -#endif - if (length > _IOC_SIZE(cmd)) - length = _IOC_SIZE(cmd); /* truncate */ - if (copy_to_user ((unsigned char *)arg, usblp->device_id_string, (unsigned long) length)) - return -EFAULT; - break; - default: - return -EINVAL; + case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ + + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ + + dbg ("usblp_ioctl GET_DEVICE_ID actlen: %d, size: %d, string: '%s'", + length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + + if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ + + if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length)) + return -EFAULT; + + break; + + default: + return -EINVAL; } return 0; @@ -257,7 +262,7 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - int retval, timeout, writecount = 0; + int timeout, err = 0, writecount = 0; while (writecount < count) { @@ -276,28 +281,17 @@ } } - if (usblp->writeurb.status == -EINPROGRESS) { - usb_unlink_urb(&usblp->writeurb); - err("usblp%d: timed out", usblp->minor); - return -EIO; - } - if (!usblp->dev) return -ENODEV; - if (!usblp->writeurb.status) { - writecount += usblp->writeurb.transfer_buffer_length; - usblp->writeurb.transfer_buffer_length = 0; - } else { - if (!(retval = usblp_check_status(usblp))) { - err("usblp%d: error %d writing to printer (retval=%d)", - usblp->minor, usblp->writeurb.status, retval); - return -EIO; - } - - return retval; + if (usblp->writeurb.status) { + err = usblp_check_status(usblp, err); + continue; } + writecount += usblp->writeurb.transfer_buffer_length; + usblp->writeurb.transfer_buffer_length = 0; + if (writecount == count) continue; @@ -368,14 +362,14 @@ interface = &dev->actconfig->interface[ifnum].altsetting[i]; if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 || - (interface->bInterfaceProtocol != 1 && interface->bInterfaceProtocol != 2) || - (interface->bInterfaceProtocol > interface->bNumEndpoints)) + interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 || + (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2)) continue; if (alts == -1) alts = i; - if (!bidir && interface->bInterfaceProtocol == 2) { + if (!bidir && interface->bInterfaceProtocol > 1) { bidir = 1; alts = i; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c --- v2.4.0-test6/linux/drivers/usb/serial/digi_acceleport.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/serial/digi_acceleport.c Sun Aug 13 19:23:19 2000 @@ -14,6 +14,58 @@ * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) * +* (8/8/2000) pberger and borchers +* -- Fixed close so that +* - it can timeout while waiting for transmit idle, if needed; +* - it ignores interrupts when flushing the port, turning +* of modem signalling, and so on; +* - it waits for the flush to really complete before returning. +* -- Read_bulk_callback and write_bulk_callback check for a closed +* port before using the tty struct or writing to the port. +* -- The two changes above fix the oops caused by interrupted closes. +* -- Added interruptible args to write_oob_command and set_modem_signals +* and added a timeout arg to transmit_idle; needed for fixes to +* close. +* -- Added code for rx_throttle and rx_unthrottle so that input flow +* control works. +* -- Added code to set overrun, parity, framing, and break errors +* (untested). +* -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length +* bulk writes are done. These hung the Digi USB device. The +* 0 length bulk writes were a new feature of usb-uhci added in +* the 2.4.0-test6 kernels. +* -- Fixed mod inc race in open; do mod inc before sleeping to wait +* for a close to finish. +* +* (7/31/2000) pberger +* -- Fixed bugs with hardware handshaking: +* - Added code to set/clear tty->hw_stopped in digi_read_oob_callback() +* and digi_set_termios() +* -- Added code in digi_set_termios() to +* - add conditional in code handling transition from B0 to only +* set RTS if RTS/CTS flow control is either not in use or if +* the port is not currently throttled. +* - handle turning off CRTSCTS. +* +* (7/30/2000) borchers +* -- Added support for more than one Digi USB device by moving +* globals to a private structure in the pointed to from the +* usb_serial structure. +* -- Moved the modem change and transmit idle wait queues into +* the port private structure, so each port has its own queue +* rather than sharing global queues. +* -- Added support for break signals. +* +* (7/25/2000) pberger +* -- Added USB-2 support. Note: the USB-2 supports 3 devices: two +* serial and a parallel port. The parallel port is implemented +* as a serial-to-parallel converter. That is, the driver actually +* presents all three USB-2 interfaces as serial ports, but the third +* one physically connects to a parallel device. Thus, for example, +* one could plug a parallel printer into the USB-2's third port, +* but from the kernel's (and userland's) point of view what's +* actually out there is a serial device. +* * (7/15/2000) borchers * -- Fixed race in open when a close is in progress. * -- Keep count of opens and dec the module use count for each @@ -24,8 +76,8 @@ * callbacks, and no longer restart read chains if there is * a status error or a sanity error. This fixed the seg * faults and other errors we used to get on disconnect. -* -- Port->active is once again a flag, not a count, as it was -* intended by usb-serial. Since it was only a char it would +* -- Port->active is once again a flag as usb-serial intended it +* to be, not a count. Since it was only a char it would * have been limited to 256 simultaneous opens. Now the open * count is kept in the port private structure in dp_open_count. * -- Added code for modularization of the digi_acceleport driver. @@ -51,7 +103,7 @@ * * (6/4/2000) pberger and borchers * -- Replaced separate calls to spin_unlock_irqrestore and -* interruptible_sleep_on_interruptible with a new function +* interruptible_sleep_on_timeout with a new function * cond_wait_interruptible_timeout_irqrestore. This eliminates * the race condition where the wake up could happen after * the unlock and before the sleep. @@ -157,7 +209,7 @@ * - Following Documentation/DocBook/kernel-locking.pdf no spin locks * are held when calling copy_to/from_user or printk. * -* $Id: digi_acceleport.c,v 1.5 2000/07/18 04:52:43 root Exp $ +* $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $ */ #include @@ -188,9 +240,13 @@ /* Defines */ -/* port buffer length -- must be <= transfer buffer length - 2 */ +/* port output buffer length -- must be <= transfer buffer length - 2 */ /* so we can be sure to send the full buffer in one urb */ -#define DIGI_PORT_BUF_LEN 8 +#define DIGI_OUT_BUF_SIZE 8 + +/* port input buffer length -- must be >= transfer buffer length - 3 */ +/* so we can be sure to hold at least one full buffer from one urb */ +#define DIGI_IN_BUF_SIZE 64 /* retry timeout while sleeping */ #define DIGI_RETRY_TIMEOUT (HZ/10) @@ -205,7 +261,8 @@ /* ids */ #define DIGI_VENDOR_ID 0x05c5 -#define DIGI_ID 0x0004 +#define DIGI_2_ID 0x0002 /* USB-2 */ +#define DIGI_4_ID 0x0004 /* USB-4 */ /* commands * "INB": can be used on the in-band endpoint @@ -335,29 +392,45 @@ /* Structures */ -typedef struct digi_private { - int dp_port_num; +typedef struct digi_serial { + spinlock_t ds_serial_lock; + struct usb_serial_port *ds_oob_port; /* out-of-band port */ + int ds_oob_port_num; /* index of out-of-band port */ + int ds_device_started; +} digi_serial_t; + +typedef struct digi_port { spinlock_t dp_port_lock; - int dp_buf_len; - unsigned char dp_buf[DIGI_PORT_BUF_LEN]; + int dp_port_num; + int dp_out_buf_len; + unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE]; + int dp_in_buf_len; + unsigned char dp_in_buf[DIGI_IN_BUF_SIZE]; + unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE]; unsigned int dp_modem_signals; + wait_queue_head_t dp_modem_change_wait; int dp_open_count; /* inc on open, dec on close */ int dp_transmit_idle; + wait_queue_head_t dp_transmit_idle_wait; + int dp_throttled; + int dp_throttle_restart; + wait_queue_head_t dp_flush_wait; int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct tq_struct dp_wakeup_task; -} digi_private_t; +} digi_port_t; /* Local Function Declarations */ static void digi_wakeup_write( struct usb_serial_port *port ); static void digi_wakeup_write_lock( struct usb_serial_port *port ); -static int digi_write_oob_command( unsigned char *buf, int count ); +static int digi_write_oob_command( struct usb_serial_port *port, + unsigned char *buf, int count, int interruptible ); static int digi_write_inb_command( struct usb_serial_port *port, - unsigned char *buf, int count ) __attribute__((unused)); + unsigned char *buf, int count, unsigned long timeout ); static int digi_set_modem_signals( struct usb_serial_port *port, - unsigned int modem_signals ); + unsigned int modem_signals, int interruptible ); static int digi_transmit_idle( struct usb_serial_port *port, unsigned long timeout ); static void digi_rx_throttle (struct usb_serial_port *port); @@ -386,25 +459,40 @@ /* device info needed for the Digi serial converter */ static u16 digi_vendor_id = DIGI_VENDOR_ID; -static u16 digi_product_id = DIGI_ID; +static u16 digi_product_2_id = DIGI_2_ID; /* USB 2 */ +static u16 digi_product_4_id = DIGI_4_ID; /* USB 4 */ -/* out of band port */ -static int oob_port_num; /* index of out-of-band port */ -static struct usb_serial_port *oob_port; /* out-of-band port */ -static int device_startup = 0; - -spinlock_t startup_lock; /* used by startup_device */ - -static wait_queue_head_t modem_change_wait; -static wait_queue_head_t transmit_idle_wait; - - -/* Globals */ +static struct usb_serial_device_type digi_acceleport_2_device = { + name: "Digi USB", + idVendor: &digi_vendor_id, + idProduct: &digi_product_2_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 0, + num_bulk_in: 4, + num_bulk_out: 4, + num_ports: 3, + open: digi_open, + close: digi_close, + write: digi_write, + write_room: digi_write_room, + write_bulk_callback: digi_write_bulk_callback, + read_bulk_callback: digi_read_bulk_callback, + chars_in_buffer: digi_chars_in_buffer, + throttle: digi_rx_throttle, + unthrottle: digi_rx_unthrottle, + ioctl: digi_ioctl, + set_termios: digi_set_termios, + break_ctl: digi_break_ctl, + startup: digi_startup, + shutdown: digi_shutdown, +}; -struct usb_serial_device_type digi_acceleport_device = { +static struct usb_serial_device_type digi_acceleport_4_device = { name: "Digi USB", idVendor: &digi_vendor_id, - idProduct: &digi_product_id, + idProduct: &digi_product_4_id, needs_interrupt_in: DONT_CARE, needs_bulk_in: MUST_HAVE, needs_bulk_out: MUST_HAVE, @@ -479,7 +567,7 @@ { unsigned long flags; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -515,20 +603,23 @@ * Write commands on the out of band port. Commands are 4 * bytes each, multiple commands can be sent at once, and * no command will be split across USB packets. Returns 0 -* if successful, -EINTR if interrupted while sleeping, or -* a negative error returned by usb_submit_urb. +* if successful, -EINTR if interrupted while sleeping and +* the interruptible flag is true, or a negative error +* returned by usb_submit_urb. */ -static int digi_write_oob_command( unsigned char *buf, int count ) +static int digi_write_oob_command( struct usb_serial_port *port, + unsigned char *buf, int count, int interruptible ) { int ret = 0; int len; - digi_private_t *oob_priv = (digi_private_t *)(oob_port->private); + struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port; + digi_port_t *oob_priv = (digi_port_t *)oob_port->private; unsigned long flags = 0; -dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count ); +dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count ); spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); @@ -538,7 +629,7 @@ cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags ); - if( signal_pending(current) ) { + if( interruptible && signal_pending(current) ) { return( -EINTR ); } spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); @@ -562,8 +653,8 @@ spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); if( ret ) { - dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d", - ret ); + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d", + ret ); } return( ret ); @@ -576,17 +667,20 @@ * * Write commands on the given port. Commands are 4 * bytes each, multiple commands can be sent at once, and -* no command will be split across USB packets. Returns 0 -* if successful, or a negative error returned by digi_write. +* no command will be split across USB packets. If timeout +* is non-zero, write in band command will return after +* waiting unsuccessfully for the URB status to clear for +* timeout ticks. Returns 0 if successful, or a negative +* error returned by digi_write. */ static int digi_write_inb_command( struct usb_serial_port *port, - unsigned char *buf, int count ) + unsigned char *buf, int count, unsigned long timeout ) { int ret = 0; int len; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; @@ -594,11 +688,17 @@ dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num, count ); + if( timeout ) + timeout += jiffies; + else + timeout = ULONG_MAX; + spin_lock_irqsave( &priv->dp_port_lock, flags ); - while( count > 0 ) { + while( count > 0 && ret == 0 ) { - while( port->write_urb->status == -EINPROGRESS ) { + while( port->write_urb->status == -EINPROGRESS + && jiffies < timeout ) { cond_wait_interruptible_timeout_irqrestore( &port->write_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); @@ -611,25 +711,26 @@ /* len must be a multiple of 4 and small enough to */ /* guarantee the write will send buffered data first, */ /* so commands are in order with data and not split */ - len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len ); + len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len ); if( len > 4 ) len &= ~3; /* write any buffered data first */ - if( priv->dp_buf_len > 0 ) { + if( priv->dp_out_buf_len > 0 ) { data[0] = DIGI_CMD_SEND_DATA; - data[1] = priv->dp_buf_len; - memcpy( data+2, priv->dp_buf, priv->dp_buf_len ); - memcpy( data+2+priv->dp_buf_len, buf, len ); + data[1] = priv->dp_out_buf_len; + memcpy( data+2, priv->dp_out_buf, + priv->dp_out_buf_len ); + memcpy( data+2+priv->dp_out_buf_len, buf, len ); port->write_urb->transfer_buffer_length - = priv->dp_buf_len+2+len; + = priv->dp_out_buf_len+2+len; } else { memcpy( data, buf, len ); port->write_urb->transfer_buffer_length = len; } if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; count -= len; buf += len; } @@ -639,8 +740,8 @@ spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret ) { - dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d", - ret ); + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, priv->dp_port_num ); } return( ret ); @@ -659,13 +760,14 @@ */ static int digi_set_modem_signals( struct usb_serial_port *port, - unsigned int modem_signals ) + unsigned int modem_signals, int interruptible ) { int ret; + digi_port_t *port_priv = (digi_port_t *)port->private; + struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port; + digi_port_t *oob_priv = (digi_port_t *)oob_port->private; unsigned char *data = oob_port->write_urb->transfer_buffer; - digi_private_t *port_priv = (digi_private_t *)(port->private); - digi_private_t *oob_priv = (digi_private_t *)(oob_port->private); unsigned long flags = 0; @@ -680,7 +782,7 @@ cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags ); - if( signal_pending(current) ) { + if( interruptible && signal_pending(current) ) { return( -EINTR ); } spin_lock_irqsave( &oob_priv->dp_port_lock, flags ); @@ -711,7 +813,7 @@ spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags ); if( ret ) { - dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d", + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d", ret ); } @@ -738,7 +840,7 @@ int ret; unsigned char buf[2]; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned long flags = 0; @@ -749,16 +851,16 @@ buf[0] = DIGI_CMD_TRANSMIT_IDLE; buf[1] = 0; - if( (ret=digi_write_inb_command( port, buf, 2 )) != 0 ) - return( ret ); - timeout += jiffies; + if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 ) + return( ret ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); while( jiffies < timeout && !priv->dp_transmit_idle ) { cond_wait_interruptible_timeout_irqrestore( - &transmit_idle_wait, DIGI_RETRY_TIMEOUT, + &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); if( signal_pending(current) ) { return( -EINTR ); @@ -777,21 +879,18 @@ static void digi_rx_throttle( struct usb_serial_port *port ) { -#ifdef DEBUG - digi_private_t *priv = (digi_private_t *)(port->private); -#endif + unsigned long flags; + digi_port_t *priv = (digi_port_t *)(port->private); dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num ); - /* stop receiving characters. We just turn off the URB request, and - let chars pile up in the device. If we're doing hardware - flowcontrol, the device will signal the other end when its buffer - fills up. If we're doing XON/XOFF, this would be a good time to - send an XOFF, although it might make sense to foist that off - upon the device too. */ - - // usb_unlink_urb(port->interrupt_in_urb); + /* stop receiving characters by not resubmitting the read urb */ + spin_lock_irqsave( &priv->dp_port_lock, flags ); + priv->dp_throttled = 1; + priv->dp_throttle_restart = 0; + priv->dp_in_buf_len = 0; + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); } @@ -799,16 +898,43 @@ static void digi_rx_unthrottle( struct usb_serial_port *port ) { -#ifdef DEBUG - digi_private_t *priv = (digi_private_t *)(port->private); -#endif + int ret = 0; + int len; + unsigned long flags; + digi_port_t *priv = (digi_port_t *)(port->private); + struct tty_struct *tty = port->tty; dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); - /* just restart the receive interrupt URB */ - //if (usb_submit_urb(port->interrupt_in_urb)) - // dbg( "digi_rx_unthrottle: usb_submit_urb failed" ); + spin_lock_irqsave( &priv->dp_port_lock, flags ); + + /* send any buffered chars from throttle time on to tty subsystem */ + len = MIN( priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count ); + if( len > 0 ) { + memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len ); + memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len ); + tty->flip.char_buf_ptr += len; + tty->flip.flag_buf_ptr += len; + tty->flip.count += len; + tty_flip_buffer_push( tty ); + } + + /* restart read chain */ + if( priv->dp_throttle_restart ) + ret = usb_submit_urb( port->read_urb ); + + /* turn throttle off */ + priv->dp_throttled = 0; + priv->dp_in_buf_len = 0; + priv->dp_throttle_restart = 0; + + spin_unlock_irqrestore( &priv->dp_port_lock, flags ); + + if( ret ) { + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, priv->dp_port_num ); + } } @@ -817,12 +943,13 @@ struct termios *old_termios ) { - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned int iflag = port->tty->termios->c_iflag; unsigned int cflag = port->tty->termios->c_cflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int old_cflag = old_termios->c_cflag; unsigned char buf[32]; + unsigned int modem_signals; int arg,ret; int i = 0; @@ -837,13 +964,18 @@ /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag&CBAUD) == B0 ) { /* don't set RTS if using hardware flow control */ - /* and throttling input -- not implemented yet */ - digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS ); + /* and throttling input */ + modem_signals = TIOCM_DTR; + if( !(port->tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &port->tty->flags) ) { + modem_signals |= TIOCM_RTS; + } + digi_set_modem_signals( port, modem_signals, 1 ); } switch( (cflag&CBAUD) ) { /* drop DTR and RTS on transition to B0 */ - case B0: digi_set_modem_signals( port, 0 ); break; + case B0: digi_set_modem_signals( port, 0, 1 ); break; case B50: arg = DIGI_BAUD_50; break; case B75: arg = DIGI_BAUD_75; break; case B110: arg = DIGI_BAUD_110; break; @@ -947,10 +1079,20 @@ else arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF; - if( (cflag&CRTSCTS) ) + if( (cflag&CRTSCTS) ) { + arg |= DIGI_INPUT_FLOW_CONTROL_RTS; - else + + /* On USB-4 it is necessary to assert RTS prior */ + /* to selecting RTS input flow control. */ + buf[i++] = DIGI_CMD_SET_RTS_SIGNAL; + buf[i++] = priv->dp_port_num; + buf[i++] = DIGI_RTS_ACTIVE; + buf[i++] = 0; + + } else { arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS; + } buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; buf[i++] = priv->dp_port_num; @@ -960,8 +1102,8 @@ } /* set output flow control */ - /*if( (iflag&IXON) != (old_iflag&IXON) - || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) )*/ { + if( (iflag&IXON) != (old_iflag&IXON) + || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) { arg = 0; @@ -970,10 +1112,12 @@ else arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; - if( (cflag&CRTSCTS) ) + if( (cflag&CRTSCTS) ) { arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS; - else + } else { arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS; + port->tty->hw_stopped = 0; + } buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; buf[i++] = priv->dp_port_num; @@ -997,7 +1141,7 @@ } - if( (ret=digi_write_oob_command( buf, i )) != 0 ) + if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 ) dbg( "digi_set_termios: write oob failed, ret=%d", ret ); } @@ -1006,12 +1150,15 @@ static void digi_break_ctl( struct usb_serial_port *port, int break_state ) { -#ifdef DEBUG - digi_private_t *priv = (digi_private_t *)(port->private); -#endif + unsigned char buf[4]; + + buf[0] = DIGI_CMD_BREAK_CONTROL; + buf[1] = 2; /* length */ + buf[2] = break_state ? 1 : 0; + buf[3] = 0; /* pad */ -dbg( "digi_break_ctl: TOP: port=%d", priv->dp_port_num ); + digi_write_inb_command( port, buf, 4, 0 ); } @@ -1020,7 +1167,7 @@ unsigned int cmd, unsigned long arg ) { - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned int val; unsigned long flags = 0; @@ -1048,7 +1195,7 @@ else if( cmd == TIOCMBIC ) val = priv->dp_modem_signals & ~val; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); - return( digi_set_modem_signals( port, val ) ); + return( digi_set_modem_signals( port, val, 1 ) ); case TIOCMIWAIT: /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ @@ -1072,7 +1219,7 @@ { int ret,data_len,new_len; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned char *data = port->write_urb->transfer_buffer; unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */ unsigned long flags = 0; @@ -1098,9 +1245,10 @@ /* buffer data if count is 1 (probably put_char) if possible */ if( count == 1 ) { new_len = MIN( count, - DIGI_PORT_BUF_LEN-priv->dp_buf_len ); - memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len ); - priv->dp_buf_len += new_len; + DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len ); + memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf, + new_len ); + priv->dp_out_buf_len += new_len; } else { new_len = 0; } @@ -1113,8 +1261,8 @@ /* allow space for any buffered data and for new data, up to */ /* transfer buffer size - 2 (for command and length bytes) */ - new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len ); - data_len = new_len + priv->dp_buf_len; + new_len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len ); + data_len = new_len + priv->dp_out_buf_len; if( data_len == 0 ) { spin_unlock_irqrestore( &priv->dp_port_lock, flags ); @@ -1127,22 +1275,24 @@ *data++ = data_len; /* copy in buffered data first */ - memcpy( data, priv->dp_buf, priv->dp_buf_len ); - data += priv->dp_buf_len; + memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len ); + data += priv->dp_out_buf_len; /* copy in new data */ memcpy( data, from_user ? user_buf : buf, new_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { ret = new_len; - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; } /* return length of new data written, or error */ spin_unlock_irqrestore( &priv->dp_port_lock, flags ); if( ret < 0 ) { - dbg( "digi_write: usb_submit_urb failed, ret=%d", ret ); + err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, priv->dp_port_num ); } + dbg( "digi_write: returning %d", ret ); return( ret ); @@ -1154,21 +1304,27 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; - digi_private_t *priv; + digi_port_t *priv; int ret = 0; -dbg( "digi_write_bulk_callback: TOP" ); +dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); - /* port sanity check */ - if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) { + /* port and serial sanity check */ + if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) { err( __FUNCTION__ ": port or port->private is NULL, status=%d", urb->status ); return; } + serial = port->serial; + if( serial == NULL || serial->private == NULL ) { + err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status ); + return; + } /* handle oob callback */ - if( priv->dp_port_num == oob_port_num ) { + if( priv->dp_port_num + == ((digi_serial_t *)(serial->private))->ds_oob_port_num ) { dbg( "digi_write_bulk_callback: oob callback" ); spin_lock( &priv->dp_port_lock ); wake_up_interruptible( &port->write_wait ); @@ -1176,29 +1332,29 @@ return; } - /* sanity checks */ - if( port_paranoia_check( port, "digi_write_bulk_callback" ) ) - return; - serial = port->serial; - if( serial_paranoia_check( serial, "digi_write_bulk_callback" ) ) + /* further sanity checks */ + if( port_paranoia_check( port, __FUNCTION__ ) + || serial_paranoia_check( serial, __FUNCTION__ ) ) return; - /* try to send any buffered data on this port */ + /* try to send any buffered data on this port, if it is open */ spin_lock( &priv->dp_port_lock ); - if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) { + if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS + && priv->dp_out_buf_len > 0 ) { *((unsigned char *)(port->write_urb->transfer_buffer)) = (unsigned char)DIGI_CMD_SEND_DATA; *((unsigned char *)(port->write_urb->transfer_buffer)+1) - = (unsigned char)priv->dp_buf_len; + = (unsigned char)priv->dp_out_buf_len; - port->write_urb->transfer_buffer_length = priv->dp_buf_len+2; + port->write_urb->transfer_buffer_length + = priv->dp_out_buf_len+2; - memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf, - priv->dp_buf_len ); + memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf, + priv->dp_out_buf_len ); if( (ret=usb_submit_urb(port->write_urb)) == 0 ) { - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; } } @@ -1224,7 +1380,7 @@ { int room; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); unsigned long flags = 0; @@ -1233,7 +1389,7 @@ if( port->write_urb->status == -EINPROGRESS ) room = 0; else - room = port->bulk_out_size - 2 - priv->dp_buf_len; + room = port->bulk_out_size - 2 - priv->dp_out_buf_len; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); @@ -1246,7 +1402,7 @@ static int digi_chars_in_buffer( struct usb_serial_port *port ) { - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); if( port->write_urb->status == -EINPROGRESS ) { @@ -1254,8 +1410,8 @@ /* return( port->bulk_out_size - 2 ); */ return( 256 ); } else { -dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_buf_len ); - return( priv->dp_buf_len ); +dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len ); + return( priv->dp_out_buf_len ); } } @@ -1266,7 +1422,7 @@ int ret; unsigned char buf[32]; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); struct termios not_termios; unsigned long flags = 0; @@ -1285,12 +1441,18 @@ return( -EAGAIN ); } + /* inc module use count before sleeping to wait for closes */ + ++priv->dp_open_count; + MOD_INC_USE_COUNT; + /* wait for a close in progress to finish */ while( priv->dp_in_close ) { cond_wait_interruptible_timeout_irqrestore( &priv->dp_close_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags ); if( signal_pending(current) ) { + --priv->dp_open_count; + MOD_DEC_USE_COUNT; return( -EINTR ); } spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -1299,16 +1461,12 @@ /* if port is already open, just return */ /* be sure exactly one open proceeds */ if( port->active ) { - ++priv->dp_open_count; - MOD_INC_USE_COUNT; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return( 0 ); } - /* open is certain */ + /* first open, mark port as active */ port->active = 1; - ++priv->dp_open_count; - MOD_INC_USE_COUNT; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); /* read modem signals automatically whenever they change */ @@ -1323,7 +1481,7 @@ buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; buf[7] = 0; - if( (ret=digi_write_oob_command( buf, 8 )) != 0 ) + if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 ) dbg( "digi_open: write oob failed, ret=%d", ret ); /* set termios settings */ @@ -1332,7 +1490,7 @@ digi_set_termios( port, ¬_termios ); /* set DTR and RTS */ - digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS ); + digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 ); return( 0 ); @@ -1345,7 +1503,7 @@ int ret; unsigned char buf[32]; struct tty_struct *tty = port->tty; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)port->private; unsigned long flags = 0; @@ -1386,7 +1544,7 @@ } /* drop DTR and RTS */ - digi_set_modem_signals( port, 0 ); + digi_set_modem_signals( port, 0, 0 ); /* disable input flow control */ buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; @@ -1406,29 +1564,24 @@ buf[10] = DIGI_DISABLE; buf[11] = 0; - /* flush fifos */ - buf[12] = DIGI_CMD_IFLUSH_FIFO; + /* disable receive */ + buf[12] = DIGI_CMD_RECEIVE_ENABLE; buf[13] = priv->dp_port_num; - buf[14] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[14] = DIGI_DISABLE; buf[15] = 0; - /* disable receive */ - buf[16] = DIGI_CMD_RECEIVE_ENABLE; + /* flush fifos */ + buf[16] = DIGI_CMD_IFLUSH_FIFO; buf[17] = priv->dp_port_num; - buf[18] = DIGI_DISABLE; + buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; buf[19] = 0; - if( (ret=digi_write_oob_command( buf, 20 )) != 0 ) + if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 ) dbg( "digi_close: write oob failed, ret=%d", ret ); /* wait for final commands on oob port to complete */ - while( oob_port->write_urb->status == -EINPROGRESS ) { - interruptible_sleep_on_timeout( &oob_port->write_wait, - DIGI_RETRY_TIMEOUT ); - if( signal_pending(current) ) { - break; - } - } + interruptible_sleep_on_timeout( &priv->dp_flush_wait, + DIGI_CLOSE_TIMEOUT ); /* shutdown any outstanding bulk writes */ usb_unlink_urb (port->write_urb); @@ -1458,23 +1611,31 @@ { int i,ret = 0; + digi_serial_t *serial_priv = (digi_serial_t *)serial->private; + struct usb_serial_port *port; /* be sure this happens exactly once */ - spin_lock( &startup_lock ); - if( device_startup ) { - spin_unlock( &startup_lock ); + spin_lock( &serial_priv->ds_serial_lock ); + if( serial_priv->ds_device_started ) { + spin_unlock( &serial_priv->ds_serial_lock ); return( 0 ); } - device_startup = 1; - spin_unlock( &startup_lock ); + serial_priv->ds_device_started = 1; + spin_unlock( &serial_priv->ds_serial_lock ); /* start reading from each bulk in endpoint for the device */ - for( i=0; itype->num_ports+1; i++ ) { + + port = &serial->port[i]; - if( (ret=usb_submit_urb(serial->port[i].read_urb)) != 0 ) { - dbg( "digi_startup_device: usb_submit_urb failed, port=%d, ret=%d", - i, ret ); + port->write_urb->transfer_flags |= USB_DISABLE_SPD; + + if( (ret=usb_submit_urb(port->read_urb)) != 0 ) { + err( + __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", + ret, i ); break; } @@ -1489,51 +1650,68 @@ { int i; - digi_private_t *priv; + digi_port_t *priv; + digi_serial_t *serial_priv; dbg( "digi_startup: TOP" ); - spin_lock_init( &startup_lock ); - init_waitqueue_head( &modem_change_wait ); - init_waitqueue_head( &transmit_idle_wait ); - /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ - for( i=0; itype->num_ports+1; i++ ) { serial->port[i].active = 0; - /* allocate private structure */ + /* allocate port private structure */ priv = serial->port[i].private = - (digi_private_t *)kmalloc( sizeof(digi_private_t), + (digi_port_t *)kmalloc( sizeof(digi_port_t), GFP_KERNEL ); - if( priv == (digi_private_t *)0 ) + if( priv == (digi_port_t *)0 ) { + while( --i >= 0 ) + kfree( serial->port[i].private ); return( 1 ); /* error */ + } - /* initialize private structure */ + /* initialize port private structure */ + spin_lock_init( &priv->dp_port_lock ); priv->dp_port_num = i; - priv->dp_buf_len = 0; + priv->dp_out_buf_len = 0; + priv->dp_in_buf_len = 0; priv->dp_modem_signals = 0; + init_waitqueue_head( &priv->dp_modem_change_wait ); priv->dp_open_count = 0; priv->dp_transmit_idle = 0; + init_waitqueue_head( &priv->dp_transmit_idle_wait ); + priv->dp_throttled = 0; + priv->dp_throttle_restart = 0; + init_waitqueue_head( &priv->dp_flush_wait ); priv->dp_in_close = 0; init_waitqueue_head( &priv->dp_close_wait ); priv->dp_wakeup_task.next = NULL; priv->dp_wakeup_task.sync = 0; priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock; priv->dp_wakeup_task.data = (void *)(&serial->port[i]); - spin_lock_init( &priv->dp_port_lock ); /* initialize write wait queue for this port */ - init_waitqueue_head(&serial->port[i].write_wait); + init_waitqueue_head( &serial->port[i].write_wait ); } - /* initialize out of band port info */ - oob_port_num = digi_acceleport_device.num_ports; - oob_port = &serial->port[oob_port_num]; - device_startup = 0; + /* allocate serial private structure */ + serial_priv = serial->private = + (digi_serial_t *)kmalloc( sizeof(digi_serial_t), + GFP_KERNEL ); + if( serial_priv == (digi_serial_t *)0 ) { + for( i=0; itype->num_ports+1; i++ ) + kfree( serial->port[i].private ); + return( 1 ); /* error */ + } + + /* initialize serial private structure */ + spin_lock_init( &serial_priv->ds_serial_lock ); + serial_priv->ds_oob_port_num = serial->type->num_ports; + serial_priv->ds_oob_port = &serial->port[serial_priv->ds_oob_port_num]; + serial_priv->ds_device_started = 0; return( 0 ); @@ -1544,22 +1722,20 @@ { int i; - digi_private_t *priv; + digi_port_t *priv; unsigned long flags; dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() ); /* stop reads and writes on all ports */ - for( i=0; itype->num_ports+1; i++ ) { usb_unlink_urb( serial->port[i].read_urb ); usb_unlink_urb( serial->port[i].write_urb ); } - device_startup = 0; - /* dec module use count */ - for( i=0; itype->num_ports; i++ ) { priv = serial->port[i].private; spin_lock_irqsave( &priv->dp_port_lock, flags ); while( priv->dp_open_count > 0 ) { @@ -1571,8 +1747,9 @@ /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ - for( i=0; itype->num_ports+1; i++ ) kfree( serial->port[i].private ); + kfree( serial->private ); } @@ -1581,18 +1758,24 @@ { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - digi_private_t *priv; + digi_port_t *priv; int ret; dbg( "digi_read_bulk_callback: TOP" ); /* port sanity check, do not resubmit if port is not valid */ - if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) { + if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) { err( __FUNCTION__ ": port or port->private is NULL, status=%d", urb->status ); return; } + if( port->serial == NULL + || serial_paranoia_check( port->serial, __FUNCTION__ ) + || port->serial->private == NULL ) { + err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status ); + return; + } /* do not resubmit urb if it has any status error */ if( urb->status ) { @@ -1601,7 +1784,8 @@ } /* handle oob or inb callback, do not resubmit if error */ - if( priv->dp_port_num == oob_port_num ) { + if( priv->dp_port_num + == ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) { if( digi_read_oob_callback( urb ) != 0 ) return; } else { @@ -1623,45 +1807,110 @@ * * Digi Read INB Callback handles reads on the in band ports, sending * the data on to the tty subsystem. When called we know port and -* port->private are not NULL. It returns 0 if successful, and -1 if -* the sanity checks failed. +* port->private are not NULL and port->serial has been validated. +* It returns 0 if successful, 1 if successful but the port is +* throttled, and -1 if the sanity checks failed. */ static int digi_read_inb_callback( struct urb *urb ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = port->serial; struct tty_struct *tty = port->tty; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; int status = ((unsigned char *)urb->transfer_buffer)[2]; unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3; - int i; + int flag,throttled; - /* sanity checks */ - if( port_paranoia_check( port, __FUNCTION__ ) - || serial_paranoia_check( serial, __FUNCTION__ ) ) + /* sanity check */ + if( port_paranoia_check( port, __FUNCTION__ ) ) return( -1 ); - /* short packet check */ + /* do not process callbacks on closed ports */ + /* but do continue the read chain */ + if( priv->dp_open_count == 0 ) + return( 0 ); + + /* short/multiple packet check */ if( urb->actual_length != len + 2 ) { - err( __FUNCTION__ ": INCOMPLETE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); + err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); return( -1 ); } + spin_lock( &priv->dp_port_lock ); + + /* check for throttle; if set, do not resubmit read urb */ + /* indicate the read chain needs to be restarted on unthrottle */ + throttled = priv->dp_throttled; + if( throttled ) + priv->dp_throttle_restart = 1; + /* receive data */ - if( opcode == DIGI_CMD_RECEIVE_DATA && urb->actual_length > 3 ) { - len = MIN( len, urb->actual_length-3 ); - for( i=0; idp_in_buf_len ); + + if( len > 0 ) { + memcpy( priv->dp_in_buf + priv->dp_in_buf_len, + data, len ); + memset( priv->dp_in_flag_buf + + priv->dp_in_buf_len, flag, len ); + priv->dp_in_buf_len += len; + } + + } else { + + len = MIN( len, TTY_FLIPBUF_SIZE - tty->flip.count ); + + if( len > 0 ) { + memcpy( tty->flip.char_buf_ptr, data, len ); + memset( tty->flip.flag_buf_ptr, flag, len ); + tty->flip.char_buf_ptr += len; + tty->flip.flag_buf_ptr += len; + tty->flip.count += len; + tty_flip_buffer_push( tty ); + } + + } + } - return( 0 ); + spin_unlock( &priv->dp_port_lock ); + + if( opcode == DIGI_CMD_RECEIVE_DISABLE ) { + dbg( __FUNCTION__ ": got RECEIVE_DISABLE" ); + } else if( opcode != DIGI_CMD_RECEIVE_DATA ) { + dbg( __FUNCTION__ ": unknown opcode: %d", opcode ); + } + + return( throttled ? 1 : 0 ); } @@ -1670,8 +1919,9 @@ * Digi Read OOB Callback * * Digi Read OOB Callback handles reads on the out of band port. -* When called we know port and port->private are not NULL. It -* returns 0 if successful, and -1 if the sanity checks failed. +* When called we know port and port->private are not NULL and +* the port->serial is valid. It returns 0 if successful, and +* -1 if the sanity checks failed. */ static int digi_read_oob_callback( struct urb *urb ) @@ -1679,19 +1929,13 @@ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; - digi_private_t *priv = (digi_private_t *)(port->private); + digi_port_t *priv = (digi_port_t *)(port->private); int opcode, line, status, val; int i; -dbg( "digi_read_oob_callback: len=%d", urb->actual_length ); - - /* sanity check */ - if( serial == NULL ) { - err( __FUNCTION__ ": port->serial is NULL, status=%d, port=%d", - urb->status, priv->dp_port_num ); - return( -1 ); - } +dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num, +urb->actual_length ); /* handle each oob command */ for( i=0; iactual_length-3; ) { @@ -1701,25 +1945,39 @@ status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++]; -dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val ); +dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", +opcode, line, status, val ); - if( status != 0 ) + if( status != 0 || line >= serial->type->num_ports ) continue; - if( (priv=serial->port[line].private) == NULL ) { - dbg( __FUNCTION__ ": port[%d].private is NULL!", line ); - continue; - } + port = &serial->port[line]; + + if( port_paranoia_check( port, __FUNCTION__ ) + || (priv=port->private) == NULL ) + return( -1 ); if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) { spin_lock( &priv->dp_port_lock ); /* convert from digi flags to termiox flags */ - if( val & DIGI_READ_INPUT_SIGNALS_CTS ) + if( val & DIGI_READ_INPUT_SIGNALS_CTS ) { priv->dp_modem_signals |= TIOCM_CTS; - else + /* port must be open to use tty struct */ + if( priv->dp_open_count + && port->tty->termios->c_cflag & CRTSCTS ) { + port->tty->hw_stopped = 0; + digi_wakeup_write( port ); + } + } else { priv->dp_modem_signals &= ~TIOCM_CTS; + /* port must be open to use tty struct */ + if( priv->dp_open_count + && port->tty->termios->c_cflag & CRTSCTS ) { + port->tty->hw_stopped = 1; + } + } if( val & DIGI_READ_INPUT_SIGNALS_DSR ) priv->dp_modem_signals |= TIOCM_DSR; else @@ -1733,16 +1991,20 @@ else priv->dp_modem_signals &= ~TIOCM_CD; - wake_up_interruptible( &modem_change_wait ); + wake_up_interruptible( &priv->dp_modem_change_wait ); spin_unlock( &priv->dp_port_lock ); } else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) { spin_lock( &priv->dp_port_lock ); priv->dp_transmit_idle = 1; - wake_up_interruptible( &transmit_idle_wait ); + wake_up_interruptible( &priv->dp_transmit_idle_wait ); spin_unlock( &priv->dp_port_lock ); + } else if( opcode == DIGI_CMD_IFLUSH_FIFO ) { + + wake_up_interruptible( &priv->dp_flush_wait ); + } } @@ -1754,19 +2016,22 @@ int digi_init (void) { - usb_serial_register (&digi_acceleport_device); + usb_serial_register (&digi_acceleport_2_device); + usb_serial_register (&digi_acceleport_4_device); return 0; } void digi_exit (void) { - usb_serial_deregister (&digi_acceleport_device); + usb_serial_deregister (&digi_acceleport_2_device); + usb_serial_deregister (&digi_acceleport_4_device); } module_init(digi_init); module_exit(digi_exit); + MODULE_AUTHOR("Peter Berger , Al Borchers "); MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c --- v2.4.0-test6/linux/drivers/usb/serial/keyspan_pda.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/serial/keyspan_pda.c Tue Aug 22 09:06:31 2000 @@ -1,8 +1,9 @@ /* * USB Keyspan PDA Converter driver * - * Copyright (C) 1999, 2000 - * Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 1999, 2000 Greg Kroah-Hartman + * Copyright (c) 1999, 2000 Brian Warner + * Copyright (c) 2000 Al Borchers * * 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 @@ -11,6 +12,24 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (07/20/2000) borchers + * - keyspan_pda_write no longer sleeps if it is called on interrupt time; + * PPP and the line discipline with stty echo on can call write on + * interrupt time and this would cause an oops if write slept + * - if keyspan_pda_write is in an interrupt, it will not call + * usb_control_msg (which sleeps) to query the room in the device + * buffer, it simply uses the current room value it has + * - if the urb is busy or if it is throttled keyspan_pda_write just + * returns 0, rather than sleeping to wait for this to change; the + * write_chan code in n_tty.c will sleep if needed before calling + * keyspan_pda_write again + * - if the device needs to be unthrottled, write now queues up the + * call to usb_control_msg (which sleeps) to unthrottle the device + * - the wakeups from keyspan_pda_write_bulk_callback are queued rather + * than done directly from the callback to avoid the race in write_chan + * - keyspan_pda_chars_in_buffer also indicates its buffer is full if the + * urb status is -EINPROGRESS, meaning it cannot write at the moment + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -35,6 +54,7 @@ #include #include #include +#include #ifdef CONFIG_USB_SERIAL_DEBUG #define DEBUG @@ -56,6 +76,8 @@ struct keyspan_pda_private { int tx_room; int tx_throttled; + struct tq_struct wakeup_task; + struct tq_struct unthrottle_task; }; #define KEYSPAN_VENDOR_ID 0x06cd @@ -69,6 +91,45 @@ +static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) +{ + + struct tty_struct *tty = port->tty; + + /* wake up port processes */ + wake_up_interruptible( &port->write_wait ); + + /* wake up line discipline */ + if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup ) + (tty->ldisc.write_wakeup)(tty); + + /* wake up other tty processes */ + wake_up_interruptible( &tty->write_wait ); + /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ + +} + +static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) +{ + + dbg(" request_unthrottle"); + /* ask the device to tell us when the tx buffer becomes + sufficiently empty */ + usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + 7, /* request_unthrottle */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_OUT, + 16, /* value: threshold */ + 0, /* index */ + NULL, + 0, + 2*HZ); + +} + + static void keyspan_pda_rx_interrupt (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -113,8 +174,8 @@ case 2: /* tx unthrottle interrupt */ tty = serial->port[0].tty; priv->tx_throttled = 0; - wake_up(&port->write_wait); /* wake up writer */ - wake_up(&tty->write_wait); /* them too */ + /* queue up a wakeup at scheduler time */ + queue_task( &priv->wakeup_task, &tq_scheduler ); break; default: break; @@ -355,7 +416,6 @@ int request_unthrottle = 0; int rc = 0; struct keyspan_pda_private *priv; - DECLARE_WAITQUEUE(wait, current); priv = (struct keyspan_pda_private *)(port->private); /* guess how much room is left in the device's ring buffer, and if we @@ -376,53 +436,22 @@ the TX urb is in-flight (wait until it completes) the device is full (wait until it says there is room) */ - while (port->write_urb->status == -EINPROGRESS) { - if (0 /* file->f_flags & O_NONBLOCK */) { - rc = -EAGAIN; - goto err; - } - interruptible_sleep_on(&port->write_wait); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - goto err; - } + if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) { + return( 0 ); } - /* at this point the URB is in our control, nobody else can submit it + /* At this point the URB is in our control, nobody else can submit it again (the only sudden transition was the one from EINPROGRESS to - finished) */ - - /* the next potential block is that our TX process might be throttled. - The transition from throttled->not happens because of an Rx - interrupt, and the wake_up occurs during the same interrupt, so we - have to be careful to avoid a race that would cause us to sleep - forever. */ - - add_wait_queue(&port->write_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - while (priv->tx_throttled) { - /* device can't accomodate any more characters. Sleep until it - can. Woken up by an Rx interrupt message, which clears - tx_throttled first. */ - dbg(" tx_throttled, going to sleep"); - if (signal_pending(current)) { - current->state = TASK_RUNNING; - remove_wait_queue(&port->write_wait, &wait); - dbg(" woke up because of signal"); - rc = -ERESTARTSYS; - goto err; - } - schedule(); - dbg(" woke up"); - } - remove_wait_queue(&port->write_wait, &wait); - set_current_state(TASK_RUNNING); + finished). Also, the tx process is not throttled. So we are + ready to write. */ count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - if (count > priv->tx_room) { + + /* Check if we might overrun the Tx buffer. If so, ask the + device how much room it really has. This is done only on + scheduler time, since usb_control_msg() sleeps. */ + if (count > priv->tx_room && !in_interrupt()) { unsigned char room; - /* Looks like we might overrun the Tx buffer. Ask the device - how much room it really has */ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 6, /* write_room */ @@ -443,19 +472,20 @@ } dbg(" roomquery says %d", room); priv->tx_room = room; - if (count > priv->tx_room) { - /* we're about to completely fill the Tx buffer, so - we'll be throttled afterwards. */ - count = priv->tx_room; - request_unthrottle = 1; - } } - priv->tx_room -= count; + if (count > priv->tx_room) { + /* we're about to completely fill the Tx buffer, so + we'll be throttled afterwards. */ + count = priv->tx_room; + request_unthrottle = 1; + } if (count) { /* now transfer data */ if (from_user) { - copy_from_user(port->write_urb->transfer_buffer, buf, count); + if( copy_from_user(port->write_urb->transfer_buffer, + buf, count) ) + return( -EFAULT ); } else { memcpy (port->write_urb->transfer_buffer, buf, count); @@ -463,6 +493,8 @@ /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; + priv->tx_room -= count; + if (usb_submit_urb(port->write_urb)) dbg(" usb_submit_urb(write bulk) failed"); } @@ -473,25 +505,11 @@ } if (request_unthrottle) { - dbg(" request_unthrottle"); - /* ask the device to tell us when the tx buffer becomes - sufficiently empty */ priv->tx_throttled = 1; /* block writers */ - rc = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - 7, /* request_unthrottle */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_OUT, - 16, /* value: threshold */ - 0, /* index */ - NULL, - 0, - 2*HZ); + queue_task( &priv->unthrottle_task, &tq_scheduler ); } return (count); - err: - return (rc); } @@ -499,7 +517,9 @@ { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial; - struct tty_struct *tty; + struct keyspan_pda_private *priv; + + priv = (struct keyspan_pda_private *)(port->private); if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) { return; @@ -510,14 +530,9 @@ return; } - wake_up_interruptible(&port->write_wait); + /* queue up a wakeup at scheduler time */ + queue_task( &priv->wakeup_task, &tq_scheduler ); - tty = port->tty; - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); } @@ -541,7 +556,7 @@ /* when throttled, return at least WAKEUP_CHARS to tell select() (via n_tty.c:normal_poll() ) that we're not writeable. */ - if (priv->tx_throttled) + if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) return 256; return 0; } @@ -644,14 +659,25 @@ static int keyspan_pda_startup (struct usb_serial *serial) { + + struct keyspan_pda_private *priv; + /* allocate the private data structures for all ports. Well, for all one ports. */ - serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private), - GFP_KERNEL); - if (!serial->port[0].private) + priv = serial->port[0].private + = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); + if (!priv) return (1); /* error */ init_waitqueue_head(&serial->port[0].write_wait); + priv->wakeup_task.next = NULL; + priv->wakeup_task.sync = 0; + priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write; + priv->wakeup_task.data = (void *)(&serial->port[0]); + priv->unthrottle_task.next = NULL; + priv->unthrottle_task.sync = 0; + priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle; + priv->unthrottle_task.data = (void *)(serial); return (0); } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.4.0-test6/linux/drivers/usb/serial/usb-serial.h Thu Jul 27 17:38:01 2000 +++ linux/drivers/usb/serial/usb-serial.h Sun Aug 13 19:23:19 2000 @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/08/2000) gkh + * Added open_count to port structure. + * * (07/23/2000) gkh * Added bulk_out_endpointAddress to port structure. * @@ -59,6 +62,7 @@ wait_queue_head_t write_wait; struct tq_struct tqueue; /* task queue for line discipline waking up */ + int open_count; /* number of times this port has been opened */ void * private; /* data private to the specific port */ }; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.0-test6/linux/drivers/usb/serial/visor.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/serial/visor.c Sun Aug 13 19:23:19 2000 @@ -11,6 +11,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/08/2000) gkh + * Fixed endian problem in visor_startup. + * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + * than once. + * * (07/23/2000) gkh * Added pool of write urbs to speed up transfers to the visor. * @@ -71,6 +76,7 @@ static void visor_throttle (struct usb_serial_port *port); static void visor_unthrottle (struct usb_serial_port *port); static int visor_startup (struct usb_serial *serial); +static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); static void visor_write_bulk_callback (struct urb *urb); @@ -94,6 +100,7 @@ throttle: visor_throttle, unthrottle: visor_unthrottle, startup: visor_startup, + shutdown: visor_shutdown, ioctl: visor_ioctl, set_termios: visor_set_termios, write: visor_write, @@ -117,13 +124,18 @@ return -EINVAL; } - port->active = 1; - - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; - return (0); + /*Start reading from the device*/ + if (usb_submit_urb(port->read_urb)) + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + } + + return 0; } @@ -134,19 +146,24 @@ dbg(__FUNCTION__ " - port %d", port->number); - if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); - } else { - /* send a shutdown message to the device */ - usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, - 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); - kfree (transfer_buffer); - } + --port->open_count; + MOD_DEC_USE_COUNT; - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - port->active = 0; + if (port->open_count <= 0) { + if (!transfer_buffer) { + err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); + } else { + /* send a shutdown message to the device */ + usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, + 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); + kfree (transfer_buffer); + } + + /* shutdown our bulk read */ + usb_unlink_urb (port->read_urb); + port->active = 0; + port->open_count = 0; + } } @@ -282,6 +299,8 @@ } else { struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer; char *string; + + le16_to_cpus(&connection_info->num_ports); info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports); for (i = 0; i < connection_info->num_ports; ++i) { switch (connection_info->connections[i].port_function_id) { @@ -319,6 +338,21 @@ /* continue on with initialization */ return (0); +} + + +static void visor_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + visor_close (&serial->port[i], NULL); + } + } } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/Makefile linux/drivers/usb/storage/Makefile --- v2.4.0-test6/linux/drivers/usb/storage/Makefile Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/Makefile Tue Aug 22 09:06:31 2000 @@ -5,6 +5,7 @@ O_TARGET := usb-storage.o M_OBJS := usb-storage.o O_OBJS := scsiglue.o protocol.o transport.o usb.o +MOD_LIST_NAME := USB_STORAGE_MODULES CFLAGS_scsiglue.o:= -I../../scsi/ CFLAGS_protocol.o:= -I../../scsi/ @@ -13,6 +14,7 @@ CFLAGS_usb.o:= -I../../scsi/ CFLAGS_shuttle_usbat.o:= -I../../scsi/ CFLAGS_sddr09.o:= -I../../scsi/ +CFLAGS_dpcm.o:= -I../../scsi/ ifeq ($(CONFIG_USB_STORAGE_DEBUG),y) O_OBJS += debug.o @@ -36,6 +38,10 @@ ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y) O_OBJS += shuttle_cf.o +endif + +ifeq ($(CONFIG_USB_STORAGE_DPCM),y) + O_OBJS += dpcm.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/dpcm.c linux/drivers/usb/storage/dpcm.c --- v2.4.0-test6/linux/drivers/usb/storage/dpcm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/storage/dpcm.c Tue Aug 22 13:10:55 2000 @@ -0,0 +1,83 @@ +/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader + * + * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * + * DPCM driver v0.1: + * + * First release + * + * Current development and maintainance by: + * (c) 2000 Brian Webb (webbb@earthlink.net) + * + * This device contains both a CompactFlash card reader, which + * usest the Control/Bulk w/o Interrupt protocol and + * a SmartMedia card reader that uses the same protocol + * as the SDDR09. + * + * 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. + */ + +#include +#include "transport.h" +#include "protocol.h" +#include "usb.h" +#include "debug.h" +#include "dpcm.h" +#include "sddr09.h" + + +/* + * Transport for the Microtech DPCM-USB + * + */ +int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) +{ + int ret; + + if(srb == NULL) + return USB_STOR_TRANSPORT_ERROR; + + US_DEBUGP("dpcm_transport: LUN=%d\n", srb->lun); + + switch(srb->lun) { + case 0: + + /* + * LUN 0 corresponds to the CompactFlash card reader. + */ + return usb_stor_CB_transport(srb, us); + +#ifdef CONFIG_USB_STORAGE_SDDR09 + case 1: + + /* + * LUN 1 corresponds to the SmartMedia card reader. + */ + + /* + * Set the LUN to 0 (just in case). + */ + srb->lun = 0; us->srb->lun = 0; + ret = sddr09_transport(srb, us); + srb->lun = 1; us->srb->lun = 1; + + return ret; +#endif + + default: + US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->lun); + return USB_STOR_TRANSPORT_ERROR; + } +} diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/dpcm.h linux/drivers/usb/storage/dpcm.h --- v2.4.0-test6/linux/drivers/usb/storage/dpcm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/storage/dpcm.h Tue Aug 22 09:06:31 2000 @@ -0,0 +1,34 @@ +/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader + * + * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * + * DPCM driver v0.1: + * + * First release + * + * Current development and maintainance by: + * (c) 2000 Brian Webb (webbb@earthlink.net) + * + * See dpcm.c for more explanation + * + * 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. + */ + +#ifndef _MICROTECH_DPCM_USB_H +#define _MICROTECH_DPCM_USB_H + +extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/scsiglue.c linux/drivers/usb/storage/scsiglue.c --- v2.4.0-test6/linux/drivers/usb/storage/scsiglue.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/scsiglue.c Tue Aug 22 09:06:31 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $ + * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -187,6 +187,12 @@ US_DEBUGP("-- simulating missing IRQ\n"); up(&(us->ip_waitq)); return SUCCESS; + } + + /* This is a sanity check that we should never hit */ + if (in_interrupt()) { + printk(KERN_ERR "usb-storage: command_abort() called from an interrupt!!! BAD!!! BAD!! BAD!!\n"); + return FAILED; } /* if we have an urb pending, let's wake the control thread up */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/shuttle_usbat.c linux/drivers/usb/storage/shuttle_usbat.c --- v2.4.0-test6/linux/drivers/usb/storage/shuttle_usbat.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/shuttle_usbat.c Tue Aug 22 09:06:31 2000 @@ -1,5 +1,7 @@ /* Driver for SCM Microsystems USB-ATAPI cable * + * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * * SCM driver v0.2: * * Removed any reference to maxlen for bulk transfers. diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/shuttle_usbat.h linux/drivers/usb/storage/shuttle_usbat.h --- v2.4.0-test6/linux/drivers/usb/storage/shuttle_usbat.h Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/shuttle_usbat.h Tue Aug 22 09:06:31 2000 @@ -1,6 +1,8 @@ /* Driver for SCM Microsystems USB-ATAPI cable * Header File * + * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * * Current development and maintainance by: * (c) 2000 Robert Baruch (autophile@dol.net) * diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c --- v2.4.0-test6/linux/drivers/usb/storage/transport.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/transport.c Tue Aug 22 09:06:31 2000 @@ -1,12 +1,13 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $ + * $Id: transport.c,v 1.12 2000/08/08 15:22:38 gowdy Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) @@ -52,6 +53,353 @@ #include /*********************************************************************** + * Helper routines + ***********************************************************************/ + +/* Calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) +{ + int i; + unsigned int total = 0; + struct scatterlist *sg; + + /* support those devices which need the length calculated + * differently + */ + if (srb->cmnd[0] == INQUIRY) { + srb->cmnd[4] = 36; + } + + if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) + return srb->cmnd[4]; + + if (srb->cmnd[0] == TEST_UNIT_READY) + return 0; + + /* Are we going to scatter gather? */ + if (srb->use_sg) { + /* Add up the sizes of all the scatter-gather segments */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + total += sg[i].length; + + return total; + } + else + /* Just return the length of the buffer */ + return srb->request_bufflen; +} + +/* Calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us) +{ + int i; + int doDefault = 0; + unsigned int len = 0; + unsigned int total = 0; + struct scatterlist *sg; + + /* This table tells us: + X = command not supported + L = return length in cmnd[4] (8 bits). + M = return length in cmnd[8] (8 bits). + G = return length in cmnd[3] and cmnd[4] (16 bits) + H = return length in cmnd[7] and cmnd[8] (16 bits) + I = return length in cmnd[8] and cmnd[9] (16 bits) + C = return length in cmnd[2] to cmnd[5] (32 bits) + D = return length in cmnd[6] to cmnd[9] (32 bits) + B = return length in blocksize so we use buff_len + R = return length in cmnd[2] to cmnd[4] (24 bits) + S = return length in cmnd[3] to cmnd[5] (24 bits) + T = return length in cmnd[6] to cmnd[8] (24 bits) + U = return length in cmnd[7] to cmnd[9] (24 bits) + 0-9 = fixed return length + V = 20 bytes + W = 24 bytes + Z = return length is mode dependant or not in command, use buff_len + */ + + static char *lengths = + + /* 0123456789ABCDEF 0123456789ABCDEF */ + + "00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */ + "XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */ + "M0HHB0X000H0HH0X" "XHH00HXX0TH0H0XX" /* 40-5F */ + "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */ + "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */ + "X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX" /* A0-BF */ + "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */ + "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */ + + /* Commands checked in table: + + CHANGE_DEFINITION 40 + COMPARE 39 + COPY 18 + COPY_AND_VERIFY 3a + ERASE 19 + ERASE_10 2c + ERASE_12 ac + EXCHANGE_MEDIUM a6 + FORMAT_UNIT 04 + GET_DATA_BUFFER_STATUS 34 + GET_MESSAGE_10 28 + GET_MESSAGE_12 a8 + GET_WINDOW 25 !!! Has more data than READ_CAPACITY, need to fix table + INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len + INQUIRY 12 + LOAD_UNLOAD 1b + LOCATE 2b + LOCK_UNLOCK_CACHE 36 + LOG_SELECT 4c + LOG_SENSE 4d + MEDIUM_SCAN 38 !!! This was M + MODE_SELECT6 15 + MODE_SELECT_10 55 + MODE_SENSE_6 1a + MODE_SENSE_10 5a + MOVE_MEDIUM a5 + OBJECT_POSITION 31 !!! Same as SEARCH_DATA_EQUAL + PAUSE_RESUME 4b + PLAY_AUDIO_10 45 + PLAY_AUDIO_12 a5 + PLAY_AUDIO_MSF 47 + PLAY_AUDIO_TRACK_INDEX 48 + PLAY_AUDIO_TRACK_RELATIVE_10 49 + PLAY_AUDIO_TRACK_RELATIVE_12 a9 + POSITION_TO_ELEMENT 2b + PRE-FETCH 34 + PREVENT_ALLOW_MEDIUM_REMOVAL 1e + PRINT 0a !!! Same as WRITE_6 but is always in bytes + READ_6 08 + READ_10 28 + READ_12 a8 + READ_BLOCK_LIMITS 05 + READ_BUFFER 3c + READ_CAPACITY 25 + READ_CDROM_CAPACITY 25 + READ_DEFECT_DATA 37 + READ_DEFECT_DATA_12 b7 + READ_ELEMENT_STATUS b8 !!! Think this is in bytes + READ_GENERATION 29 !!! Could also be M? + READ_HEADER 44 !!! This was L + READ_LONG 3e + READ_POSITION 34 !!! This should be V but conflicts with PRE-FETCH + READ_REVERSE 0f + READ_SUB-CHANNEL 42 !!! Is this in bytes? + READ_TOC 43 !!! Is this in bytes? + READ_UPDATED_BLOCK 2d + REASSIGN_BLOCKS 07 + RECEIVE 08 !!! Same as READ_6 probably in bytes though + RECEIVE_DIAGNOSTIC_RESULTS 1c + RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes + RELEASE_UNIT 17 + REQUEST_SENSE 03 + REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes + RESERVE_UNIT 16 + REWIND 01 + REZERO_UNIT 01 + SCAN 1b !!! Conflicts with various commands, should be L + SEARCH_DATA_EQUAL 31 + SEARCH_DATA_EQUAL_12 b1 + SEARCH_DATA_LOW 30 + SEARCH_DATA_LOW_12 b0 + SEARCH_DATA_HIGH 32 + SEARCH_DATA_HIGH_12 b2 + SEEK_6 0b !!! Conflicts with SLEW_AND_PRINT + SEEK_10 2b + SEND 0a !!! Same as WRITE_6, probably in bytes though + SEND 2a !!! Similar to WRITE_10 but for scanners + SEND_DIAGNOSTIC 1d + SEND_MESSAGE_6 0a !!! Same as WRITE_6 - is in bytes + SEND_MESSAGE_10 2a !!! Same as WRITE_10 - is in bytes + SEND_MESSAGE_12 aa !!! Same as WRITE_12 - is in bytes + SEND_VOLUME_TAG b6 !!! Think this is in bytes + SET_LIMITS 33 + SET_LIMITS_12 b3 + SET_WINDOW 24 + SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6 + SPACE 11 + START_STOP_UNIT 1b + STOP_PRINT 1b + SYNCHRONIZE_BUFFER 10 + SYNCHRONIZE_CACHE 35 + TEST_UNIT_READY 00 + UPDATE_BLOCK 3d + VERIFY 13 + VERIFY 2f + VERIFY_12 af + WRITE_6 0a + WRITE_10 2a + WRITE_12 aa + WRITE_AND_VERIFY 2e + WRITE_AND_VERIFY_12 ae + WRITE_BUFFER 3b + WRITE_FILEMARKS 10 + WRITE_LONG 3f + WRITE_SAME 41 + */ + + /* Not sure this is right as an INQUIRY can contain nonstandard info */ + if (srb->cmnd[0] == INQUIRY) + srb->cmnd[4] = 36; + + if (srb->sc_data_direction == SCSI_DATA_WRITE) { + doDefault = 1; + } + else + switch (lengths[srb->cmnd[0]]) { + case 'L': + len = srb->cmnd[4]; + break; + + case 'M': + len = srb->cmnd[8]; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + len = lengths[srb->cmnd[0]]-'0'; + break; + + case 'G': + len = (((unsigned int)srb->cmnd[3])<<8) | + srb->cmnd[4]; + break; + + case 'H': + len = (((unsigned int)srb->cmnd[7])<<8) | + srb->cmnd[8]; + break; + + case 'I': + len = (((unsigned int)srb->cmnd[8])<<8) | + srb->cmnd[9]; + break; + + case 'R': + len = (((unsigned int)srb->cmnd[2])<<16) | + (((unsigned int)srb->cmnd[3])<<8) | + srb->cmnd[4]; + break; + + case 'S': + len = (((unsigned int)srb->cmnd[3])<<16) | + (((unsigned int)srb->cmnd[4])<<8) | + srb->cmnd[5]; + break; + + case 'T': + len = (((unsigned int)srb->cmnd[6])<<16) | + (((unsigned int)srb->cmnd[7])<<8) | + srb->cmnd[8]; + break; + + case 'U': + len = (((unsigned int)srb->cmnd[7])<<16) | + (((unsigned int)srb->cmnd[8])<<8) | + srb->cmnd[9]; + break; + + case 'C': + len = (((unsigned int)srb->cmnd[2])<<24) | + (((unsigned int)srb->cmnd[3])<<16) | + (((unsigned int)srb->cmnd[4])<<8) | + srb->cmnd[5]; + break; + + case 'D': + len = (((unsigned int)srb->cmnd[6])<<24) | + (((unsigned int)srb->cmnd[7])<<16) | + (((unsigned int)srb->cmnd[8])<<8) | + srb->cmnd[9]; + break; + + case 'V': + len = 20; + break; + + case 'W': + len = 24; + break; + + case 'B': + /* Use buffer size due to different block sizes */ + doDefault = 1; + break; + + case 'X': + US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n", + srb->cmnd[0]); + doDefault = 1; + break; + + case 'Z': + /* Use buffer size due to mode dependence */ + doDefault = 1; + break; + + default: + US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n", + srb->cmnd[0], lengths[srb->cmnd[0]] ); + doDefault = 1; + } + + if ( doDefault == 1 ) { + /* Are we going to scatter gather? */ + if (srb->use_sg) { + /* Add up the sizes of all the sg segments */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + total += sg[i].length; + len = total; + } + else + /* Just return the length of the buffer */ + len = srb->request_bufflen; + } + + return len; +} + +/* This is a version of usb_clear_halt() that doesn't read the status from + * the device -- this is because some devices crash their internal firmware + * when the status is requested after a halt + */ +static int clear_halt(struct usb_device *dev, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); + + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, + endp, NULL, 0, HZ * 3); + + /* this is a failure case */ + if (result < 0) + return result; + + /* reset the toggles and endpoint flags */ + usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + + return 0; +} + +/*********************************************************************** * Data transfer routines ***********************************************************************/ @@ -217,7 +565,7 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } /* did we send all the data? */ @@ -287,44 +635,6 @@ srb->result = result; } -/* Calculate the length of the data transfer (not the command) for any - * given SCSI command - */ -static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) -{ - int i; - unsigned int total = 0; - struct scatterlist *sg; - - /* support those devices which need the length calculated - * differently - */ - if (us->flags & US_FL_ALT_LENGTH) { - if (srb->cmnd[0] == INQUIRY) { - srb->cmnd[4] = 36; - } - - if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) - return srb->cmnd[4]; - - if (srb->cmnd[0] == TEST_UNIT_READY) - return 0; - } - - /* Are we going to scatter gather? */ - if (srb->use_sg) { - /* Add up the sizes of all the scatter-gather segments */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - total += sg[i].length; - - return total; - } - else - /* Just return the length of the buffer */ - return srb->request_bufflen; -} - /*********************************************************************** * Transport routines ***********************************************************************/ @@ -363,7 +673,7 @@ * of determining status on it's own, we need to auto-sense almost * every time. */ - if (us->protocol == US_PR_CB) { + if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; @@ -490,7 +800,7 @@ * This is necessary because the auto-sense for some devices always * sets byte 0 == 0x70, even if there is no error */ - if ((us->protocol == US_PR_CB) && + if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && (result == USB_STOR_TRANSPORT_GOOD) && ((srb->sense_buffer[2] & 0xf) == 0x0)) srb->sense_buffer[0] = 0x0; @@ -548,10 +858,10 @@ /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, + 0)); + US_DEBUGP("-- clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -652,10 +962,10 @@ /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, + 0)); + US_DEBUGP("-- clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -710,7 +1020,7 @@ /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ @@ -757,7 +1067,7 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; @@ -796,7 +1106,7 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); @@ -810,7 +1120,7 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); return USB_STOR_TRANSPORT_ERROR; } } @@ -877,10 +1187,10 @@ schedule_timeout(HZ*6); US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); return 0; @@ -904,14 +1214,13 @@ if (result < 0) US_DEBUGP("Bulk hard reset failed %d\n", result); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + clear_halt(us->pusb_dev, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* long wait for reset */ schedule_timeout(HZ*6); return result; } - diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/transport.h linux/drivers/usb/storage/transport.h --- v2.4.0-test6/linux/drivers/usb/storage/transport.h Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/transport.h Tue Aug 22 13:10:55 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.6 2000/07/27 14:42:43 groovyjava Exp $ + * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -58,6 +58,7 @@ #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ #endif +#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ /* * Bulk only data structures @@ -132,5 +133,7 @@ extern int usb_stor_Bulk_reset(struct us_data*); void usb_stor_invoke_transport(Scsi_Cmnd *, struct us_data *); + +extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c --- v2.4.0-test6/linux/drivers/usb/storage/usb.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/usb.c Tue Aug 22 13:10:55 2000 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.16 2000/08/01 22:01:19 mdharm Exp $ + * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -44,7 +44,6 @@ */ #include - #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -56,6 +55,9 @@ #ifdef CONFIG_USB_STORAGE_SDDR09 #include "sddr09.h" #endif +#ifdef CONFIG_USB_STORAGE_DPCM +#include "dpcm.h" +#endif #include #include @@ -63,6 +65,10 @@ #include #include +/* Some informational data */ +MODULE_AUTHOR("Matthew Dharm "); +MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); + /* * Per device data */ @@ -91,6 +97,58 @@ disconnect: storage_disconnect, }; +/* + * fill_inquiry_response takes an unsigned char array (which must + * be at least 36 characters) and populates the vendor name, + * product name, and revision fields. Then the array is copied + * into the SCSI command's response buffer (oddly enough + * called request_buffer). data_len contains the length of the + * data array, which again must be at least 36. + */ + +void fill_inquiry_response(struct us_data *us, unsigned char *data, + unsigned int data_len) { + + int i; + struct scatterlist *sg; + int len = + us->srb->request_bufflen > data_len ? data_len : + us->srb->request_bufflen; + int transferred; + int amt; + + if (data_len<36) // You lose. + return; + + memcpy(data+8, us->unusual_dev->vendorName, + strlen(us->unusual_dev->vendorName) > 8 ? 8 : + strlen(us->unusual_dev->vendorName)); + memcpy(data+16, us->unusual_dev->productName, + strlen(us->unusual_dev->productName) > 16 ? 16 : + strlen(us->unusual_dev->productName)); + data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F); + data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F); + data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F); + data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F); + + if (us->srb->use_sg) { + sg = (struct scatterlist *)us->srb->request_buffer; + for (i=0; isrb->use_sg; i++) + memset(sg[i].address, 0, sg[i].length); + for (i=0, transferred=0; + isrb->use_sg && transferred < len; + i++) { + amt = sg[i].length > len-transferred ? + len-transferred : sg[i].length; + memcpy(sg[i].address, data+transferred, amt); + transferred -= amt; + } + } else { + memset(us->srb->request_buffer, 0, us->srb->request_bufflen); + memcpy(us->srb->request_buffer, data, len); + } +} + static int usb_stor_control_thread(void * __us) { wait_queue_t wait; @@ -176,7 +234,7 @@ us->srb = NULL; break; } - + /* lock the device pointers */ down(&(us->dev_semaphore)); @@ -246,50 +304,140 @@ } /* This is the list of devices we recognize, along with their flag data */ + +/* The vendor name should be kept at eight characters or less, and + * the product name should be kept at 16 characters or less. If a device + * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names + * normally generated by a device thorugh the INQUIRY response will be + * taken from this list, and this is the reason for the above size + * restriction. However, if the flag is not present, then you + * are free to use as many characters as you like. + */ + static struct us_unusual_dev us_unusual_dev_list[] = { - { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus", - US_SC_8070, US_PR_CB, 0}, + + { 0x03f0, 0x0107, 0x0200, 0x0200, + "HP", + "CD-Writer+", + US_SC_8070, US_PR_CB, NULL, + 0}, + #ifdef CONFIG_USB_STORAGE_HP8200e - { 0x03f0, 0x0207, 0x0001, 0x0001, "HP USB CD-Writer Plus 8200e", - US_SC_8070, US_PR_SCM_ATAPI, - US_FL_ALT_LENGTH | US_FL_NEED_INIT | US_FL_SINGLE_LUN}, + { 0x03f0, 0x0207, 0x0001, 0x0001, + "HP", + "CD-Writer+ 8200e", + US_SC_8070, US_PR_SCM_ATAPI, init_8200e, + US_FL_SINGLE_LUN}, #endif - { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120", - US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30/S70", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | - US_FL_MODE_XLATE | US_FL_ALT_LENGTH | US_FL_ALT_LENGTH}, - { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | - US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, - { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U", - US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U", - US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN}, - { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-05a)", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP}, -#ifdef CONFIG_USB_STORAGE_SDDR09 - { 0x0781, 0x0200, 0x0100, 0x0100, "Sandisk ImageMate (SDDR-09)", - US_SC_SCSI, US_PR_EUSB_SDDR09, + + { 0x04e6, 0x0001, 0x0200, 0x0200, + "Matshita", + "LS-120", + US_SC_8020, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x04e6, 0x0002, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x04e6, 0x0006, 0x0100, 0x0100, + "Shuttle", + "eUSB MMC Adapter", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x054c, 0x0010, 0x0210, 0x0210, + "Sony", + "DSC-S30/S70", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, + + { 0x054c, 0x002d, 0x0100, 0x0100, + "Sony", + "Memorystick MSAC-US1", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, + + { 0x057b, 0x0000, 0x0000, 0x0299, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x057b, 0x0000, 0x0300, 0x9999, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CBI, NULL, + US_FL_SINGLE_LUN}, + + { 0x0693, 0x0002, 0x0100, 0x0100, + "Hagiwara", + "FlashGate SmartMedia", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x0781, 0x0001, 0x0200, 0x0200, + "Sandisk", + "ImageMate SDDR05a", + US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP}, + +#ifdef CONFIG_USB_STORAGE_SDDR09 + { 0x0781, 0x0200, 0x0100, 0x0100, + "Sandisk", + "ImageMate SDDR09", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP }, +#endif + + { 0x0781, 0x0002, 0x0009, 0x0009, + "Sandisk", + "ImageMate SDDR31", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_IGNORE_SER}, + + { 0x07af, 0x0004, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-DB25", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x059f, 0xa601, 0x0200, 0x0200, + "LaCie", + "USB Hard Disk", + US_SC_RBC, US_PR_CB, NULL, + 0 }, + +#ifdef CONFIG_USB_STORAGE_DPCM + { 0x07af, 0x0006, 0x0100, 0x0100, + "Microtech", + "CameraMate (DPCM_USB)", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP }, #endif - { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)", - US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER}, - { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge", - US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0 }}; + + { 0x07af, 0x0005, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-HD50", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x05ab, 0x0031, 0x0100, 0x0100, + "In-System", + "USB/IDE Bridge", + US_SC_8070, US_PR_BULK, NULL, + 0 }, + + { 0x0693, 0x0005, 0x0100, 0x0100, + "Hagiwara", + "Flashgate", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0 } +}; /* Search our ususual device list, based on vendor/product combinations * to see if we can support this device. Returns a pointer to a structure @@ -319,7 +467,8 @@ } /* otherwise, we found one! */ - US_DEBUGP("-- found matching device: %s\n", ptr->name); + US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName, + ptr->productName); return ptr; } @@ -546,15 +695,15 @@ USB_ENDPOINT_NUMBER_MASK; ss->ep_int = ep_int; - /* Reset the device's NEED_INIT flag if it needs to be - initialized with a magic sequence */ - - if (flags & US_FL_NEED_INIT) - ss->flags |= US_FL_NEED_INIT; - /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) return NULL; + + /* Re-Initialize the device if it needs it */ + + if (unusual_dev && unusual_dev->initFunction) + (*unusual_dev->initFunction)(ss); + } else { /* New device -- allocate memory and initialize */ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); @@ -586,6 +735,7 @@ ss->subclass = subclass; ss->protocol = protocol; ss->flags = flags; + ss->unusual_dev = unusual_dev; /* copy over the endpoint data */ if (ep_in) @@ -604,10 +754,22 @@ strncpy(ss->vendor, mf, USB_STOR_STRING_LEN); strncpy(ss->product, prod, USB_STOR_STRING_LEN); strncpy(ss->serial, serial, USB_STOR_STRING_LEN); - if (strlen(ss->vendor) == 0) - strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN); - if (strlen(ss->product) == 0) - strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN); + if (strlen(ss->vendor) == 0) { + if (unusual_dev) + strncpy(ss->vendor, unusual_dev->vendorName, + USB_STOR_STRING_LEN); + else + strncpy(ss->vendor, "Unknown", + USB_STOR_STRING_LEN); + } + if (strlen(ss->product) == 0) { + if (unusual_dev) + strncpy(ss->product, unusual_dev->productName, + USB_STOR_STRING_LEN); + else + strncpy(ss->product, "Unknown", + USB_STOR_STRING_LEN); + } if (strlen(ss->serial) == 0) strncpy(ss->serial, "None", USB_STOR_STRING_LEN); @@ -657,6 +819,15 @@ ss->max_lun = 1; break; #endif + +#ifdef CONFIG_USB_STORAGE_DPCM + case US_PR_DPCM_USB: + ss->transport_name = "Control/Bulk-EUSB/SDDR09"; + ss->transport = dpcm_transport; + ss->transport_reset = usb_stor_CB_reset; + ss->max_lun = 1; + break; +#endif default: ss->transport_name = "Unknown"; @@ -734,6 +905,11 @@ * we to do it? */ (struct us_data *)ss->htmplt.proc_dir = ss; + + /* Just before we start our control thread, initialize + * the device if it needs initialization */ + if (unusual_dev && unusual_dev->initFunction) + (*unusual_dev->initFunction)(ss); /* start up our control thread */ ss->pid = kernel_thread(usb_stor_control_thread, ss, @@ -878,6 +1054,3 @@ module_init(usb_stor_init) ; module_exit(usb_stor_exit) ; - -MODULE_AUTHOR("Michael Gee , David L. Brown, Jr. , Matthew Dharm "); -MODULE_DESCRIPTION("USB Mass Storage driver"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/storage/usb.h linux/drivers/usb/storage/usb.h --- v2.4.0-test6/linux/drivers/usb/storage/usb.h Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/storage/usb.h Tue Aug 22 09:06:31 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.4 2000/07/28 20:14:49 groovyjava Exp $ + * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -77,6 +77,8 @@ } } +struct us_data; + /* * Unusual device list definitions */ @@ -89,9 +91,11 @@ __u16 bcdDeviceMax; /* the list specifies these parameters */ - const char* name; + const char* vendorName; + const char* productName; __u8 useProtocol; __u8 useTransport; + int (*initFunction)(struct us_data *); unsigned int flags; }; @@ -100,15 +104,11 @@ #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for Win/MacOS compatibility */ #define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for - us_transfer_length() */ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ -#define US_FL_NEED_INIT 0x00000020 /* Device needs initialization */ +#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define USB_STOR_STRING_LEN 32 -struct us_data; - typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); typedef int (*trans_reset)(struct us_data*); typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); @@ -176,6 +176,7 @@ /* mutual exclusion structures */ struct semaphore notify; /* thread begin/end */ struct semaphore queue_exclusion; /* to protect data structs */ + struct us_unusual_dev *unusual_dev; /* If unusual device */ void *extra; /* Any extra data */ void (*extra_destructor)(void *); /* extra data destructor */ }; @@ -183,5 +184,10 @@ /* The list of structures and the protective lock for them */ extern struct us_data *us_list; extern struct semaphore us_list_semaphore; + +/* Function to fill an inquiry response. See usb.c for details */ + +extern void fill_inquiry_response(struct us_data *us, + unsigned char *data, unsigned int data_len); #endif diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.4.0-test6/linux/drivers/usb/usb-core.c Fri Jun 23 21:55:10 2000 +++ linux/drivers/usb/usb-core.c Sun Aug 13 19:25:14 2000 @@ -13,6 +13,7 @@ #include #include #include +#include #include /* @@ -42,13 +43,11 @@ int uhci_init(void); int ohci_hcd_init(void); -#ifdef MODULE - /* * Cleanup */ -void cleanup_module(void) +static void __exit usb_exit(void) { usb_major_cleanup(); usbdevfs_cleanup(); @@ -59,10 +58,7 @@ * Init */ -int init_module(void) -#else -int usb_init(void) -#endif +static int __init usb_init(void) { usb_major_init(); usbdevfs_init(); @@ -99,3 +95,6 @@ #endif return 0; } + +module_init(usb_init); +module_exit(usb_exit); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.0-test6/linux/drivers/usb/usb-ohci.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/usb-ohci.c Sun Aug 13 15:59:10 2000 @@ -76,7 +76,6 @@ (OHCI_CTRL_CBSR & 0x3) \ | OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE -static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); static LIST_HEAD (ohci_hcd_list); static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; @@ -534,7 +533,6 @@ { unsigned long flags; ohci_t * ohci; - DECLARE_WAITQUEUE (wait, current); if (!urb) /* just to be sure */ return -EINVAL; @@ -580,14 +578,18 @@ spin_unlock_irqrestore (&usb_ed_lock, flags); if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { + DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAITQUEUE (wait, current); + usb_dec_dev_use (urb->dev); - add_wait_queue (&op_wakeup, &wait); - current->state = TASK_UNINTERRUPTIBLE; /* wait until all TDs are deleted */ - if (!schedule_timeout (HZ / 10)) - err("unlink URB timeout!"); - remove_wait_queue (&op_wakeup, &wait); + add_wait_queue (&unlink_wakeup, &wait); + urb_priv->wait = &unlink_wakeup; + current->state = TASK_UNINTERRUPTIBLE; + schedule (); + remove_wait_queue (&unlink_wakeup, &wait); urb->status = -ENOENT; + urb_priv->wait = 0; } else { /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; @@ -634,7 +636,6 @@ unsigned long flags; int i, cnt = 0; ed_t * ed; - DECLARE_WAITQUEUE (wait, current); struct ohci_device * dev = usb_to_ohci (usb_dev); ohci_t * ohci = usb_dev->bus->hcpriv; @@ -643,13 +644,20 @@ if (usb_dev->devnum >= 0) { - /* delete all TDs of all EDs */ + /* driver disconnects should have unlinked all urbs + * (freeing all the TDs, unlinking EDs) but we need + * to defend against bugs that prevent that. + */ spin_lock_irqsave (&usb_ed_lock, flags); for(i = 0; i < NUM_EDS; i++) { ed = &(dev->ed[i]); if (ed->state != ED_NEW) { - if (ed->state == ED_OPER) + if (ed->state == ED_OPER) { + /* driver on that interface didn't unlink an urb */ + dbg ("driver usb-%s dev %d ed 0x%x unfreed URB", + ohci->ohci_dev->slot_name, usb_dev->devnum, i); ep_unlink (ohci, ed); + } ep_rm_ed (usb_dev, ed); ed->state = ED_DEL; cnt++; @@ -657,6 +665,9 @@ } spin_unlock_irqrestore (&usb_ed_lock, flags); + /* if the controller is running, tds for those unlinked + * urbs get freed by dl_del_list at the next SF interrupt + */ if (cnt > 0) { if (ohci->disabled) { @@ -670,15 +681,21 @@ warn ("TD leak, %d", cnt); } else if (!in_interrupt ()) { + DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); + DECLARE_WAITQUEUE (wait, current); + /* SF interrupt handler calls dl_del_list */ - add_wait_queue (&op_wakeup, &wait); + add_wait_queue (&freedev_wakeup, &wait); + dev->wait = &freedev_wakeup; current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout (HZ / 10); - remove_wait_queue (&op_wakeup, &wait); + schedule (); + remove_wait_queue (&freedev_wakeup, &wait); } else { - /* drivers mustn't expect this to work */ - err ("can't free tds, interrupt context"); + /* likely some interface's driver has a refcount bug */ + err ("bus %s devnum %d deletion in interrupt", + ohci->ohci_dev->slot_name, usb_dev->devnum); + BUG (); } } } @@ -907,35 +924,34 @@ #endif break; - case ISO: - if (ohci->ed_isotail == ed) - ohci->ed_isotail = ed->ed_prev; + case ISO: + if (ohci->ed_isotail == ed) + ohci->ed_isotail = ed->ed_prev; if (ed->hwNextED != 0) - ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev; - + ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev; + if (ed->ed_prev != NULL) { ed->ed_prev->hwNextED = ed->hwNextED; } else { - for (i = 0; i < 32; i += inter) { - inter = 1; + for (i = 0; i < 32; i++) { for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); - *ed_p != 0; - ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) { - inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); - if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) { - *ed_p = ed->hwNextED; - break; - } - } + *ed_p != 0; + ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) { + // inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); + if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) { + *ed_p = ed->hwNextED; + break; + } + } } } #ifdef DEBUG ep_print_int_eds (ohci, "UNLINK_ISO"); #endif break; - } - ed->state = ED_UNLINK; - return 0; + } + ed->state = ED_UNLINK; + return 0; } @@ -1276,28 +1292,33 @@ tdINFO = le32_to_cpup (&td->hwINFO); if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td); *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3)); - if(++ (urb_priv->td_cnt) == urb_priv->length) + /* URB is done; clean up */ + if (++(urb_priv->td_cnt) == urb_priv->length) { + void *condition = urb_priv->wait; + urb_rm_priv (urb); if (urb->transfer_flags & USB_ASYNC_UNLINK) { usb_dec_dev_use (urb->dev); urb->status = -ECONNRESET; urb->complete (urb); - } else { - wake_up (&op_wakeup); + } else if (condition) { + /* unblock sohci_unlink_urb */ + wake_up (condition); } + } } else { td_p = &td->hwNextTD; } - } + if (ed->state & ED_DEL) { /* set by sohci_free_dev */ struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]); - OHCI_FREE (tdTailP); /* free dummy td */ + OHCI_FREE (tdTailP); /* free dummy td */ ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); ed->state = ED_NEW; /* if all eds are removed wake up sohci_free_dev */ - if (!--dev->ed_cnt) - wake_up (&op_wakeup); + if (!--dev->ed_cnt && dev->wait) + wake_up (dev->wait); } else { ed->state &= ~ED_URB_DEL; @@ -1839,6 +1860,7 @@ /* start controller operations */ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci->disabled = 0; writel (ohci->hc_control, &ohci->regs->control); /* Choose the interrupts we care about now, others later on demand */ @@ -1850,25 +1872,28 @@ writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM, &ohci->regs->roothub.a); writel (RH_HS_LPSC, &ohci->regs->roothub.status); +#endif /* OHCI_USE_NPS */ + // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe); -#endif /* OHCI_USE_NPS */ /* connect the virtual root hub */ ohci->rh.devnum = 0; usb_dev = usb_alloc_dev (NULL, ohci->bus); - if (!usb_dev) + if (!usb_dev) { + ohci->disabled = 1; return -ENOMEM; + } dev = usb_to_ohci (usb_dev); ohci->bus->root_hub = usb_dev; usb_connect (usb_dev); if (usb_new_device (usb_dev) != 0) { usb_free_dev (usb_dev); + ohci->disabled = 1; return -ENODEV; } - ohci->disabled = 0; return 0; } @@ -1936,7 +1961,7 @@ /* allocate OHCI */ -static ohci_t * __devinit hc_alloc_ohci (void * mem_base) +static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) { ohci_t * ohci; struct usb_bus * bus; @@ -1947,9 +1972,16 @@ memset (ohci, 0, sizeof (ohci_t)); + ohci->disabled = 1; ohci->irq = -1; ohci->regs = mem_base; + ohci->ohci_dev = dev; + dev->driver_data = ohci; + + INIT_LIST_HEAD (&ohci->ohci_hcd_list); + list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); + bus = usb_alloc_bus (&sohci_device_operations); if (!bus) { kfree (ohci); @@ -1958,8 +1990,7 @@ ohci->bus = bus; bus->hcpriv = (void *) ohci; - ohci->disabled = 1; - + return ohci; } @@ -2008,6 +2039,7 @@ hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) { ohci_t * ohci; + u8 latency, limit; char buf[8], *bufp = buf; #ifndef __sparc__ @@ -2019,15 +2051,24 @@ (unsigned long) mem_base, bufp); printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name); - ohci = hc_alloc_ohci (mem_base); + ohci = hc_alloc_ohci (dev, mem_base); if (!ohci) { return -ENOMEM; } - ohci->ohci_dev = dev; - dev->driver_data = ohci; - INIT_LIST_HEAD (&ohci->ohci_hcd_list); - list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); + /* bad pci latencies can contribute to overruns */ + pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte (dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) { + dbg ("PCI latency reduced to max %d", limit); + pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); + ohci->pci_latency = limit; + } else { + /* it might already have been reduced */ + ohci->pci_latency = latency; + } + } if (hc_reset (ohci) < 0) { hc_release_ohci (ohci); @@ -2042,7 +2083,7 @@ if (request_irq (irq, hc_interrupt, SA_SHIRQ, ohci_pci_driver.name, ohci) != 0) { - err ("request interrupt %d failed", irq); + err ("request interrupt %s failed", bufp); hc_release_ohci (ohci); return -EBUSY; } @@ -2072,6 +2113,9 @@ int temp; int i; + if (ohci->pci_latency) + pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency); + ohci->disabled = 1; if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub); @@ -2106,7 +2150,6 @@ ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) { unsigned long mem_resource, mem_len; - u8 latency, limit; void *mem_base; if (pci_enable_device(dev) < 0) @@ -2128,14 +2171,6 @@ /* controller writes into our memory */ pci_set_master (dev); - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); - if (latency) { - pci_read_config_byte (dev, PCI_MAX_LAT, &limit); - if (limit && limit < latency) { - dbg ("PCI latency reduced to max %d", limit); - pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); - } - } return hc_found_ohci (dev, dev->irq, mem_base); } @@ -2157,6 +2192,9 @@ ohci->disabled ? " (disabled)" : "", in_interrupt () ? " in interrupt" : "" ); +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif /* don't wake up sleeping controllers, or block in interrupt context */ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) { @@ -2209,6 +2247,14 @@ ohci_t *ohci = (ohci_t *) dev->driver_data; int temp; + /* guard against multiple resumes */ + atomic_inc (&ohci->resume_count); + if (atomic_read (&ohci->resume_count) != 1) { + err ("concurrent PCI resumes for usb-%s", dev->slot_name); + atomic_dec (&ohci->resume_count); + return; + } + /* did we suspend, or were we powered off? */ ohci->hc_control = readl (&ohci->regs->control); temp = ohci->hc_control & OHCI_CTRL_HCFS; @@ -2253,6 +2299,9 @@ default: warn ("odd PCI resume for usb-%s", dev->slot_name); } + + /* controller is operational, extra resumes are harmless */ + atomic_dec (&ohci->resume_count); } #endif /* CONFIG_PM */ diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h --- v2.4.0-test6/linux/drivers/usb/usb-ohci.h Mon Jul 10 16:47:25 2000 +++ linux/drivers/usb/usb-ohci.h Sun Aug 13 15:59:10 2000 @@ -366,6 +366,7 @@ int irq; int disabled; /* e.g. got a UE, we're hung */ + atomic_t resume_count; /* defending against multiple resumes */ struct ohci_regs * regs; /* OHCI controller's memory */ struct list_head ohci_hcd_list; /* list of all ohci_hcd */ @@ -384,7 +385,10 @@ struct usb_bus * bus; struct usb_device * dev[128]; struct virt_root_hub rh; - struct pci_dev *ohci_dev; + + /* PCI device handle and settings */ + struct pci_dev *ohci_dev; + u8 pci_latency; } ohci_t; diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.4.0-test6/linux/drivers/usb/usb-uhci.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/usb-uhci.c Sun Aug 13 19:23:19 2000 @@ -12,7 +12,7 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.236 2000/08/02 20:28:28 acher Exp $ + * $Id: usb-uhci.c,v 1.237 2000/08/08 14:58:17 acher Exp $ */ #include @@ -48,7 +48,7 @@ /* This enables an extra UHCI slab for memory debugging */ #define DEBUG_SLAB -#define VERSTR "$Revision: 1.236 $ time " __TIME__ " " __DATE__ +#define VERSTR "$Revision: 1.237 $ time " __TIME__ " " __DATE__ #include #include "usb-uhci.h" @@ -888,7 +888,7 @@ data += pktsze; len -= pktsze; - last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || (urb->transfer_flags & USB_DISABLE_SPD))); + last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_DISABLE_SPD))); if (last) td->hw.td.status |= TD_CTRL_IOC; // last one generates INT diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.0-test6/linux/drivers/usb/usb.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/usb.c Tue Aug 22 09:06:31 2000 @@ -1222,9 +1222,7 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer) { - int i; - int retval; - int size; + int i, retval, size; struct usb_descriptor_header *header; memcpy(config, buffer, USB_DT_CONFIG_SIZE); @@ -1252,19 +1250,54 @@ size -= config->bLength; for (i = 0; i < config->bNumInterfaces; i++) { - header = (struct usb_descriptor_header *)buffer; - if ((header->bLength > size) || (header->bLength <= 2)) { - err("ran out of descriptors parsing"); - return -1; - } - - if (header->bDescriptorType != USB_DT_INTERFACE) { - warn("unexpected descriptor 0x%X", - header->bDescriptorType); + int numskipped, len; + char *begin; + + /* Skip over the rest of the Class Specific or Vendor */ + /* Specific descriptors */ + begin = buffer; + numskipped = 0; + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if ((header->bLength > size) || (header->bLength < 2)) { + err("invalid descriptor length of %d", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below */ + /* us in the descriptor heirarchy then we're done */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + break; + + dbg("skipping descriptor 0x%X", header->bDescriptorType); + numskipped++; buffer += header->bLength; size -= header->bLength; - continue; + } + if (numskipped) + dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (!len) { + config->extra = NULL; + config->extralen = 0; + } else { + config->extra = kmalloc(len, GFP_KERNEL); + if (!config->extra) { + err("couldn't allocate memory for config extra descriptors"); + config->extralen = 0; + return -1; + } + + memcpy(config->extra, begin, len); + config->extralen = len; } retval = usb_parse_interface(dev, config->interface + i, buffer, size); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c --- v2.4.0-test6/linux/drivers/usb/usbkbd.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/usb/usbkbd.c Tue Aug 22 15:19:52 2000 @@ -1,5 +1,5 @@ /* - * $Id: usbkbd.c,v 1.11 2000/05/29 09:01:52 vojtech Exp $ + * $Id: usbkbd.c,v 1.16 2000/08/14 21:05:26 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -47,8 +47,8 @@ 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198, 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, @@ -63,7 +63,7 @@ unsigned char old[8]; struct urb irq, led; devrequest dr; - unsigned char leds; + unsigned char leds, newleds; char name[128]; int open; }; @@ -104,28 +104,37 @@ if (type != EV_LED) return -1; - if (kbd->led.status == -EINPROGRESS) { - warn("had to kill led urb"); - usb_unlink_urb(&kbd->led); - } - kbd->leds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | - (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | - (!!test_bit(LED_NUML, dev->led)); + kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | + (!!test_bit(LED_NUML, dev->led)); + if (kbd->led.status == -EINPROGRESS) + return 0; - if (usb_submit_urb(&kbd->led)) { + if (kbd->leds == kbd->newleds) + return 0; + + kbd->leds = kbd->newleds; + if (usb_submit_urb(&kbd->led)) err("usb_submit_urb(leds) failed"); - return -1; - } return 0; } static void usb_kbd_led(struct urb *urb) { + struct usb_kbd *kbd = urb->context; + if (urb->status) warn("led urb status %d received", urb->status); + + if (kbd->leds == kbd->newleds) + return; + + kbd->leds = kbd->newleds; + if (usb_submit_urb(&kbd->led)) + err("usb_submit_urb(leds) failed"); } static int usb_kbd_open(struct input_dev *dev) diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.4.0-test6/linux/drivers/video/acornfb.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/video/acornfb.c Sun Aug 13 10:04:17 2000 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -1528,13 +1527,16 @@ virtual_end = PAGE_ALIGN(virtual_end); while (virtual_start < virtual_end) { + struct page *page; + /* * Clear page reserved bit, * set count to 1, and free * the page. */ - mem_map_unreserve(virt_to_page(virtual_start)); - atomic_set(&virt_to_page(virtual_start)->count, 1); + page = virt_to_page(virtual_start); + ClearPageReserved(page); + atomic_set(&page->count, 1); free_page(virtual_start); virtual_start += PAGE_SIZE; @@ -1629,7 +1631,7 @@ for (page = current_par.screen_base; page < PAGE_ALIGN(current_par.screen_base + size); page += PAGE_SIZE) - mem_map_reserve(virt_to_page(page)); + SetPageReserved(virt_to_page(page)); /* Hand back any excess pages that we allocated. */ for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE) free_page(page); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c --- v2.4.0-test6/linux/drivers/video/hgafb.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/video/hgafb.c Thu Aug 17 23:07:55 2000 @@ -7,6 +7,8 @@ * * History: * + * - Revision 0.1.6 (17 Aug 2000): new style structs + * documentation * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc * minor fixes * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for @@ -107,19 +109,23 @@ /* Framebuffer driver structures */ static struct fb_var_screeninfo hga_default_var = { - 720, 348, /* xres, yres */ - 720, 348, /* xres_virtual, yres_virtual */ - 0, 0, /* xoffset, yoffset */ - 1, /* bits_per_pixel */ - 0, /* grayscale */ - {0, 1, 0}, /* red */ - {0, 1, 0}, /* green */ - {0, 1, 0}, /* blue */ - {0, 0, 0}, /* transp */ - 0, /* nonstd (FB_NONSTD_HGA ?) */ - 0, /* activate */ - -1, -1, /* height, width */ - 0, /* accel_flags */ + xres: 720, + yres: 348, + xres_virtual: 720, + yres_virtual: 348, + xoffset: 0, + yoffset: 0, + bits_per_pixel: 1, + grayscale: 0, + red: {0, 1, 0}, + green: {0, 1, 0}, + blue: {0, 1, 0}, + transp: {0, 0, 0}, + nonstd: 0, /* (FB_NONSTD_HGA ?) */ + activate: 0, + height: -1, + width: -1, + accel_flags: 0, /* pixclock */ /* left_margin, right_margin */ /* upper_margin, lower_margin */ @@ -129,19 +135,19 @@ }; static struct fb_fix_screeninfo hga_fix = { - "HGA", /* id */ - (unsigned long) NULL, /* smem_start */ - 0, /* smem_len */ - FB_TYPE_PACKED_PIXELS, /* type (not sure) */ - 0, /* type_aux (not sure) */ - FB_VISUAL_MONO10, /* visual */ - 8, /* xpanstep */ - 8, /* ypanstep */ - 0, /* ywrapstep */ - 90, /* line_length */ - 0, /* mmio_start */ - 0, /* mmio_len */ - FB_ACCEL_NONE /* accel */ + id: "HGA", + smem_start: (unsigned long) NULL, + smem_len: 0, + type: FB_TYPE_PACKED_PIXELS, /* (not sure) */ + type_aux: 0, /* (not sure) */ + visual: FB_VISUAL_MONO10, + xpanstep: 8, + ypanstep: 8, + ywrapstep: 0, + line_length: 90, + mmio_start: 0, + mmio_len: 0, + accel: FB_ACCEL_NONE }; static struct fb_info fb_info; @@ -377,9 +383,15 @@ * * ------------------------------------------------------------------------- */ - /* - * Get the Fixed Part of the Display - */ +/** + * hga_get_fix - get the fixed part of the display + * @fix:struct fb_fix_screeninfo to fill in + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function copies @info->fix to @fix. + * A zero is returned on success and %-EINVAL for failure. + */ int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { @@ -390,10 +402,15 @@ return 0; } - - /* - * Get the User Defined Part of the Display - */ +/** + * hga_get_var - get the user defined part of the display + * @var:struct fb_var_screeninfo to fill in + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function copies @info->var to @var. + * A zero is returned on success and %-EINVAL for failure. + */ int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -404,13 +421,23 @@ return 0; } - /* - * Set the User Defined Part of the Display - * This is the most mystical function (at least for me). - * What is the exact specification of xxx_set_var? - * Should it handle xoffset, yoffset? Should it do pannig? - * What does vmode mean? - */ +/** + * hga_set_var - set the user defined part of the display + * @var:new video mode + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This function is called for changing video modes. Since HGA cards have + * only one fixed mode we have not much to do. After checking input + * parameters @var is copied to @info->var and @info->changevar is called. + * A zero is returned on success and %-EINVAL for failure. + * + * FIXME: + * This is the most mystical function (at least for me). + * What is the exact specification of xxx_set_var()? + * Should it handle xoffset, yoffset? Should it do panning? + * What does vmode mean? + */ int hga_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -431,10 +458,20 @@ return 0; } - - /* - * Get the Colormap - */ +/** + * hga_getcolreg - read color registers + * @regno:register index to read out + * @red:red value + * @green:green value + * @blue:blue value + * @transp:transparency value + * @info:unused + * + * This callback function is used to read the color registers of a HGA + * board. Since we have only two fixed colors, RGB values are 0x0000 + * for register0 and 0xaaaa for register1. + * A zero is returned on success and 1 for failure. + */ static int hga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info) @@ -450,6 +487,17 @@ return 0; } +/** + * hga_get_cmap - get the colormap + * @cmap:struct fb_cmap to fill in + * @kspc:called from kernel space? + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function passes it's input parameters to fb_get_cmap(). + * Callback function hga_getcolreg() is used to read the color registers. + */ + int hga_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { @@ -458,9 +506,19 @@ return fb_get_cmap(cmap, kspc, hga_getcolreg, info); } - /* - * Set the Colormap - */ +/** + * hga_setcolreg - set color registers + * @regno:register index to set + * @red:red value, unused + * @green:green value, unused + * @blue:blue value, unused + * @transp:transparency value, unused + * @info:unused + * + * This callback function is used to set the color registers of a HGA + * board. Since we have only two fixed colors only @regno is checked. + * A zero is returned on success and 1 for failure. + */ static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) @@ -470,6 +528,17 @@ return 0; } +/** + * hga_set_cmap - set the colormap + * @cmap:struct fb_cmap to set + * @kspc:called from kernel space? + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This wrapper function passes it's input parameters to fb_set_cmap(). + * Callback function hga_setcolreg() is used to set the color registers. + */ + int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { @@ -478,11 +547,17 @@ return fb_set_cmap(cmap, kspc, hga_setcolreg, info); } - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ +/** + * hga_pan_display - pan or wrap the display + * @var:contains new xoffset, yoffset and vmode values + * @con:unused + * @info:pointer to fb_info object containing info for current hga board + * + * This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP + * flag in @var. If input parameters are correct it calls hga_pan() to + * program the hardware. @info->var is updated to the new values. + * A zero is returned on success and %-EINVAL for failure. + */ int hga_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) @@ -531,6 +606,18 @@ * * ------------------------------------------------------------------------- */ +/** + * hgafbcon_switch - switch console + * @con:new console to switch to + * @info:pointer to fb_info object containing info for current hga board + * + * This function should install a new colormap and change the video mode. + * Since we have fixed colors and only one video mode we have nothing to + * do. + * Only console administration is done but it should go to fbcon.c IMHO. + * A zero is returned on success and %-EINVAL for failure. + */ + static int hgafbcon_switch(int con, struct fb_info *info) { CHKINFO(-EINVAL); @@ -564,6 +651,17 @@ return 0; } +/** + * hgafbcon_updatevar - update the user defined part of the display + * @con:console to update or -1 when no consoles defined on this fb + * @info:pointer to fb_info object containing info for current hga board + * + * This function is called when @var is changed by fbcon.c without calling + * hga_set_var(). It usually means scrolling. hga_pan_display() is called + * to update the hardware and @info->var. + * A zero is returned on success and %-EINVAL for failure. + */ + static int hgafbcon_updatevar(int con, struct fb_info *info) { CHKINFO(-EINVAL); @@ -571,17 +669,21 @@ return (con < 0) ? -EINVAL : hga_pan_display(&fb_display[con].var, con, info); } +/** + * hgafbcon_blank - (un)blank the screen + * @blank_mode:blanking method to use + * @info:unused + * + * Blank the screen if blank_mode != 0, else unblank. + * Implements VESA suspend and powerdown modes on hardware that supports + * disabling hsync/vsync: + * @blank_mode == 2 means suspend vsync, + * @blank_mode == 3 means suspend hsync, + * @blank_mode == 4 means powerdown. + */ + static void hgafbcon_blank(int blank_mode, struct fb_info *info) { - /* - * Blank the screen if blank_mode != 0, else unblank. - * Implements VESA suspend and powerdown modes on hardware - * that supports disabling hsync/vsync: - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown - */ - CHKINFO( ); DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/matrox/matroxfb_DAC1064.c linux/drivers/video/matrox/matroxfb_DAC1064.c --- v2.4.0-test6/linux/drivers/video/matrox/matroxfb_DAC1064.c Mon Jul 10 16:47:25 2000 +++ linux/drivers/video/matrox/matroxfb_DAC1064.c Thu Aug 10 12:34:31 2000 @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec * - * Version: 1.21 1999/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini * * Contributors: "menion?" * Betatesting, fixes, ideas * - * "Kurt Garloff" + * "Kurt Garloff" * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" @@ -63,6 +63,9 @@ * "Mark Vojkovich" * G400 support * + * "Ken Aaker" + * memtype extension (needed for GXT130P RS/6000 adapter) + * * (following author is not in any relation with this code, but his code * is included in this driver) * @@ -755,7 +758,7 @@ if (ACCESS_FBINFO(devflags.noinit)) return 0; hw->MXoptionReg &= 0xC0000100; - hw->MXoptionReg |= 0x00078020; + hw->MXoptionReg |= 0x00000020; if (ACCESS_FBINFO(devflags.novga)) hw->MXoptionReg &= ~0x00000100; if (ACCESS_FBINFO(devflags.nobios)) @@ -763,13 +766,13 @@ if (ACCESS_FBINFO(devflags.nopciretry)) hw->MXoptionReg |= 0x20000000; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); - reg50 &= ~0x3000; - pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); - DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333); if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) { + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + hw->MXoptionReg |= 0x1080; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); mga_outl(M_CTLWTST, 0x00000300); @@ -797,20 +800,45 @@ hw->MXoptionReg &= ~0x1000; } #endif + hw->MXoptionReg |= 0x00078020; + } else if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG200) { + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x3000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + + if (ACCESS_FBINFO(devflags.memtype) == -1) + ACCESS_FBINFO(devflags.memtype) = 3; + hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; + if (ACCESS_FBINFO(devflags.sgram)) + hw->MXoptionReg |= 0x4000; + mga_outl(M_CTLWTST, 0x042450A1); + mga_outl(M_MEMRDBK, 0x00000108); + udelay(200); + mga_outl(M_MACCESS, 0x00000000); + mga_outl(M_MACCESS, 0x00008000); + udelay(100); + mga_outw(M_MEMRDBK, 0x00000108); + hw->MXoptionReg |= 0x00078020; } else { - hw->MXoptionReg |= 0x00000C00; + pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, ®50); + reg50 &= ~0x00000100; + reg50 |= 0x00000000; + pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50); + + if (ACCESS_FBINFO(devflags.memtype) == -1) + ACCESS_FBINFO(devflags.memtype) = 0; + hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10; if (ACCESS_FBINFO(devflags.sgram)) hw->MXoptionReg |= 0x4000; mga_outl(M_CTLWTST, 0x042450A1); - mga_outb(0x1E47, 0x00); - mga_outb(0x1E46, 0x00); - udelay(10); - mga_outb(0x1C05, 0x00); - mga_outb(0x1C05, 0x80); + mga_outl(M_MEMRDBK, 0x00000108); + udelay(200); + mga_outl(M_MACCESS, 0x00000000); + mga_outl(M_MACCESS, 0x00008000); udelay(100); - mga_outw(0x1E44, 0x0108); + mga_outl(M_MEMRDBK, 0x00000108); + hw->MXoptionReg |= 0x00040020; } - hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/matrox/matroxfb_Ti3026.c linux/drivers/video/matrox/matroxfb_Ti3026.c --- v2.4.0-test6/linux/drivers/video/matrox/matroxfb_Ti3026.c Mon Jul 10 16:47:25 2000 +++ linux/drivers/video/matrox/matroxfb_Ti3026.c Thu Aug 10 12:34:31 2000 @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec * - * Version: 1.21 2000/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini * * Contributors: "menion?" * Betatesting, fixes, ideas * - * "Kurt Garloff" + * "Kurt Garloff" * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/matrox/matroxfb_accel.c linux/drivers/video/matrox/matroxfb_accel.c --- v2.4.0-test6/linux/drivers/video/matrox/matroxfb_accel.c Thu Jul 27 17:38:01 2000 +++ linux/drivers/video/matrox/matroxfb_accel.c Thu Aug 10 12:34:31 2000 @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec * - * Version: 1.21 2000/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini * * Contributors: "menion?" * Betatesting, fixes, ideas * - * "Kurt Garloff" + * "Kurt Garloff" * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c --- v2.4.0-test6/linux/drivers/video/matrox/matroxfb_base.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/video/matrox/matroxfb_base.c Thu Aug 10 12:34:31 2000 @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec * - * Version: 1.21 1999/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini * * Contributors: "menion?" * Betatesting, fixes, ideas * - * "Kurt Garloff" + * "Kurt Garloff" * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" @@ -69,6 +69,9 @@ * "Anton Altaparmakov" * G400 MAX/non-MAX distinction * + * "Ken Aaker" + * memtype extension (needed for GXT130P RS/6000 adapter) + * * (following author is not in any relation with this code, but his code * is included in this driver) * @@ -1312,6 +1315,7 @@ static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ static int dfp = 0; /* "matrox:dfp */ +static int memtype = -1; /* "matrox:memtype:xxx" */ static char fontname[64]; /* "matrox:font:xxxxx" */ #ifndef MODULE @@ -2037,6 +2041,9 @@ memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); /* DEVFLAGS */ ACCESS_FBINFO(devflags.inverse) = inverse; + ACCESS_FBINFO(devflags.memtype) = memtype; + if (memtype != -1) + noinit = 0; if (cmd & PCI_COMMAND_MEMORY) { ACCESS_FBINFO(devflags.novga) = novga; ACCESS_FBINFO(devflags.nobios) = nobios; @@ -2050,6 +2057,7 @@ ACCESS_FBINFO(devflags.nobios) = 1; ACCESS_FBINFO(devflags.noinit) = 0; } + ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; ACCESS_FBINFO(devflags.precise_width) = option_precise_width; @@ -2094,10 +2102,42 @@ matroxfb_remove(PMINFO 1); } +static struct pci_device_id matroxfb_devices[] __devinitdata = { +#ifdef CONFIG_FB_MATROX_MILLENIUM + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif +#ifdef CONFIG_FB_MATROX_MYSTIQUE + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif +#ifdef CONFIG_FB_MATROX_G100 + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#endif + {0, 0, + 0, 0, 0, 0, 0} +}; + +MODULE_DEVICE_TABLE(pci, matroxfb_devices); + static struct pci_driver matroxfb_driver = { - name: "matroxfb", - probe: matroxfb_probe, - remove: pci_remove_matrox, + name: "matroxfb", + id_table: matroxfb_devices, + probe: matroxfb_probe, + remove: pci_remove_matrox, }; /* **************************** init-time only **************************** */ @@ -2378,6 +2418,8 @@ sgram = 1; else if (!strcmp(this_opt, "sdram")) sgram = 0; + else if (!strncmp(this_opt, "memtype:", 8)) + memtype = simple_strtoul(this_opt+8, NULL, 0); else { int value = 1; @@ -2461,6 +2503,8 @@ MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); MODULE_PARM(noinit, "i"); MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); +MODULE_PARM(memtype, "i"); +MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)"); MODULE_PARM(mtrr, "i"); MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); MODULE_PARM(sgram, "i"); diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/matrox/matroxfb_base.h linux/drivers/video/matrox/matroxfb_base.h --- v2.4.0-test6/linux/drivers/video/matrox/matroxfb_base.h Mon Jul 10 16:47:25 2000 +++ linux/drivers/video/matrox/matroxfb_base.h Thu Aug 10 12:34:31 2000 @@ -2,7 +2,7 @@ * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * - * (c) 1998,1999 Petr Vandrovec + * (c) 1998,1999,2000 Petr Vandrovec * */ #ifndef __MATROXFB_H__ @@ -530,6 +530,7 @@ unsigned int textvram; /* character cells */ unsigned int ydstorg; /* offset in bytes from video start to usable memory */ /* 0 except for 6MB Millenium */ + int memtype; } devflags; struct display_switch dispsw; struct { @@ -695,6 +696,7 @@ #define M_VCOUNT 0x1E20 #define M_RESET 0x1E40 +#define M_MEMRDBK 0x1E44 #define M_AGP2PLL 0x1E4C diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/matrox/matroxfb_misc.c linux/drivers/video/matrox/matroxfb_misc.c --- v2.4.0-test6/linux/drivers/video/matrox/matroxfb_misc.c Sat Feb 26 22:31:51 2000 +++ linux/drivers/video/matrox/matroxfb_misc.c Thu Aug 10 12:34:31 2000 @@ -4,14 +4,14 @@ * * (c) 1998,1999,2000 Petr Vandrovec * - * Version: 1.21 2000/01/09 + * Version: 1.50 2000/08/10 * * MTRR stuff: 1998 Tom Rini * * Contributors: "menion?" * Betatesting, fixes, ideas * - * "Kurt Garloff" + * "Kurt Garloff" * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" diff -u --recursive --new-file v2.4.0-test6/linux/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c --- v2.4.0-test6/linux/drivers/video/sa1100fb.c Wed Aug 9 19:19:51 2000 +++ linux/drivers/video/sa1100fb.c Sun Aug 13 09:54:15 2000 @@ -12,17 +12,40 @@ /* * Code Status: - * 4/1/99 - Driver appears to be working for Brutus 320x200x8bpp mode. Other - * resolutions are working, but only the 8bpp mode is supported. - * Changes need to be made to the palette encode and decode routines - * to support 4 and 16 bpp modes. - * Driver is not designed to be a module. The FrameBuffer is statically - * allocated since dynamic allocation of a 300k buffer cannot be guaranteed. - * - * 6/17/99 - FrameBuffer memory is now allocated at run-time when the - * driver is initialized. + * 1999/04/01: + * Driver appears to be working for Brutus 320x200x8bpp mode. Other + * resolutions are working, but only the 8bpp mode is supported. + * Changes need to be made to the palette encode and decode routines + * to support 4 and 16 bpp modes. + * Driver is not designed to be a module. The FrameBuffer is statically + * allocated since dynamic allocation of a 300k buffer cannot be + * guaranteed. + * + * 1999/06/17: + * FrameBuffer memory is now allocated at run-time when the + * driver is initialized. * + * 2000/04/10: + * Big cleanup for dynamic selection of machine type at run time. + * Nicolas Pitre + * + * 2000/07/19: + * Support for Bitsy aka Compaq iPAQ H3600 added. + * Jamey Hicks + * + * 2000/08/07: + * Resolved an issue caused by a change made to the Assabet's PLD + * earlier this year which broke the framebuffer driver for newer + * Phase 4 Assabets. Some other parameters were changed to optimize for + * the Sharp display. + * Tak-Shing Chan + * Jeff Sutherland + * + * 2000/08/09: + * XP860 support added + * Kunihiko IMAI */ + #include #include #include @@ -41,6 +64,7 @@ #include #include #include +#include #include #include @@ -324,7 +348,7 @@ sa1100fb_encode_var(struct fb_var_screeninfo *var, struct sa1100fb_par *par) { - // Don't know if really want to var on entry. + // Don't know if really want to zero var on entry. // Look at set_var to see. If so, may need to add extra params to par // memset(var, 0, sizeof(struct fb_var_screeninfo)); @@ -347,15 +371,26 @@ break; case 12: // This case should differ for Active/Passive mode case 16: - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - var->transp.length = 0; - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->transp.offset = 0; - break; + if (machine_is_bitsy()) { + var->red.length = 4; + var->blue.length = 4; + var->green.length = 4; + var->transp.length = 0; + var->red.offset = 12; + var->green.offset = 7; + var->blue.offset = 1; + var->transp.offset = 0; + } else { + var->red.length = 5; + var->blue.length = 5; + var->green.length = 6; + var->transp.length = 0; + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->transp.offset = 0; + } + break; } return 0; } @@ -425,10 +460,13 @@ DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base); DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base); + DPRINTK("palette_size = 0x%08lx\n",(u_long)par->palette_size); + DPRINTK("palette_mem_size = 0x%08lx\n",(u_long)palette_mem_size); DPRINTK("p_screen_base = 0x%08lx\n",(u_long)par->p_screen_base); DPRINTK("v_screen_base = 0x%08lx\n",(u_long)par->v_screen_base); DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion); DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys); + return 0; } @@ -463,8 +501,6 @@ else display = &global_disp; /* Default display settings */ - - DPRINTK("xres = %d, yres = %d\n",var->xres, var->yres); /* Decode var contents into a par structure, adjusting any */ /* out of range values. */ if ((err = sa1100fb_decode_var(var, &par))) @@ -490,7 +526,6 @@ (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) chgvar = 1; } - DPRINTK("chgvar=%d\n", chgvar); display->var = *var; display->screen_base = par.v_screen_base; @@ -505,8 +540,6 @@ display->can_soft_blank = 1; display->inverse = 0; - DPRINTK("display->var.bits_per_pixel=%d xres=%d yres=%d display->dispsw=%p\n", - display->var.bits_per_pixel, var->xres, var->yres, display->dispsw); switch (display->var.bits_per_pixel) { #ifdef FBCON_HAS_CFB4 case 4: @@ -545,7 +578,6 @@ cmap = &display->cmap; else cmap = fb_default_cmap(current_par.palette_size); - DPRINTK("visual=%d palette_size=%d cmap=%p\n", current_par.visual, current_par.palette_size, cmap); fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info); } @@ -634,14 +666,18 @@ init_var.blue.length = 5; init_var.grayscale = 0; init_var.sync = 0; + init_var.pixclock = 171521; } else if (machine_is_bitsy()) { current_par.max_xres = 320; current_par.max_yres = 240; current_par.max_bpp = 16; - init_var.red.length = 5; - init_var.green.length = 6; - init_var.blue.length = 5; - init_var.grayscale = 0; + init_var.red.length = 4; + init_var.green.length = 4; + init_var.blue.length = 4; + init_var.red.offset = 12; + init_var.green.offset = 7; + init_var.blue.offset = 1; + init_var.grayscale = 0; } else if (machine_is_brutus()) { current_par.max_xres = 320; current_par.max_yres = 240; @@ -694,6 +730,23 @@ init_var.vsync_len = 1; init_var.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT; init_var.vmode = 0; + } else if (machine_is_xp860()) { + current_par.max_xres = 1024; + current_par.max_yres = 768; + + current_par.max_bpp = 8; + init_var.red.length = 4; + init_var.green = init_var.red; + init_var.blue = init_var.red; + + init_var.hsync_len = 4; + init_var.left_margin = 3; + init_var.right_margin = 2; + + init_var.vsync_len = 3; + init_var.upper_margin = 2; + init_var.lower_margin = 1; + } current_par.p_palette_base = NULL; @@ -769,7 +822,6 @@ L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE); - memset(VideoMemRegion, 0xAA, ALLOCATED_FB_MEM_SIZE); return (VideoMemRegion == NULL ? -EINVAL : 0); } @@ -804,6 +856,12 @@ /* the last multiplication by 1.2 is to handle */ /* sync problems */ } + if (machine_is_assabet()) { + pcd = frequency[PPCR & 0xf] / 1000; + pcd *= pixclock / 1000; + pcd = pcd / 1000000; + pcd++; /* make up for integer math truncations */ + } return pcd; } @@ -844,12 +902,12 @@ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9); lcd_shadow.lccr2 = - LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) + + LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0); lcd_shadow.lccr3 = LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + LCCR3_HorSnchH + LCCR3_ACBsCntOff + - LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38); + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd); /* Set board control register to handle new color depth */ sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16); @@ -860,29 +918,33 @@ LCCR0_DMADel(0); lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) + LCCR1_HorSnchWdth( 4 ) + - LCCR1_BegLnDel( 0x1f ) + - LCCR1_EndLnDel( 0x1f ); - lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) + - LCCR2_VrtSnchWdth( 1 )+ - LCCR2_BegFrmDel( 0 ) + - LCCR2_EndFrmDel( 0 ); - lcd_shadow.lccr3 = 15; + LCCR1_BegLnDel( 0xC ) + + LCCR1_EndLnDel( 0x11 ); + lcd_shadow.lccr2 = LCCR2_DisHght( var->yres + 1 ) + + LCCR2_VrtSnchWdth( 3 )+ + LCCR2_BegFrmDel( 10 ) + + LCCR2_EndFrmDel( 1 ); + lcd_shadow.lccr3 = (/* PCD */ 0x10 + | /* ACB */ 0 + | /* API */ 0 + | LCCR3_VrtSnchL + | LCCR3_HorSnchL); } else if (machine_is_brutus()) { - DPRINTK("Configuring Brutus LCD\n"); - lcd_shadow.lccr0 = - LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + - LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + - LCCR0_DMADel(0); - lcd_shadow.lccr1 = - LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + - LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101); - lcd_shadow.lccr2 = - LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + - LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0); - lcd_shadow.lccr3 = - LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + - LCCR3_HorSnchH + LCCR3_ACBsCntOff + - LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44); + DPRINTK("Configuring Brutus LCD\n"); + lcd_shadow.lccr0 = + LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + + LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + + LCCR0_DMADel(0); + lcd_shadow.lccr1 = + LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + + LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101); + lcd_shadow.lccr2 = + LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + + LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0); + lcd_shadow.lccr3 = + LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + + LCCR3_HorSnchH + LCCR3_ACBsCntOff + + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44); } else if (machine_is_lart()) { DPRINTK("Configuring LART LCD\n"); lcd_shadow.lccr0 = @@ -950,6 +1012,25 @@ ((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) + ((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); */ + } else if (machine_is_xp860()) { + DPRINTK("Configuring XP860 LCD\n"); + lcd_shadow.lccr0 = + LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + + LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM + + LCCR0_DMADel(0); + lcd_shadow.lccr1 = + LCCR1_DisWdth(var->xres) + + LCCR1_HorSnchWdth(var->hsync_len) + + LCCR1_BegLnDel(var->left_margin) + + LCCR1_EndLnDel(var->right_margin); + lcd_shadow.lccr2 = + LCCR2_DisHght(var->yres) + + LCCR2_VrtSnchWdth(var->vsync_len) + + LCCR2_BegFrmDel(var->upper_margin) + + LCCR2_EndFrmDel(var->lower_margin); + lcd_shadow.lccr3 = + LCCR3_PixClkDiv(6) + + LCCR3_HorSnchL + LCCR3_VrtSnchL; } /* Restore interrupt status */ @@ -976,10 +1057,12 @@ static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs) { if (LCSR & LCSR_LDD) { + int controller_state = current_par.controller_state; /* Disable Done Flag is set */ LCCR0 |= LCCR0_LDM; /* Mask LCD Disable Done Interrupt */ current_par.controller_state = LCD_MODE_DISABLED; - if (current_par.controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) { + if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) { + DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n"); sa1100fb_enable_lcd_controller(); } } @@ -1010,7 +1093,8 @@ #endif } else if (machine_is_bitsy()) { #ifdef CONFIG_SA1100_BITSY - clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); + if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE) + clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); #endif } else if (machine_is_penny()) { #ifdef CONFIG_SA1100_PENNY @@ -1066,7 +1150,7 @@ #endif } else if (machine_is_bitsy()) { #ifdef CONFIG_SA1100_BITSY - set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON) + set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); DPRINTK("DBAR1=%p\n", DBAR1); DPRINTK("LCCR0=%x\n", LCCR0); DPRINTK("LCCR1=%x\n", LCCR1); @@ -1115,6 +1199,7 @@ current_par.currcon, info); sa1100fb_enable_lcd_controller(); } + /* TODO: Bitsy support for blanking display */ } @@ -1164,7 +1249,7 @@ current_par.montype = 1; if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL) != 0) { - printk("sa1100fb: failed in request_irq\n"); + printk(KERN_ERR "sa1100fb: failed in request_irq\n"); return -EBUSY; } DPRINTK("sa1100fb: request_irq succeeded\n"); @@ -1185,6 +1270,9 @@ #endif } else if (machine_is_tifon()) { GPDR |= GPIO_GPIO(24); /* set GPIO24 to output */ + } else if (machine_is_xp860()) { + GPDR |= 0x3fc; + GAFR |= 0x3fc; } if (sa1100fb_set_var(&init_var, -1, &fb_info)) diff -u --recursive --new-file v2.4.0-test6/linux/fs/Config.in linux/fs/Config.in --- v2.4.0-test6/linux/fs/Config.in Wed Aug 9 19:19:51 2000 +++ linux/fs/Config.in Mon Aug 14 13:31:10 2000 @@ -99,7 +99,9 @@ fi dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET - + if [ "$CONFIG_SMB_FS" != "n" ]; then + string 'Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "" + fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS source fs/ncpfs/Config.in diff -u --recursive --new-file v2.4.0-test6/linux/fs/adfs/dir.c linux/fs/adfs/dir.c --- v2.4.0-test6/linux/fs/adfs/dir.c Fri Jun 23 21:55:10 2000 +++ linux/fs/adfs/dir.c Fri Aug 11 14:29:02 2000 @@ -40,12 +40,12 @@ switch ((unsigned long)filp->f_pos) { case 0: - if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) goto free_out; filp->f_pos += 1; case 1: - if (filldir(dirent, "..", 2, 1, dir.parent_id) < 0) + if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0) goto free_out; filp->f_pos += 1; @@ -60,7 +60,7 @@ goto unlock_out; while (ops->getnext(&dir, &obj) == 0) { if (filldir(dirent, obj.name, obj.name_len, - filp->f_pos, obj.file_id) < 0) + filp->f_pos, obj.file_id, DT_UNKNOWN) < 0) goto unlock_out; filp->f_pos += 1; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/affs/dir.c linux/fs/affs/dir.c --- v2.4.0-test6/linux/fs/affs/dir.c Mon Jul 10 16:47:25 2000 +++ linux/fs/affs/dir.c Fri Aug 11 14:29:02 2000 @@ -72,14 +72,14 @@ if (filp->f_pos == 0) { filp->private_data = (void *)0; - if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) { + if (filldir(dirent,".",1,filp->f_pos,inode->i_ino,DT_DIR) < 0) { return 0; } ++filp->f_pos; stored++; } if (filp->f_pos == 1) { - if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) { + if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode),DT_DIR) < 0) { return stored; } filp->f_pos = 2; @@ -135,7 +135,7 @@ pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n", namelen,name,ino,i); filp->private_data = (void *)ino; - if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0) + if (filldir(dirent,name,namelen,filp->f_pos,ino,DT_UNKNOWN) < 0) goto readdir_done; filp->private_data = (void *)(unsigned long)i; affs_brelse(fh_bh); diff -u --recursive --new-file v2.4.0-test6/linux/fs/autofs/root.c linux/fs/autofs/root.c --- v2.4.0-test6/linux/fs/autofs/root.c Mon Jul 10 16:47:25 2000 +++ linux/fs/autofs/root.c Fri Aug 11 14:29:02 2000 @@ -54,19 +54,19 @@ switch(nr) { case 0: - if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ default: while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) { if ( !ent->dentry || d_mountpoint(ent->dentry) ) { - if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0) + if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0) return 0; filp->f_pos = nr; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/autofs4/expire.c linux/fs/autofs4/expire.c --- v2.4.0-test6/linux/fs/autofs4/expire.c Mon Jul 10 16:47:25 2000 +++ linux/fs/autofs4/expire.c Fri Aug 11 14:55:39 2000 @@ -23,7 +23,9 @@ int count; spin_lock(&dcache_lock); - count = atomic_read(&mnt->mnt_count); + count = atomic_read(&mnt->mnt_count) - 2; + if (!is_autofs4_dentry(mnt->mnt_mountpoint)) + count--; repeat: next = this_parent->mnt_mounts.next; resume: @@ -33,7 +35,7 @@ mnt_child); next = tmp->next; /* Decrement count for unused children */ - count += atomic_read(&p->mnt_count) - 1; + count += atomic_read(&p->mnt_count) - 2; if (!list_empty(&p->mnt_mounts)) { this_parent = p; goto repeat; diff -u --recursive --new-file v2.4.0-test6/linux/fs/bfs/dir.c linux/fs/bfs/dir.c --- v2.4.0-test6/linux/fs/bfs/dir.c Fri Jun 23 21:55:10 2000 +++ linux/fs/bfs/dir.c Fri Aug 11 14:29:02 2000 @@ -50,7 +50,7 @@ de = (struct bfs_dirent *)(bh->b_data + offset); if (de->ino) { int size = strnlen(de->name, BFS_NAMELEN); - if (filldir(dirent, de->name, size, f->f_pos, de->ino) < 0) { + if (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) { brelse(bh); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/block_dev.c linux/fs/block_dev.c --- v2.4.0-test6/linux/fs/block_dev.c Wed Aug 9 19:19:51 2000 +++ linux/fs/block_dev.c Fri Aug 11 15:18:00 2000 @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -347,7 +348,7 @@ } } -void bdev_init(void) +void __init bdev_init(void) { int i; struct list_head *head = bdev_hashtable; @@ -364,7 +365,7 @@ 0, SLAB_HWCACHE_ALIGN, init_once, NULL); if (!bdev_cachep) - panic("cannot create bdev slab cache"); + panic("Cannot create bdev_cache SLAB cache"); } /* diff -u --recursive --new-file v2.4.0-test6/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.0-test6/linux/fs/buffer.c Wed Aug 9 19:19:51 2000 +++ linux/fs/buffer.c Thu Aug 17 11:27:25 2000 @@ -119,7 +119,7 @@ when trying to refill buffers. */ int interval; /* jiffies delay between kupdate flushes */ int age_buffer; /* Time for normal buffer to age before we flush it */ - int age_super; /* Time for superblock to age before we flush it */ + int dummy1; /* unused, was age_super */ int dummy2; /* unused */ int dummy3; /* unused */ } b_un; @@ -894,7 +894,7 @@ static __inline__ void __mark_dirty(struct buffer_head *bh, int flag) { - bh->b_flushtime = jiffies + (flag ? bdf_prm.b_un.age_super : bdf_prm.b_un.age_buffer); + bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer; refile_buffer(bh); } @@ -1714,8 +1714,10 @@ loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; __block_commit_write(inode,page,from,to); kunmap(page); - if (pos > inode->i_size) + if (pos > inode->i_size) { inode->i_size = pos; + mark_inode_dirty(inode); + } return 0; } @@ -1781,15 +1783,12 @@ * for them to complete. Clean up the buffer_heads afterwards. */ -static int do_kio(int rw, int nr, struct buffer_head *bh[], int size) +static int wait_kio(int rw, int nr, struct buffer_head *bh[], int size) { int iosize; int i; struct buffer_head *tmp; - if (rw == WRITE) - rw = WRITERAW; - ll_rw_block(rw, nr, bh); iosize = 0; spin_lock(&unused_list_lock); @@ -1840,6 +1839,7 @@ int pageind; int bhind; int offset; + int sectors = size>>9; unsigned long blocknr; struct kiobuf * iobuf = NULL; struct page * map; @@ -1891,9 +1891,10 @@ tmp->b_this_page = tmp; init_buffer(tmp, end_buffer_io_kiobuf, iobuf); - tmp->b_dev = dev; + tmp->b_rdev = tmp->b_dev = dev; tmp->b_blocknr = blocknr; - tmp->b_state = 1 << BH_Mapped; + tmp->b_rsector = blocknr*sectors; + tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req); if (rw == WRITE) { set_bit(BH_Uptodate, &tmp->b_state); @@ -1905,12 +1906,13 @@ offset += size; atomic_inc(&iobuf->io_count); - + + generic_make_request(rw, tmp); /* - * Start the IO if we have got too much + * Wait for IO if we have got too much */ if (bhind >= KIO_MAX_SECTORS) { - err = do_kio(rw, bhind, bh, size); + err = wait_kio(rw, bhind, bh, size); if (err >= 0) transferred += err; else @@ -1928,7 +1930,7 @@ /* Is there any IO still left to submit? */ if (bhind) { - err = do_kio(rw, bhind, bh, size); + err = wait_kio(rw, bhind, bh, size); if (err >= 0) transferred += err; else diff -u --recursive --new-file v2.4.0-test6/linux/fs/coda/dir.c linux/fs/coda/dir.c --- v2.4.0-test6/linux/fs/coda/dir.c Fri Jul 14 12:12:14 2000 +++ linux/fs/coda/dir.c Fri Aug 11 14:29:02 2000 @@ -748,7 +748,7 @@ char *name = vdirent->d_name; errfill = filldir(getdent, name, namlen, - offs, ino); + offs, ino, DT_UNKNOWN); CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d, name %*s, offset %d, result: %d, errfill: %d.\n", i,vdirent->d_fileno, vdirent->d_namlen, vdirent->d_reclen, vdirent->d_type, pos, string_offset, vdirent->d_namlen, vdirent->d_name, (u_int) offs, result, errfill); /* errfill means no space for filling in this round */ if ( errfill < 0 ) { diff -u --recursive --new-file v2.4.0-test6/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c --- v2.4.0-test6/linux/fs/cramfs/inode.c Wed Aug 9 19:19:51 2000 +++ linux/fs/cramfs/inode.c Fri Aug 11 14:29:02 2000 @@ -258,7 +258,7 @@ break; namelen--; } - error = filldir(dirent, name, namelen, offset, CRAMINO(de)); + error = filldir(dirent, name, namelen, offset, CRAMINO(de), de->mode >> 12); if (error) break; diff -u --recursive --new-file v2.4.0-test6/linux/fs/dcache.c linux/fs/dcache.c --- v2.4.0-test6/linux/fs/dcache.c Wed Aug 9 19:19:51 2000 +++ linux/fs/dcache.c Fri Aug 11 19:14:46 2000 @@ -1189,7 +1189,9 @@ if (!dentry_cache) panic("Cannot create dentry cache"); +#if PAGE_SHIFT < 13 mempages >>= (13 - PAGE_SHIFT); +#endif mempages *= sizeof(struct list_head); for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++) ; @@ -1228,9 +1230,6 @@ /* SLAB cache for __getname() consumers */ kmem_cache_t *names_cachep; -/* SLAB cache for files_struct structures */ -kmem_cache_t *files_cachep; - /* SLAB cache for file structures */ kmem_cache_t *filp_cachep; @@ -1246,19 +1245,13 @@ sizeof(struct buffer_head), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if(!bh_cachep) - panic("Cannot create buffer head SLAB cache\n"); + panic("Cannot create buffer head SLAB cache"); names_cachep = kmem_cache_create("names_cache", PAGE_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!names_cachep) panic("Cannot create names SLAB cache"); - - files_cachep = kmem_cache_create("files_cache", - sizeof(struct files_struct), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!files_cachep) - panic("Cannot create files SLAB cache"); filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, diff -u --recursive --new-file v2.4.0-test6/linux/fs/devfs/base.c linux/fs/devfs/base.c --- v2.4.0-test6/linux/fs/devfs/base.c Thu Jul 27 17:38:01 2000 +++ linux/fs/devfs/base.c Fri Aug 11 14:29:02 2000 @@ -2439,14 +2439,14 @@ case 0: scan_dir_for_removable (parent); err = (*filldir) (dirent, "..", 2, file->f_pos, - file->f_dentry->d_parent->d_inode->i_ino); + file->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; ++stored; /* Fall through */ case 1: - err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino); + err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; @@ -2463,7 +2463,7 @@ { if ( IS_HIDDEN (de) ) continue; err = (*filldir) (dirent, de->name, de->namelen, - file->f_pos, de->inode.ino); + file->f_pos, de->inode.ino, de->mode >> 12); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; diff -u --recursive --new-file v2.4.0-test6/linux/fs/devpts/root.c linux/fs/devpts/root.c --- v2.4.0-test6/linux/fs/devpts/root.c Fri Jun 23 21:55:10 2000 +++ linux/fs/devpts/root.c Fri Aug 11 14:29:02 2000 @@ -52,12 +52,12 @@ switch(nr) { case 0: - if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ @@ -66,7 +66,7 @@ int ptynr = nr - 2; if ( sbi->inodes[ptynr] ) { genptsname(numbuf, ptynr); - if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_CHR) < 0 ) return 0; } filp->f_pos = ++nr; diff -u --recursive --new-file v2.4.0-test6/linux/fs/efs/dir.c linux/fs/efs/dir.c --- v2.4.0-test6/linux/fs/efs/dir.c Sat Feb 26 22:31:52 2000 +++ linux/fs/efs/dir.c Fri Aug 11 14:29:02 2000 @@ -78,7 +78,7 @@ filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; /* copy filename and data in dirslot */ - filldir(dirent, nameptr, namelen, filp->f_pos, inodenum); + filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN); /* sanity check */ if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { diff -u --recursive --new-file v2.4.0-test6/linux/fs/exec.c linux/fs/exec.c --- v2.4.0-test6/linux/fs/exec.c Wed Aug 9 19:19:51 2000 +++ linux/fs/exec.c Mon Aug 14 10:19:55 2000 @@ -402,7 +402,10 @@ if (mm) { struct mm_struct *active_mm = current->active_mm; - init_new_context(current, mm); + if (init_new_context(current, mm)) { + mmdrop(mm); + return -ENOMEM; + } task_lock(current); current->mm = mm; current->active_mm = mm; @@ -433,7 +436,7 @@ if (atomic_read(¤t->sig->count) <= 1) return 0; - newsig = kmalloc(sizeof(*newsig), GFP_KERNEL); + newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL); if (newsig == NULL) return -ENOMEM; spin_lock_init(&newsig->siglock); @@ -457,7 +460,7 @@ if (current->sig == oldsig) return; if (atomic_dec_and_test(&oldsig->count)) - kfree(oldsig); + kmem_cache_free(sigact_cachep, oldsig); } /* @@ -467,22 +470,30 @@ static inline void flush_old_files(struct files_struct * files) { - unsigned long j; + long j = -1; - j = 0; + write_lock(&files->file_lock); for (;;) { unsigned long set, i; + j++; i = j * __NFDBITS; if (i >= files->max_fds || i >= files->max_fdset) break; - set = xchg(&files->close_on_exec->fds_bits[j], 0); - j++; + set = files->close_on_exec->fds_bits[j]; + if (!set) + continue; + files->close_on_exec->fds_bits[j] = 0; + write_unlock(&files->file_lock); for ( ; set ; i++,set >>= 1) { - if (set & 1) + if (set & 1) { sys_close(i); + } } + write_lock(&files->file_lock); + } + write_unlock(&files->file_lock); } int flush_old_exec(struct linux_binprm * bprm) diff -u --recursive --new-file v2.4.0-test6/linux/fs/ext2/dir.c linux/fs/ext2/dir.c --- v2.4.0-test6/linux/fs/ext2/dir.c Sun Mar 19 18:35:31 2000 +++ linux/fs/ext2/dir.c Fri Aug 11 14:29:01 2000 @@ -20,6 +20,10 @@ #include +static unsigned char ext2_filetype_table[] = { + DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK +}; + static int ext2_readdir(struct file *, void *, filldir_t); struct file_operations ext2_dir_operations = { @@ -152,10 +156,15 @@ * during the copy operation. */ unsigned long version = filp->f_version; + unsigned char d_type = DT_UNKNOWN; + if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE) + && de->file_type < EXT2_FT_MAX) + d_type = ext2_filetype_table[de->file_type]; error = filldir(dirent, de->name, de->name_len, - filp->f_pos, le32_to_cpu(de->inode)); + filp->f_pos, le32_to_cpu(de->inode), + d_type); if (error) break; if (version != filp->f_version) diff -u --recursive --new-file v2.4.0-test6/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v2.4.0-test6/linux/fs/fat/dir.c Wed Aug 9 19:19:51 2000 +++ linux/fs/fat/dir.c Sun Aug 13 12:01:54 2000 @@ -313,7 +313,7 @@ /* Fake . and .. for the root directory. */ if (inode->i_ino == MSDOS_ROOT_INO) { while (cpos < 2) { - if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0) + if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0) return 0; cpos++; filp->f_pos++; @@ -466,7 +466,8 @@ if (!long_slots||shortnames) { if (both) bufname[i] = '\0'; - if (filldir(dirent, bufname, i, *furrfu, inum) < 0) + if (filldir(dirent, bufname, i, *furrfu, inum, + (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) goto FillFailed; } else { char longname[275]; @@ -478,7 +479,8 @@ memcpy(&longname[long_len+1], bufname, i); long_len += i; } - if (filldir(dirent, longname, long_len, *furrfu, inum) < 0) + if (filldir(dirent, longname, long_len, *furrfu, inum, + (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) goto FillFailed; } @@ -508,7 +510,8 @@ const char * name, int name_len, off_t offset, - ino_t ino) + ino_t ino, + unsigned int d_type) { struct dirent *d1 = (struct dirent *)buf; struct dirent *d2 = d1 + 1; diff -u --recursive --new-file v2.4.0-test6/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.4.0-test6/linux/fs/fcntl.c Wed Aug 9 19:19:51 2000 +++ linux/fs/fcntl.c Sat Aug 12 19:48:04 2000 @@ -129,7 +129,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) { int err = -EBADF; - struct file * file; + struct file * file, *tofree; struct files_struct * files = current->files; write_lock(&files->file_lock); @@ -144,31 +144,40 @@ get_file(file); /* We are now finished with oldfd */ err = expand_files(files, newfd); - if (err < 0) { - write_unlock(&files->file_lock); - fput(file); - goto out; - } + if (err < 0) + goto out_fput; /* To avoid races with open() and dup(), we will mark the fd as * in-use in the open-file bitmap throughout the entire dup2() * process. This is quite safe: do_close() uses the fd array * entry, not the bitmap, to decide what work needs to be * done. --sct */ + /* Doesn't work. open() might be there first. --AV */ + + /* Yes. It's a race. In user space. Nothing sane to do */ + err = -EBUSY; + tofree = files->fd[newfd]; + if (!tofree && FD_ISSET(newfd, files->open_fds)) + goto out_fput; + + files->fd[newfd] = file; FD_SET(newfd, files->open_fds); + FD_CLR(newfd, files->close_on_exec); write_unlock(&files->file_lock); - - do_close(files, newfd, 0); - write_lock(&files->file_lock); - allocate_fd(files, file, newfd); + if (tofree) + filp_close(tofree, files); err = newfd; - out: return err; out_unlock: write_unlock(&files->file_lock); goto out; + +out_fput: + write_unlock(&files->file_lock); + fput(file); + goto out; } asmlinkage long sys_dup(unsigned int fildes) @@ -209,16 +218,11 @@ return 0; } -asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct file * filp; - long err = -EBADF; +static long do_fcntl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file * filp) +{ + long err = 0; - filp = fget(fd); - if (!filp) - goto out; - err = 0; - lock_kernel(); switch (cmd) { case F_DUPFD: err = -EINVAL; @@ -228,13 +232,10 @@ } break; case F_GETFD: - err = FD_ISSET(fd, current->files->close_on_exec); + err = get_close_on_exec(fd); break; case F_SETFD: - if (arg&1) - FD_SET(fd, current->files->close_on_exec); - else - FD_CLR(fd, current->files->close_on_exec); + set_close_on_exec(fd, arg&1); break; case F_GETFL: err = filp->f_flags; @@ -287,11 +288,60 @@ err = sock_fcntl (filp, cmd, arg); break; } + + return err; +} + +asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + long err = -EBADF; + + filp = fget(fd); + if (!filp) + goto out; + + lock_kernel(); + err = do_fcntl(fd, cmd, arg, filp); + unlock_kernel(); + + fput(filp); +out: + return err; +} + +#if BITS_PER_LONG == 32 +asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + long err; + + err = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + lock_kernel(); + switch (cmd) { + case F_GETLK64: + err = fcntl_getlk64(fd, (struct flock64 *) arg); + break; + case F_SETLK64: + err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg); + break; + case F_SETLKW64: + err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg); + break; + default: + err = do_fcntl(fd, cmd, arg, filp); + break; + } unlock_kernel(); fput(filp); out: return err; } +#endif /* Table to convert sigio signal codes into poll band bitmaps */ diff -u --recursive --new-file v2.4.0-test6/linux/fs/hfs/dir_cap.c linux/fs/hfs/dir_cap.c --- v2.4.0-test6/linux/fs/hfs/dir_cap.c Sat Feb 26 22:31:52 2000 +++ linux/fs/hfs/dir_cap.c Fri Aug 11 14:29:02 2000 @@ -190,7 +190,7 @@ if (filp->f_pos == 0) { /* Entry 0 is for "." */ - if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) { + if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) { return 0; } filp->f_pos = 1; @@ -207,7 +207,7 @@ } if (filldir(dirent, DOT_DOT->Name, - DOT_DOT_LEN, 1, ntohl(cnid))) { + DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) { return 0; } filp->f_pos = 2; @@ -234,7 +234,7 @@ len = hfs_namein(dir, tmp_name, &((struct hfs_cat_key *)brec.key)->CName); if (filldir(dirent, tmp_name, len, - filp->f_pos, ino)) { + filp->f_pos, ino, DT_UNKNOWN)) { hfs_cat_close(entry, &brec); return 0; } @@ -250,7 +250,8 @@ /* In root dir last-2 entry is for ".rootinfo" */ if (filldir(dirent, DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_CAP_FNDR)) { + ntohl(entry->cnid) | HFS_CAP_FNDR, + DT_UNKNOWN)) { return 0; } } @@ -262,7 +263,8 @@ /* In normal dirs last-1 entry is for ".finderinfo" */ if (filldir(dirent, DOT_FINDERINFO->Name, DOT_FINDERINFO_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_CAP_FDIR)) { + ntohl(entry->cnid) | HFS_CAP_FDIR, + DT_UNKNOWN)) { return 0; } } @@ -274,7 +276,8 @@ /* In normal dirs last entry is for ".resource" */ if (filldir(dirent, DOT_RESOURCE->Name, DOT_RESOURCE_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_CAP_RDIR)) { + ntohl(entry->cnid) | HFS_CAP_RDIR, + DT_UNKNOWN)) { return 0; } } diff -u --recursive --new-file v2.4.0-test6/linux/fs/hfs/dir_dbl.c linux/fs/hfs/dir_dbl.c --- v2.4.0-test6/linux/fs/hfs/dir_dbl.c Sat Feb 26 22:31:52 2000 +++ linux/fs/hfs/dir_dbl.c Fri Aug 11 14:29:02 2000 @@ -183,7 +183,8 @@ if (filp->f_pos == 0) { /* Entry 0 is for "." */ - if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) { + if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, + DT_DIR)) { return 0; } filp->f_pos = 1; @@ -192,7 +193,7 @@ if (filp->f_pos == 1) { /* Entry 1 is for ".." */ if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1, - hfs_get_hl(entry->key.ParID))) { + hfs_get_hl(entry->key.ParID), DT_DIR)) { return 0; } filp->f_pos = 2; @@ -229,7 +230,8 @@ &((struct hfs_cat_key *)brec.key)->CName); } - if (filldir(dirent, tmp_name, len, filp->f_pos, ino)) { + if (filldir(dirent, tmp_name, len, filp->f_pos, ino, + DT_UNKNOWN)) { hfs_cat_close(entry, &brec); return 0; } @@ -243,7 +245,8 @@ /* In root dir last entry is for "%RootInfo" */ if (filldir(dirent, PCNT_ROOTINFO->Name, PCNT_ROOTINFO_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_DBL_HDR)) { + ntohl(entry->cnid) | HFS_DBL_HDR, + DT_UNKNOWN)) { return 0; } } diff -u --recursive --new-file v2.4.0-test6/linux/fs/hfs/dir_nat.c linux/fs/hfs/dir_nat.c --- v2.4.0-test6/linux/fs/hfs/dir_nat.c Sat Feb 26 22:31:52 2000 +++ linux/fs/hfs/dir_nat.c Fri Aug 11 14:29:02 2000 @@ -191,7 +191,8 @@ if (filp->f_pos == 0) { /* Entry 0 is for "." */ - if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino)) { + if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, + DT_DIR)) { return 0; } filp->f_pos = 1; @@ -208,7 +209,7 @@ } if (filldir(dirent, DOT_DOT->Name, - DOT_DOT_LEN, 1, ntohl(cnid))) { + DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) { return 0; } filp->f_pos = 2; @@ -235,7 +236,7 @@ len = hfs_namein(dir, tmp_name, &((struct hfs_cat_key *)brec.key)->CName); if (filldir(dirent, tmp_name, len, - filp->f_pos, ino)) { + filp->f_pos, ino, DT_UNKNOWN)) { hfs_cat_close(entry, &brec); return 0; } @@ -250,14 +251,16 @@ /* In normal dirs entry 2 is for ".AppleDouble" */ if (filldir(dirent, DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_NAT_HDIR)) { + ntohl(entry->cnid) | HFS_NAT_HDIR, + DT_UNKNOWN)) { return 0; } } else if (type == HFS_NAT_HDIR) { /* In .AppleDouble entry 2 is for ".Parent" */ if (filldir(dirent, DOT_PARENT->Name, DOT_PARENT_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_NAT_HDR)) { + ntohl(entry->cnid) | HFS_NAT_HDR, + DT_UNKNOWN)) { return 0; } } @@ -270,7 +273,8 @@ (type == HFS_NAT_HDIR)) { if (filldir(dirent, ROOTINFO->Name, ROOTINFO_LEN, filp->f_pos, - ntohl(entry->cnid) | HFS_NAT_HDR)) { + ntohl(entry->cnid) | HFS_NAT_HDR, + DT_UNKNOWN)) { return 0; } } diff -u --recursive --new-file v2.4.0-test6/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c --- v2.4.0-test6/linux/fs/hpfs/dir.c Fri Jul 14 12:12:14 2000 +++ linux/fs/hpfs/dir.c Fri Aug 11 14:29:01 2000 @@ -108,14 +108,14 @@ return 0; } if (filp->f_pos == 0) { - if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) { + if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) { hpfs_unlock_inode(inode); return 0; } filp->f_pos = 11; } if (filp->f_pos == 11) { - if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) { + if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir, DT_DIR) < 0) { hpfs_unlock_inode(inode); return 0; } @@ -144,7 +144,7 @@ goto again; } tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3); - if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode) < 0) { + if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) { filp->f_pos = old_pos; if (tempname != (char *)de->name) kfree(tempname); hpfs_brelse4(&qbh); diff -u --recursive --new-file v2.4.0-test6/linux/fs/hpfs/hpfs.h linux/fs/hpfs/hpfs.h --- v2.4.0-test6/linux/fs/hpfs/hpfs.h Thu May 13 23:48:20 1999 +++ linux/fs/hpfs/hpfs.h Sun Aug 13 10:22:47 2000 @@ -187,7 +187,9 @@ in data block */ secno code_page_data; /* sector number of a code_page_data containing c.p. array */ - unsigned index; /* index in c.p. array in that sector*/ + unsigned short index; /* index in c.p. array in that sector*/ + unsigned short unknown; /* some unknown value; usually 0; + 2 in Japanese version */ } array[31]; /* unknown length */ }; @@ -207,7 +209,7 @@ struct { unsigned short ix; /* index */ unsigned short code_page_number; /* code page number */ - unsigned short zero1; + unsigned short unknown; /* the same as in cp directory */ unsigned char map[128]; /* upcase table for chars 80..ff */ unsigned short zero2; } code_page[3]; diff -u --recursive --new-file v2.4.0-test6/linux/fs/hpfs/map.c linux/fs/hpfs/map.c --- v2.4.0-test6/linux/fs/hpfs/map.c Thu May 13 23:48:20 1999 +++ linux/fs/hpfs/map.c Sun Aug 13 10:22:47 2000 @@ -59,6 +59,11 @@ cpds = cp->array[0].code_page_data; cpi = cp->array[0].index; brelse(bh); + + if (cpi >= 3) { + printk("HPFS: Code page index out of array\n"); + return NULL; + } if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL; if ((unsigned)cpd->offs[cpi] > 0x178) { diff -u --recursive --new-file v2.4.0-test6/linux/fs/inode.c linux/fs/inode.c --- v2.4.0-test6/linux/fs/inode.c Wed Aug 9 19:19:51 2000 +++ linux/fs/inode.c Thu Aug 17 11:27:25 2000 @@ -771,6 +771,7 @@ list_del(&inode->i_list); INIT_LIST_HEAD(&inode->i_list); inode->i_state|=I_FREEING; + inodes_stat.nr_inodes--; spin_unlock(&inode_lock); if (inode->i_data.nrpages) @@ -799,11 +800,11 @@ list_del(&inode->i_list); INIT_LIST_HEAD(&inode->i_list); inode->i_state|=I_FREEING; + inodes_stat.nr_inodes--; spin_unlock(&inode_lock); clear_inode(inode); } } - inodes_stat.nr_inodes--; destroy_inode(inode); } } diff -u --recursive --new-file v2.4.0-test6/linux/fs/ioctl.c linux/fs/ioctl.c --- v2.4.0-test6/linux/fs/ioctl.c Mon Jul 10 16:47:25 2000 +++ linux/fs/ioctl.c Sat Aug 12 19:48:04 2000 @@ -58,11 +58,11 @@ lock_kernel(); switch (cmd) { case FIOCLEX: - FD_SET(fd, current->files->close_on_exec); + set_close_on_exec(fd, 1); break; case FIONCLEX: - FD_CLR(fd, current->files->close_on_exec); + set_close_on_exec(fd, 0); break; case FIONBIO: diff -u --recursive --new-file v2.4.0-test6/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- v2.4.0-test6/linux/fs/isofs/dir.c Thu May 11 15:30:08 2000 +++ linux/fs/isofs/dir.c Fri Aug 11 14:29:01 2000 @@ -202,7 +202,7 @@ /* Handle the case of the '.' directory */ if (de->name_len[0] == 1 && de->name[0] == 0) { - if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) break; filp->f_pos += de_len; continue; @@ -213,7 +213,7 @@ /* Handle the case of the '..' directory */ if (de->name_len[0] == 1 && de->name[0] == 1) { inode_number = filp->f_dentry->d_parent->d_inode->i_ino; - if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0) + if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0) break; filp->f_pos += de_len; continue; @@ -258,7 +258,7 @@ } } if (len > 0) { - if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0) + if (filldir(dirent, p, len, filp->f_pos, inode_number, DT_UNKNOWN) < 0) break; } filp->f_pos += de_len; diff -u --recursive --new-file v2.4.0-test6/linux/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c --- v2.4.0-test6/linux/fs/jffs/inode-v23.c Wed Aug 9 19:19:51 2000 +++ linux/fs/jffs/inode-v23.c Fri Aug 11 14:29:03 2000 @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: inode-v23.c,v 1.33 2000/08/09 15:59:06 dwmw2 Exp $ + * $Id: inode-v23.c,v 1.34 2000/08/10 08:58:00 dwmw2 Exp $ * * * Ported to Linux 2.3.x and MTD: @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -350,7 +349,7 @@ inode->i_mtime = raw_inode->mtime; inode->i_ctime = raw_inode->ctime; inode->i_blksize = PAGE_SIZE; - inode->i_blocks = (raw_inode->dsize + PAGE_SIZE - 1) >> PAGE_SHIFT; + inode->i_blocks = (inode->i_size + 511) >> 9; inode->i_version = 0; inode->i_flags = sb->s_flags; inode->u.generic_ip = (void *)jffs_find_file(c, raw_inode->ino); @@ -558,7 +557,7 @@ D2(printk("jffs_readdir(): inode: 0x%p, filp: 0x%p\n", inode, filp)); if (filp->f_pos == 0) { D3(printk("jffs_readdir(): \".\" %lu\n", inode->i_ino)); - if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) { + if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) { return 0; } filp->f_pos = 1; @@ -572,7 +571,7 @@ inode->u.generic_ip)->pino; } D3(printk("jffs_readdir(): \"..\" %u\n", ddino)); - if (filldir(dirent, "..", 2, filp->f_pos, ddino) < 0) + if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) return 0; filp->f_pos++; } @@ -584,7 +583,7 @@ D3(printk("jffs_readdir(): \"%s\" ino: %u\n", (f->name ? f->name : ""), f->ino)); if (filldir(dirent, f->name, f->nsize, - filp->f_pos , f->ino) < 0) + filp->f_pos , f->ino, DT_UNKNOWN) < 0) return 0; filp->f_pos++; } @@ -1571,7 +1570,7 @@ inode->i_mtime = f->mtime; inode->i_ctime = f->ctime; inode->i_blksize = PAGE_SIZE; - inode->i_blocks = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + inode->i_blocks = (inode->i_size + 511) >> 9; if (S_ISREG(inode->i_mode)) { inode->i_op = &jffs_file_inode_operations; inode->i_fop = &jffs_file_operations; diff -u --recursive --new-file v2.4.0-test6/linux/fs/locks.c linux/fs/locks.c --- v2.4.0-test6/linux/fs/locks.c Mon Jul 10 16:47:26 2000 +++ linux/fs/locks.c Mon Aug 21 07:33:59 2000 @@ -103,6 +103,11 @@ * * Fixed /proc/locks interface so that we can't overrun the buffer we are handed. * Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997. + * + * Use slab allocator instead of kmalloc/kfree. + * Use generic list implementation from . + * Sped up posix_locks_deadlock by only considering blocked locks. + * Matthew Wilcox , March, 2000. */ #include @@ -205,8 +210,58 @@ /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX * style lock. */ -static int posix_make_lock(struct file *filp, struct file_lock *fl, - struct flock *l) +static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock *l) +{ + loff_t start; + + switch (l->l_whence) { + case 0: /*SEEK_SET*/ + start = 0; + break; + case 1: /*SEEK_CUR*/ + start = filp->f_pos; + break; + case 2: /*SEEK_END*/ + start = filp->f_dentry->d_inode->i_size; + break; + default: + return (0); + } + + if (((start += l->l_start) < 0) || (l->l_len < 0)) + return (0); + fl->fl_end = start + l->l_len - 1; + if (l->l_len > 0 && fl->fl_end < 0) + return (0); + fl->fl_start = start; /* we record the absolute position */ + if (l->l_len == 0) + fl->fl_end = OFFSET_MAX; + + fl->fl_owner = current->files; + fl->fl_pid = current->pid; + fl->fl_file = filp; + fl->fl_flags = FL_POSIX; + fl->fl_notify = NULL; + fl->fl_insert = NULL; + fl->fl_remove = NULL; + + switch (l->l_type) { + case F_RDLCK: + case F_WRLCK: + case F_UNLCK: + fl->fl_type = l->l_type; + break; + default: + return (0); + } + + return (1); +} + +#if BITS_PER_LONG == 32 +static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock64 *l) { loff_t start; @@ -253,6 +308,7 @@ return (1); } +#endif /* Check if two locks overlap each other. */ @@ -300,8 +356,8 @@ locks_delete_block(waiter); } list_add_tail(&waiter->fl_block, &blocker->fl_block); -// list_add(&waiter->fl_link, &blocked_list); -// waiter->fl_next = blocker; + list_add(&waiter->fl_link, &blocked_list); + waiter->fl_next = blocker; } /* Wake up processes blocked waiting for blocker. @@ -460,34 +516,27 @@ struct file_lock *block_fl) { struct list_head *tmp; - void *caller_owner, *blocked_owner; + fl_owner_t caller_owner, blocked_owner; unsigned int caller_pid, blocked_pid; caller_owner = caller_fl->fl_owner; caller_pid = caller_fl->fl_pid; blocked_owner = block_fl->fl_owner; blocked_pid = block_fl->fl_pid; + tmp = blocked_list.next; next_task: if (caller_owner == blocked_owner && caller_pid == blocked_pid) return 1; - list_for_each(tmp, &file_lock_list) { - struct list_head *btmp; + while (tmp != &blocked_list) { struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - if (fl->fl_owner == NULL || list_empty(&fl->fl_block)) - continue; - list_for_each(btmp, &fl->fl_block) { - struct file_lock *bfl = list_entry(tmp, struct file_lock, fl_block); - if (bfl->fl_owner == blocked_owner && - bfl->fl_pid == blocked_pid) { - if (fl->fl_owner == caller_owner && - fl->fl_pid == caller_pid) { - return (1); - } - blocked_owner = fl->fl_owner; - blocked_pid = fl->fl_pid; - goto next_task; - } + tmp = tmp->next; + if ((fl->fl_owner == blocked_owner) + && (fl->fl_pid == blocked_pid)) { + fl = fl->fl_next; + blocked_owner = fl->fl_owner; + blocked_pid = fl->fl_pid; + goto next_task; } } return 0; @@ -816,13 +865,12 @@ if (right) { if (left == right) { /* The new lock breaks the old one in two pieces, - * so we have to use the second new lock (in this - * case, even F_UNLCK may fail!). + * so we have to use the second new lock. */ - locks_copy_lock(new_fl2, right); - locks_insert_lock(before, left); left = new_fl2; new_fl2 = NULL; + locks_copy_lock(left, right); + locks_insert_lock(before, left); } right->fl_start = caller->fl_end + 1; locks_wake_up_blocks(right, 0); @@ -909,7 +957,8 @@ if (!filp) goto out; - if (!posix_make_lock(filp, file_lock, &flock)) + error = -EINVAL; + if (!flock_to_posix_lock(filp, file_lock, &flock)) goto out_putf; if (filp->f_op->lock) { @@ -928,6 +977,18 @@ flock.l_type = F_UNLCK; if (fl != NULL) { flock.l_pid = fl->fl_pid; +#if BITS_PER_LONG == 32 + /* + * Make sure we can represent the posix lock via + * legacy 32bit flock. + */ + error = -EOVERFLOW; + if (fl->fl_start > OFFT_OFFSET_MAX) + goto out_putf; + if ((fl->fl_end != OFFSET_MAX) + && (fl->fl_end > OFFT_OFFSET_MAX)) + goto out_putf; +#endif flock.l_start = fl->fl_start; flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : fl->fl_end - fl->fl_start + 1; @@ -993,7 +1054,7 @@ } error = -EINVAL; - if (!posix_make_lock(filp, file_lock, &flock)) + if (!flock_to_posix_lock(filp, file_lock, &flock)) goto out_putf; error = -EBADF; @@ -1043,6 +1104,151 @@ locks_free_lock(file_lock); return error; } + +#if BITS_PER_LONG == 32 +/* Report the first existing lock that would conflict with l. + * This implements the F_GETLK command of fcntl(). + */ +int fcntl_getlk64(unsigned int fd, struct flock64 *l) +{ + struct file *filp; + struct file_lock *fl, *file_lock = locks_alloc_lock(); + struct flock64 flock; + int error; + + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + error = -EINVAL; + if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) + goto out; + + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + if (!flock64_to_posix_lock(filp, file_lock, &flock)) + goto out_putf; + + if (filp->f_op->lock) { + error = filp->f_op->lock(filp, F_GETLK, file_lock); + if (error < 0) + goto out_putf; + else if (error == LOCK_USE_CLNT) + /* Bypass for NFS with no locking - 2.0.36 compat */ + fl = posix_test_lock(filp, file_lock); + else + fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock); + } else { + fl = posix_test_lock(filp, file_lock); + } + + flock.l_type = F_UNLCK; + if (fl != NULL) { + flock.l_pid = fl->fl_pid; + flock.l_start = fl->fl_start; + flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : + fl->fl_end - fl->fl_start + 1; + flock.l_whence = 0; + flock.l_type = fl->fl_type; + } + error = -EFAULT; + if (!copy_to_user(l, &flock, sizeof(flock))) + error = 0; + +out_putf: + fput(filp); +out: + locks_free_lock(file_lock); + return error; +} + +/* Apply the lock described by l to an open file descriptor. + * This implements both the F_SETLK and F_SETLKW commands of fcntl(). + */ +int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) +{ + struct file *filp; + struct file_lock *file_lock = locks_alloc_lock(); + struct flock64 flock; + struct inode *inode; + int error; + + /* + * This might block, so we do it before checking the inode. + */ + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + + /* Get arguments and validate them ... + */ + + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + inode = filp->f_dentry->d_inode; + + /* Don't allow mandatory locks on files that may be memory mapped + * and shared. + */ + if (IS_MANDLOCK(inode) && + (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { + struct vm_area_struct *vma; + struct address_space *mapping = inode->i_mapping; + spin_lock(&mapping->i_shared_lock); + for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) { + if (!(vma->vm_flags & VM_MAYSHARE)) + continue; + spin_unlock(&mapping->i_shared_lock); + error = -EAGAIN; + goto out_putf; + } + spin_unlock(&mapping->i_shared_lock); + } + + error = -EINVAL; + if (!flock64_to_posix_lock(filp, file_lock, &flock)) + goto out_putf; + + error = -EBADF; + switch (flock.l_type) { + case F_RDLCK: + if (!(filp->f_mode & FMODE_READ)) + goto out_putf; + break; + case F_WRLCK: + if (!(filp->f_mode & FMODE_WRITE)) + goto out_putf; + break; + case F_UNLCK: + break; + case F_SHLCK: + case F_EXLCK: + default: + error = -EINVAL; + goto out_putf; + } + + if (filp->f_op->lock != NULL) { + error = filp->f_op->lock(filp, cmd, file_lock); + if (error < 0) + goto out_putf; + } + error = posix_lock_file(filp, file_lock, cmd == F_SETLKW); + +out_putf: + fput(filp); +out: + locks_free_lock(file_lock); + return error; +} +#endif /* BITS_PER_LONG == 32 */ /* * This function is called when the file is being removed diff -u --recursive --new-file v2.4.0-test6/linux/fs/minix/dir.c linux/fs/minix/dir.c --- v2.4.0-test6/linux/fs/minix/dir.c Sat Feb 26 22:31:53 2000 +++ linux/fs/minix/dir.c Fri Aug 11 14:29:01 2000 @@ -43,7 +43,7 @@ de = (struct minix_dir_entry *) (offset + bh->b_data); if (de->inode) { int size = strnlen(de->name, info->s_namelen); - if (filldir(dirent, de->name, size, filp->f_pos, de->inode) < 0) { + if (filldir(dirent, de->name, size, filp->f_pos, de->inode, DT_UNKNOWN) < 0) { brelse(bh); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/namei.c linux/fs/namei.c --- v2.4.0-test6/linux/fs/namei.c Wed Aug 9 19:19:51 2000 +++ linux/fs/namei.c Thu Aug 10 12:44:59 2000 @@ -1690,7 +1690,8 @@ triple_up(&old_dir->i_zombie, &new_dir->i_zombie, &target->i_zombie); - d_rehash(new_dentry); + if (d_unhashed(new_dentry)) + d_rehash(new_dentry); dput(new_dentry); } else double_up(&old_dir->i_zombie, diff -u --recursive --new-file v2.4.0-test6/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c --- v2.4.0-test6/linux/fs/ncpfs/dir.c Mon Jul 10 16:47:26 2000 +++ linux/fs/ncpfs/dir.c Fri Aug 11 14:29:01 2000 @@ -446,13 +446,13 @@ result = 0; if (filp->f_pos == 0) { - if (filldir(dirent, ".", 1, 0, inode->i_ino)) + if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) goto out; filp->f_pos = 1; } if (filp->f_pos == 1) { if (filldir(dirent, "..", 2, 1, - dentry->d_parent->d_inode->i_ino)) + dentry->d_parent->d_inode->i_ino, DT_DIR)) goto out; filp->f_pos = 2; } @@ -503,7 +503,7 @@ goto invalid_cache; res = filldir(dirent, dent->d_name.name, dent->d_name.len, filp->f_pos, - dent->d_inode->i_ino); + dent->d_inode->i_ino, DT_UNKNOWN); dput(dent); if (res) goto finished; @@ -650,7 +650,7 @@ if (!ino) ino = iunique(inode->i_sb, 2); ctl.filled = filldir(dirent, qname.name, qname.len, - filp->f_pos, ino); + filp->f_pos, ino, DT_UNKNOWN); if (!ctl.filled) filp->f_pos += 1; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.4.0-test6/linux/fs/nfs/dir.c Mon Jul 10 16:47:26 2000 +++ linux/fs/nfs/dir.c Mon Aug 21 13:00:25 2000 @@ -264,7 +264,7 @@ * retrieving the current dirent on the server */ fileid = nfs_fileid_to_ino_t(entry->ino); res = filldir(dirent, entry->name, entry->len, - entry->prev_cookie, fileid); + entry->prev_cookie, fileid, DT_UNKNOWN); if (res < 0) break; file->f_pos = desc->target = entry->cookie; @@ -890,9 +890,8 @@ struct inode *inode = dentry->d_inode; int error = -EBUSY, rehash = 0; - dfprintk(VFS, "NFS: safe_remove(%s/%s, %ld)\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino); + dfprintk(VFS, "NFS: safe_remove(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); /* * Unhash the dentry while we remove the file ... @@ -910,7 +909,8 @@ goto out; } nfs_zap_caches(dir_i); - NFS_CACHEINV(inode); + if (inode) + NFS_CACHEINV(inode); error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name); if (error < 0) goto out; diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.4.0-test6/linux/fs/nfs/inode.c Wed Aug 9 19:19:51 2000 +++ linux/fs/nfs/inode.c Mon Aug 21 13:00:25 2000 @@ -402,9 +402,6 @@ server->rsize = nfs_block_size(fsinfo.rtpref, NULL); if (data->wsize == 0) server->wsize = nfs_block_size(fsinfo.wtpref, NULL); - server->dtsize = nfs_block_size(fsinfo.dtpref, NULL); - if (server->dtsize > PAGE_CACHE_SIZE) - server->dtsize = PAGE_CACHE_SIZE; /* NFSv3: we don't have bsize, but rather rtmult and wtmult... */ if (!fsinfo.bsize) fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult; @@ -433,6 +430,12 @@ server->wpages = NFS_WRITE_MAXIOV; server->wsize = server->wpages << PAGE_CACHE_SHIFT; } + + server->dtsize = nfs_block_size(fsinfo.dtpref, NULL); + if (server->dtsize > PAGE_CACHE_SIZE) + server->dtsize = PAGE_CACHE_SIZE; + if (server->dtsize > server->rsize) + server->dtsize = server->rsize; maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN; diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.4.0-test6/linux/fs/nfs/proc.c Fri Jun 23 21:55:10 2000 +++ linux/fs/nfs/proc.c Mon Aug 21 13:00:25 2000 @@ -321,11 +321,7 @@ struct nfs_readdirargs arg; struct nfs_readdirres res; struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred }; - struct nfs_server *server = NFS_DSERVER(dir); int status; - - if (server->rsize < size) - size = server->rsize; arg.fh = NFS_FH(dir); arg.cookie = cookie; diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.4.0-test6/linux/fs/nfs/write.c Mon Jun 19 16:32:00 2000 +++ linux/fs/nfs/write.c Sat Aug 12 12:05:17 2000 @@ -1291,7 +1291,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) { - struct nfs_page *req; + struct nfs_page *first, *last; struct dentry *dentry; struct inode *inode; loff_t start, end, len; @@ -1299,32 +1299,28 @@ /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ - end = 0; - start = ~0; - req = nfs_list_entry(head->next); - dentry = req->wb_dentry; - data->dentry = dentry; - data->cred = req->wb_cred; + list_splice(head, &data->pages); + INIT_LIST_HEAD(head); + first = nfs_list_entry(data->pages.next); + last = nfs_list_entry(data->pages.prev); + dentry = first->wb_dentry; inode = dentry->d_inode; - while (!list_empty(head)) { - struct nfs_page *req; - loff_t rqstart, rqend; - req = nfs_list_entry(head->next); - nfs_list_remove_request(req); - nfs_list_add_request(req, &data->pages); - rqstart = page_offset(req->wb_page) + req->wb_offset; - rqend = rqstart + req->wb_bytes; - if (rqstart < start) - start = rqstart; - if (rqend > end) - end = rqend; - } - data->args.fh = NFS_FH(dentry); - data->args.offset = start; + + /* + * Determine the offset range of requests in the COMMIT call. + * We rely on the fact that data->pages is an ordered list... + */ + start = page_offset(first->wb_page) + first->wb_offset; + end = page_offset(last->wb_page) + (last->wb_offset + last->wb_bytes); len = end - start; /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */ - if (end >= inode->i_size || len > (~((u32)0) >> 1)) + if (end >= inode->i_size || len < 0 || len > (~((u32)0) >> 1)) len = 0; + + data->dentry = dentry; + data->cred = first->wb_cred; + data->args.fh = NFS_FH(dentry); + data->args.offset = start; data->res.count = data->args.count = (u32)len; data->res.fattr = &data->fattr; data->res.verf = &data->verf; diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c --- v2.4.0-test6/linux/fs/nfsd/nfs3xdr.c Fri Jun 23 21:55:10 2000 +++ linux/fs/nfsd/nfs3xdr.c Fri Aug 11 14:29:02 2000 @@ -669,7 +669,7 @@ #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) static int encode_entry(struct readdir_cd *cd, const char *name, - int namlen, off_t offset, ino_t ino, int plus) + int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus) { u32 *p = cd->buffer; int buflen, slen, elen; @@ -747,16 +747,16 @@ int nfs3svc_encode_entry(struct readdir_cd *cd, const char *name, - int namlen, off_t offset, ino_t ino) + int namlen, off_t offset, ino_t ino, unsigned int d_type) { - return encode_entry(cd, name, namlen, offset, ino, 0); + return encode_entry(cd, name, namlen, offset, ino, d_type, 0); } int nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name, - int namlen, off_t offset, ino_t ino) + int namlen, off_t offset, ino_t ino, unsigned int d_type) { - return encode_entry(cd, name, namlen, offset, ino, 1); + return encode_entry(cd, name, namlen, offset, ino, d_type, 1); } /* FSSTAT */ diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.4.0-test6/linux/fs/nfsd/nfsfh.c Mon Jul 10 16:47:26 2000 +++ linux/fs/nfsd/nfsfh.c Fri Aug 11 14:29:02 2000 @@ -41,7 +41,7 @@ * the name matching the specified inode number. */ static int filldir_one(void * __buf, const char * name, int len, - off_t pos, ino_t ino) + off_t pos, ino_t ino, unsigned int d_type) { struct nfsd_getdents_callback *buf = __buf; struct qstr *qs = buf->name; diff -u --recursive --new-file v2.4.0-test6/linux/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c --- v2.4.0-test6/linux/fs/nfsd/nfsxdr.c Fri Jun 23 21:55:10 2000 +++ linux/fs/nfsd/nfsxdr.c Fri Aug 11 14:29:02 2000 @@ -390,7 +390,7 @@ int nfssvc_encode_entry(struct readdir_cd *cd, const char *name, - int namlen, off_t offset, ino_t ino) + int namlen, off_t offset, ino_t ino, unsigned int d_type) { u32 *p = cd->buffer; int buflen, slen; diff -u --recursive --new-file v2.4.0-test6/linux/fs/nls/Config.in linux/fs/nls/Config.in --- v2.4.0-test6/linux/fs/nls/Config.in Thu Jul 27 17:38:01 2000 +++ linux/fs/nls/Config.in Thu Aug 17 23:34:28 2000 @@ -4,7 +4,8 @@ # msdos and Joliet want NLS if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \ - -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then + -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \ + -o "$CONFIG_SMB_FS" != "n" ]; then define_bool CONFIG_NLS y else define_bool CONFIG_NLS n diff -u --recursive --new-file v2.4.0-test6/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c --- v2.4.0-test6/linux/fs/ntfs/fs.c Thu Jul 27 17:38:02 2000 +++ linux/fs/ntfs/fs.c Fri Aug 11 14:29:02 2000 @@ -200,7 +200,7 @@ /* filldir expects an off_t rather than an loff_t. Hope we don't have more than 65535 index records */ error=nf->filldir(nf->dirent,nf->name,nf->namelen, - (nf->ph<<16)|nf->pl,inum); + (nf->ph<<16)|nf->pl,inum,DT_UNKNOWN); ntfs_free(nf->name); /* Linux filldir errors are negative, other errors positive */ return error; @@ -226,11 +226,11 @@ if(cb.ph==0xFFFF){ /* FIXME: Maybe we can return those with the previous call */ switch(cb.pl){ - case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino); + case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino,DT_DIR); filp->f_pos=0xFFFF0001; return 0; /* FIXME: parent directory */ - case 1: filldir(dirent,"..",2,filp->f_pos,0); + case 1: filldir(dirent,"..",2,filp->f_pos,0,DT_DIR); filp->f_pos=0xFFFF0002; return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/open.c linux/fs/open.c --- v2.4.0-test6/linux/fs/open.c Wed Aug 9 19:19:51 2000 +++ linux/fs/open.c Fri Aug 11 15:16:21 2000 @@ -680,7 +680,7 @@ repeat: fd = find_next_zero_bit(files->open_fds, - current->files->max_fdset, + files->max_fdset, files->next_fd); /* @@ -691,7 +691,7 @@ goto out; /* Do we need to expand the fdset array? */ - if (fd >= current->files->max_fdset) { + if (fd >= files->max_fdset) { error = expand_fdset(files, fd); if (!error) { error = -EMFILE; @@ -799,36 +799,27 @@ * Careful here! We test whether the file pointer is NULL before * releasing the fd. This ensures that one clone task can't release * an fd while another clone is opening it. - * - * The "release" argument tells us whether or not to mark the fd as free - * or not in the open-files bitmap. dup2 uses this to retain the fd - * without races. */ -int do_close(struct files_struct *files, unsigned int fd, int release) +asmlinkage long sys_close(unsigned int fd) { - int error; struct file * filp; + struct files_struct *files = current->files; - error = -EBADF; write_lock(&files->file_lock); - filp = frip(files, fd); + if (fd >= files->max_fds) + goto out_unlock; + filp = files->fd[fd]; if (!filp) goto out_unlock; + files->fd[fd] = NULL; FD_CLR(fd, files->close_on_exec); - if (release) - __put_unused_fd(files, fd); + __put_unused_fd(files, fd); write_unlock(&files->file_lock); - error = filp_close(filp, files); -out: - return error; + return filp_close(filp, files); + out_unlock: write_unlock(&files->file_lock); - goto out; -} - -asmlinkage long sys_close(unsigned int fd) -{ - return do_close(current->files, fd, 1); + return -EBADF; } /* diff -u --recursive --new-file v2.4.0-test6/linux/fs/openpromfs/inode.c linux/fs/openpromfs/inode.c --- v2.4.0-test6/linux/fs/openpromfs/inode.c Thu Jul 27 17:38:02 2000 +++ linux/fs/openpromfs/inode.c Sat Aug 12 12:08:50 2000 @@ -1,4 +1,4 @@ -/* $Id: inode.c,v 1.12 2000/07/13 08:06:42 davem Exp $ +/* $Id: inode.c,v 1.13 2000/08/12 13:25:46 davem Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) @@ -757,14 +757,14 @@ i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, ino) < 0) return 0; + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall thru */ case 1: if (filldir(dirent, "..", 2, i, (NODE(ino).parent == 0xffff) ? - OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent)) < 0) + OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0) return 0; i++; filp->f_pos++; @@ -780,14 +780,14 @@ if (prom_getname (nodes[node].node, buffer, 128) < 0) return 0; if (filldir(dirent, buffer, strlen(buffer), - filp->f_pos, NODE2INO(node)) < 0) + filp->f_pos, NODE2INO(node), DT_DIR) < 0) return 0; filp->f_pos++; node = nodes[node].next; } j = NODEP2INO(NODE(ino).first_prop); if (!i) { - if (filldir(dirent, ".node", 5, filp->f_pos, j) < 0) + if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0) return 0; filp->f_pos++; } else @@ -798,7 +798,7 @@ if (alias_names [i]) { if (filldir (dirent, alias_names [i], strlen (alias_names [i]), - filp->f_pos, j) < 0) return 0; + filp->f_pos, j, DT_REG) < 0) return 0; filp->f_pos++; } } @@ -810,7 +810,7 @@ if (i) i--; else { if (filldir(dirent, p, strlen(p), - filp->f_pos, j) < 0) + filp->f_pos, j, DT_REG) < 0) return 0; filp->f_pos++; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/pipe.c linux/fs/pipe.c --- v2.4.0-test6/linux/fs/pipe.c Fri Jul 14 12:12:14 2000 +++ linux/fs/pipe.c Fri Aug 11 05:54:13 2000 @@ -545,9 +545,9 @@ this.len = strlen(name); this.hash = inode->i_ino; /* will go */ dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this); - dentry->d_op = &pipefs_dentry_operations; if (!dentry) goto close_f12_inode_i_j; + dentry->d_op = &pipefs_dentry_operations; d_add(dentry, inode); f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt)); f1->f_dentry = f2->f_dentry = dget(dentry); diff -u --recursive --new-file v2.4.0-test6/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.4.0-test6/linux/fs/proc/array.c Wed Aug 9 19:19:51 2000 +++ linux/fs/proc/array.c Sat Aug 12 20:00:03 2000 @@ -301,12 +301,11 @@ { unsigned long vsize, eip, esp, wchan; long priority, nice; - int tty_pgrp; + int tty_pgrp = -1, tty_nr = 0; sigset_t sigign, sigcatch; char state; int res; pid_t ppid; - int tty_nr; struct mm_struct *mm; state = *get_task_state(task); @@ -315,6 +314,10 @@ mm = task->mm; if(mm) atomic_inc(&mm->mm_users); + if (task->tty) { + tty_pgrp = task->tty->pgrp; + tty_nr = kdev_t_to_nr(task->tty->device); + } task_unlock(task); if (mm) { struct vm_area_struct *vma; @@ -332,14 +335,6 @@ wchan = get_wchan(task); collect_sigign_sigcatch(task, &sigign, &sigcatch); - - task_lock(task); - if (task->tty) - tty_pgrp = task->tty->pgrp; - else - tty_pgrp = -1; - tty_nr = task->tty ? kdev_t_to_nr(task->tty->device) : 0; - task_unlock(task); /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" Unix priority/nice value */ diff -u --recursive --new-file v2.4.0-test6/linux/fs/proc/base.c linux/fs/proc/base.c --- v2.4.0-test6/linux/fs/proc/base.c Mon Jul 10 16:47:26 2000 +++ linux/fs/proc/base.c Fri Aug 11 14:29:01 2000 @@ -522,12 +522,12 @@ fd = filp->f_pos; switch (fd) { case 0: - if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) goto out; filp->f_pos++; case 1: ino = fake_ino(pid, PROC_PID_INO); - if (filldir(dirent, "..", 2, 1, ino) < 0) + if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) goto out; filp->f_pos++; default: @@ -555,7 +555,7 @@ } while (i); ino = fake_ino(pid, PROC_PID_FD_DIR + fd); - if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0) + if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) break; } put_files_struct(files); @@ -578,13 +578,13 @@ i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, i, inode->i_ino, DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall through */ case 1: - if (filldir(dirent, "..", 2, i, PROC_ROOT_INO) < 0) + if (filldir(dirent, "..", 2, i, PROC_ROOT_INO, DT_DIR) < 0) return 0; i++; filp->f_pos++; @@ -595,7 +595,8 @@ return 1; p = base_stuff + i; while (p->name) { - if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type)) < 0) + if (filldir(dirent, p->name, p->len, filp->f_pos, + fake_ino(pid, p->type), p->mode >> 12) < 0) return 0; filp->f_pos++; p++; @@ -1007,7 +1008,7 @@ if (!nr) { ino_t ino = fake_ino(0,PROC_PID_INO); - if (filldir(dirent, "self", 4, filp->f_pos, ino) < 0) + if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0) return 0; filp->f_pos++; nr++; @@ -1022,7 +1023,7 @@ do buf[--j] = '0' + (pid % 10); while (pid/=10); - if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0) + if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) break; filp->f_pos++; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/proc/generic.c linux/fs/proc/generic.c --- v2.4.0-test6/linux/fs/proc/generic.c Fri Jun 23 21:55:10 2000 +++ linux/fs/proc/generic.c Fri Aug 11 14:29:01 2000 @@ -294,15 +294,15 @@ i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, ino) < 0) + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall through */ case 1: if (filldir(dirent, "..", 2, i, - filp->f_dentry->d_parent->d_inode->i_ino - ) < 0) + filp->f_dentry->d_parent->d_inode->i_ino, + DT_DIR) < 0) return 0; i++; filp->f_pos++; @@ -320,7 +320,8 @@ } do { - if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0) + if (filldir(dirent, de->name, de->namelen, filp->f_pos, + de->low_ino, de->mode >> 12) < 0) return 0; filp->f_pos++; de = de->next; diff -u --recursive --new-file v2.4.0-test6/linux/fs/qnx4/dir.c linux/fs/qnx4/dir.c --- v2.4.0-test6/linux/fs/qnx4/dir.c Sat Feb 26 22:31:54 2000 +++ linux/fs/qnx4/dir.c Fri Aug 11 14:29:02 2000 @@ -62,7 +62,7 @@ QNX4_INODES_PER_BLOCK + le->dl_inode_ndx; } - if (filldir(dirent, de->di_fname, size, filp->f_pos, ino) < 0) { + if (filldir(dirent, de->di_fname, size, filp->f_pos, ino, DT_UNKNOWN) < 0) { brelse(bh); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/readdir.c linux/fs/readdir.c --- v2.4.0-test6/linux/fs/readdir.c Mon Jul 10 16:47:26 2000 +++ linux/fs/readdir.c Fri Aug 11 14:29:01 2000 @@ -13,9 +13,7 @@ #include -int vfs_readdir(struct file *file, - int (*filler)(void *,const char *,int,off_t,ino_t), - void *buf) +int vfs_readdir(struct file *file, filldir_t filler, void *buf) { struct inode *inode = file->f_dentry->d_inode; int res = -ENOTDIR; @@ -49,13 +47,13 @@ i = filp->f_pos; switch (i) { case 0: - if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino) < 0) + if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0) break; i++; filp->f_pos++; /* fallthrough */ case 1: - if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino) < 0) + if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) break; i++; filp->f_pos++; @@ -83,7 +81,7 @@ if (!list_empty(&de->d_hash) && de->d_inode) { spin_unlock(&dcache_lock); - if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino) < 0) + if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0) break; spin_lock(&dcache_lock); } @@ -124,7 +122,8 @@ int count; }; -static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, + ino_t ino, unsigned int d_type) { struct readdir_callback * buf = (struct readdir_callback *) __buf; struct old_linux_dirent * dirent; @@ -184,7 +183,8 @@ int error; }; -static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +static int filldir(void * __buf, const char * name, int namlen, off_t offset, + ino_t ino, unsigned int d_type) { struct linux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; @@ -240,3 +240,89 @@ out: return error; } + +/* + * And even better one including d_type field and 64bit d_ino and d_off. + */ +struct linux_dirent64 { + u64 d_ino; + s64 d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +}; + +#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) + +struct getdents_callback64 { + struct linux_dirent64 * current_dir; + struct linux_dirent64 * previous; + int count; + int error; +}; + +static int filldir64(void * __buf, const char * name, int namlen, off_t offset, + ino_t ino, unsigned int d_type) +{ + struct linux_dirent64 * dirent, d; + struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; + int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) { + d.d_off = offset; + copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off)); + } + dirent = buf->current_dir; + buf->previous = dirent; + memset(&d, 0, NAME_OFFSET(&d)); + d.d_ino = ino; + d.d_reclen = reclen; + d.d_type = d_type; + copy_to_user(dirent, &d, NAME_OFFSET(&d)); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +} + +asmlinkage long sys_getdents64(unsigned int fd, void * dirent, unsigned int count) +{ + struct file * file; + struct linux_dirent64 * lastdirent; + struct getdents_callback64 buf; + int error; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + buf.current_dir = (struct linux_dirent64 *) dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = vfs_readdir(file, filldir64, &buf); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + struct linux_dirent64 d; + d.d_off = file->f_pos; + copy_to_user(&lastdirent->d_off, &d.d_off, sizeof(d.d_off)); + error = count - buf.count; + } + +out_putf: + fput(file); +out: + return error; +} + diff -u --recursive --new-file v2.4.0-test6/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.4.0-test6/linux/fs/romfs/inode.c Wed Aug 9 19:19:51 2000 +++ linux/fs/romfs/inode.c Fri Aug 11 14:29:02 2000 @@ -254,6 +254,10 @@ return res; } +static unsigned char romfs_dtype_table[] = { + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO +}; + static int romfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { @@ -298,7 +302,8 @@ nextfh = ntohl(ri.next); if ((nextfh & ROMFH_TYPE) == ROMFH_HRD) ino = ntohl(ri.spec); - if (filldir(dirent, fsname, j, offset, ino) < 0) { + if (filldir(dirent, fsname, j, offset, ino, + romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) { return stored; } stored++; diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog --- v2.4.0-test6/linux/fs/smbfs/ChangeLog Thu Jul 27 17:38:02 2000 +++ linux/fs/smbfs/ChangeLog Mon Aug 14 13:31:10 2000 @@ -1,5 +1,16 @@ ChangeLog for smbfs. +2000-08-14 Urban Widmark + + * dir.c: support case sensitive shares + * inode.c: ascii mount options + * proc.c: check length of paths to avoid buffer overflow + * proc.c: don't do interruptable_sleep in smb_retry to avoid signal + problem/race. + * proc.c: O_RDONLY & smb_revalidate_inode fix (tail -f) + * proc.c: add nls support + * sock.c: attempt to fix smb_data_callback (avoid infinite loop) + 2000-07-25 Urban Widmark * proc.c: fix 3 places where bad server responses could cause an Oops. diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile --- v2.4.0-test6/linux/fs/smbfs/Makefile Thu Jul 27 17:38:02 2000 +++ linux/fs/smbfs/Makefile Mon Aug 14 13:31:10 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := smbfs.o -O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o +O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o M_OBJS := $(O_TARGET) # If you want debugging output, you may add these flags to the EXTRA_CFLAGS diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v2.4.0-test6/linux/fs/smbfs/dir.c Thu Jul 27 17:38:02 2000 +++ linux/fs/smbfs/dir.c Mon Aug 14 13:31:10 2000 @@ -14,6 +14,7 @@ #include #include +#include #include #include "smb_debug.h" @@ -66,12 +67,12 @@ switch ((unsigned int) filp->f_pos) { case 0: - if (filldir(dirent, ".", 1, 0, dir->i_ino) < 0) + if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) goto out; filp->f_pos = 1; case 1: if (filldir(dirent, "..", 2, 1, - dentry->d_parent->d_inode->i_ino) < 0) + dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) goto out; filp->f_pos = 2; } @@ -127,7 +128,7 @@ } if (filldir(dirent, entry->name, entry->len, - filp->f_pos, entry->ino) < 0) + filp->f_pos, entry->ino, DT_UNKNOWN) < 0) break; filp->f_pos += 1; } @@ -142,7 +143,7 @@ } /* - * Note: in order to allow the smbclient process to open the + * Note: in order to allow the smbmount process to open the * mount point, we don't revalidate if conn_pid is NULL. */ static int @@ -190,6 +191,13 @@ d_delete: smb_delete_dentry, }; +static struct dentry_operations smbfs_dentry_operations_case = +{ + d_revalidate: smb_lookup_validate, + d_delete: smb_delete_dentry, +}; + + /* * This is the callback when the dcache has a lookup hit. */ @@ -249,8 +257,7 @@ if (a->len != b->len) goto out; - for (i=0; i < a->len; i++) - { + for (i=0; i < a->len; i++) { if (tolower(a->name[i]) != tolower(b->name[i])) goto out; } @@ -300,6 +307,7 @@ struct smb_fattr finfo; struct inode *inode; int error; + struct smb_sb_info *server; error = -ENAMETOOLONG; if (dentry->d_name.len > SMB_MAXNAMELEN) @@ -315,15 +323,18 @@ inode = NULL; if (error == -ENOENT) goto add_entry; - if (!error) - { + if (!error) { error = -EACCES; finfo.f_ino = smb_invent_inos(1); inode = smb_iget(dir->i_sb, &finfo); - if (inode) - { + if (inode) { add_entry: - dentry->d_op = &smbfs_dentry_operations; + server = server_from_dentry(dentry); + if (server->mnt->flags & SMB_MOUNT_CASE) + dentry->d_op = &smbfs_dentry_operations_case; + else + dentry->d_op = &smbfs_dentry_operations; + d_add(dentry, inode); smb_renew_times(dentry); error = 0; diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/getopt.c linux/fs/smbfs/getopt.c --- v2.4.0-test6/linux/fs/smbfs/getopt.c Wed Dec 31 16:00:00 1969 +++ linux/fs/smbfs/getopt.c Mon Aug 14 13:31:10 2000 @@ -0,0 +1,61 @@ +/* + * getopt.c + */ + +#include +#include + +#include "getopt.h" + +/** + * smb_getopt - option parser + * @caller: name of the caller, for error messages + * @options: the options string + * @opts: an array of &struct option entries controlling parser operations + * @optopt: output; will contain the current option + * @optarg: output; will contain the value (if one exists) + * @flag: output; may be NULL; should point to a long for or'ing flags + * @value: output; may be NULL; will be overwritten with the integer value + * of the current argument. + * + * Helper to parse options on the format used by mount ("a=b,c=d,e,f"). + * Returns opts->val if a matching entry in the 'opts' array is found, + * 0 when no more tokens are found, -1 if an error is encountered. + */ +int smb_getopt(char *caller, char **options, struct option *opts, + char **optopt, char **optarg, unsigned long *flag, + unsigned long *value) +{ + char *token; + char *val; + int i; + + if ( (token = strsep(options, ",")) == NULL) + return 0; + *optopt = token; + + *optarg = NULL; + if ((val = strchr (token, '=')) != NULL) { + *val++ = 0; + if (value) + *value = simple_strtoul(val, NULL, 0); + *optarg = val; + } + + for (i = 0; opts[i].name != NULL; i++) { + if (!strcmp(opts[i].name, token)) { + if (opts[i].has_arg && (!val || !*val)) { + printk("%s: the %s option requires an argument\n", + caller, token); + return -1; + } + + if (flag && opts[i].flag) + *flag |= opts[i].flag; + + return opts[i].val; + } + } + printk("%s: Unrecognized mount option %s\n", caller, token); + return -1; +} diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/getopt.h linux/fs/smbfs/getopt.h --- v2.4.0-test6/linux/fs/smbfs/getopt.h Wed Dec 31 16:00:00 1969 +++ linux/fs/smbfs/getopt.h Mon Aug 14 13:31:10 2000 @@ -0,0 +1,15 @@ +#ifndef _LINUX_GETOPT_H +#define _LINUX_GETOPT_H + +struct option { + const char *name; + int has_arg; + unsigned long flag; + int val; +}; + +extern int smb_getopt(char *caller, char **options, struct option *opts, + char **optopt, char **optarg, unsigned long *flag, + unsigned long *value); + +#endif /* _LINUX_GETOPT_H */ diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.4.0-test6/linux/fs/smbfs/inode.c Thu Jul 27 17:38:02 2000 +++ linux/fs/smbfs/inode.c Mon Aug 21 07:55:49 2000 @@ -7,6 +7,7 @@ * Please add a note about your changes to smbfs in the ChangeLog file. */ +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,6 +31,7 @@ #include #include "smb_debug.h" +#include "getopt.h" static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); @@ -282,6 +285,82 @@ clear_inode(ino); } +/* FIXME: flags and has_arg could probably be merged. */ +struct option opts[] = { + { "version", 1, 0, 'v' }, + { "win95", 0, SMB_MOUNT_WIN95, 1 }, + { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 }, + { "dirattr", 0, SMB_MOUNT_DIRATTR, 1 }, + { "case", 0, SMB_MOUNT_CASE, 1 }, + { "uid", 1, 0, 'u' }, + { "gid", 1, 0, 'g' }, + { "file_mode", 1, 0, 'f' }, + { "dir_mode", 1, 0, 'd' }, + { "iocharset", 1, 0, 'i' }, + { "codepage", 1, 0, 'c' }, + { NULL, 0, 0, 0} +}; + +static int +parse_options(struct smb_mount_data_kernel *mnt, char *options) +{ + int c; + unsigned long flags; + unsigned long value; + char *optarg; + char *optopt; + + flags = 0; + while ( (c = smb_getopt("smbfs", &options, opts, + &optopt, &optarg, &flags, &value)) > 0) { + + VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : ""); + + switch (c) { + case 1: + /* got a "flag" option */ + break; + case 'v': + if (value != SMB_MOUNT_VERSION) { + printk ("smbfs: Bad mount version %ld, expected %d\n", + value, SMB_MOUNT_VERSION); + return 0; + } + mnt->version = value; + break; + case 'u': + mnt->uid = value; + break; + case 'g': + mnt->gid = value; + break; + case 'f': + mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO); + mnt->file_mode |= S_IFREG; + break; + case 'd': + mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO); + mnt->dir_mode |= S_IFDIR; + break; + case 'i': + strncpy(mnt->codepage.local_name, optarg, + SMB_NLS_MAXNAMELEN); + break; + case 'c': + strncpy(mnt->codepage.remote_name, optarg, + SMB_NLS_MAXNAMELEN); + break; + default: + printk ("smbfs: Unrecognized mount option %s\n", + optopt); + return -1; + } + } + mnt->flags = flags; + return c; +} + + static void smb_put_super(struct super_block *sb) { @@ -300,18 +379,32 @@ kfree(sb->u.smbfs_sb.temp_buf); if (server->packet) smb_vfree(server->packet); + + if(sb->u.smbfs_sb.remote_nls) { + unload_nls(sb->u.smbfs_sb.remote_nls); + sb->u.smbfs_sb.remote_nls = NULL; + } + if(sb->u.smbfs_sb.local_nls) { + unload_nls(sb->u.smbfs_sb.local_nls); + sb->u.smbfs_sb.local_nls = NULL; + } } struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { - struct smb_mount_data *mnt; + struct smb_mount_data_kernel *mnt; + struct smb_mount_data *oldmnt; struct inode *root_inode; struct smb_fattr root; + int ver; if (!raw_data) goto out_no_data; - if (((struct smb_mount_data *) raw_data)->version != SMB_MOUNT_VERSION) + + oldmnt = (struct smb_mount_data *) raw_data; + ver = oldmnt->version; + if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII) goto out_wrong_data; sb->s_blocksize = 1024; /* Eh... Is this correct? */ @@ -320,6 +413,7 @@ sb->s_flags = 0; sb->s_op = &smb_sops; + sb->u.smbfs_sb.mnt = NULL; sb->u.smbfs_sb.sock_file = NULL; init_MUTEX(&sb->u.smbfs_sb.sem); init_waitqueue_head(&sb->u.smbfs_sb.wait); @@ -332,30 +426,61 @@ goto out_no_mem; /* Allocate the global temp buffer */ - sb->u.smbfs_sb.temp_buf = kmalloc(SMB_MAXPATHLEN + 20, GFP_KERNEL); + sb->u.smbfs_sb.temp_buf = kmalloc(2*SMB_MAXPATHLEN + 20, GFP_KERNEL); if (!sb->u.smbfs_sb.temp_buf) goto out_no_temp; + /* Setup NLS stuff */ + sb->u.smbfs_sb.remote_nls = NULL; + sb->u.smbfs_sb.local_nls = NULL; + sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20; + /* Allocate the mount data structure */ - mnt = kmalloc(sizeof(struct smb_mount_data), GFP_KERNEL); + /* FIXME: merge this with the other malloc and get a whole page? */ + mnt = kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL); if (!mnt) goto out_no_mount; - *mnt = *((struct smb_mount_data *) raw_data); - /* FIXME: passes config flags in high bits of file mode. Should be a - separate flags field. (but smbmount includes kernel headers ...) */ - mnt->version = (mnt->file_mode >> 9); - mnt->file_mode &= (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->file_mode |= S_IFREG; - mnt->dir_mode &= (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->dir_mode |= S_IFDIR; sb->u.smbfs_sb.mnt = mnt; + + memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); + strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, + SMB_NLS_MAXNAMELEN); + strncpy(mnt->codepage.local_name, CONFIG_SMB_NLS_REMOTE, + SMB_NLS_MAXNAMELEN); + + if (ver == SMB_MOUNT_OLDVERSION) { + mnt->version = oldmnt->version; + + /* FIXME: is this enough to convert uid/gid's ? */ + mnt->mounted_uid = oldmnt->mounted_uid; + mnt->uid = oldmnt->uid; + mnt->gid = oldmnt->gid; + + mnt->file_mode = + oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + mnt->dir_mode = + oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + mnt->file_mode |= S_IFREG; + mnt->dir_mode |= S_IFDIR; + + mnt->flags = (oldmnt->file_mode >> 9); + } else { + if (parse_options(mnt, raw_data)) + goto out_bad_option; + + mnt->mounted_uid = current->uid; + } + smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage); + if (!sb->u.smbfs_sb.convert) + PARANOIA("convert funcptr was NULL!\n"); + /* * Display the enabled options * Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2) */ - if (mnt->version & SMB_FIX_OLDATTR) + if (mnt->flags & SMB_MOUNT_OLDATTR) printk("SMBFS: Using core getattr (Win 95 speedup)\n"); - else if (mnt->version & SMB_FIX_DIRATTR) + else if (mnt->flags & SMB_MOUNT_DIRATTR) printk("SMBFS: Using dir ff getattr\n"); /* @@ -374,16 +499,18 @@ out_no_root: iput(root_inode); +out_bad_option: kfree(sb->u.smbfs_sb.mnt); out_no_mount: kfree(sb->u.smbfs_sb.temp_buf); out_no_temp: smb_vfree(sb->u.smbfs_sb.packet); out_no_mem: - printk(KERN_ERR "smb_read_super: allocation failure\n"); + if (!sb->u.smbfs_sb.mnt) + printk(KERN_ERR "smb_read_super: allocation failure\n"); goto out_fail; out_wrong_data: - printk(KERN_ERR "SMBFS: need mount version %d\n", SMB_MOUNT_VERSION); + printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver); goto out_fail; out_no_data: printk(KERN_ERR "smb_read_super: missing data argument\n"); diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.4.0-test6/linux/fs/smbfs/proc.c Thu Jul 27 17:38:02 2000 +++ linux/fs/smbfs/proc.c Mon Aug 14 13:31:10 2000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,10 +26,14 @@ #include "smb_debug.h" + /* Features. Undefine if they cause problems, this should perhaps be a config option. */ #define SMBFS_POSIX_UNLINK 1 +/* Allow smb_retry to be interrupted. Not sure of the benefit ... */ +/* #define SMB_RETRY_INTR */ + #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) #define SMB_CMD(packet) (*(packet+8)) #define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1)) @@ -48,6 +53,20 @@ smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir, struct smb_fattr *fattr); + +static inline void +smb_lock_server(struct smb_sb_info *server) +{ + down(&(server->sem)); +} + +static inline void +smb_unlock_server(struct smb_sb_info *server) +{ + up(&(server->sem)); +} + + static void str_upper(char *name, int len) { @@ -83,6 +102,96 @@ } } +/* no conversion, just a wrapper for memcpy. */ +static int convert_memcpy(char *output, int olen, + const char *input, int ilen, + struct nls_table *nls_from, + struct nls_table *nls_to) +{ + memcpy(output, input, ilen); + return ilen; +} + +/* convert from one "codepage" to another (possibly being utf8). */ +static int convert_cp(char *output, int olen, + const char *input, int ilen, + struct nls_table *nls_from, + struct nls_table *nls_to) +{ + int len = 0; + int n; + wchar_t ch; + + if (!nls_from || !nls_to) { + PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to); + return convert_memcpy(output, olen, input, ilen, NULL, NULL); + } + + while (ilen > 0) { + /* convert by changing to unicode and back to the new cp */ + n = nls_from->char2uni((unsigned char *)input, ilen, &ch); + if (n < 0) + goto out; + input += n; + ilen -= n; + + n = nls_to->uni2char(ch, output, olen); + if (n < 0) + goto out; + output += n; + olen -= n; + + len += n; + } +out: + return len; +} + +static int setcodepage(struct smb_sb_info *server, + struct nls_table **p, char *name) +{ + struct nls_table *nls; + + if (!name || !*name) { + nls = NULL; + } else if ( (nls = load_nls(name)) == NULL) { + printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name); + return -EINVAL; + } + + /* if already set, unload the previous one. */ + if (*p) + unload_nls(*p); + *p = nls; + + return 0; +} + +/* Handles all changes to codepage settings. */ +int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp) +{ + int n; + + smb_lock_server(server); + + n = setcodepage(server, &server->local_nls, cp->local_name); + if (n != 0) + goto out; + n = setcodepage(server, &server->remote_nls, cp->remote_name); + if (n != 0) + setcodepage(server, &server->local_nls, NULL); + +out: + if (server->local_nls != NULL && server->remote_nls != NULL) + server->convert = convert_cp; + else + server->convert = convert_memcpy; + + smb_unlock_server(server); + return n; +} + + /*****************************************************************************/ /* */ /* Encoding/Decoding section */ @@ -107,9 +216,11 @@ * smb_build_path: build the path to entry and name storing it in buf. * The path returned will have the trailing '\0'. */ -static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf) +static int smb_build_path(struct smb_sb_info *server, char * buf, + struct dentry * entry, struct qstr * name) { char *path = buf; + int len; if (entry == NULL) goto test_name_and_out; @@ -129,9 +240,16 @@ * and store it in reversed order [see reverse_string()] */ for (;;) { - memcpy(path, entry->d_name.name, entry->d_name.len); - reverse_string(path, entry->d_name.len); - path += entry->d_name.len; + if (entry->d_name.len > SMB_MAXNAMELEN) + return -ENAMETOOLONG; + if (path - buf + entry->d_name.len > SMB_MAXPATHLEN) + return -ENAMETOOLONG; + + len = server->convert(path, SMB_MAXNAMELEN, + entry->d_name.name, entry->d_name.len, + server->local_nls, server->remote_nls); + reverse_string(path, len); + path += len; *(path++) = '\\'; @@ -147,25 +265,28 @@ if (name != NULL) { *(path++) = '\\'; name_and_out: - memcpy(path, name->name, name->len); - path += name->len; + len = server->convert(path, SMB_MAXNAMELEN, + name->name, name->len, + server->local_nls, server->remote_nls); + path += len; } out: *(path++) = '\0'; return (path-buf); } -static char *smb_encode_path(struct smb_sb_info *server, char *buf, - struct dentry *dir, struct qstr *name) +static int smb_encode_path(struct smb_sb_info *server, char *buf, + struct dentry *dir, struct qstr *name) { - char *start = buf; - - buf += smb_build_path(dir, name, buf); + int result; + result = smb_build_path(server, buf, dir, name); + if (result < 0) + goto out; if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS) - str_upper(start, buf - start); - - return buf; + str_upper(buf, result); +out: + return result; } /* The following are taken directly from msdos-fs */ @@ -464,18 +585,6 @@ return EIO; } -static inline void -smb_lock_server(struct smb_sb_info *server) -{ - down(&(server->sem)); -} - -static inline void -smb_unlock_server(struct smb_sb_info *server) -{ - up(&(server->sem)); -} - /* * smb_retry: This function should be called when smb_request_ok has * indicated an error. If the error was indicated because the @@ -495,8 +604,7 @@ smb_close_socket(server); - if (pid == 0) - { + if (pid == 0) { printk(KERN_ERR "smb_retry: no connection process\n"); server->state = CONN_RETRIED; goto out; @@ -511,26 +619,35 @@ * Note: use the "priv" flag, as a user process may need to reconnect. */ error = kill_proc(pid, SIGUSR1, 1); - if (error) - { + if (error) { printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error); goto out_restore; } - VERBOSE("signalled pid %d, waiting for new connection\n", - server->conn_pid); + VERBOSE("signalled pid %d, waiting for new connection\n", pid); /* * Wait for the new connection. */ +#ifdef SMB_RETRY_INTR interruptible_sleep_on_timeout(&server->wait, 5*HZ); if (signal_pending(current)) printk(KERN_INFO "smb_retry: caught signal\n"); +#else + /* + * We don't want to be interrupted. For example, what if 'current' + * already has recieved a signal? sleep_on would terminate immediately + * and smbmount would not be able to re-establish connection. + * + * smbmount should be able to reconnect later, but it can't because + * it will get an -EIO on attempts to open the mountpoint! + */ + sleep_on_timeout(&server->wait, 5*HZ); +#endif /* * Check for a valid connection. */ - if (server->state == CONN_VALID) - { + if (server->state == CONN_VALID) { /* This should be changed to VERBOSE, except many smbfs problems is with the userspace daemon not reconnecting. */ PARANOIA("sucessful, new pid=%d, generation=%d\n", @@ -656,7 +773,7 @@ if (server->opt.protocol == SMB_PROTOCOL_NT1 && (server->opt.max_xmit < 0x1000) && !(server->opt.capabilities & SMB_CAP_NT_SMBS)) { - server->mnt->version |= SMB_FIX_WIN95; + server->mnt->flags |= SMB_MOUNT_WIN95; #ifdef SMBFS_DEBUG_VERBOSE printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n"); #endif @@ -667,7 +784,11 @@ server->opt.capabilities); out: +#ifdef SMB_RETRY_INTR wake_up_interruptible(&server->wait); +#else + wake_up(&server->wait); +#endif return error; out_putf: @@ -738,7 +859,7 @@ { struct inode *ino = dentry->d_inode; int mode, read_write = 0x42, read_only = 0x40; - int error; + int res; char *p; /* @@ -748,6 +869,9 @@ if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode = read_only; #if 0 + /* FIXME: why is this code not in? below we fix it so that a caller + wanting RO doesn't get RW. smb_revalidate_inode does some + optimization based on access mode. tail -f needs it to be correct. */ if (!(wish & (O_WRONLY | O_RDWR))) mode = read_only; #endif @@ -757,20 +881,23 @@ WSET(server->packet, smb_vwv0, mode); WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + res = smb_encode_path(server, p, dentry, NULL); + if (res < 0) + goto out; + p += res; + smb_setup_bcc(server, p); - error = smb_request_ok(server, SMBopen, 7, 0); - if (error != 0) - { + res = smb_request_ok(server, SMBopen, 7, 0); + if (res != 0) { if (smb_retry(server)) goto retry; if (mode == read_write && - (error == -EACCES || error == -ETXTBSY || error == -EROFS)) + (res == -EACCES || res == -ETXTBSY || res == -EROFS)) { VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n", - DENTRY_PATH(dentry), error); + DENTRY_PATH(dentry), res); mode = read_only; goto retry; } @@ -783,10 +910,12 @@ /* smb_vwv2 has mtime */ /* smb_vwv4 has size */ ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK); + if (!(wish & (O_WRONLY | O_RDWR))) + ino->u.smbfs_i.access = SMB_O_RDONLY; ino->u.smbfs_i.open = server->generation; out: - return error; + return res; } /* @@ -1025,7 +1154,7 @@ { struct smb_sb_info *server = server_from_dentry(dentry); char *p; - int error; + int result; smb_lock_server(server); @@ -1034,22 +1163,24 @@ WSET(server->packet, smb_vwv0, attr); DSET(server->packet, smb_vwv1, utc2local(server, ctime)); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); - error = smb_request_ok(server, SMBcreate, 1, 0); - if (error < 0) - { + result = smb_request_ok(server, SMBcreate, 1, 0); + if (result < 0) { if (smb_retry(server)) goto retry; goto out; } *fileid = WVAL(server->packet, smb_vwv0); - error = 0; + result = 0; out: smb_unlock_server(server); - return error; + return result; } int @@ -1064,14 +1195,22 @@ retry: p = smb_setup_header(server, SMBmv, 1, 0); WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR); + *p++ = 4; - p = smb_encode_path(server, p, old_dentry, NULL); + result = smb_encode_path(server, p, old_dentry, NULL); + if (result < 0) + goto out; + p += result; + *p++ = 4; - p = smb_encode_path(server, p, new_dentry, NULL); + result = smb_encode_path(server, p, new_dentry, NULL); + if (result < 0) + goto out; + p += result; + smb_setup_bcc(server, p); - if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) - { + if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; @@ -1097,12 +1236,14 @@ retry: p = smb_setup_header(server, command, 0, 0); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); result = smb_request_ok(server, command, 0, 0); - if (result < 0) - { + if (result < 0) { if (smb_retry(server)) goto retry; goto out; @@ -1165,11 +1306,13 @@ p = smb_setup_header(server, SMBunlink, 1, 0); WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); - if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) - { + if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) { #if SMBFS_POSIX_UNLINK if (result == -EACCES && !flag) { /* Posix semantics is for the read-only state @@ -1220,8 +1363,7 @@ *p++ = 0; smb_setup_bcc(server, p); - if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) - { + if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; @@ -1306,6 +1448,8 @@ len--; entry->len = len; + /* FIXME: These only work for ascii chars, and recent smbmount doesn't + allow the flag to be set anyway. Remove? */ switch (server->opt.case_handling) { case SMB_CASE_UPPER: str_upper(entry->name, len); @@ -1316,7 +1460,13 @@ default: break; } - DEBUG1("len=%d, name=%.*s\n", len, len, entry->name); + + entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN, + entry->name, len, + server->remote_nls, server->local_nls); + entry->name = server->name_buf; + + DEBUG1("len=%d, name=%.*s\n", entry->len, entry->len, entry->name); return p + 22; } @@ -1355,7 +1505,10 @@ WSET(server->packet, smb_vwv1, aDIR); *p++ = 4; if (first == 1) { - p = smb_encode_path(server, p, dir, &mask); + result = smb_encode_path(server, p, dir, &mask); + if (result < 0) + goto unlock_return; + p += result; *p++ = 5; WSET(p, 0, 0); p += 2; @@ -1467,12 +1620,11 @@ switch (level) { case 1: len = *((unsigned char *) p + 22); - entry->len = len; entry->name = p + 23; result = p + 24 + len; VERBOSE("info 1 at %p, len=%d, name=%.*s\n", - p, entry->len, entry->len, entry->name); + p, len, len, entry->name); break; case 260: result = p + WVAL(p, 0); @@ -1482,14 +1634,14 @@ entry->name = p + 94; if (len && entry->name[len-1] == '\0') len--; - entry->len = len; VERBOSE("info 260 at %p, len=%d, name=%.*s\n", - p, entry->len, entry->len, entry->name); + p, len, len, entry->name); break; default: PARANOIA("Unknown info level %d\n", level); result = p + WVAL(p, 0); + goto out; } switch (server->opt.case_handling) { @@ -1503,6 +1655,11 @@ break; } + entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN, + entry->name, len, + server->remote_nls, server->local_nls); + entry->name = server->name_buf; +out: return result; } @@ -1561,7 +1718,12 @@ * Encode the initial path */ mask = param + 12; - mask_len = smb_encode_path(server, mask, dir, &star) - mask; + + mask_len = smb_encode_path(server, mask, dir, &star); + if (mask_len < 0) { + entries = mask_len; + goto unlock_return; + } first = 1; VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask); @@ -1753,7 +1915,11 @@ int mask_len, result; retry: - mask_len = smb_encode_path(server, mask, dentry, NULL) - mask; + mask_len = smb_encode_path(server, mask, dentry, NULL); + if (mask_len < 0) { + result = mask_len; + goto out; + } VERBOSE("name=%s, len=%d\n", mask, mask_len); WSET(param, 0, aSYSTEM | aHIDDEN | aDIR); WSET(param, 2, 1); /* max count */ @@ -1828,7 +1994,10 @@ retry: p = smb_setup_header(server, SMBgetatr, 0, 0); *p++ = 4; - p = smb_encode_path(server, p, dir, NULL); + result = smb_encode_path(server, p, dir, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) @@ -1874,7 +2043,10 @@ retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); - p = smb_encode_path(server, param + 6, dir, NULL); + result = smb_encode_path(server, param + 6, dir, NULL); + if (result < 0) + goto out; + p = param + 6 + result; result = smb_trans2_request(server, TRANSACT2_QPATHINFO, 0, NULL, p - param, param, @@ -1905,7 +2077,7 @@ * Kludge alert: Win 95 swaps the date and time field, * contrary to the CIFS docs and Win NT practice. */ - if (server->mnt->version & SMB_FIX_WIN95) { + if (server->mnt->flags & SMB_MOUNT_WIN95) { off_date = 2; off_time = 0; } @@ -1945,21 +2117,16 @@ /* * Select whether to use core or trans2 getattr. + * Win 95 appears to break with the trans2 getattr. */ - if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) { - /* - * Win 95 appears to break with the trans2 getattr. - * Note: mnt->version options are set at mount time (inode.c) - */ - if (server->mnt->version & (SMB_FIX_OLDATTR|SMB_FIX_WIN95)) - goto core_attr; - if (server->mnt->version & SMB_FIX_DIRATTR) + if (server->opt.protocol < SMB_PROTOCOL_LANMAN2 || + (server->mnt->flags & (SMB_MOUNT_OLDATTR|SMB_MOUNT_WIN95)) ) { + result = smb_proc_getattr_core(server, dir, fattr); + } else { + if (server->mnt->flags & SMB_MOUNT_DIRATTR) result = smb_proc_getattr_ff(server, dir, fattr); else result = smb_proc_getattr_trans2(server, dir, fattr); - } else { - core_attr: - result = smb_proc_getattr_core(server, dir, fattr); } smb_finish_dirent(server, fattr); @@ -2008,14 +2175,16 @@ WSET(server->packet, smb_vwv6, 0); WSET(server->packet, smb_vwv7, 0); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; *p++ = 4; *p++ = 0; smb_setup_bcc(server, p); result = smb_request_ok(server, SMBsetatr, 0, 0); - if (result < 0) - { + if (result < 0) { if (smb_retry(server)) goto retry; goto out; @@ -2073,8 +2242,7 @@ #endif result = smb_request_ok(server, SMBsetattrE, 0, 0); - if (result < 0) - { + if (result < 0) { if (smb_retry(server)) goto retry; goto out; @@ -2107,7 +2275,10 @@ retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); - p = smb_encode_path(server, param + 6, dir, NULL); + result = smb_encode_path(server, param + 6, dir, NULL); + if (result < 0) + goto out; + p = param + 6 + result; WSET(data, 0, 0); /* creation time */ WSET(data, 2, 0); @@ -2170,8 +2341,7 @@ smb_lock_server(server); /* setting the time on a Win95 server fails (tridge) */ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 && - !(server->mnt->version & SMB_FIX_WIN95)) - { + !(server->mnt->flags & SMB_MOUNT_WIN95)) { if (smb_is_open(inode) && inode->u.smbfs_i.access != SMB_O_RDONLY) result = smb_proc_setattr_ext(server, inode, fattr); @@ -2182,8 +2352,7 @@ * Fail silently on directories ... timestamp can't be set? */ result = 0; - if (S_ISREG(inode->i_mode)) - { + if (S_ISREG(inode->i_mode)) { /* * Set the mtime by opening and closing the file. * Note that the file is opened read-only, but this @@ -2192,8 +2361,7 @@ result = -EACCES; if (!smb_is_open(inode)) smb_proc_open(server, dentry, SMB_O_RDONLY); - if (smb_is_open(inode)) - { + if (smb_is_open(inode)) { inode->i_mtime = fattr->f_mtime; result = smb_proc_close_inode(server, inode); } @@ -2208,7 +2376,7 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr) { struct smb_sb_info *server = &(sb->u.smbfs_sb); - int error; + int result; char *p; smb_lock_server(server); @@ -2216,8 +2384,7 @@ retry: smb_setup_header(server, SMBdskattr, 0, 0); - if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) - { + if ((result = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; @@ -2226,11 +2393,11 @@ attr->f_blocks = WVAL(p, 0); attr->f_bsize = WVAL(p, 2) * WVAL(p, 4); attr->f_bavail = attr->f_bfree = WVAL(p, 6); - error = 0; + result = 0; out: smb_unlock_server(server); - return error; + return result; } int diff -u --recursive --new-file v2.4.0-test6/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c --- v2.4.0-test6/linux/fs/smbfs/sock.c Thu Jul 27 17:38:02 2000 +++ linux/fs/smbfs/sock.c Mon Aug 14 13:31:10 2000 @@ -111,12 +111,16 @@ unsigned char peek_buf[4]; int result; mm_segment_t fs; + int count = 100; /* this is a lot, we should have some data waiting */ + int found = 0; fs = get_fs(); set_fs(get_ds()); lock_kernel(); - while (1) { + while (count-- > 0) { + peek_buf[0] = 0; + result = -EIO; if (job->sk->dead) { PARANOIA("sock dead!\n"); @@ -125,7 +129,7 @@ result = _recvfrom(socket, (void *) peek_buf, 1, MSG_PEEK | MSG_DONTWAIT); - if (result == -EAGAIN) + if (result < 0) break; if (peek_buf[0] != 0x85) break; @@ -136,13 +140,15 @@ DEBUG1("got SESSION KEEPALIVE\n"); - if (result == -EAGAIN) + if (result < 0) break; + found = 1; } unlock_kernel(); set_fs(fs); - if (result != -EAGAIN) + DEBUG1("found=%d, count=%d, result=%d\n", found, count, result); + if (found) found_data(job->sk); kfree(ptr); } diff -u --recursive --new-file v2.4.0-test6/linux/fs/stat.c linux/fs/stat.c --- v2.4.0-test6/linux/fs/stat.c Wed Aug 9 19:19:51 2000 +++ linux/fs/stat.c Fri Aug 11 14:37:49 2000 @@ -52,6 +52,10 @@ SET_OLDSTAT_UID(tmp, inode->i_uid); SET_OLDSTAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); +#if BITS_PER_LONG == 32 + if (inode->i_size > 0x7fffffff) + return -EOVERFLOW; +#endif tmp.st_size = inode->i_size; tmp.st_atime = inode->i_atime; tmp.st_mtime = inode->i_mtime; @@ -74,6 +78,10 @@ SET_STAT_UID(tmp, inode->i_uid); SET_STAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); +#if BITS_PER_LONG == 32 + if (inode->i_size > 0x7fffffff) + return -EOVERFLOW; +#endif tmp.st_size = inode->i_size; tmp.st_atime = inode->i_atime; tmp.st_mtime = inode->i_mtime; diff -u --recursive --new-file v2.4.0-test6/linux/fs/super.c linux/fs/super.c --- v2.4.0-test6/linux/fs/super.c Wed Aug 9 19:19:51 2000 +++ linux/fs/super.c Fri Aug 11 14:31:45 2000 @@ -10,13 +10,12 @@ * - umount system call * - ustat system call * - * Added options to /proc/mounts - * Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996. - * * GK 2/5/95 - Changed to support mounting the root fs via NFS * * Added kerneld support: Jacques Gelinas and Bjorn Ekwall * Added change_root: Werner Almesberger & Hans Lermen, Feb '96 + * Added options to /proc/mounts: + * Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996. * Added devfs support: Richard Gooch , 13-JAN-1998 * Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000 */ @@ -428,6 +427,33 @@ kfree(mnt); } + +/* Use octal escapes, like mount does, for embedded spaces etc. */ +static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' }; + +static int +mangle(const unsigned char *s, char *buf, int len) { + char *sp; + int n; + + sp = buf; + while(*s && sp-buf < len-3) { + for (n = 0; n < sizeof(need_escaping); n++) { + if (*s == need_escaping[n]) { + *sp++ = '\\'; + *sp++ = '0' + ((*s & 0300) >> 6); + *sp++ = '0' + ((*s & 070) >> 3); + *sp++ = '0' + (*s & 07); + goto next; + } + } + *sp++ = *s; + next: + s++; + } + return sp - buf; /* no trailing NUL */ +} + static struct proc_fs_info { int flag; char *str; @@ -466,27 +492,32 @@ struct proc_fs_info *fs_infop; struct proc_nfs_info *nfs_infop; struct nfs_server *nfss; - int len = 0; - char *path,*buffer = (char *) __get_free_page(GFP_KERNEL); + int len, prevlen; + char *path, *buffer = (char *) __get_free_page(GFP_KERNEL); if (!buffer) return 0; - for (p = vfsmntlist.next; p!=&vfsmntlist && len < PAGE_SIZE - 160; - p = p->next) { + len = prevlen = 0; + +#define FREEROOM ((int)PAGE_SIZE-200-len) +#define MANGLE(s) len += mangle((s), buf+len, FREEROOM); + + for (p = vfsmntlist.next; p != &vfsmntlist; p = p->next) { struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list); if (!(tmp->mnt_flags & MNT_VISIBLE)) continue; path = d_path(tmp->mnt_root, tmp, buffer, PAGE_SIZE); if (!path) continue; - len += sprintf( buf + len, "%s %s %s %s", - tmp->mnt_devname ? tmp->mnt_devname : "none", path, - tmp->mnt_sb->s_type->name, - tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw" ); + MANGLE(tmp->mnt_devname ? tmp->mnt_devname : "none"); + buf[len++] = ' '; + MANGLE(path); + buf[len++] = ' '; + MANGLE(tmp->mnt_sb->s_type->name); + len += sprintf(buf+len, " %s", + tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw"); for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { - if (tmp->mnt_sb->s_flags & fs_infop->flag) { - strcpy(buf + len, fs_infop->str); - len += strlen(fs_infop->str); - } + if (tmp->mnt_sb->s_flags & fs_infop->flag) + MANGLE(fs_infop->str); } if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) { nfss = &tmp->mnt_sb->u.nfs_sb.s_server; @@ -527,17 +558,24 @@ str = nfs_infop->str; else str = nfs_infop->nostr; - strcpy(buf + len, str); - len += strlen(str); + MANGLE(str); } - len += sprintf(buf+len, ",addr=%s", - nfss->hostname); + len += sprintf(buf+len, ",addr="); + MANGLE(nfss->hostname); + } + len += sprintf(buf + len, " 0 0\n"); + if (FREEROOM <= 3) { + len = prevlen; + len += sprintf(buf+len, "# truncated\n"); + break; } - len += sprintf( buf + len, " 0 0\n" ); + prevlen = len; } free_page((unsigned long) buffer); return len; +#undef MANGLE +#undef FREEROOM } /** @@ -775,7 +813,8 @@ dev = to_kdev_t(bdev->bd_dev); sb = get_super(dev); if (sb) { - if (fs_type == sb->s_type) { + if (fs_type == sb->s_type && + ((flags ^ sb->s_flags) & MS_RDONLY) == 0) { path_release(&nd); return sb; } @@ -1090,7 +1129,7 @@ if (retval) goto out; retval = -EINVAL; - if (nd.dentry!=nd.mnt->mnt_root) + if (nd.dentry != nd.mnt->mnt_root) goto dput_and_out; retval = -EPERM; @@ -1263,8 +1302,8 @@ * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * - * NOTE! As old versions of mount() didn't use this setup, the flags - * have to have a special 16-bit magic number in the high word: + * NOTE! As pre-0.97 versions of mount() didn't use this setup, the + * flags have to have a special 16-bit magic number in the high word: * 0xC0ED. If this magic word isn't present, the flags and data info * aren't used, as the syscall assumes we are talking to an older * version that didn't understand them. @@ -1736,7 +1775,7 @@ printk("okay\n"); return 0; } - printk(KERN_ERR "error %d\n",blivet); + printk(KERN_ERR "error %d\n", blivet); return error; } /* FIXME: we should hold i_zombie on nd.dentry */ diff -u --recursive --new-file v2.4.0-test6/linux/fs/sysv/dir.c linux/fs/sysv/dir.c --- v2.4.0-test6/linux/fs/sysv/dir.c Sat Feb 26 22:31:54 2000 +++ linux/fs/sysv/dir.c Fri Aug 11 14:29:01 2000 @@ -61,7 +61,7 @@ inode->i_ino, (off_t) filp->f_pos, sde.inode); i = strnlen(sde.name, SYSV_NAMELEN); - if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode) < 0) { + if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode, DT_UNKNOWN) < 0) { brelse(bh); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/fs/udf/dir.c linux/fs/udf/dir.c --- v2.4.0-test6/linux/fs/udf/dir.c Thu Mar 2 14:36:23 2000 +++ linux/fs/udf/dir.c Fri Aug 11 14:29:02 2000 @@ -94,7 +94,7 @@ if ( filp->f_pos == 0 ) { - if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino)) + if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR)) return 0; } @@ -206,7 +206,7 @@ if (!lfi) /* parent directory */ { - if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino)) + if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR)) { if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); @@ -219,7 +219,7 @@ { if ((flen = udf_get_filename(nameptr, fname, lfi))) { - if (filldir(dirent, fname, flen, filp->f_pos, iblock)) + if (filldir(dirent, fname, flen, filp->f_pos, iblock, DT_UNKNOWN)) { if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); diff -u --recursive --new-file v2.4.0-test6/linux/fs/ufs/dir.c linux/fs/ufs/dir.c --- v2.4.0-test6/linux/fs/ufs/dir.c Sun Mar 19 18:35:31 2000 +++ linux/fs/ufs/dir.c Fri Aug 11 14:29:02 2000 @@ -122,11 +122,14 @@ * not the directory has been modified * during the copy operation. */ unsigned long version = filp->f_version; + unsigned char d_type = DT_UNKNOWN; UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino))) UFSD(("namlen %u\n", ufs_get_de_namlen(de))) + if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) + d_type = de->d_u.d_44.d_type; error = filldir(dirent, de->d_name, ufs_get_de_namlen(de), - filp->f_pos, SWAB32(de->d_ino)); + filp->f_pos, SWAB32(de->d_ino), d_type); if (error) break; if (version != filp->f_version) diff -u --recursive --new-file v2.4.0-test6/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.4.0-test6/linux/fs/umsdos/dir.c Mon Jul 10 16:47:26 2000 +++ linux/fs/umsdos/dir.c Fri Aug 11 14:29:01 2000 @@ -76,7 +76,7 @@ if (d->count == 0) { PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", len, name, offset)); - ret = d->filldir (d->dirbuf, name, len, offset, ino); + ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN); d->stop = ret < 0; d->count = 1; } @@ -120,7 +120,7 @@ Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n")); if (filldir (dirbuf, "DOS", 3, - UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) { + UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) { filp->f_pos++; } goto out_end; @@ -235,7 +235,7 @@ */ if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) { if (filldir (dirbuf, entry.name, entry.name_len, - cur_f_pos, inode->i_ino) < 0) { + cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) { pos = cur_f_pos; } Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n", diff -u --recursive --new-file v2.4.0-test6/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.4.0-test6/linux/fs/umsdos/rdir.c Tue May 23 15:31:36 2000 +++ linux/fs/umsdos/rdir.c Fri Aug 11 14:29:01 2000 @@ -33,7 +33,8 @@ const char *name, int name_len, off_t offset, - ino_t ino) + ino_t ino, + unsigned int d_type) { int ret = 0; struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf; @@ -48,11 +49,11 @@ /* Make sure the .. entry points back to the pseudo_root */ ino = pseudo_root->i_ino; } - ret = d->filldir (d->dirbuf, name, name_len, offset, ino); + ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN); } } else { /* Any DOS directory */ - ret = d->filldir (d->dirbuf, name, name_len, offset, ino); + ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN); } return ret; } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h --- v2.4.0-test6/linux/include/asm-alpha/bitops.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-alpha/bitops.h Thu Aug 10 15:19:40 2000 @@ -271,6 +271,8 @@ tmp = *p; found_first: tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h --- v2.4.0-test6/linux/include/asm-alpha/fcntl.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-alpha/fcntl.h Fri Aug 11 14:37:49 2000 @@ -63,4 +63,8 @@ __kernel_pid_t l_pid; }; +#ifdef __KERNEL__ +#define flock64 flock +#endif + #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h --- v2.4.0-test6/linux/include/asm-alpha/mmu_context.h Thu May 11 15:30:08 2000 +++ linux/include/asm-alpha/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -205,11 +205,12 @@ # endif #endif -extern inline void +extern inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context = 0; tsk->thread.ptbr = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT; + return 0; } extern inline void diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.4.0-test6/linux/include/asm-alpha/unistd.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-alpha/unistd.h Fri Aug 11 14:29:03 2000 @@ -314,6 +314,7 @@ #define __NR_pivot_root 374 #define __NR_mincore 375 #define __NR_pciconfig_iobase 376 +#define __NR_getdents64 377 #if defined(__GNUC__) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h --- v2.4.0-test6/linux/include/asm-arm/a.out.h Fri Oct 22 13:21:52 1999 +++ linux/include/asm-arm/a.out.h Sun Aug 13 09:54:15 2000 @@ -1,7 +1,7 @@ #ifndef __ARM_A_OUT_H__ #define __ARM_A_OUT_H__ -#include +#include struct exec { diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-arc/hardware.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-arc/hardware.h Sun Aug 13 09:54:15 2000 @@ -82,7 +82,7 @@ * RAM definitions */ #define GET_MEMORY_END(p) (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages)) -#define PARAMS_BASE (PAGE_OFFSET + 0x7c000) +#define PARAMS_OFFSET 0x7c000 #else diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-arc/ide.h linux/include/asm-arm/arch-arc/ide.h --- v2.4.0-test6/linux/include/asm-arm/arch-arc/ide.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-arc/ide.h Sun Aug 13 09:54:15 2000 @@ -12,6 +12,7 @@ * 29-07-1998 RMK Major re-work of IDE architecture specific code */ #include +#include /* * Set up a hw structure for a specified data port, control port and IRQ. diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h --- v2.4.0-test6/linux/include/asm-arm/arch-arc/irq.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/arch-arc/irq.h Mon Aug 14 13:09:07 2000 @@ -10,14 +10,24 @@ * 11-01-1998 RMK Added mask_and_ack_irq * 22-08-1998 RMK Restructured IRQ routines */ +#include #include +#ifdef CONFIG_ARCH_ARC +#define a_clf() clf() +#define a_stf() stf() +#else +#define a_clf() do { } while (0) +#define a_stf() do { } while (0) +#endif + #define fixup_irq(x) (x) static void arc_mask_irq_ack_a(unsigned int irq) { unsigned int temp; + a_clf(); __asm__ __volatile__( "ldrb %0, [%2]\n" " bic %0, %0, %1\n" @@ -26,30 +36,35 @@ : "=&r" (temp) : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)), "r" (ioaddr(IOC_IRQCLRA))); + a_stf(); } static void arc_mask_irq_a(unsigned int irq) { unsigned int temp; + a_clf(); __asm__ __volatile__( "ldrb %0, [%2]\n" " bic %0, %0, %1\n" " strb %0, [%2]" : "=&r" (temp) : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA))); + a_stf(); } static void arc_unmask_irq_a(unsigned int irq) { unsigned int temp; + a_clf(); __asm__ __volatile__( "ldrb %0, [%2]\n" " orr %0, %0, %1\n" " strb %0, [%2]" : "=&r" (temp) : "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA))); + a_stf(); } static void arc_mask_irq_b(unsigned int irq) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h --- v2.4.0-test6/linux/include/asm-arm/arch-arc/system.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-arc/system.h Mon Aug 14 13:09:07 2000 @@ -3,22 +3,6 @@ * * Copyright (c) 1996-1999 Russell King and Dave Gilbert */ -#include - -#ifdef CONFIG_ARCH_ARC - -#define cliIF() \ - do { \ - unsigned long temp; \ - __asm__ __volatile__( \ -" mov %0, pc\n" \ -" orr %0, %0, #0x0c000000\n" \ -" teqp %0, #0\n" \ - : "=r" (temp) \ - : ); \ - } while(0) - -#endif static void arch_idle(void) { diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-cl7500/dma.h linux/include/asm-arm/arch-cl7500/dma.h --- v2.4.0-test6/linux/include/asm-arm/arch-cl7500/dma.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-cl7500/dma.h Sun Aug 13 09:54:15 2000 @@ -7,13 +7,15 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H +/* DMA is not yet implemented! It should be the same as acorn, copy over.. */ + /* * This is the maximum DMA address that can be DMAd to. * There should not be more than (0xd0000000 - 0xc0000000) * bytes of RAM. */ #define MAX_DMA_ADDRESS 0xd0000000 -#define MAX_DMA_CHANNELS 1 +#define MAX_DMA_CHANNELS 0 #define DMA_S0 0 diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-cl7500/hardware.h linux/include/asm-arm/arch-cl7500/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-cl7500/hardware.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-arm/arch-cl7500/hardware.h Sun Aug 13 09:54:15 2000 @@ -67,6 +67,8 @@ #define IOEB_BASE ((volatile unsigned char *)0xe0350050) #define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000) #define PCIO_BASE 0xe0010000 +/* in/out bias for the ISA slot region */ +#define ISASLOT_IO 0x80400000 /* * RAM definitions @@ -76,8 +78,6 @@ p->u1.s.pages_in_bank[1] + \ p->u1.s.pages_in_bank[2] + \ p->u1.s.pages_in_bank[3])) - -#define PARAMS_BASE 0 #define FLUSH_BASE_PHYS 0x00000000 /* ROM */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-cl7500/ide.h linux/include/asm-arm/arch-cl7500/ide.h --- v2.4.0-test6/linux/include/asm-arm/arch-cl7500/ide.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-arm/arch-cl7500/ide.h Sun Aug 13 09:54:15 2000 @@ -7,6 +7,7 @@ * 29-07-1998 RMK Major re-work of IDE architecture specific code */ #include +#include /* * Set up a hw structure for a specified data port, control port and IRQ. @@ -15,7 +16,7 @@ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) { - ide_ioreg_t reg = (ide_ioreg_t) data_port; + ide_ioreg_t reg = data_port; int i; memset(hw, 0, sizeof(*hw)); @@ -24,9 +25,14 @@ hw->io_ports[i] = reg; reg += 1; } - hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; - if (irq) + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206; + } + if (irq != NULL) *irq = 0; + hw->io_ports[IDE_IRQ_OFFSET] = 0; } /* @@ -36,4 +42,9 @@ static __inline__ void ide_init_default_hwifs(void) { + hw_regs_t hw; + + ide_init_hwif_ports(&hw, ISASLOT_IO + 0x1f0, ISASLOT_IO + 0x3f6, NULL); + hw.irq = IRQ_ISA_14; + ide_register_hw(&hw, NULL); } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-cl7500/serial.h linux/include/asm-arm/arch-cl7500/serial.h --- v2.4.0-test6/linux/include/asm-arm/arch-cl7500/serial.h Thu Mar 2 14:36:23 2000 +++ linux/include/asm-arm/arch-cl7500/serial.h Sun Aug 13 09:54:15 2000 @@ -11,6 +11,8 @@ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H +#include + /* * This assumes you have a 1.8432 MHz clock for your UART. * @@ -27,9 +29,10 @@ /* UART CLK PORT IRQ FLAGS */ #define STD_SERIAL_PORT_DEFNS \ { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS }, /* ttyS1 */ \ - { 0, BASE_BAUD, 0x804002e8, 41, STD_COM_FLAGS }, /* ttyS2 */ \ - { 0, BASE_BAUD, 0x804003e8, 40, STD_COM_FLAGS }, /* ttyS3 */ \ + { 0, BASE_BAUD, 0x2F8, 0, STD_COM_FLAGS }, /* ttyS1 */ \ + /* ISA Slot Serial ports */ \ + { 0, BASE_BAUD, ISASLOT_IO + 0x2e8, 41, STD_COM_FLAGS }, /* ttyS2 */ \ + { 0, BASE_BAUD, ISASLOT_IO + 0x3e8, 40, STD_COM_FLAGS }, /* ttyS3 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS5 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS6 */ \ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-cl7500/time.h linux/include/asm-arm/arch-cl7500/time.h --- v2.4.0-test6/linux/include/asm-arm/arch-cl7500/time.h Thu Mar 2 14:36:23 2000 +++ linux/include/asm-arm/arch-cl7500/time.h Sun Aug 13 09:54:15 2000 @@ -8,7 +8,6 @@ * 10-Oct-1996 RMK Brought up to date with arch-sa110eval * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ -extern void ioctime_init(void); static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -33,8 +32,6 @@ */ extern __inline__ void setup_timer(void) { - ioctime_init(); - timer_irq.handler = timer_interrupt; setup_arm_irq(IRQ_TIMER, &timer_irq); diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-cl7500/uncompress.h linux/include/asm-arm/arch-cl7500/uncompress.h --- v2.4.0-test6/linux/include/asm-arm/arch-cl7500/uncompress.h Tue Nov 23 22:42:21 1999 +++ linux/include/asm-arm/arch-cl7500/uncompress.h Sun Aug 13 09:54:15 2000 @@ -5,11 +5,12 @@ */ #define BASE 0x03010000 +#define SERBASE (BASE + (0x3f8 << 2)) static __inline__ void putc(char c) { - while (!(*((volatile unsigned int *)(BASE + 0xbf4)) & 0x20)); - *((volatile unsigned int *)(BASE + 0xbe0)) = c; + while (!(*((volatile unsigned int *)(SERBASE + 0x14)) & 0x20)); + *((volatile unsigned int *)(SERBASE)) = c; } /* @@ -27,13 +28,13 @@ static __inline__ void arch_decomp_setup(void) { - int baud = 3686400 / (9600 * 16); + int baud = 3686400 / (9600 * 32); - *((volatile unsigned int *)(BASE + 0xBEC)) = 0x80; - *((volatile unsigned int *)(BASE + 0xBE0)) = baud & 0xff; - *((volatile unsigned int *)(BASE + 0xBE4)) = (baud & 0xff00) >> 8; - *((volatile unsigned int *)(BASE + 0xBEC)) = 3; /* 8 bits */ - *((volatile unsigned int *)(BASE + 0xBF0)) = 3; /* DTR, RTS */ + *((volatile unsigned int *)(SERBASE + 0xC)) = 0x80; + *((volatile unsigned int *)(SERBASE + 0x0)) = baud & 0xff; + *((volatile unsigned int *)(SERBASE + 0x4)) = (baud & 0xff00) >> 8; + *((volatile unsigned int *)(SERBASE + 0xC)) = 3; /* 8 bits */ + *((volatile unsigned int *)(SERBASE + 0x10)) = 3; /* DTR, RTS */ } /* diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa110/hardware.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-arm/arch-ebsa110/hardware.h Sun Aug 13 09:54:15 2000 @@ -42,7 +42,7 @@ #define UNCACHEABLE_ADDR 0xf3000000 -#define PARAMS_BASE (PAGE_OFFSET + 0x400) +#define PARAMS_OFFSET 0x400 #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/hardware.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/arch-ebsa285/hardware.h Sun Aug 13 09:54:15 2000 @@ -11,7 +11,7 @@ #include #include -#ifdef CONFIG_FOOTBRIDGE_HOST +#ifdef CONFIG_ARCH_FOOTBRIDGE /* Virtual Physical Size * 0xff800000 0x40000000 1MB X-Bus * 0xff000000 0x7c000000 1MB PCI I/O space @@ -61,7 +61,9 @@ #define PCIMEM_BASE 0xf0000000 #elif defined(CONFIG_ARCH_CO285) - +/* + * This is the COEBSA285 cut-down mapping + */ #define PCIMEM_SIZE 0x80000000 #define PCIMEM_BASE 0x80000000 @@ -85,7 +87,7 @@ #else -#error Add your add-in architecture here +#error "Undefined footbridge architecture" #endif @@ -102,7 +104,6 @@ #define XBUS_SWITCH_J17_9 ((*XBUS_SWITCH) & (1 << 6)) #define PARAMS_OFFSET 0x0100 -#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET) #define FLUSH_BASE_PHYS 0x50000000 #define UNCACHEABLE_ADDR (ARMCSR_BASE + 0x108) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/irq.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/arch-ebsa285/irq.h Sun Aug 13 09:54:15 2000 @@ -13,12 +13,13 @@ #include #include #include +#include /* * Footbridge IRQ translation table * Converts from our IRQ numbers into FootBridge masks */ -static int dc21285_irq_mask[] = { +static const int dc21285_irq_mask[] = { IRQ_MASK_UART_RX, /* 0 */ IRQ_MASK_UART_TX, /* 1 */ IRQ_MASK_TIMER1, /* 2 */ @@ -45,8 +46,10 @@ static inline int fixup_irq(unsigned int irq) { +#ifdef PCIIACK_BASE if (irq == isa_irq) irq = *(unsigned char *)PCIIACK_BASE; +#endif return irq; } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/irqs.h linux/include/asm-arm/arch-ebsa285/irqs.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/irqs.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/arch-ebsa285/irqs.h Sun Aug 13 09:54:15 2000 @@ -8,6 +8,7 @@ * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder * 01-Feb-1999 PJB ISA IRQs start at 0 not 16 */ +#include #define NR_IRQS 36 #define NR_DC21285_IRQS 16 diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/keyboard.h linux/include/asm-arm/arch-ebsa285/keyboard.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/keyboard.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/arch-ebsa285/keyboard.h Sun Aug 13 09:54:15 2000 @@ -6,11 +6,10 @@ * (C) 1998 Russell King * (C) 1998 Phil Blundell */ +#include #include #include -extern int have_isa_bridge; - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, @@ -71,7 +70,7 @@ #define SYSRQ_KEY 0x54 /* resource allocation */ -#define kbd_request_region() +#define kbd_request_region() request_region(0x60, 16, "keyboard") #define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ "keyboard", NULL) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/memory.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/arch-ebsa285/memory.h Sun Aug 13 09:54:15 2000 @@ -17,58 +17,53 @@ #include -#if defined(CONFIG_FOOTBRIDGE_HOST) - +#if defined(CONFIG_FOOTBRIDGE_ADDIN) /* - * Task size: 3GB + * If we may be using add-in footbridge mode, then we must + * use the out-of-line translation that makes use of the + * PCI BAR */ -#define TASK_SIZE (0xc0000000UL) -#define TASK_SIZE_26 (0x04000000UL) +#ifndef __ASSEMBLY__ +extern unsigned long __virt_to_bus(unsigned long); +extern unsigned long __bus_to_virt(unsigned long); +#endif -/* - * Page offset: 3GB - */ -#define PAGE_OFFSET (0xc0000000UL) -#define PHYS_OFFSET (0x00000000UL) +#elif defined(CONFIG_FOOTBRIDGE_HOST) #define __virt_to_bus__is_a_macro #define __virt_to_bus(x) ((x) - 0xe0000000) #define __bus_to_virt__is_a_macro #define __bus_to_virt(x) ((x) + 0xe0000000) -#elif defined(CONFIG_FOOTBRIDGE_ADDIN) +#else -#if defined(CONFIG_ARCH_CO285) +#error "Undefined footbridge mode" -/* - * Task size: 1.5GB - */ -#define TASK_SIZE (0x60000000UL) -#define TASK_SIZE_26 (0x04000000UL) +#endif -/* - * Page offset: 1.5GB - */ +#if defined(CONFIG_ARCH_FOOTBRIDGE) + +/* Task size and page offset at 3GB */ +#define TASK_SIZE (0xc0000000UL) +#define PAGE_OFFSET (0xc0000000UL) + +#elif defined(CONFIG_ARCH_CO285) + +/* Task size and page offset at 1.5GB */ +#define TASK_SIZE (0x60000000UL) #define PAGE_OFFSET (0x60000000UL) -#define PHYS_OFFSET (0x00000000UL) #else -#error Add in your architecture here +#error "Undefined footbridge architecture" #endif -#ifndef __ASSEMBLY__ -extern unsigned long __virt_to_bus(unsigned long); -extern unsigned long __bus_to_virt(unsigned long); -#endif - -#endif +#define TASK_SIZE_26 (0x04000000UL) +#define PHYS_OFFSET (0x00000000UL) /* - * On Footbridge machines, the dram is contiguous. - * On Host Footbridge, these conversions are constant. - * On an add-in footbridge, these depend on register settings. + * The DRAM is always contiguous. */ #define __virt_to_phys__is_a_macro #define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/system.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-ebsa285/system.h Sun Aug 13 09:54:15 2000 @@ -7,6 +7,7 @@ #include #include #include +#include static void arch_idle(void) { diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h --- v2.4.0-test6/linux/include/asm-arm/arch-ebsa285/time.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-arm/arch-ebsa285/time.h Sun Aug 13 09:54:15 2000 @@ -21,7 +21,7 @@ #include #include -#include +#include static int rtc_base; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/hardware.h linux/include/asm-arm/arch-l7200/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/hardware.h Tue May 23 15:31:36 2000 +++ linux/include/asm-arm/arch-l7200/hardware.h Sun Aug 13 09:54:15 2000 @@ -41,7 +41,7 @@ #define FLUSH_BASE_PHYS 0x40000000 /* ROM */ #define FLUSH_BASE 0xdf000000 -#define PARAMS_BASE (PAGE_OFFSET + 0x0100) +#define PARAMS_OFFSET (0x0100) #define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET) #define PCIO_BASE IO_BASE diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/ide.h linux/include/asm-arm/arch-l7200/ide.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/ide.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-arm/arch-l7200/ide.h Sun Aug 13 09:54:15 2000 @@ -4,7 +4,7 @@ * Copyright (c) 2000 Steve Hill (sjhill@cotw.com) * * Changelog: - * 29-03-2000 SJH Created file placeholder + * 03-29-2000 SJH Created file placeholder */ #include diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/io.h linux/include/asm-arm/arch-l7200/io.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/io.h Tue May 23 15:31:36 2000 +++ linux/include/asm-arm/arch-l7200/io.h Sun Aug 13 09:54:15 2000 @@ -1,10 +1,10 @@ /* * linux/include/asm-arm/arch-l7200/io.h * - * Copyright (C) 2000 Steven Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) * * Modifications: - * 21-03-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h + * 03-21-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h */ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H @@ -14,188 +14,6 @@ #define IO_SPACE_LIMIT 0xffffffff /* - * We use two different types of addressing - PC style addresses, and ARM - * addresses. PC style accesses the PC hardware with the normal PC IO - * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+ - * and are translated to the start of IO. Note that all addresses are - * shifted left! - */ -#define __PORT_PCIO(x) (!((x) & 0x80000000)) - -/* - * Dynamic IO functions. - */ - -extern __inline__ void __outb (unsigned int value, unsigned int port) -{ - unsigned long temp; - __asm__ __volatile__( - "tst %2, #0x80000000\n\t" - "mov %0, %4\n\t" - "addeq %0, %0, %3\n\t" - "strb %1, [%0, %2, lsl #2] @ outb" - : "=&r" (temp) - : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) - : "cc"); -} - -extern __inline__ void __outw (unsigned int value, unsigned int port) -{ - unsigned long temp; - __asm__ __volatile__( - "tst %2, #0x80000000\n\t" - "mov %0, %4\n\t" - "addeq %0, %0, %3\n\t" - "str %1, [%0, %2, lsl #2] @ outw" - : "=&r" (temp) - : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) - : "cc"); -} - -extern __inline__ void __outl (unsigned int value, unsigned int port) -{ - unsigned long temp; - __asm__ __volatile__( - "tst %2, #0x80000000\n\t" - "mov %0, %4\n\t" - "addeq %0, %0, %3\n\t" - "str %1, [%0, %2, lsl #2] @ outl" - : "=&r" (temp) - : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) - : "cc"); -} - -#define DECLARE_DYN_IN(sz,fnsuffix,instr) \ -extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \ -{ \ - unsigned long temp, value; \ - __asm__ __volatile__( \ - "tst %2, #0x80000000\n\t" \ - "mov %0, %4\n\t" \ - "addeq %0, %0, %3\n\t" \ - "ldr" ##instr## " %1, [%0, %2, lsl #2] @ in"###fnsuffix \ - : "=&r" (temp), "=r" (value) \ - : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \ - : "cc"); \ - return (unsigned sz)value; \ -} - -extern __inline__ unsigned int __ioaddr (unsigned int port) \ -{ \ - if (__PORT_PCIO(port)) \ - return (unsigned int)(PCIO_BASE + (port << 2)); \ - else \ - return (unsigned int)(IO_BASE + (port << 2)); \ -} - -#define DECLARE_IO(sz,fnsuffix,instr) \ - DECLARE_DYN_IN(sz,fnsuffix,instr) - -DECLARE_IO(char,b,"b") -DECLARE_IO(short,w,"") -DECLARE_IO(int,l,"") - -#undef DECLARE_IO -#undef DECLARE_DYN_IN - -/* - * Constant address IO functions - * - * These have to be macros for the 'J' constraint to work - - * +/-4096 immediate operand. - */ -#define __outbc(value,port) \ -({ \ - if (__PORT_PCIO((port))) \ - __asm__ __volatile__( \ - "strb %0, [%1, %2] @ outbc" \ - : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ - else \ - __asm__ __volatile__( \ - "strb %0, [%1, %2] @ outbc" \ - : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \ -}) - -#define __inbc(port) \ -({ \ - unsigned char result; \ - if (__PORT_PCIO((port))) \ - __asm__ __volatile__( \ - "ldrb %0, [%1, %2] @ inbc" \ - : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ - else \ - __asm__ __volatile__( \ - "ldrb %0, [%1, %2] @ inbc" \ - : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ - result; \ -}) - -#define __outwc(value,port) \ -({ \ - unsigned long v = value; \ - if (__PORT_PCIO((port))) \ - __asm__ __volatile__( \ - "str %0, [%1, %2] @ outwc" \ - : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ - else \ - __asm__ __volatile__( \ - "str %0, [%1, %2] @ outwc" \ - : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2)); \ -}) - -#define __inwc(port) \ -({ \ - unsigned short result; \ - if (__PORT_PCIO((port))) \ - __asm__ __volatile__( \ - "ldr %0, [%1, %2] @ inwc" \ - : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ - else \ - __asm__ __volatile__( \ - "ldr %0, [%1, %2] @ inwc" \ - : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ - result & 0xffff; \ -}) - -#define __outlc(value,port) \ -({ \ - unsigned long v = value; \ - if (__PORT_PCIO((port))) \ - __asm__ __volatile__( \ - "str %0, [%1, %2] @ outlc" \ - : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ - else \ - __asm__ __volatile__( \ - "str %0, [%1, %2] @ outlc" \ - : : "r" (v), "r" (IO_BASE), "r" ((port) << 2)); \ -}) - -#define __inlc(port) \ -({ \ - unsigned long result; \ - if (__PORT_PCIO((port))) \ - __asm__ __volatile__( \ - "ldr %0, [%1, %2] @ inlc" \ - : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ - else \ - __asm__ __volatile__( \ - "ldr %0, [%1, %2] @ inlc" \ - : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ - result; \ -}) - -#define __ioaddrc(port) \ - (__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2)) - -#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p)) -#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p)) -#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p)) -#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p)) -#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p)) -#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p)) -#define __ioaddr(p) (__builtin_constant_p((p)) ? __ioaddr(p) : __ioaddrc(p)) - -/* * Translated address IO functions * * IO address has already been translated to a virtual address @@ -206,5 +24,19 @@ #define inw_t(p) (*(volatile unsigned int *)(p)) #define outl_t(v,p) (*(volatile unsigned long *)(p) = (v)) #define inl_t(p) (*(volatile unsigned long *)(p)) + +/* + * FIXME - These are to allow for linking. On all the other + * ARM platforms, the entire IO space is contiguous. + * The 7200 has three separate IO spaces. The below + * macros will eventually become more involved. Use + * with caution and don't be surprised by kernel oopses!!! + */ +#define inb(p) inb_t(p) +#define inw(p) inw_t(p) +#define inl(p) inl_t(p) +#define outb(v,p) outb_t(v,p) +#define outw(v,p) outw_t(v,p) +#define outl(v,p) outl_t(v,p) #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/memory.h linux/include/asm-arm/arch-l7200/memory.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/memory.h Tue May 23 15:31:36 2000 +++ linux/include/asm-arm/arch-l7200/memory.h Sun Aug 13 09:54:15 2000 @@ -1,7 +1,7 @@ /* * linux/include/asm-arm/arch-l7200/memory.h * - * Copyright (c) 2000 Steven Hill (sjhill@cotw.com) + * Copyright (c) 2000 Steve Hill (sjhill@cotw.com) * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net) * * Changelog: @@ -9,8 +9,8 @@ * 04-13-2000 RS Changed bus macros for new addr * 05-03-2000 SJH Removed bus macros and fixed virt_to_phys macro */ -#ifndef __ASM_ARCH_MMU_H -#define __ASM_ARCH_MMU_H +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H /* * Task size: 3GB diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/system.h linux/include/asm-arm/arch-l7200/system.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/system.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-l7200/system.h Sun Aug 13 09:54:15 2000 @@ -1,21 +1,22 @@ /* * linux/include/asm-arm/arch-l7200/system.h * - * Copyright (c) 2000 Steven Hill (sjhill@cotw.com) + * Copyright (c) 2000 Steve Hill (sjhill@cotw.com) * * Changelog * 03-21-2000 SJH Created * 04-26-2000 SJH Fixed functions * 05-03-2000 SJH Removed usage of obsolete 'iomd.h' + * 05-31-2000 SJH Properly implemented 'arch_idle' */ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H static void arch_idle(void) { - while (!current->need_resched && !hlt_counter) - { }; -/* outb(0, IOMD_SUSMODE);*/ + while (!current->need_resched && !hlt_counter) { + cpu_do_idle(IDLE_WAIT_SLOW); + } } extern inline void arch_reset(char mode) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/time.h linux/include/asm-arm/arch-l7200/time.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/time.h Tue May 23 15:31:36 2000 +++ linux/include/asm-arm/arch-l7200/time.h Sun Aug 13 09:54:15 2000 @@ -54,8 +54,6 @@ */ extern __inline__ void setup_timer(void) { - xtime.tv_sec = RTC_RTCDR; - RTC_RTCC = 0; /* Clear interrupt */ timer_irq.handler = timer_interrupt; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-l7200/uncompress.h linux/include/asm-arm/arch-l7200/uncompress.h --- v2.4.0-test6/linux/include/asm-arm/arch-l7200/uncompress.h Tue May 23 15:31:36 2000 +++ linux/include/asm-arm/arch-l7200/uncompress.h Sun Aug 13 09:54:15 2000 @@ -2,18 +2,43 @@ * linux/include/asm-arm/arch-l7200/uncompress.h * * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 05-01-2000 SJH Created + * 05-13-2000 SJH Filled in function bodies + * 07-26-2000 SJH Removed hard coded buad rate */ +#include + +#define IO_UART IO_START + 0x00044000 + +#define __raw_writeb(v,p) (*(volatile unsigned char *)(p) = (v)) +#define __raw_readb(p) (*(volatile unsigned char *)(p)) + static __inline__ void putc(char c) { + while(__raw_readb(IO_UART + 0x18) & 0x20 || + __raw_readb(IO_UART + 0x18) & 0x08); + __raw_writeb(c, IO_UART + 0x00); } static void puts(const char *s) { + while (*s) { + if (*s == 10) { /* If a LF, add CR */ + putc(10); + putc(13); + } + putc(*(s++)); + } } static __inline__ void arch_decomp_setup(void) { + __raw_writeb(0x00, IO_UART + 0x08); /* Set HSB */ + __raw_writeb(0x00, IO_UART + 0x20); /* Disable IRQs */ + __raw_writeb(0x01, IO_UART + 0x14); /* Enable UART */ } #define arch_decomp_wdog() diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-rpc/hardware.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/arch-rpc/hardware.h Sun Aug 13 09:54:15 2000 @@ -78,7 +78,6 @@ p->u1.s.pages_in_bank[2] + \ p->u1.s.pages_in_bank[3])) -#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET) #define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET) #define FLUSH_BASE_PHYS 0x00000000 /* ROM */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-sa1100/cerf.h linux/include/asm-arm/arch-sa1100/cerf.h --- v2.4.0-test6/linux/include/asm-arm/arch-sa1100/cerf.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-sa1100/cerf.h Sun Aug 13 09:54:15 2000 @@ -0,0 +1,16 @@ +#ifndef _INCLUDE_CERF_H_ +#define _INCLUDE_CERF_H_ + +/* GPIOs for CF+ slot lines */ +#define GPIO_CF_IRQ GPIO_GPIO (22) /* 1111 MBGNT _OR_ CF IRQ */ +#define GPIO_CF_CD GPIO_GPIO (23) /* 1111 MBREQ _OR_ CF CD */ +#define GPIO_CF_BVD2 GPIO_GPIO (19) /* Graphics IRQ _OR_ CF BVD */ +#define GPIO_CF_BVD1 GPIO_GPIO (20) /* 1111 IRQ _OR_ CF BVD */ + +#define IRQ_GPIO_CF_IRQ IRQ_GPIO22 +#define IRQ_GPIO_CF_CD IRQ_GPIO23 +#define IRQ_GPIO_CF_BVD2 IRQ_GPIO19 +#define IRQ_GPIO_CF_BVD1 IRQ_GPIO20 + +#endif + diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-sa1100/hardware.h linux/include/asm-arm/arch-sa1100/hardware.h --- v2.4.0-test6/linux/include/asm-arm/arch-sa1100/hardware.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-sa1100/hardware.h Sun Aug 13 09:54:15 2000 @@ -77,6 +77,10 @@ #define machine_has_neponset() (0) #endif +#ifdef CONFIG_SA1100_CERF +#include "cerf.h" +#endif + #ifdef CONFIG_SA1100_EMPEG #include "empeg.h" #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-sa1100/ide.h linux/include/asm-arm/arch-sa1100/ide.h --- v2.4.0-test6/linux/include/asm-arm/arch-sa1100/ide.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-sa1100/ide.h Sun Aug 13 09:54:15 2000 @@ -7,10 +7,9 @@ #include -#ifdef CONFIG_BLK_DEV_IDE - #include -#include +#include +#include /* * Set up a hw structure for a specified data port, control port and IRQ. @@ -118,7 +117,24 @@ ide_register_hw(&hw, NULL); #endif } + else if (machine_is_lart()) { +#ifdef CONFIG_SA1100_LART + hw_regs_t hw; + + /* Enable GPIO as interrupt line */ + GPDR &= ~GPIO_GPIO1; + set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE); + + /* set PCMCIA interface timing */ + MECR = 0x00060006; + + /* init the interface */ +/* ide_init_hwif_ports(&hw, 0xe00000000, 0xe00001000, NULL); */ + ide_init_hwif_ports(&hw, 0xe00001000, 0xe00000000, NULL); + hw.irq = IRQ_GPIO1; + ide_register_hw(&hw, NULL); +#endif + } } -#endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-sa1100/irq.h linux/include/asm-arm/arch-sa1100/irq.h --- v2.4.0-test6/linux/include/asm-arm/arch-sa1100/irq.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-sa1100/irq.h Sun Aug 13 09:54:15 2000 @@ -16,6 +16,7 @@ */ #include #include +#include #define fixup_irq(x) (x) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-sa1100/uncompress.h linux/include/asm-arm/arch-sa1100/uncompress.h --- v2.4.0-test6/linux/include/asm-arm/arch-sa1100/uncompress.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/arch-sa1100/uncompress.h Sun Aug 13 09:54:15 2000 @@ -9,6 +9,8 @@ #include "hardware.h" #include "serial_reg.h" +#include + /* Assabet's Status Control "Register" */ unsigned long SCR_value; @@ -29,7 +31,7 @@ serial_port = (unsigned long *)_Ser3UTCR0; else serial_port = (unsigned long *)_Ser1UTCR0; - } else if (machine_is_brutus()) + } else if (machine_is_brutus()||machine_is_nanoengine()) serial_port = (unsigned long *)_Ser1UTCR0; else if (machine_is_empeg() || machine_is_bitsy() || machine_is_victor() || machine_is_lart()) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/arch-shark/keyboard.h linux/include/asm-arm/arch-shark/keyboard.h --- v2.4.0-test6/linux/include/asm-arm/arch-shark/keyboard.h Tue Apr 11 15:09:23 2000 +++ linux/include/asm-arm/arch-shark/keyboard.h Sun Aug 13 09:54:15 2000 @@ -11,8 +11,6 @@ #include #include -extern int have_isa_bridge; - extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/assembler.h linux/include/asm-arm/assembler.h --- v2.4.0-test6/linux/include/asm-arm/assembler.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/assembler.h Sun Aug 13 09:54:15 2000 @@ -7,5 +7,9 @@ * Do not include any C declarations in this file - it is included by * assembler source. */ +#ifndef __ASSEMBLY__ +#error "Only include this from assembly code" +#endif + #include #include diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h --- v2.4.0-test6/linux/include/asm-arm/dma.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/dma.h Sun Aug 13 09:54:15 2000 @@ -4,7 +4,6 @@ typedef unsigned int dmach_t; #include -#include #include #include #include diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h --- v2.4.0-test6/linux/include/asm-arm/hardware.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/hardware.h Sun Aug 13 09:54:15 2000 @@ -11,4 +11,10 @@ #include +#ifdef PARAMS_OFFSET +#define PARAMS_BASE ((PAGE_OFFSET) + (PARAMS_OFFSET)) +#else +#define PARAMS_BASE 0 +#endif + #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/leds.h linux/include/asm-arm/leds.h --- v2.4.0-test6/linux/include/asm-arm/leds.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/leds.h Sun Aug 13 09:54:15 2000 @@ -25,17 +25,20 @@ led_amber_on, led_amber_off, led_red_on, - led_red_off + led_red_off, + /* + * I want this between led_timer and led_start, but + * someone has decided to export this to user space + */ + led_halted } led_event_t; /* Use this routine to handle LEDs */ #ifdef CONFIG_LEDS extern void (*leds_event)(led_event_t); -#define set_leds_event(r) leds_event = r #else #define leds_event(e) -#define set_leds_event(r) #endif #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/mc146818rtc.h linux/include/asm-arm/mc146818rtc.h --- v2.4.0-test6/linux/include/asm-arm/mc146818rtc.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/mc146818rtc.h Sun Aug 13 09:54:15 2000 @@ -4,6 +4,7 @@ #ifndef _ASM_MC146818RTC_H #define _ASM_MC146818RTC_H +#include #include #ifndef RTC_PORT @@ -23,7 +24,5 @@ outb_p((addr),RTC_PORT(0)); \ outb_p((val),RTC_PORT(1)); \ }) - -#define RTC_IRQ 8 #endif /* _ASM_MC146818RTC_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/mmu_context.h linux/include/asm-arm/mmu_context.h --- v2.4.0-test6/linux/include/asm-arm/mmu_context.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-arm/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -15,7 +15,7 @@ #include #define destroy_context(mm) do { } while(0) -#define init_new_context(tsk,mm) do { } while(0) +#define init_new_context(tsk,mm) 0 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/page.h linux/include/asm-arm/page.h --- v2.4.0-test6/linux/include/asm-arm/page.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-arm/page.h Sun Aug 13 09:54:15 2000 @@ -91,8 +91,8 @@ #define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) #ifndef CONFIG_DISCONTIGMEM -#define MAP_NR(addr) ((__pa(addr) - PHYS_OFFSET) >> PAGE_SHIFT) -#define virt_to_page(kaddr) (mem_map + ((__pa(kaddr) - PHYS_OFFSET) >> PAGE_SHIFT)) +#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT) - \ + (PHYS_OFFSET >> PAGE_SHIFT)) #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/pgalloc.h linux/include/asm-arm/pgalloc.h --- v2.4.0-test6/linux/include/asm-arm/pgalloc.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-arm/pgalloc.h Sun Aug 13 09:54:15 2000 @@ -5,7 +5,6 @@ #define _ASMARM_PGALLOC_H #include -#include #include diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h --- v2.4.0-test6/linux/include/asm-arm/pgtable.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-arm/pgtable.h Sun Aug 13 09:54:15 2000 @@ -7,7 +7,6 @@ #include #include #include -#include /* * PMD_SHIFT determines the size of the area a second-level page table can map @@ -80,7 +79,8 @@ #define pte_clear(ptep) set_pte((ptep), __pte(0)) #ifndef CONFIG_DISCONTIGMEM -#define pte_page(x) (mem_map + (unsigned long)(((pte_val(pte) - PHYS_OFFSET) >> PAGE_SHIFT))) +#define pte_page(x) (mem_map + (pte_val((x)) >> PAGE_SHIFT) - \ + (PHYS_OFFSET >> PAGE_SHIFT)) #else /* * I'm not happy with this - we needlessly convert a physical address @@ -88,7 +88,7 @@ * which, if __va and __pa are expensive causes twice the expense for * zero gain. --rmk */ -#define pte_page(x) (mem_map + MAP_NR(__va(pte_val(pte)))) +#define pte_page(x) (mem_map + MAP_NR(__va(pte_val((x))))) #endif #define pmd_none(pmd) (!pmd_val(pmd)) @@ -172,9 +172,6 @@ #define module_map vmalloc #define module_unmap vfree - -/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -#define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags)) #define io_remap_page_range remap_page_range diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armo/assembler.h linux/include/asm-arm/proc-armo/assembler.h --- v2.4.0-test6/linux/include/asm-arm/proc-armo/assembler.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/proc-armo/assembler.h Sun Aug 13 09:54:15 2000 @@ -6,10 +6,6 @@ * This file contains arm architecture specific defines * for the different processors */ -#ifndef __ASSEMBLY__ -#error "Only include this from assembly code" -#endif - #define MODE_USR USR26_MODE #define MODE_FIQ FIQ26_MODE #define MODE_IRQ IRQ26_MODE @@ -60,3 +56,25 @@ #define SVCMODE(tmpreg)\ teqp pc, $0x00000003;\ mov r0, r0 + + +/* + * Save the current IRQ state and disable IRQs + * Note that this macro assumes FIQs are enabled, and + * that the processor is in SVC mode. + */ + .macro save_and_disable_irqs, oldcpsr, temp + mov \oldcpsr, pc + orr \temp, \oldcpsr, #0x08000000 + teqp \temp, #0 + .endm + +/* + * Restore interrupt state previously stored in + * a register + * ** Actually do nothing on Arc - hope that the caller uses a MOVS PC soon + * after! + */ + .macro restore_irqs, oldcpsr + @ This be restore_irqs + .endm diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h --- v2.4.0-test6/linux/include/asm-arm/proc-armo/cache.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-arm/proc-armo/cache.h Sun Aug 13 09:54:15 2000 @@ -10,6 +10,9 @@ #define flush_icache_page(vma,page) do { } while (0) #define flush_icache_range(start,end) do { } while (0) +/* DAG: ARM3 will flush cache on MEMC updates anyway? so don't bother */ +#define clean_cache_area(_start,_size) do { } while (0) + /* * TLB flushing: * diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armo/locks.h linux/include/asm-arm/proc-armo/locks.h --- v2.4.0-test6/linux/include/asm-arm/proc-armo/locks.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/proc-armo/locks.h Sun Aug 13 09:54:15 2000 @@ -0,0 +1,158 @@ +/* + * linux/include/asm-arm/proc-armo/locks.h + * + * Copyright (C) 2000 Russell King + * Fixes for 26 bit machines, (C) 2000 Dave Gilbert + * + * Interrupt safe locking assembler. + * + */ +#ifndef __ASM_PROC_LOCKS_H +#define __ASM_PROC_LOCKS_H + +/* Decrements by 1, fails if value < 0 */ +#define __down_op(ptr,fail) \ + ({ \ + __asm__ __volatile__ ( \ + "@ atomic down operation\n" \ +" mov r0, pc\n" \ +" orr lr, r0, #0x08000000\n" \ +" teqp lr, #0\n" \ +" ldr lr, [%0]\n" \ +" and r0, r0, #0x0c000003\n" \ +" subs lr, lr, #1\n" \ +" str lr, [%0]\n" \ +" orrmi r0, r0, #0x80000000 @ set N\n" \ +" teqp r0, #0\n" \ +" movmi r0, %0\n" \ +" blmi " SYMBOL_NAME_STR(fail) \ + : \ + : "r" (ptr) \ + : "r0", "lr", "cc"); \ + }) + +#define __down_op_ret(ptr,fail) \ + ({ \ + unsigned int result; \ + __asm__ __volatile__ ( \ +" @ down_op_ret\n" \ +" mov r0, pc\n" \ +" orr lr, r0, #0x08000000\n" \ +" teqp lr, #0\n" \ +" ldr lr, [%1]\n" \ +" and r0, r0, #0x0c000003\n" \ +" subs lr, lr, #1\n" \ +" str lr, [%1]\n" \ +" orrmi r0, r0, #0x80000000 @ set N\n" \ +" teqp r0, #0\n" \ +" movmi r0, %1\n" \ +" movpl r0, #0\n" \ +" blmi " SYMBOL_NAME_STR(fail) "\n" \ +" mov %0, r0" \ + : "=&r" (result) \ + : "r" (ptr) \ + : "r0", "lr", "cc"); \ + result; \ + }) + +#define __up_op(ptr,wake) \ + ({ \ + __asm__ __volatile__ ( \ + "@ up_op\n" \ +" mov r0, pc\n" \ +" orr lr, r0, #0x08000000\n" \ +" teqp lr, #0\n" \ +" ldr lr, [%0]\n" \ +" and r0, r0, #0x0c000003\n" \ +" adds lr, lr, #1\n" \ +" str lr, [%0]\n" \ +" orrle r0, r0, #0x80000000 @ set N - should this be mi ??? DAG ! \n" \ +" teqp r0, #0\n" \ +" movmi r0, %0\n" \ +" blmi " SYMBOL_NAME_STR(wake) \ + : \ + : "r" (ptr) \ + : "r0", "lr", "cc"); \ + }) + +/* + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that sub'ing + * BIAS once per CPU will result in the long remaining + * negative. + */ +#define RW_LOCK_BIAS 0x01000000 +#define RW_LOCK_BIAS_STR "0x01000000" + +/* Decrements by RW_LOCK_BIAS rather than 1, fails if value != 0 */ +#define __down_op_write(ptr,fail) \ + ({ \ + __asm__ __volatile__( \ + "@ down_op_write\n" \ +" mov r0, pc\n" \ +" orr lr, r0, #0x08000000\n" \ +" teqp lr, #0\n" \ +" and r0, r0, #0x0c000003\n" \ +\ +" ldr lr, [%0]\n" \ +" subs lr, lr, %1\n" \ +" str lr, [%0]\n" \ +\ +" orreq r0, r0, #0x40000000 @ set Z \n"\ +" teqp r0, #0\n" \ +" movne r0, %0\n" \ +" blne " SYMBOL_NAME_STR(fail) \ + : \ + : "r" (ptr), "I" (RW_LOCK_BIAS) \ + : "r0", "lr", "cc"); \ + }) + +/* Increments by RW_LOCK_BIAS, wakes if value >= 0 */ +#define __up_op_write(ptr,wake) \ + ({ \ + __asm__ __volatile__( \ + "@ up_op_read\n" \ +" mov r0, pc\n" \ +" orr lr, r0, #0x08000000\n" \ +" teqp lr, #0\n" \ +\ +" ldr lr, [%0]\n" \ +" and r0, r0, #0x0c000003\n" \ +" adds lr, lr, %1\n" \ +" str lr, [%0]\n" \ +\ +" orrcs r0, r0, #0x20000000 @ set C\n" \ +" teqp r0, #0\n" \ +" movcs r0, %0\n" \ +" blcs " SYMBOL_NAME_STR(wake) \ + : \ + : "r" (ptr), "I" (RW_LOCK_BIAS) \ + : "r0", "lr", "cc"); \ + }) + +#define __down_op_read(ptr,fail) \ + __down_op(ptr, fail) + +#define __up_op_read(ptr,wake) \ + ({ \ + __asm__ __volatile__( \ + "@ up_op_read\n" \ +" mov r0, pc\n" \ +" orr lr, r0, #0x08000000\n" \ +" teqp lr, #0\n" \ +\ +" ldr lr, [%0]\n" \ +" and r0, r0, #0x0c000003\n" \ +" adds lr, lr, %1\n" \ +" str lr, [%0]\n" \ +\ +" orreq r0, r0, #0x40000000 @ Set Z \n" \ +" teqp r0, #0\n" \ +" moveq r0, %0\n" \ +" bleq " SYMBOL_NAME_STR(wake) \ + : \ + : "r" (ptr), "I" (1) \ + : "r0", "lr", "cc"); \ + }) + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armo/system.h linux/include/asm-arm/proc-armo/system.h --- v2.4.0-test6/linux/include/asm-arm/proc-armo/system.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-arm/proc-armo/system.h Sun Aug 13 09:54:15 2000 @@ -77,6 +77,24 @@ : "memory"); \ } while(0) +#define __clf() do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ clf\n" \ +" orr %0, %0, #0x04000000\n" \ +" teqp %0, #0\n" \ + : "=r" (temp)); \ + } while(0) + +#define __stf() do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ stf\n" \ +" bic %0, %0, #0x04000000\n" \ +" teqp %0, #0\n" \ + : "=r" (temp)); \ + } while(0) + /* * save current IRQ & FIQ state */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armv/assembler.h linux/include/asm-arm/proc-armv/assembler.h --- v2.4.0-test6/linux/include/asm-arm/proc-armv/assembler.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/proc-armv/assembler.h Sun Aug 13 09:54:15 2000 @@ -6,10 +6,6 @@ * This file contains ARM processor specifics for * the ARM6 and better processors. */ -#ifndef __ASSEMBLY__ -#error "Only include this from assembly code" -#endif - #define MODE_USR USR_MODE #define MODE_FIQ FIQ_MODE #define MODE_IRQ IRQ_MODE @@ -35,9 +31,8 @@ instr regs /* - * Save the current IRQ state and disable IRQs - * Note that this macro assumes FIQs are enabled, and - * that the processor is in SVC mode. + * Save the current IRQ state and disable IRQs. Note that this macro + * assumes FIQs are enabled, and that the processor is in SVC mode. */ .macro save_and_disable_irqs, oldcpsr, temp mrs \oldcpsr, cpsr @@ -46,8 +41,8 @@ .endm /* - * Restore interrupt state previously stored in - * a register + * Restore interrupt state previously stored in a register. We don't + * guarantee that this will preserve the flags. */ .macro restore_irqs, oldcpsr msr cpsr_c, \oldcpsr diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armv/elf.h linux/include/asm-arm/proc-armv/elf.h --- v2.4.0-test6/linux/include/asm-arm/proc-armv/elf.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-arm/proc-armv/elf.h Sun Aug 13 09:54:15 2000 @@ -17,6 +17,6 @@ there is no other ELF system currently supported by iBCS. @@ Could print a warning message to encourage users to upgrade. */ #define SET_PERSONALITY(ex,ibcs2) \ - set_personality((ex).e_flags&EF_ARM_APCS26 ?PER_LINUX :PER_LINUX_32BIT) + set_personality(((ex).e_flags&EF_ARM_APCS26 ?PER_LINUX :PER_LINUX_32BIT)) #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h --- v2.4.0-test6/linux/include/asm-arm/proc-armv/system.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-arm/proc-armv/system.h Sun Aug 13 09:54:15 2000 @@ -79,6 +79,36 @@ }) /* + * Enable FIQs + */ +#define __stf() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ stf\n" \ +" bic %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + +/* + * Disable FIQs + */ +#define __clf() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ clf\n" \ +" orr %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory"); \ + }) + +/* * save current IRQ & FIQ state */ #define __save_flags(x) \ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h --- v2.4.0-test6/linux/include/asm-arm/proc-armv/uaccess.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/proc-armv/uaccess.h Sun Aug 13 09:54:15 2000 @@ -41,7 +41,7 @@ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "3: mvn %0, %3\n" \ + "3: mov %0, %3\n" \ " b 2b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ @@ -49,7 +49,7 @@ " .long 1b, 3b\n" \ " .previous" \ : "=r" (err) \ - : "r" (x), "r" (addr), "i" (EFAULT), "0" (err)) + : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) #define __put_user_asm_half(x,addr,err) \ ({ \ @@ -60,7 +60,7 @@ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "4: mvn %0, %5\n" \ + "4: mov %0, %5\n" \ " b 3b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ @@ -71,7 +71,7 @@ : "=r" (err) \ : "r" (__temp), "r" (__temp >> 8), \ "r" (addr), "r" ((int)(addr) + 1), \ - "i" (EFAULT), "0" (err)); \ + "i" (-EFAULT), "0" (err)); \ }) #define __put_user_asm_word(x,addr,err) \ @@ -80,7 +80,7 @@ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "3: mvn %0, %3\n" \ + "3: mov %0, %3\n" \ " b 2b\n" \ " .previous\n" \ " .section __ex_table,\"a\"\n" \ @@ -88,7 +88,7 @@ " .long 1b, 3b\n" \ " .previous" \ : "=r" (err) \ - : "r" (x), "r" (addr), "i" (EFAULT), "0" (err)) + : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) #define __get_user_asm_byte(x,addr,err) \ __asm__ __volatile__( \ @@ -96,7 +96,7 @@ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "3: mvn %0, %3\n" \ + "3: mov %0, %3\n" \ " mov %1, #0\n" \ " b 2b\n" \ " .previous\n" \ @@ -105,7 +105,7 @@ " .long 1b, 3b\n" \ " .previous" \ : "=r" (err), "=r" (x) \ - : "r" (addr), "i" (EFAULT), "0" (err)) + : "r" (addr), "i" (-EFAULT), "0" (err)) #define __get_user_asm_half(x,addr,err) \ ({ \ @@ -117,7 +117,7 @@ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "4: mvn %0, %5\n" \ + "4: mov %0, %5\n" \ " mov %1, #0\n" \ " b 3b\n" \ " .previous\n" \ @@ -128,7 +128,7 @@ " .previous" \ : "=r" (err), "=r" (x), "=&r" (__temp) \ : "r" (addr), "r" ((int)(addr) + 1), \ - "i" (EFAULT), "0" (err)); \ + "i" (-EFAULT), "0" (err)); \ }) @@ -138,7 +138,7 @@ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ - "3: mvn %0, %3\n" \ + "3: mov %0, %3\n" \ " mov %1, #0\n" \ " b 2b\n" \ " .previous\n" \ @@ -147,7 +147,7 @@ " .long 1b, 3b\n" \ " .previous" \ : "=r" (err), "=r" (x) \ - : "r" (addr), "i" (EFAULT), "0" (err)) + : "r" (addr), "i" (-EFAULT), "0" (err)) extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n); #define __do_copy_from_user(to,from,n) \ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/resource.h linux/include/asm-arm/resource.h --- v2.4.0-test6/linux/include/asm-arm/resource.h Tue Dec 14 01:27:24 1999 +++ linux/include/asm-arm/resource.h Sun Aug 13 09:54:15 2000 @@ -18,26 +18,26 @@ #define RLIM_NLIMITS 10 +#ifdef __KERNEL__ + /* * SuS says limits have to be unsigned. * Which makes a ton more sense anyway. */ #define RLIM_INFINITY (~0UL) -#ifdef __KERNEL__ - -#define INIT_RLIMITS \ -{ \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { _STK_LIM, _STK_LIM }, \ - { 0, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { 0, 0 }, \ - { INR_OPEN, INR_OPEN }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ +#define INIT_RLIMITS \ +{ \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { _STK_LIM, RLIM_INFINITY }, \ + { 0, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ + { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/system.h linux/include/asm-arm/system.h --- v2.4.0-test6/linux/include/asm-arm/system.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/system.h Sun Aug 13 09:54:15 2000 @@ -1,11 +1,10 @@ #ifndef __ASM_ARM_SYSTEM_H #define __ASM_ARM_SYSTEM_H -#include - #ifdef __KERNEL__ #include +#include /* information about the system we're running on */ extern unsigned int system_rev; @@ -13,365 +12,14 @@ extern unsigned int system_serial_high; extern unsigned int mem_fclk_21285; -/* The type of machine we're running on */ -extern unsigned int __machine_arch_type; - -/* see arch/arm/kernel/arch.c for a description of these */ -#define MACH_TYPE_EBSA110 0 -#define MACH_TYPE_RISCPC 1 -#define MACH_TYPE_NEXUSPCI 3 -#define MACH_TYPE_EBSA285 4 -#define MACH_TYPE_NETWINDER 5 -#define MACH_TYPE_CATS 6 -#define MACH_TYPE_TBOX 7 -#define MACH_TYPE_CO285 8 -#define MACH_TYPE_CLPS7110 9 -#define MACH_TYPE_ARCHIMEDES 10 -#define MACH_TYPE_A5K 11 -#define MACH_TYPE_ETOILE 12 -#define MACH_TYPE_LACIE_NAS 13 -#define MACH_TYPE_CLPS7500 14 -#define MACH_TYPE_SHARK 15 -#define MACH_TYPE_BRUTUS 16 -#define MACH_TYPE_PERSONAL_SERVER 17 -#define MACH_TYPE_ITSY 18 -#define MACH_TYPE_L7200 19 -/* 20 is free - contact rmk@arm.linux.org.uk directly if you wish to use this number */ -#define MACH_TYPE_INTEGRATOR 21 -#define MACH_TYPE_BITSY 22 -#define MACH_TYPE_IXP1200 23 -#define MACH_TYPE_THINCLIENT 24 -#define MACH_TYPE_ASSABET 25 -#define MACH_TYPE_VICTOR 26 -#define MACH_TYPE_LART 27 -#define MACH_TYPE_RANGER 28 -#define MACH_TYPE_GRAPHICSCLIENT 29 -#define MACH_TYPE_XP860 30 - /* - * Sort out a definition for machine_arch_type - * The rules are: - * 1. If one architecture is selected, then all machine_is_xxx() - * are constant. - * 2. If two or more architectures are selected, then the selected - * machine_is_xxx() are variable, and the unselected machine_is_xxx() - * are constant zero. - * - * In general, you should use machine_is_xxxx() in your code, not: - * - switch (machine_arch_type) { } - * - if (machine_arch_type = xxxx) - * - __machine_arch_type - * - * Please note that these are kept in numeric order (ie, the same - * order as the list above). + * This tells us if we have an ISA bridge + * present in a PCI system. */ -#ifdef CONFIG_ARCH_EBSA110 -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_EBSA110 -# endif -# define machine_is_ebsa110() (machine_arch_type == MACH_TYPE_EBSA110) -#else -# define machine_is_ebsa110() (0) -#endif - -#ifdef CONFIG_ARCH_RPC -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_RISCPC -# endif -# define machine_is_riscpc() (machine_arch_type == MACH_TYPE_RISCPC) -#else -# define machine_is_riscpc() (0) -#endif - -#ifdef CONFIG_ARCH_EBSA285 -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_EBSA285 -# endif -# define machine_is_ebsa285() (machine_arch_type == MACH_TYPE_EBSA285) -#else -# define machine_is_ebsa285() (0) -#endif - -#ifdef CONFIG_ARCH_NETWINDER -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_NETWINDER -# endif -# define machine_is_netwinder() (machine_arch_type == MACH_TYPE_NETWINDER) -#else -# define machine_is_netwinder() (0) -#endif - -#ifdef CONFIG_ARCH_CATS -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_CATS -# endif -# define machine_is_cats() (machine_arch_type == MACH_TYPE_CATS) -#else -# define machine_is_cats() (0) -#endif - -#ifdef CONFIG_ARCH_CO285 -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_CO285 -# endif -# define machine_is_co285() (machine_arch_type == MACH_TYPE_CO285) -#else -# define machine_is_co285() (0) -#endif - -#ifdef CONFIG_ARCH_ARC -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_ARCHIMEDES -# endif -# define machine_is_arc() (machine_arch_type == MACH_TYPE_ARCHIMEDES) -#else -# define machine_is_arc() (0) -#endif - -#ifdef CONFIG_ARCH_A5K -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_A5K -# endif -# define machine_is_a5k() (machine_arch_type == MACH_TYPE_A5K) -#else -# define machine_is_a5k() (0) -#endif - -#ifdef CONFIG_ARCH_CLPS7500 -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_CLPS7500 -# endif -# define machine_is_clps7500() (machine_arch_type == MACH_TYPE_CLPS7500) -#else -# define machine_is_clps7500() (0) -#endif - -#ifdef CONFIG_ARCH_SHARK -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_SHARK -# endif -# define machine_is_shark() (machine_arch_type == MACH_TYPE_SHARK) -#else -# define machine_is_shark() (0) -#endif - -#ifdef CONFIG_SA1100_BRUTUS -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_BRUTUS -# endif -# define machine_is_brutus() (machine_arch_type == MACH_TYPE_BRUTUS) -#else -# define machine_is_brutus() (0) -#endif - -#ifdef CONFIG_ARCH_PERSONAL_SERVER -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_PERSONAL_SERVER -# endif -# define machine_is_personal_server() (machine_arch_type == MACH_TYPE_PERSONAL_SERVER) -#else -# define machine_is_personal_server() (0) -#endif - -#ifdef CONFIG_SA1100_ITSY -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_ITSY -# endif -# define machine_is_itsy() (machine_arch_type == MACH_TYPE_ITSY) -#else -# define machine_is_itsy() (0) -#endif - -#ifdef CONFIG_ARCH_L7200 -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_L7200 -# endif -# define machine_is_l7200() (machine_arch_type == MACH_TYPE_L7200) +#ifdef CONFIG_PCI +extern int have_isa_bridge; #else -# define machine_is_l7200() (0) -#endif - -#ifdef CONFIG_SA1100_BITSY -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_BITSY -# endif -# define machine_is_bitsy() (machine_arch_type == MACH_TYPE_BITSY) -#else -# define machine_is_bitsy() (0) -#endif - -#ifdef CONFIG_SA1100_THINCLIENT -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_THINCLIENT -# endif -# define machine_is_thinclient() (machine_arch_type == MACH_TYPE_THINCLIENT) -#else -# define machine_is_thinclient() (0) -#endif - -#ifdef CONFIG_SA1100_ASSABET -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_ASSABET -# endif -# define machine_is_assabet() (machine_arch_type == MACH_TYPE_ASSABET) -#else -# define machine_is_assabet() (0) -#endif - -#ifdef CONFIG_SA1100_VICTOR -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_VICTOR -# endif -# define machine_is_victor() (machine_arch_type == MACH_TYPE_VICTOR) -#else -# define machine_is_victor() (0) -#endif - -#ifdef CONFIG_SA1100_LART -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_LART -# endif -# define machine_is_lart() (machine_arch_type == MACH_TYPE_LART) -#else -# define machine_is_lart() (0) -#endif - -#ifdef CONFIG_SA1100_GRAPHICSCLIENT -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_GRAPHICSCLIENT -# endif -# define machine_is_grpahicsclient() \ - (machine_arch_type == MACH_TYPE_GRAPHICSCLIENT) -#else -# define machine_is_graphicsclient() \ - (0) -#endif - -#ifdef CONFIG_SA1100_XP860 -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_XP860 -# endif -# define machine_is_xp860() (machine_arch_type == MACH_TYPE_XP860) -#else -# define machine_is_xp860() (0) -#endif - -/* - * The following are currently unregistered - */ -#ifdef CONFIG_SA1100_EMPEG -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_EMPEG -# endif -# define machine_is_empeg() (machine_arch_type == MACH_TYPE_EMPEG) -#else -# define machine_is_empeg() (0) -#endif - -#ifdef CONFIG_SA1100_TIFON -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_TIFON -# endif -# define machine_is_tifon() (machine_arch_type == MACH_TYPE_TIFON) -#else -# define machine_is_tifon() (0) -#endif - -#ifdef CONFIG_SA1100_PLEB -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_PLEB -# endif -# define machine_is_pleb() (machine_arch_type == MACH_TYPE_PLEB) -#else -# define machine_is_pleb() (0) -#endif - -#ifdef CONFIG_SA1100_PENNY -# ifdef machine_arch_type -# undef machine_arch_type -# define machine_arch_type __machine_arch_type -# else -# define machine_arch_type MACH_TYPE_PENNY -# endif -# define machine_is_penny() (machine_arch_type == MACH_TYPE_PENNY) -#else -# define machine_is_penny() (0) -#endif - -#ifndef machine_arch_type -#define machine_arch_type __machine_arch_type +#define have_isa_bridge (0) #endif #include @@ -408,8 +56,6 @@ mb(); \ } while (0) -#endif - /* For spinlocks etc */ #define local_irq_save(x) __save_flags_cli(x) #define local_irq_restore(x) __restore_flags(x) @@ -422,10 +68,14 @@ #define cli() __cli() #define sti() __sti() +#define clf() __clf() +#define stf() __stf() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) #define save_flags_cli(x) __save_flags_cli(x) -#endif +#endif /* CONFIG_SMP */ + +#endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/termbits.h linux/include/asm-arm/termbits.h --- v2.4.0-test6/linux/include/asm-arm/termbits.h Fri Jan 8 11:11:45 1999 +++ linux/include/asm-arm/termbits.h Sun Aug 13 09:54:15 2000 @@ -1,8 +1,6 @@ #ifndef __ASM_ARM_TERMBITS_H #define __ASM_ARM_TERMBITS_H -#include - typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/termios.h linux/include/asm-arm/termios.h --- v2.4.0-test6/linux/include/asm-arm/termios.h Fri Jan 28 15:09:09 2000 +++ linux/include/asm-arm/termios.h Sun Aug 13 09:54:15 2000 @@ -68,8 +68,6 @@ #ifdef __KERNEL__ -#include - /* * Translate a "termio" structure into a "termios". Ugh. */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h --- v2.4.0-test6/linux/include/asm-arm/uaccess.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/uaccess.h Sun Aug 13 09:54:15 2000 @@ -46,7 +46,14 @@ /* * Single-value transfer routines. They automatically use the right - * size if we just have the right pointer type. + * size if we just have the right pointer type. Note that the functions + * which read from user space (*get_*) need to take care not to leak + * kernel data even if the calling code is buggy and fails to check + * the return value. This means zeroing out the destination variable + * or buffer on error. Normally this is done out of line by the + * fixup code, but there are a few places where it intrudes on the + * main code path. When we only write to user space, there is no + * problem. * * The "__xxx" versions of the user access functions do not verify the * address space - it must have been done previously with a separate @@ -54,24 +61,27 @@ * * The "xxx_ret" versions return constant specified in the third * argument if something bad happens. + * + * The "xxx_error" versions set the third argument to EFAULT if an + * error occurs, and leave it unchanged on success. Note that these + * versions are void (ie, don't return a value as such). */ #define get_user(x,p) __get_user_check((x),(p),sizeof(*(p))) #define __get_user(x,p) __get_user_nocheck((x),(p),sizeof(*(p))) +#define __get_user_error(x,p,e) __get_user_nocheck_error((x),(p),sizeof(*(p)),(e)) #define get_user_ret(x,p,r) ({ if (get_user(x,p)) return r; }) #define __get_user_ret(x,p,r) ({ if (__get_user(x,p)) return r; }) #define put_user(x,p) __put_user_check((__typeof(*(p)))(x),(p),sizeof(*(p))) #define __put_user(x,p) __put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p))) +#define __put_user_error(x,p,e) __put_user_nocheck_error((x),(p),sizeof(*(p)),(e)) #define put_user_ret(x,p,r) ({ if (put_user(x,p)) return r; }) #define __put_user_ret(x,p,r) ({ if (__put_user(x,p)) return r; }) static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n) { - char *end = (char *)to + n; - if (access_ok(VERIFY_READ, from, n)) { + if (access_ok(VERIFY_READ, from, n)) __do_copy_from_user(to, from, n); - if (n) memset(end - n, 0, n); - } return n; } @@ -147,26 +157,38 @@ ({ \ long __gu_err = -EFAULT, __gu_val = 0; \ const __typeof__(*(ptr)) *__gu_addr = (ptr); \ - if (access_ok(VERIFY_READ,__gu_addr,size)) \ + if (access_ok(VERIFY_READ,__gu_addr,size)) { \ + __gu_err = 0; \ __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ + } \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) #define __get_user_nocheck(x,ptr,size) \ ({ \ - long __gu_err = 0, __gu_val = 0; \ + long __gu_err = 0, __gu_val; \ __get_user_size(__gu_val,(ptr),(size),__gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) +#define __get_user_nocheck_error(x,ptr,size,err) \ +({ \ + long __gu_val; \ + __get_user_size(__gu_val,(ptr),(size),(err)); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + (void) 0; \ +}) + #define __put_user_check(x,ptr,size) \ ({ \ long __pu_err = -EFAULT; \ __typeof__(*(ptr)) *__pu_addr = (ptr); \ - if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ + if (access_ok(VERIFY_WRITE,__pu_addr,size)) { \ + __pu_err = 0; \ __put_user_size((x),__pu_addr,(size),__pu_err); \ + } \ __pu_err; \ }) @@ -177,11 +199,16 @@ __pu_err; \ }) +#define __put_user_nocheck_error(x,ptr,size,err) \ +({ \ + __put_user_size((x),(ptr),(size),err); \ + (void) 0; \ +}) + extern long __get_user_bad(void); #define __get_user_size(x,ptr,size,retval) \ do { \ - retval = 0; \ switch (size) { \ case 1: __get_user_asm_byte(x,ptr,retval); break; \ case 2: __get_user_asm_half(x,ptr,retval); break; \ @@ -194,7 +221,6 @@ #define __put_user_size(x,ptr,size,retval) \ do { \ - retval = 0; \ switch (size) { \ case 1: __put_user_asm_byte(x,ptr,retval); break; \ case 2: __put_user_asm_half(x,ptr,retval); break; \ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/unaligned.h linux/include/asm-arm/unaligned.h --- v2.4.0-test6/linux/include/asm-arm/unaligned.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-arm/unaligned.h Sun Aug 13 09:54:15 2000 @@ -1,7 +1,7 @@ #ifndef __ASM_ARM_UNALIGNED_H #define __ASM_ARM_UNALIGNED_H -#include +#include extern int __bug_unaligned_x(void *ptr); diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h --- v2.4.0-test6/linux/include/asm-arm/unistd.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-arm/unistd.h Fri Aug 11 14:29:03 2000 @@ -223,6 +223,7 @@ #define __NR_setgid32 (__NR_SYSCALL_BASE+214) #define __NR_setfsuid32 (__NR_SYSCALL_BASE+215) #define __NR_setfsgid32 (__NR_SYSCALL_BASE+216) +#define __NR_getdents64 (__NR_SYSCALL_BASE+217) #define __sys2(x) #x #define __sys1(x) __sys2(x) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/user.h linux/include/asm-arm/user.h --- v2.4.0-test6/linux/include/asm-arm/user.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/user.h Sun Aug 13 09:54:15 2000 @@ -2,7 +2,7 @@ #define _ARM_USER_H #include -#include +#include /* Core file format: The core file is written in such a way that gdb can understand it and provide useful information to the user (under linux we use the 'trad-core' bfd). There are quite a number of diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h --- v2.4.0-test6/linux/include/asm-i386/apic.h Mon Jun 19 16:32:01 2000 +++ linux/include/asm-i386/apic.h Wed Aug 23 11:35:06 2000 @@ -68,6 +68,7 @@ extern void connect_bsp_APIC (void); extern void disconnect_bsp_APIC (void); extern void disable_local_APIC (void); +extern int verify_local_APIC (void); extern void cache_APIC_registers (void); extern void sync_Arb_IDs(void); extern void setup_local_APIC (void); diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/apicdef.h linux/include/asm-i386/apicdef.h --- v2.4.0-test6/linux/include/asm-i386/apicdef.h Tue May 23 15:31:36 2000 +++ linux/include/asm-i386/apicdef.h Fri Aug 18 09:30:51 2000 @@ -11,10 +11,12 @@ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 #define APIC_ID 0x20 +#define APIC_ID_MASK (0x0F<<24) #define GET_APIC_ID(x) (((x)>>24)&0x0F) #define APIC_LVR 0x30 +#define APIC_LVR_MASK 0xFF00FF #define GET_APIC_VERSION(x) ((x)&0xFF) -#define GET_APIC_MAXLVT(x) (((x)>>16)&0x0F) +#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF) #define APIC_INTEGRATED(x) ((x)&0xF0) #define APIC_TASKPRI 0x80 #define APIC_TPRI_MASK 0xFF diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.4.0-test6/linux/include/asm-i386/bugs.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-i386/bugs.h Wed Aug 23 11:54:53 2000 @@ -463,7 +463,7 @@ && boot_cpu_data.x86 == 5 && boot_cpu_data.x86_model == 2 && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11)) - panic("Kernel compiled for PPro+, assumes a local APIC without the read-before-write bug!"); + panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!"); #endif /* diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/e820.h linux/include/asm-i386/e820.h --- v2.4.0-test6/linux/include/asm-i386/e820.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-i386/e820.h Fri Aug 18 09:30:51 2000 @@ -28,9 +28,9 @@ struct e820map { int nr_map; struct e820entry { - long long addr; /* start of memory segment */ - long long size; /* size of memory segment */ - long type; /* type of memory segment */ + unsigned long long addr; /* start of memory segment */ + unsigned long long size; /* size of memory segment */ + unsigned long type; /* type of memory segment */ } map[E820MAX]; }; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h --- v2.4.0-test6/linux/include/asm-i386/fcntl.h Mon Jul 10 16:47:26 2000 +++ linux/include/asm-i386/fcntl.h Fri Aug 11 14:37:49 2000 @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -60,6 +64,14 @@ off_t l_start; off_t l_len; pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; }; #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h --- v2.4.0-test6/linux/include/asm-i386/mmu_context.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-i386/mmu_context.h Wed Aug 23 11:36:57 2000 @@ -10,7 +10,7 @@ * possibly do the LDT unload here? */ #define destroy_context(mm) do { } while(0) -#define init_new_context(tsk,mm) do { } while (0) +#define init_new_context(tsk,mm) 0 #ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.4.0-test6/linux/include/asm-i386/unistd.h Tue Mar 14 19:10:40 2000 +++ linux/include/asm-i386/unistd.h Fri Aug 11 14:39:23 2000 @@ -225,6 +225,8 @@ #define __NR_mincore 218 #define __NR_madvise 219 #define __NR_madvise1 219 /* delete when C lib stub is removed */ +#define __NR_getdents64 220 +#define __NR_fcntl64 221 /* user-visible error numbers are in the range -1 - -124: see */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/acpi-ext.h linux/include/asm-ia64/acpi-ext.h --- v2.4.0-test6/linux/include/asm-ia64/acpi-ext.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-ia64/acpi-ext.h Fri Aug 11 19:09:06 2000 @@ -69,7 +69,7 @@ u8 eid; } acpi_entry_lsapic_t; -typedef struct { +typedef struct acpi_entry_iosapic { u8 type; u8 length; u16 reserved; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/asmmacro.h linux/include/asm-ia64/asmmacro.h --- v2.4.0-test6/linux/include/asm-ia64/asmmacro.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ia64/asmmacro.h Fri Aug 11 19:09:06 2000 @@ -23,7 +23,7 @@ #endif #define ENTRY(name) \ - .align 16; \ + .align 32; \ .proc name; \ name: diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/efi.h linux/include/asm-ia64/efi.h --- v2.4.0-test6/linux/include/asm-ia64/efi.h Fri Mar 10 16:40:49 2000 +++ linux/include/asm-ia64/efi.h Fri Aug 11 19:09:06 2000 @@ -226,6 +226,7 @@ } extern void efi_init (void); +extern void efi_map_pal_code (void); extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); extern void efi_gettimeofday (struct timeval *tv); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/ia32.h linux/include/asm-ia64/ia32.h --- v2.4.0-test6/linux/include/asm-ia64/ia32.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-ia64/ia32.h Fri Aug 11 19:09:06 2000 @@ -40,7 +40,6 @@ __kernel_off_t32 l_start; __kernel_off_t32 l_len; __kernel_pid_t32 l_pid; - short __unused; }; @@ -105,11 +104,21 @@ } sigset32_t; struct sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal - with 32 bits */ + unsigned int sa_handler; /* Really a pointer, but need to deal + with 32 bits */ unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ - sigset32_t sa_mask; /* A 32 bit mask */ + unsigned int sa_restorer; /* Another 32 bit pointer */ + sigset32_t sa_mask; /* A 32 bit mask */ +}; + +typedef unsigned int old_sigset32_t; /* at least 32 bits */ + +struct old_sigaction32 { + unsigned int sa_handler; /* Really a pointer, but need to deal + with 32 bits */ + old_sigset32_t sa_mask; /* A 32 bit mask */ + unsigned int sa_flags; + unsigned int sa_restorer; /* Another 32 bit pointer */ }; typedef struct sigaltstack_ia32 { diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/io.h linux/include/asm-ia64/io.h --- v2.4.0-test6/linux/include/asm-ia64/io.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-ia64/io.h Fri Aug 11 19:09:06 2000 @@ -47,6 +47,10 @@ return (void *) (address + PAGE_OFFSET); } +/* + * The following two macros are deprecated and scheduled for removal. + * Please use the PCI-DMA interface defined in instead. + */ #define bus_to_virt phys_to_virt #define virt_to_bus virt_to_phys @@ -315,6 +319,7 @@ #define writeq(v,a) __writeq((v), (void *) (a)) #define __raw_writeb writeb #define __raw_writew writew +#define __raw_writel writel #define __raw_writeq writeq #ifndef inb_p diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/machvec.h linux/include/asm-ia64/machvec.h --- v2.4.0-test6/linux/include/asm-ia64/machvec.h Fri Mar 10 16:40:49 2000 +++ linux/include/asm-ia64/machvec.h Fri Aug 11 19:09:06 2000 @@ -4,8 +4,8 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Srinivasa Thirumalachar * Copyright (C) Vijay Chander - * Copyright (C) 1999 Hewlett-Packard Co. - * Copyright (C) David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2000 David Mosberger-Tang */ #ifndef _ASM_IA64_MACHVEC_H #define _ASM_IA64_MACHVEC_H @@ -21,6 +21,7 @@ struct task_struct; struct timeval; struct vm_area_struct; +struct acpi_entry_iosapic; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_irq_init_t (void); @@ -30,15 +31,33 @@ typedef void ia64_mv_mca_handler_t (void); typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *); typedef void ia64_mv_log_print_t (void); +typedef void ia64_mv_register_iosapic_t (struct acpi_entry_iosapic *); + +extern void machvec_noop (void); # if defined (CONFIG_IA64_HP_SIM) # include # elif defined (CONFIG_IA64_DIG) # include # elif defined (CONFIG_IA64_SGI_SN1_SIM) -# include +# include # elif defined (CONFIG_IA64_GENERIC) +# ifdef MACHVEC_PLATFORM_HEADER +# include MACHVEC_PLATFORM_HEADER +# else +# define platform_name ia64_mv.name +# define platform_setup ia64_mv.setup +# define platform_irq_init ia64_mv.irq_init +# define platform_map_nr ia64_mv.map_nr +# define platform_mca_init ia64_mv.mca_init +# define platform_mca_handler ia64_mv.mca_handler +# define platform_cmci_handler ia64_mv.cmci_handler +# define platform_log_print ia64_mv.log_print +# define platform_pci_fixup ia64_mv.pci_fixup +# define platform_register_iosapic ia64_mv.register_iosapic +# endif + struct ia64_machine_vector { const char *name; ia64_mv_setup_t *setup; @@ -49,6 +68,7 @@ ia64_mv_mca_handler_t *mca_handler; ia64_mv_cmci_handler_t *cmci_handler; ia64_mv_log_print_t *log_print; + ia64_mv_register_iosapic_t *register_iosapic; }; #define MACHVEC_INIT(name) \ @@ -61,22 +81,12 @@ platform_mca_init, \ platform_mca_handler, \ platform_cmci_handler, \ - platform_log_print \ + platform_log_print, \ + platform_register_iosapic \ } -# ifndef MACHVEC_INHIBIT_RENAMING -# define platform_name ia64_mv.name -# define platform_setup ia64_mv.setup -# define platform_irq_init ia64_mv.irq_init -# define platform_map_nr ia64_mv.map_nr -# define platform_mca_init ia64_mv.mca_init -# define platform_mca_handler ia64_mv.mca_handler -# define platform_cmci_handler ia64_mv.cmci_handler -# define platform_log_print ia64_mv.log_print -# endif - extern struct ia64_machine_vector ia64_mv; -extern void machvec_noop (void); +extern void machvec_init (const char *name); # else # error Unknown configuration. Update asm-ia64/machvec.h. @@ -103,6 +113,12 @@ #endif #ifndef platform_log_print # define platform_log_print ((ia64_mv_log_print_t *) machvec_noop) +#endif +#ifndef platform_pci_fixup +# define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop) +#endif +#ifndef platform_register_iosapic +# define platform_register_iosapic ((ia64_mv_register_iosapic_t *) machvec_noop) #endif #endif /* _ASM_IA64_MACHVEC_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/machvec_dig.h linux/include/asm-ia64/machvec_dig.h --- v2.4.0-test6/linux/include/asm-ia64/machvec_dig.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-ia64/machvec_dig.h Fri Aug 11 19:09:06 2000 @@ -5,6 +5,7 @@ extern ia64_mv_irq_init_t dig_irq_init; extern ia64_mv_pci_fixup_t dig_pci_fixup; extern ia64_mv_map_nr_t map_nr_dense; +extern ia64_mv_register_iosapic_t dig_register_iosapic; /* * This stuff has dual use! @@ -18,5 +19,6 @@ #define platform_irq_init dig_irq_init #define platform_pci_fixup dig_pci_fixup #define platform_map_nr map_nr_dense +#define platform_register_iosapic dig_register_iosapic #endif /* _ASM_IA64_MACHVEC_DIG_h */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/machvec_init.h linux/include/asm-ia64/machvec_init.h --- v2.4.0-test6/linux/include/asm-ia64/machvec_init.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-ia64/machvec_init.h Fri Aug 11 19:09:06 2000 @@ -1,4 +1,6 @@ -#define MACHVEC_INHIBIT_RENAMING +#define __MACHVEC_HDR(n) +#define __MACHVEC_EXPAND(n) __MACHVEC_HDR(n) +#define MACHVEC_PLATFORM_HEADER __MACHVEC_EXPAND(MACHVEC_PLATFORM_NAME) #include @@ -7,3 +9,5 @@ = MACHVEC_INIT(name); #define MACHVEC_DEFINE(name) MACHVEC_HELPER(name) + +MACHVEC_DEFINE(MACHVEC_PLATFORM_NAME) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/mmu_context.h linux/include/asm-ia64/mmu_context.h --- v2.4.0-test6/linux/include/asm-ia64/mmu_context.h Sun Feb 13 19:29:04 2000 +++ linux/include/asm-ia64/mmu_context.h Fri Aug 11 19:09:06 2000 @@ -2,12 +2,13 @@ #define _ASM_IA64_MMU_CONTEXT_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang */ #include #include +#include #include @@ -26,21 +27,6 @@ * architecture manual guarantees this number to be in the range * 18-24. * - * A context number has the following format: - * - * +--------------------+---------------------+ - * | generation number | region id | - * +--------------------+---------------------+ - * - * A context number of 0 is considered "invalid". - * - * The generation number is incremented whenever we end up having used - * up all available region ids. At that point with flush the entire - * TLB and reuse the first region id. The new generation number - * ensures that when we context switch back to an old process, we do - * not inadvertently end up using its possibly reused region id. - * Instead, we simply allocate a new region id for that process. - * * Copyright (C) 1998 David Mosberger-Tang */ @@ -56,9 +42,15 @@ #define IA64_HW_CONTEXT_MASK ((1UL << IA64_HW_CONTEXT_BITS) - 1) -extern unsigned long ia64_next_context; +struct ia64_ctx { + spinlock_t lock; + unsigned int next; /* next context number to use */ + unsigned int limit; /* next >= limit => must call wrap_mmu_context() */ +}; -extern void get_new_mmu_context (struct mm_struct *mm); +extern struct ia64_ctx ia64_ctx; + +extern void wrap_mmu_context (struct mm_struct *mm); static inline void enter_lazy_tlb (struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) @@ -76,18 +68,31 @@ } extern inline void +get_new_mmu_context (struct mm_struct *mm) +{ + spin_lock(&ia64_ctx.lock); + { + if (ia64_ctx.next >= ia64_ctx.limit) + wrap_mmu_context(mm); + mm->context = ia64_ctx.next++; + } + spin_unlock(&ia64_ctx.lock); + +} + +extern inline void get_mmu_context (struct mm_struct *mm) { /* check if our ASN is of an older generation and thus invalid: */ - if (((mm->context ^ ia64_next_context) & ~IA64_HW_CONTEXT_MASK) != 0) { + if (mm->context == 0) get_new_mmu_context(mm); - } } -extern inline void +extern inline int init_new_context (struct task_struct *p, struct mm_struct *mm) { mm->context = 0; + return 0; } extern inline void @@ -103,7 +108,7 @@ unsigned long rid_incr = 0; unsigned long rr0, rr1, rr2, rr3, rr4; - rid = (mm->context & IA64_HW_CONTEXT_MASK); + rid = mm->context; #ifndef CONFIG_IA64_TLB_CHECKS_REGION_NUMBER rid <<= 3; /* make space for encoding the region number */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h --- v2.4.0-test6/linux/include/asm-ia64/offsets.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-ia64/offsets.h Fri Aug 11 19:09:06 2000 @@ -11,10 +11,10 @@ #define PT_PTRACED_BIT 0 #define PT_TRACESYS_BIT 1 -#define IA64_TASK_SIZE 2768 /* 0xad0 */ +#define IA64_TASK_SIZE 2864 /* 0xb30 */ #define IA64_PT_REGS_SIZE 400 /* 0x190 */ #define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */ -#define IA64_SIGINFO_SIZE 136 /* 0x88 */ +#define IA64_SIGINFO_SIZE 128 /* 0x80 */ #define UNW_FRAME_INFO_SIZE 448 /* 0x1c0 */ #define IA64_TASK_PTRACE_OFFSET 48 /* 0x30 */ @@ -23,7 +23,7 @@ #define IA64_TASK_PROCESSOR_OFFSET 100 /* 0x64 */ #define IA64_TASK_THREAD_OFFSET 896 /* 0x380 */ #define IA64_TASK_THREAD_KSP_OFFSET 896 /* 0x380 */ -#define IA64_TASK_THREAD_SIGMASK_OFFSET 2648 /* 0xa58 */ +#define IA64_TASK_THREAD_SIGMASK_OFFSET 2744 /* 0xab8 */ #define IA64_TASK_PID_OFFSET 188 /* 0xbc */ #define IA64_TASK_MM_OFFSET 88 /* 0x58 */ #define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/page.h linux/include/asm-ia64/page.h --- v2.4.0-test6/linux/include/asm-ia64/page.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-ia64/page.h Fri Aug 11 19:09:06 2000 @@ -100,13 +100,14 @@ #define MAP_NR_SN1(addr) (((unsigned long) (addr) - PAGE_OFFSET) >> PAGE_SHIFT) #ifdef CONFIG_IA64_GENERIC -# define virt_to_page(kaddr) (mem_map + platform_map_nr(kaddr)) +# include +# define virt_to_page(kaddr) (mem_map + platform_map_nr(kaddr)) #elif defined (CONFIG_IA64_SN_SN1_SIM) -# define virt_to_page(kaddr) (mem_map + MAP_NR_SN1(kaddr)) +# define virt_to_page(kaddr) (mem_map + MAP_NR_SN1(kaddr)) #else -# define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) +# define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) #endif -#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) # endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h --- v2.4.0-test6/linux/include/asm-ia64/pal.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ia64/pal.h Fri Aug 11 19:09:06 2000 @@ -18,7 +18,8 @@ * 00/03/07 davidm Updated pal_cache_flush() to be in sync with PAL v2.6. * 00/03/23 cfleck Modified processor min-state save area to match updated PAL & SAL info * 00/05/24 eranian Updated to latest PAL spec, fix structures bugs, added - * 00/05/25 eranian Support for stack calls, and statis physical calls + * 00/05/25 eranian Support for stack calls, and static physical calls + * 00/06/18 eranian Support for stacked physical calls */ /* @@ -646,10 +647,12 @@ extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_stacked (u64, u64, u64, u64); extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64); +extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64); #define PAL_CALL(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_static(a0, a1, a2, a3) #define PAL_CALL_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_stacked(a0, a1, a2, a3) #define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_static(a0, a1, a2, a3) +#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3) typedef int (*ia64_pal_handler) (u64, ...); extern ia64_pal_handler ia64_pal; @@ -951,7 +954,7 @@ /* Return information about processor's optional power management capabilities. */ extern inline s64 ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf) -{ +{ struct ia64_pal_retval iprv; PAL_CALL_STK(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0); return iprv.status; @@ -1370,17 +1373,17 @@ dirty_bit_valid : 1, mem_attr_valid : 1, reserved : 60; - } pal_itr_valid_s; -} pal_itr_valid_u_t; + } pal_tr_valid_s; +} pal_tr_valid_u_t; /* Read a translation register */ extern inline s64 -ia64_pal_vm_tr_read (u64 reg_num, u64 tr_type, u64 tr_buffer, pal_itr_valid_u_t *itr_valid) -{ +ia64_pal_tr_read (u64 reg_num, u64 tr_type, u64 *tr_buffer, pal_tr_valid_u_t *tr_valid) +{ struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_VM_TR_READ, reg_num, tr_type, tr_buffer); - if (itr_valid) - itr_valid->piv_val = iprv.v0; + PAL_CALL_PHYS_STK(iprv, PAL_VM_TR_READ, reg_num, tr_type,(u64)__pa(tr_buffer)); + if (tr_valid) + tr_valid->piv_val = iprv.v0; return iprv.status; } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/param.h linux/include/asm-ia64/param.h --- v2.4.0-test6/linux/include/asm-ia64/param.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-ia64/param.h Fri Aug 11 19:09:06 2000 @@ -10,23 +10,13 @@ #include -#ifdef CONFIG_IA64_HP_SIM +#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_SOFTSDV_HACKS) /* * Yeah, simulating stuff is slow, so let us catch some breath between * timer interrupts... */ # define HZ 20 -#endif - -#ifdef CONFIG_IA64_DIG -# ifdef CONFIG_IA64_SOFTSDV_HACKS -# define HZ 20 -# else -# define HZ 100 -# endif -#endif - -#ifndef HZ +#else # define HZ 1024 #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h --- v2.4.0-test6/linux/include/asm-ia64/pci.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ia64/pci.h Sun Aug 13 10:17:16 2000 @@ -1,6 +1,14 @@ #ifndef _ASM_IA64_PCI_H #define _ASM_IA64_PCI_H +#include +#include +#include +#include + +#include +#include + /* * Can be used to override the logic in pci_scan_bus for skipping * already-configured bus numbers - to be used for buggy BIOSes or @@ -11,6 +19,8 @@ #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM 0x10000000 +struct pci_dev; + extern inline void pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ @@ -23,18 +33,8 @@ /* * Dynamic DMA mapping API. - * IA-64 has everything mapped statically. */ -#include -#include -#include - -#include -#include - -struct pci_dev; - /* * Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices, @@ -64,13 +64,7 @@ * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern inline dma_addr_t -pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - return virt_to_bus(ptr); -} +extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); /* * Unmap a single streaming mode DMA translation. The dma_addr and size @@ -80,13 +74,7 @@ * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern inline void -pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); /* * Map a set of buffers described by scatterlist in streaming @@ -104,26 +92,14 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern inline int -pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - return nents; -} +extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* * Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern inline void -pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* * Make physical memory consistent for a single @@ -135,13 +111,7 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern inline void -pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); /* * Make physical memory consistent for a set of streaming mode DMA @@ -150,20 +120,15 @@ * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern inline void -pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - /* Nothing to do */ -} +extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); /* Return whether the given PCI device DMA address mask can * be supported properly. For example, if your device can * only drive the low 24-bits during PCI bus mastering, then * you would pass 0x00ffffff as the mask to this function. */ -extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +extern inline int +pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) { return 1; } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h --- v2.4.0-test6/linux/include/asm-ia64/pgtable.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-ia64/pgtable.h Sun Aug 13 10:17:16 2000 @@ -286,7 +286,17 @@ * contains the memory attribute bits, dirty bits, and various other * bits as well. */ -#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) +#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) + +/* + * Macro to make mark a page protection value as "write-combining". + * Note that "protection" is really a misnomer here as the protection + * value contains the memory attribute bits, dirty bits, and various + * other bits as well. Accesses through a write-combining translation + * works bypasses the caches, but does allow for consecutive writes to + * be combined into single (but larger) write transactions. + */ +#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) /* * Return the region index for virtual address ADDRESS. diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h --- v2.4.0-test6/linux/include/asm-ia64/processor.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-ia64/processor.h Fri Aug 11 19:09:06 2000 @@ -19,6 +19,7 @@ #include #define IA64_NUM_DBG_REGS 8 +#define IA64_NUM_PM_REGS 4 /* * TASK_SIZE really is a mis-named. It really is the maximum user @@ -152,12 +153,13 @@ #define IA64_THREAD_FPH_VALID (__IA64_UL(1) << 0) /* floating-point high state valid? */ #define IA64_THREAD_DBG_VALID (__IA64_UL(1) << 1) /* debug registers valid? */ -#define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 2) /* don't log unaligned accesses */ -#define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 3) /* generate SIGBUS on unaligned acc. */ -#define IA64_THREAD_KRBS_SYNCED (__IA64_UL(1) << 4) /* krbs synced with process vm? */ +#define IA64_THREAD_PM_VALID (__IA64_UL(1) << 2) /* performance registers valid? */ +#define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 3) /* don't log unaligned accesses */ +#define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 4) /* generate SIGBUS on unaligned acc. */ +#define IA64_THREAD_KRBS_SYNCED (__IA64_UL(1) << 5) /* krbs synced with process vm? */ #define IA64_KERNEL_DEATH (__IA64_UL(1) << 63) /* see die_if_kernel()... */ -#define IA64_THREAD_UAC_SHIFT 2 +#define IA64_THREAD_UAC_SHIFT 3 #define IA64_THREAD_UAC_MASK (IA64_THREAD_UAC_NOPRINT | IA64_THREAD_UAC_SIGBUS) #ifndef __ASSEMBLY__ @@ -285,6 +287,14 @@ struct ia64_fpreg fph[96]; /* saved/loaded on demand */ __u64 dbr[IA64_NUM_DBG_REGS]; __u64 ibr[IA64_NUM_DBG_REGS]; +#ifdef CONFIG_PERFMON + __u64 pmc[IA64_NUM_PM_REGS]; + __u64 pmd[IA64_NUM_PM_REGS]; + __u64 pmod[IA64_NUM_PM_REGS]; +# define INIT_THREAD_PM {0, }, {0, }, {0, }, +#else +# define INIT_THREAD_PM +#endif __u64 map_base; /* base address for mmap() */ #ifdef CONFIG_IA32_SUPPORT __u64 eflag; /* IA32 EFLAGS reg */ @@ -316,6 +326,7 @@ {{{{0}}}, }, /* fph */ \ {0, }, /* dbr */ \ {0, }, /* ibr */ \ + INIT_THREAD_PM \ 0x2000000000000000 /* map_base */ \ INIT_THREAD_IA32, \ 0 /* siginfo */ \ @@ -338,8 +349,12 @@ struct mm_struct; struct task_struct; -/* Free all resources held by a thread. */ -extern void release_thread (struct task_struct *); +/* + * Free all resources held by a thread. This is called after the + * parent of DEAD_TASK has collected the exist status of the task via + * wait(). This is a no-op on IA-64. + */ +#define release_thread(dead_task) /* * This is the mechanism for creating a new kernel thread. @@ -392,6 +407,18 @@ extern void __ia64_init_fpu (void); extern void __ia64_save_fpu (struct ia64_fpreg *fph); extern void __ia64_load_fpu (struct ia64_fpreg *fph); +extern void ia64_save_debug_regs (unsigned long *save_area); +extern void ia64_load_debug_regs (unsigned long *save_area); + +#ifdef CONFIG_IA32_SUPPORT +extern void ia32_save_state (struct thread_struct *thread); +extern void ia32_load_state (struct thread_struct *thread); +#endif + +#ifdef CONFIG_PERFMON +extern void ia64_save_pm_regs (struct thread_struct *thread); +extern void ia64_load_pm_regs (struct thread_struct *thread); +#endif #define ia64_fph_enable() __asm__ __volatile__ (";; rsm psr.dfh;; srlz.d;;" ::: "memory"); #define ia64_fph_disable() __asm__ __volatile__ (";; ssm psr.dfh;; srlz.d;;" ::: "memory"); diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/scatterlist.h linux/include/asm-ia64/scatterlist.h --- v2.4.0-test6/linux/include/asm-ia64/scatterlist.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-ia64/scatterlist.h Fri Aug 11 19:09:06 2000 @@ -13,6 +13,7 @@ * indirection buffer, NULL otherwise: */ char *alt_address; + char *orig_address; /* Save away the original buffer address (used by pci-dma.c) */ unsigned int length; /* buffer length */ }; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/siginfo.h linux/include/asm-ia64/siginfo.h --- v2.4.0-test6/linux/include/asm-ia64/siginfo.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ia64/siginfo.h Fri Aug 11 19:09:06 2000 @@ -14,12 +14,13 @@ } sigval_t; #define SI_MAX_SIZE 128 -#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 3) +#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4) typedef struct siginfo { int si_signo; int si_errno; int si_code; + int __pad0; union { int _pad[SI_PAD_SIZE]; @@ -212,7 +213,7 @@ #define SIGEV_THREAD 2 /* deliver via thread creation */ #define SIGEV_MAX_SIZE 64 -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) +#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) typedef struct sigevent { sigval_t sigev_value; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h --- v2.4.0-test6/linux/include/asm-ia64/smp.h Wed Apr 26 16:34:09 2000 +++ linux/include/asm-ia64/smp.h Fri Aug 11 19:09:06 2000 @@ -99,5 +99,9 @@ extern void __init init_smp_config (void); extern void smp_do_timer (struct pt_regs *regs); +extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info, + int retry, int wait); + + #endif /* CONFIG_SMP */ #endif /* _ASM_IA64_SMP_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/spinlock.h linux/include/asm-ia64/spinlock.h --- v2.4.0-test6/linux/include/asm-ia64/spinlock.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ia64/spinlock.h Fri Aug 11 19:09:06 2000 @@ -15,8 +15,11 @@ #include #include +#undef NEW_LOCK + +#ifdef NEW_LOCK typedef struct { - volatile unsigned int lock; + volatile unsigned char lock; } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } @@ -26,44 +29,86 @@ * Streamlined test_and_set_bit(0, (x)). We use test-and-test-and-set * rather than a simple xchg to avoid writing the cache-line when * there is contention. + * + * XXX Fix me: instead of preserving ar.pfs, we should just mark it + * XXX as "clobbered". Unfortunately, the Mar 2000 release of the compiler + * XXX doesn't let us do that. The August release fixes that. */ -#if 1 /* Bad code generation? */ -#define spin_lock(x) __asm__ __volatile__ ( \ - "mov ar.ccv = r0\n" \ - "mov r29 = 1\n" \ - ";;\n" \ - "1:\n" \ - "ld4 r2 = %0\n" \ - ";;\n" \ - "cmp4.eq p0,p7 = r0,r2\n" \ - "(p7) br.cond.spnt.few 1b \n" \ - "cmpxchg4.acq r2 = %0, r29, ar.ccv\n" \ - ";;\n" \ - "cmp4.eq p0,p7 = r0, r2\n" \ - "(p7) br.cond.spnt.few 1b\n" \ - ";;\n" \ - :: "m" __atomic_fool_gcc((x)) : "r2", "r29", "memory") - -#else -#define spin_lock(x) \ -{ \ - spinlock_t *__x = (x); \ - \ - do { \ - while (__x->lock); \ - } while (cmpxchg_acq(&__x->lock, 0, 1)); \ +#define spin_lock(x) \ +{ \ + register char *addr __asm__ ("r31") = (char *) &(x)->lock; \ + long saved_pfs; \ + \ + __asm__ __volatile__ ( \ + "mov r30=1\n" \ + "mov ar.ccv=r0\n" \ + ";;\n" \ + IA64_SEMFIX"cmpxchg1.acq r30=[%1],r30,ar.ccv\n" \ + ";;\n" \ + "cmp.ne p15,p0=r30,r0\n" \ + "mov %0=ar.pfs\n" \ + "(p15) br.call.spnt.few b7=ia64_spinlock_contention\n" \ + ";;\n" \ + "1: (p15) mov ar.pfs=%0;;\n" /* force a new bundle */ \ + : "=&r"(saved_pfs) : "r"(addr) \ + : "p15", "r28", "r29", "r30", "memory"); \ } -#endif + +#define spin_trylock(x) \ +({ \ + register char *addr __asm__ ("r31") = (char *) &(x)->lock; \ + register long result; \ + \ + __asm__ __volatile__ ( \ + "mov r30=1\n" \ + "mov ar.ccv=r0\n" \ + ";;\n" \ + IA64_SEMFIX"cmpxchg1.acq %0=[%1],r30,ar.ccv\n" \ + : "=r"(result) : "r"(addr) : "r30", "memory"); \ + (result == 0); \ +}) #define spin_is_locked(x) ((x)->lock != 0) +#define spin_unlock(x) ({((spinlock_t *) x)->lock = 0;}) +#define spin_unlock_wait(x) ({ while ((x)->lock); }) -#define spin_unlock(x) ({((spinlock_t *) x)->lock = 0; barrier();}) +#else /* !NEW_LOCK */ -/* Streamlined !test_and_set_bit(0, (x)) */ -#define spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0) +typedef struct { + volatile unsigned int lock; +} spinlock_t; + +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +#define spin_lock_init(x) ((x)->lock = 0) +/* + * Streamlined test_and_set_bit(0, (x)). We use test-and-test-and-set + * rather than a simple xchg to avoid writing the cache-line when + * there is contention. + */ +#define spin_lock(x) __asm__ __volatile__ ( \ + "mov ar.ccv = r0\n" \ + "mov r29 = 1\n" \ + ";;\n" \ + "1:\n" \ + "ld4 r2 = %0\n" \ + ";;\n" \ + "cmp4.eq p0,p7 = r0,r2\n" \ + "(p7) br.cond.spnt.few 1b \n" \ + IA64_SEMFIX"cmpxchg4.acq r2 = %0, r29, ar.ccv\n" \ + ";;\n" \ + "cmp4.eq p0,p7 = r0, r2\n" \ + "(p7) br.cond.spnt.few 1b\n" \ + ";;\n" \ + :: "m" __atomic_fool_gcc((x)) : "r2", "r29", "memory") + +#define spin_is_locked(x) ((x)->lock != 0) +#define spin_unlock(x) ({((spinlock_t *) x)->lock = 0; barrier();}) +#define spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0) #define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); }) +#endif /* !NEW_LOCK */ + typedef struct { volatile int read_counter:31; volatile int write_lock:1; @@ -73,12 +118,12 @@ #define read_lock(rw) \ do { \ int tmp = 0; \ - __asm__ __volatile__ ("1:\tfetchadd4.acq %0 = %1, 1\n" \ + __asm__ __volatile__ ("1:\t"IA64_SEMFIX"fetchadd4.acq %0 = %1, 1\n" \ ";;\n" \ "tbit.nz p6,p0 = %0, 31\n" \ "(p6) br.cond.sptk.few 2f\n" \ ".section .text.lock,\"ax\"\n" \ - "2:\tfetchadd4.rel %0 = %1, -1\n" \ + "2:\t"IA64_SEMFIX"fetchadd4.rel %0 = %1, -1\n" \ ";;\n" \ "3:\tld4.acq %0 = %1\n" \ ";;\n" \ @@ -94,7 +139,7 @@ #define read_unlock(rw) \ do { \ int tmp = 0; \ - __asm__ __volatile__ ("fetchadd4.rel %0 = %1, -1\n" \ + __asm__ __volatile__ (IA64_SEMFIX"fetchadd4.rel %0 = %1, -1\n" \ : "=r" (tmp) \ : "m" (__atomic_fool_gcc(rw)) \ : "memory"); \ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h --- v2.4.0-test6/linux/include/asm-ia64/system.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-ia64/system.h Fri Aug 11 19:09:06 2000 @@ -27,6 +27,15 @@ #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) +#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) + /* Workaround for Errata 97. */ +# define IA64_SEMFIX_INSN mf; +# define IA64_SEMFIX "mf;" +#else +# define IA64_SEMFIX_INSN +# define IA64_SEMFIX "" +#endif + #ifndef __ASSEMBLY__ #include @@ -231,13 +240,13 @@ ({ \ switch (sz) { \ case 4: \ - __asm__ __volatile__ ("fetchadd4.rel %0=%1,%3" \ + __asm__ __volatile__ (IA64_SEMFIX"fetchadd4.rel %0=%1,%3" \ : "=r"(tmp), "=m"(__atomic_fool_gcc(v)) \ : "m" (__atomic_fool_gcc(v)), "i"(n)); \ break; \ \ case 8: \ - __asm__ __volatile__ ("fetchadd8.rel %0=%1,%3" \ + __asm__ __volatile__ (IA64_SEMFIX"fetchadd8.rel %0=%1,%3" \ : "=r"(tmp), "=m"(__atomic_fool_gcc(v)) \ : "m" (__atomic_fool_gcc(v)), "i"(n)); \ break; \ @@ -280,22 +289,22 @@ switch (size) { case 1: - __asm__ __volatile ("xchg1 %0=%1,%2" : "=r" (result) + __asm__ __volatile (IA64_SEMFIX"xchg1 %0=%1,%2" : "=r" (result) : "m" (*(char *) ptr), "r" (x) : "memory"); return result; case 2: - __asm__ __volatile ("xchg2 %0=%1,%2" : "=r" (result) + __asm__ __volatile (IA64_SEMFIX"xchg2 %0=%1,%2" : "=r" (result) : "m" (*(short *) ptr), "r" (x) : "memory"); return result; case 4: - __asm__ __volatile ("xchg4 %0=%1,%2" : "=r" (result) + __asm__ __volatile (IA64_SEMFIX"xchg4 %0=%1,%2" : "=r" (result) : "m" (*(int *) ptr), "r" (x) : "memory"); return result; case 8: - __asm__ __volatile ("xchg8 %0=%1,%2" : "=r" (result) + __asm__ __volatile (IA64_SEMFIX"xchg8 %0=%1,%2" : "=r" (result) : "m" (*(long *) ptr), "r" (x) : "memory"); return result; } @@ -305,7 +314,6 @@ #define xchg(ptr,x) \ ((__typeof__(*(ptr))) __xchg ((unsigned long) (x), (ptr), sizeof(*(ptr)))) -#define tas(ptr) (xchg ((ptr), 1)) /* * Atomic compare and exchange. Compare OLD with MEM, if identical, @@ -324,50 +332,50 @@ struct __xchg_dummy { unsigned long a[100]; }; #define __xg(x) (*(struct __xchg_dummy *)(x)) -#define ia64_cmpxchg(sem,ptr,old,new,size) \ -({ \ - __typeof__(ptr) _p_ = (ptr); \ - __typeof__(new) _n_ = (new); \ - __u64 _o_, _r_; \ - \ - switch (size) { \ - case 1: _o_ = (__u8 ) (old); break; \ - case 2: _o_ = (__u16) (old); break; \ - case 4: _o_ = (__u32) (old); break; \ - case 8: _o_ = (__u64) (old); break; \ - default: \ - } \ - __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ - switch (size) { \ - case 1: \ - __asm__ __volatile__ ("cmpxchg1."sem" %0=%2,%3,ar.ccv" \ - : "=r"(_r_), "=m"(__xg(_p_)) \ - : "m"(__xg(_p_)), "r"(_n_)); \ - break; \ - \ - case 2: \ - __asm__ __volatile__ ("cmpxchg2."sem" %0=%2,%3,ar.ccv" \ - : "=r"(_r_), "=m"(__xg(_p_)) \ - : "m"(__xg(_p_)), "r"(_n_)); \ - break; \ - \ - case 4: \ - __asm__ __volatile__ ("cmpxchg4."sem" %0=%2,%3,ar.ccv" \ - : "=r"(_r_), "=m"(__xg(_p_)) \ - : "m"(__xg(_p_)), "r"(_n_)); \ - break; \ - \ - case 8: \ - __asm__ __volatile__ ("cmpxchg8."sem" %0=%2,%3,ar.ccv" \ - : "=r"(_r_), "=m"(__xg(_p_)) \ - : "m"(__xg(_p_)), "r"(_n_)); \ - break; \ - \ - default: \ - _r_ = __cmpxchg_called_with_bad_pointer(); \ - break; \ - } \ - (__typeof__(old)) _r_; \ +#define ia64_cmpxchg(sem,ptr,old,new,size) \ +({ \ + __typeof__(ptr) _p_ = (ptr); \ + __typeof__(new) _n_ = (new); \ + __u64 _o_, _r_; \ + \ + switch (size) { \ + case 1: _o_ = (__u8 ) (long) (old); break; \ + case 2: _o_ = (__u16) (long) (old); break; \ + case 4: _o_ = (__u32) (long) (old); break; \ + case 8: _o_ = (__u64) (long) (old); break; \ + default: \ + } \ + __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ + switch (size) { \ + case 1: \ + __asm__ __volatile__ (IA64_SEMFIX"cmpxchg1."sem" %0=%2,%3,ar.ccv" \ + : "=r"(_r_), "=m"(__xg(_p_)) \ + : "m"(__xg(_p_)), "r"(_n_)); \ + break; \ + \ + case 2: \ + __asm__ __volatile__ (IA64_SEMFIX"cmpxchg2."sem" %0=%2,%3,ar.ccv" \ + : "=r"(_r_), "=m"(__xg(_p_)) \ + : "m"(__xg(_p_)), "r"(_n_)); \ + break; \ + \ + case 4: \ + __asm__ __volatile__ (IA64_SEMFIX"cmpxchg4."sem" %0=%2,%3,ar.ccv" \ + : "=r"(_r_), "=m"(__xg(_p_)) \ + : "m"(__xg(_p_)), "r"(_n_)); \ + break; \ + \ + case 8: \ + __asm__ __volatile__ (IA64_SEMFIX"cmpxchg8."sem" %0=%2,%3,ar.ccv" \ + : "=r"(_r_), "=m"(__xg(_p_)) \ + : "m"(__xg(_p_)), "r"(_n_)); \ + break; \ + \ + default: \ + _r_ = __cmpxchg_called_with_bad_pointer(); \ + break; \ + } \ + (__typeof__(old)) _r_; \ }) #define cmpxchg_acq(ptr,o,n) ia64_cmpxchg("acq", (ptr), (o), (n), sizeof(*(ptr))) @@ -418,15 +426,15 @@ extern void ia64_save_extra (struct task_struct *task); extern void ia64_load_extra (struct task_struct *task); -#define __switch_to(prev,next,last) do { \ - if (((prev)->thread.flags & IA64_THREAD_DBG_VALID) \ - || IS_IA32_PROCESS(ia64_task_regs(prev))) \ - ia64_save_extra(prev); \ - if (((next)->thread.flags & IA64_THREAD_DBG_VALID) \ - || IS_IA32_PROCESS(ia64_task_regs(next))) \ - ia64_load_extra(next); \ - ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \ - (last) = ia64_switch_to((next)); \ +#define __switch_to(prev,next,last) do { \ + if (((prev)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \ + || IS_IA32_PROCESS(ia64_task_regs(prev))) \ + ia64_save_extra(prev); \ + if (((next)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \ + || IS_IA32_PROCESS(ia64_task_regs(next))) \ + ia64_load_extra(next); \ + ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \ + (last) = ia64_switch_to((next)); \ } while (0) #ifdef CONFIG_SMP @@ -444,6 +452,7 @@ */ # define switch_to(prev,next,last) do { \ if (ia64_get_fpu_owner() == (prev) && ia64_psr(ia64_task_regs(prev))->mfh) { \ + ia64_psr(ia64_task_regs(prev))->mfh = 0; \ (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ __ia64_save_fpu((prev)->thread.fph); \ } \ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ia64/unistd.h linux/include/asm-ia64/unistd.h --- v2.4.0-test6/linux/include/asm-ia64/unistd.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-ia64/unistd.h Fri Aug 11 14:29:03 2000 @@ -203,6 +203,7 @@ #define __NR_lstat 1211 #define __NR_fstat 1212 #define __NR_clone2 1213 +#define __NR_getdents64 1214 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h --- v2.4.0-test6/linux/include/asm-m68k/mmu_context.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-m68k/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -12,10 +12,11 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { } -extern inline void +extern inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context = virt_to_phys(mm->pgd); + return 0; } #define destroy_context(mm) do { } while(0) @@ -108,9 +109,10 @@ extern unsigned char ctx_live[SUN3_CONTEXTS_NUM]; /* set the context for a new task to unmapped */ -static inline void init_new_context(struct task_struct *tsk, struct mm_struct *mm) +static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context = SUN3_INVALID_CONTEXT; + return 0; } /* find the context given to this process, and if it hasn't already diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h --- v2.4.0-test6/linux/include/asm-m68k/unistd.h Tue Jan 11 22:31:44 2000 +++ linux/include/asm-m68k/unistd.h Fri Aug 11 14:29:03 2000 @@ -220,6 +220,7 @@ #define __NR_setgid32 214 #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 +#define __NR_getdents64 220 /* user-visible error numbers are in the range -1 - -122: see */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-mips/mmu_context.h linux/include/asm-mips/mmu_context.h --- v2.4.0-test6/linux/include/asm-mips/mmu_context.h Tue May 23 15:31:36 2000 +++ linux/include/asm-mips/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -57,10 +57,11 @@ * Initialize the context related info for a new mm_struct * instance. */ -extern inline void +extern inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context = 0; + return 0; } extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h --- v2.4.0-test6/linux/include/asm-mips/unistd.h Tue May 23 15:31:36 2000 +++ linux/include/asm-mips/unistd.h Fri Aug 11 14:29:03 2000 @@ -1205,11 +1205,12 @@ #define __NR_pivot_root (__NR_Linux + 216) #define __NR_mincore (__NR_Linux + 217) #define __NR_madvise (__NR_Linux + 218) +#define __NR_getdents64 (__NR_Linux + 219) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 218 +#define __NR_Linux_syscalls 219 #ifndef _LANGUAGE_ASSEMBLY diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-mips64/mmu_context.h linux/include/asm-mips64/mmu_context.h --- v2.4.0-test6/linux/include/asm-mips64/mmu_context.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-mips64/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -70,7 +70,7 @@ * Initialize the context related info for a new mm_struct * instance. */ -extern inline void +extern inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { #ifndef CONFIG_SMP @@ -82,12 +82,11 @@ * Init the "context" values so that a tlbpid allocation * happens on the first switch. */ - if (mm->context) - memset((void *)mm->context, 0, smp_num_cpus * - sizeof(unsigned long)); - else - printk("Warning: init_new_context failed\n"); + if (mm->context == 0) + return -ENOMEM; + memset((void *)mm->context, 0, smp_num_cpus * sizeof(unsigned long)); #endif + return 0; } extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-mips64/unistd.h linux/include/asm-mips64/unistd.h --- v2.4.0-test6/linux/include/asm-mips64/unistd.h Tue May 23 15:31:36 2000 +++ linux/include/asm-mips64/unistd.h Fri Aug 11 14:29:03 2000 @@ -1204,11 +1204,12 @@ #define __NR_Linux32_root_pivot (__NR_Linux32 + 216) #define __NR_Linux32_mincore (__NR_Linux32 + 217) #define __NR_Linux32_madvise (__NR_Linux32 + 218) +#define __NR_Linux32_getdents64 (__NR_Linux32 + 219) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux32_syscalls 218 +#define __NR_Linux32_syscalls 219 /* * Linux 64-bit syscalls are in the range from 5000 to 5999. @@ -1427,11 +1428,12 @@ #define __NR_root_pivot (__NR_Linux + 210) #define __NR_mincore (__NR_Linux + 211) #define __NR_madvise (__NR_Linux + 212) +#define __NR_getdents64 (__NR_Linux + 213) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 212 +#define __NR_Linux_syscalls 213 #ifndef _LANGUAGE_ASSEMBLY diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ppc/mmu_context.h linux/include/asm-ppc/mmu_context.h --- v2.4.0-test6/linux/include/asm-ppc/mmu_context.h Fri Jun 23 21:55:11 2000 +++ linux/include/asm-ppc/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -77,7 +77,7 @@ /* * Set up the context for a new address space. */ -#define init_new_context(tsk,mm) ((mm)->context = NO_CONTEXT) +#define init_new_context(tsk,mm) (((mm)->context = NO_CONTEXT), 0) /* * We're finished using the context for an address space. diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h --- v2.4.0-test6/linux/include/asm-ppc/unistd.h Fri Jul 14 12:12:15 2000 +++ linux/include/asm-ppc/unistd.h Fri Aug 11 14:29:03 2000 @@ -205,6 +205,7 @@ #define __NR_sys_pciconfig_write 199 #define __NR_sys_pciconfig_iobase 200 #define __NR_multiplexer 201 +#define __NR_getdents64 202 #define __NR(n) #n diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-s390/mmu_context.h linux/include/asm-s390/mmu_context.h --- v2.4.0-test6/linux/include/asm-s390/mmu_context.h Fri May 12 14:18:56 2000 +++ linux/include/asm-s390/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -12,7 +12,7 @@ /* * get a new mmu context.. S390 don't know about contexts. */ -#define init_new_context(tsk,mm) do { } while (0) +#define init_new_context(tsk,mm) 0 #define destroy_context(mm) flush_tlb_mm(mm) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-s390/unistd.h linux/include/asm-s390/unistd.h --- v2.4.0-test6/linux/include/asm-s390/unistd.h Fri May 12 14:18:56 2000 +++ linux/include/asm-s390/unistd.h Fri Aug 11 14:29:03 2000 @@ -208,6 +208,7 @@ #define __NR_pivot_root 217 #define __NR_mincore 218 #define __NR_madvise 219 +#define __NR_getdents64 220 /* user-visible error numbers are in the range -1 - -122: see */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sh/dma.h linux/include/asm-sh/dma.h --- v2.4.0-test6/linux/include/asm-sh/dma.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sh/dma.h Thu Aug 10 13:03:25 2000 @@ -1,6 +1,7 @@ #ifndef __ASM_SH_DMA_H #define __ASM_SH_DMA_H +#include #include /* need byte IO */ #define MAX_DMA_CHANNELS 8 diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sh/machvec_init.h linux/include/asm-sh/machvec_init.h --- v2.4.0-test6/linux/include/asm-sh/machvec_init.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sh/machvec_init.h Thu Aug 10 13:03:25 2000 @@ -12,6 +12,8 @@ #ifndef __SH_MACHVEC_INIT_H #define __SH_MACHVEC_INIT_H +#include + /* * In a GENERIC kernel, we have lots of these vectors floating about, * all but one of which we want to go away. In a non-GENERIC kernel, diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sh/mmu_context.h linux/include/asm-sh/mmu_context.h --- v2.4.0-test6/linux/include/asm-sh/mmu_context.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sh/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -67,10 +67,11 @@ * Initialize the context related info for a new mm_struct * instance. */ -extern __inline__ void init_new_context(struct task_struct *tsk, +extern __inline__ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { mm->context = NO_CONTEXT; + return 0; } /* diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sh/unistd.h linux/include/asm-sh/unistd.h --- v2.4.0-test6/linux/include/asm-sh/unistd.h Tue May 23 15:31:36 2000 +++ linux/include/asm-sh/unistd.h Fri Aug 11 14:29:03 2000 @@ -229,6 +229,7 @@ #define __NR_pivot_root 217 #define __NR_mincore 218 #define __NR_madvise 219 +#define __NR_getdents64 220 /* user-visible error numbers are in the range -1 - -125: see */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v2.4.0-test6/linux/include/asm-sparc/bitops.h Thu Jul 27 17:38:02 2000 +++ linux/include/asm-sparc/bitops.h Sat Aug 12 12:08:50 2000 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.59 2000/07/13 01:51:50 davem Exp $ +/* $Id: bitops.h,v 1.60 2000/08/10 23:49:16 davem Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -232,6 +232,8 @@ found_first: tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } @@ -379,7 +381,11 @@ tmp = *p; found_first: - return result + ffz(__swab32(tmp) | (~0UL << size)); + tmp = __swab32(tmp) | (~0UL << size); + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ + return result + ffz(tmp); + found_middle: return result + ffz(__swab32(tmp)); } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v2.4.0-test6/linux/include/asm-sparc/fcntl.h Mon Jul 10 16:47:27 2000 +++ linux/include/asm-sparc/fcntl.h Sun Aug 13 12:01:54 2000 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.13 2000/07/06 01:41:45 davem Exp $ */ +/* $Id: fcntl.h,v 1.14 2000/08/12 20:49:49 jj Exp $ */ #ifndef _SPARC_FCNTL_H #define _SPARC_FCNTL_H @@ -34,6 +34,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -58,6 +62,15 @@ short l_whence; off_t l_start; off_t l_len; + pid_t l_pid; + short __unused; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; pid_t l_pid; short __unused; }; diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/md.h linux/include/asm-sparc/md.h --- v2.4.0-test6/linux/include/asm-sparc/md.h Mon Jan 12 15:15:54 1998 +++ linux/include/asm-sparc/md.h Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* $Id: md.h,v 1.1 1997/12/15 15:12:39 jj Exp $ - * md.h: High speed xor_block operation for RAID4/5 - * - */ - -#ifndef __ASM_MD_H -#define __ASM_MD_H - -/* #define HAVE_ARCH_XORBLOCK */ - -#define MD_XORBLOCK_ALIGNMENT sizeof(long) - -#endif /* __ASM_MD_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/mmu_context.h linux/include/asm-sparc/mmu_context.h --- v2.4.0-test6/linux/include/asm-sparc/mmu_context.h Thu Feb 10 17:11:21 2000 +++ linux/include/asm-sparc/mmu_context.h Thu Aug 10 13:30:05 2000 @@ -13,7 +13,7 @@ * Initialize a new mmu context. This is invoked when a new * address space instance (unique or shared) is instantiated. */ -#define init_new_context(tsk, mm) ((mm)->context = NO_CONTEXT) +#define init_new_context(tsk, mm) (((mm)->context = NO_CONTEXT), 0) /* * Destroy a dead context. This occurs when mmput drops the diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h --- v2.4.0-test6/linux/include/asm-sparc/page.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc/page.h Thu Aug 10 12:43:12 2000 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.53 2000/06/04 08:36:33 anton Exp $ +/* $Id: page.h,v 1.54 2000/08/10 01:04:53 davem Exp $ * page.h: Various defines and such for MMU operations on the Sparc for * the Linux kernel. * diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v2.4.0-test6/linux/include/asm-sparc/pgtable.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc/pgtable.h Mon Aug 14 13:09:07 2000 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.101 2000/08/09 00:00:17 davem Exp $ */ +/* $Id: pgtable.h,v 1.102 2000/08/14 00:46:13 anton Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -201,11 +201,9 @@ #define SIZEOF_PTR_LOG2 2 -BTFIXUPDEF_CALL_CONST(unsigned long, sparc_pte_pagenr, pte_t) BTFIXUPDEF_CALL_CONST(unsigned long, pmd_page, pmd_t) BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page, pgd_t) -#define sparc_pte_pagenr(pte) BTFIXUP_CALL(sparc_pte_pagenr)(pte) #define pmd_page(pmd) BTFIXUP_CALL(pmd_page)(pmd) #define pgd_page(pgd) BTFIXUP_CALL(pgd_page)(pgd) @@ -305,7 +303,9 @@ /* Permanent address of a page. */ #define page_address(page) ((page)->virtual) -#define pte_page(x) (mem_map+sparc_pte_pagenr(x)) + +BTFIXUPDEF_CALL(struct page *, pte_page, pte_t) +#define pte_page(pte) BTFIXUP_CALL(pte_page)(pte) /* * Conversion functions: convert a page and protection to a page entry, diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h --- v2.4.0-test6/linux/include/asm-sparc/spinlock.h Thu Mar 2 14:36:23 2000 +++ linux/include/asm-sparc/spinlock.h Mon Aug 14 13:09:07 2000 @@ -16,7 +16,7 @@ * Define this to use the verbose/debugging versions in * arch/sparc/lib/debuglocks.c * - * Be sure to make check_asm whenever changing this option. + * Be sure to make dep whenever changing this option. */ #define SPIN_LOCK_DEBUG @@ -28,7 +28,7 @@ typedef struct _spinlock_debug spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0 } -#define spin_lock_init(lp) do { (lp)->owner_pc = 0; (lp)->lock = 0; } while(0) +#define spin_lock_init(lp) do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0) #define spin_is_locked(lp) (*((volatile unsigned char *)(&((lp)->lock))) != 0) #define spin_unlock_wait(lp) do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock)) @@ -49,6 +49,8 @@ #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, {0} } +#define rwlock_init(lp) do { *(lp)= RW_LOCK_UNLOCKED; } while(0) + extern void _do_read_lock(rwlock_t *rw, char *str); extern void _do_read_unlock(rwlock_t *rw, char *str); extern void _do_write_lock(rwlock_t *rw, char *str); @@ -143,6 +145,9 @@ typedef struct { volatile unsigned int lock; } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } + +#define rwlock_init(lp) do { *(lp)= RW_LOCK_UNLOCKED; } while(0) + /* Sort of like atomic_t's on Sparc, but even more clever. * diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.4.0-test6/linux/include/asm-sparc/unistd.h Tue Feb 1 01:35:44 2000 +++ linux/include/asm-sparc/unistd.h Mon Aug 14 13:09:07 2000 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.66 2000/01/29 17:57:25 jj Exp $ */ +/* $Id: unistd.h,v 1.70 2000/08/14 05:39:07 jj Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -67,7 +67,7 @@ #define __NR_geteuid 49 /* SunOS calls getuid() */ #define __NR_getegid 50 /* SunOS calls getgid() */ #define __NR_acct 51 /* Common */ -/* #define __NR_ni_syscall 52 ENOSYS under SunOS */ +/* #define __NR_memory_ordering 52 Linux sparc64 specific */ #define __NR_getgid32 53 /* Linux sparc32 specific */ #define __NR_ioctl 54 /* Common */ #define __NR_reboot 55 /* Common */ @@ -169,8 +169,8 @@ /* #define __NR_getmsg 151 SunOS Specific */ /* #define __NR_putmsg 152 SunOS Specific */ #define __NR_poll 153 /* Common */ -/* #define __NR_ni_syscall 154 ENOSYS under SunOS */ -/* #define __NR_nfssvc 155 SunOS Specific */ +#define __NR_getdents64 154 /* Linux specific */ +#define __NR_fcntl64 155 /* Linux sparc32 Specific */ /* #define __NR_getdirentries 156 SunOS Specific */ #define __NR_statfs 157 /* Common */ #define __NR_fstatfs 158 /* Common */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h --- v2.4.0-test6/linux/include/asm-sparc64/bitops.h Mon Jul 10 16:47:27 2000 +++ linux/include/asm-sparc64/bitops.h Sat Aug 12 12:08:50 2000 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.29 2000/06/30 10:18:39 davem Exp $ +/* $Id: bitops.h,v 1.30 2000/08/10 23:49:16 davem Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -158,6 +158,8 @@ found_first: tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } @@ -217,6 +219,8 @@ tmp = __swab64p(p); found_first: tmp |= (~0UL << size); + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h --- v2.4.0-test6/linux/include/asm-sparc64/fcntl.h Mon Jul 10 16:47:27 2000 +++ linux/include/asm-sparc64/fcntl.h Sun Aug 13 12:01:54 2000 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.8 2000/07/06 01:41:45 davem Exp $ */ +/* $Id: fcntl.h,v 1.10 2000/08/12 20:49:49 jj Exp $ */ #ifndef _SPARC64_FCNTL_H #define _SPARC64_FCNTL_H @@ -34,6 +34,12 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#ifdef __KERNEL__ +#define F_GETLK64 12 +#define F_SETLK64 13 +#define F_SETLKW64 14 +#endif + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -71,6 +77,10 @@ __kernel_pid_t32 l_pid; short __unused; }; +#endif + +#ifdef __KERNEL__ +#define flock64 flock #endif #endif /* !(_SPARC64_FCNTL_H) */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h --- v2.4.0-test6/linux/include/asm-sparc64/hardirq.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc64/hardirq.h Wed Aug 23 09:30:13 2000 @@ -39,7 +39,7 @@ /* * Are we in an interrupt context? Either doing bottom half - * or hardware interrupt processing? On any cpu? + * or hardware interrupt processing? */ #define in_interrupt() ((local_irq_count(smp_processor_id()) + \ local_bh_count(smp_processor_id())) != 0) @@ -52,22 +52,18 @@ #define hardirq_trylock(cpu) ((void)(cpu), local_irq_count(smp_processor_id()) == 0) #define hardirq_endlock(cpu) do { (void)(cpu); } while(0) -#define hardirq_enter(cpu) ((void)(cpu), local_irq_count(smp_processor_id())++) -#define hardirq_exit(cpu) ((void)(cpu), local_irq_count(smp_processor_id())--) - #define synchronize_irq() barrier() #else /* (CONFIG_SMP) */ static __inline__ int irqs_running(void) { - enum brlock_indices idx = BR_GLOBALIRQ_LOCK; - int i, count = 0; + int i; for (i = 0; i < smp_num_cpus; i++) - count += (__brlock_array[cpu_logical_map(i)][idx] != 0); - - return count; + if (local_irq_count(cpu_logical_map(i))) + return 1; + return 0; } extern unsigned char global_irq_holder; @@ -85,7 +81,7 @@ { spinlock_t *lock = &__br_write_locks[BR_GLOBALIRQ_LOCK].lock; - return (!irqs_running() && !spin_is_locked(lock)); + return (!local_irq_count(cpu) && !spin_is_locked(lock)); } #define hardirq_endlock(cpu) do { (void)(cpu); } while (0) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/kdebug.h linux/include/asm-sparc64/kdebug.h --- v2.4.0-test6/linux/include/asm-sparc64/kdebug.h Mon Jan 12 15:15:58 1998 +++ linux/include/asm-sparc64/kdebug.h Sat Aug 12 12:08:50 2000 @@ -1,77 +1,9 @@ -/* $Id: kdebug.h,v 1.3 1997/12/14 23:24:47 ecd Exp $ - * kdebug.h: Defines and definitions for debugging the Linux kernel - * under various kernel debuggers. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ #ifndef _SPARC64_KDEBUG_H #define _SPARC64_KDEBUG_H -#include - -/* XXX This needs to all be fixed for Ultra/V9 -DaveM */ - -/* The debugger lives in 1MB of virtual address space right underneath - * the boot prom. - */ - -#define DEBUG_FIRSTVADDR 0xffc00000 -#define DEBUG_LASTVADDR LINUX_OPPROM_BEGVM - -/* Breakpoints are enter through trap table entry 126. So in sparc assembly - * if you want to drop into the debugger you do: - * - * t DEBUG_BP_TRAP - */ - -#define DEBUG_BP_TRAP 126 - -#ifndef __ASSEMBLY__ -/* The debug vector is passed in %o1 at boot time. It is a pointer to - * a structure in the debuggers address space. Here is its format. +/* + * No kernel debugger on sparc64. Kept here because drivers/sbus/char/ + * includes it for sparc32 sake. */ -typedef unsigned int (*debugger_funct)(void); - -struct kernel_debug { - /* First the entry point into the debugger. You jump here - * to give control over to the debugger. - */ - unsigned long kdebug_entry; - unsigned long kdebug_trapme; /* Figure out later... */ - /* The following is the number of pages that the debugger has - * taken from to total pool. - */ - unsigned long *kdebug_stolen_pages; - /* Ok, after you remap yourself and/or change the trap table - * from what you were left with at boot time you have to call - * this synchronization function so the debugger can check out - * what you have done. - */ - debugger_funct teach_debugger; -}; /* I think that is it... */ - -extern struct kernel_debug *linux_dbvec; - -/* Use this macro in C-code to enter the debugger. */ -extern __inline__ void sp_enter_debugger(void) -{ - __asm__ __volatile__("jmpl %0, %%o7\n\t" - "nop\n\t" : : - "r" (linux_dbvec) : "o7", "memory"); -} - -#define SP_ENTER_DEBUGGER do { \ - if((linux_dbvec!=0) && ((*(short *)linux_dbvec)!=-1)) \ - sp_enter_debugger(); \ - } while(0) - -#endif /* !(__ASSEMBLY__) */ - -/* Some nice offset defines for assembler code. */ -#define KDEBUG_ENTRY_OFF 0x0 -#define KDEBUG_DUNNO_OFF 0x4 -#define KDEBUG_DUNNO2_OFF 0x8 -#define KDEBUG_TEACH_OFF 0xc - -#endif /* !(_SPARC64_KDEBUG_H) */ +#endif diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/machines.h linux/include/asm-sparc64/machines.h --- v2.4.0-test6/linux/include/asm-sparc64/machines.h Mon Apr 14 16:28:22 1997 +++ linux/include/asm-sparc64/machines.h Wed Dec 31 16:00:00 1969 @@ -1,71 +0,0 @@ -/* $Id: machines.h,v 1.2 1997/04/04 00:50:23 davem Exp $ - * machines.h: Defines for taking apart the machine type value in the - * idprom and determining the kind of machine we are on. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ -#ifndef _SPARC64_MACHINES_H -#define _SPARC64_MACHINES_H - -/* XXX This should disappear. -DaveM */ - -struct Sun_Machine_Models { - char *name; - unsigned char id_machtype; -}; - -/* Current number of machines we know about that has an IDPROM - * machtype entry including one entry for the 0x80 OBP machines. - */ -#define NUM_SUN_MACHINES 15 - -extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES]; - -/* The machine type in the idprom area looks like this: - * - * --------------- - * | ARCH | MACH | - * --------------- - * 7 4 3 0 - * - * The ARCH field determines the architecture line (sun4, sun4c, etc). - * The MACH field determines the machine make within that architecture. - */ - -#define SM_ARCH_MASK 0xf0 -#define SM_SUN4 0x20 -#define SM_SUN4C 0x50 -#define SM_SUN4M 0x70 -#define SM_SUN4M_OBP 0x80 - -#define SM_TYP_MASK 0x0f -/* Sun4 machines */ -#define SM_4_260 0x01 /* Sun 4/200 series */ -#define SM_4_110 0x02 /* Sun 4/100 series */ -#define SM_4_330 0x03 /* Sun 4/300 series */ -#define SM_4_470 0x04 /* Sun 4/400 series */ - -/* Sun4c machines Full Name - PROM NAME */ -#define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */ -#define SM_4C_IPC 0x02 /* Sun4c SparcStation IPC - Sun 4/40 */ -#define SM_4C_SS1PLUS 0x03 /* Sun4c SparcStation 1+ - Sun 4/65 */ -#define SM_4C_SLC 0x04 /* Sun4c SparcStation SLC - Sun 4/20 */ -#define SM_4C_SS2 0x05 /* Sun4c SparcStation 2 - Sun 4/75 */ -#define SM_4C_ELC 0x06 /* Sun4c SparcStation ELC - Sun 4/25 */ -#define SM_4C_IPX 0x07 /* Sun4c SparcStation IPX - Sun 4/50 */ - -/* Sun4m machines, these predate the OpenBoot. These values only mean - * something if the value in the ARCH field is SM_SUN4M, if it is - * SM_SUN4M_OBP then you have the following situation: - * 1) You either have a sun4d, a sun4e, or a recently made sun4m. - * 2) You have to consult OpenBoot to determine which machine this is. - */ -#define SM_4M_SS60 0x01 /* Sun4m SparcSystem 600 */ -#define SM_4M_SS50 0x02 /* Sun4m SparcStation 10 */ -#define SM_4M_SS40 0x03 /* Sun4m SparcStation 5 */ - -/* Sun4d machines -- N/A */ -/* Sun4e machines -- N/A */ -/* Sun4u machines -- N/A */ - -#endif /* !(_SPARC64_MACHINES_H) */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/md.h linux/include/asm-sparc64/md.h --- v2.4.0-test6/linux/include/asm-sparc64/md.h Thu May 27 09:55:22 1999 +++ linux/include/asm-sparc64/md.h Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ -/* $Id: md.h,v 1.3 1999/05/25 16:53:28 jj Exp $ - * md.h: High speed xor_block operation for RAID4/5 - * utilizing the UltraSparc Visual Instruction Set. - * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#ifndef __ASM_MD_H -#define __ASM_MD_H - -#include -#include - -#undef HAVE_ARCH_XORBLOCK - -#define MD_XORBLOCK_ALIGNMENT 64 - -/* void __xor_block (char *dest, char *src, long len) - * { - * while (len--) *dest++ ^= *src++; - * } - * - * Requirements: - * !(((long)dest | (long)src) & (MD_XORBLOCK_ALIGNMENT - 1)) && - * !(len & 127) && len >= 256 - */ - -static inline void __xor_block (char *dest, char *src, long len) -{ - __asm__ __volatile__ (" - wr %%g0, %3, %%fprs - wr %%g0, %4, %%asi - membar #LoadStore|#StoreLoad|#StoreStore - sub %2, 128, %2 - ldda [%0] %4, %%f0 - ldda [%1] %4, %%f16 -1: ldda [%0 + 64] %%asi, %%f32 - fxor %%f0, %%f16, %%f16 - fxor %%f2, %%f18, %%f18 - fxor %%f4, %%f20, %%f20 - fxor %%f6, %%f22, %%f22 - fxor %%f8, %%f24, %%f24 - fxor %%f10, %%f26, %%f26 - fxor %%f12, %%f28, %%f28 - fxor %%f14, %%f30, %%f30 - stda %%f16, [%0] %4 - ldda [%1 + 64] %%asi, %%f48 - ldda [%0 + 128] %%asi, %%f0 - fxor %%f32, %%f48, %%f48 - fxor %%f34, %%f50, %%f50 - add %0, 128, %0 - fxor %%f36, %%f52, %%f52 - add %1, 128, %1 - fxor %%f38, %%f54, %%f54 - subcc %2, 128, %2 - fxor %%f40, %%f56, %%f56 - fxor %%f42, %%f58, %%f58 - fxor %%f44, %%f60, %%f60 - fxor %%f46, %%f62, %%f62 - stda %%f48, [%0 - 64] %%asi - bne,pt %%xcc, 1b - ldda [%1] %4, %%f16 - ldda [%0 + 64] %%asi, %%f32 - fxor %%f0, %%f16, %%f16 - fxor %%f2, %%f18, %%f18 - fxor %%f4, %%f20, %%f20 - fxor %%f6, %%f22, %%f22 - fxor %%f8, %%f24, %%f24 - fxor %%f10, %%f26, %%f26 - fxor %%f12, %%f28, %%f28 - fxor %%f14, %%f30, %%f30 - stda %%f16, [%0] %4 - ldda [%1 + 64] %%asi, %%f48 - membar #Sync - fxor %%f32, %%f48, %%f48 - fxor %%f34, %%f50, %%f50 - fxor %%f36, %%f52, %%f52 - fxor %%f38, %%f54, %%f54 - fxor %%f40, %%f56, %%f56 - fxor %%f42, %%f58, %%f58 - fxor %%f44, %%f60, %%f60 - fxor %%f46, %%f62, %%f62 - stda %%f48, [%0 + 64] %%asi - membar #Sync|#StoreStore|#StoreLoad - wr %%g0, 0, %%fprs - " : : - "r" (dest), "r" (src), "r" (len), "i" (FPRS_FEF), "i" (ASI_BLK_P) : - "cc", "memory"); -} - -#endif /* __ASM_MD_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h --- v2.4.0-test6/linux/include/asm-sparc64/mmu_context.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc64/mmu_context.h Sat Aug 12 12:08:50 2000 @@ -1,4 +1,4 @@ -/* $Id: mmu_context.h,v 1.43 2000/08/09 08:04:45 davem Exp $ */ +/* $Id: mmu_context.h,v 1.45 2000/08/12 13:25:52 davem Exp $ */ #ifndef __SPARC64_MMU_CONTEXT_H #define __SPARC64_MMU_CONTEXT_H @@ -31,7 +31,7 @@ * address space instance (unique or shared) is instantiated. * This just needs to set mm->context to an invalid context. */ -#define init_new_context(__tsk, __mm) ((__mm)->context = 0UL) +#define init_new_context(__tsk, __mm) (((__mm)->context = 0UL), 0) /* Destroy a dead context. This occurs when mmput drops the * mm_users count to zero, the mmaps have been released, and @@ -100,29 +100,35 @@ /* Switch the current MM context. */ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) { - long dirty; + unsigned long ctx_valid; spin_lock(&mm->page_table_lock); if (CTX_VALID(mm->context)) - dirty = 0; - else - dirty = 1; - if (dirty || (old_mm != mm)) { - unsigned long vm_mask; + ctx_valid = 1; + else + ctx_valid = 0; - if (dirty) + if (!ctx_valid || (old_mm != mm)) { + if (!ctx_valid) get_new_mmu_context(mm); - vm_mask = (1UL << cpu); - if (!(mm->cpu_vm_mask & vm_mask)) { - mm->cpu_vm_mask |= vm_mask; - dirty = 1; - } - load_secondary_context(mm); - if (dirty != 0) - clean_secondary_context(); reload_tlbmiss_state(tsk, mm); + } + + { + unsigned long vm_mask = (1UL << cpu); + + /* Even if (mm == old_mm) we _must_ check + * the cpu_vm_mask. If we do not we could + * corrupt the TLB state because of how + * smp_flush_tlb_{page,range,mm} on sparc64 + * and lazy tlb switches work. -DaveM + */ + if (!ctx_valid || !(mm->cpu_vm_mask & vm_mask)) { + mm->cpu_vm_mask |= vm_mask; + clean_secondary_context(); + } } spin_unlock(&mm->page_table_lock); } diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/openprom.h linux/include/asm-sparc64/openprom.h --- v2.4.0-test6/linux/include/asm-sparc64/openprom.h Tue Apr 14 17:44:25 1998 +++ linux/include/asm-sparc64/openprom.h Sun Aug 13 12:01:54 2000 @@ -1,4 +1,4 @@ -/* $Id: openprom.h,v 1.7 1998/03/15 10:14:47 ecd Exp $ */ +/* $Id: openprom.h,v 1.8 2000/08/12 19:55:25 anton Exp $ */ #ifndef __SPARC64_OPENPROM_H #define __SPARC64_OPENPROM_H @@ -7,12 +7,6 @@ * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ - -/* Empirical constants... */ -#define KADB_DEBUGGER_BEGVM 0xffc00000 /* Where kern debugger is in virt-mem */ -#define LINUX_OPPROM_BEGVM 0xffd00000 -#define LINUX_OPPROM_ENDVM 0xfff00000 -#define LINUX_OPPROM_MAGIC 0x10010407 #ifndef __ASSEMBLY__ /* V0 prom device operations. */ diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h --- v2.4.0-test6/linux/include/asm-sparc64/page.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc64/page.h Thu Aug 10 12:43:12 2000 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.35 2000/04/13 04:45:59 davem Exp $ */ +/* $Id: page.h,v 1.36 2000/08/10 01:04:53 davem Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.4.0-test6/linux/include/asm-sparc64/pgtable.h Wed Aug 9 19:19:51 2000 +++ linux/include/asm-sparc64/pgtable.h Sat Aug 12 12:08:50 2000 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.130 2000/08/09 00:00:17 davem Exp $ +/* $Id: pgtable.h,v 1.131 2000/08/11 03:00:14 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -174,7 +174,6 @@ (pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL)) #define pgd_set(pgdp, pmdp) \ (pgd_val(*(pgdp)) = (__pa((unsigned long) (pmdp)) >> 11UL)) -#define sparc64_pte_pagenr(pte) (((unsigned long) ((pte_val(pte)&~PAGE_OFFSET)-phys_base)>>PAGE_SHIFT)) #define pmd_page(pmd) ((unsigned long) __va((pmd_val(pmd)<<11UL))) #define pgd_page(pgd) ((unsigned long) __va((pgd_val(pgd)<<11UL))) #define pte_none(pte) (!pte_val(pte)) @@ -206,7 +205,7 @@ #define __page_address(page) ((page)->virtual) #define page_address(page) ({ __page_address(page); }) -#define pte_page(x) (mem_map+sparc64_pte_pagenr(x)) +#define pte_page(x) (mem_map+(((pte_val(x)&_PAGE_PADDR)-phys_base)>>PAGE_SHIFT)) /* Be very careful when you change these three, they are delicate. */ #define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_ACCESSED | _PAGE_R)) diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h --- v2.4.0-test6/linux/include/asm-sparc64/spinlock.h Sun Mar 19 18:35:31 2000 +++ linux/include/asm-sparc64/spinlock.h Mon Aug 14 13:09:08 2000 @@ -109,6 +109,7 @@ typedef unsigned int rwlock_t; #define RW_LOCK_UNLOCKED 0 +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) extern void __read_lock(rwlock_t *); extern void __read_unlock(rwlock_t *); @@ -128,6 +129,7 @@ unsigned int reader_pc[4]; } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0xff, { 0, 0, 0, 0 } } +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) extern void _do_read_lock(rwlock_t *rw, char *str); extern void _do_read_unlock(rwlock_t *rw, char *str); diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h --- v2.4.0-test6/linux/include/asm-sparc64/unistd.h Tue May 23 15:31:36 2000 +++ linux/include/asm-sparc64/unistd.h Mon Aug 14 13:09:08 2000 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.44 2000/05/16 16:42:33 jj Exp $ */ +/* $Id: unistd.h,v 1.47 2000/08/14 05:39:07 jj Exp $ */ #ifndef _SPARC64_UNISTD_H #define _SPARC64_UNISTD_H @@ -169,8 +169,8 @@ /* #define __NR_getmsg 151 SunOS Specific */ /* #define __NR_putmsg 152 SunOS Specific */ #define __NR_poll 153 /* Common */ -/* #define __NR_ni_syscall 154 ENOSYS under SunOS */ -/* #define __NR_nfssvc 155 SunOS Specific */ +#define __NR_getdents64 154 /* Linux specific */ +/* #define __NR_fcntl64 155 Linux sparc32 Specific */ /* #define __NR_getdirentries 156 SunOS Specific */ #define __NR_statfs 157 /* Common */ #define __NR_fstatfs 158 /* Common */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/agp_backend.h linux/include/linux/agp_backend.h --- v2.4.0-test6/linux/include/linux/agp_backend.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/agp_backend.h Sun Aug 13 19:37:15 2000 @@ -50,8 +50,9 @@ VIA_VP3, VIA_MVP3, VIA_MVP4, - VIA_APOLLO_SUPER, VIA_APOLLO_PRO, + VIA_APOLLO_KX133, + VIA_APOLLO_KT133, SIS_GENERIC, AMD_GENERIC, AMD_IRONGATE, diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/capi.h linux/include/linux/capi.h --- v2.4.0-test6/linux/include/linux/capi.h Mon Mar 27 08:08:31 2000 +++ linux/include/linux/capi.h Mon Aug 21 07:49:03 2000 @@ -1,37 +1,9 @@ /* - * $Id: capi.h,v 1.3 2000/03/08 17:06:34 calle Exp $ + * $Id: capi.h,v 1.4 2000/06/12 09:20:20 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: capi.h,v $ - * Revision 1.3 2000/03/08 17:06:34 calle - * - changes for devfs and 2.3.49 - * - capifs now configurable (no need with devfs) - * - New Middleware ioctl CAPI_NCCI_GETUNIT - * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs) - * - * Revision 1.2 2000/03/03 15:50:42 calle - * - kernel CAPI: - * - Changed parameter "param" in capi_signal from __u32 to void *. - * - rewrote notifier handling in kcapi.c - * - new notifier NCCI_UP and NCCI_DOWN - * - User CAPI: - * - /dev/capi20 is now a cloning device. - * - middleware extentions prepared. - * - capidrv.c - * - locking of list operations and module count updates. - * - * Revision 1.1 1997/03/04 21:27:33 calle - * First version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * * */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/dirent.h linux/include/linux/dirent.h --- v2.4.0-test6/linux/include/linux/dirent.h Tue Jul 9 21:38:08 1996 +++ linux/include/linux/dirent.h Fri Aug 11 14:29:01 2000 @@ -8,4 +8,12 @@ char d_name[256]; /* We must not include limits.h! */ }; +struct dirent64 { + __u64 d_ino; + __s64 d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h --- v2.4.0-test6/linux/include/linux/etherdevice.h Fri Jan 28 15:09:09 2000 +++ linux/include/linux/etherdevice.h Tue Aug 22 08:59:00 2000 @@ -40,15 +40,10 @@ unsigned char *haddr); extern struct net_device * init_etherdev(struct net_device *, int); -#if 1 /*def CONFIG_IP_ROUTER*/ static __inline__ void eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, int len, int base) { - memcpy (dest->data, src, len); + memcpy (dest->data, src, len); } -#else -extern void eth_copy_and_sum(struct sk_buff *dest, - unsigned char *src, int length, int base); -#endif #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/file.h linux/include/linux/file.h --- v2.4.0-test6/linux/include/linux/file.h Thu Jul 27 17:38:02 2000 +++ linux/include/linux/file.h Wed Aug 23 11:22:26 2000 @@ -7,6 +7,27 @@ extern void FASTCALL(fput(struct file *)); extern struct file * FASTCALL(fget(unsigned int fd)); + +static inline int get_close_on_exec(unsigned int fd) +{ + struct files_struct *files = current->files; + int res; + read_lock(&files->file_lock); + res = FD_ISSET(fd, files->close_on_exec); + read_unlock(&files->file_lock); + return res; +} + +static inline void set_close_on_exec(unsigned int fd, int flag) +{ + struct files_struct *files = current->files; + write_lock(&files->file_lock); + if (flag) + FD_SET(fd, files->close_on_exec); + else + FD_CLR(fd, files->close_on_exec); + write_unlock(&files->file_lock); +} static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) { @@ -30,15 +51,6 @@ return file; } -static inline struct file * frip(struct files_struct *files, unsigned int fd) -{ - struct file * file = NULL; - - if (fd < files->max_fds) - file = xchg(&files->fd[fd], NULL); - return file; -} - extern void put_filp(struct file *); extern int get_unused_fd(void); @@ -67,18 +79,20 @@ * array. At any such point, we are vulnerable to a dup2() race * installing a file in the array before us. We need to detect this and * fput() the struct file we are about to overwrite in this case. + * + * It should never happen - if we allow dup2() do it, _really_ bad things + * will follow. */ static inline void fd_install(unsigned int fd, struct file * file) { struct files_struct *files = current->files; - struct file * result; write_lock(&files->file_lock); - result = xchg(&files->fd[fd], file); + if (files->fd[fd]) + BUG(); + files->fd[fd] = file; write_unlock(&files->file_lock); - if (result) - fput(result); } void put_files_struct(struct files_struct *fs); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.0-test6/linux/include/linux/fs.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/fs.h Wed Aug 23 11:35:07 2000 @@ -71,8 +71,6 @@ #define READA 2 /* read-ahead - don't block if no resources */ #define SPECIAL 4 /* For non-blockdevice requests in request queue */ -#define WRITERAW 5 /* raw write - don't play with buffer lists */ - #define SEL_IN 1 #define SEL_OUT 2 #define SEL_EX 4 @@ -535,6 +533,7 @@ #ifndef OFFSET_MAX #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) #define OFFSET_MAX INT_LIMIT(loff_t) +#define OFFT_OFFSET_MAX INT_LIMIT(off_t) #endif extern struct list_head file_lock_list; @@ -544,6 +543,9 @@ extern int fcntl_getlk(unsigned int, struct flock *); extern int fcntl_setlk(unsigned int, unsigned int, struct flock *); +extern int fcntl_getlk64(unsigned int, struct flock64 *); +extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *); + /* fs/locks.c */ extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_flock(struct file *); @@ -694,12 +696,25 @@ extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); /* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +/* * This is the "filldir" function type, used by readdir() to let * the kernel specify what kind of dirent layout it wants to have. * This allows the kernel to read directories into kernel space or * to have different dirent layouts depending on the binary type. */ -typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t); +typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t, unsigned); struct block_device_operations { int (*open) (struct inode *, struct file *); @@ -875,7 +890,6 @@ asmlinkage long sys_open(const char *, int, int); asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */ -extern int do_close(struct files_struct *, unsigned int, int); /* yes, it's really unsigned */ extern int do_truncate(struct dentry *, loff_t start); extern struct file *filp_open(const char *, int, int); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/highmem.h linux/include/linux/highmem.h --- v2.4.0-test6/linux/include/linux/highmem.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/highmem.h Wed Aug 23 11:35:07 2000 @@ -29,6 +29,9 @@ #define kunmap(page) do { } while (0) +#define kmap_atomic(page,idx) kmap(page) +#define kunmap_atomic(page,idx) kunmap(page) + #endif /* CONFIG_HIGHMEM */ /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/if_packet.h linux/include/linux/if_packet.h --- v2.4.0-test6/linux/include/linux/if_packet.h Thu Aug 26 13:05:41 1999 +++ linux/include/linux/if_packet.h Thu Aug 10 13:01:26 2000 @@ -38,6 +38,7 @@ /* Value 4 is still used by obsolete turbo-packet. */ #define PACKET_RX_RING 5 #define PACKET_STATISTICS 6 +#define PACKET_COPY_THRESH 7 struct tpacket_stats { diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/if_tun.h linux/include/linux/if_tun.h --- v2.4.0-test6/linux/include/linux/if_tun.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_tun.h Wed Aug 23 09:30:13 2000 @@ -0,0 +1,92 @@ +/* + * Universal TUN/TAP device driver. + * Copyright (C) 1999-2000 Maxim Krasnyansky + * + * 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. + * + * $Id: if_tun.h,v 1.1 2000/08/23 05:59:28 davem Exp $ + */ + +#ifndef __IF_TUN_H +#define __IF_TUN_H + +/* Uncomment to enable debugging */ +/* #define TUN_DEBUG 1 */ + +#ifdef __KERNEL__ + +#ifdef TUN_DEBUG +#define DBG if(tun->debug)printk +#define DBG1 if(debug==2)printk +#else +#define DBG( a... ) +#define DBG1( a... ) +#endif + +struct tun_struct { + char name[8]; + unsigned long flags; + + struct fasync_struct *fasync; + wait_queue_head_t read_wait; + + struct net_device dev; + struct sk_buff_head txq; + struct net_device_stats stats; + +#ifdef TUN_DEBUG + int debug; +#endif +}; + +#ifndef MIN +#define MIN(a,b) ( (a)<(b) ? (a):(b) ) +#endif + +#endif /* __KERNEL__ */ + +/* Number of devices */ +#define TUN_MAX_DEV 255 + +/* TX queue size */ +#define TUN_TXQ_SIZE 10 + +/* Max frame size */ +#define TUN_MAX_FRAME 4096 + +/* TUN device flags */ +#define TUN_TUN_DEV 0x0001 +#define TUN_TAP_DEV 0x0002 +#define TUN_TYPE_MASK 0x000f + +#define TUN_FASYNC 0x0010 +#define TUN_NOCHECKSUM 0x0020 +#define TUN_NO_PI 0x0040 + +#define TUN_IFF_SET 0x1000 + +/* Ioctl defines */ +#define TUNSETNOCSUM (('T'<< 8) | 200) +#define TUNSETDEBUG (('T'<< 8) | 201) +#define TUNSETIFF (('T'<< 8) | 202) + +/* TUNSETIFF ifr flags */ +#define IFF_TUN 0x0001 +#define IFF_TAP 0x0002 +#define IFF_NO_PI 0x1000 + +struct tun_pi { + unsigned short flags; + unsigned short proto; +}; +#define TUN_PKT_STRIP 0x0001 + +#endif /* __IF_TUN_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/in6.h linux/include/linux/in6.h --- v2.4.0-test6/linux/include/linux/in6.h Mon Jul 10 16:47:27 2000 +++ linux/include/linux/in6.h Wed Aug 23 11:35:08 2000 @@ -34,21 +34,10 @@ __u8 u6_addr8[16]; __u16 u6_addr16[8]; __u32 u6_addr32[4]; -#if (~0UL) > 0xffffffff -#ifndef __RELAX_IN6_ADDR_ALIGNMENT - /* Alas, protocols do not respect 64bit alignmnet. - rsvp/pim/... are broken. However, it is good - idea to force correct alignment always, when - it is possible. - */ - __u64 u6_addr64[2]; -#endif -#endif } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 #define s6_addr32 in6_u.u6_addr32 -#define s6_addr64 in6_u.u6_addr64 }; struct sockaddr_in6 { diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/input.h linux/include/linux/input.h --- v2.4.0-test6/linux/include/linux/input.h Fri Jun 23 21:55:11 2000 +++ linux/include/linux/input.h Tue Aug 22 09:06:31 2000 @@ -2,7 +2,7 @@ #define _INPUT_H /* - * $Id: input.h,v 1.14 2000/06/03 20:18:52 vojtech Exp $ + * $Id: input.h,v 1.18 2000/07/25 21:36:56 vojtech Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * @@ -210,7 +210,7 @@ #define KEY_F22 121 #define KEY_F23 122 #define KEY_F24 123 -#define KEY_JPN 124 +#define KEY_KPCOMMA 124 #define KEY_LEFTMETA 125 #define KEY_RIGHTMETA 126 #define KEY_COMPOSE 127 @@ -266,8 +266,29 @@ #define KEY_EDIT 176 #define KEY_SCROLLUP 177 #define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 -#define KEY_UNKNOWN 180 +#define KEY_INTL1 181 +#define KEY_INTL2 182 +#define KEY_INTL3 183 +#define KEY_INTL4 184 +#define KEY_INTL5 185 +#define KEY_INTL6 186 +#define KEY_INTL7 187 +#define KEY_INTL8 188 +#define KEY_INTL9 189 +#define KEY_LANG1 190 +#define KEY_LANG2 191 +#define KEY_LANG3 192 +#define KEY_LANG4 193 +#define KEY_LANG5 194 +#define KEY_LANG6 195 +#define KEY_LANG7 196 +#define KEY_LANG8 197 +#define KEY_LANG9 198 + +#define KEY_UNKNOWN 200 #define BTN_MISC 0x100 #define BTN_0 0x100 @@ -424,6 +445,8 @@ #define BUS_GAMEPORT 0x14 #define BUS_PARPORT 0x15 #define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 #ifdef __KERNEL__ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v2.4.0-test6/linux/include/linux/isdn.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/isdn.h Mon Aug 21 07:49:03 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.105 2000/05/18 23:14:19 keil Exp $ +/* $Id: isdn.h,v 1.106 2000/08/10 22:52:46 kai Exp $ * Main header for the Linux ISDN subsystem (linklevel). * diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/isdn_divertif.h linux/include/linux/isdn_divertif.h --- v2.4.0-test6/linux/include/linux/isdn_divertif.h Thu Aug 12 09:42:34 1999 +++ linux/include/linux/isdn_divertif.h Mon Aug 21 07:49:03 2000 @@ -1,6 +1,5 @@ -/* - * $Id: isdn_divertif.h,v 1.3 1999/07/05 20:22:00 werner Exp $ - * +/* $Id: isdn_divertif.h,v 1.4 2000/05/11 22:29:22 kai Exp $ + * Header for the diversion supplementary interface for i4l. * * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de) @@ -18,15 +17,6 @@ * 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. - * - * $Log: isdn_divertif.h,v $ - * Revision 1.3 1999/07/05 20:22:00 werner - * changes to use diversion sources for all kernel versions. - * removed static device, only proc filesystem used - * - * Revision 1.2 1999/07/04 21:38:38 werner - * ported from kernel version 2.0 - * * */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/kernelcapi.h linux/include/linux/kernelcapi.h --- v2.4.0-test6/linux/include/linux/kernelcapi.h Mon Jul 10 16:47:27 2000 +++ linux/include/linux/kernelcapi.h Mon Aug 21 07:49:03 2000 @@ -1,65 +1,17 @@ /* - * $Id: kernelcapi.h,v 1.6 2000/03/03 15:50:42 calle Exp $ + * $Id: kernelcapi.h,v 1.7 2000/06/12 09:20:20 kai Exp $ * * Kernel CAPI 2.0 Interface for Linux * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * - * $Log: kernelcapi.h,v $ - * Revision 1.6 2000/03/03 15:50:42 calle - * - kernel CAPI: - * - Changed parameter "param" in capi_signal from __u32 to void *. - * - rewrote notifier handling in kcapi.c - * - new notifier NCCI_UP and NCCI_DOWN - * - User CAPI: - * - /dev/capi20 is now a cloning device. - * - middleware extentions prepared. - * - capidrv.c - * - locking of list operations and module count updates. - * - * Revision 1.5 2000/01/28 16:45:40 calle - * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), - * will search named driver and call the add_card function if one exist. - * - * Revision 1.4 1999/09/10 17:24:19 calle - * Changes for proposed standard for CAPI2.0: - * - AK148 "Linux Exention" - * - * Revision 1.3 1999/07/01 15:26:56 calle - * complete new version (I love it): - * + new hardware independed "capi_driver" interface that will make it easy to: - * - support other controllers with CAPI-2.0 (i.e. USB Controller) - * - write a CAPI-2.0 for the passive cards - * - support serial link CAPI-2.0 boxes. - * + wrote "capi_driver" for all supported cards. - * + "capi_driver" (supported cards) now have to be configured with - * make menuconfig, in the past all supported cards where included - * at once. - * + new and better informations in /proc/capi/ - * + new ioctl to switch trace of capi messages per controller - * using "avmcapictrl trace [contr] on|off|...." - * + complete testcircle with all supported cards and also the - * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. - * - * Revision 1.2 1999/06/21 15:24:26 calle - * extend information in /proc. - * - * Revision 1.1 1997/03/04 21:27:33 calle - * First version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * - * */ + #ifndef __KERNELCAPI_H__ #define __KERNELCAPI_H__ -#define CAPI_MAXAPPL 128 /* maximum number of applications */ -#define CAPI_MAXCONTR 16 /* maximum number of controller */ +#define CAPI_MAXAPPL 20 /* maximum number of applications */ +#define CAPI_MAXCONTR 10 /* maximum number of controller */ #define CAPI_MAXDATAWINDOW 8 @@ -162,6 +114,46 @@ #define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a #define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b +typedef enum { + CapiMessageNotSupportedInCurrentState = 0x2001, + CapiIllContrPlciNcci = 0x2002, + CapiNoPlciAvailable = 0x2003, + CapiNoNcciAvailable = 0x2004, + CapiNoListenResourcesAvailable = 0x2005, + CapiNoFaxResourcesAvailable = 0x2006, + CapiIllMessageParmCoding = 0x2007, +} RESOURCE_CODING_PROBLEM; + +typedef enum { + CapiB1ProtocolNotSupported = 0x3001, + CapiB2ProtocolNotSupported = 0x3002, + CapiB3ProtocolNotSupported = 0x3003, + CapiB1ProtocolParameterNotSupported = 0x3004, + CapiB2ProtocolParameterNotSupported = 0x3005, + CapiB3ProtocolParameterNotSupported = 0x3006, + CapiBProtocolCombinationNotSupported = 0x3007, + CapiNcpiNotSupported = 0x3008, + CapiCipValueUnknown = 0x3009, + CapiFlagsNotSupported = 0x300a, + CapiFacilityNotSupported = 0x300b, + CapiDataLengthNotSupportedByCurrentProtocol = 0x300c, + CapiResetProcedureNotSupportedByCurrentProtocol = 0x300d, + CapiTeiAssignmentFailed = 0x300e, +} REQUESTED_SERVICES_PROBLEM; + +typedef enum { + CapiSuccess = 0x0000, + CapiSupplementaryServiceNotSupported = 0x300e, + CapiRequestNotAllowedInThisState = 0x3010, +} SUPPLEMENTARY_SERVICE_INFO; + +typedef enum { + CapiProtocolErrorLayer1 = 0x3301, + CapiProtocolErrorLayer2 = 0x3302, + CapiProtocolErrorLayer3 = 0x3303, + CapiTimeOut = 0x3303, // SuppServiceReason + CapiCallGivenToOtherApplication = 0x3304, +} CAPI_REASON; #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/major.h linux/include/linux/major.h --- v2.4.0-test6/linux/include/linux/major.h Fri Jun 23 21:55:11 2000 +++ linux/include/linux/major.h Wed Aug 23 09:30:13 2000 @@ -134,6 +134,8 @@ #define USB_ACM_AUX_MAJOR 167 #define USB_CHAR_MAJOR 180 +#define TUN_MAJOR 195 + #define UNIX98_PTY_MASTER_MAJOR 128 #define UNIX98_PTY_MAJOR_COUNT 8 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/mca.h linux/include/linux/mca.h --- v2.4.0-test6/linux/include/linux/mca.h Tue Aug 31 17:29:14 1999 +++ linux/include/linux/mca.h Wed Aug 23 12:21:00 2000 @@ -1,46 +1,50 @@ /* - * Header for Microchannel Architecture Bus + * Header for Microchannel Architecture Bus * Written by Martin Kolinek, February 1996 -*/ + */ #ifndef _LINUX_MCA_H #define _LINUX_MCA_H /* The detection of MCA bus is done in the real mode (using BIOS). - * The information is exported to the protected code, where this + * The information is exported to the protected code, where this * variable is set to one in case MCA bus was detected. -*/ + */ #ifndef MCA_bus__is_a_macro extern int MCA_bus; #endif -/* maximal number of MCA slots - actually, some machines have less, but -they all have sufficient number of POS registers to cover 8. */ +/* Maximal number of MCA slots - actually, some machines have less, but + * they all have sufficient number of POS registers to cover 8. + */ #define MCA_MAX_SLOT_NR 8 /* MCA_NOTFOUND is an error condition. The other two indicate - motherboard POS registers contain the adapter. They might be - returned by the mca_find_adapter() function, and can be used as - arguments to mca_read_stored_pos(). I'm not going to allow direct - access to the motherboard registers until we run across an adapter - that requires it. We don't know enough about them to know if it's - safe. - - See Documentation/mca.txt or one of the existing drivers for - more information. -*/ + * motherboard POS registers contain the adapter. They might be + * returned by the mca_find_adapter() function, and can be used as + * arguments to mca_read_stored_pos(). I'm not going to allow direct + * access to the motherboard registers until we run across an adapter + * that requires it. We don't know enough about them to know if it's + * safe. + * + * See Documentation/mca.txt or one of the existing drivers for + * more information. + */ #define MCA_NOTFOUND (-1) #define MCA_INTEGSCSI (MCA_MAX_SLOT_NR) #define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1) +#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2) -/* max number of adapters, including both slots and various integrated -things. */ -#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+2) - -/* returns the slot of the first enabled adapter matching id. User can -specify a starting slot beyond zero, to deal with detecting multiple -devices. Returns MCA_NOTFOUND if id not found. Also checks the -integrated adapters. */ +/* Max number of adapters, including both slots and various integrated + * things. + */ +#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3) + +/* Returns the slot of the first enabled adapter matching id. User can + * specify a starting slot beyond zero, to deal with detecting multiple + * devices. Returns MCA_NOTFOUND if id not found. Also checks the + * integrated adapters. + */ extern int mca_find_adapter(int id, int start); extern int mca_find_unused_adapter(int id, int start); @@ -55,39 +59,37 @@ /* gets a byte out of POS register (stored in memory) */ extern unsigned char mca_read_stored_pos(int slot, int reg); -/* - This can be expanded later. Right now, it gives us a way of - getting meaningful information into the MCA_info structure, - so we can have a more interesting /proc/mca. -*/ +/* This can be expanded later. Right now, it gives us a way of + * getting meaningful information into the MCA_info structure, + * so we can have a more interesting /proc/mca. + */ extern void mca_set_adapter_name(int slot, char* name); extern char* mca_get_adapter_name(int slot); -/* - This sets up an information callback for /proc/mca/slot?. The - function is called with the buffer, slot, and device pointer (or - some equally informative context information, or nothing, if you - prefer), and is expected to put useful information into the - buffer. The adapter name, id, and POS registers get printed - before this is called though, so don't do it again. - - This should be called with a NULL procfn when a module - unregisters, thus preventing kernel crashes and other such - nastiness. -*/ +/* This sets up an information callback for /proc/mca/slot?. The + * function is called with the buffer, slot, and device pointer (or + * some equally informative context information, or nothing, if you + * prefer), and is expected to put useful information into the + * buffer. The adapter name, id, and POS registers get printed + * before this is called though, so don't do it again. + * + * This should be called with a NULL procfn when a module + * unregisters, thus preventing kernel crashes and other such + * nastiness. + */ typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev); extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev); /* These routines actually mess with the hardware POS registers. They -temporarily disable the device (and interrupts), so make sure you know -what you're doing if you use them. Furthermore, writing to a POS may -result in two devices trying to share a resource, which in turn can -result in multiple devices sharing memory spaces, IRQs, or even trashing -hardware. YOU HAVE BEEN WARNED. - -You can only access slots with this. Motherboard registers are off -limits. -*/ + * temporarily disable the device (and interrupts), so make sure you know + * what you're doing if you use them. Furthermore, writing to a POS may + * result in two devices trying to share a resource, which in turn can + * result in multiple devices sharing memory spaces, IRQs, or even trashing + * hardware. YOU HAVE BEEN WARNED. + * + * You can only access slots with this. Motherboard registers are off + * limits. + */ /* read a byte from the specified POS register. */ extern unsigned char mca_read_pos(int slot, int reg); @@ -96,7 +98,8 @@ extern void mca_write_pos(int slot, int reg, unsigned char byte); /* Should only be called by the NMI interrupt handler, this will do some -fancy stuff to figure out what might have generated a NMI. */ + * fancy stuff to figure out what might have generated a NMI. + */ extern void mca_handle_nmi(void); #endif /* _LINUX_MCA_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.0-test6/linux/include/linux/mm.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/mm.h Wed Aug 23 11:35:07 2000 @@ -384,7 +384,6 @@ extern void swapin_readahead(swp_entry_t); /* mmap.c */ -extern void vma_init(void); extern void merge_segments(struct mm_struct *, unsigned long, unsigned long); extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void build_mmap_avl(struct mm_struct *); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.4.0-test6/linux/include/linux/netdevice.h Mon Jul 10 16:47:27 2000 +++ linux/include/linux/netdevice.h Wed Aug 23 11:36:12 2000 @@ -402,7 +402,6 @@ extern struct net_device loopback_dev; /* The loopback */ extern struct net_device *dev_base; /* All devices */ extern rwlock_t dev_base_lock; /* Device list lock */ -extern struct netdev_boot_setup dev_boot_setup[]; extern int netdev_boot_setup_add(char *name, struct ifmap *map); extern int netdev_boot_setup_check(struct net_device *dev); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h --- v2.4.0-test6/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h Thu Aug 10 12:35:15 2000 @@ -62,21 +62,13 @@ } dst; }; -#define IP_PARTS_NATIVE(n) \ -(unsigned int)((n)>>24)&0xFF, \ -(unsigned int)((n)>>16)&0xFF, \ -(unsigned int)((n)>>8)&0xFF, \ -(unsigned int)((n)&0xFF) - -#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) - #ifdef __KERNEL__ #define DUMP_TUPLE(tp) \ -DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \ +DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ (tp), (tp)->dst.protonum, \ - IP_PARTS((tp)->src.ip), ntohs((tp)->src.u.all), \ - IP_PARTS((tp)->dst.ip), ntohs((tp)->dst.u.all)) + NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ + NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/netfilter_ipv4/ip_queue.h linux/include/linux/netfilter_ipv4/ip_queue.h --- v2.4.0-test6/linux/include/linux/netfilter_ipv4/ip_queue.h Tue Apr 11 15:09:24 2000 +++ linux/include/linux/netfilter_ipv4/ip_queue.h Thu Aug 10 12:35:15 2000 @@ -26,6 +26,10 @@ unsigned int hook; /* Netfilter hook we rode in on */ char indev_name[IFNAMSIZ]; /* Name of incoming interface */ char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */ + unsigned short hw_protocol; /* Hardware protocol (network order) */ + unsigned short hw_type; /* Hardware type */ + unsigned char hw_addrlen; /* Hardware address length */ + unsigned char hw_addr[8]; /* Hardware address */ size_t data_len; /* Length of packet data */ unsigned char payload[0]; /* Optional packet data */ } ipq_packet_msg_t; diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h --- v2.4.0-test6/linux/include/linux/nfsd/nfsd.h Mon Jul 10 16:47:27 2000 +++ linux/include/linux/nfsd/nfsd.h Wed Aug 23 11:35:51 2000 @@ -57,7 +57,7 @@ char dotonly; }; typedef int (*encode_dent_fn)(struct readdir_cd *, const char *, - int, off_t, ino_t); + int, off_t, ino_t, unsigned int); typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); /* diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/nfsd/xdr.h linux/include/linux/nfsd/xdr.h --- v2.4.0-test6/linux/include/linux/nfsd/xdr.h Fri Mar 10 16:40:50 2000 +++ linux/include/linux/nfsd/xdr.h Wed Aug 23 11:35:50 2000 @@ -151,7 +151,7 @@ int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *); int nfssvc_encode_entry(struct readdir_cd *, const char *name, - int namlen, off_t offset, ino_t ino); + int namlen, off_t offset, ino_t ino, unsigned int); int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/nfsd/xdr3.h linux/include/linux/nfsd/xdr3.h --- v2.4.0-test6/linux/include/linux/nfsd/xdr3.h Sun Feb 20 21:12:40 2000 +++ linux/include/linux/nfsd/xdr3.h Wed Aug 23 11:35:51 2000 @@ -292,9 +292,11 @@ int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *, struct nfsd3_fhandle_pair *); int nfs3svc_encode_entry(struct readdir_cd *, const char *name, - int namlen, off_t offset, ino_t ino); + int namlen, off_t offset, ino_t ino, + unsigned int); int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, - int namlen, off_t offset, ino_t ino); + int namlen, off_t offset, ino_t ino, + unsigned int); #endif /* _LINUX_NFSD_XDR3_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h --- v2.4.0-test6/linux/include/linux/pci_ids.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/pci_ids.h Wed Aug 9 20:53:30 2000 @@ -549,6 +549,7 @@ #define PCI_VENDOR_ID_PLX 0x10b5 #define PCI_VENDOR_ID_PLX_ROMULUS 0x106a #define PCI_DEVICE_ID_PLX_SPCOM800 0x1076 +#define PCI_DEVICE_ID_PLX_1077 0x1077 #define PCI_DEVICE_ID_PLX_SPCOM200 0x1103 #define PCI_DEVICE_ID_PLX_9050 0x9050 #define PCI_DEVICE_ID_PLX_9060 0x9060 @@ -856,8 +857,8 @@ #define PCI_VENDOR_ID_V3 0x11b0 #define PCI_DEVICE_ID_V3_V960 0x0001 #define PCI_DEVICE_ID_V3_V350 0x0001 -#define PCI_DEVICE_ID_V3_V960V2 0x0002 -#define PCI_DEVICE_ID_V3_V350V2 0x0002 +#define PCI_DEVICE_ID_V3_V961 0x0002 +#define PCI_DEVICE_ID_V3_V351 0x0002 #define PCI_VENDOR_ID_NP 0x11bc #define PCI_DEVICE_ID_NP_PCI_FDDI 0x0001 @@ -978,6 +979,9 @@ #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006 #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007 #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B #define PCI_VENDOR_ID_PICTUREL 0x12c5 #define PCI_DEVICE_ID_PICTUREL_PCIVST 0x0081 diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/raid/md_k.h linux/include/linux/raid/md_k.h --- v2.4.0-test6/linux/include/linux/raid/md_k.h Thu Jul 27 17:38:02 2000 +++ linux/include/linux/raid/md_k.h Mon Aug 21 07:30:37 2000 @@ -89,7 +89,7 @@ /* * default readahead */ -#define MD_READAHEAD (256 * 512) +#define MD_READAHEAD MAX_READAHEAD extern inline int disk_faulty(mdp_disk_t * d) { diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h --- v2.4.0-test6/linux/include/linux/rtnetlink.h Thu Feb 10 17:11:22 2000 +++ linux/include/linux/rtnetlink.h Thu Aug 10 13:01:26 2000 @@ -277,9 +277,11 @@ #define RTAX_CWND RTAX_CWND RTAX_ADVMSS, #define RTAX_ADVMSS RTAX_ADVMSS + RTAX_REORDERING, +#define RTAX_REORDERING RTAX_REORDERING }; -#define RTAX_MAX RTAX_ADVMSS +#define RTAX_MAX RTAX_REORDERING diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.4.0-test6/linux/include/linux/sched.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/sched.h Wed Aug 23 11:35:07 2000 @@ -367,6 +367,9 @@ struct signal_queue *sigqueue, **sigqueue_tail; unsigned long sas_ss_sp; size_t sas_ss_size; + int (*notifier)(void *priv); + void *notifier_data; + sigset_t *notifier_mask; /* Thread group tracking */ u32 parent_exec_id; @@ -541,9 +544,13 @@ extern int in_group_p(gid_t); extern int in_egroup_p(gid_t); +extern void proc_caches_init(void); extern void flush_signals(struct task_struct *); extern void flush_signal_handlers(struct task_struct *); extern int dequeue_signal(sigset_t *, siginfo_t *); +extern void block_all_signals(int (*notifier)(void *priv), void *priv, + sigset_t *mask); +extern void unblock_all_signals(void); extern int send_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); extern int kill_pg_info(int, struct siginfo *, pid_t); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/serial.h linux/include/linux/serial.h --- v2.4.0-test6/linux/include/linux/serial.h Fri Jun 23 21:55:11 2000 +++ linux/include/linux/serial.h Wed Aug 23 11:35:06 2000 @@ -123,6 +123,8 @@ #define ASYNC_BUGGY_UART 0x4000 /* This is a buggy UART, skip some safety * checks. Note: can be dangerous! */ +#define ASYNC_AUTOPROBE 0x8000 /* Port was autoprobed by PCI or PNP code */ + #define ASYNC_FLAGS 0x7FFF /* Possible legal async flags */ #define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged * users can set or reset */ @@ -137,7 +139,6 @@ #define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */ #define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards --- no longer used */ -#define ASYNC_AUTOPROBE 0x00800000 /* Port was autoprobed */ #define ASYNC_INTERNAL_FLAGS 0xFF000000 /* Internal flags */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.4.0-test6/linux/include/linux/skbuff.h Mon Jul 10 16:47:27 2000 +++ linux/include/linux/skbuff.h Wed Aug 23 11:35:41 2000 @@ -931,6 +931,12 @@ return skb; } +#define skb_queue_walk(queue, skb) \ + for (skb = (queue)->next; \ + (skb != (struct sk_buff *)(queue)); \ + skb=skb->next) + + extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait); extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/slab.h linux/include/linux/slab.h --- v2.4.0-test6/linux/include/linux/slab.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/slab.h Wed Aug 23 11:35:07 2000 @@ -73,6 +73,8 @@ extern kmem_cache_t *filp_cachep; extern kmem_cache_t *dquot_cachep; extern kmem_cache_t *bh_cachep; +extern kmem_cache_t *fs_cachep; +extern kmem_cache_t *sigact_cachep; #ifdef CONFIG_SMP extern unsigned long slab_cache_drain_mask; diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/smb.h linux/include/linux/smb.h --- v2.4.0-test6/linux/include/linux/smb.h Wed Jun 16 19:26:27 1999 +++ linux/include/linux/smb.h Wed Aug 23 11:35:06 2000 @@ -62,6 +62,13 @@ #ifdef __KERNEL__ +#define SMB_NLS_MAXNAMELEN 20 +struct smb_nls_codepage { + char local_name[SMB_NLS_MAXNAMELEN]; + char remote_name[SMB_NLS_MAXNAMELEN]; +}; + + #define SMB_MAXNAMELEN 255 #define SMB_MAXPATHLEN 1024 diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h --- v2.4.0-test6/linux/include/linux/smb_fs.h Thu Jul 27 17:38:02 2000 +++ linux/include/linux/smb_fs.h Mon Aug 14 13:31:10 2000 @@ -73,13 +73,6 @@ #define SMB_F_CACHEVALID 0x01 /* directory cache valid */ #define SMB_F_LOCALWRITE 0x02 /* file modified locally */ -/* - * Bug fix flags - */ -#define SMB_FIX_WIN95 0x0001 /* Win 95 server */ -#define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */ -#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */ - /* NT1 protocol capability bits */ #define SMB_CAP_RAW_MODE 0x0001 @@ -122,6 +115,7 @@ struct inode *smb_iget(struct super_block *, struct smb_fattr *); /* linux/fs/smbfs/proc.c */ +int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); __u32 smb_len(unsigned char *); __u8 *smb_encode_smb_length(__u8 *, __u32); __u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16); diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h --- v2.4.0-test6/linux/include/linux/smb_fs_sb.h Wed Jun 16 19:28:24 1999 +++ linux/include/linux/smb_fs_sb.h Wed Aug 23 11:35:06 2000 @@ -23,7 +23,7 @@ enum smb_conn_state state; struct file * sock_file; - struct smb_mount_data *mnt; + struct smb_mount_data_kernel *mnt; unsigned char *temp_buf; /* Connections are counted. Each time a new socket arrives, @@ -41,8 +41,20 @@ unsigned short rcls; /* The error codes we received */ unsigned short err; - /* We use our on data_ready callback, but need the original one */ + /* We use our own data_ready callback, but need the original one */ void *data_ready; + + /* nls pointers for codepage conversions */ + struct nls_table *remote_nls; + struct nls_table *local_nls; + + /* utf8 can make strings longer so we can't do in-place conversion. + This is a buffer for temporary stuff. We only need one so no need + to put it on the stack. This points to temp_buf space. */ + char *name_buf; + + int (*convert)(char *, int, const char *, int, + struct nls_table *, struct nls_table *); }; #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/smb_mount.h linux/include/linux/smb_mount.h --- v2.4.0-test6/linux/include/linux/smb_mount.h Thu Aug 27 10:58:23 1998 +++ linux/include/linux/smb_mount.h Mon Aug 14 13:31:10 2000 @@ -11,7 +11,7 @@ #include -#define SMB_MOUNT_VERSION 6 +#define SMB_MOUNT_VERSION 6 struct smb_mount_data { int version; @@ -21,5 +21,38 @@ __kernel_mode_t file_mode; __kernel_mode_t dir_mode; }; + + +#ifdef __KERNEL__ + +/* "vers" in big-endian */ +#define SMB_MOUNT_ASCII 0x76657273 + +#define SMB_MOUNT_OLDVERSION 6 +#undef SMB_MOUNT_VERSION +#define SMB_MOUNT_VERSION 7 + +/* flags */ +#define SMB_MOUNT_WIN95 0x0001 /* Win 95 server */ +#define SMB_MOUNT_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */ +#define SMB_MOUNT_DIRATTR 0x0004 /* Use find_first for getattr */ +#define SMB_MOUNT_CASE 0x0008 /* Be case sensitive */ + + +struct smb_mount_data_kernel { + int version; + + __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */ + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_mode_t file_mode; + __kernel_mode_t dir_mode; + + u32 flags; + + struct smb_nls_codepage codepage; +}; + +#endif #endif diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/sound.h linux/include/linux/sound.h --- v2.4.0-test6/linux/include/linux/sound.h Mon Jan 4 11:42:43 1999 +++ linux/include/linux/sound.h Sat Aug 12 19:51:52 2000 @@ -1,3 +1,28 @@ + +/* + * Minor numbers for the sound driver. + */ + +#define SND_DEV_CTL 0 /* Control port /dev/mixer */ +#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM + synthesizer and MIDI output) */ +#define SND_DEV_MIDIN 2 /* Raw midi access */ +#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ +#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ +/* #define SND_DEV_STATUS 6 */ /* /dev/sndstat (obsolete) */ +#define SND_DEV_UNUSED 6 +#define SND_DEV_AWFM 7 /* Reserved */ +#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +/* #define SND_DEV_SNDPROC 9 */ /* /dev/sndproc for programmable devices (not used) */ +/* #define SND_DEV_DMMIDI 9 */ +#define SND_DEV_SYNTH 9 /* Raw synth access /dev/synth (same as /dev/dmfm) */ +#define SND_DEV_DMFM 10 /* Raw synth access /dev/dmfm */ +#define SND_DEV_UNKNOWN11 11 +#define SND_DEV_ADSP 12 /* Like /dev/dsp (obsolete) */ +#define SND_DEV_AMIDI 13 /* Like /dev/midi (obsolete) */ +#define SND_DEV_ADMMIDI 14 /* Like /dev/dmmidi (onsolete) */ + /* * Sound core interface functions */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.4.0-test6/linux/include/linux/sysctl.h Thu Jul 27 17:38:02 2000 +++ linux/include/linux/sysctl.h Thu Aug 10 13:01:26 2000 @@ -260,6 +260,15 @@ NET_TCP_SYNACK_RETRIES=76, NET_TCP_MAX_ORPHANS=77, NET_TCP_MAX_TW_BUCKETS=78, + NET_TCP_FACK=79, + NET_TCP_REORDERING=80, + NET_TCP_ECN=81, + NET_TCP_DSACK=82, + NET_TCP_MEM=83, + NET_TCP_WMEM=84, + NET_TCP_RMEM=85, + NET_TCP_APP_WIN=86, + NET_TCP_ADV_WIN_SCALE=87, }; enum { diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h --- v2.4.0-test6/linux/include/linux/ufs_fs.h Mon Jul 10 16:47:27 2000 +++ linux/include/linux/ufs_fs.h Wed Aug 23 11:35:06 2000 @@ -250,19 +250,6 @@ __s32 tv_usec; }; -/* - * File types - */ -#define DT_UNKNOWN 0 -#define DT_FIFO 1 -#define DT_CHR 2 -#define DT_DIR 4 -#define DT_BLK 6 -#define DT_REG 8 -#define DT_LNK 10 -#define DT_SOCK 12 -#define DT_WHT 14 - struct ufs_dir_entry { __u32 d_ino; /* inode number of this entry */ __u16 d_reclen; /* length of this entry */ diff -u --recursive --new-file v2.4.0-test6/linux/include/linux/usb.h linux/include/linux/usb.h --- v2.4.0-test6/linux/include/linux/usb.h Wed Aug 9 19:19:51 2000 +++ linux/include/linux/usb.h Tue Aug 22 09:06:31 2000 @@ -261,7 +261,7 @@ struct usb_endpoint_descriptor *endpoint; - unsigned char *extra; + unsigned char *extra; /* Extra descriptors */ int extralen; } __attribute__ ((packed)); @@ -288,6 +288,9 @@ __u8 MaxPower; struct usb_interface *interface; + + unsigned char *extra; /* Extra descriptors */ + int extralen; } __attribute__ ((packed)); /* String descriptor */ diff -u --recursive --new-file v2.4.0-test6/linux/include/net/dst.h linux/include/net/dst.h --- v2.4.0-test6/linux/include/net/dst.h Fri Jan 28 15:09:09 2000 +++ linux/include/net/dst.h Wed Aug 23 11:36:13 2000 @@ -44,6 +44,7 @@ unsigned ssthresh; unsigned cwnd; unsigned advmss; + unsigned reordering; unsigned long rate_last; /* rate limiting for ICMP */ unsigned long rate_tokens; diff -u --recursive --new-file v2.4.0-test6/linux/include/net/snmp.h linux/include/net/snmp.h --- v2.4.0-test6/linux/include/net/snmp.h Thu Feb 10 17:11:23 2000 +++ linux/include/net/snmp.h Thu Aug 10 13:01:26 2000 @@ -199,7 +199,45 @@ unsigned long TCPPrequeueDropped; unsigned long TCPHPHits; unsigned long TCPHPHitsToUser; - unsigned long __pad[32-26]; + unsigned long TCPPureAcks; + unsigned long TCPHPAcks; + unsigned long TCPRenoRecovery; + unsigned long TCPSackRecovery; + unsigned long TCPSACKReneging; + unsigned long TCPFACKReorder; + unsigned long TCPSACKReorder; + unsigned long TCPRenoReorder; + unsigned long TCPTSReorder; + unsigned long TCPFullUndo; + unsigned long TCPPartialUndo; + unsigned long TCPDSACKUndo; + unsigned long TCPLossUndo; + unsigned long TCPLoss; + unsigned long TCPLostRetransmit; + unsigned long TCPRenoFailures; + unsigned long TCPSackFailures; + unsigned long TCPLossFailures; + unsigned long TCPFastRetrans; + unsigned long TCPForwardRetrans; + unsigned long TCPSlowStartRetrans; + unsigned long TCPTimeouts; + unsigned long TCPRenoRecoveryFail; + unsigned long TCPSackRecoveryFail; + unsigned long TCPSchedulerFailed; + unsigned long TCPRcvCollapsed; + unsigned long TCPDSACKOldSent; + unsigned long TCPDSACKOfoSent; + unsigned long TCPDSACKRecv; + unsigned long TCPDSACKOfoRecv; + unsigned long TCPAbortOnSyn; + unsigned long TCPAbortOnData; + unsigned long TCPAbortOnClose; + unsigned long TCPAbortOnMemory; + unsigned long TCPAbortOnTimeout; + unsigned long TCPAbortOnLinger; + unsigned long TCPAbortFailed; + unsigned long TCPMemoryPressures; + unsigned long __pad[64-64]; }; #define SNMP_INC_STATS(mib, field) ((mib)[2*smp_processor_id()+!in_softirq()].field++) diff -u --recursive --new-file v2.4.0-test6/linux/include/net/sock.h linux/include/net/sock.h --- v2.4.0-test6/linux/include/net/sock.h Thu Jul 27 17:38:02 2000 +++ linux/include/net/sock.h Wed Aug 23 11:36:14 2000 @@ -268,10 +268,10 @@ __u8 pingpong; /* The session is interactive */ __u8 blocked; /* Delayed ACK was blocked by socket lock*/ __u32 ato; /* Predicted tick of soft clock */ + unsigned long timeout; /* Currently scheduled timeout */ __u32 lrcvtime; /* timestamp of last received data packet*/ - __u16 last_seg_size; /* Size of last incoming segment */ - __u16 rcv_mss; /* MSS used for delayed ACK decisions */ - __u32 rcv_segs; /* Number of received segments since last ack */ + __u16 last_seg_size; /* Size of last incoming segment */ + __u16 rcv_mss; /* MSS used for delayed ACK decisions */ } ack; /* Data for direct copy to user */ @@ -284,19 +284,18 @@ } ucopy; __u32 snd_wl1; /* Sequence for window update */ - __u32 snd_wl2; /* Ack sequence for update */ __u32 snd_wnd; /* The window we expect to receive */ __u32 max_window; /* Maximal window ever seen from peer */ __u32 pmtu_cookie; /* Last pmtu seen by socket */ __u16 mss_cache; /* Cached effective mss, not including SACKS */ __u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ __u16 ext_header_len; /* Network protocol overhead (IP/IPv6 options) */ - __u8 dup_acks; /* Consecutive duplicate acks seen from other end */ - __u8 retransmits; + __u8 ca_state; /* State of fast-retransmit machine */ + __u8 retransmits; /* Number of unrecovered RTO timeouts. */ - __u8 __empty1; - __u8 sorry; - __u8 defer_accept; + __u8 reordering; /* Packet reordering metric. */ + __u8 queue_shrunk; /* Write queue has been shrunk recently.*/ + __u8 defer_accept; /* User waits for some data after accept() */ /* RTT measurement */ __u8 backoff; /* backoff */ @@ -305,9 +304,9 @@ __u32 rto; /* retransmit timeout */ __u32 packets_out; /* Packets which are "in flight" */ - __u32 fackets_out; /* Non-retrans SACK'd packets */ - __u32 retrans_out; /* Fast-retransmitted packets out */ - __u32 high_seq; /* snd_nxt at onset of congestion */ + __u32 left_out; /* Packets which leaved network */ + __u32 retrans_out; /* Retransmitted packets out */ + /* * Slow start and congestion control (see also Nagle, and Karn & Partridge) @@ -316,12 +315,11 @@ __u32 snd_cwnd; /* Sending congestion window */ __u16 snd_cwnd_cnt; /* Linear increase counter */ __u16 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ - - __u8 nonagle; /* Disable Nagle algorithm? */ - __u8 syn_retries; /* num of allowed syn retries */ - __u16 user_mss; /* mss requested by user in ioctl */ + __u32 snd_cwnd_used; + __u32 snd_cwnd_stamp; /* Two commonly used timers in both sender and receiver paths. */ + unsigned long timeout; struct timer_list retransmit_timer; /* Resend (no ack) */ struct timer_list delack_timer; /* Ack delay */ @@ -329,16 +327,12 @@ struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} specific */ struct sk_buff *send_head; /* Front of stuff to transmit */ - struct sk_buff *retrans_head; /* retrans head can be - * different to the head of - * write queue if we are doing - * fast retransmit - */ __u32 rcv_wnd; /* Current receiver window */ __u32 rcv_wup; /* rcv_nxt on last window update sent */ - __u32 write_seq; - __u32 copied_seq; + __u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ + __u32 pushed_seq; /* Last pushed seq, required to talk to windows */ + __u32 copied_seq; /* Head of yet unread data */ /* * Options received (usually on last packet, some only on SYN packets). */ @@ -348,7 +342,7 @@ char saw_tstamp; /* Saw TIMESTAMP on last packet */ __u8 snd_wscale; /* Window scaling received from sender */ __u8 rcv_wscale; /* Window scaling to send to receiver */ - __u8 rexmt_done; /* Retransmitted up to send head? */ + __u8 nonagle; /* Disable Nagle algorithm? */ __u8 keepalive_probes; /* num of allowed keep alive probes */ /* PAWS/RTTM data */ @@ -358,19 +352,37 @@ long ts_recent_stamp;/* Time we stored ts_recent (for aging) */ /* SACKs data */ + __u16 user_mss; /* mss requested by user in ioctl */ + __u8 dsack; /* D-SACK is scheduled */ + __u8 eff_sacks; /* Size of SACK array to send with next packet */ + struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ - struct timer_list probe_timer; /* Probes */ __u32 window_clamp; /* Maximal window to advertise */ + __u32 rcv_ssthresh; /* Current window clamp */ __u8 probes_out; /* unanswered 0 window probes */ __u8 num_sacks; /* Number of SACK blocks */ __u16 advmss; /* Advertised MSS */ - __u32 syn_stamp; - __u32 syn_seq; - __u32 fin_seq; - __u32 urg_seq; - __u32 urg_data; + __u8 syn_retries; /* num of allowed syn retries */ + __u8 ecn_flags; /* ECN status bits. */ + __u16 prior_ssthresh; /* ssthresh saved at recovery start */ + __u32 lost_out; /* Lost packets */ + __u32 sacked_out; /* SACK'd packets */ + __u32 fackets_out; /* FACK'd packets */ + __u32 high_seq; /* snd_nxt at onset of congestion */ + + __u32 retrans_stamp; /* Timestamp of the last retransmit, + * also used in SYN-SENT to remember stamp of + * the first SYN. */ + __u32 undo_marker; /* tracking retrans started here. */ + int undo_retrans; /* number of undoable retransmissions. */ + __u32 syn_seq; /* Seq of received SYN. */ + __u32 fin_seq; /* Seq of received FIN. */ + __u32 urg_seq; /* Seq of received urgent pointer */ + __u16 urg_data; /* Saved octet of OOB data and control flags */ + __u8 pending; /* Scheduled timer event */ + __u8 __empty; /* The syn_wait_lock is necessary only to avoid tcp_get_info having * to grab the main lock sock while browsing the listening hash @@ -482,8 +494,8 @@ __u16 sport; /* Source port */ unsigned short family; /* Address family */ - unsigned char reuse, /* SO_REUSEADDR setting */ - __unused; + unsigned char reuse; /* SO_REUSEADDR setting */ + unsigned char shutdown; atomic_t refcnt; /* Reference count */ socket_lock_t lock; /* Synchronizer... */ @@ -497,6 +509,8 @@ atomic_t wmem_alloc; /* Transmit queue bytes committed */ struct sk_buff_head write_queue; /* Packet sending queue */ atomic_t omem_alloc; /* "o" is "option" or "other" */ + int wmem_queued; /* Persistent queue size */ + int forward_alloc; /* Space allocated forward. */ __u32 saddr; /* Sending source */ unsigned int allocation; /* Allocation mode */ int sndbuf; /* Size of send buffer in bytes */ @@ -539,8 +553,6 @@ struct proto *prot; - unsigned short shutdown; - #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) union { struct ipv6_pinfo af_inet6; @@ -734,6 +746,11 @@ #define RCV_SHUTDOWN 1 #define SEND_SHUTDOWN 2 +#define SOCK_SNDBUF_LOCK 1 +#define SOCK_RCVBUF_LOCK 2 +#define SOCK_BINDADDR_LOCK 4 + + /* Used by processes to "lock" a socket state, so that * interrupts and bottom half handlers won't change it * from under us. It essentially blocks any incoming @@ -801,8 +818,6 @@ int priority); extern void sock_wfree(struct sk_buff *skb); extern void sock_rfree(struct sk_buff *skb); -extern void sock_cfree(struct sk_buff *skb); -extern unsigned long sock_rspace(struct sock *sk); extern unsigned long sock_wspace(struct sock *sk); extern int sock_setsockopt(struct socket *sock, int level, @@ -982,8 +997,6 @@ * we do not release it in this function, because protocol * probably wants some additional cleanups or even continuing * to work with this socket (TCP). - * - * NOTE: When softnet goes in replace _irq with _bh! */ extern __inline__ void sock_orphan(struct sock *sk) { @@ -1003,6 +1016,25 @@ write_unlock_bh(&sk->callback_lock); } +static inline int sock_i_uid(struct sock *sk) +{ + int uid; + + read_lock(&sk->callback_lock); + uid = sk->socket ? sk->socket->inode->i_uid : 0; + read_unlock(&sk->callback_lock); + return uid; +} + +static inline unsigned long sock_i_ino(struct sock *sk) +{ + unsigned long ino; + + read_lock(&sk->callback_lock); + ino = sk->socket ? sk->socket->inode->i_ino : 0; + read_unlock(&sk->callback_lock); + return ino; +} extern __inline__ struct dst_entry * __sk_dst_get(struct sock *sk) @@ -1110,14 +1142,6 @@ atomic_add(skb->truesize, &sk->rmem_alloc); } -extern __inline__ void skb_set_owner_c(struct sk_buff *skb, struct sock *sk) -{ - sock_hold(sk); - skb->sk = sk; - skb->destructor = sock_cfree; -} - - extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces @@ -1194,7 +1218,7 @@ } #define SOCK_MIN_SNDBUF 2048 -#define SOCK_MIN_RCVBUF 128 +#define SOCK_MIN_RCVBUF 256 /* Must be less or equal SOCK_MIN_SNDBUF */ #define SOCK_MIN_WRITE_SPACE SOCK_MIN_SNDBUF diff -u --recursive --new-file v2.4.0-test6/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.4.0-test6/linux/include/net/tcp.h Fri Jun 23 21:55:11 2000 +++ linux/include/net/tcp.h Wed Aug 23 11:36:24 2000 @@ -19,9 +19,13 @@ #define _TCP_H #define TCP_DEBUG 1 +#define FASTRETRANS_DEBUG 1 + +/* Be paranoid about data immediately beyond right edge of window. */ #undef TCP_FORMAL_WINDOW -#define TCP_MORE_COARSE_ACKS -#undef TCP_LESS_COARSE_ACKS + +/* Cancel timers, when they are not required. */ +#undef TCP_CLEAR_TIMERS #include #include @@ -173,7 +177,7 @@ } extern atomic_t tcp_orphan_count; -extern int tcp_tw_count; +extern int tcp_tw_count; extern void tcp_time_wait(struct sock *sk, int state, int timeo); extern void tcp_timewait_kill(struct tcp_tw_bucket *tw); extern void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo); @@ -242,12 +246,14 @@ /* Minimal RCV_MSS. */ #define TCP_MIN_RCVMSS 536 -/* - * How much of the receive buffer do we advertize - * (the rest is reserved for headers and driver packet overhead) - * Use a power of 2. - */ -#define TCP_WINDOW_ADVERTISE_DIVISOR 2 +/* After receiving this amount of duplicate ACKs fast retransmit starts. */ +#define TCP_FASTRETRANS_THRESH 3 + +/* Maximal reordering. */ +#define TCP_MAX_REORDERING 127 + +/* Maximal number of ACKs sent quickly to accelerate slow-start. */ +#define TCP_MAX_QUICKACKS 16 /* urg_data states */ #define TCP_URG_VALID 0x0100 @@ -292,7 +298,6 @@ #define TCP_DELACK_MAX (HZ/5) /* maximal time to delay before sending an ACK */ #define TCP_DELACK_MIN (2) /* minimal time to delay before sending an ACK, * 2 scheduler ticks, not depending on HZ. */ -#define TCP_ATO_MAX (HZ/2) /* Clamp ATO estimator at his value. */ #define TCP_ATO_MIN 2 #define TCP_RTO_MAX (120*HZ) #define TCP_RTO_MIN (HZ/5) @@ -414,6 +419,19 @@ extern int sysctl_tcp_abort_on_overflow; extern int sysctl_tcp_max_orphans; extern int sysctl_tcp_max_tw_buckets; +extern int sysctl_tcp_fack; +extern int sysctl_tcp_reordering; +extern int sysctl_tcp_ecn; +extern int sysctl_tcp_dsack; +extern int sysctl_tcp_mem[3]; +extern int sysctl_tcp_wmem[3]; +extern int sysctl_tcp_rmem[3]; +extern int sysctl_tcp_app_win; +extern int sysctl_tcp_adv_win_scale; + +extern atomic_t tcp_memory_allocated; +extern atomic_t tcp_sockets_allocated; +extern int tcp_memory_pressure; struct open_request; @@ -606,6 +624,23 @@ struct tcphdr *th, unsigned len); +enum tcp_ack_state_t +{ + TCP_ACK_SCHED = 1, + TCP_ACK_TIMER = 2, + TCP_ACK_PUSHED= 4 +}; + +static inline void tcp_schedule_ack(struct tcp_opt *tp) +{ + tp->ack.pending |= TCP_ACK_SCHED; +} + +static inline int tcp_ack_scheduled(struct tcp_opt *tp) +{ + return tp->ack.pending&TCP_ACK_SCHED; +} + static __inline__ void tcp_dec_quickack_mode(struct tcp_opt *tp) { if (tp->ack.quick && --tp->ack.quick == 0) { @@ -614,11 +649,27 @@ } } +extern void tcp_enter_quickack_mode(struct tcp_opt *tp); + static __inline__ void tcp_delack_init(struct tcp_opt *tp) { memset(&tp->ack, 0, sizeof(tp->ack)); } +enum tcp_ca_state +{ + TCP_CA_Open = 0, +#define TCPF_CA_Open (1<tp_pinfo.af_tcp; + + switch (what) { + case TCP_TIME_RETRANS: + case TCP_TIME_PROBE0: + tp->pending = 0; + +#ifdef TCP_CLEAR_TIMERS + if (timer_pending(&tp->retransmit_timer) && + del_timer(&tp->retransmit_timer)) + __sock_put(sk); +#endif + break; + case TCP_TIME_DACK: + tp->ack.blocked = 0; + tp->ack.pending = 0; + +#ifdef TCP_CLEAR_TIMERS + if (timer_pending(&tp->delack_timer) && + del_timer(&tp->delack_timer)) + __sock_put(sk); +#endif + break; + default: + printk(timer_bug_msg); + return; + }; + +} + +/* + * Reset the retransmission timer + */ +static inline void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + + if (when > TCP_RTO_MAX) { +#ifdef TCP_DEBUG + printk(KERN_DEBUG "reset_xmit_timer sk=%p %d when=0x%lx, caller=%p\n", sk, what, when, current_text_addr()); +#endif + when = TCP_RTO_MAX; + } + + switch (what) { + case TCP_TIME_RETRANS: + case TCP_TIME_PROBE0: + tp->pending = what; + tp->timeout = jiffies+when; + if (!mod_timer(&tp->retransmit_timer, tp->timeout)) + sock_hold(sk); + break; + + case TCP_TIME_DACK: + tp->ack.pending |= TCP_ACK_TIMER; + tp->ack.timeout = jiffies+when; + if (!mod_timer(&tp->delack_timer, tp->ack.timeout)) + sock_hold(sk); + break; + + default: + printk(KERN_DEBUG "bug: unknown timer value\n"); + }; +} + /* Compute the current effective MSS, taking SACKs and IP options, * and even PMTU discovery events into account. */ @@ -757,9 +879,9 @@ if (dst && dst->pmtu != tp->pmtu_cookie) mss_now = tcp_sync_mss(sk, dst->pmtu); - if(tp->sack_ok && tp->num_sacks) + if (tp->eff_sacks) mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + - (tp->num_sacks * TCPOLEN_SACK_PERBLOCK)); + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); return mss_now; } @@ -774,15 +896,8 @@ extern __inline__ void tcp_initialize_rcv_mss(struct sock *sk) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - struct dst_entry *dst = __sk_dst_get(sk); - int mss; - - if (dst) - mss = dst->advmss; - else - mss = tp->mss_cache; - tp->ack.rcv_mss = max(min(mss, TCP_MIN_RCVMSS), TCP_MIN_MSS); + tp->ack.rcv_mss = max(min(tp->advmss, TCP_MIN_RCVMSS), TCP_MIN_MSS); } static __inline__ void __tcp_fast_path_on(struct tcp_opt *tp, u32 snd_wnd) @@ -797,9 +912,6 @@ __tcp_fast_path_on(tp, tp->snd_wnd>>tp->snd_wscale); } - - - /* Compute the actual receive window we are currently advertising. * Rcv_nxt can be after the window if our peer push more data * than the offered window. @@ -819,52 +931,6 @@ */ extern u32 __tcp_select_window(struct sock *sk); -/* Chose a new window to advertise, update state in tcp_opt for the - * socket, and return result with RFC1323 scaling applied. The return - * value can be stuffed directly into th->window for an outgoing - * frame. - */ -extern __inline__ u16 tcp_select_window(struct sock *sk) -{ - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - u32 cur_win = tcp_receive_window(tp); - u32 new_win = __tcp_select_window(sk); - - /* Never shrink the offered window */ - if(new_win < cur_win) { - /* Danger Will Robinson! - * Don't update rcv_wup/rcv_wnd here or else - * we will not be able to advertise a zero - * window in time. --DaveM - * - * Relax Will Robinson. - */ - new_win = cur_win; - } - tp->rcv_wnd = new_win; - tp->rcv_wup = tp->rcv_nxt; - - /* RFC1323 scaling applied */ - new_win >>= tp->rcv_wscale; - -#ifdef TCP_FORMAL_WINDOW - if (new_win == 0) { - /* If we advertise zero window, disable fast path. */ - tp->pred_flags = 0; - } else if (cur_win == 0 && tp->pred_flags == 0 && - skb_queue_len(&tp->out_of_order_queue) == 0 && - !tp->urg_data) { - /* If we open zero window, enable fast path. - Without this it will be open by the first data packet, - it is too late to merge checksumming to copy. - */ - tcp_fast_path_on(tp); - } -#endif - - return new_win; -} - /* TCP timestamps are only 32-bits, this causes a slight * complication on 64-bit systems since we store a snapshot * of jiffies in the buffer control blocks below. We decidely @@ -907,6 +973,12 @@ __u8 sacked; /* State flags for SACK/FACK. */ #define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */ #define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */ +#define TCPCB_LOST 0x04 /* SKB is lost */ +#define TCPCB_TAGBITS 0x07 /* All tag bits */ + +#define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */ +#define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS) + __u16 urg_ptr; /* Valid w/URG flags is set. */ __u32 ack_seq; /* Sequence number ACK'd */ @@ -914,11 +986,28 @@ #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) +#define for_retrans_queue(skb, sk, tp) \ + for (skb = (sk)->write_queue.next; \ + (skb != (tp)->send_head) && \ + (skb != (struct sk_buff *)&(sk)->write_queue); \ + skb=skb->next) + + +#include + + /* * Compute minimal free write space needed to queue new packets. */ -#define tcp_min_write_space(__sk) \ - (atomic_read(&(__sk)->wmem_alloc) / 2) +static inline int tcp_min_write_space(struct sock *sk) +{ + return sk->wmem_queued/2; +} + +static inline int tcp_wspace(struct sock *sk) +{ + return sk->sndbuf - sk->wmem_queued; +} /* This determines how many packets are "in the network" to the best @@ -932,89 +1021,97 @@ * Read this equation as: * * "Packets sent once on transmission queue" MINUS - * "Packets acknowledged by FACK information" PLUS + * "Packets left network, but not honestly ACKed yet" PLUS * "Packets fast retransmitted" */ static __inline__ int tcp_packets_in_flight(struct tcp_opt *tp) { - return tp->packets_out - tp->fackets_out + tp->retrans_out; + return tp->packets_out - tp->left_out + tp->retrans_out; } /* Recalculate snd_ssthresh, we want to set it to: * * one half the current congestion window, but no * less than two segments - * - * We must take into account the current send window - * as well, however we keep track of that using different - * units so a conversion is necessary. -DaveM - * - * RED-PEN. - * RFC 2581: "an easy mistake to make is to simply use cwnd, - * rather than FlightSize" - * I see no references to FlightSize here. snd_wnd is not FlightSize, - * it is also apriory characteristics. - * - * FlightSize = min((snd_nxt-snd_una)/mss, packets_out) ? */ extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) { - u32 FlightSize = (tp->snd_nxt - tp->snd_una)/tp->mss_cache; + return max(tp->snd_cwnd>>1, 2); +} + +/* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. + * The exception is rate halving phase, when cwnd is decreasing towards + * ssthresh. + */ +extern __inline__ __u32 tcp_current_ssthresh(struct tcp_opt *tp) +{ + if ((1<ca_state)&(TCPF_CA_CWR|TCPF_CA_Recovery)) + return tp->snd_ssthresh; + else + return max(tp->snd_ssthresh, (tp->snd_cwnd>>1)+(tp->snd_cwnd>>2)); +} + +extern void tcp_cwnd_application_limited(struct sock *sk); - FlightSize = min(FlightSize, tcp_packets_in_flight(tp)); +/* Congestion window validation. (RFC2861) */ - return max(min(FlightSize, tp->snd_cwnd) >> 1, 2); +static inline void tcp_cwnd_validate(struct sock *sk, struct tcp_opt *tp) +{ + if (tp->packets_out >= tp->snd_cwnd) { + /* Network is feed fully. */ + tp->snd_cwnd_used = 0; + tp->snd_cwnd_stamp = tcp_time_stamp; + } else { + /* Network starves. */ + if (tp->packets_out > tp->snd_cwnd_used) + tp->snd_cwnd_used = tp->packets_out; + + if ((s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= tp->rto) + tcp_cwnd_application_limited(sk); + } } /* Set slow start threshould and cwnd not falling to slow start */ -extern __inline__ void __tcp_enter_cong_avoid(struct tcp_opt *tp) +extern __inline__ void __tcp_enter_cwr(struct tcp_opt *tp) { + tp->undo_marker = 0; tp->snd_ssthresh = tcp_recalc_ssthresh(tp); - if (tp->snd_ssthresh > tp->snd_cwnd_clamp) - tp->snd_ssthresh = tp->snd_cwnd_clamp; - tp->snd_cwnd = tp->snd_ssthresh; + tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1); tp->snd_cwnd_cnt = 0; tp->high_seq = tp->snd_nxt; + tp->snd_cwnd_stamp = tcp_time_stamp; + TCP_ECN_queue_cwr(tp); } -extern __inline__ void tcp_enter_cong_avoid(struct tcp_opt *tp) +extern __inline__ void tcp_enter_cwr(struct tcp_opt *tp) { - if (!tp->high_seq || after(tp->snd_nxt, tp->high_seq)) - __tcp_enter_cong_avoid(tp); + tp->prior_ssthresh = 0; + if (tp->ca_state < TCP_CA_CWR) { + __tcp_enter_cwr(tp); + tp->ca_state = TCP_CA_CWR; + } } +extern __u32 tcp_init_cwnd(struct tcp_opt *tp); -/* Increase initial CWND conservatively, i.e. only if estimated - RTT is low enough. It is not quite correct, we should use - POWER i.e. RTT*BANDWIDTH, but we still cannot estimate this. - - Numbers are taken from RFC1414. +/* Slow start with delack produces 3 packets of burst, so that + * it is safe "de facto". */ -static __inline__ __u32 tcp_init_cwnd(struct tcp_opt *tp) +static __inline__ __u32 tcp_max_burst(struct tcp_opt *tp) { - __u32 cwnd; - - if (!tp->srtt || tp->srtt > ((HZ/50)<<3) || tp->mss_cache > 1460) - cwnd = 2; - else if (tp->mss_cache > 1095) - cwnd = 3; - else - cwnd = 4; - - return min(cwnd, tp->snd_cwnd_clamp); + return 3; } - static __inline__ int tcp_minshall_check(struct tcp_opt *tp) { return after(tp->snd_sml,tp->snd_una) && !after(tp->snd_sml, tp->snd_nxt); } -static __inline__ void tcp_minshall_update(struct tcp_opt *tp, int mss, int len) +static __inline__ void tcp_minshall_update(struct tcp_opt *tp, int mss, struct sk_buff *skb) { - if (len < mss) - tp->snd_sml = tp->snd_nxt; + if (skb->len < mss) + tp->snd_sml = TCP_SKB_CB(skb)->end_seq; } /* Return 0, if packet can be sent now without violation Nagle's rules: @@ -1041,17 +1138,6 @@ static __inline__ int tcp_snd_test(struct tcp_opt *tp, struct sk_buff *skb, unsigned cur_mss, int tail) { - /* - * Reset CWND after idle period longer RTO to "restart window". - * It is "side" effect of the function, which is _not_ good - * from viewpoint of clarity. But we have to make it before - * checking congestion window below. Alternative is to prepend - * all the calls with this test. - */ - if (tp->packets_out==0 && - (s32)(tcp_time_stamp - tp->lsndtime) > tp->rto) - tp->snd_cwnd = min(tp->snd_cwnd, tcp_init_cwnd(tp)); - /* RFC 1122 - section 4.2.3.4 * * We must queue if @@ -1062,8 +1148,7 @@ * (part of SWS is done on packetization) * Minshall version sounds: there are no _small_ * segments in flight. (tcp_nagle_check) - * c) We are retransmiting [Nagle] - * d) We have too many packets 'in flight' + * c) We have too many packets 'in flight' * * Don't use the nagle rule for urgent data (or * for the final FIN -DaveM). @@ -1081,13 +1166,12 @@ skb_tailroom(skb) < 32) && ((tcp_packets_in_flight(tp) < tp->snd_cwnd) || (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) && - !after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) && - tp->retransmits == 0); + !after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd)); } static __inline__ void tcp_check_probe_timer(struct sock *sk, struct tcp_opt *tp) { - if (!tp->packets_out && !timer_pending(&tp->probe_timer)) + if (!tp->packets_out && !tp->pending) tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, tp->rto); } @@ -1111,6 +1195,7 @@ tcp_write_xmit(sk)) tcp_check_probe_timer(sk, tp); } + tcp_cwnd_validate(sk, tp); } static __inline__ void tcp_push_pending_frames(struct sock *sk, @@ -1119,6 +1204,24 @@ __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk)); } +static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_opt *tp) +{ + struct sk_buff *skb = tp->send_head; + + return (skb && + tcp_snd_test(tp, skb, tcp_current_mss(sk), tcp_skb_is_last(sk, skb))); +} + +static __inline__ void tcp_init_wl(struct tcp_opt *tp, u32 ack, u32 seq) +{ + tp->snd_wl1 = seq; +} + +static __inline__ void tcp_update_wl(struct tcp_opt *tp, u32 ack, u32 seq) +{ + tp->snd_wl1 = seq; +} + extern void tcp_destroy_sock(struct sock *sk); @@ -1143,7 +1246,6 @@ __tcp_checksum_complete(skb); } - /* Prequeue for VJ style copy to user, combined with checksumming. */ static __inline__ void tcp_prequeue_init(struct tcp_opt *tp) @@ -1167,12 +1269,15 @@ if (tp->ucopy.task) { if ((tp->ucopy.memory += skb->truesize) <= (sk->rcvbuf<<1)) { __skb_queue_tail(&tp->ucopy.prequeue, skb); - if (skb_queue_len(&tp->ucopy.prequeue) == 1) + if (skb_queue_len(&tp->ucopy.prequeue) == 1) { wake_up_interruptible(sk->sleep); + if (!tcp_ack_scheduled(tp)) + tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4); + } } else { NET_INC_STATS_BH(TCPPrequeueDropped); tp->ucopy.memory -= skb->truesize; - kfree_skb(skb); + __kfree_skb(skb); } return 1; } @@ -1231,6 +1336,13 @@ tcp_destroy_sock(sk); } +static __inline__ void tcp_sack_reset(struct tcp_opt *tp) +{ + tp->dsack = 0; + tp->eff_sacks = 0; + tp->num_sacks = 0; +} + static __inline__ void tcp_build_and_update_options(__u32 *ptr, struct tcp_opt *tp, __u32 tstamp) { if (tp->tstamp_ok) { @@ -1241,17 +1353,22 @@ *ptr++ = htonl(tstamp); *ptr++ = htonl(tp->ts_recent); } - if(tp->sack_ok && tp->num_sacks) { + if (tp->eff_sacks) { + struct tcp_sack_block *sp = tp->dsack ? tp->duplicate_sack : tp->selective_acks; int this_sack; *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_SACK << 8) | (TCPOLEN_SACK_BASE + - (tp->num_sacks * TCPOLEN_SACK_PERBLOCK))); - for(this_sack = 0; this_sack < tp->num_sacks; this_sack++) { - *ptr++ = htonl(tp->selective_acks[this_sack].start_seq); - *ptr++ = htonl(tp->selective_acks[this_sack].end_seq); + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK))); + for(this_sack = 0; this_sack < tp->eff_sacks; this_sack++) { + *ptr++ = htonl(sp[this_sack].start_seq); + *ptr++ = htonl(sp[this_sack].end_seq); + } + if (tp->dsack) { + tp->dsack = 0; + tp->eff_sacks--; } } } @@ -1330,42 +1447,44 @@ space >>= 1; (*rcv_wscale)++; } + if (*rcv_wscale && sysctl_tcp_app_win && space>=mss && + space - max((space>>sysctl_tcp_app_win), mss>>*rcv_wscale) < 65536/2) + (*rcv_wscale)--; + } + + /* Set initial window to value enough for senders, + * following RFC1414. Senders, not following this RFC, + * will be satisfied with 2. + */ + if (mss > (1<<*rcv_wscale)) { + int init_cwnd = 4; + if (mss > 1460*3) + init_cwnd = 2; + else if (mss > 1460) + init_cwnd = 3; + if (*rcv_wnd > init_cwnd*mss) + *rcv_wnd = init_cwnd*mss; } /* Set the clamp no higher than max representable value */ (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp); } +static inline int tcp_win_from_space(int space) +{ + return sysctl_tcp_adv_win_scale<=0 ? + (space>>(-sysctl_tcp_adv_win_scale)) : + space - (space>>sysctl_tcp_adv_win_scale); +} + /* Note: caller must be prepared to deal with negative returns */ extern __inline__ int tcp_space(struct sock *sk) { - return (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / - TCP_WINDOW_ADVERTISE_DIVISOR; + return tcp_win_from_space(sk->rcvbuf - atomic_read(&sk->rmem_alloc)); } extern __inline__ int tcp_full_space( struct sock *sk) { - return sk->rcvbuf / TCP_WINDOW_ADVERTISE_DIVISOR; -} - -extern __inline__ void tcp_init_buffer_space(struct sock *sk) -{ - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int rcvbuf = tp->advmss+MAX_TCP_HEADER+16+sizeof(struct sk_buff); - int sndbuf = tp->mss_clamp+MAX_TCP_HEADER+16+sizeof(struct sk_buff); - - if (sk->rcvbuf < 3*rcvbuf) - sk->rcvbuf = min (3*rcvbuf, sysctl_rmem_max); - - /* Reserve slack space to reduce jitter of advertised window. */ - if (tp->window_clamp >= tcp_full_space(sk)) { - int nwin = tcp_full_space(sk) - tp->mss_clamp; - - if (nwin >= MAX_TCP_WINDOW && nwin >= 2*tp->advmss) - tp->window_clamp = nwin; - } - - if (sk->sndbuf < 3*sndbuf) - sk->sndbuf = min (3*sndbuf, sysctl_wmem_max); + return tcp_win_from_space(sk->rcvbuf); } extern __inline__ void tcp_acceptq_removed(struct sock *sk) @@ -1473,61 +1592,85 @@ req->snd_wscale = tp->snd_wscale; req->wscale_ok = tp->wscale_ok; req->acked = 0; + req->ecn_ok = 0; req->rmt_port = skb->h.th->source; } -extern const char timer_bug_msg[]; +#define TCP_MEM_QUANTUM ((int)PAGE_SIZE) -static inline void tcp_clear_xmit_timer(struct sock *sk, int what) +static inline void tcp_free_skb(struct sock *sk, struct sk_buff *skb) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - struct timer_list *timer; - - switch (what) { - case TCP_TIME_RETRANS: - timer = &tp->retransmit_timer; - break; - case TCP_TIME_DACK: - tp->ack.blocked = 0; - timer = &tp->delack_timer; - break; - case TCP_TIME_PROBE0: - timer = &tp->probe_timer; - break; - default: - printk(timer_bug_msg); - return; - }; + sk->tp_pinfo.af_tcp.queue_shrunk = 1; + sk->wmem_queued -= skb->truesize; + sk->forward_alloc += skb->truesize; + __kfree_skb(skb); +} - if (timer_pending(timer) && del_timer(timer)) - __sock_put(sk); +static inline void tcp_charge_skb(struct sock *sk, struct sk_buff *skb) +{ + sk->wmem_queued += skb->truesize; + sk->forward_alloc -= skb->truesize; } -/* This function does not return reliable answer. Use it only as advice. - */ +extern void __tcp_mem_reclaim(struct sock *sk); +extern int tcp_mem_schedule(struct sock *sk, int size, int kind); -static inline int tcp_timer_is_set(struct sock *sk, int what) +static inline void tcp_mem_reclaim(struct sock *sk) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - int ret; + if (sk->forward_alloc >= TCP_MEM_QUANTUM) + __tcp_mem_reclaim(sk); +} - switch (what) { - case TCP_TIME_RETRANS: - ret = timer_pending(&tp->retransmit_timer); - break; - case TCP_TIME_DACK: - ret = timer_pending(&tp->delack_timer); - break; - case TCP_TIME_PROBE0: - ret = timer_pending(&tp->probe_timer); - break; - default: - ret = 0; - printk(timer_bug_msg); - }; - return ret; +static inline void tcp_enter_memory_pressure(void) +{ + if (!tcp_memory_pressure) { + NET_INC_STATS(TCPMemoryPressures); + tcp_memory_pressure = 1; + } } +static inline void tcp_moderate_sndbuf(struct sock *sk) +{ + if (!(sk->userlocks&SOCK_SNDBUF_LOCK)) { + sk->sndbuf = min(sk->sndbuf, sk->wmem_queued/2); + sk->sndbuf = max(sk->sndbuf, SOCK_MIN_SNDBUF); + } +} + +static inline struct sk_buff *tcp_alloc_skb(struct sock *sk, int size, int gfp) +{ + struct sk_buff *skb = alloc_skb(size, gfp); + + if (skb) { + if (sk->forward_alloc >= (int)skb->truesize || + tcp_mem_schedule(sk, skb->truesize, 0)) + return skb; + __kfree_skb(skb); + } else { + tcp_enter_memory_pressure(); + tcp_moderate_sndbuf(sk); + } + return NULL; +} + +static inline void tcp_writequeue_purge(struct sock *sk) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(&sk->write_queue)) != NULL) + tcp_free_skb(sk, skb); + tcp_mem_reclaim(sk); +} + +extern void tcp_rfree(struct sk_buff *skb); + +static inline void tcp_set_owner_r(struct sk_buff *skb, struct sock *sk) +{ + skb->sk = sk; + skb->destructor = tcp_rfree; + atomic_add(skb->truesize, &sk->rmem_alloc); + sk->forward_alloc -= skb->truesize; +} extern void tcp_listen_wlock(void); @@ -1570,28 +1713,30 @@ return fin_timeout; } -#if 0 /* TCP_DEBUG */ -#define TCP_CHECK_TIMER(sk) \ -do { struct tcp_opt *__tp = &sk->tp_pinfo.af_tcp; \ - if (sk->state != TCP_CLOSE) { \ - if (__tp->packets_out) { \ - if (!tcp_timer_is_set(sk, TCP_TIME_RETRANS) && !timer_is_running(&__tp->retransmit_timer) && net_ratelimit()) \ - printk(KERN_DEBUG "sk=%p RETRANS" __FUNCTION__ "(%d) %d\n", sk, __LINE__, sk->state); \ - } else if (__tp->send_head) { \ - if (!tcp_timer_is_set(sk, TCP_TIME_PROBE0) && !timer_is_running(&__tp->probe_timer) && net_ratelimit()) \ - printk(KERN_DEBUG "sk=%p PROBE0" __FUNCTION__ "(%d) %d\n", sk, __LINE__, sk->state); \ - } \ - if (__tp->ack.pending) { \ - if (!tcp_timer_is_set(sk, TCP_TIME_DACK) && !timer_is_running(&__tp->delack_timer) && net_ratelimit()) \ - printk(KERN_DEBUG "sk=%p DACK" __FUNCTION__ "(%d) %d\n", sk, __LINE__, sk->state); \ - } \ - if (__tp->packets_out > skb_queue_len(&sk->write_queue) || \ - (__tp->send_head && skb_queue_len(&sk->write_queue) == 0)) { \ - printk(KERN_DEBUG "sk=%p QUEUE" __FUNCTION__ "(%d) %d %d %d %p\n", sk, __LINE__, sk->state, __tp->packets_out, skb_queue_len(&sk->write_queue), __tp->send_head); \ - } \ - } } while (0) -#else +static inline int tcp_paws_check(struct tcp_opt *tp, int rst) +{ + if ((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) + return 0; + if (xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS) + return 0; + + /* RST segments are not recommended to carry timestamp, + and, if they do, it is recommended to ignore PAWS because + "their cleanup function should take precedence over timestamps." + Certainly, it is mistake. It is necessary to understand the reasons + of this constraint to relax it: if peer reboots, clock may go + out-of-sync and half-open connections will not be reset. + Actually, the problem would be not existing if all + the implementations followed draft about maintaining clock + via reboots. Linux-2.2 DOES NOT! + + However, we can relax time bounds for RST segments to MSL. + */ + if (rst && xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_MSL) + return 0; + return 1; +} + #define TCP_CHECK_TIMER(sk) do { } while (0); -#endif #endif /* _TCP_H */ diff -u --recursive --new-file v2.4.0-test6/linux/include/net/tcp_ecn.h linux/include/net/tcp_ecn.h --- v2.4.0-test6/linux/include/net/tcp_ecn.h Wed Dec 31 16:00:00 1969 +++ linux/include/net/tcp_ecn.h Wed Aug 23 11:36:15 2000 @@ -0,0 +1,155 @@ +#ifndef _NET_TCP_ECN_H_ +#define _NET_TCP_ECN_H_ 1 + +#include + +#ifdef CONFIG_INET_ECN + +#include + +#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)|TCP_FLAG_ECE|TCP_FLAG_CWR) + +#define TCP_ECN_OK 1 +#define TCP_ECN_QUEUE_CWR 2 +#define TCP_ECN_DEMAND_CWR 4 + +static __inline__ void +TCP_ECN_queue_cwr(struct tcp_opt *tp) +{ + if (tp->ecn_flags&TCP_ECN_OK) + tp->ecn_flags |= TCP_ECN_QUEUE_CWR; +} + + +/* Output functions */ + +static __inline__ void +TCP_ECN_send_synack(struct tcp_opt *tp, struct sk_buff *skb) +{ + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR; + if (!(tp->ecn_flags&TCP_ECN_OK)) + TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE; +} + +static __inline__ void +TCP_ECN_send_syn(struct tcp_opt *tp, struct sk_buff *skb) +{ + tp->ecn_flags = 0; + if (sysctl_tcp_ecn) { + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; + tp->ecn_flags = TCP_ECN_OK; + } +} + +static __inline__ void +TCP_ECN_make_synack(struct open_request *req, struct tcphdr *th) +{ + if (req->ecn_ok) + th->ece = 1; +} + +static __inline__ void +TCP_ECN_send(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb, int tcp_header_len) +{ + if (tp->ecn_flags & TCP_ECN_OK) { + /* Not-retransmitted data segment: set ECT and inject CWR. */ + if (skb->len != tcp_header_len && + !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) { + INET_ECN_xmit(sk); + if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) { + tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; + skb->h.th->cwr = 1; + } + } else { + /* ACK or retransmitted segment: clear ECT|CE */ + INET_ECN_dontxmit(sk); + } + if (tp->ecn_flags & TCP_ECN_DEMAND_CWR) + skb->h.th->ece = 1; + } +} + +/* Input functions */ + +static __inline__ void +TCP_ECN_accept_cwr(struct tcp_opt *tp, struct sk_buff *skb) +{ + if (skb->h.th->cwr) + tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; +} + +static __inline__ void +TCP_ECN_check_ce(struct tcp_opt *tp, struct sk_buff *skb) +{ + if (tp->ecn_flags&TCP_ECN_OK) { + if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags)) + tp->ecn_flags |= TCP_ECN_DEMAND_CWR; + /* Funny extension: if ECT is not set on a segment, + * it is surely retransmit. It is not in ECN RFC, + * but Linux follows this rule. */ + else if (!INET_ECN_is_capable((TCP_SKB_CB(skb)->flags))) + tcp_enter_quickack_mode(tp); + } +} + +static __inline__ void +TCP_ECN_rcv_synack(struct tcp_opt *tp, struct tcphdr *th) +{ + if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || th->cwr)) + tp->ecn_flags &= ~TCP_ECN_OK; +} + +static __inline__ void +TCP_ECN_rcv_syn(struct tcp_opt *tp, struct tcphdr *th) +{ + if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || !th->cwr)) + tp->ecn_flags &= ~TCP_ECN_OK; +} + +static __inline__ int +TCP_ECN_rcv_ecn_echo(struct tcp_opt *tp, struct tcphdr *th) +{ + if (th->ece && !th->syn && (tp->ecn_flags&TCP_ECN_OK)) + return 1; + return 0; +} + +static __inline__ void +TCP_ECN_openreq_child(struct tcp_opt *tp, struct open_request *req) +{ + tp->ecn_flags = req->ecn_ok ? TCP_ECN_OK : 0; +} + +static __inline__ void +TCP_ECN_create_request(struct open_request *req, struct tcphdr *th) +{ + if (sysctl_tcp_ecn && th->ece && th->cwr) + req->ecn_ok = 1; +} + + + +#else + +#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) + + +#define TCP_ECN_send_syn(x...) do { } while (0) +#define TCP_ECN_send_synack(x...) do { } while (0) +#define TCP_ECN_make_synack(x...) do { } while (0) +#define TCP_ECN_send(x...) do { } while (0) + +#define TCP_ECN_queue_cwr(x...) do { } while (0) + +#define TCP_ECN_accept_cwr(x...) do { } while (0) +#define TCP_ECN_check_ce(x...) do { } while (0) +#define TCP_ECN_rcv_synack(x...) do { } while (0) +#define TCP_ECN_rcv_syn(x...) do { } while (0) +#define TCP_ECN_rcv_ecn_echo(x...) (0) +#define TCP_ECN_openreq_child(x...) do { } while (0) +#define TCP_ECN_create_request(x...) do { } while (0) + + +#endif + +#endif diff -u --recursive --new-file v2.4.0-test6/linux/init/main.c linux/init/main.c --- v2.4.0-test6/linux/init/main.c Wed Aug 9 19:19:51 2000 +++ linux/init/main.c Sun Aug 13 19:25:14 2000 @@ -95,7 +95,6 @@ extern void signals_init(void); extern void bdev_init(void); extern int init_pcmcia_ds(void); -extern int usb_init(void); extern void free_initmem(void); extern void filesystem_setup(void); @@ -562,8 +561,8 @@ mempages = num_physpages; fork_init(mempages); + proc_caches_init(); vfs_caches_init(mempages); - vma_init(); buffer_init(mempages); page_cache_init(mempages); kiobuf_setup(); @@ -685,10 +684,6 @@ #endif #ifdef CONFIG_ISAPNP isapnp_init(); -#endif -#ifdef CONFIG_USB - usb_init(); /* Do this before doing initcalls, so that we can make - usbcore initialize here, and all drivers initialize later */ #endif #ifdef CONFIG_TC tc_init(); diff -u --recursive --new-file v2.4.0-test6/linux/ipc/shm.c linux/ipc/shm.c --- v2.4.0-test6/linux/ipc/shm.c Mon Jul 10 16:47:27 2000 +++ linux/ipc/shm.c Fri Aug 11 14:29:04 2000 @@ -438,12 +438,12 @@ switch(nr) { case 0: - if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ @@ -456,7 +456,7 @@ continue; if (shp->shm_flags & SHM_UNLK) continue; - if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr) < 0 ) + if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr, DT_REG) < 0 ) break;; } filp->f_pos = nr; diff -u --recursive --new-file v2.4.0-test6/linux/kernel/exit.c linux/kernel/exit.c --- v2.4.0-test6/linux/kernel/exit.c Wed Aug 9 19:19:51 2000 +++ linux/kernel/exit.c Fri Aug 11 14:57:43 2000 @@ -229,7 +229,7 @@ dput(fs->altroot); mntput(fs->altrootmnt); } - kfree(fs); + kmem_cache_free(fs_cachep, fs); } } @@ -264,7 +264,7 @@ tsk->sig = NULL; spin_unlock_irq(&tsk->sigmask_lock); if (atomic_dec_and_test(&sig->count)) - kfree(sig); + kmem_cache_free(sigact_cachep, sig); } flush_signals(tsk); diff -u --recursive --new-file v2.4.0-test6/linux/kernel/fork.c linux/kernel/fork.c --- v2.4.0-test6/linux/kernel/fork.c Wed Aug 9 19:19:51 2000 +++ linux/kernel/fork.c Wed Aug 23 11:33:48 2000 @@ -32,9 +32,6 @@ unsigned long total_forks; /* Handle normal Linux uptimes. */ int last_pid; -/* SLAB cache for mm_struct's. */ -kmem_cache_t *mm_cachep; - struct task_struct *pidhash[PIDHASH_SZ]; void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) @@ -314,18 +311,19 @@ tsk->mm = mm; tsk->active_mm = mm; - /* - * child gets a private LDT (if there was an LDT in the parent) - */ - copy_segments(tsk, mm); - down(¤t->mm->mmap_sem); retval = dup_mmap(mm); up(¤t->mm->mmap_sem); if (retval) goto free_pt; - init_new_context(tsk,mm); + /* + * child gets a private LDT (if there was an LDT in the parent) + */ + copy_segments(tsk, mm); + + if (init_new_context(tsk,mm)) + goto free_pt; good_mm: tsk->mm = mm; @@ -340,7 +338,7 @@ static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old) { - struct fs_struct *fs = kmalloc(sizeof(*old), GFP_KERNEL); + struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); /* We don't need to lock fs - think why ;-) */ if (fs) { atomic_set(&fs->count, 1); @@ -506,7 +504,7 @@ atomic_inc(¤t->sig->count); return 0; } - tsk->sig = kmalloc(sizeof(*tsk->sig), GFP_KERNEL); + tsk->sig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL); if (!tsk->sig) return -1; spin_lock_init(&tsk->sig->siglock); @@ -553,8 +551,6 @@ *p = *current; - lock_kernel(); - retval = -EAGAIN; if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) goto bad_fork_free; @@ -671,11 +667,12 @@ nr_threads++; write_unlock_irq(&tasklist_lock); + if (p->ptrace & PT_PTRACED) + send_sig(SIGSTOP, p, 1); + wake_up_process(p); /* do this last */ ++total_forks; -bad_fork: - unlock_kernel(); fork_out: if ((clone_flags & CLONE_VFORK) && (retval > 0)) down(&sem); @@ -696,5 +693,53 @@ free_uid(p->user); bad_fork_free: free_task_struct(p); - goto bad_fork; + goto fork_out; +} + +/* SLAB cache for signal_struct structures (tsk->sig) */ +kmem_cache_t *sigact_cachep; + +/* SLAB cache for files_struct structures (tsk->files) */ +kmem_cache_t *files_cachep; + +/* SLAB cache for fs_struct structures (tsk->fs) */ +kmem_cache_t *fs_cachep; + +/* SLAB cache for vm_area_struct structures */ +kmem_cache_t *vm_area_cachep; + +/* SLAB cache for mm_struct structures (tsk->mm) */ +kmem_cache_t *mm_cachep; + +void __init proc_caches_init(void) +{ + sigact_cachep = kmem_cache_create("signal_act", + sizeof(struct signal_struct), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!sigact_cachep) + panic("Cannot create signal action SLAB cache"); + + files_cachep = kmem_cache_create("files_cache", + sizeof(struct files_struct), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!files_cachep) + panic("Cannot create files SLAB cache"); + + fs_cachep = kmem_cache_create("fs_cache", + sizeof(struct fs_struct), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!fs_cachep) + panic("Cannot create fs_struct SLAB cache"); + + vm_area_cachep = kmem_cache_create("vm_area_struct", + sizeof(struct vm_area_struct), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if(!vm_area_cachep) + panic("vma_init: Cannot alloc vm_area_struct SLAB cache"); + + mm_cachep = kmem_cache_create("mm_struct", + sizeof(struct mm_struct), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if(!mm_cachep) + panic("vma_init: Cannot alloc mm_struct SLAB cache"); } diff -u --recursive --new-file v2.4.0-test6/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.0-test6/linux/kernel/ksyms.c Wed Aug 9 19:19:51 2000 +++ linux/kernel/ksyms.c Mon Aug 14 15:18:34 2000 @@ -527,6 +527,7 @@ /* library functions */ EXPORT_SYMBOL(strnicmp); EXPORT_SYMBOL(strspn); +EXPORT_SYMBOL(strsep); /* software interrupts */ EXPORT_SYMBOL(tasklet_hi_vec); diff -u --recursive --new-file v2.4.0-test6/linux/kernel/sched.c linux/kernel/sched.c --- v2.4.0-test6/linux/kernel/sched.c Wed Aug 9 19:19:51 2000 +++ linux/kernel/sched.c Wed Aug 23 11:31:15 2000 @@ -247,7 +247,7 @@ * one will have the least active cache context.) Also find * the executing process which has the least priority. */ - oldest_idle = -1ULL; + oldest_idle = (cycles_t) -1; target_tsk = NULL; max_prio = 1; @@ -454,7 +454,6 @@ */ static inline void __schedule_tail(struct task_struct *prev) { - current->need_resched |= prev->need_resched; #ifdef CONFIG_SMP if ((prev->state == TASK_RUNNING) && (prev != idle_task(smp_processor_id()))) { diff -u --recursive --new-file v2.4.0-test6/linux/kernel/signal.c linux/kernel/signal.c --- v2.4.0-test6/linux/kernel/signal.c Fri Jun 23 21:55:23 2000 +++ linux/kernel/signal.c Mon Aug 21 11:46:57 2000 @@ -45,6 +45,42 @@ } +/* Given the mask, find the first available signal that should be serviced. */ + +static int +next_signal(sigset_t *signal, sigset_t *mask) +{ + unsigned long i, *s, *m, x; + int sig = 0; + + s = signal->sig; + m = mask->sig; + switch (_NSIG_WORDS) { + default: + for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m) + if ((x = *s &~ *m) != 0) { + sig = ffz(~x) + i*_NSIG_BPW + 1; + break; + } + break; + + case 2: if ((x = s[0] &~ m[0]) != 0) + sig = 1; + else if ((x = s[1] &~ m[1]) != 0) + sig = _NSIG_BPW + 1; + else + break; + sig += ffz(~x); + break; + + case 1: if ((x = *s &~ *m) != 0) + sig = ffz(~x) + 1; + break; + } + + return sig; +} + /* * Flush all pending signals for a task. */ @@ -86,6 +122,32 @@ } } +/* Notify the system that a driver wants to block all signals for this + * process, and wants to be notified if any signals at all were to be + * sent/acted upon. If the notifier routine returns non-zero, then the + * signal will be acted upon after all. If the notifier routine returns 0, + * then then signal will be blocked. Only one block per process is + * allowed. priv is a pointer to private data that the notifier routine + * can use to determine if the signal should be blocked or not. */ + +void +block_all_signals(int (*notifier)(void *priv), void *priv, sigset_t *mask) +{ + current->notifier_mask = mask; + current->notifier_data = priv; + current->notifier = notifier; +} + +/* Notify the system that blocking has ended. */ + +void +unblock_all_signals(void) +{ + current->notifier = NULL; + current->notifier_data = NULL; + recalc_sigpending(current); +} + /* * Dequeue a signal and return the element to the caller, which is * expected to free it. @@ -96,7 +158,6 @@ int dequeue_signal(sigset_t *mask, siginfo_t *info) { - unsigned long i, *s, *m, x; int sig = 0; #if DEBUG_SIG @@ -104,30 +165,22 @@ signal_pending(current)); #endif - /* Find the first desired signal that is pending. */ - s = current->signal.sig; - m = mask->sig; - switch (_NSIG_WORDS) { - default: - for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m) - if ((x = *s &~ *m) != 0) { - sig = ffz(~x) + i*_NSIG_BPW + 1; - break; - } - break; - - case 2: if ((x = s[0] &~ m[0]) != 0) - sig = 1; - else if ((x = s[1] &~ m[1]) != 0) - sig = _NSIG_BPW + 1; - else - break; - sig += ffz(~x); - break; - - case 1: if ((x = *s &~ *m) != 0) - sig = ffz(~x) + 1; - break; + sig = next_signal(¤t->signal, mask); + if (current->notifier) { + sigset_t merged; + int i; + int altsig; + + for (i = 0; i < _NSIG_WORDS; i++) + merged.sig[i] = mask->sig[i] + | current->notifier_mask->sig[i]; + altsig = next_signal(¤t->signal, &merged); + if (sig != altsig) { + if (!(current->notifier)(current->notifier_data)) { + current->sigpending = 0; + return 0; + } + } } if (sig) { @@ -657,6 +710,8 @@ EXPORT_SYMBOL(recalc_sigpending); EXPORT_SYMBOL(send_sig); EXPORT_SYMBOL(send_sig_info); +EXPORT_SYMBOL(block_all_signals); +EXPORT_SYMBOL(unblock_all_signals); /* diff -u --recursive --new-file v2.4.0-test6/linux/kernel/timer.c linux/kernel/timer.c --- v2.4.0-test6/linux/kernel/timer.c Wed Aug 9 19:19:51 2000 +++ linux/kernel/timer.c Mon Aug 21 09:22:45 2000 @@ -180,17 +180,15 @@ unsigned long flags; spin_lock_irqsave(&timerlist_lock, flags); - if (timer->list.next) + if (timer_pending(timer)) goto bug; internal_add_timer(timer); -out: spin_unlock_irqrestore(&timerlist_lock, flags); return; - bug: + spin_unlock_irqrestore(&timerlist_lock, flags); printk("bug: kernel timer added twice at %p.\n", __builtin_return_address(0)); - goto out; } static inline int detach_timer (struct timer_list *timer) diff -u --recursive --new-file v2.4.0-test6/linux/lib/cmdline.c linux/lib/cmdline.c --- v2.4.0-test6/linux/lib/cmdline.c Fri Jun 23 21:55:23 2000 +++ linux/lib/cmdline.c Fri Aug 11 19:14:46 2000 @@ -85,12 +85,12 @@ * @ptr: Where parse begins * @retptr: (output) Pointer to next char after parse completes * - * Parses a string into a number. The number stored - * at @ptr is potentially suffixed with %K (for - * kilobytes, or 1024 bytes) or suffixed with %M (for - * megabytes, or 1048576 bytes). If the number is suffixed - * with K or M, then the return value is the number - * multiplied by one kilobyte, or one megabyte, respectively. + * Parses a string into a number. The number stored at @ptr is + * potentially suffixed with %K (for kilobytes, or 1024 bytes), + * %M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or + * 1073741824). If the number is suffixed with K, M, or G, then + * the return value is the number multiplied by one kilobyte, one + * megabyte, or one gigabyte, respectively. */ unsigned long memparse (char *ptr, char **retptr) @@ -98,6 +98,9 @@ unsigned long ret = simple_strtoul (ptr, retptr, 0); switch (**retptr) { + case 'G': + case 'g': + ret <<= 10; case 'M': case 'm': ret <<= 10; diff -u --recursive --new-file v2.4.0-test6/linux/lib/string.c linux/lib/string.c --- v2.4.0-test6/linux/lib/string.c Mon Jul 10 16:47:27 2000 +++ linux/lib/string.c Thu Aug 10 13:10:14 2000 @@ -250,7 +250,7 @@ *s = strpbrk( sbegin, ct); if (*s && **s != '\0') - **s++ = '\0'; + *(*s)++ = '\0'; return (sbegin); } #endif diff -u --recursive --new-file v2.4.0-test6/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.0-test6/linux/mm/filemap.c Wed Aug 9 19:19:51 2000 +++ linux/mm/filemap.c Mon Aug 21 09:33:15 2000 @@ -414,7 +414,7 @@ if (buffer_locked(bh) || !buffer_dirty(bh) || !buffer_uptodate(bh)) continue; - bh->b_flushtime = 0; + bh->b_flushtime = jiffies; ll_rw_block(WRITE, 1, &bh); } while ((bh = bh->b_this_page) != head); return 0; @@ -513,7 +513,6 @@ struct address_space *mapping, unsigned long offset, struct page **hash) { - struct page *alias; unsigned long flags; if (PageLocked(page)) @@ -526,9 +525,6 @@ add_page_to_inode_queue(mapping, page); __add_page_to_hash_queue(page, hash); lru_cache_add(page); - alias = __find_page_nolock(mapping, offset, *hash); - if (alias != page) - BUG(); } void add_to_page_cache(struct page * page, struct address_space * mapping, unsigned long offset) diff -u --recursive --new-file v2.4.0-test6/linux/mm/highmem.c linux/mm/highmem.c --- v2.4.0-test6/linux/mm/highmem.c Wed Aug 9 19:19:51 2000 +++ linux/mm/highmem.c Mon Aug 14 13:11:16 2000 @@ -339,7 +339,7 @@ bh->b_count = bh_orig->b_count; bh->b_rdev = bh_orig->b_rdev; bh->b_state = bh_orig->b_state; - bh->b_flushtime = 0; + bh->b_flushtime = jiffies; bh->b_next_free = NULL; bh->b_prev_free = NULL; /* bh->b_this_page */ diff -u --recursive --new-file v2.4.0-test6/linux/mm/mmap.c linux/mm/mmap.c --- v2.4.0-test6/linux/mm/mmap.c Thu Jul 27 17:38:02 2000 +++ linux/mm/mmap.c Fri Aug 11 14:57:43 2000 @@ -36,9 +36,6 @@ __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; -/* SLAB cache for vm_area_struct's. */ -kmem_cache_t *vm_area_cachep; - int sysctl_overcommit_memory; /* Check that a process has enough memory to allocate a @@ -993,21 +990,4 @@ kmem_cache_free(vm_area_cachep, mpnt); mpnt = prev; } -} - -void __init vma_init(void) -{ - vm_area_cachep = kmem_cache_create("vm_area_struct", - sizeof(struct vm_area_struct), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if(!vm_area_cachep) - panic("vma_init: Cannot alloc vm_area_struct cache."); - - mm_cachep = kmem_cache_create("mm_struct", - sizeof(struct mm_struct), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if(!mm_cachep) - panic("vma_init: Cannot alloc mm_struct cache."); } diff -u --recursive --new-file v2.4.0-test6/linux/mm/slab.c linux/mm/slab.c --- v2.4.0-test6/linux/mm/slab.c Wed Aug 9 19:19:51 2000 +++ linux/mm/slab.c Fri Aug 11 15:04:54 2000 @@ -843,21 +843,17 @@ static DECLARE_WAIT_QUEUE_HEAD(cache_drain_wait); unsigned long slab_cache_drain_mask; -static void drain_cpu_caches(kmem_cache_t *cachep) +/* + * Waits for all CPUs to execute slab_drain_local_cache(). + * Caller must be holding cache_drain_sem. + */ +static void slab_drain_all_sync(void) { DECLARE_WAITQUEUE(wait, current); - unsigned long cpu_mask = 0; - int i; - - for (i = 0; i < smp_num_cpus; i++) - cpu_mask |= (1UL << cpu_logical_map(i)); - - down(&cache_drain_sem); - - cache_to_drain = cachep; - slab_cache_drain_mask = cpu_mask; + local_irq_disable(); slab_drain_local_cache(); + local_irq_enable(); add_wait_queue(&cache_drain_wait, &wait); current->state = TASK_UNINTERRUPTIBLE; @@ -865,7 +861,21 @@ schedule(); current->state = TASK_RUNNING; remove_wait_queue(&cache_drain_wait, &wait); +} + +static void drain_cpu_caches(kmem_cache_t *cachep) +{ + unsigned long cpu_mask = 0; + int i; + for (i = 0; i < smp_num_cpus; i++) + cpu_mask |= (1UL << cpu_logical_map(i)); + + down(&cache_drain_sem); + + cache_to_drain = cachep; + slab_cache_drain_mask = cpu_mask; + slab_drain_all_sync(); cache_to_drain = NULL; up(&cache_drain_sem); @@ -1594,7 +1604,6 @@ /* Called from per-cpu timer interrupt. */ void slab_drain_local_cache(void) { - local_irq_disable(); if (ccupdate_state != NULL) { ccupdate_struct_t *new = ccupdate_state; cpucache_t *old = cc_data(new->cachep); @@ -1610,7 +1619,6 @@ cc->avail = 0; } } - local_irq_enable(); clear_bit(smp_processor_id(), &slab_cache_drain_mask); if (slab_cache_drain_mask == 0) @@ -1619,7 +1627,6 @@ static void do_ccupdate(ccupdate_struct_t *data) { - DECLARE_WAITQUEUE(wait, current); unsigned long cpu_mask = 0; int i; @@ -1630,16 +1637,7 @@ ccupdate_state = data; slab_cache_drain_mask = cpu_mask; - - slab_drain_local_cache(); - - add_wait_queue(&cache_drain_wait, &wait); - current->state = TASK_UNINTERRUPTIBLE; - while (slab_cache_drain_mask != 0UL) - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&cache_drain_wait, &wait); - + slab_drain_all_sync(); ccupdate_state = NULL; up(&cache_drain_sem); diff -u --recursive --new-file v2.4.0-test6/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.4.0-test6/linux/net/appletalk/ddp.c Thu Jul 27 17:38:02 2000 +++ linux/net/appletalk/ddp.c Tue Aug 22 08:59:00 2000 @@ -1611,7 +1611,10 @@ struct sk_buff *newskb; /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ newskb = skb_realloc_headroom(skb, 32); - kfree(skb); + kfree_skb(skb); + if (!newskb) + return 0; + skb = newskb; } else skb = skb_unshare(skb, GFP_ATOMIC); diff -u --recursive --new-file v2.4.0-test6/linux/net/core/dev.c linux/net/core/dev.c --- v2.4.0-test6/linux/net/core/dev.c Fri Jun 23 21:55:23 2000 +++ linux/net/core/dev.c Tue Aug 22 08:59:00 2000 @@ -58,6 +58,7 @@ * the backlog queue. * Paul Rusty Russell : SIOCSIFNAME * Pekka Riikonen : Netdev boot-time settings code + * Andrew Morton : Make unregister_netdevice wait indefinitely on dev->refcnt */ #include @@ -258,7 +259,7 @@ *******************************************************************************/ /* Boot time configuration table */ -struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; +static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; /** * netdev_boot_setup_add - add new setup entry @@ -2311,7 +2312,7 @@ int unregister_netdevice(struct net_device *dev) { - unsigned long now; + unsigned long now, warning_time; struct net_device *d, **dp; /* If device is running, close it first. */ @@ -2379,31 +2380,30 @@ printk("unregister_netdevice: waiting %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)); #endif - /* EXPLANATION. If dev->refcnt is not 1 now (1 is our own reference) - it means that someone in the kernel still has reference + /* EXPLANATION. If dev->refcnt is not now 1 (our own reference) + it means that someone in the kernel still has a reference to this device and we cannot release it. "New style" devices have destructors, hence we can return from this - function and destructor will do all the work later. + function and destructor will do all the work later. As of kernel 2.4.0 + there are very few "New Style" devices. - "Old style" devices expect that device is free of any references - upon exit from this function. WE CANNOT MAKE such release - without delay. Note that it is not new feature. Referencing devices - after they are released occured in 2.0 and 2.2. - Now we just can know about each fact of illegal usage. - - So, we linger for 10*HZ (it is an arbitrary number) + "Old style" devices expect that the device is free of any references + upon exit from this function. + We cannot return from this function until all such references have + fallen away. This is because the caller of this function will probably + immediately kfree(*dev) and then be unloaded via sys_delete_module. + + So, we linger until all references fall away. The duration of the + linger is basically unbounded! It is driven by, for example, the + current setting of sysctl_ipfrag_time. After 1 second, we start to rebroadcast unregister notifications in hope that careless clients will release the device. - If timeout expired, we have no choice how to cross fingers - and return. Real alternative would be block here forever - and we will make it eventually, when all peaceful citizens - will be notified and repaired. */ - now = jiffies; + now = warning_time = jiffies; while (atomic_read(&dev->refcnt) != 1) { if ((jiffies - now) > 1*HZ) { /* Rebroadcast unregister notification */ @@ -2412,12 +2412,13 @@ current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/4); current->state = TASK_RUNNING; - if ((jiffies - now) > 10*HZ) - break; + if ((jiffies - warning_time) > 10*HZ) { + printk(KERN_EMERG "unregister_netdevice: waiting for %s to " + "become free. Usage count = %d\n", + dev->name, atomic_read(&dev->refcnt)); + warning_time = jiffies; + } } - - if (atomic_read(&dev->refcnt) != 1) - printk("unregister_netdevice: Old style device %s leaked(refcnt=%d). Wait for crash.\n", dev->name, atomic_read(&dev->refcnt)-1); dev_put(dev); return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/net/core/neighbour.c linux/net/core/neighbour.c --- v2.4.0-test6/linux/net/core/neighbour.c Wed Aug 9 19:19:51 2000 +++ linux/net/core/neighbour.c Thu Aug 10 13:01:26 2000 @@ -832,7 +832,8 @@ if (lladdr != neigh->ha) { memcpy(&neigh->ha, lladdr, dev->addr_len); neigh_update_hhs(neigh); - neigh->confirmed = jiffies - (neigh->parms->base_reachable_time<<1); + if (!(new&NUD_CONNECTED)) + neigh->confirmed = jiffies - (neigh->parms->base_reachable_time<<1); #ifdef CONFIG_ARPD notify = 1; #endif diff -u --recursive --new-file v2.4.0-test6/linux/net/core/sock.c linux/net/core/sock.c --- v2.4.0-test6/linux/net/core/sock.c Wed Aug 9 19:19:51 2000 +++ linux/net/core/sock.c Fri Aug 18 10:26:25 2000 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.96 2000/07/26 01:04:14 davem Exp $ + * Version: $Id: sock.c,v 1.98 2000/08/16 16:09:15 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -231,6 +231,7 @@ if (val > sysctl_wmem_max) val = sysctl_wmem_max; + sk->userlocks |= SOCK_SNDBUF_LOCK; sk->sndbuf = max(val*2,SOCK_MIN_SNDBUF); /* @@ -249,6 +250,7 @@ if (val > sysctl_rmem_max) val = sysctl_rmem_max; + sk->userlocks |= SOCK_RCVBUF_LOCK; /* FIXME: is this lower bound the right one? */ sk->rcvbuf = max(val*2,SOCK_MIN_RCVBUF); break; @@ -647,11 +649,6 @@ atomic_sub(skb->truesize, &sk->rmem_alloc); } -void sock_cfree(struct sk_buff *skb) -{ - sock_put(skb->sk); -} - /* * Allocate a skb from the socket's send buffer. */ @@ -710,36 +707,6 @@ kfree(mem); atomic_sub(size, &sk->omem_alloc); } - -/* FIXME: this is insane. We are trying suppose to be controlling how - * how much space we have for data bytes, not packet headers. - * This really points out that we need a better system for doing the - * receive buffer. -- erics - * WARNING: This is currently ONLY used in tcp. If you need it else where - * this will probably not be what you want. Possibly these two routines - * should move over to the ipv4 directory. - */ -unsigned long sock_rspace(struct sock *sk) -{ - int amt = 0; - - if (sk != NULL) { - /* This used to have some bizarre complications that - * to attempt to reserve some amount of space. This doesn't - * make sense, since the number returned here does not - * actually reflect allocated space, but rather the amount - * of space we committed to. We gamble that we won't - * run out of memory, and returning a smaller number does - * not change the gamble. If we lose the gamble tcp still - * works, it may just slow down for retransmissions. - */ - amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc); - if (amt < 0) - amt = 0; - } - return amt; -} - /* It is almost wait_for_tcp_memory minus release_sock/lock_sock. I think, these locks should be removed for datagram sockets. diff -u --recursive --new-file v2.4.0-test6/linux/net/ethernet/eth.c linux/net/ethernet/eth.c --- v2.4.0-test6/linux/net/ethernet/eth.c Fri Jun 23 21:55:24 2000 +++ linux/net/ethernet/eth.c Tue Aug 22 08:59:00 2000 @@ -258,43 +258,3 @@ { memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); } - -#if 0 /*ndef CONFIG_IP_ROUTER*/ -/* This one is only slowdown with checksumming in user process context. --ANK */ - -/* - * Copy from an ethernet device memory space to an sk_buff while checksumming if IP - */ - -void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base) -{ - struct ethhdr *eth; - struct iphdr *iph; - int ip_length; - - eth=(struct ethhdr *)src; - if(eth->h_proto!=htons(ETH_P_IP)) - { - memcpy(dest->data,src,length); - return; - } - /* - * We have to watch for padded packets. The csum doesn't include the - * padding, and there is no point in copying the padding anyway. - * We have to use the smaller of length and ip_length because it - * can happen that ip_length > length. - */ - memcpy(dest->data,src,sizeof(struct iphdr)+ETH_HLEN); /* ethernet is always >= 34 */ - length -= sizeof(struct iphdr) + ETH_HLEN; - iph=(struct iphdr*)(src+ETH_HLEN); - ip_length = ntohs(iph->tot_len) - sizeof(struct iphdr); - - /* Also watch out for bogons - min IP size is 8 (rfc-1042) */ - if ((ip_length <= length) && (ip_length > 7)) - length=ip_length; - - dest->csum=csum_partial_copy_nocheck(src+sizeof(struct iphdr)+ETH_HLEN,dest->data+sizeof(struct iphdr)+ETH_HLEN,length,base); - dest->ip_summed=1; -} - -#endif /* !(CONFIG_IP_ROUTER) */ diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.4.0-test6/linux/net/ipv4/Config.in Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/Config.in Tue Aug 22 08:59:00 2000 @@ -25,7 +25,6 @@ # not yet ready.. # bool ' IP: ARP support' CONFIG_IP_PNP_ARP fi -bool ' IP: optimize as router not host' CONFIG_IP_ROUTER tristate ' IP: tunneling' CONFIG_NET_IPIP tristate ' IP: GRE tunnels over IP' CONFIG_NET_IPGRE if [ "$CONFIG_IP_MULTICAST" = "y" ]; then @@ -38,7 +37,6 @@ bool ' IP: PIM-SM version 2 support' CONFIG_IP_PIMSM_V2 fi fi -bool ' IP: aliasing support' CONFIG_IP_ALIAS if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_RTNETLINK" = "y" ]; then bool ' IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- v2.4.0-test6/linux/net/ipv4/Makefile Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/Makefile Thu Aug 10 13:01:26 2000 @@ -11,7 +11,7 @@ IPV4_OBJS := utils.o route.o inetpeer.o proc.o protocol.o \ ip_input.o ip_fragment.o ip_forward.o ip_options.o \ ip_output.o ip_sockglue.o \ - tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\ + tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \ raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o IPV4X_OBJS := diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.4.0-test6/linux/net/ipv4/af_inet.c Wed Apr 26 16:34:09 2000 +++ linux/net/ipv4/af_inet.c Fri Aug 18 10:26:25 2000 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.110 2000/04/25 04:13:34 davem Exp $ + * Version: $Id: af_inet.c,v 1.112 2000/08/16 16:20:56 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -159,6 +159,8 @@ BUG_TRAP(atomic_read(&sk->rmem_alloc) == 0); BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0); + BUG_TRAP(sk->wmem_queued == 0); + BUG_TRAP(sk->forward_alloc == 0); if (sk->protinfo.af_inet.opt) kfree(sk->protinfo.af_inet.opt); @@ -300,9 +302,6 @@ /* * Create an inet socket. - * - * FIXME: Gcc would generate much better code if we set the parameters - * up in in-memory structure order. Gcc68K even more so */ static int inet_create(struct socket *sock, int protocol) @@ -494,6 +493,8 @@ goto out; } + if (sk->rcv_saddr) + sk->userlocks |= SOCK_BINDADDR_LOCK; sk->sport = htons(sk->num); sk->daddr = 0; sk->dport = 0; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.4.0-test6/linux/net/ipv4/devinet.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/devinet.c Tue Aug 22 08:59:00 2000 @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.37 2000/07/26 01:04:15 davem Exp $ + * Version: $Id: devinet.c,v 1.38 2000/08/19 23:22:56 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -470,9 +470,7 @@ struct in_ifaddr **ifap = NULL; struct in_ifaddr *ifa = NULL; struct net_device *dev; -#ifdef CONFIG_IP_ALIAS char *colon; -#endif int ret = 0; /* @@ -483,11 +481,9 @@ return -EFAULT; ifr.ifr_name[IFNAMSIZ-1] = 0; -#ifdef CONFIG_IP_ALIAS colon = strchr(ifr.ifr_name, ':'); if (colon) *colon = 0; -#endif #ifdef CONFIG_KMOD dev_load(ifr.ifr_name); @@ -530,10 +526,8 @@ goto done; } -#ifdef CONFIG_IP_ALIAS if (colon) *colon = ':'; -#endif if ((in_dev=__in_dev_get(dev)) != NULL) { for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) @@ -564,7 +558,6 @@ goto rarok; case SIOCSIFFLAGS: -#ifdef CONFIG_IP_ALIAS if (colon) { if (ifa == NULL) { ret = -EADDRNOTAVAIL; @@ -574,7 +567,6 @@ inet_del_ifa(in_dev, ifap, 1); break; } -#endif ret = dev_change_flags(dev, ifr.ifr_flags); break; @@ -589,12 +581,10 @@ ret = -ENOBUFS; break; } -#ifdef CONFIG_IP_ALIAS if (colon) memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); else -#endif - memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); + memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); } else { ret = 0; if (ifa->ifa_local == sin->sin_addr.s_addr) diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c --- v2.4.0-test6/linux/net/ipv4/fib_semantics.c Fri Jun 23 21:55:24 2000 +++ linux/net/ipv4/fib_semantics.c Tue Aug 22 08:59:00 2000 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: semantics. * - * Version: $Id: fib_semantics.c,v 1.16 2000/06/21 17:14:50 davem Exp $ + * Version: $Id: fib_semantics.c,v 1.17 2000/08/19 23:22:56 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -764,25 +764,20 @@ rtm->rtm_type = RTN_UNICAST; if (r->rt_dev) { -#ifdef CONFIG_IP_ALIAS char *colon; -#endif struct net_device *dev; char devname[IFNAMSIZ]; if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1)) return -EFAULT; devname[IFNAMSIZ-1] = 0; -#ifdef CONFIG_IP_ALIAS colon = strchr(devname, ':'); if (colon) *colon = 0; -#endif dev = __dev_get_by_name(devname); if (!dev) return -ENODEV; rta->rta_oif = &dev->ifindex; -#ifdef CONFIG_IP_ALIAS if (colon) { struct in_ifaddr *ifa; struct in_device *in_dev = __in_dev_get(dev); @@ -796,7 +791,6 @@ return -ENODEV; rta->rta_prefsrc = &ifa->ifa_local; } -#endif } ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v2.4.0-test6/linux/net/ipv4/ip_input.c Wed Apr 26 16:34:09 2000 +++ linux/net/ipv4/ip_input.c Tue Aug 22 08:59:00 2000 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.48 2000/04/15 01:48:10 davem Exp $ + * Version: $Id: ip_input.c,v 1.49 2000/08/21 20:41:55 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -297,7 +297,6 @@ skb = ip_defrag(skb); if (!skb) return 0; - iph = skb->nh.iph; } return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.4.0-test6/linux/net/ipv4/ip_sockglue.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/ip_sockglue.c Thu Aug 10 13:01:26 2000 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.50 2000/07/26 01:04:17 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.51 2000/08/09 11:59:04 davem Exp $ * * Authors: see ip.c * @@ -724,16 +724,14 @@ break; case IP_MULTICAST_IF: { - struct ip_mreqn mreq; - len = min(len,sizeof(struct ip_mreqn)); - mreq.imr_ifindex = sk->protinfo.af_inet.mc_index; - mreq.imr_address.s_addr = sk->protinfo.af_inet.mc_addr; - mreq.imr_multiaddr.s_addr = 0; + struct in_addr addr; + len = min(len,sizeof(struct in_addr)); + addr.s_addr = sk->protinfo.af_inet.mc_addr; release_sock(sk); if(put_user(len, optlen)) return -EFAULT; - if(copy_to_user((void *)optval, &mreq, len)) + if(copy_to_user((void *)optval, &addr, len)) return -EFAULT; return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile --- v2.4.0-test6/linux/net/ipv4/netfilter/Makefile Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/Makefile Thu Aug 10 12:35:15 2000 @@ -19,7 +19,8 @@ # Link order matters here. ifeq ($(CONFIG_IP_NF_CONNTRACK),y) -O_OBJS += ip_conntrack_standalone.o $(IP_NF_CONNTRACK_OBJ) +OX_OBJS += ip_conntrack_standalone.o +O_OBJS += $(IP_NF_CONNTRACK_OBJ) else ifeq ($(CONFIG_IP_NF_CONNTRACK),m) MI_OBJS += $(IP_NF_CONNTRACK_OBJ) diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_conntrack_core.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/ip_conntrack_core.c Thu Aug 10 12:35:15 2000 @@ -660,8 +660,8 @@ } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF)) == htonl(0x000000FF)) { printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n", - IP_PARTS((*pskb)->nh.iph->saddr), - IP_PARTS((*pskb)->nh.iph->daddr), + NIPQUAD((*pskb)->nh.iph->saddr), + NIPQUAD((*pskb)->nh.iph->daddr), (*pskb)->sk, (*pskb)->pkt_type); } #endif @@ -998,7 +998,7 @@ .tuple.dst.ip; DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", - IP_PARTS(sin.sin_addr.s_addr), ntohs(sin.sin_port)); + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); ip_conntrack_put(h->ctrack); if (copy_to_user(user, &sin, sizeof(sin)) != 0) return -EFAULT; @@ -1006,8 +1006,8 @@ return 0; } DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n", - IP_PARTS(tuple.src.ip), ntohs(tuple.src.u.tcp.port), - IP_PARTS(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); return -ENOENT; } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_conntrack_ftp.c linux/net/ipv4/netfilter/ip_conntrack_ftp.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_conntrack_ftp.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/ip_conntrack_ftp.c Thu Aug 10 12:35:15 2000 @@ -21,14 +21,6 @@ #define DEBUGP(format, args...) #endif -#define IP_PARTS_NATIVE(n) \ -(unsigned int)((n)>>24)&0xFF, \ -(unsigned int)((n)>>16)&0xFF, \ -(unsigned int)((n)>>8)&0xFF, \ -(unsigned int)((n)&0xFF) - -#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) - static struct { const char *pattern; size_t plen; @@ -111,7 +103,7 @@ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { - /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; const char *data = (const char *)tcph + tcph->doff * 4; unsigned int tcplen = len - iph->ihl * 4; @@ -142,8 +134,8 @@ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *)tcph, tcplen, 0))) { DEBUGP("ftp_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", - tcph, tcplen, IP_PARTS(iph->saddr), - IP_PARTS(iph->daddr)); + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); return NF_ACCEPT; } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_conntrack_standalone.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c Thu Aug 10 12:35:15 2000 @@ -332,7 +332,6 @@ module_init(init); module_exit(fini); -#ifdef MODULE EXPORT_SYMBOL(ip_conntrack_protocol_register); EXPORT_SYMBOL(invert_tuplepr); EXPORT_SYMBOL(ip_conntrack_alter_reply); @@ -346,4 +345,3 @@ EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_tuple_taken); EXPORT_SYMBOL(ip_ct_gather_frags); -#endif diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_nat_core.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/ip_nat_core.c Thu Aug 10 12:35:15 2000 @@ -206,7 +206,7 @@ /* FIXME: IPTOS_TOS(iph->tos) --RR */ if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) { DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n", - IP_PARTS(var_ip)); + NIPQUAD(var_ip)); return 0; } @@ -312,7 +312,7 @@ && *var_ipp != orig_dstip && !do_extra_mangle(*var_ipp, other_ipp)) { DEBUGP("Range %u %u.%u.%u.%u rt failed!\n", - i, IP_PARTS(*var_ipp)); + i, NIPQUAD(*var_ipp)); /* Can't route? This whole range part is * probably screwed, but keep trying * anyway. */ @@ -513,8 +513,8 @@ ? " PROTO_SPECIFIED" : "", (mr->range[i].flags & IP_NAT_RANGE_FULL) ? " FULL" : "", - IP_PARTS(mr->range[i].min_ip), - IP_PARTS(mr->range[i].max_ip), + NIPQUAD(mr->range[i].min_ip), + NIPQUAD(mr->range[i].max_ip), mr->range[i].min.all, mr->range[i].max.all); } @@ -715,7 +715,7 @@ *pskb, info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", - IP_PARTS(info->manips[i].manip.ip), + NIPQUAD(info->manips[i].manip.ip), htons(info->manips[i].manip.u.all)); manip_pkt((*pskb)->nh.iph->protocol, (*pskb)->nh.iph, @@ -797,7 +797,7 @@ DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n", info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "DST" : "SRC", - IP_PARTS(info->manips[i].manip.ip), + NIPQUAD(info->manips[i].manip.ip), ntohs(info->manips[i].manip.u.udp.port)); manip_pkt(inner->protocol, inner, skb->len - ((void *)inner - (void *)iph), @@ -812,7 +812,7 @@ DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n", info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", - IP_PARTS(info->manips[i].manip.ip)); + NIPQUAD(info->manips[i].manip.ip)); manip_pkt(0, iph, skb->len, &info->manips[i].manip, info->manips[i].maniptype, diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_nat_ftp.c linux/net/ipv4/netfilter/ip_nat_ftp.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_nat_ftp.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/ip_nat_ftp.c Thu Aug 10 12:35:15 2000 @@ -54,13 +54,13 @@ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; DEBUGP("nat_expected: PORT cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", - IP_PARTS(newsrcip), IP_PARTS(newdstip)); + NIPQUAD(newsrcip), NIPQUAD(newdstip)); } else { /* PASV command: make the connection go to the server */ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", - IP_PARTS(newsrcip), IP_PARTS(newdstip)); + NIPQUAD(newsrcip), NIPQUAD(newdstip)); } UNLOCK_BH(&ip_ftp_lock); @@ -69,7 +69,7 @@ else newip = newdstip; - DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", IP_PARTS(newip)); + DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); mr.rangesize = 1; /* We don't want to manip the per-protocol, just the IPs... */ @@ -110,7 +110,7 @@ MUST_BE_LOCKED(&ip_ftp_lock); sprintf(buffer, "%u,%u,%u,%u,%u,%u", - IP_PARTS(newip), port>>8, port&0xFF); + NIPQUAD(newip), port>>8, port&0xFF); tcplen = (*pskb)->len - iph->ihl * 4; newtcplen = tcplen - matchlen + strlen(buffer); diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_nat_rule.c Fri May 12 14:18:56 2000 +++ linux/net/ipv4/netfilter/ip_nat_rule.c Thu Aug 10 12:35:15 2000 @@ -226,7 +226,7 @@ = { 1, { { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } } } }; DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack, - IP_PARTS(ip)); + NIPQUAD(ip)); return ip_nat_setup_info(conntrack, &mr, hooknum); } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ip_queue.c Wed Aug 9 19:19:51 2000 +++ linux/net/ipv4/netfilter/ip_queue.c Thu Aug 10 12:35:15 2000 @@ -4,10 +4,11 @@ * * (C) 2000 James Morris, this code is GPL. * - * 2000-03-27: Simplified code (thanks to Andi Kleen for clues). (JM) - * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report). (JM) + * 2000-03-27: Simplified code (thanks to Andi Kleen for clues). + * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report). * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian - * Zander). (JM) + * Zander). + * 2000-08-01: Added Nick Williams' MAC support. * */ #include @@ -398,6 +399,14 @@ else pm->indev_name[0] = '\0'; if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name); else pm->outdev_name[0] = '\0'; + pm->hw_protocol = e->skb->protocol; + if (e->skb->rx_dev) { + pm->hw_type = e->skb->rx_dev->type; + if (e->skb->rx_dev->hard_header_parse) + pm->hw_addrlen = + e->skb->rx_dev->hard_header_parse(e->skb, + pm->hw_addr); + } if (data_len) memcpy(pm->payload, e->skb->data, data_len); nlh->nlmsg_len = skb->tail - old_tail; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ipt_LOG.c Thu May 11 15:30:08 2000 +++ linux/net/ipv4/netfilter/ipt_LOG.c Thu Aug 10 12:35:15 2000 @@ -288,14 +288,15 @@ if (in && !out) { /* MAC logging for input chain only. */ printk("MAC="); - if ((*pskb)->dev && (*pskb)->dev->hard_header_len) { + if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != iph) { int i; unsigned char *p = (*pskb)->mac.raw; for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++) printk("%02x%c", *p, i==(*pskb)->dev->hard_header_len - 1 ? ' ':':'); - } + } else + printk(" "); } dump_packet(loginfo, iph, (*pskb)->len, 1); diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ipt_MASQUERADE.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c Thu Aug 10 12:35:15 2000 @@ -92,7 +92,7 @@ } newsrc = rt->rt_src; - DEBUGP("newsrc = %u.%u.%u.%u\n", IP_PARTS(newsrc)); + DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc)); ip_rt_put(rt); WRITE_LOCK(&masq_lock); diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ipt_REJECT.c linux/net/ipv4/netfilter/ipt_REJECT.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ipt_REJECT.c Thu Jul 27 17:38:02 2000 +++ linux/net/ipv4/netfilter/ipt_REJECT.c Thu Aug 10 12:35:15 2000 @@ -247,11 +247,6 @@ DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n"); return 0; } - /* Only for local input. Rest is too dangerous. */ - if ((hook_mask & ~(1 << NF_IP_LOCAL_IN)) != 0) { - DEBUGP("REJECT: TCP_RESET only from INPUT\n"); - return 0; - } } return 1; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ipt_limit.c linux/net/ipv4/netfilter/ipt_limit.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ipt_limit.c Thu May 11 15:30:08 2000 +++ linux/net/ipv4/netfilter/ipt_limit.c Thu Aug 10 12:35:15 2000 @@ -15,14 +15,6 @@ #include #include -#define IP_PARTS_NATIVE(n) \ -(unsigned int)((n)>>24)&0xFF, \ -(unsigned int)((n)>>16)&0xFF, \ -(unsigned int)((n)>>8)&0xFF, \ -(unsigned int)((n)&0xFF) - -#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) - /* The algorithm used is the Simple Token Bucket Filter (TBF) * see net/sched/sch_tbf.c in the linux source tree */ diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/netfilter/ipt_owner.c linux/net/ipv4/netfilter/ipt_owner.c --- v2.4.0-test6/linux/net/ipv4/netfilter/ipt_owner.c Fri May 12 14:18:56 2000 +++ linux/net/ipv4/netfilter/ipt_owner.c Sun Aug 13 12:53:19 2000 @@ -15,18 +15,29 @@ match_pid(const struct sk_buff *skb, pid_t pid) { struct task_struct *p; + struct files_struct *files; int i; read_lock(&tasklist_lock); p = find_task_by_pid(pid); - if(p && p->files) { - for (i=0; i < p->files->max_fds; i++) { - if (fcheck_files(p->files, i) == skb->sk->socket->file) { + if (!p) + goto out; + task_lock(p); + files = p->files; + if(files) { + read_lock(&files->file_lock); + for (i=0; i < files->max_fds; i++) { + if (fcheck_files(files, i) == skb->sk->socket->file) { + read_unlock(&files->file_lock); + task_unlock(p); read_unlock(&tasklist_lock); return 1; } - } + } + read_unlock(&files->file_lock); } + task_unlock(p); +out: read_unlock(&tasklist_lock); return 0; } @@ -35,19 +46,28 @@ match_sid(const struct sk_buff *skb, pid_t sid) { struct task_struct *p; + struct file *file = skb->sk->socket->file; int i, found=0; read_lock(&tasklist_lock); for_each_task(p) { - if ((p->session != sid) || !p->files) + struct files_struct *files; + if (p->session != sid) continue; - for (i=0; i < p->files->max_fds; i++) { - if (fcheck_files(p->files, i) == skb->sk->socket->file) { - found = 1; - break; + task_lock(p); + files = p->files; + if (files) { + read_lock(&files->file_lock); + for (i=0; i < files->max_fds; i++) { + if (fcheck_files(files, i) == file) { + found = 1; + break; + } } + read_unlock(&files->file_lock); } + task_unlock(p); if(found) break; } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/proc.c linux/net/ipv4/proc.c --- v2.4.0-test6/linux/net/ipv4/proc.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/proc.c Thu Aug 10 13:01:26 2000 @@ -7,7 +7,7 @@ * PROC file system. It is mainly used for debugging and * statistics. * - * Version: $Id: proc.c,v 1.43 2000/07/07 22:29:42 davem Exp $ + * Version: $Id: proc.c,v 1.44 2000/08/09 11:59:04 davem Exp $ * * Authors: Fred N. van Kempen, * Gerald J. Heim, @@ -71,9 +71,11 @@ int len = socket_get_info(buffer,start,offset,length); - len += sprintf(buffer+len,"TCP: inuse %d orphan %d tw %d\n", + len += sprintf(buffer+len,"TCP: inuse %d orphan %d tw %d alloc %d mem %d\n", fold_prot_inuse(&tcp_prot), - atomic_read(&tcp_orphan_count), tcp_tw_count); + atomic_read(&tcp_orphan_count), tcp_tw_count, + atomic_read(&tcp_sockets_allocated), + atomic_read(&tcp_memory_allocated)); len += sprintf(buffer+len,"UDP: inuse %d\n", fold_prot_inuse(&udp_prot)); len += sprintf(buffer+len,"RAW: inuse %d\n", @@ -175,7 +177,22 @@ " ListenOverflows ListenDrops" " TCPPrequeued TCPDirectCopyFromBacklog" " TCPDirectCopyFromPrequeue TCPPrequeueDropped" - " TCPHPHits TCPHPHitsToUser\n" + " TCPHPHits TCPHPHitsToUser" + " TCPPureAcks TCPHPAcks" + " TCPRenoRecovery TCPSackRecovery" + " TCPSACKReneging" + " TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder" + " TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo" + " TCPLoss TCPLostRetransmit" + " TCPRenoFailures TCPSackFailures TCPLossFailures" + " TCPFastRetrans TCPForwardRetrans TCPSlowStartRetrans" + " TCPTimeouts" + " TCPRenoRecoveryFail TCPSackRecoveryFail" + " TCPSchedulerFailed TCPRcvCollapsed" + " TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv" + " TCPAbortOnSyn TCPAbortOnData TCPAbortOnClose" + " TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger" + " TCPAbortFailed TCPMemoryPressures\n" "TcpExt:"); for (i=0; i * Fred N. van Kempen, @@ -628,8 +628,8 @@ i, src, srcp, dest, destp, sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, 0, - sp->socket ? sp->socket->inode->i_ino : 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), atomic_read(&sp->refcnt), sp); } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.4.0-test6/linux/net/ipv4/route.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/route.c Thu Aug 10 13:01:26 2000 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.88 2000/07/07 23:47:45 davem Exp $ + * Version: $Id: route.c,v 1.89 2000/08/09 11:59:04 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1127,8 +1127,6 @@ memcpy(&rt->u.dst.mxlock, fi->fib_metrics, sizeof(fi->fib_metrics)); if (fi->fib_mtu == 0) { rt->u.dst.pmtu = rt->u.dst.dev->mtu; - if (rt->u.dst.pmtu > IP_MAX_MTU) - rt->u.dst.pmtu = IP_MAX_MTU; if (rt->u.dst.mxlock&(1<rt_gateway != rt->rt_dst && rt->u.dst.pmtu > 576) @@ -1139,9 +1137,9 @@ #endif } else { rt->u.dst.pmtu = rt->u.dst.dev->mtu; - if (rt->u.dst.pmtu > IP_MAX_MTU) - rt->u.dst.pmtu = IP_MAX_MTU; } + if (rt->u.dst.pmtu > IP_MAX_MTU) + rt->u.dst.pmtu = IP_MAX_MTU; if (rt->u.dst.advmss == 0) rt->u.dst.advmss = max(rt->u.dst.dev->mtu-40, ip_rt_min_advmss); if (rt->u.dst.advmss > 65535-40) diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.4.0-test6/linux/net/ipv4/sysctl_net_ipv4.c Fri Jan 28 15:09:09 2000 +++ linux/net/ipv4/sysctl_net_ipv4.c Thu Aug 10 13:01:26 2000 @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.43 2000/01/16 05:11:27 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.44 2000/08/09 11:59:04 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -209,6 +209,24 @@ &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_TCP_ORPHAN_RETRIES, "tcp_orphan_retries", &sysctl_tcp_orphan_retries, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_FACK, "tcp_fack", + &sysctl_tcp_fack, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_REORDERING, "tcp_reordering", + &sysctl_tcp_reordering, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_ECN, "tcp_ecn", + &sysctl_tcp_ecn, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_DSACK, "tcp_dsack", + &sysctl_tcp_dsack, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_MEM, "tcp_mem", + &sysctl_tcp_mem, sizeof(sysctl_tcp_mem), 0644, NULL, &proc_dointvec}, + {NET_TCP_WMEM, "tcp_wmem", + &sysctl_tcp_wmem, sizeof(sysctl_tcp_wmem), 0644, NULL, &proc_dointvec}, + {NET_TCP_RMEM, "tcp_rmem", + &sysctl_tcp_rmem, sizeof(sysctl_tcp_rmem), 0644, NULL, &proc_dointvec}, + {NET_TCP_APP_WIN, "tcp_app_win", + &sysctl_tcp_app_win, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_ADV_WIN_SCALE, "tcp_adv_win_scale", + &sysctl_tcp_adv_win_scale, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.4.0-test6/linux/net/ipv4/tcp.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/tcp.c Fri Aug 18 10:26:25 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.170 2000/07/08 00:20:43 davem Exp $ + * Version: $Id: tcp.c,v 1.173 2000/08/15 20:15:23 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -201,7 +201,7 @@ * tcp_do_sendmsg to avoid burstiness. * Eric Schenk : Fix fast close down bug with * shutdown() followed by close(). - * Andi Kleen : Make poll agree with SIGIO + * Andi Kleen : Make poll agree with SIGIO * Salvatore Sanfilippo : Support SO_LINGER with linger == 1 and * lingertime == 0 (RFC 793 ABORT Call) * @@ -436,6 +436,96 @@ atomic_t tcp_orphan_count = ATOMIC_INIT(0); +int sysctl_tcp_mem[3] = { 0, }; +int sysctl_tcp_wmem[3] = { 4*1024, 16*1024, 128*1024 }; +int sysctl_tcp_rmem[3] = { 4*1024, 87380, 87380*2 }; + +atomic_t tcp_memory_allocated; /* Current allocated memory. */ +atomic_t tcp_sockets_allocated; /* Current number of TCP sockets. */ + +/* Pressure flag: try to collapse. + * Technical note: it is used by multiple contexts non atomically. + * All the tcp_mem_schedule() is of this nature: accounting + * is strict, actions are advisory and have some latency. */ +int tcp_memory_pressure; + +#define TCP_PAGES(amt) (((amt)+TCP_MEM_QUANTUM-1)/TCP_MEM_QUANTUM) + +int tcp_mem_schedule(struct sock *sk, int size, int kind) +{ + int amt = TCP_PAGES(size); + + sk->forward_alloc += amt*TCP_MEM_QUANTUM; + atomic_add(amt, &tcp_memory_allocated); + + /* Under limit. */ + if (atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) { + if (tcp_memory_pressure) + tcp_memory_pressure = 0; + return 1; + } + + /* Over hard limit. */ + if (atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]) { + tcp_enter_memory_pressure(); + goto suppress_allocation; + } + + /* Under pressure. */ + if (atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[1]) + tcp_enter_memory_pressure(); + + if (kind) { + if (atomic_read(&sk->rmem_alloc) < sysctl_tcp_rmem[0]) + return 1; + } else { + if (sk->wmem_queued < sysctl_tcp_wmem[0]) + return 1; + } + + if (!tcp_memory_pressure || + sysctl_tcp_mem[2] > atomic_read(&tcp_sockets_allocated) + * TCP_PAGES(sk->wmem_queued+atomic_read(&sk->rmem_alloc)+ + sk->forward_alloc)) + return 1; + +suppress_allocation: + + if (kind == 0) { + tcp_moderate_sndbuf(sk); + + /* Fail only if socket is _under_ its sndbuf. + * In this case we cannot block, so that we have to fail. + */ + if (sk->wmem_queued+size >= sk->sndbuf) + return 1; + } + + /* Alas. Undo changes. */ + sk->forward_alloc -= amt*TCP_MEM_QUANTUM; + atomic_sub(amt, &tcp_memory_allocated); + return 0; +} + +void __tcp_mem_reclaim(struct sock *sk) +{ + if (sk->forward_alloc >= TCP_MEM_QUANTUM) { + atomic_sub(sk->forward_alloc/TCP_MEM_QUANTUM, &tcp_memory_allocated); + sk->forward_alloc &= (TCP_MEM_QUANTUM-1); + if (tcp_memory_pressure && + atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) + tcp_memory_pressure = 0; + } +} + +void tcp_rfree(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + + atomic_sub(skb->truesize, &sk->rmem_alloc); + sk->forward_alloc += skb->truesize; +} + /* * LISTEN is a special case for poll.. */ @@ -504,6 +594,9 @@ /* Connected? */ if ((1 << sk->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) { + /* Potential race condition. If read of tp below will + * escape above sk->state, we can be illegally awaken + * in SYN_* states. */ if ((tp->rcv_nxt != tp->copied_seq) && (tp->urg_seq != tp->copied_seq || tp->rcv_nxt != tp->copied_seq+1 || @@ -511,7 +604,7 @@ mask |= POLLIN | POLLRDNORM; if (!(sk->shutdown & SEND_SHUTDOWN)) { - if (sock_wspace(sk) >= tcp_min_write_space(sk)) { + if (tcp_wspace(sk) >= tcp_min_write_space(sk)) { mask |= POLLOUT | POLLWRNORM; } else { /* send SIGIO later */ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); @@ -521,7 +614,7 @@ * wspace test but before the flags are set, * IO signal will be lost. */ - if (sock_wspace(sk) >= tcp_min_write_space(sk)) + if (tcp_wspace(sk) >= tcp_min_write_space(sk)) mask |= POLLOUT | POLLWRNORM; } } @@ -533,39 +626,10 @@ } /* - * Socket write_space callback. - * This (or rather the sock_wake_async) should agree with poll. - * - * WARNING. This callback is called, when socket is not locked. - * - * This wakeup is used by TCP only as dead-lock breaker, real - * wakeup occurs when incoming ack frees some space in buffer. + * TCP socket write_space callback. Not used. */ void tcp_write_space(struct sock *sk) { - struct socket *sock; - - read_lock(&sk->callback_lock); - if ((sock = sk->socket) != NULL && atomic_read(&sk->wmem_alloc) == 0) { - if (test_bit(SOCK_NOSPACE, &sock->flags)) { - if (sk->sleep && waitqueue_active(sk->sleep)) { - clear_bit(SOCK_NOSPACE, &sock->flags); - wake_up_interruptible(sk->sleep); - } - } - - if (sock->fasync_list) - sock_wake_async(sock, 2, POLL_OUT); - } - read_unlock(&sk->callback_lock); -} - -/* Listening TCP sockets never sleep to wait for memory, so - * it is completely silly to wake them up on queue space - * available events. So we hook them up to this dummy callback. - */ -static void tcp_listen_write_space(struct sock *sk) -{ } int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) @@ -647,7 +711,6 @@ if (sk->prot->get_port(sk, sk->num) == 0) { sk->sport = htons(sk->num); - sk->write_space = tcp_listen_write_space; sk_dst_reset(sk); sk->prot->hash(sk); @@ -774,7 +837,7 @@ static inline int tcp_memory_free(struct sock *sk) { - return atomic_read(&sk->wmem_alloc) < sk->sndbuf; + return sk->wmem_queued < sk->sndbuf; } /* @@ -782,33 +845,44 @@ */ static long wait_for_tcp_memory(struct sock * sk, long timeo) { - if (!tcp_memory_free(sk)) { - DECLARE_WAITQUEUE(wait, current); + long vm_wait = 0; + long current_timeo = timeo; + DECLARE_WAITQUEUE(wait, current); - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + if (tcp_memory_free(sk)) + current_timeo = vm_wait = (net_random()%(HZ/5))+2; - add_wait_queue(sk->sleep, &wait); - for (;;) { - set_bit(SOCK_NOSPACE, &sk->socket->flags); + clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(sk->sleep, &wait); + for (;;) { + set_bit(SOCK_NOSPACE, &sk->socket->flags); - if (signal_pending(current)) - break; - if (tcp_memory_free(sk)) - break; - if (sk->shutdown & SEND_SHUTDOWN) - break; - if (sk->err) - break; - release_sock(sk); - if (!tcp_memory_free(sk)) - timeo = schedule_timeout(timeo); - lock_sock(sk); + set_current_state(TASK_INTERRUPTIBLE); + + if (signal_pending(current)) + break; + if (tcp_memory_free(sk) && !vm_wait) + break; + if (sk->shutdown & SEND_SHUTDOWN) + break; + if (sk->err) + break; + release_sock(sk); + if (!tcp_memory_free(sk) || vm_wait) + current_timeo = schedule_timeout(current_timeo); + lock_sock(sk); + if (vm_wait) { + if (timeo != MAX_SCHEDULE_TIMEOUT && + (timeo -= vm_wait-current_timeo) < 0) + timeo = 0; + break; + } else { + timeo = current_timeo; } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); return timeo; } @@ -925,43 +999,35 @@ from += copy; copied += copy; seglen -= copy; - if (PSH_NEEDED) + if (PSH_NEEDED || + after(tp->write_seq, tp->pushed_seq+(tp->max_window>>1))) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; + tp->pushed_seq = tp->write_seq; + } continue; } } - /* A chunk was here doing something strange - * with psh etc. It is deleted, because it was - * evident non-sense. --ANK - */ - copy = min(seglen, mss_now); /* Determine how large of a buffer to allocate. */ - tmp = MAX_TCP_HEADER + 15; + tmp = MAX_TCP_HEADER + 15 + tp->mss_cache; if (copy < mss_now && !(flags & MSG_OOB)) { - tmp += mss_now; - /* What is happening here is that we want to * tack on later members of the users iovec * if possible into a single frame. When we - * leave this loop our caller checks to see if + * leave this loop our we check to see if * we can send queued frames onto the wire. - * See tcp_v[46]_sendmsg() for this. */ queue_it = 1; } else { - tmp += copy; queue_it = 0; } - if (tcp_memory_free(sk)) { - skb = alloc_skb(tmp, GFP_KERNEL); - if (skb == NULL) - goto do_oom; - skb_set_owner_w(skb, sk); - } else { + skb = NULL; + if (tcp_memory_free(sk)) + skb = tcp_alloc_skb(sk, tmp, GFP_KERNEL); + if (skb == NULL) { /* If we didn't get any memory, we need to sleep. */ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); set_bit(SOCK_NOSPACE, &sk->socket->flags); @@ -987,11 +1053,18 @@ seglen -= copy; /* Prepare control bits for TCP header creation engine. */ - TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | - ((PSH_NEEDED) ? - TCPCB_FLAG_PSH : 0)); + TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; + if (PSH_NEEDED || + after(tp->write_seq+copy, tp->pushed_seq+(tp->max_window>>1))) { + TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK|TCPCB_FLAG_PSH; + tp->pushed_seq = tp->write_seq + copy; + } else { + TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; + } TCP_SKB_CB(skb)->sacked = 0; if (flags & MSG_OOB) { + /* Funny. 8) This makes URG fully meaningless. + * Well, OK. It does not contradict to anything yet. */ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_URG; TCP_SKB_CB(skb)->urg_ptr = copy; } else @@ -1041,15 +1114,12 @@ err = -EPIPE; } goto out; -do_oom: - err = copied ? : -ENOBUFS; - goto out; do_interrupted: if(copied) err = copied; goto out; do_fault: - kfree_skb(skb); + __kfree_skb(skb); do_fault2: err = -EFAULT; goto out; @@ -1072,7 +1142,7 @@ if (sk->urginline || !tp->urg_data || tp->urg_data == TCP_URG_READ) return -EINVAL; /* Yes this is right ! */ - if (sk->done) + if (sk->state==TCP_CLOSE && !sk->done) return -ENOTCONN; if (tp->urg_data & TCP_URG_VALID) { @@ -1095,7 +1165,6 @@ return err ? -EFAULT : len; } - /* Do not set sk->done, it is set only by normal data receive */ if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) return 0; @@ -1117,8 +1186,6 @@ static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb) { __skb_unlink(skb, &sk->receive_queue); - BUG_TRAP(atomic_read(&skb->users) == 1); - /* Well, if I missed something then punishment will be terrible oops. */ __kfree_skb(skb); } @@ -1143,34 +1210,19 @@ tcp_eat_skb(sk, skb); } - if (tp->ack.pending) { + if (tcp_ack_scheduled(tp)) { /* Delayed ACKs frequently hit locked sockets during bulk receive. */ if (tp->ack.blocked -#ifdef TCP_MORE_COARSE_ACKS /* Once-per-two-segments ACK was not sent by tcp_input.c */ || tp->rcv_nxt - tp->rcv_wup > tp->ack.rcv_mss -#endif /* - * If this read emptied read buffer, we send ACK when: - * - * -- ATO estimator diverged. In this case it is useless - * to delay ACK, it will miss in any case. - * - * -- The second condition is triggered when we did not - * ACK 8 segments not depending of their size. - * Linux senders allocate full-sized frame even for one byte - * packets, so that default queue for MTU=8K can hold - * only 8 packets. Note, that no other workarounds - * but counting packets are possible. If sender selected - * a small sndbuf or have larger mtu lockup will still - * occur. Well, not lockup, but 10-20msec gap. - * It is essentially dead lockup for 1Gib ethernet - * and loopback :-). The value 8 covers all reasonable - * cases and we may receive packet of any size - * with maximal possible rate now. + * If this read emptied read buffer, we send ACK, if + * connection is not bidirectional, user drained + * receive buffer and there was a small segment + * in queue. */ || (copied > 0 && - (tp->ack.ato >= TCP_DELACK_MAX || tp->ack.rcv_segs > 7) && + (tp->ack.pending&TCP_ACK_PUSHED) && !tp->ack.pingpong && atomic_read(&sk->rmem_alloc) == 0)) { time_to_ack = 1; @@ -1185,15 +1237,19 @@ */ if(copied > 0 && !time_to_ack && !(sk->shutdown&RCV_SHUTDOWN)) { __u32 rcv_window_now = tcp_receive_window(tp); - __u32 new_window = __tcp_select_window(sk); - /* Send ACK now, if this read freed lots of space - * in our buffer. Certainly, new_window is new window. - * We can advertise it now, if it is not less than current one. - * "Lots" means "at least twice" here. - */ - if(new_window && new_window >= 2*rcv_window_now) - time_to_ack = 1; + /* Optimize, __tcp_select_window() is not cheap. */ + if (2*rcv_window_now <= tp->window_clamp) { + __u32 new_window = __tcp_select_window(sk); + + /* Send ACK now, if this read freed lots of space + * in our buffer. Certainly, new_window is new window. + * We can advertise it now, if it is not less than current one. + * "Lots" means "at least twice" here. + */ + if(new_window && new_window >= 2*rcv_window_now) + time_to_ack = 1; + } } if (time_to_ack) tcp_send_ack(sk); @@ -1345,23 +1401,25 @@ !timeo) break; } else { + if (sk->done) + break; + if (sk->err) { copied = sock_error(sk); break; } - if (sk->shutdown & RCV_SHUTDOWN) { - if (!(flags&MSG_PEEK)) - sk->done = 1; + if (sk->shutdown & RCV_SHUTDOWN) break; - } if (sk->state == TCP_CLOSE) { - if (sk->done) { + if (!sk->done) { + /* This occurs when user tries to read + * from never connected socket. + */ copied = -ENOTCONN; break; - } else if (!(flags&MSG_PEEK)) - sk->done = 1; + } break; } @@ -1629,14 +1687,20 @@ static __inline__ void tcp_kill_sk_queues(struct sock *sk) { /* First the read buffer. */ - skb_queue_purge(&sk->receive_queue); + __skb_queue_purge(&sk->receive_queue); /* Next, the error queue. */ - skb_queue_purge(&sk->error_queue); + __skb_queue_purge(&sk->error_queue); /* Next, the write queue. */ BUG_TRAP(skb_queue_empty(&sk->write_queue)); + /* Account for returned memory. */ + tcp_mem_reclaim(sk); + + BUG_TRAP(sk->wmem_queued == 0); + BUG_TRAP(sk->forward_alloc == 0); + /* It is _impossible_ for the backlog to contain anything * when we get here. All user references to this socket * have gone away, only the net layer knows can touch it. @@ -1706,9 +1770,11 @@ while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) { u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin; data_was_unread += len; - kfree_skb(skb); + __kfree_skb(skb); } + tcp_mem_reclaim(sk); + /* As outlined in draft-ietf-tcpimpl-prob-03.txt, section * 3.10, we send a RST here because data was lost. To * witness the awful effects of the old behavior of always @@ -1720,11 +1786,13 @@ */ if(data_was_unread != 0) { /* Unread data was tossed, zap the connection. */ + NET_INC_STATS_USER(TCPAbortOnClose); tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_KERNEL); } else if (sk->linger && sk->lingertime==0) { /* Check zero linger _after_ checking for unread data. */ sk->prot->disconnect(sk, 0); + NET_INC_STATS_USER(TCPAbortOnData); } else if (tcp_close_state(sk)) { /* We FIN if the application ate all the data before * zapping the connection. @@ -1807,6 +1875,7 @@ if (tp->linger2 < 0) { tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_ATOMIC); + NET_INC_STATS_BH(TCPAbortOnLinger); } else { int tmo = tcp_fin_time(tp); @@ -1819,12 +1888,17 @@ } } } - if (sk->state != TCP_CLOSE && - atomic_read(&tcp_orphan_count) > sysctl_tcp_max_orphans) { - if (net_ratelimit()) - printk(KERN_INFO "TCP: too many of orphaned sockets\n"); - tcp_set_state(sk, TCP_CLOSE); - tcp_send_active_reset(sk, GFP_ATOMIC); + if (sk->state != TCP_CLOSE) { + tcp_mem_reclaim(sk); + if (atomic_read(&tcp_orphan_count) > sysctl_tcp_max_orphans || + (sk->wmem_queued > SOCK_MIN_SNDBUF && + atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])) { + if (net_ratelimit()) + printk(KERN_INFO "TCP: too many of orphaned sockets\n"); + tcp_set_state(sk, TCP_CLOSE); + tcp_send_active_reset(sk, GFP_ATOMIC); + NET_INC_STATS_BH(TCPAbortOnMemory); + } } atomic_inc(&tcp_orphan_count); @@ -1873,7 +1947,7 @@ tcp_clear_xmit_timers(sk); __skb_queue_purge(&sk->receive_queue); - __skb_queue_purge(&sk->write_queue); + tcp_writequeue_purge(sk); __skb_queue_purge(&tp->out_of_order_queue); sk->dport = 0; @@ -1887,25 +1961,21 @@ sk->shutdown = 0; sk->done = 0; - sk->write_space = tcp_write_space; tp->srtt = 0; - if (sysctl_tcp_tw_recycle) { - if ((tp->write_seq += 2) == 0) - tp->write_seq = 1; - } else { - tp->write_seq = 0; - } + if ((tp->write_seq += tp->max_window+2) == 0) + tp->write_seq = 1; tp->backoff = 0; tp->snd_cwnd = 2; tp->probes_out = 0; tp->packets_out = 0; - tp->high_seq = 0; tp->snd_ssthresh = 0x7fffffff; tp->snd_cwnd_cnt = 0; - tp->dup_acks = 0; + tp->ca_state = TCP_CA_Open; + tcp_clear_retrans(tp); tcp_delack_init(tp); - tp->send_head = tp->retrans_head = NULL; + tp->send_head = NULL; tp->saw_tstamp = 0; + tcp_sack_reset(tp); __sk_dst_reset(sk); BUG_TRAP(!sk->num || sk->prev); @@ -1916,8 +1986,7 @@ /* * Wait for an incoming connection, avoid race - * conditions. This must be called with the socket locked, - * and without the kernel lock held. + * conditions. This must be called with the socket locked. */ static int wait_for_connect(struct sock * sk, long timeo) { @@ -1965,8 +2034,6 @@ /* * This will accept the next outstanding connection. - * - * Be careful about race conditions here - this is subtle. */ struct sock *tcp_accept(struct sock *sk, int flags, int *err) @@ -2095,7 +2162,7 @@ err = -EINVAL; else { tp->keepalive_time = val * HZ; - if (sk->keepopen) { + if (sk->keepopen && !((1<state)&(TCPF_CLOSE|TCPF_LISTEN))) { __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp; if (tp->keepalive_time > elapsed) elapsed = tp->keepalive_time - elapsed; @@ -2152,7 +2219,7 @@ tp->window_clamp = 0; } else { tp->window_clamp = val 512) + sysctl_tcp_mem[1] = sysctl_tcp_mem[2] - 512; + if (sysctl_tcp_mem[1] - sysctl_tcp_mem[0] > 512) + sysctl_tcp_mem[0] = sysctl_tcp_mem[1] - 512; + + if (order < 3) { + sysctl_tcp_wmem[2] = 64*1024; + sysctl_tcp_rmem[0] = PAGE_SIZE; + sysctl_tcp_rmem[1] = 43689; + sysctl_tcp_rmem[2] = 2*43689; + } printk("TCP: Hash tables configured (established %d bind %d)\n", tcp_ehash_size<<1, tcp_bhash_size); diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.4.0-test6/linux/net/ipv4/tcp_input.c Wed Apr 26 16:34:09 2000 +++ linux/net/ipv4/tcp_input.c Fri Aug 18 10:26:25 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.193 2000/04/20 14:41:16 davem Exp $ + * Version: $Id: tcp_input.c,v 1.198 2000/08/15 20:15:23 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -55,20 +55,15 @@ * work without delayed acks. * Andi Kleen: Process packets with PSH set in the * fast path. + * J Hadi Salim: ECN support */ -#include #include #include #include #include #include -#ifdef CONFIG_SYSCTL -#define SYNC_INIT 0 /* let the user enable it */ -#else -#define SYNC_INIT 1 -#endif /* These are on by default so the code paths get tested. * For the final 2.2 this may be undone at our discretion. -DaveM @@ -76,33 +71,39 @@ int sysctl_tcp_timestamps = 1; int sysctl_tcp_window_scaling = 1; int sysctl_tcp_sack = 1; +int sysctl_tcp_fack = 1; +int sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH; +int sysctl_tcp_ecn = 1; +int sysctl_tcp_dsack = 1; +int sysctl_tcp_app_win = 31; +int sysctl_tcp_adv_win_scale = 2; -int sysctl_tcp_syncookies = SYNC_INIT; -int sysctl_tcp_stdurg; -int sysctl_tcp_rfc1337; -int sysctl_tcp_tw_recycle = 1; -int sysctl_tcp_abort_on_overflow = 0; +int sysctl_tcp_stdurg = 0; +int sysctl_tcp_rfc1337 = 0; int sysctl_tcp_max_orphans = NR_FILE; -int sysctl_tcp_max_tw_buckets = NR_FILE*2; -static int prune_queue(struct sock *sk); +#define FLAG_DATA 0x01 /* Incoming frame contained data. */ +#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ +#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ +#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ +#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ +#define FLAG_DATA_SACKED 0x20 /* New SACK. */ +#define FLAG_ECE 0x40 /* ECE in this ACK */ +#define FLAG_DATA_LOST 0x80 /* SACK detected data lossage. */ +#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ + +#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) +#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) +#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE) +#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) + +#define IsReno(tp) ((tp)->sack_ok == 0) +#define IsFack(tp) ((tp)->sack_ok & 2) + +#define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) -/* - * Adapt the MSS value used to make delayed ack decision to the +/* Adapt the MSS value used to make delayed ack decision to the * real world. - * - * The constant 536 hasn't any good meaning. In IPv4 world - * MTU may be smaller, though it contradicts to RFC1122, which - * states that MSS must be at least 536. - * We use the constant to do not ACK each second - * packet in a stream of tiny size packets. - * It means that super-low mtu links will be aggressively delacked. - * Seems, it is even good. If they have so low mtu, they are weirdly - * slow. - * - * AK: BTW it may be useful to add an option to lock the rcv_mss. - * this way the beowulf people wouldn't need ugly patches to get the - * ack frequencies they want and it would be an elegant way to tune delack. */ static __inline__ void tcp_measure_rcv_mss(struct tcp_opt *tp, struct sk_buff *skb) { @@ -117,6 +118,9 @@ len = skb->len; if (len >= tp->ack.rcv_mss) { tp->ack.rcv_mss = len; + /* Dubious? Rather, it is final cut. 8) */ + if (tcp_flag_word(skb->h.th)&TCP_REMNANT) + tp->ack.pending |= TCP_ACK_PUSHED; } else { /* Otherwise, we make more careful check taking into account, * that SACKs block is variable. @@ -124,37 +128,47 @@ * "len" is invariant segment length, including TCP header. */ len = skb->tail - skb->h.raw; - if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr)) { + if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) || + /* If PSH is not set, packet should be + * full sized, provided peer TCP is not badly broken. + * This observation (if it is correct 8)) allows + * to handle super-low mtu links fairly. + */ + (len >= TCP_MIN_MSS + sizeof(struct tcphdr) && + !(tcp_flag_word(skb->h.th)&TCP_REMNANT))) { /* Subtract also invariant (if peer is RFC compliant), * tcp header plus fixed timestamp option length. * Resulting "len" is MSS free of SACK jitter. */ len -= tp->tcp_header_len; - if (len == lss) - tp->ack.rcv_mss = len; tp->ack.last_seg_size = len; + if (len == lss) { + tp->ack.rcv_mss = len; + return; + } } + tp->ack.pending |= TCP_ACK_PUSHED; } } - -static __inline__ void tcp_enter_quickack_mode(struct tcp_opt *tp) +static void tcp_incr_quickack(struct tcp_opt *tp) { - unsigned quickacks = tcp_receive_window(tp)/(2*tp->ack.rcv_mss); + unsigned quickacks = tp->rcv_wnd/(2*tp->ack.rcv_mss); - tp->ack.quick = max(min(quickacks, 127), 1); + if (quickacks==0) + quickacks=2; + if (quickacks > tp->ack.quick) + tp->ack.quick = min(quickacks, TCP_MAX_QUICKACKS); +} - if (!tp->tstamp_ok && tp->ack.quick>2) { - /* Quick ACKs are _dangerous_, if RTTM is not used. - * See comment in tcp_init_metrics(). We still help - * them to overcome the most difficult, initial - * phase of slow start. - */ - tp->ack.quick = 2; - } +void tcp_enter_quickack_mode(struct tcp_opt *tp) +{ + tcp_incr_quickack(tp); + tp->ack.pingpong = 0; + tp->ack.ato = TCP_ATO_MIN; } -/* Send ACKs quickly, if "quick" count is not ehausted +/* Send ACKs quickly, if "quick" count is not exhausted * and the session is not interactive. */ @@ -163,6 +177,173 @@ return (tp->ack.quick && !tp->ack.pingpong); } +/* Buffer size and advertised window tuning. + * + * 1. Tuning sk->sndbuf, when connection enters established state. + */ + +static void tcp_fixup_sndbuf(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int sndmem = tp->mss_clamp+MAX_TCP_HEADER+16+sizeof(struct sk_buff); + + if (sk->sndbuf < 3*sndmem) + sk->sndbuf = min(3*sndmem, sysctl_tcp_wmem[2]); +} + +/* 2. Tuning advertised window (window_clamp, rcv_ssthresh) + * + * All tcp_full_space() is split to two parts: "network" buffer, allocated + * forward and advertised in receiver window (tp->rcv_wnd) and + * "application buffer", required to isolate scheduling/application + * latencies from network. + * window_clamp is maximal advertised window. It can be less than + * tcp_full_space(), in this case tcp_full_space() - window_clamp + * is reserved for "application" buffer. The less window_clamp is + * the smoother our behaviour from viewpoint of network, but the lower + * throughput and the higher sensitivity of the connection to losses. 8) + * + * rcv_ssthresh is more strict window_clamp used at "slow start" + * phase to predict further behaviour of this connection. + * It is used for two goals: + * - to enforce header prediction at sender, even when application + * requires some significant "application buffer". It is check #1. + * - to prevent pruning of receive queue because of misprediction + * of receiver window. Check #2. + * + * The scheme does not work when sender sends good segments opening + * window and then starts to feed us spagetti. But it should work + * in common situations. Otherwise, we have to rely on queue collapsing. + */ + +/* Slow part of check#2. */ +static int +__tcp_grow_window(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) +{ + /* Optimize this! */ + int truesize = tcp_win_from_space(skb->truesize)/2; + int window = tcp_full_space(sk)/2; + + while (tp->rcv_ssthresh <= window) { + if (truesize <= skb->len) + return 2*tp->ack.rcv_mss; + + truesize >>= 1; + window >>= 1; + } + return 0; +} + +static __inline__ void +tcp_grow_window(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) +{ + /* Check #1 */ + if (tp->rcv_ssthresh < tp->window_clamp && + (int)tp->rcv_ssthresh < tcp_space(sk) && + !tcp_memory_pressure) { + int incr; + + /* Check #2. Increase window, if skb with such overhead + * will fit to rcvbuf in future. + */ + if (tcp_win_from_space(skb->truesize) <= skb->len) + incr = 2*tp->advmss; + else + incr = __tcp_grow_window(sk, tp, skb); + + if (incr) { + tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, tp->window_clamp); + tp->ack.quick |= 1; + } + } +} + +/* 3. Tuning rcvbuf, when connection enters established state. */ + +static void tcp_fixup_rcvbuf(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int rcvmem = tp->advmss+MAX_TCP_HEADER+16+sizeof(struct sk_buff); + + /* Try to select rcvbuf so that 4 mss-sized segments + * will fit to window and correspoding skbs will fit to our rcvbuf. + * (was 3; 4 is minimum to allow fast retransmit to work.) + */ + while (tcp_win_from_space(rcvmem) < tp->advmss) + rcvmem += 128; + if (sk->rcvbuf < 4*rcvmem) + sk->rcvbuf = min(4*rcvmem, sysctl_tcp_rmem[2]); +} + +/* 4. Try to fixup all. It is made iimediately after connection enters + * established state. + */ +static void tcp_init_buffer_space(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int maxwin; + + if (!(sk->userlocks&SOCK_RCVBUF_LOCK)) + tcp_fixup_rcvbuf(sk); + if (!(sk->userlocks&SOCK_SNDBUF_LOCK)) + tcp_fixup_sndbuf(sk); + + maxwin = tcp_full_space(sk); + + if (tp->window_clamp >= maxwin) { + tp->window_clamp = maxwin; + + if (sysctl_tcp_app_win && maxwin>4*tp->advmss) + tp->window_clamp = max(maxwin-(maxwin>>sysctl_tcp_app_win), 4*tp->advmss); + } + + /* Force reservation of one segment. */ + if (sysctl_tcp_app_win && + tp->window_clamp > 2*tp->advmss && + tp->window_clamp + tp->advmss > maxwin) + tp->window_clamp = max(2*tp->advmss, maxwin-tp->advmss); + + tp->rcv_ssthresh = min(tp->rcv_ssthresh, tp->window_clamp); + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +/* 5. Recalculate window clamp after socket hit its memory bounds. */ +static void tcp_clamp_window(struct sock *sk, struct tcp_opt *tp) +{ + struct sk_buff *skb; + int app_win = tp->rcv_nxt - tp->copied_seq; + int ofo_win = 0; + + tp->ack.quick = 0; + + skb_queue_walk(&tp->out_of_order_queue, skb) { + ofo_win += skb->len; + } + + /* If overcommit is due to out of order segments, + * do not clamp window. Try to expand rcvbuf instead. + */ + if (ofo_win) { + if (sk->rcvbuf < sysctl_tcp_rmem[2] && + !(sk->userlocks&SOCK_RCVBUF_LOCK) && + !tcp_memory_pressure && + atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) + sk->rcvbuf = min(atomic_read(&sk->rmem_alloc), sysctl_tcp_rmem[2]); + } + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) { + app_win += ofo_win; + if (atomic_read(&sk->rmem_alloc) >= 2*sk->rcvbuf) + app_win >>= 1; + if (app_win > tp->ack.rcv_mss) + app_win -= tp->ack.rcv_mss; + app_win = max(app_win, 2*tp->advmss); + + if (!ofo_win) + tp->window_clamp = min(tp->window_clamp, app_win); + tp->rcv_ssthresh = min(tp->window_clamp, 2*tp->advmss); + } +} + /* There is something which you must keep in mind when you analyze the * behavior of the tp->ato delayed ack timeout interval. When a * connection starts up, we want to ack as quickly as possible. The @@ -173,14 +354,13 @@ * each ACK we send, he increments snd_cwnd and transmits more of his * queue. -DaveM */ -static void tcp_event_data_recv(struct tcp_opt *tp, struct sk_buff *skb) +static void tcp_event_data_recv(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) { u32 now; - tcp_measure_rcv_mss(tp, skb); + tcp_schedule_ack(tp); - tp->ack.pending = 1; - tp->ack.rcv_segs++; + tcp_measure_rcv_mss(tp, skb); now = tcp_time_stamp; @@ -188,37 +368,31 @@ /* The _first_ data packet received, initialize * delayed ACK engine. */ - - /* Help sender leave slow start quickly. */ tcp_enter_quickack_mode(tp); - - /* Pingpong is off, session is not interactive by default */ - tp->ack.pingpong = 0; - - /* ATO is minimal */ - tp->ack.ato = TCP_ATO_MIN; } else { int m = now - tp->ack.lrcvtime; - if (m > TCP_ATO_MAX/2) { - /* Do not touch ATO, if interval is out of bounds. - * It will be deflated by delack timer, if our peer - * really sends too rarely. + if (m <= TCP_ATO_MIN/2) { + /* The fastest case is the first. */ + tp->ack.ato = (tp->ack.ato>>1) + TCP_ATO_MIN/2; + } else if (m < tp->ack.ato) { + tp->ack.ato = (tp->ack.ato>>1) + m; + if (tp->ack.ato > tp->rto) + tp->ack.ato = tp->rto; + } else if (m > tp->rto) { + /* Too long gap. Apparently sender falled to + * restart window, so that we send ACKs quickly. */ - if (m > tp->rto) { - /* Too long gap. Apparently sender falled to - * restart window, so that we send ACKs quickly. - */ - tcp_enter_quickack_mode(tp); - } - } else { - if (m <= 0) - m = TCP_ATO_MIN/2; - if (m <= tp->ack.ato) - tp->ack.ato = (tp->ack.ato >> 1) + m; + tcp_incr_quickack(tp); + tcp_mem_reclaim(sk); } } tp->ack.lrcvtime = now; + + TCP_ECN_check_ce(tp, skb); + + if (skb->len >= 128) + tcp_grow_window(sk, tp, skb); } /* Called to compute a smoothed rtt estimate. The data fed to this @@ -230,7 +404,6 @@ * To save cycles in the RFC 1323 implementation it was better to break * it up into three procedures. -- erics */ - static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt) { long m = mrtt; /* RTT */ @@ -243,6 +416,13 @@ * * On a 1990 paper the rto value is changed to: * RTO = rtt + 4 * mdev + * + * Funny. This algorithm seems to be very broken. + * These formulae increase RTO, when it should be decreased, increase + * too slowly, when it should be incresed fastly, decrease too fastly + * etc. I guess in BSD RTO takes ONE value, so that it is absolutely + * does not matter how to _calculate_ it. Seems, it was trap + * that VJ failed to avoid. 8) */ if(m == 0) m = 1; @@ -263,16 +443,27 @@ /* Calculate rto without backoff. This is the second half of Van Jacobson's * routine referred to above. */ - static __inline__ void tcp_set_rto(struct tcp_opt *tp) { tp->rto = (tp->srtt >> 3) + tp->mdev; /* I am not enough educated to understand this magic. * However, it smells bad. snd_cwnd>31 is common case. */ + /* OK, I found comment in 2.0 source tree, it deserves + * to be reproduced: + * ==== + * Note: Jacobson's algorithm is fine on BSD which has a 1/2 second + * granularity clock, but with our 1/100 second granularity clock we + * become too sensitive to minor changes in the round trip time. + * We add in two compensating factors. First we multiply by 5/4. + * For large congestion windows this allows us to tolerate burst + * traffic delaying up to 1/4 of our packets. We also add in + * a rtt / cong_window term. For small congestion windows this allows + * a single packet delay, but has negligible effect + * on the compensation for large windows. + */ tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1)); } - /* Keep the rto between HZ/5 and 120*HZ. 120*HZ is the upper bound * on packet lifetime in the internet. We need the HZ/5 lower @@ -292,11 +483,12 @@ tp->rto = TCP_RTO_MAX; } + /* Save metrics learned by this TCP session. This function is called only, when TCP finishes sucessfully i.e. when it enters TIME-WAIT or goes from LAST-ACK to CLOSE. */ -static void tcp_update_metrics(struct sock *sk) +void tcp_update_metrics(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct dst_entry *dst = __sk_dst_get(sk); @@ -344,19 +536,20 @@ dst->rttvar -= (dst->rttvar - m)>>2; } - if (tp->snd_ssthresh == 0x7FFFFFFF) { + if (tp->snd_ssthresh >= 0xFFFF) { /* Slow start still did not finish. */ if (dst->ssthresh && !(dst->mxlock&(1<snd_cwnd > dst->ssthresh) - dst->ssthresh = tp->snd_cwnd; + (tp->snd_cwnd>>1) > dst->ssthresh) + dst->ssthresh = (tp->snd_cwnd>>1); if (!(dst->mxlock&(1<snd_cwnd > dst->cwnd) dst->cwnd = tp->snd_cwnd; - } else if (tp->snd_cwnd >= tp->snd_ssthresh && !tp->high_seq) { + } else if (tp->snd_cwnd > tp->snd_ssthresh && + tp->ca_state == TCP_CA_Open) { /* Cong. avoidance phase, cwnd is reliable. */ if (!(dst->mxlock&(1<ssthresh = tp->snd_cwnd; + dst->ssthresh = max(tp->snd_cwnd>>1, tp->snd_ssthresh); if (!(dst->mxlock&(1<cwnd = (dst->cwnd + tp->snd_cwnd)>>1; } else { @@ -370,9 +563,37 @@ tp->snd_ssthresh > dst->ssthresh) dst->ssthresh = tp->snd_ssthresh; } + + if (!(dst->mxlock&(1<reordering < tp->reordering && + tp->reordering != sysctl_tcp_reordering) + dst->reordering = tp->reordering; + } } } +/* Increase initial CWND conservatively: if estimated + * RTT is low enough (<20msec) or if we have some preset ssthresh. + * + * Numbers are taken from RFC1414. + */ +__u32 tcp_init_cwnd(struct tcp_opt *tp) +{ + __u32 cwnd; + + if (tp->mss_cache > 1460) + return 2; + + cwnd = (tp->mss_cache > 1095) ? 3 : 4; + + if (!tp->srtt || (tp->snd_ssthresh >= 0xFFFF && tp->srtt > ((HZ/50)<<3))) + cwnd = 2; + else if (cwnd > tp->snd_ssthresh) + cwnd = tp->snd_ssthresh; + + return min(cwnd, tp->snd_cwnd_clamp); +} + /* Initialize metrics on socket. */ static void tcp_init_metrics(struct sock *sk) @@ -392,6 +613,10 @@ if (tp->snd_ssthresh > tp->snd_cwnd_clamp) tp->snd_ssthresh = tp->snd_cwnd_clamp; } + if (dst->reordering && tp->reordering != dst->reordering) { + tp->sack_ok &= ~2; + tp->reordering = dst->reordering; + } if (dst->rtt == 0) goto reset; @@ -422,9 +647,9 @@ if (tp->rto < TCP_TIMEOUT_INIT && !tp->saw_tstamp) goto reset; tp->snd_cwnd = tcp_init_cwnd(tp); + tp->snd_cwnd_stamp = tcp_time_stamp; return; - reset: /* Play conservative. If timestamps are not * supported, TCP will fail to recalculate correct @@ -437,402 +662,967 @@ } } -/* WARNING: this must not be called if tp->saw_tstamp was false. */ -extern __inline__ void -tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp, u32 seq) +static void tcp_update_reordering(struct tcp_opt *tp, int metric, int ts) { - if (!after(seq, tp->rcv_wup)) { - /* PAWS bug workaround wrt. ACK frames, the PAWS discard - * extra check below makes sure this can only happen - * for pure ACK frames. -DaveM - * - * Not only, also it occurs for expired timestamps - * and RSTs with bad timestamp option. --ANK - */ + if (metric > tp->reordering) { + tp->reordering = min(TCP_MAX_REORDERING, metric); - if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0 || - xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = xtime.tv_sec; - } + /* This exciting event is worth to be remembered. 8) */ + if (ts) + NET_INC_STATS_BH(TCPTSReorder); + else if (IsReno(tp)) + NET_INC_STATS_BH(TCPRenoReorder); + else if (IsFack(tp)) + NET_INC_STATS_BH(TCPFACKReorder); + else + NET_INC_STATS_BH(TCPSACKReorder); +#if FASTRETRANS_DEBUG > 1 + printk(KERN_DEBUG "Disorder%d %d %u f%u s%u rr%d\n", + tp->sack_ok, tp->ca_state, + tp->reordering, tp->fackets_out, tp->sacked_out, + tp->undo_marker ? tp->undo_retrans : 0); +#endif + /* Disable FACK yet. */ + tp->sack_ok &= ~2; } } -extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct sk_buff *skb) -{ - return ((s32)(tp->rcv_tsval - tp->ts_recent) < 0 && - xtime.tv_sec < tp->ts_recent_stamp + TCP_PAWS_24DAYS +/* This procedure tags the retransmission queue when SACKs arrive. + * + * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L). + * Packets in queue with these bits set are counted in variables + * sacked_out, retrans_out and lost_out, correspondingly. + * + * Valid combinations are: + * Tag InFlight Description + * 0 1 - orig segment is in flight. + * S 0 - nothing flies, orig reached receiver. + * L 0 - nothing flies, orig lost by net. + * R 2 - both orig and retransmit are in flight. + * L|R 1 - orig is lost, retransmit is in flight. + * S|R 1 - orig reached receiver, retrans is still in flight. + * (L|S|R is logically valid, it could occur when L|R is sacked, + * but it is equivalent to plain S and code short-curcuits it to S. + * L|S is logically invalid, it would mean -1 packet in flight 8)) + * + * These 6 states form finite state machine, controlled by the following events: + * 1. New ACK (+SACK) arrives. (tcp_sacktag_write_queue()) + * 2. Retransmission. (tcp_retransmit_skb(), tcp_xmit_retransmit_queue()) + * 3. Loss detection event of one of three flavors: + * A. Scoreboard estimator decided the packet is lost. + * A'. Reno "three dupacks" marks head of queue lost. + * A''. Its FACK modfication, head until snd.fack is lost. + * B. SACK arrives sacking data transmitted after never retransmitted + * hole was sent out. + * C. SACK arrives sacking SND.NXT at the moment, when the + * segment was retransmitted. + * 4. D-SACK added new rule: D-SACK changes any tag to S. + * + * It is pleasant to note, that state diagram turns out to be commutative, + * so that we are allowed not to be bothered by order of our actions, + * when multiple events arrive simultaneously. (see the function below). + * + * Reordering detection. + * -------------------- + * Reordering metric is maximal distance, which a packet can be displaced + * in packet stream. With SACKs we can estimate it: + * + * 1. SACK fills old hole and the corresponding segment was not + * ever retransmitted -> reordering. Alas, we cannot use it + * when segment was retransmitted. + * 2. The last flaw is solved with D-SACK. D-SACK arrives + * for retransmitted and already SACKed segment -> reordering.. + * Both of these heuristics are not used in Loss state, when we cannot + * account for retransmits accurately. + */ +static int +tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked; + struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2); + int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; + int reord = tp->packets_out; + int prior_fackets; + u32 lost_retrans = 0; + int flag = 0; + int i; - /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM + if (!tp->sacked_out) + tp->fackets_out = 0; + prior_fackets = tp->fackets_out; + + for (i=0; istart_seq); + __u32 end_seq = ntohl(sp->end_seq); + int fack_count = 0; + int dup_sack = 0; - I cannot see quitely as all the idea behind PAWS - is destroyed 8) + /* Check for D-SACK. */ + if (i == 0) { + u32 ack = TCP_SKB_CB(ack_skb)->ack_seq; + + if (before(start_seq, ack)) { + dup_sack = 1; + NET_INC_STATS_BH(TCPDSACKRecv); + } else if (num_sacks > 1 && + !after(end_seq, ntohl(sp[1].end_seq)) && + !before(start_seq, ntohl(sp[1].start_seq))) { + dup_sack = 1; + NET_INC_STATS_BH(TCPDSACKOfoRecv); + } + + /* D-SACK for already forgotten data... + * Do dumb counting. */ + if (dup_sack && + !after(end_seq, prior_snd_una) && + after(end_seq, tp->undo_marker)) + tp->undo_retrans--; + + /* Eliminate too old ACKs, but take into + * account more or less fresh ones, they can + * contain valid SACK info. + */ + if (before(ack, prior_snd_una-tp->max_window)) + return 0; + } - The problem is only in reordering duplicate ACKs. - Hence, we can check this rare case more carefully. - - 1. Check that it is really duplicate ACK (ack==snd_una) - 2. Give it some small "replay" window (~RTO) - - We do not know units of foreign ts values, but make conservative - assumption that they are >=1ms. It solves problem - noted in Dave's mail to tcpimpl and does not harm PAWS. --ANK - */ - && (TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq || - TCP_SKB_CB(skb)->ack_seq != tp->snd_una || - !skb->h.th->ack || - (s32)(tp->ts_recent - tp->rcv_tsval) > (tp->rto*1024)/HZ)); -} + /* Event "B" in the comment above. */ + if (after(end_seq, tp->high_seq)) + flag |= FLAG_DATA_LOST; + + for_retrans_queue(skb, sk, tp) { + u8 sacked = TCP_SKB_CB(skb)->sacked; + int in_sack; + /* The retransmission queue is always in order, so + * we can short-circuit the walk early. + */ + if(!before(TCP_SKB_CB(skb)->seq, end_seq)) + break; -static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) -{ - u32 end_window = tp->rcv_wup + tp->rcv_wnd; -#ifdef TCP_FORMAL_WINDOW - u32 rcv_wnd = tcp_receive_window(tp); -#else - u32 rcv_wnd = tp->rcv_wnd; -#endif + fack_count++; - if (rcv_wnd && - after(end_seq, tp->rcv_nxt) && - before(seq, end_window)) - return 1; - if (seq != end_window) - return 0; - return (seq == end_seq); -} + in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && + !before(end_seq, TCP_SKB_CB(skb)->end_seq); -/* This functions checks to see if the tcp header is actually acceptable. */ -extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) -{ -#ifdef TCP_FORMAL_WINDOW - u32 rcv_wnd = tcp_receive_window(tp); -#else - u32 rcv_wnd = tp->rcv_wnd; -#endif - if (seq == tp->rcv_nxt) - return (rcv_wnd || (end_seq == seq)); + /* Account D-SACK for retransmitted packet. */ + if ((dup_sack && in_sack) && + (sacked & TCPCB_RETRANS) && + after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker)) + tp->undo_retrans--; + + /* The frame is ACKed. */ + if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) { + if (sacked&TCPCB_RETRANS) { + if ((dup_sack && in_sack) && + (sacked&TCPCB_SACKED_ACKED)) + reord = min(fack_count, reord); + } else { + /* If it was in a hole, we detected reordering. */ + if (fack_count < prior_fackets && + !(sacked&TCPCB_SACKED_ACKED)) + reord = min(fack_count, reord); + } - return __tcp_sequence(tp, seq, end_seq); -} + /* Nothing to do; acked frame is about to be dropped. */ + continue; + } -/* When we get a reset we do this. */ -static void tcp_reset(struct sock *sk) -{ - /* We want the right error as BSD sees it (and indeed as we do). */ - switch (sk->state) { - case TCP_SYN_SENT: - sk->err = ECONNREFUSED; - break; - case TCP_CLOSE_WAIT: - sk->err = EPIPE; - break; - case TCP_CLOSE: - return; - default: - sk->err = ECONNRESET; - } + if ((sacked&TCPCB_SACKED_RETRANS) && + after(end_seq, TCP_SKB_CB(skb)->ack_seq) && + (!lost_retrans || after(end_seq, lost_retrans))) + lost_retrans = end_seq; - if (!sk->dead) - sk->error_report(sk); + if (!in_sack) + continue; - tcp_done(sk); -} + if (!(sacked&TCPCB_SACKED_ACKED)) { + if (sacked & TCPCB_SACKED_RETRANS) { + /* If the segment is not tagged as lost, + * we do not clear RETRANS, believing + * that retransmission is still in flight. + */ + if (sacked & TCPCB_LOST) { + TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); + tp->lost_out--; + tp->retrans_out--; + } + } else { + /* New sack for not retransmitted frame, + * which was in hole. It is reordering. + */ + if (!(sacked & TCPCB_RETRANS) && + fack_count < prior_fackets) + reord = min(fack_count, reord); + + if (sacked & TCPCB_LOST) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; + tp->lost_out--; + } + } -/* This tags the retransmission queue when SACKs arrive. */ -static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp, int nsacks) -{ - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int i = nsacks; + TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED; + flag |= FLAG_DATA_SACKED; + tp->sacked_out++; - while(i--) { - struct sk_buff *skb = skb_peek(&sk->write_queue); - __u32 start_seq = ntohl(sp->start_seq); - __u32 end_seq = ntohl(sp->end_seq); - int fack_count = 0; + if (fack_count > tp->fackets_out) + tp->fackets_out = fack_count; + } else { + if (dup_sack && (sacked&TCPCB_RETRANS)) + reord = min(fack_count, reord); + } - while((skb != NULL) && - (skb != tp->send_head) && - (skb != (struct sk_buff *)&sk->write_queue)) { - /* The retransmission queue is always in order, so - * we can short-circuit the walk early. + /* D-SACK. We can detect redundant retransmission + * in S|R and plain R frames and clear it. + * undo_retrans is decreased above, L|R frames + * are accounted above as well. */ - if(after(TCP_SKB_CB(skb)->seq, end_seq)) - break; + if (dup_sack && + (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS)) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; + tp->retrans_out--; + } + } + } - /* We play conservative, we don't allow SACKS to partially - * tag a sequence space. - */ - fack_count++; - if(!after(start_seq, TCP_SKB_CB(skb)->seq) && - !before(end_seq, TCP_SKB_CB(skb)->end_seq)) { - /* If this was a retransmitted frame, account for it. */ - if((TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) && - tp->retrans_out) - tp->retrans_out--; - TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED; + /* Check for lost retransmit. This superb idea is + * borrowed from "ratehalving". Event "C". + * Later note: FACK people cheated me again 8), + * we have to account for reordering! Ugly, + * but should help. + */ + if (lost_retrans && tp->ca_state == TCP_CA_Recovery) { + struct sk_buff *skb; - /* RULE: All new SACKs will either decrease retrans_out - * or advance fackets_out. - */ - if(fack_count > tp->fackets_out) - tp->fackets_out = fack_count; + for_retrans_queue(skb, sk, tp) { + if (after(TCP_SKB_CB(skb)->seq, lost_retrans)) + break; + if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) + continue; + if ((TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) && + after(lost_retrans, TCP_SKB_CB(skb)->ack_seq) && + (IsFack(tp) || + !before(lost_retrans, TCP_SKB_CB(skb)->ack_seq+tp->reordering*tp->mss_cache))) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; + tp->retrans_out--; + + if (!(TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_SACKED_ACKED))) { + tp->lost_out++; + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + flag |= FLAG_DATA_SACKED; + NET_INC_STATS_BH(TCPLostRetransmit); + } } - skb = skb->next; } - sp++; /* Move on to the next SACK block. */ } + + tp->left_out = tp->sacked_out + tp->lost_out; + + if (reord < tp->fackets_out && tp->ca_state != TCP_CA_Loss) + tcp_update_reordering(tp, (tp->fackets_out+1)-reord, 0); + +#if FASTRETRANS_DEBUG > 0 + BUG_TRAP((int)tp->sacked_out >= 0); + BUG_TRAP((int)tp->lost_out >= 0); + BUG_TRAP((int)tp->retrans_out >= 0); + BUG_TRAP((int)tcp_packets_in_flight(tp) >= 0); +#endif + return flag; } -/* Look for tcp options. Normally only called on SYN and SYNACK packets. - * But, this can also be called on packets in the established flow when - * the fast version below fails. +void tcp_clear_retrans(struct tcp_opt *tp) +{ + tp->left_out = 0; + tp->retrans_out = 0; + + tp->fackets_out = 0; + tp->sacked_out = 0; + tp->lost_out = 0; + + tp->undo_marker = 0; + tp->undo_retrans = 0; +} + +/* Enter Loss state. If "how" is not zero, forget all SACK information + * and reset tags completely, otherwise preserve SACKs. If receiver + * dropped its ofo queue, we will know this due to reneging detection. */ -void tcp_parse_options(struct sock *sk, struct tcphdr *th, struct tcp_opt *tp, int no_fancy) +void tcp_enter_loss(struct sock *sk, int how) { - unsigned char *ptr; - int length=(th->doff*4)-sizeof(struct tcphdr); + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + struct sk_buff *skb; + int cnt = 0; - ptr = (unsigned char *)(th + 1); - tp->saw_tstamp = 0; + /* Reduce ssthresh if it has not yet been made inside this window. */ + if (tp->ca_state <= TCP_CA_Disorder || + tp->snd_una == tp->high_seq || + (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) { + tp->prior_ssthresh = tcp_current_ssthresh(tp); + tp->snd_ssthresh = tcp_recalc_ssthresh(tp); + } + tp->snd_cwnd = 1; + tp->snd_cwnd_cnt = 0; + tp->snd_cwnd_stamp = tcp_time_stamp; + + tcp_clear_retrans(tp); + + /* Push undo marker, if it was plain RTO and nothing + * was retransmitted. */ + if (!how) + tp->undo_marker = tp->snd_una; + + for_retrans_queue(skb, sk, tp) { + cnt++; + if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS) + tp->undo_marker = 0; + TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; + if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + tp->lost_out++; + } else { + tp->sacked_out++; + tp->fackets_out = cnt; + } + } + tp->left_out = tp->sacked_out + tp->lost_out; - while(length>0) { - int opcode=*ptr++; - int opsize; + tp->reordering = min(tp->reordering, sysctl_tcp_reordering); + tp->ca_state = TCP_CA_Loss; + tp->high_seq = tp->snd_nxt; + TCP_ECN_queue_cwr(tp); +} - switch (opcode) { - case TCPOPT_EOL: - return; - case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ - length--; - continue; - default: - opsize=*ptr++; - if (opsize < 2) /* "silly options" */ - return; - if (opsize > length) - break; /* don't parse partial options */ - switch(opcode) { - case TCPOPT_MSS: - if(opsize==TCPOLEN_MSS && th->syn) { - u16 in_mss = ntohs(*(__u16 *)ptr); - if (in_mss) { - if (tp->user_mss && tp->user_mss < in_mss) - in_mss = tp->user_mss; - tp->mss_clamp = in_mss; - } - } - break; - case TCPOPT_WINDOW: - if(opsize==TCPOLEN_WINDOW && th->syn) - if (!no_fancy && sysctl_tcp_window_scaling) { - tp->wscale_ok = 1; - tp->snd_wscale = *(__u8 *)ptr; - if(tp->snd_wscale > 14) { - if(net_ratelimit()) - printk("tcp_parse_options: Illegal window " - "scaling value %d >14 received.", - tp->snd_wscale); - tp->snd_wscale = 14; - } - } - break; - case TCPOPT_TIMESTAMP: - if(opsize==TCPOLEN_TIMESTAMP) { - if (sysctl_tcp_timestamps && !no_fancy) { - tp->tstamp_ok = 1; - tp->saw_tstamp = 1; - tp->rcv_tsval = ntohl(*(__u32 *)ptr); - tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4)); - } - } - break; - case TCPOPT_SACK_PERM: - if(opsize==TCPOLEN_SACK_PERM && th->syn) { - if (sysctl_tcp_sack && !no_fancy) { - tp->sack_ok = 1; - tp->num_sacks = 0; - } - } - break; +static int tcp_check_sack_reneging(struct sock *sk, struct tcp_opt *tp) +{ + struct sk_buff *skb; - case TCPOPT_SACK: - if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) && - sysctl_tcp_sack && (sk != NULL) && !th->syn) { - int sack_bytes = opsize - TCPOLEN_SACK_BASE; + /* If ACK arrived pointing to a remembered SACK, + * it means that our remembered SACKs do not reflect + * real state of receiver i.e. + * receiver _host_ is heavily congested (or buggy). + * Do processing similar to RTO timeout. + */ + if ((skb = skb_peek(&sk->write_queue)) != NULL && + (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { + NET_INC_STATS_BH(TCPSACKReneging); + + tcp_enter_loss(sk, 1); + tp->retransmits++; + tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)); + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + return 1; + } + return 0; +} + +static inline int tcp_fackets_out(struct tcp_opt *tp) +{ + return IsReno(tp) ? tp->sacked_out+1 : tp->fackets_out; +} - if(!(sack_bytes % TCPOLEN_SACK_PERBLOCK)) { - int num_sacks = sack_bytes >> 3; - struct tcp_sack_block *sackp; - sackp = (struct tcp_sack_block *)ptr; - tcp_sacktag_write_queue(sk, sackp, num_sacks); - } - } - }; - ptr+=opsize-2; - length-=opsize; - }; +/* Linux NewReno/SACK/FACK/ECN state machine. + * -------------------------------------- + * + * "Open" Normal state, no dubious events, fast path. + * "Disorder" In all the respects it is "Open", + * but requires a bit more attention. It is entered when + * we see some SACKs or dupacks. It is split of "Open" + * mainly to move some processing from fast path to slow one. + * "CWR" CWND was reduced due to some Congestion Notification event. + * It can be ECN, ICMP source quench, local device congestion. + * "Recovery" CWND was reduced, we are fast-retransmitting. + * "Loss" CWND was reduced due to RTO timeout or SACK reneging. + * + * tcp_fastretrans_alert() is entered: + * - each incoming ACK, if state is not "Open" + * - when arrived ACK is unusual, namely: + * * SACK + * * Duplicate ACK. + * * ECN ECE. + * + * Counting packets in flight is pretty simple. + * + * in_flight = packets_out - left_out + retrans_out + * + * packets_out is SND.NXT-SND.UNA counted in packets. + * + * retrans_out is number of retransmitted segments. + * + * left_out is number of segments left network, but not ACKed yet. + * + * left_out = sacked_out + lost_out + * + * sacked_out: Packets, which arrived to receiver out of order + * and hence not ACKed. With SACKs this number is simply + * amount of SACKed data. Even without SACKs + * it is easy to give pretty reliable estimate of this number, + * counting duplicate ACKs. + * + * lost_out: Packets lost by network. TCP has no explicit + * "loss notification" feedback from network (for now). + * It means that this number can be only _guessed_. + * Actually, it is the heuristics to predict lossage that + * distinguishes different algorithms. + * + * F.e. after RTO, when all the queue is considered as lost, + * lost_out = packets_out and in_flight = retrans_out. + * + * Essentially, we have now two algorithms counting + * lost packets. + * + * FACK: It is the simplest heuristics. As soon as we decided + * that something is lost, we decide that _all_ not SACKed + * packets until the most forward SACK are lost. I.e. + * lost_out = fackets_out - sacked_out and left_out = fackets_out. + * It is absolutely correct estimate, if network does not reorder + * packets. And it loses any connection to reality when reordering + * takes place. We use FACK by default until reordering + * is suspected on the path to this destination. + * + * NewReno: when Recovery is entered, we assume that one segment + * is lost (classic Reno). While we are in Recovery and + * a partial ACK arrives, we assume that one more packet + * is lost (NewReno). This heuristics are the same in NewReno + * and SACK. + * + * Imagine, that's all! Forget about all this shamanism about CWND inflation + * deflation etc. CWND is real congestion window, never inflated, changes + * only according to classic VJ rules. + * + * Really tricky (and requiring careful tuning) part of algorithm + * is hidden in functions tcp_time_to_recover() and tcp_xmit_retransmit_queue(). + * The first determines the moment _when_ we should reduce CWND and, + * hence, slow down forward transmission. In fact, it determines the moment + * when we decide that hole is caused by loss, rather than by a reorder. + * + * tcp_xmit_retransmit_queue() decides, _what_ we should retransmit to fill + * holes, caused by lost packets. + * + * And the most logically complicated part of algorithm is undo + * heuristics. We detect false retransmits due to both too early + * fast retransmit (reordering) and underestimated RTO, analyzing + * timestamps and D-SACKs. When we detect that some segments were + * retransmitted by mistake and CWND reduction was wrong, we undo + * window reduction and abort recovery phase. This logic is hidden + * inside several functions named tcp_try_undo_. + */ + +/* This function decides, when we should leave Disordered state + * and enter Recovery phase, reducing congestion window. + * + * Main question: may we further continue forward transmission + * with the same cwnd? + */ +static int +tcp_time_to_recover(struct sock *sk, struct tcp_opt *tp) +{ + /* Trick#1: The loss is proven. */ + if (tp->lost_out) + return 1; + + /* Not-A-Trick#2 : Classic rule... */ + if (tcp_fackets_out(tp) > tp->reordering) + return 1; + + /* Trick#3: It is still not OK... But will it be useful to delay + * recovery more? + */ + if (tp->packets_out <= tp->reordering && + tp->sacked_out >= max(tp->packets_out/2, sysctl_tcp_reordering) && + !tcp_may_send_now(sk, tp)) { + /* We have nothing to send. This connection is limited + * either by receiver window or by application. + */ + return 1; } + + return 0; } -/* Fast parse options. This hopes to only see timestamps. - * If it is wrong it falls back on tcp_parse_options(). +/* If we receive more dupacks than we expected counting segments + * in assumption of absent reordering, interpret this as reordering. + * The only another reason could be bug in receiver TCP. */ -static __inline__ int tcp_fast_parse_options(struct sock *sk, struct tcphdr *th, struct tcp_opt *tp) +static void tcp_check_reno_reordering(struct tcp_opt *tp, int addend) { - /* If we didn't send out any options ignore them all. */ - if (tp->tcp_header_len == sizeof(struct tcphdr)) - return 0; - if (th->doff == sizeof(struct tcphdr)>>2) { - tp->saw_tstamp = 0; - return 0; - } else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) { - __u32 *ptr = (__u32 *)(th + 1); - if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) - | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { - tp->saw_tstamp = 1; - ++ptr; - tp->rcv_tsval = ntohl(*ptr); - ++ptr; - tp->rcv_tsecr = ntohl(*ptr); - return 1; + if (tp->sacked_out + 1 > tp->packets_out) { + tp->sacked_out = tp->packets_out ? tp->packets_out - 1 : 0; + tcp_update_reordering(tp, tp->packets_out+addend, 0); + } +} + +/* Emulate SACKs for SACKless connection: account for a new dupack. */ + +static void tcp_add_reno_sack(struct tcp_opt *tp) +{ + ++tp->sacked_out; + tcp_check_reno_reordering(tp, 0); + tp->left_out = tp->sacked_out + tp->lost_out; +} + +/* Account for ACK, ACKing some data in Reno Recovery phase. */ + +static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_opt *tp, int acked) +{ + if (acked > 0) { + /* One ACK eated lost packet. Must eat! */ + BUG_TRAP(tp->lost_out == 0); + + /* The rest eat duplicate ACKs. */ + if (acked-1 >= tp->sacked_out) + tp->sacked_out = 0; + else + tp->sacked_out -= acked-1; + } + tcp_check_reno_reordering(tp, acked); + tp->left_out = tp->sacked_out + tp->lost_out; +} + +static inline void tcp_reset_reno_sack(struct tcp_opt *tp) +{ + tp->sacked_out = 0; + tp->left_out = tp->lost_out; +} + +/* Mark head of queue up as lost. */ +static void +tcp_mark_head_lost(struct sock *sk, struct tcp_opt *tp, int packets, u32 high_seq) +{ + struct sk_buff *skb; + int cnt = packets; + + BUG_TRAP(cnt <= tp->packets_out); + + for_retrans_queue(skb, sk, tp) { + if (--cnt < 0 || after(TCP_SKB_CB(skb)->end_seq, high_seq)) + break; + if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + tp->lost_out++; } } - tcp_parse_options(sk, th, tp, 0); - return 1; + tp->left_out = tp->sacked_out + tp->lost_out; } -#define FLAG_DATA 0x01 /* Incoming frame contained data. */ -#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ -#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ -#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ -#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged new data. */ +/* Account newly detected lost packet(s) */ + +static void tcp_update_scoreboard(struct sock *sk, struct tcp_opt *tp) +{ + if (IsFack(tp)) { + int lost = tp->fackets_out - tp->reordering; + if (lost <= 0) + lost = 1; + tcp_mark_head_lost(sk, tp, lost, tp->high_seq); + } else { + tcp_mark_head_lost(sk, tp, 1, tp->high_seq); + } +} + +/* CWND moderation, preventing bursts due to too big ACKs + * in dubious situations. + */ +static __inline__ void tcp_moderate_cwnd(struct tcp_opt *tp) +{ + tp->snd_cwnd = min(tp->snd_cwnd, + tcp_packets_in_flight(tp)+tcp_max_burst(tp)); + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +/* Decrease cwnd each second ack. */ + +static void tcp_cwnd_down(struct tcp_opt *tp) +{ + int decr = tp->snd_cwnd_cnt + 1; + + tp->snd_cwnd_cnt = decr&1; + decr >>= 1; + + if (decr && tp->snd_cwnd > tp->snd_ssthresh/2) + tp->snd_cwnd -= decr; + + tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1); + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +/* Nothing was retransmitted or returned timestamp is less + * than timestamp of the first retransmission. + */ +static __inline__ int tcp_packet_delayed(struct tcp_opt *tp) +{ + return !tp->retrans_stamp || + (tp->saw_tstamp && + (__s32)(tp->rcv_tsecr - tp->retrans_stamp) < 0); +} + +/* Undo procedures. */ + +#if FASTRETRANS_DEBUG > 1 +static void DBGUNDO(struct sock *sk, struct tcp_opt *tp, const char *msg) +{ + printk(KERN_DEBUG "Undo %s %u.%u.%u.%u/%u c%u l%u ss%u/%u p%u\n", + msg, + NIPQUAD(sk->daddr), ntohs(sk->dport), + tp->snd_cwnd, tp->left_out, + tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); +} +#else +#define DBGUNDO(x...) do { } while (0) +#endif + +static void tcp_undo_cwr(struct tcp_opt *tp, int undo) +{ + if (tp->prior_ssthresh) { + tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh<<1); + if (undo && tp->prior_ssthresh > tp->snd_ssthresh) + tp->snd_ssthresh = tp->prior_ssthresh; + } else { + tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh); + } + tcp_moderate_cwnd(tp); + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +static inline int tcp_may_undo(struct tcp_opt *tp) +{ + return tp->undo_marker && + (!tp->undo_retrans || tcp_packet_delayed(tp)); +} + +/* People celebrate: "We love our President!" */ +static int tcp_try_undo_recovery(struct sock *sk, struct tcp_opt *tp) +{ + if (tcp_may_undo(tp)) { + /* Happy end! We did not retransmit anything + * or our original transmission succeeded. + */ + DBGUNDO(sk, tp, tp->ca_state == TCP_CA_Loss ? "loss" : "retrans"); + tcp_undo_cwr(tp, 1); + if (tp->ca_state == TCP_CA_Loss) + NET_INC_STATS_BH(TCPLossUndo); + else + NET_INC_STATS_BH(TCPFullUndo); + tp->undo_marker = 0; + } + if (tp->snd_una == tp->high_seq && IsReno(tp)) { + /* Hold old state until something *above* high_seq + * is ACKed. For Reno it is MUST to prevent false + * fast retransmits (RFC2582). SACK TCP is safe. */ + tcp_moderate_cwnd(tp); + return 1; + } + tp->ca_state = TCP_CA_Open; + return 0; +} + +/* Try to undo cwnd reduction, because D-SACKs acked all retransmitted data */ +static void tcp_try_undo_dsack(struct sock *sk, struct tcp_opt *tp) +{ + if (tp->undo_marker && !tp->undo_retrans) { + DBGUNDO(sk, tp, "D-SACK"); + tcp_undo_cwr(tp, 1); + tp->undo_marker = 0; + NET_INC_STATS_BH(TCPDSACKUndo); + } +} + +/* Undo during fast recovery after partial ACK. */ + +static int tcp_try_undo_partial(struct sock *sk, struct tcp_opt *tp, int acked) +{ + /* Partial ACK arrived. Force Hoe's retransmit. */ + int failed = IsReno(tp) || tp->fackets_out>tp->reordering; + + if (tcp_may_undo(tp)) { + /* Plain luck! Hole if filled with delayed + * packet, rather than with a retransmit. + */ + if (tp->retrans_out == 0) + tp->retrans_stamp = 0; + + tcp_update_reordering(tp, tcp_fackets_out(tp)+acked, 1); + + DBGUNDO(sk, tp, "Hoe"); + tcp_undo_cwr(tp, 0); + NET_INC_STATS_BH(TCPPartialUndo); + + /* So... Do not make Hoe's retransmit yet. + * If the first packet was delayed, the rest + * ones are most probably delayed as well. + */ + failed = 0; + } + return failed; +} + +/* Undo during loss recovery after partial ACK. */ +static int tcp_try_undo_loss(struct sock *sk, struct tcp_opt *tp) +{ + if (tcp_may_undo(tp)) { + struct sk_buff *skb; + for_retrans_queue(skb, sk, tp) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; + } + DBGUNDO(sk, tp, "partial loss"); + tp->lost_out = 0; + tp->left_out = tp->sacked_out; + tcp_undo_cwr(tp, 1); + NET_INC_STATS_BH(TCPLossUndo); + tp->retransmits = 0; + tp->undo_marker = 0; + if (!IsReno(tp)) { + tp->ca_state = TCP_CA_Open; + tp->backoff = 0; + } + return 1; + } + return 0; +} + +static __inline__ void tcp_complete_cwr(struct tcp_opt *tp) +{ + tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh); + tp->snd_cwnd_stamp = tcp_time_stamp; +} -static __inline__ void clear_fast_retransmit(struct tcp_opt *tp) +static void tcp_try_to_open(struct sock *sk, struct tcp_opt *tp, int flag) { - if (tp->dup_acks > 3) - tp->snd_cwnd = (tp->snd_ssthresh); + tp->left_out = tp->sacked_out; - tp->dup_acks = 0; + if (tp->retrans_out == 0) + tp->retrans_stamp = 0; + + if (flag&FLAG_ECE) + tcp_enter_cwr(tp); + + if (tp->ca_state != TCP_CA_CWR) { + int state = TCP_CA_Open; + + if (tp->left_out || + tp->retrans_out || + tp->undo_marker) + state = TCP_CA_Disorder; + + if (tp->ca_state != state) { + tp->ca_state = state; + tp->high_seq = tp->snd_nxt; + } + tcp_moderate_cwnd(tp); + } else { + tcp_cwnd_down(tp); + } +} + +/* Process an event, which can update packets-in-flight not trivially. + * Main goal of this function is to calculate new estimate for left_out, + * taking into account both packets sitting in receiver's buffer and + * packets lost by network. + * + * Besides that it does CWND reduction, when packet loss is detected + * and changes state of machine. + * + * It does _not_ decide what to send, it is made in function + * tcp_xmit_retransmit_queue(). + */ +static void +tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, + int prior_packets, int flag) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int is_dupack = (tp->snd_una == prior_snd_una && !(flag&FLAG_NOT_DUP)); + + /* Some technical things: + * 1. Reno does not count dupacks (sacked_out) automatically. */ + if (!tp->packets_out) + tp->sacked_out = 0; + /* 2. SACK counts snd_fack in packets inaccurately. */ + if (tp->sacked_out == 0) + tp->fackets_out = 0; + + /* Now state machine starts. + * A. ECE, hence prohibit cwnd undoing, the reduction is required. */ + if (flag&FLAG_ECE) + tp->prior_ssthresh = 0; + + /* B. In all the states check for reneging SACKs. */ + if (tp->sacked_out && tcp_check_sack_reneging(sk, tp)) + return; + + /* C. Process data loss notification, provided it is valid. */ + if ((flag&FLAG_DATA_LOST) && + before(tp->snd_una, tp->high_seq) && + tp->ca_state != TCP_CA_Open && + tp->fackets_out > tp->reordering) { + tcp_mark_head_lost(sk, tp, tp->fackets_out-tp->reordering, tp->high_seq); + NET_INC_STATS_BH(TCPLoss); + } + + /* D. Synchronize left_out to current state. */ + tp->left_out = tp->sacked_out + tp->lost_out; + + /* E. Check state exit conditions. State can be terminated + * when high_seq is ACKed. */ + if (tp->ca_state == TCP_CA_Open) { + BUG_TRAP(tp->retrans_out == 0); + tp->retrans_stamp = 0; + } else if (!before(tp->snd_una, tp->high_seq)) { + switch (tp->ca_state) { + case TCP_CA_Loss: + tp->retransmits = 0; + if (tcp_try_undo_recovery(sk, tp)) + return; + tp->backoff = 0; + break; + + case TCP_CA_CWR: + /* CWR is to be held something *above* high_seq + * is ACKed for CWR bit to reach receiver. */ + if (tp->snd_una != tp->high_seq) { + tcp_complete_cwr(tp); + tp->ca_state = TCP_CA_Open; + } + break; + + case TCP_CA_Disorder: + tcp_try_undo_dsack(sk, tp); + if (IsReno(tp) || !tp->undo_marker) { + tp->undo_marker = 0; + tp->ca_state = TCP_CA_Open; + } + break; + + case TCP_CA_Recovery: + if (IsReno(tp)) + tcp_reset_reno_sack(tp); + if (tcp_try_undo_recovery(sk, tp)) + return; + tcp_complete_cwr(tp); + break; + } + } + + /* F. Process state. */ + switch (tp->ca_state) { + case TCP_CA_Recovery: + if (prior_snd_una == tp->snd_una) { + if (IsReno(tp) && is_dupack) + tcp_add_reno_sack(tp); + } else { + int acked = prior_packets - tp->packets_out; + if (IsReno(tp)) + tcp_remove_reno_sacks(sk, tp, acked); + is_dupack = tcp_try_undo_partial(sk, tp, acked); + } + break; + case TCP_CA_Loss: + if (flag & FLAG_ACKED) + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + if (!tcp_try_undo_loss(sk, tp)) { + tcp_moderate_cwnd(tp); + tcp_xmit_retransmit_queue(sk); + return; + } + if (tp->ca_state != TCP_CA_Open) + return; + /* Loss is undone; fall through to processing in Open state. */ + default: + if (IsReno(tp)) { + if (tp->snd_una != prior_snd_una) + tcp_reset_reno_sack(tp); + if (is_dupack) + tcp_add_reno_sack(tp); + } + + if (tp->ca_state == TCP_CA_Disorder) + tcp_try_undo_dsack(sk, tp); + + if (!tcp_time_to_recover(sk, tp)) { + tcp_try_to_open(sk, tp, flag); + return; + } + + /* Otherwise enter Recovery state */ + + if (IsReno(tp)) + NET_INC_STATS_BH(TCPRenoRecovery); + else + NET_INC_STATS_BH(TCPSackRecovery); + + tp->high_seq = tp->snd_nxt; + tp->prior_ssthresh = 0; + tp->undo_marker = tp->snd_una; + tp->undo_retrans = tp->retrans_out; + + if (tp->ca_state < TCP_CA_CWR) { + if (!(flag&FLAG_ECE)) + tp->prior_ssthresh = tcp_current_ssthresh(tp); + tp->snd_ssthresh = tcp_recalc_ssthresh(tp); + TCP_ECN_queue_cwr(tp); + } + + tp->snd_cwnd_cnt = 0; + tp->ca_state = TCP_CA_Recovery; + } + + if (is_dupack) + tcp_update_scoreboard(sk, tp); + tcp_cwnd_down(tp); + tcp_xmit_retransmit_queue(sk); +} + +/* Read draft-ietf-tcplw-high-performance before mucking + * with this code. (Superceeds RFC1323) + */ +static void tcp_ack_saw_tstamp(struct tcp_opt *tp) +{ + __u32 seq_rtt; + + /* RTTM Rule: A TSecr value received in a segment is used to + * update the averaged RTT measurement only if the segment + * acknowledges some new data, i.e., only if it advances the + * left edge of the send window. + * + * See draft-ietf-tcplw-high-performance-00, section 3.3. + * 1998/04/10 Andrey V. Savochkin + */ + seq_rtt = tcp_time_stamp - tp->rcv_tsecr; + tcp_rtt_estimator(tp, seq_rtt); + tcp_set_rto(tp); + tp->rto <<= tp->backoff; + tcp_bound_rto(tp); } -/* NOTE: This code assumes that tp->dup_acks gets cleared when a - * retransmit timer fires. - */ -static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup) +static void tcp_ack_no_tstamp(struct tcp_opt *tp, u32 seq_rtt, int flag) { - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - - /* Note: If not_dup is set this implies we got a - * data carrying packet or a window update. - * This carries no new information about possible - * lost packets, so we have to ignore it for the purposes - * of counting duplicate acks. Ideally this does not imply we - * should stop our fast retransmit phase, more acks may come - * later without data to help us. Unfortunately this would make - * the code below much more complex. For now if I see such - * a packet I clear the fast retransmit phase. + /* We don't have a timestamp. Can only use + * packets that are not retransmitted to determine + * rtt estimates. Also, we must not reset the + * backoff for rto until we get a non-retransmitted + * packet. This allows us to deal with a situation + * where the network delay has increased suddenly. + * I.e. Karn's algorithm. (SIGCOMM '87, p5.) */ - if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) { - /* This is the standard reno style fast retransmit branch. */ - - /* 1. When the third duplicate ack is received, set ssthresh - * to one half the current congestion window, but no less - * than two segments. Retransmit the missing segment. - */ - if (tp->high_seq == 0 || after(ack, tp->high_seq)) { - tp->dup_acks++; - if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) { - __tcp_enter_cong_avoid(tp); - /* ... and account for 3 ACKs, which are - * already received to this time. - */ - tp->snd_cwnd += 3; - - if(!tp->fackets_out) - tcp_retransmit_skb(sk, - skb_peek(&sk->write_queue)); - else - tcp_fack_retransmit(sk); - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); - } - } else if (++tp->dup_acks > 3) { - /* 2. Each time another duplicate ACK arrives, increment - * cwnd by the segment size. [...] Transmit a packet... - * - * Packet transmission will be done on normal flow processing - * since we're not in "retransmit mode". We do not use - * duplicate ACKs to artificially inflate the congestion - * window when doing FACK. - */ - if(!tp->fackets_out) { - tp->snd_cwnd++; - } else { - /* Fill any further holes which may have - * appeared. - * - * We may want to change this to run every - * further multiple-of-3 dup ack increments, - * to be more robust against out-of-order - * packet delivery. -DaveM - */ - tcp_fack_retransmit(sk); - } - } - } else if (tp->high_seq != 0) { - /* In this branch we deal with clearing the Floyd style - * block on duplicate fast retransmits, and if requested - * we do Hoe style secondary fast retransmits. - */ - if (!before(ack, tp->high_seq) || (not_dup & FLAG_DATA) != 0) { - /* Once we have acked all the packets up to high_seq - * we are done this fast retransmit phase. - * Alternatively data arrived. In this case we - * Have to abort the fast retransmit attempt. - * Note that we do want to accept a window - * update since this is expected with Hoe's algorithm. - */ - clear_fast_retransmit(tp); - /* After we have cleared up to high_seq we can - * clear the Floyd style block. - */ - if (!before(ack, tp->high_seq)) { - tp->high_seq = 0; - tp->fackets_out = 0; - } - } else if (tp->dup_acks >= 3) { - if (!tp->fackets_out) { - /* Hoe Style. We didn't ack the whole - * window. Take this as a cue that - * another packet was lost and retransmit it. - * Don't muck with the congestion window here. - * Note that we have to be careful not to - * act if this was a window update and it - * didn't ack new data, since this does - * not indicate a packet left the system. - * We can test this by just checking - * if ack changed from snd_una, since - * the only way to get here without advancing - * from snd_una is if this was a window update. - */ - if (ack != tp->snd_una && before(ack, tp->high_seq)) { - tcp_retransmit_skb(sk, - skb_peek(&sk->write_queue)); - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); - } - } else { - /* FACK style, fill any remaining holes in - * receiver's queue. - */ - tcp_fack_retransmit(sk); - } - } + if (!tp->retransmits && !(flag & FLAG_RETRANS_DATA_ACKED)) { + tp->backoff = 0; + tcp_rtt_estimator(tp, seq_rtt); + tcp_set_rto(tp); + tcp_bound_rto(tp); } } +static __inline__ void +tcp_ack_update_rtt(struct tcp_opt *tp, int flag, u32 seq_rtt) +{ + if (tp->saw_tstamp) + tcp_ack_saw_tstamp(tp); + else + tcp_ack_no_tstamp(tp, seq_rtt, flag); +} + /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ @@ -855,31 +1645,38 @@ } } +static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp) +{ + if (tp->packets_out==0) { + tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS); + } else { + struct sk_buff *skb = skb_peek(&sk->write_queue); + __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when); + + if ((__s32)when <= 0) + when = TCP_RTO_MIN; + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, when); + } +} + /* Remove acknowledged frames from the retransmission queue. */ -static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, - __u32 *seq, __u32 *seq_rtt) +static int tcp_clean_rtx_queue(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sk_buff *skb; __u32 now = tcp_time_stamp; int acked = 0; - - /* If we are retransmitting, and this ACK clears up to - * the retransmit head, or further, then clear our state. - */ - if (tp->retrans_head != NULL && - !before(ack, TCP_SKB_CB(tp->retrans_head)->end_seq)) - tp->retrans_head = NULL; + __u32 seq_rtt = 0; /* F..g gcc... */ while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) { struct tcp_skb_cb *scb = TCP_SKB_CB(skb); __u8 sacked = scb->sacked; - + /* If our packet is before the ack sequence we can * discard it as it's confirmed to have arrived at * the other end. */ - if (after(scb->end_seq, ack)) + if (after(scb->end_seq, tp->snd_una)) break; /* Initial outgoing SYN's get put onto the write_queue @@ -889,711 +1686,482 @@ * connection startup slow start one packet too * quickly. This is severely frowned upon behavior. */ - if((sacked & TCPCB_SACKED_RETRANS) && tp->retrans_out) - tp->retrans_out--; if(!(scb->flags & TCPCB_FLAG_SYN)) { acked |= FLAG_DATA_ACKED; - if(sacked & TCPCB_SACKED_RETRANS) - acked |= FLAG_RETRANS_DATA_ACKED; - if(tp->fackets_out) - tp->fackets_out--; } else { acked |= FLAG_SYN_ACKED; - /* This is pure paranoia. */ - tp->retrans_head = NULL; } + + if (sacked) { + if(sacked & TCPCB_RETRANS) { + if(sacked & TCPCB_SACKED_RETRANS) + tp->retrans_out--; + acked |= FLAG_RETRANS_DATA_ACKED; + } + if(sacked & TCPCB_SACKED_ACKED) + tp->sacked_out--; + if(sacked & TCPCB_LOST) + tp->lost_out--; + } + if(tp->fackets_out) + tp->fackets_out--; tp->packets_out--; - *seq = scb->seq; - *seq_rtt = now - scb->when; + seq_rtt = now - scb->when; __skb_unlink(skb, skb->list); - kfree_skb(skb); + tcp_free_skb(sk, skb); + } + + if (acked&FLAG_ACKED) { + tcp_ack_update_rtt(tp, acked, seq_rtt); + tcp_ack_packets_out(sk, tp); + } + +#if FASTRETRANS_DEBUG > 0 + BUG_TRAP((int)tp->sacked_out >= 0); + BUG_TRAP((int)tp->lost_out >= 0); + BUG_TRAP((int)tp->retrans_out >= 0); + if (tp->packets_out==0 && tp->sack_ok) { + if (tp->lost_out) { + printk(KERN_DEBUG "Leak l=%u %d\n", tp->lost_out, tp->ca_state); + tp->lost_out = 0; + } + if (tp->sacked_out) { + printk(KERN_DEBUG "Leak s=%u %d\n", tp->sacked_out, tp->ca_state); + tp->sacked_out = 0; + } + if (tp->retrans_out) { + printk(KERN_DEBUG "Leak r=%u %d\n", tp->retrans_out, tp->ca_state); + tp->retrans_out = 0; + } } +#endif return acked; } -static void tcp_ack_probe(struct sock *sk, __u32 ack) +static void tcp_ack_probe(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - + /* Was it a usable window open? */ - if (tp->send_head != NULL) { - if (!after(TCP_SKB_CB(tp->send_head)->end_seq, ack + tp->snd_wnd)) { - tp->backoff = 0; - tcp_clear_xmit_timer(sk, TCP_TIME_PROBE0); - /* If packets_out==0, socket must be waked up by - * subsequent tcp_data_snd_check(). This function is - * not for random using! - */ - } else if (!tp->packets_out) { - tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, - min(tp->rto << tp->backoff, TCP_RTO_MAX)); - } + if (!after(TCP_SKB_CB(tp->send_head)->end_seq, tp->snd_una + tp->snd_wnd)) { + tp->backoff = 0; + tcp_clear_xmit_timer(sk, TCP_TIME_PROBE0); + /* Socket must be waked up by subsequent tcp_data_snd_check(). + * This function is not for random using! + */ + } else { + tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, + min(tp->rto << tp->backoff, TCP_RTO_MAX)); } } -/* Should we open up the congestion window? */ -static __inline__ int should_advance_cwnd(struct tcp_opt *tp, int flag) +static __inline__ int tcp_ack_is_dubious(struct tcp_opt *tp, int flag) { - /* Data must have been acked. */ - if ((flag & FLAG_DATA_ACKED) == 0) - return 0; - - /* Some of the data acked was retransmitted somehow? */ - if ((flag & FLAG_RETRANS_DATA_ACKED) != 0) { - /* We advance in all cases except during - * non-FACK fast retransmit/recovery. - */ - if (tp->fackets_out != 0 || - tp->retransmits != 0) - return 1; + return (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) || + tp->ca_state != TCP_CA_Open); +} - /* Non-FACK fast retransmit does it's own - * congestion window management, don't get - * in the way. - */ - return 0; - } +static __inline__ int tcp_may_raise_cwnd(struct tcp_opt *tp, int flag) +{ + return (!(flag & FLAG_ECE) || tp->snd_cwnd < tp->snd_ssthresh) && + !((1<ca_state)&(TCPF_CA_Recovery|TCPF_CA_CWR)); +} - /* New non-retransmitted data acked, always advance. */ - return 1; +/* Check that window update is acceptable. + * The function assumes that snd_una<=ack<=snd_next. + */ +static __inline__ int +tcp_may_update_window(struct tcp_opt *tp, u32 ack, u32 ack_seq, u32 nwin) +{ + return (after(ack, tp->snd_una) || + after(ack_seq, tp->snd_wl1) || + (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd)); } -/* Read draft-ietf-tcplw-high-performance before mucking - * with this code. (Superceeds RFC1323) +/* Update our send window. + * + * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2 + * and in FreeBSD. NetBSD's one is even worse.) is wrong. */ -static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp, - u32 seq, u32 ack, int flag) +static int tcp_ack_update_window(struct sock *sk, struct tcp_opt *tp, + struct sk_buff *skb, u32 ack, u32 ack_seq) { - __u32 seq_rtt; + int flag = 0; + u32 nwin = ntohs(skb->h.th->window) << tp->snd_wscale; - /* RTTM Rule: A TSecr value received in a segment is used to - * update the averaged RTT measurement only if the segment - * acknowledges some new data, i.e., only if it advances the - * left edge of the send window. - * - * See draft-ietf-tcplw-high-performance-00, section 3.3. - * 1998/04/10 Andrey V. Savochkin - */ - if (!(flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED))) - return; + if (tcp_may_update_window(tp, ack, ack_seq, nwin)) { + flag |= FLAG_WIN_UPDATE; + tcp_update_wl(tp, ack, ack_seq); - seq_rtt = tcp_time_stamp - tp->rcv_tsecr; - tcp_rtt_estimator(tp, seq_rtt); - if (tp->retransmits) { - if (tp->packets_out == 0) { - tp->retransmits = 0; - tp->fackets_out = 0; - tp->retrans_out = 0; - tp->backoff = 0; - tcp_set_rto(tp); - } else { - /* Still retransmitting, use backoff */ - tcp_set_rto(tp); - tp->rto = tp->rto << tp->backoff; + if (tp->snd_wnd != nwin) { + tp->snd_wnd = nwin; + + /* Note, it is the only place, where + * fast path is recovered for sending TCP. + */ + if (skb_queue_len(&tp->out_of_order_queue) == 0 && +#ifdef TCP_FORMAL_WINDOW + tcp_receive_window(tp) && +#endif + !tp->urg_data) + tcp_fast_path_on(tp); + + if (nwin > tp->max_window) { + tp->max_window = nwin; + tcp_sync_mss(sk, tp->pmtu_cookie); + } } - } else { - tcp_set_rto(tp); } - tcp_bound_rto(tp); -} - -static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp) -{ - struct sk_buff *skb = skb_peek(&sk->write_queue); + tp->snd_una = ack; #ifdef TCP_DEBUG - /* It occured in 2.3, because of racy timers. Namely, - * retransmit timer did not check packets_out and retransmitted - * send_head sometimes and, hence, messed all the write_queue. - * Now it is impossible, I bet. --ANK - */ - if (skb == NULL) { - printk("Sucks! packets_out=%d, sk=%p, %d\n", tp->packets_out, sk, sk->state); - return; + if (before(tp->snd_una + tp->snd_wnd, tp->snd_nxt)) { + if (net_ratelimit()) + printk(KERN_DEBUG "TCP: peer shrinks window. Bad, what else can I say?\n"); } #endif - /* Some data was ACK'd, if still retransmitting (due to a - * timeout), resend more of the retransmit queue. The - * congestion window is handled properly by that code. - */ - if (tp->retransmits) { - tcp_xmit_retransmit_queue(sk); - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); - } else { - __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when); - if ((__s32)when < 0) - when = 1; - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, when); - } + return flag; } /* This routine deals with incoming acks, but not outgoing ones. */ -static int tcp_ack(struct sock *sk, struct tcphdr *th, - u32 ack_seq, u32 ack, int len) +static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int flag = 0; - u32 seq = 0; - u32 seq_rtt = 0; - - if(sk->state == TCP_CLOSE) - return 1; /* Dead, can't ack any more so why bother */ + u32 prior_snd_una = tp->snd_una; + u32 ack_seq = TCP_SKB_CB(skb)->seq; + u32 ack = TCP_SKB_CB(skb)->ack_seq; + u32 prior_in_flight; + int prior_packets; /* If the ack is newer than sent or older than previous acks * then we can probably ignore it. */ - if (after(ack, tp->snd_nxt) || before(ack, tp->snd_una)) + if (after(ack, tp->snd_nxt)) goto uninteresting_ack; - /* If there is data set flag 1 */ - if (len != th->doff*4) - flag |= FLAG_DATA; - - /* Update our send window. */ - - /* This is the window update code as per RFC 793 - * snd_wl{1,2} are used to prevent unordered - * segments from shrinking the window - */ - if (before(tp->snd_wl1, ack_seq) || - (tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) { - u32 nwin = ntohs(th->window) << tp->snd_wscale; - - if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) { - flag |= FLAG_WIN_UPDATE; - if (tp->snd_wnd != nwin) { - tp->snd_wnd = nwin; + if (before(ack, prior_snd_una)) + goto old_ack; - /* Note, it is the only place, where - * fast path is recovered for sending TCP. - */ - if (skb_queue_len(&tp->out_of_order_queue) == 0 && -#ifdef TCP_FORMAL_WINDOW - tcp_receive_window(tp) && -#endif - !tp->urg_data) - tcp_fast_path_on(tp); + if (!(flag&FLAG_SLOWPATH) && after(ack, prior_snd_una)) { + /* Window is constant, pure forward advance. + * No more checks are required. + * Note, we use the fact that SND.UNA>=SND.WL2. + */ + tcp_update_wl(tp, ack, ack_seq); + tp->snd_una = ack; + flag |= FLAG_WIN_UPDATE; - if (nwin > tp->max_window) { - tp->max_window = nwin; - tcp_sync_mss(sk, tp->pmtu_cookie); - } - } + NET_INC_STATS_BH(TCPHPAcks); + } else { + if (ack_seq != TCP_SKB_CB(skb)->end_seq) + flag |= FLAG_DATA; + else + NET_INC_STATS_BH(TCPPureAcks); - tp->snd_wl1 = ack_seq; - tp->snd_wl2 = ack; - } - } + flag |= tcp_ack_update_window(sk, tp, skb, ack, ack_seq); - /* BEWARE! From this place and until return from this function - * snd_nxt and snd_wnd are out of sync. All the routines, called - * from here must get "ack" as argument or they should not depend - * on right edge of window. It is _UGLY_. It cries to be fixed. --ANK - */ + if (TCP_SKB_CB(skb)->sacked) + flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); + + if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th)) + flag |= FLAG_ECE; + } /* We passed data and got it acked, remove any soft error * log. Something worked... */ sk->err_soft = 0; - tp->probes_out = 0; tp->rcv_tstamp = tcp_time_stamp; + if ((prior_packets = tp->packets_out) == 0) + goto no_queue; - /* See if we can take anything off of the retransmit queue. */ - flag |= tcp_clean_rtx_queue(sk, ack, &seq, &seq_rtt); - - /* If this ack opens up a zero window, clear backoff. It was - * being used to time the probes, and is probably far higher than - * it needs to be for normal retransmission. - */ - if (tcp_timer_is_set(sk, TCP_TIME_PROBE0)) - tcp_ack_probe(sk, ack); - - /* We must do this here, before code below clears out important - * state contained in tp->fackets_out and tp->retransmits. -DaveM - */ - if (should_advance_cwnd(tp, flag)) - tcp_cong_avoid(tp); + prior_in_flight = tcp_packets_in_flight(tp); - /* If we have a timestamp, we always do rtt estimates. */ - if (tp->saw_tstamp) { - tcp_ack_saw_tstamp(sk, tp, seq, ack, flag); - } else { - /* If we were retransmiting don't count rtt estimate. */ - if (tp->retransmits) { - if (tp->packets_out == 0) { - tp->retransmits = 0; - tp->fackets_out = 0; - tp->retrans_out = 0; - } - } else { - /* We don't have a timestamp. Can only use - * packets that are not retransmitted to determine - * rtt estimates. Also, we must not reset the - * backoff for rto until we get a non-retransmitted - * packet. This allows us to deal with a situation - * where the network delay has increased suddenly. - * I.e. Karn's algorithm. (SIGCOMM '87, p5.) - */ - if (flag & (FLAG_DATA_ACKED|FLAG_SYN_ACKED)) { - if(!(flag & FLAG_RETRANS_DATA_ACKED)) { - tp->backoff = 0; - tcp_rtt_estimator(tp, seq_rtt); - tcp_set_rto(tp); - tcp_bound_rto(tp); - } - } - } - } + /* See if we can take anything off of the retransmit queue. */ + flag |= tcp_clean_rtx_queue(sk); - if (tp->packets_out) { - if (flag & FLAG_DATA_ACKED) - tcp_ack_packets_out(sk, tp); + if (tcp_ack_is_dubious(tp, flag)) { + /* Advanve CWND, if state allows this. */ + if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd && + tcp_may_raise_cwnd(tp, flag)) + tcp_cong_avoid(tp); + tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); } else { - tcp_clear_xmit_timer(sk, TCP_TIME_RETRANS); + if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd) + tcp_cong_avoid(tp); } - flag &= (FLAG_DATA | FLAG_WIN_UPDATE); - if ((ack == tp->snd_una && tp->packets_out && flag == 0) || - (tp->high_seq != 0)) { - tcp_fast_retrans(sk, ack, flag); - } else { - /* Clear any aborted fast retransmit starts. */ - tp->dup_acks = 0; - } - /* It is not a brain fart, I thought a bit now. 8) - * - * Forward progress is indicated, if: - * 1. the ack acknowledges new data. - * 2. or the ack is duplicate, but it is caused by new segment - * arrival. This case is filtered by: - * - it contains no data, syn or fin. - * - it does not update window. - * 3. or new SACK. It is difficult to check, so that we ignore it. - * - * Forward progress is also indicated by arrival new data, - * which was caused by window open from our side. This case is more - * difficult and it is made (alas, incorrectly) in tcp_data_queue(). - * --ANK (990513) - */ - if (ack != tp->snd_una || (flag == 0 && !th->fin)) + if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP)) dst_confirm(sk->dst_cache); - if (ack != tp->snd_una) - tp->sorry = 1; + return 1; + +no_queue: + tp->probes_out = 0; - /* Remember the highest ack received. */ - tp->snd_una = ack; + /* If this ack opens up a zero window, clear backoff. It was + * being used to time the probes, and is probably far higher than + * it needs to be for normal retransmission. + */ + if (tp->send_head) + tcp_ack_probe(sk); return 1; +old_ack: + if (TCP_SKB_CB(skb)->sacked) + tcp_sacktag_write_queue(sk, skb, prior_snd_una); + uninteresting_ack: - SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt); + SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt); return 0; } -int tcp_paws_check(struct tcp_opt *tp, int rst) -{ - if ((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) - return 0; - if (xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS) - return 0; - - /* RST segments are not recommended to carry timestamp, - and, if they do, it is recommended to ignore PAWS because - "their cleanup function should take precedence over timestamps." - Certainly, it is mistake. It is necessary to understand the reasons - of this constraint to relax it: if peer reboots, clock may go - out-of-sync and half-open connections will not be reset. - Actually, the problem would be not existing if all - the implementations followed draft about maintaining clock - via reboots. Linux-2.2 DOES NOT! - However, we can relax time bounds for RST segments to MSL. - */ - if (rst && xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_MSL) - return 0; - return 1; -} - -static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) +/* Look for tcp options. Normally only called on SYN and SYNACK packets. + * But, this can also be called on packets in the established flow when + * the fast version below fails. + */ +void tcp_parse_options(struct sk_buff *skb, struct tcp_opt *tp) { - if (seq == s_win) - return 1; - if (after(end_seq, s_win) && before(seq, e_win)) - return 1; - return (seq == e_win && seq == end_seq); -} + unsigned char *ptr; + struct tcphdr *th = skb->h.th; + int length=(th->doff*4)-sizeof(struct tcphdr); + + ptr = (unsigned char *)(th + 1); + tp->saw_tstamp = 0; -/* New-style handling of TIME_WAIT sockets. */ + while(length>0) { + int opcode=*ptr++; + int opsize; -/* Must be called with locally disabled BHs. */ -void tcp_timewait_kill(struct tcp_tw_bucket *tw) -{ - struct tcp_ehash_bucket *ehead; - struct tcp_bind_hashbucket *bhead; - struct tcp_bind_bucket *tb; + switch (opcode) { + case TCPOPT_EOL: + return; + case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ + length--; + continue; + default: + opsize=*ptr++; + if (opsize < 2) /* "silly options" */ + return; + if (opsize > length) + break; /* don't parse partial options */ + switch(opcode) { + case TCPOPT_MSS: + if(opsize==TCPOLEN_MSS && th->syn) { + u16 in_mss = ntohs(*(__u16 *)ptr); + if (in_mss) { + if (tp->user_mss && tp->user_mss < in_mss) + in_mss = tp->user_mss; + tp->mss_clamp = in_mss; + } + } + break; + case TCPOPT_WINDOW: + if(opsize==TCPOLEN_WINDOW && th->syn) + if (sysctl_tcp_window_scaling) { + tp->wscale_ok = 1; + tp->snd_wscale = *(__u8 *)ptr; + if(tp->snd_wscale > 14) { + if(net_ratelimit()) + printk("tcp_parse_options: Illegal window " + "scaling value %d >14 received.", + tp->snd_wscale); + tp->snd_wscale = 14; + } + } + break; + case TCPOPT_TIMESTAMP: + if(opsize==TCPOLEN_TIMESTAMP) { + if (sysctl_tcp_timestamps) { + tp->tstamp_ok = 1; + tp->saw_tstamp = 1; + tp->rcv_tsval = ntohl(*(__u32 *)ptr); + tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4)); + } + } + break; + case TCPOPT_SACK_PERM: + if(opsize==TCPOLEN_SACK_PERM && th->syn) { + if (sysctl_tcp_sack) { + tp->sack_ok = 1; + tcp_sack_reset(tp); + } + } + break; - /* Unlink from established hashes. */ - ehead = &tcp_ehash[tw->hashent]; - write_lock(&ehead->lock); - if (!tw->pprev) { - write_unlock(&ehead->lock); - return; - } - if(tw->next) - tw->next->pprev = tw->pprev; - *(tw->pprev) = tw->next; - tw->pprev = NULL; - write_unlock(&ehead->lock); - - /* Disassociate with bind bucket. */ - bhead = &tcp_bhash[tcp_bhashfn(tw->num)]; - spin_lock(&bhead->lock); - if ((tb = tw->tb) != NULL) { - if(tw->bind_next) - tw->bind_next->bind_pprev = tw->bind_pprev; - *(tw->bind_pprev) = tw->bind_next; - tw->tb = NULL; - if (tb->owners == NULL) { - if (tb->next) - tb->next->pprev = tb->pprev; - *(tb->pprev) = tb->next; - kmem_cache_free(tcp_bucket_cachep, tb); - } - } - spin_unlock(&bhead->lock); - -#ifdef INET_REFCNT_DEBUG - if (atomic_read(&tw->refcnt) != 1) { - printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, atomic_read(&tw->refcnt)); + case TCPOPT_SACK: + if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) && + !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) && + tp->sack_ok) { + TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; + } + }; + ptr+=opsize-2; + length-=opsize; + }; } -#endif - tcp_tw_put(tw); } -/* - * * Main purpose of TIME-WAIT state is to close connection gracefully, - * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN - * (and, probably, tail of data) and one or more our ACKs are lost. - * * What is TIME-WAIT timeout? It is associated with maximal packet - * lifetime in the internet, which results in wrong conclusion, that - * it is set to catch "old duplicate segments" wandering out of their path. - * It is not quite correct. This timeout is calculated so that it exceeds - * maximal retransmision timeout enough to allow to lose one (or more) - * segments sent by peer and our ACKs. This time may be calculated from RTO. - * * When TIME-WAIT socket receives RST, it means that another end - * finally closed and we are allowed to kill TIME-WAIT too. - * * Second purpose of TIME-WAIT is catching old duplicate segments. - * Well, certainly it is pure paranoia, but if we load TIME-WAIT - * with this semantics, we MUST NOT kill TIME-WAIT state with RSTs. - * * If we invented some more clever way to catch duplicates - * (f.e. based on PAWS), we could truncate TIME-WAIT to several RTOs. - * - * The algorithm below is based on FORMAL INTERPRETATION of RFCs. - * When you compare it to RFCs, please, read section SEGMENT ARRIVES - * from the very beginning. - * - * NOTE. With recycling (and later with fin-wait-2) TW bucket - * is _not_ stateless. It means, that strictly speaking we must - * spinlock it. I do not want! Well, probability of misbehaviour - * is ridiculously low and, seems, we could use some mb() tricks - * to avoid misread sequence numbers, states etc. --ANK - */ -enum tcp_tw_status -tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, - struct tcphdr *th, unsigned len) -{ - struct tcp_opt tp; - int paws_reject = 0; - - tp.saw_tstamp = 0; - if (th->doff > (sizeof(struct tcphdr)>>2) && tw->ts_recent_stamp) { - tcp_parse_options(NULL, th, &tp, 0); - - if (tp.saw_tstamp) { - tp.ts_recent = tw->ts_recent; - tp.ts_recent_stamp = tw->ts_recent_stamp; - paws_reject = tcp_paws_check(&tp, th->rst); - } - } - - if (tw->substate == TCP_FIN_WAIT2) { - /* Just repeat all the checks of tcp_rcv_state_process() */ - - /* Out of window, send ACK */ - if (paws_reject || - !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - tw->rcv_nxt, tw->rcv_nxt + tw->rcv_wnd)) - return TCP_TW_ACK; - - if (th->rst) - goto kill; - - if (th->syn && TCP_SKB_CB(skb)->seq != tw->syn_seq) - goto kill_with_rst; - - /* Dup ACK? */ - if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) || - TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { - tcp_tw_put(tw); - return TCP_TW_SUCCESS; - } - - /* New data or FIN. If new data arrive after half-duplex close, - * reset. - */ - if (!th->fin || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) { -kill_with_rst: - tcp_tw_deschedule(tw); - tcp_timewait_kill(tw); - tcp_tw_put(tw); - return TCP_TW_RST; - } - - /* FIN arrived, enter true time-wait state. */ - tw->substate = TCP_TIME_WAIT; - tw->rcv_nxt = TCP_SKB_CB(skb)->end_seq; - if (tp.saw_tstamp) { - tw->ts_recent_stamp = xtime.tv_sec; - tw->ts_recent = tp.rcv_tsval; - } - - /* I am shamed, but failed to make it more elegant. - * Yes, it is direct reference to IP, which is impossible - * to generalize to IPv6. Taking into account that IPv6 - * do not undertsnad recycling in any case, it not - * a big problem in practice. --ANK */ - if (tw->family == AF_INET && - sysctl_tcp_tw_recycle && tw->ts_recent_stamp && - tcp_v4_tw_remember_stamp(tw)) - tcp_tw_schedule(tw, tw->timeout); - else - tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); - return TCP_TW_ACK; - } - - /* - * Now real TIME-WAIT state. - * - * RFC 1122: - * "When a connection is [...] on TIME-WAIT state [...] - * [a TCP] MAY accept a new SYN from the remote TCP to - * reopen the connection directly, if it: - * - * (1) assigns its initial sequence number for the new - * connection to be larger than the largest sequence - * number it used on the previous connection incarnation, - * and - * - * (2) returns to TIME-WAIT state if the SYN turns out - * to be an old duplicate". - */ - - if (!paws_reject && - (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq && - TCP_SKB_CB(skb)->seq == tw->rcv_nxt)) { - /* In window segment, it may be only reset or bare ack. */ - - if (th->rst) { - /* This is TIME_WAIT assasination, in two flavors. - * Oh well... nobody has a sufficient solution to this - * protocol bug yet. - */ - if (sysctl_tcp_rfc1337 == 0) { -kill: - tcp_tw_deschedule(tw); - tcp_timewait_kill(tw); - tcp_tw_put(tw); - return TCP_TW_SUCCESS; - } - } - tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); - - if (tp.saw_tstamp) { - tw->ts_recent = tp.rcv_tsval; - tw->ts_recent_stamp = xtime.tv_sec; +/* Fast parse options. This hopes to only see timestamps. + * If it is wrong it falls back on tcp_parse_options(). + */ +static __inline__ int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, struct tcp_opt *tp) +{ + if (th->doff == sizeof(struct tcphdr)>>2) { + tp->saw_tstamp = 0; + return 0; + } else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) { + __u32 *ptr = (__u32 *)(th + 1); + if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { + tp->saw_tstamp = 1; + ++ptr; + tp->rcv_tsval = ntohl(*ptr); + ++ptr; + tp->rcv_tsecr = ntohl(*ptr); + return 1; } - - tcp_tw_put(tw); - return TCP_TW_SUCCESS; - } - - /* Out of window segment. - - All the segments are ACKed immediately. - - The only exception is new SYN. We accept it, if it is - not old duplicate and we are not in danger to be killed - by delayed old duplicates. RFC check is that it has - newer sequence number works at rates <40Mbit/sec. - However, if paws works, it is reliable AND even more, - we even may relax silly seq space cutoff. - - RED-PEN: we violate main RFC requirement, if this SYN will appear - old duplicate (i.e. we receive RST in reply to SYN-ACK), - we must return socket to time-wait state. It is not good, - but not fatal yet. - */ - - if (th->syn && !th->rst && !th->ack && !paws_reject && - (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) || - (tp.saw_tstamp && (s32)(tw->ts_recent - tp.rcv_tsval) < 0))) { - u32 isn = tw->snd_nxt + 2; - if (isn == 0) - isn++; - TCP_SKB_CB(skb)->when = isn; - return TCP_TW_SYN; } + tcp_parse_options(skb, tp); + return 1; +} - if (paws_reject) - NET_INC_STATS_BH(PAWSEstabRejected); +extern __inline__ void +tcp_store_ts_recent(struct tcp_opt *tp) +{ + tp->ts_recent = tp->rcv_tsval; + tp->ts_recent_stamp = xtime.tv_sec; +} - if(!th->rst) { - /* In this case we must reset the TIMEWAIT timer. +extern __inline__ void +tcp_replace_ts_recent(struct tcp_opt *tp, u32 seq) +{ + if (tp->saw_tstamp && !after(seq, tp->rcv_wup)) { + /* PAWS bug workaround wrt. ACK frames, the PAWS discard + * extra check below makes sure this can only happen + * for pure ACK frames. -DaveM * - * If it is ACKless SYN it may be both old duplicate - * and new good SYN with random sequence number ack) - tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); - /* Send ACK. Note, we do not put the bucket, - * it will be released by caller. - */ - return TCP_TW_ACK; + if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0 || + xtime.tv_sec >= tp->ts_recent_stamp + TCP_PAWS_24DAYS) + tcp_store_ts_recent(tp); } - tcp_tw_put(tw); - return TCP_TW_SUCCESS; } -/* Enter the time wait state. This is called with locally disabled BH. - * Essentially we whip up a timewait bucket, copy the - * relevant info into it from the SK, and mess with hash chains - * and list linkage. +/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM + * + * It is not fatal. If this ACK does _not_ change critical state (seqs, window) + * it can pass through stack. So, the following predicate verifies that + * this segment is not used for anything but congestion avoidance or + * fast retransmit. Moreover, we even are able to eliminate most of such + * second order effects, if we apply some small "replay" window (~RTO) + * to timestamp space. + * + * All these measures still do not guarantee that we reject wrapped ACKs + * on networks with high bandwidth, when sequence space is recycled fastly, + * but it guarantees that such events will be very rare and do not affect + * connection seriously. This doesn't look nice, but alas, PAWS is really + * buggy extension. + * + * [ Later note. Even worse! It is buggy for segments _with_ data. RFC + * states that events when retransmit arrives after original data are rare. + * It is a blatant lie. VJ forgot about fast retransmit! 8)8) It is + * the biggest problem on large power networks even with minor reordering. + * OK, let's give it small replay window. If peer clock is even 1hz, it is safe + * up to bandwidth of 18Gigabit/sec. 8) ] */ -static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) + +static int tcp_disordered_ack(struct tcp_opt *tp, struct sk_buff *skb) { - struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->hashent]; - struct tcp_bind_hashbucket *bhead; - struct sock **head, *sktw; + struct tcphdr *th = skb->h.th; + u32 seq = TCP_SKB_CB(skb)->seq; + u32 ack = TCP_SKB_CB(skb)->ack_seq; - write_lock(&ehead->lock); + return (/* 1. Pure ACK with correct sequence number. */ + (th->ack && seq == TCP_SKB_CB(skb)->end_seq && seq == tp->rcv_nxt) && - /* Step 1: Remove SK from established hash. */ - if (sk->pprev) { - if(sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - sock_prot_dec_use(sk->prot); - } + /* 2. ... and duplicate ACK. */ + ack == tp->snd_una && - /* Step 2: Hash TW into TIMEWAIT half of established hash table. */ - head = &(ehead + tcp_ehash_size)->chain; - sktw = (struct sock *)tw; - if((sktw->next = *head) != NULL) - (*head)->pprev = &sktw->next; - *head = sktw; - sktw->pprev = head; - atomic_inc(&tw->refcnt); + /* 3. ... and does not update window. */ + !tcp_may_update_window(tp, ack, seq, ntohs(th->window)<snd_wscale) && - write_unlock(&ehead->lock); + /* 4. ... and sits in replay window. */ + (s32)(tp->ts_recent - tp->rcv_tsval) <= (tp->rto*1024)/HZ); +} - /* Step 3: Put TW into bind hash. Original socket stays there too. - Note, that any socket with sk->num!=0 MUST be bound in binding - cache, even if it is closed. - */ - bhead = &tcp_bhash[tcp_bhashfn(sk->num)]; - spin_lock(&bhead->lock); - tw->tb = (struct tcp_bind_bucket *)sk->prev; - BUG_TRAP(sk->prev!=NULL); - if ((tw->bind_next = tw->tb->owners) != NULL) - tw->tb->owners->bind_pprev = &tw->bind_next; - tw->tb->owners = (struct sock*)tw; - tw->bind_pprev = &tw->tb->owners; - spin_unlock(&bhead->lock); +extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct sk_buff *skb) +{ + return ((s32)(tp->ts_recent - tp->rcv_tsval) > TCP_PAWS_WINDOW && + xtime.tv_sec < tp->ts_recent_stamp + TCP_PAWS_24DAYS && + !tcp_disordered_ack(tp, skb)); } -/* - * Move a socket to time-wait or dead fin-wait-2 state. - */ -void tcp_time_wait(struct sock *sk, int state, int timeo) +static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) { - struct tcp_tw_bucket *tw = NULL; - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int recycle_ok = 0; + u32 end_window = tp->rcv_wup + tp->rcv_wnd; +#ifdef TCP_FORMAL_WINDOW + u32 rcv_wnd = tcp_receive_window(tp); +#else + u32 rcv_wnd = tp->rcv_wnd; +#endif - if (sysctl_tcp_tw_recycle && tp->ts_recent_stamp) - recycle_ok = tp->af_specific->remember_stamp(sk); + if (rcv_wnd && + after(end_seq, tp->rcv_nxt) && + before(seq, end_window)) + return 1; + if (seq != end_window) + return 0; + return (seq == end_seq); +} - if (tcp_tw_count < sysctl_tcp_max_tw_buckets) - tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC); - - if(tw != NULL) { - int rto = (tp->rto<<2) - (tp->rto>>1); - - /* Give us an identity. */ - tw->daddr = sk->daddr; - tw->rcv_saddr = sk->rcv_saddr; - tw->bound_dev_if= sk->bound_dev_if; - tw->num = sk->num; - tw->state = TCP_TIME_WAIT; - tw->substate = state; - tw->sport = sk->sport; - tw->dport = sk->dport; - tw->family = sk->family; - tw->reuse = sk->reuse; - tw->rcv_wscale = tp->rcv_wscale; - atomic_set(&tw->refcnt, 0); - - tw->hashent = sk->hashent; - tw->rcv_nxt = tp->rcv_nxt; - tw->snd_nxt = tp->snd_nxt; - tw->rcv_wnd = tcp_receive_window(tp); - tw->syn_seq = tp->syn_seq; - tw->ts_recent = tp->ts_recent; - tw->ts_recent_stamp= tp->ts_recent_stamp; - tw->pprev_death = NULL; - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - if(tw->family == PF_INET6) { - memcpy(&tw->v6_daddr, - &sk->net_pinfo.af_inet6.daddr, - sizeof(struct in6_addr)); - memcpy(&tw->v6_rcv_saddr, - &sk->net_pinfo.af_inet6.rcv_saddr, - sizeof(struct in6_addr)); - } +/* This functions checks to see if the tcp header is actually acceptable. + * + * Actually, our check is seriously broken, we must accept RST,ACK,URG + * even on zero window effectively trimming data. It is RFC, guys. + * But our check is so beautiful, that I do not want to repair it + * now. However, taking into account those stupid plans to start to + * send some texts with RST, we have to handle at least this case. --ANK + */ +extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq, int rst) +{ +#ifdef TCP_FORMAL_WINDOW + u32 rcv_wnd = tcp_receive_window(tp); +#else + u32 rcv_wnd = tp->rcv_wnd; #endif - /* Linkage updates. */ - __tcp_tw_hashdance(sk, tw); - - /* Get the TIME_WAIT timeout firing. */ - if (timeo < rto) - timeo = rto; + if (seq == tp->rcv_nxt) + return (rcv_wnd || (end_seq == seq) || rst); - if (recycle_ok) { - tw->timeout = rto; - } else { - tw->timeout = TCP_TIMEWAIT_LEN; - if (state == TCP_TIME_WAIT) - timeo = TCP_TIMEWAIT_LEN; - } + return __tcp_sequence(tp, seq, end_seq); +} - tcp_tw_schedule(tw, timeo); - } else { - /* Sorry, if we're out of memory, just CLOSE this - * socket up. We've got bigger problems than - * non-graceful socket closings. - */ - if (net_ratelimit()) - printk(KERN_INFO "TCP: time wait bucket table overflow\n"); +/* When we get a reset we do this. */ +static void tcp_reset(struct sock *sk) +{ + /* We want the right error as BSD sees it (and indeed as we do). */ + switch (sk->state) { + case TCP_SYN_SENT: + sk->err = ECONNREFUSED; + break; + case TCP_CLOSE_WAIT: + sk->err = EPIPE; + break; + case TCP_CLOSE: + return; + default: + sk->err = ECONNRESET; } - tcp_update_metrics(sk); + if (!sk->dead) + sk->error_report(sk); + tcp_done(sk); } @@ -1611,22 +2179,22 @@ * * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT. */ - static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); tp->fin_seq = TCP_SKB_CB(skb)->end_seq; - tp->ack.pending = 1; - tp->ack.quick = 0; + tcp_schedule_ack(tp); sk->shutdown |= RCV_SHUTDOWN; + sk->done = 1; switch(sk->state) { case TCP_SYN_RECV: case TCP_ESTABLISHED: /* Move to CLOSE_WAIT */ tcp_set_state(sk, TCP_CLOSE_WAIT); + tp->ack.pingpong = 1; break; case TCP_CLOSE_WAIT: @@ -1644,6 +2212,7 @@ * happens, we must ack the received FIN and * enter the CLOSING state. */ + tcp_send_ack(sk); tcp_set_state(sk, TCP_CLOSING); break; case TCP_FIN_WAIT2: @@ -1664,7 +2233,8 @@ */ __skb_queue_purge(&tp->out_of_order_queue); if (tp->sack_ok) - tp->num_sacks = 0; + tcp_sack_reset(tp); + tcp_mem_reclaim(sk); if (!sk->dead) { sk->state_change(sk); @@ -1677,51 +2247,90 @@ } } +static __inline__ int +tcp_sack_extend(struct tcp_sack_block *sp, u32 seq, u32 end_seq) +{ + if (!after(seq, sp->end_seq) && !after(sp->start_seq, end_seq)) { + if (before(seq, sp->start_seq)) + sp->start_seq = seq; + if (after(end_seq, sp->end_seq)) + sp->end_seq = end_seq; + return 1; + } + return 0; +} + +static __inline__ void tcp_dsack_set(struct tcp_opt *tp, u32 seq, u32 end_seq) +{ + if (tp->sack_ok && sysctl_tcp_dsack) { + if (before(seq, tp->rcv_nxt)) + NET_INC_STATS_BH(TCPDSACKOldSent); + else + NET_INC_STATS_BH(TCPDSACKOfoSent); + + tp->dsack = 1; + tp->duplicate_sack[0].start_seq = seq; + tp->duplicate_sack[0].end_seq = end_seq; + tp->eff_sacks = min(tp->num_sacks+1, 4-tp->tstamp_ok); + } +} + +static __inline__ void tcp_dsack_extend(struct tcp_opt *tp, u32 seq, u32 end_seq) +{ + if (!tp->dsack) + tcp_dsack_set(tp, seq, end_seq); + else + tcp_sack_extend(tp->duplicate_sack, seq, end_seq); +} + +static void tcp_send_dupack(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && + before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { + NET_INC_STATS_BH(DelayedACKLost); + tcp_enter_quickack_mode(tp); + + if (tp->sack_ok && sysctl_tcp_dsack) { + u32 end_seq = TCP_SKB_CB(skb)->end_seq; + + if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) + end_seq = tp->rcv_nxt; + tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, end_seq); + } + } + + tcp_send_ack(sk); +} + /* These routines update the SACK block as out-of-order packets arrive or * in-order packets close up the sequence space. */ -static void tcp_sack_maybe_coalesce(struct tcp_opt *tp, struct tcp_sack_block *sp) +static void tcp_sack_maybe_coalesce(struct tcp_opt *tp) { - int this_sack, num_sacks = tp->num_sacks; - struct tcp_sack_block *swalk = &tp->selective_acks[0]; + int this_sack; + struct tcp_sack_block *sp = &tp->selective_acks[0]; + struct tcp_sack_block *swalk = sp+1; - /* If more than one SACK block, see if the recent change to SP eats into + /* See if the recent change to the first SACK eats into * or hits the sequence space of other SACK blocks, if so coalesce. */ - if(num_sacks != 1) { - for(this_sack = 0; this_sack < num_sacks; this_sack++, swalk++) { - if(swalk == sp) - continue; + for (this_sack = 1; this_sack < tp->num_sacks; ) { + if (tcp_sack_extend(sp, swalk->start_seq, swalk->end_seq)) { + int i; - /* First case, bottom of SP moves into top of the - * sequence space of SWALK. - */ - if(between(sp->start_seq, swalk->start_seq, swalk->end_seq)) { - sp->start_seq = swalk->start_seq; - goto coalesce; - } - /* Second case, top of SP moves into bottom of the - * sequence space of SWALK. + /* Zap SWALK, by moving every further SACK up by one slot. + * Decrease num_sacks. */ - if(between(sp->end_seq, swalk->start_seq, swalk->end_seq)) { - sp->end_seq = swalk->end_seq; - goto coalesce; - } + tp->num_sacks--; + tp->eff_sacks = min(tp->num_sacks+tp->dsack, 4-tp->tstamp_ok); + for(i=this_sack; i < tp->num_sacks; i++) + sp[i] = sp[i+1]; + continue; } + this_sack++, swalk++; } - /* SP is the only SACK, or no coalescing cases found. */ - return; - -coalesce: - /* Zap SWALK, by moving every further SACK up by one slot. - * Decrease num_sacks. - */ - for(; this_sack < num_sacks-1; this_sack++, swalk++) { - struct tcp_sack_block *next = (swalk + 1); - swalk->start_seq = next->start_seq; - swalk->end_seq = next->end_seq; - } - tp->num_sacks--; } static __inline__ void tcp_sack_swap(struct tcp_sack_block *sack1, struct tcp_sack_block *sack2) @@ -1737,151 +2346,117 @@ sack2->end_seq = tmp; } -static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb) +static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct tcp_sack_block *sp = &tp->selective_acks[0]; int cur_sacks = tp->num_sacks; + int this_sack; if (!cur_sacks) goto new_sack; - /* Optimize for the common case, new ofo frames arrive - * "in order". ;-) This also satisfies the requirements - * of RFC2018 about ordering of SACKs. - */ - if(sp->end_seq == TCP_SKB_CB(skb)->seq) { - sp->end_seq = TCP_SKB_CB(skb)->end_seq; - tcp_sack_maybe_coalesce(tp, sp); - } else if(sp->start_seq == TCP_SKB_CB(skb)->end_seq) { - /* Re-ordered arrival, in this case, can be optimized - * as well. - */ - sp->start_seq = TCP_SKB_CB(skb)->seq; - tcp_sack_maybe_coalesce(tp, sp); - } else { - struct tcp_sack_block *swap = sp + 1; - int this_sack, max_sacks = (tp->tstamp_ok ? 3 : 4); - - /* Oh well, we have to move things around. - * Try to find a SACK we can tack this onto. - */ - - for(this_sack = 1; this_sack < cur_sacks; this_sack++, swap++) { - if((swap->end_seq == TCP_SKB_CB(skb)->seq) || - (swap->start_seq == TCP_SKB_CB(skb)->end_seq)) { - if(swap->end_seq == TCP_SKB_CB(skb)->seq) - swap->end_seq = TCP_SKB_CB(skb)->end_seq; - else - swap->start_seq = TCP_SKB_CB(skb)->seq; - tcp_sack_swap(sp, swap); - tcp_sack_maybe_coalesce(tp, sp); - return; - } - } - - /* Could not find an adjacent existing SACK, build a new one, - * put it at the front, and shift everyone else down. We - * always know there is at least one SACK present already here. - * - * If the sack array is full, forget about the last one. - */ - if (cur_sacks >= max_sacks) { - cur_sacks--; - tp->num_sacks--; - } - while(cur_sacks >= 1) { - struct tcp_sack_block *this = &tp->selective_acks[cur_sacks]; - struct tcp_sack_block *prev = (this - 1); - this->start_seq = prev->start_seq; - this->end_seq = prev->end_seq; - cur_sacks--; + for (this_sack=0; this_sack0; this_sack--, sp--) + tcp_sack_swap(sp, sp-1); + if (cur_sacks > 1) + tcp_sack_maybe_coalesce(tp); + return; } + } - new_sack: - /* Build the new head SACK, and we're done. */ - sp->start_seq = TCP_SKB_CB(skb)->seq; - sp->end_seq = TCP_SKB_CB(skb)->end_seq; - tp->num_sacks++; + /* Could not find an adjacent existing SACK, build a new one, + * put it at the front, and shift everyone else down. We + * always know there is at least one SACK present already here. + * + * If the sack array is full, forget about the last one. + */ + if (this_sack >= 4) { + this_sack--; + tp->num_sacks--; + sp--; } + for(; this_sack > 0; this_sack--, sp--) + *sp = *(sp-1); + +new_sack: + /* Build the new head SACK, and we're done. */ + sp->start_seq = seq; + sp->end_seq = end_seq; + tp->num_sacks++; + tp->eff_sacks = min(tp->num_sacks+tp->dsack, 4-tp->tstamp_ok); } -static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb) +/* RCV.NXT advances, some SACKs should be eaten. */ + +static void tcp_sack_remove(struct tcp_opt *tp) { struct tcp_sack_block *sp = &tp->selective_acks[0]; int num_sacks = tp->num_sacks; int this_sack; - /* This is an in order data segment _or_ an out-of-order SKB being - * moved to the receive queue, so we know this removed SKB will eat - * from the front of a SACK. - */ - for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) { - /* Check if the start of the sack is covered by skb. */ - if(!before(sp->start_seq, TCP_SKB_CB(skb)->seq) && - before(sp->start_seq, TCP_SKB_CB(skb)->end_seq)) - break; - } - - /* This should only happen if so many SACKs get built that some get - * pushed out before we get here, or we eat some in sequence packets - * which are before the first SACK block. - */ - if(this_sack >= num_sacks) + /* Empty ofo queue, hence, all the SACKs are eaten. Clear. */ + if (skb_queue_len(&tp->out_of_order_queue) == 0) { + tp->num_sacks = 0; + tp->eff_sacks = tp->dsack; return; + } - sp->start_seq = TCP_SKB_CB(skb)->end_seq; - if(!before(sp->start_seq, sp->end_seq)) { - /* Zap this SACK, by moving forward any other SACKS. */ - for(this_sack += 1; this_sack < num_sacks; this_sack++, sp++) { - struct tcp_sack_block *next = (sp + 1); - sp->start_seq = next->start_seq; - sp->end_seq = next->end_seq; + for(this_sack = 0; this_sack < num_sacks; ) { + /* Check if the start of the sack is covered by RCV.NXT. */ + if (!before(tp->rcv_nxt, sp->start_seq)) { + int i; + + /* RCV.NXT must cover all the block! */ + BUG_TRAP(!before(tp->rcv_nxt, sp->end_seq)); + + /* Zap this SACK, by moving forward any other SACKS. */ + for (i=this_sack+1; i < num_sacks; i++) + sp[i-1] = sp[i]; + num_sacks--; + continue; } - tp->num_sacks--; + this_sack++; + sp++; } -} - -static void tcp_sack_extend(struct tcp_opt *tp, struct sk_buff *old_skb, struct sk_buff *new_skb) -{ - struct tcp_sack_block *sp = &tp->selective_acks[0]; - int num_sacks = tp->num_sacks; - int this_sack; - - for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) { - if(sp->end_seq == TCP_SKB_CB(old_skb)->end_seq) - break; + if (num_sacks != tp->num_sacks) { + tp->num_sacks = num_sacks; + tp->eff_sacks = min(tp->num_sacks+tp->dsack, 4-tp->tstamp_ok); } - if(this_sack >= num_sacks) - return; - sp->end_seq = TCP_SKB_CB(new_skb)->end_seq; } - /* This one checks to see if we can put data from the * out_of_order queue into the receive_queue. */ static void tcp_ofo_queue(struct sock *sk) { - struct sk_buff *skb; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + __u32 dsack_high = tp->rcv_nxt; + struct sk_buff *skb; - while ((skb = skb_peek(&tp->out_of_order_queue))) { + while ((skb = skb_peek(&tp->out_of_order_queue)) != NULL) { if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) break; + if (before(TCP_SKB_CB(skb)->seq, dsack_high)) { + __u32 dsack = dsack_high; + if (before(TCP_SKB_CB(skb)->end_seq, dsack_high)) + dsack_high = TCP_SKB_CB(skb)->end_seq; + tcp_dsack_extend(tp, TCP_SKB_CB(skb)->seq, dsack); + } + if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { SOCK_DEBUG(sk, "ofo packet was already received \n"); __skb_unlink(skb, skb->list); - kfree_skb(skb); + __kfree_skb(skb); continue; } SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); - if(tp->sack_ok) - tcp_sack_remove_skb(tp, skb); __skb_unlink(skb, skb->list); __skb_queue_tail(&sk->receive_queue, skb); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; @@ -1892,10 +2467,14 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) { - struct sk_buff *skb1; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int eaten = 0; + if (tp->dsack) { + tp->dsack = 0; + tp->eff_sacks = min(tp->num_sacks, 4-tp->tstamp_ok); + } + /* Queue data for delivery to the user. * Packets in sequence go to the receive queue. * Out of sequence packets to the out_of_order_queue. @@ -1924,20 +2503,27 @@ if (!eaten) { queue_and_out: - skb_set_owner_r(skb, sk); + tcp_set_owner_r(skb, sk); __skb_queue_tail(&sk->receive_queue, skb); } - dst_confirm(sk->dst_cache); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; if(skb->len) - tcp_event_data_recv(tp, skb); + tcp_event_data_recv(sk, tp, skb); if(skb->h.th->fin) tcp_fin(skb, sk, skb->h.th); - /* This may have eaten into a SACK block. */ - if(tp->sack_ok && tp->num_sacks) - tcp_sack_remove_skb(tp, skb); - tcp_ofo_queue(sk); + if (skb_queue_len(&tp->out_of_order_queue)) { + tcp_ofo_queue(sk); + + /* RFC2581. 4.2. SHOULD send immediate ACK, when + * gap in queue is filled. + */ + if (skb_queue_len(&tp->out_of_order_queue) == 0) + tp->ack.pingpong = 0; + } + + if(tp->num_sacks) + tcp_sack_remove(tp); /* Turn on fast path. */ if (skb_queue_len(&tp->out_of_order_queue) == 0 && @@ -1948,24 +2534,28 @@ tcp_fast_path_on(tp); if (eaten) { - kfree_skb(skb); + __kfree_skb(skb); } else if (!sk->dead) sk->data_ready(sk, 0); return; } +#ifdef TCP_DEBUG /* An old packet, either a retransmit or some packet got lost. */ if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { /* A retransmit, 2nd most common case. Force an imediate ack. * * It is impossible, seq is checked by top level. */ - NETDEBUG(printk("retransmit in tcp_data_queue: seq %X\n", TCP_SKB_CB(skb)->seq)); + printk("BUG: retransmit in tcp_data_queue: seq %X\n", TCP_SKB_CB(skb)->seq); tcp_enter_quickack_mode(tp); - tp->ack.pending = 1; - kfree_skb(skb); + tcp_schedule_ack(tp); + __kfree_skb(skb); return; } +#endif + + tcp_enter_quickack_mode(tp); if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { /* Partial packet, seq < rcv_next < end_seq */ @@ -1973,67 +2563,198 @@ tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); + tcp_dsack_set(tp, TCP_SKB_CB(skb)->seq, tp->rcv_nxt); goto queue_and_out; } - /* Ok. This is an out_of_order segment, force an ack. */ - tp->ack.pending = 1; + TCP_ECN_check_ce(tp, skb); /* Disable header prediction. */ tp->pred_flags = 0; - + tcp_schedule_ack(tp); SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); - skb_set_owner_r(skb, sk); + tcp_set_owner_r(skb, sk); if (skb_peek(&tp->out_of_order_queue) == NULL) { /* Initial out of order segment, build 1 SACK. */ if(tp->sack_ok) { tp->num_sacks = 1; + tp->dsack = 0; + tp->eff_sacks = 1; tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq; tp->selective_acks[0].end_seq = TCP_SKB_CB(skb)->end_seq; } __skb_queue_head(&tp->out_of_order_queue,skb); } else { - for(skb1=tp->out_of_order_queue.prev; ; skb1 = skb1->prev) { - /* Already there. */ - if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb1)->seq) { - if (skb->len >= skb1->len) { - if(tp->sack_ok) - tcp_sack_extend(tp, skb1, skb); - __skb_append(skb1, skb); - __skb_unlink(skb1, skb1->list); - kfree_skb(skb1); - } else { - /* A duplicate, smaller than what is in the - * out-of-order queue right now, toss it. - */ - kfree_skb(skb); - } + struct sk_buff *skb1=tp->out_of_order_queue.prev; + u32 seq = TCP_SKB_CB(skb)->seq; + u32 end_seq = TCP_SKB_CB(skb)->end_seq; + + if (seq == TCP_SKB_CB(skb1)->end_seq) { + __skb_append(skb1, skb); + + if (tp->num_sacks == 0 || + tp->selective_acks[0].end_seq != seq) + goto add_sack; + + /* Common case: data arrive in order after hole. */ + tp->selective_acks[0].end_seq = end_seq; + return; + } + + /* Find place to insert this segment. */ + do { + if (!after(TCP_SKB_CB(skb1)->seq, seq)) break; + } while ((skb1=skb1->prev) != (struct sk_buff*)&tp->out_of_order_queue); + + /* Do skb overlap to previous one? */ + if (skb1 != (struct sk_buff*)&tp->out_of_order_queue && + before(seq, TCP_SKB_CB(skb1)->end_seq)) { + if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { + /* All the bits are present. Drop. */ + __kfree_skb(skb); + tcp_dsack_set(tp, seq, end_seq); + goto add_sack; + } + if (after(seq, TCP_SKB_CB(skb1)->seq)) { + /* Partial overlap. */ + tcp_dsack_set(tp, seq, TCP_SKB_CB(skb1)->end_seq); + } else { + skb1 = skb1->prev; } - - if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb1)->seq)) { - __skb_append(skb1, skb); - if(tp->sack_ok) - tcp_sack_new_ofo_skb(sk, skb); - break; + } + __skb_insert(skb, skb1, skb1->next, &tp->out_of_order_queue); + + /* And clean segments covered by new one as whole. */ + while ((skb1 = skb->next) != (struct sk_buff*)&tp->out_of_order_queue && + after(end_seq, TCP_SKB_CB(skb1)->seq)) { + if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { + tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, end_seq); + break; + } + __skb_unlink(skb1, skb1->list); + tcp_dsack_extend(tp, TCP_SKB_CB(skb1)->seq, TCP_SKB_CB(skb1)->end_seq); + __kfree_skb(skb1); + } + +add_sack: + if (tp->sack_ok) + tcp_sack_new_ofo_skb(sk, seq, end_seq); + } +} + + +static void tcp_collapse_queue(struct sock *sk, struct sk_buff_head *q) +{ + struct sk_buff *skb = skb_peek(q); + struct sk_buff *skb_next; + + while (skb && + skb != (struct sk_buff *)q && + (skb_next = skb->next) != (struct sk_buff *)q) { + struct tcp_skb_cb *scb = TCP_SKB_CB(skb); + struct tcp_skb_cb *scb_next = TCP_SKB_CB(skb_next); + + if (scb->end_seq == scb_next->seq && + skb_tailroom(skb) >= skb_next->len && +#define TCP_DONT_COLLAPSE (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN) + !(tcp_flag_word(skb->h.th)&TCP_DONT_COLLAPSE) && + !(tcp_flag_word(skb_next->h.th)&TCP_DONT_COLLAPSE)) { + /* OK to collapse two skbs to one */ + memcpy(skb_put(skb, skb_next->len), skb_next->data, skb_next->len); + __skb_unlink(skb_next, skb_next->list); + scb->end_seq = scb_next->end_seq; + __kfree_skb(skb_next); + NET_INC_STATS_BH(TCPRcvCollapsed); + } else { + /* Lots of spare tailroom, reallocate this skb to trim it. */ + if (tcp_win_from_space(skb->truesize) > skb->len && + skb_tailroom(skb) > sizeof(struct sk_buff) + 16) { + struct sk_buff *nskb; + + nskb = skb_copy_expand(skb, skb_headroom(skb), 0, GFP_ATOMIC); + if (nskb) { + tcp_set_owner_r(nskb, sk); + memcpy(nskb->data-skb_headroom(skb), + skb->data-skb_headroom(skb), + skb_headroom(skb)); + __skb_append(skb, nskb); + __skb_unlink(skb, skb->list); + __kfree_skb(skb); + } } + skb = skb_next; + } + } +} + +/* Clean the out_of_order queue if we can, trying to get + * the socket within its memory limits again. + * + * Return less than zero if we should start dropping frames + * until the socket owning process reads some of the data + * to stabilize the situation. + */ +static int tcp_prune_queue(struct sock *sk) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + + SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq); + + NET_INC_STATS_BH(PruneCalled); + + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) + tcp_clamp_window(sk, tp); + else if (tcp_memory_pressure) + tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss); + + tcp_collapse_queue(sk, &sk->receive_queue); + tcp_collapse_queue(sk, &tp->out_of_order_queue); + tcp_mem_reclaim(sk); + + if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) + return 0; + + /* Collapsing did not help, destructive actions follow. + * This must not ever occur. */ - /* See if we've hit the start. If so insert. */ - if (skb1 == skb_peek(&tp->out_of_order_queue)) { - __skb_queue_head(&tp->out_of_order_queue,skb); - if(tp->sack_ok) - tcp_sack_new_ofo_skb(sk, skb); - break; - } - } + /* First, purge the out_of_order queue. */ + if (skb_queue_len(&tp->out_of_order_queue)) { + net_statistics[smp_processor_id()*2].OfoPruned += skb_queue_len(&tp->out_of_order_queue); + __skb_queue_purge(&tp->out_of_order_queue); + + /* Reset SACK state. A conforming SACK implementation will + * do the same at a timeout based retransmit. When a connection + * is in a sad state like this, we care only about integrity + * of the connection not performance. + */ + if(tp->sack_ok) + tcp_sack_reset(tp); + tcp_mem_reclaim(sk); } - return; + + if(atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) + return 0; + + /* If we are really being abused, tell the caller to silently + * drop receive data on the floor. It will get retransmitted + * and hopefully then we'll have sufficient space. + */ + NET_INC_STATS_BH(RcvPruned); + + /* Massive buffer overcommit. */ + return -1; } +static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb) +{ + return (int)skb->truesize <= sk->forward_alloc || + tcp_mem_schedule(sk, skb->truesize, 1); +} /* * This routine handles the data. If there is room in the buffer, @@ -2053,53 +2774,103 @@ if (skb->len == 0 && !th->fin) goto drop; + TCP_ECN_accept_cwr(tp, skb); + /* * If our receive queue has grown past its limits shrink it. * Make sure to do this before moving rcv_nxt, otherwise * data might be acked for that we don't have enough room. */ - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) { - if (prune_queue(sk) < 0) { - /* Still not enough room. That can happen when - * skb->true_size differs significantly from skb->len. - */ + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + !tcp_rmem_schedule(sk, skb)) { + if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) goto drop; - } } tcp_data_queue(sk, skb); +#ifdef TCP_DEBUG if (before(tp->rcv_nxt, tp->copied_seq)) { printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n"); tp->rcv_nxt = tp->copied_seq; } +#endif return; drop: - kfree_skb(skb); + __kfree_skb(skb); +} + +/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. + * As additional protections, we do not touch cwnd in retransmission phases, + * and if application hit its sndbuf limit recently. + */ +void tcp_cwnd_application_limited(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + if (tp->ca_state == TCP_CA_Open && + sk->socket && !test_bit(SOCK_NOSPACE, &sk->socket->flags)) { + /* Limited by application or receiver window. */ + u32 win_used = max(tp->snd_cwnd_used, 2); + if (win_used < tp->snd_cwnd) { + tp->snd_ssthresh = tcp_current_ssthresh(tp); + tp->snd_cwnd = (tp->snd_cwnd+win_used)>>1; + } + tp->snd_cwnd_used = 0; + } + tp->snd_cwnd_stamp = tcp_time_stamp; } + /* When incoming ACK allowed to free some skb from write_queue, - * we remember this in flag tp->sorry and wake up socket on the exit - * from tcp input handler. Probably, handler has already eat this space - * sending ACK and cloned frames from tcp_write_xmit(). + * we remember this event in flag tp->queue_shrunk and wake up socket + * on the exit from tcp input handler. */ -static __inline__ void tcp_new_space(struct sock *sk) +static void tcp_new_space(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct socket *sock; - tp->sorry = 0; + if (tp->packets_out < tp->snd_cwnd && + !(sk->userlocks&SOCK_SNDBUF_LOCK) && + !tcp_memory_pressure && + atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) { + int sndmem, demanded; + + sndmem = tp->mss_clamp+MAX_TCP_HEADER+16+sizeof(struct sk_buff); + demanded = max(tp->snd_cwnd, tp->reordering+1); + sndmem *= 2*demanded; + if (sndmem > sk->sndbuf) + sk->sndbuf = min(sndmem, sysctl_tcp_wmem[2]); + tp->snd_cwnd_stamp = tcp_time_stamp; + } + + /* Wakeup users. */ + if (tcp_wspace(sk) >= tcp_min_write_space(sk)) { + struct socket *sock = sk->socket; - if (sock_wspace(sk) >= tcp_min_write_space(sk) && - (sock = sk->socket) != NULL) { clear_bit(SOCK_NOSPACE, &sock->flags); if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); - if (sock->fasync_list) + if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); + + /* Satisfy those who hook write_space() callback. */ + if (sk->write_space != tcp_write_space) + sk->write_space(sk); + } +} + +static inline void tcp_check_space(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + if (tp->queue_shrunk) { + tp->queue_shrunk = 0; + if (sk->socket && test_bit(SOCK_NOSPACE, &sk->socket->flags)) + tcp_new_space(sk); } } @@ -2118,7 +2889,8 @@ struct sk_buff *skb = sk->tp_pinfo.af_tcp.send_head; if (skb != NULL) - __tcp_data_snd_check(sk, skb); + __tcp_data_snd_check(sk, skb); + tcp_check_space(sk); } /* @@ -2128,32 +2900,15 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - /* This also takes care of updating the window. - * This if statement needs to be simplified. - * - * Rules for delaying an ack: - * - delay time <= 0.5 HZ - * - we don't have a window update to send - * - must send at least every 2 full sized packets - * - must send an ACK if we have any out of order data - * - * With an extra heuristic to handle loss of packet - * situations and also helping the sender leave slow - * start in an expediant manner. - */ - - /* More than one full frame received or... */ + /* More than one full frame received... */ if (((tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss -#ifdef TCP_MORE_COARSE_ACKS - /* Avoid to send immediate ACK from input path, if it - * does not advance window far enough. tcp_recvmsg() will do this. + /* ... and right edge of window advances far enough. + * (tcp_recvmsg() will send ACK otherwise). Or... */ - && (!sysctl_tcp_retrans_collapse || __tcp_select_window(sk) >= tp->rcv_wnd) -#endif - ) || + && __tcp_select_window(sk) >= tp->rcv_wnd) || /* We ACK each frame or... */ tcp_in_quickack_mode(tp) || - /* We have out of order data or */ + /* We have out of order data. */ (ofo_possible && skb_peek(&tp->out_of_order_queue) != NULL)) { /* Then ack it now */ @@ -2167,14 +2922,13 @@ static __inline__ void tcp_ack_snd_check(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - if (tp->ack.pending == 0) { + if (!tcp_ack_scheduled(tp)) { /* We sent a data segment already. */ return; } __tcp_ack_snd_check(sk, 1); } - /* * This routine is only called when we have urgent data * signalled. Its the 'slow' part of tcp_urg. It could be @@ -2248,92 +3002,6 @@ } } -/* Clean the out_of_order queue if we can, trying to get - * the socket within its memory limits again. - * - * Return less than zero if we should start dropping frames - * until the socket owning process reads some of the data - * to stabilize the situation. - */ -static int prune_queue(struct sock *sk) -{ - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - struct sk_buff *skb; - int pruned = 0; - - SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq); - - NET_INC_STATS_BH(PruneCalled); - - /* First, purge the out_of_order queue. */ - skb = __skb_dequeue_tail(&tp->out_of_order_queue); - if(skb != NULL) { - /* Free it all. */ - do { - pruned += skb->len; - net_statistics[smp_processor_id()*2].OfoPruned += skb->len; - kfree_skb(skb); - skb = __skb_dequeue_tail(&tp->out_of_order_queue); - } while(skb != NULL); - - /* Reset SACK state. A conforming SACK implementation will - * do the same at a timeout based retransmit. When a connection - * is in a sad state like this, we care only about integrity - * of the connection not performance. - */ - if(tp->sack_ok) - tp->num_sacks = 0; - } - - /* If we are really being abused, tell the caller to silently - * drop receive data on the floor. It will get retransmitted - * and hopefully then we'll have sufficient space. - * - * We used to try to purge the in-order packets too, but that - * turns out to be deadly and fraught with races. Consider: - * - * 1) If we acked the data, we absolutely cannot drop the - * packet. This data would then never be retransmitted. - * 2) It is possible, with a proper sequence of events involving - * delayed acks and backlog queue handling, to have the user - * read the data before it gets acked. The previous code - * here got this wrong, and it lead to data corruption. - * 3) Too much state changes happen when the FIN arrives, so once - * we've seen that we can't remove any in-order data safely. - * - * The net result is that removing in-order receive data is too - * complex for anyones sanity. So we don't do it anymore. But - * if we are really having our buffer space abused we stop accepting - * new receive data. - * - * 8) The arguments are interesting, but I even cannot imagine - * what kind of arguments could force us to drop NICE, ALREADY - * RECEIVED DATA only to get one more packet? --ANK - * - * FIXME: it should recompute SACK state and only remove enough - * buffers to get into bounds again. The current scheme loses - * badly sometimes on links with large RTT, especially when - * the driver has high overhead per skb. - * (increasing the rcvbuf is not enough because it inflates the - * the window too, disabling flow control effectively) -AK - * - * Mmm... Why not to scale it seprately then? Just replace - * / WINDOW_ADVERTISE_DIVISOR with >> sk->window_advertise_scale - * and adjust it dynamically, when TCP window flow control - * fails? -ANK - */ - - tp->ack.quick = 0; - - if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1)) - return 0; - - NET_INC_STATS_BH(RcvPruned); - - /* Massive buffer overcommit. */ - return -1; -} - static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -2454,9 +3122,6 @@ * We do checksum and copy also but from device to kernel. */ - /* RED-PEN. Using static variables to pass function arguments - * cannot be good idea... - */ tp->saw_tstamp = 0; /* pred_flags is 0xS?10 << 16 + snd_wnd @@ -2468,7 +3133,7 @@ * PSH flag is ignored. */ - if ((tcp_flag_word(th) & ~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) == tp->pred_flags && + if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { int tcp_header_len = tp->tcp_header_len; @@ -2500,10 +3165,8 @@ * seq == rcv_nxt and rcv_wup <= rcv_nxt. * Hence, check seq<=rcv_wup reduces to: */ - if (tp->rcv_nxt == tp->rcv_wup) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = xtime.tv_sec; - } + if (tp->rcv_nxt == tp->rcv_wup) + tcp_store_ts_recent(tp); } if (len <= tcp_header_len) { @@ -2512,18 +3175,15 @@ /* We know that such packets are checksummed * on entry. */ - tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->ack_seq, len); - kfree_skb(skb); + tcp_ack(sk, skb, 0); + __kfree_skb(skb); tcp_data_snd_check(sk); - if (tp->sorry) - tcp_new_space(sk); return 0; } else { /* Header too small */ TCP_INC_STATS_BH(TcpInErrs); goto discard; } - } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) { + } else { int eaten = 0; if (tp->ucopy.task == current && @@ -2546,67 +3206,59 @@ if (tcp_checksum_complete_user(sk, skb)) goto csum_error; - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) + if ((int)skb->truesize > sk->forward_alloc) goto step5; NET_INC_STATS_BH(TCPHPHits); /* Bulk data transfer: receiver */ __skb_pull(skb,tcp_header_len); - - /* DO NOT notify forward progress here. - * It saves dozen of CPU instructions in fast path. --ANK - * And where is it signaled then ? -AK - * Nowhere. 8) --ANK - */ __skb_queue_tail(&sk->receive_queue, skb); - skb_set_owner_r(skb, sk); - + tcp_set_owner_r(skb, sk); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; - - /* FIN bit check is not done since if FIN is set in - * this frame, the pred_flags won't match up. -DaveM - */ - sk->data_ready(sk, 0); } - tcp_event_data_recv(tp, skb); + tcp_event_data_recv(sk, tp, skb); + + if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) { + /* Well, only one small jumplet in fast path... */ + tcp_ack(sk, skb, FLAG_DATA); + tcp_data_snd_check(sk); + if (!tcp_ack_scheduled(tp)) + goto no_ack; + } -#ifdef TCP_MORE_COARSE_ACKS if (eaten) { if (tcp_in_quickack_mode(tp)) { tcp_send_ack(sk); } else { tcp_send_delayed_ack(sk); } - } else -#endif - __tcp_ack_snd_check(sk, 0); + } else { + __tcp_ack_snd_check(sk, 0); + } +no_ack: if (eaten) - kfree_skb(skb); + __kfree_skb(skb); + else + sk->data_ready(sk, 0); return 0; } - /* Packet is in sequence, flags are trivial; - * only ACK is strange. Jump to step 5. - */ - if (tcp_checksum_complete_user(sk, skb)) - goto csum_error; - goto step5; } slow_path: - if (tcp_checksum_complete_user(sk, skb)) + if (len < (th->doff<<2) || tcp_checksum_complete_user(sk, skb)) goto csum_error; /* * RFC1323: H1. Apply PAWS check first. */ - if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp && + if (tcp_fast_parse_options(skb, th, tp) && tp->saw_tstamp && tcp_paws_discard(tp, skb)) { if (!th->rst) { NET_INC_STATS_BH(PAWSEstabRejected); - tcp_send_ack(sk); + tcp_send_dupack(sk, skb); goto discard; } /* Resets are accepted even if PAWS failed. @@ -2620,23 +3272,15 @@ * Standard slow path. */ - if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) { + if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, th->rst)) { /* RFC793, page 37: "In all states except SYN-SENT, all reset * (RST) segments are validated by checking their SEQ-fields." * And page 69: "If an incoming segment is not acceptable, * an acknowledgment should be sent in reply (unless the RST bit * is set, if so drop the segment and return)". */ - if (th->rst) - goto discard; - if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { - SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n", - TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - tp->rcv_wup, tp->rcv_wnd); - } - tcp_enter_quickack_mode(tp); - tcp_send_ack(sk); - NET_INC_STATS_BH(DelayedACKLost); + if (!th->rst) + tcp_send_dupack(sk, skb); goto discard; } @@ -2645,378 +3289,43 @@ goto discard; } - if (tp->saw_tstamp) { - tcp_replace_ts_recent(sk, tp, - TCP_SKB_CB(skb)->seq); - } + tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { - SOCK_DEBUG(sk, "syn in established state\n"); TCP_INC_STATS_BH(TcpInErrs); + NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); return 1; } step5: if(th->ack) - tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len); - + tcp_ack(sk, skb, FLAG_SLOWPATH); + /* Process urgent data. */ tcp_urg(sk, th, len); /* step 7: process the segment text */ tcp_data(skb, sk, len); - /* Be careful, tcp_data() may have put this into TIME_WAIT. */ - if(sk->state != TCP_CLOSE) { - tcp_data_snd_check(sk); - tcp_ack_snd_check(sk); - if (tp->sorry) - tcp_new_space(sk); - } - + tcp_data_snd_check(sk); + tcp_ack_snd_check(sk); return 0; csum_error: TCP_INC_STATS_BH(TcpInErrs); discard: - kfree_skb(skb); + __kfree_skb(skb); return 0; } - -/* This is not only more efficient than what we used to do, it eliminates - * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM - * - * Actually, we could lots of memory writes here. tp of listening - * socket contains all necessary default parameters. - */ -struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb) -{ - struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0); - - if(newsk != NULL) { - struct tcp_opt *newtp; -#ifdef CONFIG_FILTER - struct sk_filter *filter; -#endif - - memcpy(newsk, sk, sizeof(*newsk)); - newsk->state = TCP_SYN_RECV; - - /* SANITY */ - newsk->pprev = NULL; - newsk->prev = NULL; - - /* Clone the TCP header template */ - newsk->dport = req->rmt_port; - - sock_lock_init(newsk); - bh_lock_sock(newsk); - - atomic_set(&newsk->rmem_alloc, 0); - skb_queue_head_init(&newsk->receive_queue); - atomic_set(&newsk->wmem_alloc, 0); - skb_queue_head_init(&newsk->write_queue); - atomic_set(&newsk->omem_alloc, 0); - - newsk->done = 0; - newsk->proc = 0; - newsk->backlog.head = newsk->backlog.tail = NULL; - skb_queue_head_init(&newsk->error_queue); - newsk->write_space = tcp_write_space; -#ifdef CONFIG_FILTER - if ((filter = newsk->filter) != NULL) - sk_filter_charge(newsk, filter); -#endif - - /* Now setup tcp_opt */ - newtp = &(newsk->tp_pinfo.af_tcp); - newtp->pred_flags = 0; - newtp->rcv_nxt = req->rcv_isn + 1; - newtp->snd_nxt = req->snt_isn + 1; - newtp->snd_una = req->snt_isn + 1; - newtp->snd_sml = req->snt_isn + 1; - - tcp_delack_init(newtp); - if (skb->len >= 536) - newtp->ack.last_seg_size = skb->len; - - tcp_prequeue_init(newtp); - - newtp->snd_wl1 = req->rcv_isn; - newtp->snd_wl2 = req->snt_isn; - - newtp->retransmits = 0; - newtp->backoff = 0; - newtp->srtt = 0; - newtp->mdev = TCP_TIMEOUT_INIT; - newtp->rto = TCP_TIMEOUT_INIT; - - newtp->packets_out = 0; - newtp->fackets_out = 0; - newtp->retrans_out = 0; - newtp->snd_ssthresh = 0x7fffffff; - - /* So many TCP implementations out there (incorrectly) count the - * initial SYN frame in their delayed-ACK and congestion control - * algorithms that we must have the following bandaid to talk - * efficiently to them. -DaveM - */ - newtp->snd_cwnd = 2; - newtp->snd_cwnd_cnt = 0; - newtp->high_seq = 0; - - newtp->dup_acks = 0; - tcp_init_xmit_timers(newsk); - skb_queue_head_init(&newtp->out_of_order_queue); - newtp->send_head = newtp->retrans_head = NULL; - newtp->rcv_wup = req->rcv_isn + 1; - newtp->write_seq = req->snt_isn + 1; - newtp->copied_seq = req->rcv_isn + 1; - - newtp->saw_tstamp = 0; - - newtp->probes_out = 0; - newtp->num_sacks = 0; - newtp->syn_seq = req->rcv_isn; - newtp->fin_seq = req->rcv_isn; - newtp->urg_data = 0; - newtp->listen_opt = NULL; - newtp->accept_queue = newtp->accept_queue_tail = NULL; - /* Deinitialize syn_wait_lock to trap illegal accesses. */ - memset(&newtp->syn_wait_lock, 0, sizeof(newtp->syn_wait_lock)); - - /* Back to base struct sock members. */ - newsk->err = 0; - newsk->priority = 0; - atomic_set(&newsk->refcnt, 1); -#ifdef INET_REFCNT_DEBUG - atomic_inc(&inet_sock_nr); -#endif - - if (newsk->keepopen) - tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp)); - newsk->socket = NULL; - newsk->sleep = NULL; - - newtp->tstamp_ok = req->tstamp_ok; - if((newtp->sack_ok = req->sack_ok) != 0) - newtp->num_sacks = 0; - newtp->window_clamp = req->window_clamp; - newtp->rcv_wnd = req->rcv_wnd; - newtp->wscale_ok = req->wscale_ok; - if (newtp->wscale_ok) { - newtp->snd_wscale = req->snd_wscale; - newtp->rcv_wscale = req->rcv_wscale; - } else { - newtp->snd_wscale = newtp->rcv_wscale = 0; - newtp->window_clamp = min(newtp->window_clamp,65535); - } - newtp->snd_wnd = ntohs(skb->h.th->window) << newtp->snd_wscale; - newtp->max_window = newtp->snd_wnd; - - if (newtp->tstamp_ok) { - newtp->ts_recent = req->ts_recent; - newtp->ts_recent_stamp = xtime.tv_sec; - newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; - } else { - newtp->ts_recent_stamp = 0; - newtp->tcp_header_len = sizeof(struct tcphdr); - } - newtp->mss_clamp = req->mss; - } - return newsk; -} - -/* - * Process an incoming packet for SYN_RECV sockets represented - * as an open_request. - */ - -struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, - struct open_request *req, - struct open_request **prev) -{ - struct tcphdr *th = skb->h.th; - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); - int paws_reject = 0; - struct tcp_opt ttp; - struct sock *child; - - ttp.saw_tstamp = 0; - if (th->doff > (sizeof(struct tcphdr)>>2)) { - tcp_parse_options(NULL, th, &ttp, 0); - - if (ttp.saw_tstamp) { - ttp.ts_recent = req->ts_recent; - /* We do not store true stamp, but it is not required, - * it can be estimated (approximately) - * from another data. - */ - ttp.ts_recent_stamp = xtime.tv_sec - ((TCP_TIMEOUT_INIT/HZ)<retrans); - paws_reject = tcp_paws_check(&ttp, th->rst); - } - } - - /* Check for pure retransmited SYN. */ - if (TCP_SKB_CB(skb)->seq == req->rcv_isn && - flg == TCP_FLAG_SYN && - !paws_reject) { - /* - * RFC793 draws (Incorrectly! It was fixed in RFC1122) - * this case on figure 6 and figure 8, but formal - * protocol description says NOTHING. - * To be more exact, it says that we should send ACK, - * because this segment (at least, if it has no data) - * is out of window. - * - * CONCLUSION: RFC793 (even with RFC1122) DOES NOT - * describe SYN-RECV state. All the description - * is wrong, we cannot believe to it and should - * rely only on common sense and implementation - * experience. - * - * Enforce "SYN-ACK" according to figure 8, figure 6 - * of RFC793, fixed by RFC1122. - */ - req->class->rtx_syn_ack(sk, req, NULL); - return NULL; - } - - /* Further reproduces section "SEGMENT ARRIVES" - for state SYN-RECEIVED of RFC793. - It is broken, however, it does not work only - when SYNs are crossed, which is impossible in our - case. - - But generally, we should (RFC lies!) to accept ACK - from SYNACK both here and in tcp_rcv_state_process(). - tcp_rcv_state_process() does not, hence, we do not too. - - Note that the case is absolutely generic: - we cannot optimize anything here without - violating protocol. All the checks must be made - before attempt to create socket. - */ - - /* RFC793: "first check sequence number". */ - - if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - req->rcv_isn+1, req->rcv_isn+1+req->rcv_wnd)) { - /* Out of window: send ACK and drop. */ - if (!(flg & TCP_FLAG_RST)) - req->class->send_ack(skb, req); - if (paws_reject) - NET_INC_STATS_BH(PAWSEstabRejected); - return NULL; - } - - /* In sequence, PAWS is OK. */ - - if (ttp.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1)) - req->ts_recent = ttp.rcv_tsval; - - if (TCP_SKB_CB(skb)->seq == req->rcv_isn) { - /* Truncate SYN, it is out of window starting - at req->rcv_isn+1. */ - flg &= ~TCP_FLAG_SYN; - } - - /* RFC793: "second check the RST bit" and - * "fourth, check the SYN bit" - */ - if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) - goto embryonic_reset; - - /* RFC793: "fifth check the ACK field" */ - - if (!(flg & TCP_FLAG_ACK)) - return NULL; - - /* Invalid ACK: reset will be sent by listening socket */ - if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1) - return sk; - /* Also, it would be not so bad idea to check rcv_tsecr, which - * is essentially ACK extension and too early or too late values - * should cause reset in unsynchronized states. - */ - - /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ - if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) { - req->acked = 1; - return NULL; - } - - /* OK, ACK is valid, create big socket and - * feed this segment to it. It will repeat all - * the tests. THIS SEGMENT MUST MOVE SOCKET TO - * ESTABLISHED STATE. If it will be dropped after - * socket is created, wait for troubles. - */ - child = tp->af_specific->syn_recv_sock(sk, skb, req, NULL); - if (child == NULL) - goto listen_overflow; - - tcp_synq_unlink(tp, req, prev); - tcp_synq_removed(sk, req); - - tcp_acceptq_queue(sk, req, child); - return child; - -listen_overflow: - if (!sysctl_tcp_abort_on_overflow) { - req->acked = 1; - return NULL; - } - -embryonic_reset: - NET_INC_STATS_BH(EmbryonicRsts); - if (!(flg & TCP_FLAG_RST)) - req->class->send_reset(skb); - - tcp_synq_drop(sk, req, prev); - return NULL; -} - -/* - * Queue segment on the new socket if the new socket is active, - * otherwise we just shortcircuit this and continue with - * the new socket. - */ - -int tcp_child_process(struct sock *parent, struct sock *child, - struct sk_buff *skb) -{ - int ret = 0; - int state = child->state; - - if (child->lock.users == 0) { - ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len); - - /* Wakeup parent, send SIGIO */ - if (state == TCP_SYN_RECV && child->state != state) - parent->data_ready(parent, 0); - } else { - /* Alas, it is possible again, because we do lookup - * in main socket hash table and lock on listening - * socket does not protect us more. - */ - sk_add_backlog(child, skb); - } - - bh_unlock_sock(child); - return ret; -} - static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, struct tcphdr *th, unsigned len) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - tcp_parse_options(sk, th, tp, 0); + tcp_parse_options(skb, tp); if (th->ack) { /* rfc793: @@ -3027,24 +3336,12 @@ * a reset (unless the RST bit is set, if so drop * the segment and return)" * - * I cite this place to emphasize one essential - * detail, this check is different of one - * in established state: SND.UNA <= SEG.ACK <= SND.NXT. - * SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT, - * because we have no previous data sent before SYN. - * --ANK(990513) - * * We do not send data with SYN, so that RFC-correct * test reduces to: */ if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt) return 1; - /* Check not from any RFC, but it is evident consequence - * of combining PAWS and usual SYN-SENT logic: ACK _is_ - * checked in SYN-SENT unlike another states, hence - * echoed tstamp must be checked too. - */ if (tp->saw_tstamp) { if (tp->rcv_tsecr == 0) { /* Workaround for bug in linux-2.1 and early @@ -3055,13 +3352,9 @@ tp->saw_tstamp = 0; /* But do not forget to store peer's timestamp! */ - if (th->syn) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = xtime.tv_sec; - } - } else if ((__s32)(tp->rcv_tsecr - tcp_time_stamp) > 0 || - (__s32)(tp->rcv_tsecr - tp->syn_stamp) < 0) { - NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "TCP: synsent reject.\n")); + if (th->syn) + tcp_store_ts_recent(tp); + } else if (!between(tp->rcv_tsecr, tp->retrans_stamp, tcp_time_stamp)) { NET_INC_STATS_BH(PAWSActiveRejected); return 1; } @@ -3095,30 +3388,12 @@ * are acceptable then ... * (our SYN has been ACKed), change the connection * state to ESTABLISHED..." - * - * Do you see? SYN-less ACKs in SYN-SENT state are - * completely ignored. - * - * The bug causing stalled SYN-SENT sockets - * was here: tcp_ack advanced snd_una and canceled - * retransmit timer, so that bare ACK received - * in SYN-SENT state (even with invalid ack==ISS, - * because tcp_ack check is too weak for SYN-SENT) - * causes moving socket to invalid semi-SYN-SENT, - * semi-ESTABLISHED state and connection hangs. - * --ANK (990514) - * - * Bare ACK is valid, however. - * Actually, RFC793 requires to send such ACK - * in reply to any out of window packet. - * It is wrong, but Linux also send such - * useless ACKs sometimes. - * --ANK (990724) */ + TCP_ECN_rcv_synack(tp, th); + tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - tcp_ack(sk,th, TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->ack_seq, len); + tcp_ack(sk, skb, FLAG_SLOWPATH); /* Ok.. it's good. Set up sequence numbers and * move to established. @@ -3130,12 +3405,10 @@ * never scaled. */ tp->snd_wnd = ntohs(th->window); - tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq; + tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq); + tp->syn_seq = TCP_SKB_CB(skb)->seq; tp->fin_seq = TCP_SKB_CB(skb)->seq; - tcp_set_state(sk, TCP_ESTABLISHED); - if (tp->wscale_ok == 0) { tp->snd_wscale = tp->rcv_wscale = 0; tp->window_clamp = min(tp->window_clamp,65535); @@ -3144,12 +3417,14 @@ if (tp->tstamp_ok) { tp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; } else tp->tcp_header_len = sizeof(struct tcphdr); - if (tp->saw_tstamp) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = xtime.tv_sec; - } + if (tp->saw_tstamp) + tcp_store_ts_recent(tp); + if (tp->sack_ok && sysctl_tcp_fack) + tp->sack_ok |= 2; + tcp_sync_mss(sk, tp->pmtu_cookie); tcp_initialize_rcv_mss(sk); tcp_init_metrics(sk); @@ -3158,15 +3433,24 @@ if (sk->keepopen) tcp_reset_keepalive_timer(sk, keepalive_time_when(tp)); + if (tp->snd_wscale == 0) + __tcp_fast_path_on(tp, tp->snd_wnd); + else + tp->pred_flags = 0; + + /* Remember, tcp_poll() does not lock socket! + * Change state from SYN-SENT only after copied_seq + * is initilized. */ tp->copied_seq = tp->rcv_nxt; - __tcp_fast_path_on(tp, tp->snd_wnd); + mb(); + tcp_set_state(sk, TCP_ESTABLISHED); if(!sk->dead) { sk->state_change(sk); sk_wake_async(sk, 0, POLL_OUT); } - if (tp->write_pending) { + if (tp->write_pending || tp->defer_accept) { /* Save one ACK. Data will be ready after * several ticks, if write_pending is set. * @@ -3174,11 +3458,10 @@ * look so _wonderfully_ clever, that I was not able * to stand against the temptation 8) --ANK */ - tp->ack.pending = 1; + tcp_schedule_ack(tp); tp->ack.lrcvtime = tcp_time_stamp; tcp_enter_quickack_mode(tp); - tp->ack.ato = TCP_ATO_MIN; - tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MIN); + tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX); goto discard; } else { tcp_send_ack(sk); @@ -3204,20 +3487,12 @@ if (th->syn) { /* We see SYN without ACK. It is attempt of - * simultaneous connect with crossed SYNs. - * - * The previous version of the code - * checked for "connecting to self" - * here. that check is done now in - * tcp_connect. - * - * RED-PEN: BTW, it does not. 8) + * simultaneous connect with crossed SYNs. + * Particularly, it can be connect to self. */ tcp_set_state(sk, TCP_SYN_RECV); - if (tp->saw_tstamp) { - tp->ts_recent = tp->rcv_tsval; - tp->ts_recent_stamp = xtime.tv_sec; - } + if (tp->saw_tstamp) + tcp_store_ts_recent(tp); tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; @@ -3232,6 +3507,8 @@ tcp_sync_mss(sk, tp->pmtu_cookie); tcp_initialize_rcv_mss(sk); + TCP_ECN_rcv_syn(tp, th); + tcp_send_synack(sk); #if 0 /* Note, we could accept data and URG from this segment. @@ -3251,7 +3528,7 @@ */ discard: - kfree_skb(skb); + __kfree_skb(skb); return 0; } @@ -3273,35 +3550,6 @@ switch (sk->state) { case TCP_CLOSE: - /* When state == CLOSED, hash lookup always fails. - * - * But, there is a back door, the backlog queue. - * If we have a sequence of packets in the backlog - * during __release_sock() which have a sequence such - * that: - * packet X causes entry to TCP_CLOSE state - * ... - * packet X + N has FIN bit set - * - * We report a (luckily) harmless error in this case. - * The issue is that backlog queue processing bypasses - * any hash lookups (we know which socket packets are for). - * The correct behavior here is what 2.0.x did, since - * a TCP_CLOSE socket does not exist. Drop the frame - * and send a RST back to the other end. - */ - - /* 1. The socket may be moved to TIME-WAIT state. - 2. While this socket was locked, another socket - with the same identity could be created. - 3. To continue? - - CONCLUSION: discard and only discard! - - Alternative would be relookup and recurse into tcp_v?_rcv - (not *_do_rcv) to work with timewait and listen states - correctly. - */ goto discard; case TCP_LISTEN: @@ -3340,56 +3588,20 @@ goto step6; } - /* Parse the tcp_options present on this header. - * By this point we really only expect timestamps. - * Note that this really has to be here and not later for PAWS - * (RFC1323) to work. - */ - if (tcp_fast_parse_options(sk, th, tp) && tp->saw_tstamp && + if (tcp_fast_parse_options(skb, th, tp) && tp->saw_tstamp && tcp_paws_discard(tp, skb)) { if (!th->rst) { - tcp_send_ack(sk); + NET_INC_STATS_BH(PAWSEstabRejected); + tcp_send_dupack(sk, skb); goto discard; } /* Reset is accepted even if it did not pass PAWS. */ } - /* The silly FIN test here is necessary to see an advancing ACK in - * retransmitted FIN frames properly. Consider the following sequence: - * - * host1 --> host2 FIN XSEQ:XSEQ(0) ack YSEQ - * host2 --> host1 FIN YSEQ:YSEQ(0) ack XSEQ - * host1 --> host2 XSEQ:XSEQ(0) ack YSEQ+1 - * host2 --> host1 FIN YSEQ:YSEQ(0) ack XSEQ+1 (fails tcp_sequence test) - * - * At this point the connection will deadlock with host1 believing - * that his FIN is never ACK'd, and thus it will retransmit it's FIN - * forever. The following fix is from Taral (taral@taral.net). - * - * RED-PEN. Seems, the above is not true. - * If at least one end is RFC compliant, it will send ACK to - * out of window FIN and, hence, move peer to TIME-WAIT. - * I comment out this line. --ANK - * - * RED-PEN. DANGER! tcp_sequence check rejects also SYN-ACKs - * received in SYN-RECV. The problem is that description of - * segment processing in SYN-RECV state in RFC792 is WRONG. - * Correct check would accept ACK from this SYN-ACK, see - * figures 6 and 8 (fixed by RFC1122). Compare this - * to problem with FIN, they smell similarly. --ANK - */ - /* step 1: check sequence number */ - if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq) -#if 0 - && !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt) -#endif - ) { - if (!th->rst) { - NET_INC_STATS_BH(DelayedACKLost); - tcp_enter_quickack_mode(tp); - tcp_send_ack(sk); - } + if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, th->rst)) { + if (!th->rst) + tcp_send_dupack(sk, skb); goto discard; } @@ -3399,10 +3611,7 @@ goto discard; } - if (tp->saw_tstamp) { - tcp_replace_ts_recent(sk, tp, - TCP_SKB_CB(skb)->seq); - } + tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); /* step 3: check security and precedence [ignored] */ @@ -3423,47 +3632,51 @@ */ if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) { + NET_INC_STATS_BH(TCPAbortOnSyn); tcp_reset(sk); return 1; } /* step 5: check the ACK field */ if (th->ack) { - int acceptable = tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->ack_seq, len); + int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH); switch(sk->state) { case TCP_SYN_RECV: if (acceptable) { - tcp_set_state(sk, TCP_ESTABLISHED); tp->copied_seq = tp->rcv_nxt; + mb(); + tcp_set_state(sk, TCP_ESTABLISHED); /* Note, that this wakeup is only for marginal * crossed SYN case. Passively open sockets * are not waked up, because sk->sleep == NULL * and sk->socket == NULL. */ - if (!sk->dead) { + if (sk->socket) { sk->state_change(sk); sk_wake_async(sk,0,POLL_OUT); } tp->snd_una = TCP_SKB_CB(skb)->ack_seq; tp->snd_wnd = ntohs(th->window) << tp->snd_wscale; - tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq; + tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq); /* tcp_ack considers this ACK as duplicate * and does not calculate rtt. * Fix it at least with timestamps. */ if (tp->saw_tstamp && !tp->srtt) - tcp_ack_saw_tstamp(sk, tp, 0, 0, FLAG_SYN_ACKED); + tcp_ack_saw_tstamp(tp); + + if (tp->tstamp_ok) + tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; tcp_init_metrics(sk); + tcp_initialize_rcv_mss(sk); + tcp_init_buffer_space(sk); tcp_fast_path_on(tp); } else { - SOCK_DEBUG(sk, "bad ack\n"); return 1; } break; @@ -3484,6 +3697,7 @@ (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) { tcp_done(sk); + NET_INC_STATS_BH(TCPAbortOnData); return 1; } @@ -3543,6 +3757,7 @@ if (sk->shutdown & RCV_SHUTDOWN) { if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { + NET_INC_STATS_BH(TCPAbortOnData); tcp_reset(sk); return 1; } @@ -3558,13 +3773,11 @@ if (sk->state != TCP_CLOSE) { tcp_data_snd_check(sk); tcp_ack_snd_check(sk); - if (tp->sorry) - tcp_new_space(sk); } if (!queued) { discard: - kfree_skb(skb); + __kfree_skb(skb); } return 0; } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.4.0-test6/linux/net/ipv4/tcp_ipv4.c Wed Aug 9 19:19:52 2000 +++ linux/net/ipv4/tcp_ipv4.c Fri Aug 18 10:26:25 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.210 2000/07/26 01:04:19 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.212 2000/08/18 17:10:04 davem Exp $ * * IPv4 specific functions * @@ -574,9 +574,8 @@ fall back to VJ's scheme and use initial timestamp retrieved from peer table. */ - if (tw->substate == TCP_TIME_WAIT && - sysctl_tcp_tw_recycle && tw->ts_recent_stamp) { - if ((tp->write_seq = tw->snd_nxt + 2) == 0) + if (tw->ts_recent_stamp) { + if ((tp->write_seq = tw->snd_nxt+65535+2) == 0) tp->write_seq = 1; tp->ts_recent = tw->ts_recent; tp->ts_recent_stamp = tw->ts_recent_stamp; @@ -691,7 +690,7 @@ daddr = rt->rt_dst; err = -ENOBUFS; - buff = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 0, GFP_KERNEL); + buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL); if (buff == NULL) goto failure; @@ -926,7 +925,7 @@ * we have no reasons to ignore it. */ if (sk->lock.users == 0) - tcp_enter_cong_avoid(tp); + tcp_enter_cwr(tp); goto out; case ICMP_PARAMETERPROB: err = EPROTO; @@ -1296,7 +1295,6 @@ { struct tcp_opt tp; struct open_request *req; - struct tcphdr *th = skb->h.th; __u32 saddr = skb->nh.iph->saddr; __u32 daddr = skb->nh.iph->daddr; __u32 isn = TCP_SKB_CB(skb)->when; @@ -1341,7 +1339,15 @@ tp.mss_clamp = 536; tp.user_mss = sk->tp_pinfo.af_tcp.user_mss; - tcp_parse_options(NULL, th, &tp, want_cookie); + tcp_parse_options(skb, &tp); + + if (want_cookie) { + tp.sack_ok = 0; + tp.wscale_ok = 0; + tp.snd_wscale = 0; + tp.tstamp_ok = 0; + tp.saw_tstamp = 0; + } if (tp.saw_tstamp && tp.rcv_tsval == 0) { /* Some OSes (unknown ones, but I see them on web server, which @@ -1359,6 +1365,8 @@ req->af.v4_req.rmt_addr = saddr; req->af.v4_req.opt = tcp_v4_save_options(sk, skb); req->class = &or_ipv4; + if (!want_cookie) + TCP_ECN_create_request(req, skb->h.th); if (want_cookie) { #ifdef CONFIG_SYN_COOKIES @@ -1384,8 +1392,6 @@ peer->v4daddr == saddr) { if (xtime.tv_sec < peer->tcp_ts_stamp + TCP_PAWS_MSL && (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) { - NETDEBUG(printk(KERN_DEBUG "TW_REC: reject openreq %u/%u %u.%u.%u.%u/%u\n", \ - peer->tcp_ts, req->ts_recent, NIPQUAD(saddr), ntohs(skb->h.th->source))); NET_INC_STATS_BH(PAWSPassiveRejected); dst_release(dst); goto drop_and_free; @@ -1470,10 +1476,8 @@ newtp->ext_header_len = newsk->protinfo.af_inet.opt->optlen; tcp_sync_mss(newsk, dst->pmtu); - tcp_initialize_rcv_mss(newsk); newtp->advmss = dst->advmss; - - tcp_init_buffer_space(newsk); + tcp_initialize_rcv_mss(newsk); __tcp_v4_hash(newsk); __tcp_inherit_port(sk, newsk); @@ -1493,33 +1497,30 @@ struct open_request *req, **prev; struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sock *nsk; /* Find possible connection requests. */ req = tcp_v4_search_req(tp, skb->nh.iph, th, &prev); if (req) return tcp_check_req(sk, skb, req, prev); - if (tp->accept_queue) { - struct sock *nsk; - - nsk = __tcp_v4_lookup_established(skb->nh.iph->saddr, - th->source, - skb->nh.iph->daddr, - ntohs(th->dest), - tcp_v4_iif(skb)); - - if (nsk) { - if (nsk->state != TCP_TIME_WAIT) { - bh_lock_sock(nsk); - return nsk; - } - tcp_tw_put((struct tcp_tw_bucket*)sk); - return NULL; + nsk = __tcp_v4_lookup_established(skb->nh.iph->saddr, + th->source, + skb->nh.iph->daddr, + ntohs(th->dest), + tcp_v4_iif(skb)); + + if (nsk) { + if (nsk->state != TCP_TIME_WAIT) { + bh_lock_sock(nsk); + return nsk; } + tcp_tw_put((struct tcp_tw_bucket*)sk); + return NULL; } #ifdef CONFIG_SYN_COOKIES - if (!th->rst && (th->syn || th->ack)) + if (!th->rst && !th->syn && th->ack) sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt)); #endif return sk; @@ -1534,8 +1535,8 @@ return -1; } skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) { - if (skb->len <= 68) { + } else { + if (skb->len <= 76) { if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr, skb->nh.iph->daddr, csum_partial((char *)skb->h.th, skb->len, 0))) @@ -1576,7 +1577,7 @@ return 0; } - if (tcp_checksum_complete(skb)) + if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb)) goto csum_err; if (sk->state == TCP_LISTEN) { @@ -1634,10 +1635,13 @@ /* Count it even if it's bad */ TCP_INC_STATS_BH(TcpInSegs); - if (len < sizeof(struct tcphdr)) - goto bad_packet; - - if (tcp_v4_checksum_init(skb) < 0) + /* An explanation is required here, I think. + * Packet length and doff are validated by header prediction, + * provided case of th->doff==0 is elimineted. + * So, we defer the checks. */ + if (th->doff < sizeof(struct tcphdr)/4 || + (skb->ip_summed != CHECKSUM_UNNECESSARY && + tcp_v4_checksum_init(skb) < 0)) goto bad_packet; TCP_SKB_CB(skb)->seq = ntohl(th->seq); @@ -1645,6 +1649,8 @@ len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->when = 0; + TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; + TCP_SKB_CB(skb)->sacked = 0; skb->used = 0; sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, @@ -1674,7 +1680,7 @@ return ret; no_tcp_socket: - if (tcp_checksum_complete(skb)) { + if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); } else { @@ -1691,7 +1697,7 @@ goto discard_it; do_time_wait: - if (tcp_checksum_complete(skb)) { + if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); goto discard_and_relse; } @@ -1734,7 +1740,8 @@ { struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); __u32 new_saddr; - int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT; + int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT && + !(sk->userlocks & SOCK_BINDADDR_LOCK); if (rt == NULL) { int err; @@ -1755,11 +1762,7 @@ __sk_dst_set(sk, &rt->u.dst); } - /* Force route checking if want_rewrite. - * The idea is good, the implementation is disguisting. - * Well, if I made bind on this socket, you cannot randomly ovewrite - * its source address. --ANK - */ + /* Force route checking if want_rewrite. */ if (want_rewrite) { int tmp; struct rtable *new_rt; @@ -1932,12 +1935,19 @@ tp->snd_cwnd_clamp = ~0; tp->mss_cache = 536; + tp->reordering = sysctl_tcp_reordering; + sk->state = TCP_CLOSE; sk->write_space = tcp_write_space; sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific; + sk->sndbuf = sysctl_tcp_wmem[1]; + sk->rcvbuf = sysctl_tcp_rmem[1]; + + atomic_inc(&tcp_sockets_allocated); + return 0; } @@ -1948,7 +1958,7 @@ tcp_clear_xmit_timers(sk); /* Cleanup up the write buffer. */ - __skb_queue_purge(&sk->write_queue); + tcp_writequeue_purge(sk); /* Cleans up our, hopefuly empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); @@ -1960,11 +1970,13 @@ if(sk->prev != NULL) tcp_put_port(sk); + atomic_dec(&tcp_sockets_allocated); + return 0; } /* Proc filesystem TCP sock list dumping. */ -static void get_openreq(struct sock *sk, struct open_request *req, char *tmpbuf, int i) +static void get_openreq(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid) { int ttd = req->expires - jiffies; @@ -1980,7 +1992,7 @@ 1, /* timers active (only the expire timer) */ ttd, req->retrans, - sk->socket ? sk->socket->inode->i_uid : 0, + uid, 0, /* non standard timer */ 0, /* open_requests have no inode */ atomic_read(&sk->refcnt), @@ -2000,33 +2012,31 @@ src = sp->rcv_saddr; destp = ntohs(sp->dport); srcp = ntohs(sp->sport); - timer_active = 0; - timer_expires = (unsigned) -1; - if (timer_pending(&tp->retransmit_timer) && tp->retransmit_timer.expires < timer_expires) { + if (tp->pending == TCP_TIME_RETRANS) { timer_active = 1; - timer_expires = tp->retransmit_timer.expires; - } else if (timer_pending(&tp->probe_timer) && tp->probe_timer.expires < timer_expires) { + timer_expires = tp->timeout; + } else if (tp->pending == TCP_TIME_PROBE0) { timer_active = 4; - timer_expires = tp->probe_timer.expires; - } - if (timer_pending(&sp->timer) && sp->timer.expires < timer_expires) { + timer_expires = tp->timeout; + } else if (timer_pending(&sp->timer)) { timer_active = 2; timer_expires = sp->timer.expires; - } - if(timer_active == 0) + } else { + timer_active = 0; timer_expires = jiffies; + } sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d", i, src, srcp, dest, destp, sp->state, tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, timer_active, timer_expires-jiffies, tp->retransmits, - sp->socket ? sp->socket->inode->i_uid : 0, + sock_i_uid(sp), tp->probes_out, - sp->socket ? sp->socket->inode->i_ino : 0, + sock_i_ino(sp), atomic_read(&sp->refcnt), sp, - tp->rto, tp->ack.ato, tp->ack.quick, tp->ack.pingpong + tp->rto, tp->ack.ato, tp->ack.quick, tp->ack.pingpong, sp->sndbuf ); } @@ -2051,18 +2061,20 @@ atomic_read(&tw->refcnt), tw); } +#define TMPSZ 150 + int tcp_get_info(char *buffer, char **start, off_t offset, int length) { int len = 0, num = 0, i; off_t begin, pos = 0; - char tmpbuf[129]; + char tmpbuf[TMPSZ+1]; - if (offset < 128) - len += sprintf(buffer, "%-127s\n", + if (offset < TMPSZ) + len += sprintf(buffer, "%-*s\n", TMPSZ-1, " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout inode"); - pos = 128; + pos = TMPSZ; /* First, walk listening socket table. */ tcp_listen_lock(); @@ -2073,15 +2085,16 @@ for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) { struct open_request *req; + int uid; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); if (!TCP_INET_FAMILY(sk->family)) goto skip_listen; - pos += 128; + pos += TMPSZ; if (pos >= offset) { get_tcp_sock(sk, tmpbuf, num); - len += sprintf(buffer+len, "%-127s\n", tmpbuf); + len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); if (len >= length) { tcp_listen_unlock(); goto out_no_bh; @@ -2089,6 +2102,7 @@ } skip_listen: + uid = sock_i_uid(sk); read_lock_bh(&tp->syn_wait_lock); lopt = tp->listen_opt; if (lopt && lopt->qlen != 0) { @@ -2097,11 +2111,11 @@ if (!TCP_INET_FAMILY(req->class->family)) continue; - pos += 128; + pos += TMPSZ; if (pos < offset) continue; - get_openreq(sk, req, tmpbuf, num); - len += sprintf(buffer+len, "%-127s\n", tmpbuf); + get_openreq(sk, req, tmpbuf, num, uid); + len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); if(len >= length) { read_unlock_bh(&tp->syn_wait_lock); tcp_listen_unlock(); @@ -2129,11 +2143,11 @@ for(sk = head->chain; sk; sk = sk->next, num++) { if (!TCP_INET_FAMILY(sk->family)) continue; - pos += 128; + pos += TMPSZ; if (pos < offset) continue; get_tcp_sock(sk, tmpbuf, num); - len += sprintf(buffer+len, "%-127s\n", tmpbuf); + len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); if(len >= length) { read_unlock(&head->lock); goto out; @@ -2144,11 +2158,11 @@ tw = (struct tcp_tw_bucket *)tw->next, num++) { if (!TCP_INET_FAMILY(tw->family)) continue; - pos += 128; + pos += TMPSZ; if (pos < offset) continue; get_timewait_sock(tw, tmpbuf, num); - len += sprintf(buffer+len, "%-127s\n", tmpbuf); + len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf); if(len >= length) { read_unlock(&head->lock); goto out; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/tcp_minisocks.c linux/net/ipv4/tcp_minisocks.c --- v2.4.0-test6/linux/net/ipv4/tcp_minisocks.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/tcp_minisocks.c Thu Aug 10 13:01:26 2000 @@ -0,0 +1,970 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Implementation of the Transmission Control Protocol(TCP). + * + * Version: $Id: tcp_minisocks.c,v 1.1 2000/08/09 11:59:04 davem Exp $ + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * Corey Minyard + * Florian La Roche, + * Charles Hedrick, + * Linus Torvalds, + * Alan Cox, + * Matthew Dillon, + * Arnt Gulbrandsen, + * Jorge Cwik, + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_SYSCTL +#define SYNC_INIT 0 /* let the user enable it */ +#else +#define SYNC_INIT 1 +#endif + +int sysctl_tcp_tw_recycle = 0; +int sysctl_tcp_max_tw_buckets = NR_FILE*2; + +int sysctl_tcp_syncookies = SYNC_INIT; +int sysctl_tcp_abort_on_overflow = 0; + +static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) +{ + if (seq == s_win) + return 1; + if (after(end_seq, s_win) && before(seq, e_win)) + return 1; + return (seq == e_win && seq == end_seq); +} + +/* New-style handling of TIME_WAIT sockets. */ + +int tcp_tw_count = 0; + + +/* Must be called with locally disabled BHs. */ +void tcp_timewait_kill(struct tcp_tw_bucket *tw) +{ + struct tcp_ehash_bucket *ehead; + struct tcp_bind_hashbucket *bhead; + struct tcp_bind_bucket *tb; + + /* Unlink from established hashes. */ + ehead = &tcp_ehash[tw->hashent]; + write_lock(&ehead->lock); + if (!tw->pprev) { + write_unlock(&ehead->lock); + return; + } + if(tw->next) + tw->next->pprev = tw->pprev; + *(tw->pprev) = tw->next; + tw->pprev = NULL; + write_unlock(&ehead->lock); + + /* Disassociate with bind bucket. */ + bhead = &tcp_bhash[tcp_bhashfn(tw->num)]; + spin_lock(&bhead->lock); + if ((tb = tw->tb) != NULL) { + if(tw->bind_next) + tw->bind_next->bind_pprev = tw->bind_pprev; + *(tw->bind_pprev) = tw->bind_next; + tw->tb = NULL; + if (tb->owners == NULL) { + if (tb->next) + tb->next->pprev = tb->pprev; + *(tb->pprev) = tb->next; + kmem_cache_free(tcp_bucket_cachep, tb); + } + } + spin_unlock(&bhead->lock); + +#ifdef INET_REFCNT_DEBUG + if (atomic_read(&tw->refcnt) != 1) { + printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, atomic_read(&tw->refcnt)); + } +#endif + tcp_tw_put(tw); +} + +/* + * * Main purpose of TIME-WAIT state is to close connection gracefully, + * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN + * (and, probably, tail of data) and one or more our ACKs are lost. + * * What is TIME-WAIT timeout? It is associated with maximal packet + * lifetime in the internet, which results in wrong conclusion, that + * it is set to catch "old duplicate segments" wandering out of their path. + * It is not quite correct. This timeout is calculated so that it exceeds + * maximal retransmision timeout enough to allow to lose one (or more) + * segments sent by peer and our ACKs. This time may be calculated from RTO. + * * When TIME-WAIT socket receives RST, it means that another end + * finally closed and we are allowed to kill TIME-WAIT too. + * * Second purpose of TIME-WAIT is catching old duplicate segments. + * Well, certainly it is pure paranoia, but if we load TIME-WAIT + * with this semantics, we MUST NOT kill TIME-WAIT state with RSTs. + * * If we invented some more clever way to catch duplicates + * (f.e. based on PAWS), we could truncate TIME-WAIT to several RTOs. + * + * The algorithm below is based on FORMAL INTERPRETATION of RFCs. + * When you compare it to RFCs, please, read section SEGMENT ARRIVES + * from the very beginning. + * + * NOTE. With recycling (and later with fin-wait-2) TW bucket + * is _not_ stateless. It means, that strictly speaking we must + * spinlock it. I do not want! Well, probability of misbehaviour + * is ridiculously low and, seems, we could use some mb() tricks + * to avoid misread sequence numbers, states etc. --ANK + */ +enum tcp_tw_status +tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, + struct tcphdr *th, unsigned len) +{ + struct tcp_opt tp; + int paws_reject = 0; + + tp.saw_tstamp = 0; + if (th->doff > (sizeof(struct tcphdr)>>2) && tw->ts_recent_stamp) { + tcp_parse_options(skb, &tp); + + if (tp.saw_tstamp) { + tp.ts_recent = tw->ts_recent; + tp.ts_recent_stamp = tw->ts_recent_stamp; + paws_reject = tcp_paws_check(&tp, th->rst); + } + } + + if (tw->substate == TCP_FIN_WAIT2) { + /* Just repeat all the checks of tcp_rcv_state_process() */ + + /* Out of window, send ACK */ + if (paws_reject || + !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, + tw->rcv_nxt, tw->rcv_nxt + tw->rcv_wnd)) + return TCP_TW_ACK; + + if (th->rst) + goto kill; + + if (th->syn && TCP_SKB_CB(skb)->seq != tw->syn_seq) + goto kill_with_rst; + + /* Dup ACK? */ + if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) || + TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { + tcp_tw_put(tw); + return TCP_TW_SUCCESS; + } + + /* New data or FIN. If new data arrive after half-duplex close, + * reset. + */ + if (!th->fin || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) { +kill_with_rst: + tcp_tw_deschedule(tw); + tcp_timewait_kill(tw); + tcp_tw_put(tw); + return TCP_TW_RST; + } + + /* FIN arrived, enter true time-wait state. */ + tw->substate = TCP_TIME_WAIT; + tw->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + if (tp.saw_tstamp) { + tw->ts_recent_stamp = xtime.tv_sec; + tw->ts_recent = tp.rcv_tsval; + } + + /* I am shamed, but failed to make it more elegant. + * Yes, it is direct reference to IP, which is impossible + * to generalize to IPv6. Taking into account that IPv6 + * do not undertsnad recycling in any case, it not + * a big problem in practice. --ANK */ + if (tw->family == AF_INET && + sysctl_tcp_tw_recycle && tw->ts_recent_stamp && + tcp_v4_tw_remember_stamp(tw)) + tcp_tw_schedule(tw, tw->timeout); + else + tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); + return TCP_TW_ACK; + } + + /* + * Now real TIME-WAIT state. + * + * RFC 1122: + * "When a connection is [...] on TIME-WAIT state [...] + * [a TCP] MAY accept a new SYN from the remote TCP to + * reopen the connection directly, if it: + * + * (1) assigns its initial sequence number for the new + * connection to be larger than the largest sequence + * number it used on the previous connection incarnation, + * and + * + * (2) returns to TIME-WAIT state if the SYN turns out + * to be an old duplicate". + */ + + if (!paws_reject && + (TCP_SKB_CB(skb)->seq == tw->rcv_nxt && + (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) { + /* In window segment, it may be only reset or bare ack. */ + + if (th->rst) { + /* This is TIME_WAIT assasination, in two flavors. + * Oh well... nobody has a sufficient solution to this + * protocol bug yet. + */ + if (sysctl_tcp_rfc1337 == 0) { +kill: + tcp_tw_deschedule(tw); + tcp_timewait_kill(tw); + tcp_tw_put(tw); + return TCP_TW_SUCCESS; + } + } + tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); + + if (tp.saw_tstamp) { + tw->ts_recent = tp.rcv_tsval; + tw->ts_recent_stamp = xtime.tv_sec; + } + + tcp_tw_put(tw); + return TCP_TW_SUCCESS; + } + + /* Out of window segment. + + All the segments are ACKed immediately. + + The only exception is new SYN. We accept it, if it is + not old duplicate and we are not in danger to be killed + by delayed old duplicates. RFC check is that it has + newer sequence number works at rates <40Mbit/sec. + However, if paws works, it is reliable AND even more, + we even may relax silly seq space cutoff. + + RED-PEN: we violate main RFC requirement, if this SYN will appear + old duplicate (i.e. we receive RST in reply to SYN-ACK), + we must return socket to time-wait state. It is not good, + but not fatal yet. + */ + + if (th->syn && !th->rst && !th->ack && !paws_reject && + (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) || + (tp.saw_tstamp && (s32)(tw->ts_recent - tp.rcv_tsval) < 0))) { + u32 isn = tw->snd_nxt+65535+2; + if (isn == 0) + isn++; + TCP_SKB_CB(skb)->when = isn; + return TCP_TW_SYN; + } + + if (paws_reject) + NET_INC_STATS_BH(PAWSEstabRejected); + + if(!th->rst) { + /* In this case we must reset the TIMEWAIT timer. + * + * If it is ACKless SYN it may be both old duplicate + * and new good SYN with random sequence number ack) + tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); + + /* Send ACK. Note, we do not put the bucket, + * it will be released by caller. + */ + return TCP_TW_ACK; + } + tcp_tw_put(tw); + return TCP_TW_SUCCESS; +} + +/* Enter the time wait state. This is called with locally disabled BH. + * Essentially we whip up a timewait bucket, copy the + * relevant info into it from the SK, and mess with hash chains + * and list linkage. + */ +static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) +{ + struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->hashent]; + struct tcp_bind_hashbucket *bhead; + struct sock **head, *sktw; + + write_lock(&ehead->lock); + + /* Step 1: Remove SK from established hash. */ + if (sk->pprev) { + if(sk->next) + sk->next->pprev = sk->pprev; + *sk->pprev = sk->next; + sk->pprev = NULL; + sock_prot_dec_use(sk->prot); + } + + /* Step 2: Hash TW into TIMEWAIT half of established hash table. */ + head = &(ehead + tcp_ehash_size)->chain; + sktw = (struct sock *)tw; + if((sktw->next = *head) != NULL) + (*head)->pprev = &sktw->next; + *head = sktw; + sktw->pprev = head; + atomic_inc(&tw->refcnt); + + write_unlock(&ehead->lock); + + /* Step 3: Put TW into bind hash. Original socket stays there too. + Note, that any socket with sk->num!=0 MUST be bound in binding + cache, even if it is closed. + */ + bhead = &tcp_bhash[tcp_bhashfn(sk->num)]; + spin_lock(&bhead->lock); + tw->tb = (struct tcp_bind_bucket *)sk->prev; + BUG_TRAP(sk->prev!=NULL); + if ((tw->bind_next = tw->tb->owners) != NULL) + tw->tb->owners->bind_pprev = &tw->bind_next; + tw->tb->owners = (struct sock*)tw; + tw->bind_pprev = &tw->tb->owners; + spin_unlock(&bhead->lock); +} + +/* + * Move a socket to time-wait or dead fin-wait-2 state. + */ +void tcp_time_wait(struct sock *sk, int state, int timeo) +{ + struct tcp_tw_bucket *tw = NULL; + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int recycle_ok = 0; + + if (sysctl_tcp_tw_recycle && tp->ts_recent_stamp) + recycle_ok = tp->af_specific->remember_stamp(sk); + + if (tcp_tw_count < sysctl_tcp_max_tw_buckets) + tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC); + + if(tw != NULL) { + int rto = (tp->rto<<2) - (tp->rto>>1); + + /* Give us an identity. */ + tw->daddr = sk->daddr; + tw->rcv_saddr = sk->rcv_saddr; + tw->bound_dev_if= sk->bound_dev_if; + tw->num = sk->num; + tw->state = TCP_TIME_WAIT; + tw->substate = state; + tw->sport = sk->sport; + tw->dport = sk->dport; + tw->family = sk->family; + tw->reuse = sk->reuse; + tw->rcv_wscale = tp->rcv_wscale; + atomic_set(&tw->refcnt, 0); + + tw->hashent = sk->hashent; + tw->rcv_nxt = tp->rcv_nxt; + tw->snd_nxt = tp->snd_nxt; + tw->rcv_wnd = tcp_receive_window(tp); + tw->syn_seq = tp->syn_seq; + tw->ts_recent = tp->ts_recent; + tw->ts_recent_stamp= tp->ts_recent_stamp; + tw->pprev_death = NULL; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if(tw->family == PF_INET6) { + memcpy(&tw->v6_daddr, + &sk->net_pinfo.af_inet6.daddr, + sizeof(struct in6_addr)); + memcpy(&tw->v6_rcv_saddr, + &sk->net_pinfo.af_inet6.rcv_saddr, + sizeof(struct in6_addr)); + } +#endif + /* Linkage updates. */ + __tcp_tw_hashdance(sk, tw); + + /* Get the TIME_WAIT timeout firing. */ + if (timeo < rto) + timeo = rto; + + if (recycle_ok) { + tw->timeout = rto; + } else { + tw->timeout = TCP_TIMEWAIT_LEN; + if (state == TCP_TIME_WAIT) + timeo = TCP_TIMEWAIT_LEN; + } + + tcp_tw_schedule(tw, timeo); + } else { + /* Sorry, if we're out of memory, just CLOSE this + * socket up. We've got bigger problems than + * non-graceful socket closings. + */ + if (net_ratelimit()) + printk(KERN_INFO "TCP: time wait bucket table overflow\n"); + } + + tcp_update_metrics(sk); + tcp_done(sk); +} + +/* Kill off TIME_WAIT sockets once their lifetime has expired. */ +static int tcp_tw_death_row_slot = 0; + +static void tcp_twkill(unsigned long); + +static struct tcp_tw_bucket *tcp_tw_death_row[TCP_TWKILL_SLOTS]; +static spinlock_t tw_death_lock = SPIN_LOCK_UNLOCKED; +static struct timer_list tcp_tw_timer = { function: tcp_twkill }; + +static void SMP_TIMER_NAME(tcp_twkill)(unsigned long dummy) +{ + struct tcp_tw_bucket *tw; + int killed = 0; + + /* NOTE: compare this to previous version where lock + * was released after detaching chain. It was racy, + * because tw buckets are scheduled in not serialized context + * in 2.3 (with netfilter), and with softnet it is common, because + * soft irqs are not sequenced. + */ + spin_lock(&tw_death_lock); + + if (tcp_tw_count == 0) + goto out; + + while((tw = tcp_tw_death_row[tcp_tw_death_row_slot]) != NULL) { + tcp_tw_death_row[tcp_tw_death_row_slot] = tw->next_death; + tw->pprev_death = NULL; + spin_unlock(&tw_death_lock); + + tcp_timewait_kill(tw); + tcp_tw_put(tw); + + killed++; + + spin_lock(&tw_death_lock); + } + tcp_tw_death_row_slot = + ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1)); + + if ((tcp_tw_count -= killed) != 0) + mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD); + net_statistics[smp_processor_id()*2].TimeWaited += killed; +out: + spin_unlock(&tw_death_lock); +} + +SMP_TIMER_DEFINE(tcp_twkill, tcp_twkill_task); + +/* These are always called from BH context. See callers in + * tcp_input.c to verify this. + */ + +/* This is for handling early-kills of TIME_WAIT sockets. */ +void tcp_tw_deschedule(struct tcp_tw_bucket *tw) +{ + spin_lock(&tw_death_lock); + if (tw->pprev_death) { + if(tw->next_death) + tw->next_death->pprev_death = tw->pprev_death; + *tw->pprev_death = tw->next_death; + tw->pprev_death = NULL; + tcp_tw_put(tw); + if (--tcp_tw_count == 0) + del_timer(&tcp_tw_timer); + } + spin_unlock(&tw_death_lock); +} + +/* Short-time timewait calendar */ + +static int tcp_twcal_hand = -1; +static int tcp_twcal_jiffie; +static void tcp_twcal_tick(unsigned long); +static struct timer_list tcp_twcal_timer = {function: tcp_twcal_tick}; +static struct tcp_tw_bucket *tcp_twcal_row[TCP_TW_RECYCLE_SLOTS]; + +void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo) +{ + struct tcp_tw_bucket **tpp; + int slot; + + /* timeout := RTO * 3.5 + * + * 3.5 = 1+2+0.5 to wait for two retransmits. + * + * RATIONALE: if FIN arrived and we entered TIME-WAIT state, + * our ACK acking that FIN can be lost. If N subsequent retransmitted + * FINs (or previous seqments) are lost (probability of such event + * is p^(N+1), where p is probability to lose single packet and + * time to detect the loss is about RTO*(2^N - 1) with exponential + * backoff). Normal timewait length is calculated so, that we + * waited at least for one retransmitted FIN (maximal RTO is 120sec). + * [ BTW Linux. following BSD, violates this requirement waiting + * only for 60sec, we should wait at least for 240 secs. + * Well, 240 consumes too much of resources 8) + * ] + * This interval is not reduced to catch old duplicate and + * responces to our wandering segments living for two MSLs. + * However, if we use PAWS to detect + * old duplicates, we can reduce the interval to bounds required + * by RTO, rather than MSL. So, if peer understands PAWS, we + * kill tw bucket after 3.5*RTO (it is important that this number + * is greater than TS tick!) and detect old duplicates with help + * of PAWS. + */ + slot = (timeo + (1<> TCP_TW_RECYCLE_TICK; + + spin_lock(&tw_death_lock); + + /* Unlink it, if it was scheduled */ + if (tw->pprev_death) { + if(tw->next_death) + tw->next_death->pprev_death = tw->pprev_death; + *tw->pprev_death = tw->next_death; + tw->pprev_death = NULL; + tcp_tw_count--; + } else + atomic_inc(&tw->refcnt); + + if (slot >= TCP_TW_RECYCLE_SLOTS) { + /* Schedule to slow timer */ + if (timeo >= TCP_TIMEWAIT_LEN) { + slot = TCP_TWKILL_SLOTS-1; + } else { + slot = (timeo + TCP_TWKILL_PERIOD-1) / TCP_TWKILL_PERIOD; + if (slot >= TCP_TWKILL_SLOTS) + slot = TCP_TWKILL_SLOTS-1; + } + tw->ttd = jiffies + timeo; + slot = (tcp_tw_death_row_slot + slot) & (TCP_TWKILL_SLOTS - 1); + tpp = &tcp_tw_death_row[slot]; + } else { + tw->ttd = jiffies + (slot< (slot<next_death = *tpp) != NULL) + (*tpp)->pprev_death = &tw->next_death; + *tpp = tw; + tw->pprev_death = tpp; + + if (tcp_tw_count++ == 0) + mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD); + spin_unlock(&tw_death_lock); +} + +void SMP_TIMER_NAME(tcp_twcal_tick)(unsigned long dummy) +{ + int n, slot; + unsigned long j; + unsigned long now = jiffies; + int killed = 0; + int adv = 0; + + spin_lock(&tw_death_lock); + if (tcp_twcal_hand < 0) + goto out; + + slot = tcp_twcal_hand; + j = tcp_twcal_jiffie; + + for (n=0; nnext_death; + tw->pprev_death = NULL; + + tcp_timewait_kill(tw); + tcp_tw_put(tw); + killed++; + } + } else { + if (!adv) { + adv = 1; + tcp_twcal_jiffie = j; + tcp_twcal_hand = slot; + } + + if (tcp_twcal_row[slot] != NULL) { + mod_timer(&tcp_twcal_timer, j); + goto out; + } + } + j += (1<state = TCP_SYN_RECV; + + /* SANITY */ + newsk->pprev = NULL; + newsk->prev = NULL; + + /* Clone the TCP header template */ + newsk->dport = req->rmt_port; + + sock_lock_init(newsk); + bh_lock_sock(newsk); + + atomic_set(&newsk->rmem_alloc, 0); + skb_queue_head_init(&newsk->receive_queue); + atomic_set(&newsk->wmem_alloc, 0); + skb_queue_head_init(&newsk->write_queue); + atomic_set(&newsk->omem_alloc, 0); + newsk->wmem_queued = 0; + newsk->forward_alloc = 0; + + newsk->done = 0; + newsk->proc = 0; + newsk->backlog.head = newsk->backlog.tail = NULL; + skb_queue_head_init(&newsk->error_queue); + newsk->write_space = tcp_write_space; +#ifdef CONFIG_FILTER + if ((filter = newsk->filter) != NULL) + sk_filter_charge(newsk, filter); +#endif + + /* Now setup tcp_opt */ + newtp = &(newsk->tp_pinfo.af_tcp); + newtp->pred_flags = 0; + newtp->rcv_nxt = req->rcv_isn + 1; + newtp->snd_nxt = req->snt_isn + 1; + newtp->snd_una = req->snt_isn + 1; + newtp->snd_sml = req->snt_isn + 1; + + tcp_delack_init(newtp); + + tcp_prequeue_init(newtp); + + tcp_init_wl(newtp, req->snt_isn, req->rcv_isn); + + newtp->retransmits = 0; + newtp->backoff = 0; + newtp->srtt = 0; + newtp->mdev = TCP_TIMEOUT_INIT; + newtp->rto = TCP_TIMEOUT_INIT; + + newtp->packets_out = 0; + newtp->left_out = 0; + newtp->retrans_out = 0; + newtp->sacked_out = 0; + newtp->fackets_out = 0; + newtp->snd_ssthresh = 0x7fffffff; + + /* So many TCP implementations out there (incorrectly) count the + * initial SYN frame in their delayed-ACK and congestion control + * algorithms that we must have the following bandaid to talk + * efficiently to them. -DaveM + */ + newtp->snd_cwnd = 2; + newtp->snd_cwnd_cnt = 0; + + newtp->ca_state = TCP_CA_Open; + tcp_init_xmit_timers(newsk); + skb_queue_head_init(&newtp->out_of_order_queue); + newtp->send_head = NULL; + newtp->rcv_wup = req->rcv_isn + 1; + newtp->write_seq = req->snt_isn + 1; + newtp->pushed_seq = newtp->write_seq; + newtp->copied_seq = req->rcv_isn + 1; + + newtp->saw_tstamp = 0; + + newtp->dsack = 0; + newtp->eff_sacks = 0; + + newtp->probes_out = 0; + newtp->num_sacks = 0; + newtp->syn_seq = req->rcv_isn; + newtp->fin_seq = req->rcv_isn; + newtp->urg_data = 0; + newtp->listen_opt = NULL; + newtp->accept_queue = newtp->accept_queue_tail = NULL; + /* Deinitialize syn_wait_lock to trap illegal accesses. */ + memset(&newtp->syn_wait_lock, 0, sizeof(newtp->syn_wait_lock)); + + /* Back to base struct sock members. */ + newsk->err = 0; + newsk->priority = 0; + atomic_set(&newsk->refcnt, 1); +#ifdef INET_REFCNT_DEBUG + atomic_inc(&inet_sock_nr); +#endif + atomic_inc(&tcp_sockets_allocated); + + if (newsk->keepopen) + tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp)); + newsk->socket = NULL; + newsk->sleep = NULL; + + newtp->tstamp_ok = req->tstamp_ok; + if((newtp->sack_ok = req->sack_ok) != 0) { + if (sysctl_tcp_fack) + newtp->sack_ok |= 2; + } + newtp->window_clamp = req->window_clamp; + newtp->rcv_ssthresh = req->rcv_wnd; + newtp->rcv_wnd = req->rcv_wnd; + newtp->wscale_ok = req->wscale_ok; + if (newtp->wscale_ok) { + newtp->snd_wscale = req->snd_wscale; + newtp->rcv_wscale = req->rcv_wscale; + } else { + newtp->snd_wscale = newtp->rcv_wscale = 0; + newtp->window_clamp = min(newtp->window_clamp,65535); + } + newtp->snd_wnd = ntohs(skb->h.th->window) << newtp->snd_wscale; + newtp->max_window = newtp->snd_wnd; + + if (newtp->tstamp_ok) { + newtp->ts_recent = req->ts_recent; + newtp->ts_recent_stamp = xtime.tv_sec; + newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + } else { + newtp->ts_recent_stamp = 0; + newtp->tcp_header_len = sizeof(struct tcphdr); + } + if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len) + newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len; + newtp->mss_clamp = req->mss; + TCP_ECN_openreq_child(newtp, req); + } + return newsk; +} + +/* + * Process an incoming packet for SYN_RECV sockets represented + * as an open_request. + */ + +struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, + struct open_request *req, + struct open_request **prev) +{ + struct tcphdr *th = skb->h.th; + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); + int paws_reject = 0; + struct tcp_opt ttp; + struct sock *child; + + ttp.saw_tstamp = 0; + if (th->doff > (sizeof(struct tcphdr)>>2)) { + tcp_parse_options(skb, &ttp); + + if (ttp.saw_tstamp) { + ttp.ts_recent = req->ts_recent; + /* We do not store true stamp, but it is not required, + * it can be estimated (approximately) + * from another data. + */ + ttp.ts_recent_stamp = xtime.tv_sec - ((TCP_TIMEOUT_INIT/HZ)<retrans); + paws_reject = tcp_paws_check(&ttp, th->rst); + } + } + + /* Check for pure retransmited SYN. */ + if (TCP_SKB_CB(skb)->seq == req->rcv_isn && + flg == TCP_FLAG_SYN && + !paws_reject) { + /* + * RFC793 draws (Incorrectly! It was fixed in RFC1122) + * this case on figure 6 and figure 8, but formal + * protocol description says NOTHING. + * To be more exact, it says that we should send ACK, + * because this segment (at least, if it has no data) + * is out of window. + * + * CONCLUSION: RFC793 (even with RFC1122) DOES NOT + * describe SYN-RECV state. All the description + * is wrong, we cannot believe to it and should + * rely only on common sense and implementation + * experience. + * + * Enforce "SYN-ACK" according to figure 8, figure 6 + * of RFC793, fixed by RFC1122. + */ + req->class->rtx_syn_ack(sk, req, NULL); + return NULL; + } + + /* Further reproduces section "SEGMENT ARRIVES" + for state SYN-RECEIVED of RFC793. + It is broken, however, it does not work only + when SYNs are crossed, which is impossible in our + case. + + But generally, we should (RFC lies!) to accept ACK + from SYNACK both here and in tcp_rcv_state_process(). + tcp_rcv_state_process() does not, hence, we do not too. + + Note that the case is absolutely generic: + we cannot optimize anything here without + violating protocol. All the checks must be made + before attempt to create socket. + */ + + /* RFC793: "first check sequence number". */ + + if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, + req->rcv_isn+1, req->rcv_isn+1+req->rcv_wnd)) { + /* Out of window: send ACK and drop. */ + if (!(flg & TCP_FLAG_RST)) + req->class->send_ack(skb, req); + if (paws_reject) + NET_INC_STATS_BH(PAWSEstabRejected); + return NULL; + } + + /* In sequence, PAWS is OK. */ + + if (ttp.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1)) + req->ts_recent = ttp.rcv_tsval; + + if (TCP_SKB_CB(skb)->seq == req->rcv_isn) { + /* Truncate SYN, it is out of window starting + at req->rcv_isn+1. */ + flg &= ~TCP_FLAG_SYN; + } + + /* RFC793: "second check the RST bit" and + * "fourth, check the SYN bit" + */ + if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) + goto embryonic_reset; + + /* RFC793: "fifth check the ACK field" */ + + if (!(flg & TCP_FLAG_ACK)) + return NULL; + + /* Invalid ACK: reset will be sent by listening socket */ + if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1) + return sk; + /* Also, it would be not so bad idea to check rcv_tsecr, which + * is essentially ACK extension and too early or too late values + * should cause reset in unsynchronized states. + */ + + /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ + if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) { + req->acked = 1; + return NULL; + } + + /* OK, ACK is valid, create big socket and + * feed this segment to it. It will repeat all + * the tests. THIS SEGMENT MUST MOVE SOCKET TO + * ESTABLISHED STATE. If it will be dropped after + * socket is created, wait for troubles. + */ + child = tp->af_specific->syn_recv_sock(sk, skb, req, NULL); + if (child == NULL) + goto listen_overflow; + + tcp_synq_unlink(tp, req, prev); + tcp_synq_removed(sk, req); + + tcp_acceptq_queue(sk, req, child); + return child; + +listen_overflow: + if (!sysctl_tcp_abort_on_overflow) { + req->acked = 1; + return NULL; + } + +embryonic_reset: + NET_INC_STATS_BH(EmbryonicRsts); + if (!(flg & TCP_FLAG_RST)) + req->class->send_reset(skb); + + tcp_synq_drop(sk, req, prev); + return NULL; +} + +/* + * Queue segment on the new socket if the new socket is active, + * otherwise we just shortcircuit this and continue with + * the new socket. + */ + +int tcp_child_process(struct sock *parent, struct sock *child, + struct sk_buff *skb) +{ + int ret = 0; + int state = child->state; + + if (child->lock.users == 0) { + ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len); + + /* Wakeup parent, send SIGIO */ + if (state == TCP_SYN_RECV && child->state != state) + parent->data_ready(parent, 0); + } else { + /* Alas, it is possible again, because we do lookup + * in main socket hash table and lock on listening + * socket does not protect us more. + */ + sk_add_backlog(child, skb); + } + + bh_unlock_sock(child); + return ret; +} diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.4.0-test6/linux/net/ipv4/tcp_output.c Wed Apr 26 16:34:09 2000 +++ linux/net/ipv4/tcp_output.c Fri Aug 18 10:26:25 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.124 2000/04/08 07:21:24 davem Exp $ + * Version: $Id: tcp_output.c,v 1.127 2000/08/15 20:15:23 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -32,6 +32,7 @@ * David S. Miller : Output engine completely rewritten. * Andrea Arcangeli: SYNACK carry ts_recent in tsecr. * Cacophonix Gaul : draft-minshall-nagle-01 + * J Hadi Salim : ECN support * */ @@ -42,13 +43,29 @@ /* People can turn this off for buggy TCP's found in printers etc. */ int sysctl_tcp_retrans_collapse = 1; -static __inline__ void update_send_head(struct sock *sk) +static __inline__ +void update_send_head(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) { - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - - tp->send_head = tp->send_head->next; + tp->send_head = skb->next; if (tp->send_head == (struct sk_buff *) &sk->write_queue) tp->send_head = NULL; + tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; + if (tp->packets_out++ == 0) + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); +} + +/* SND.NXT, if window was not shrunk. + * If window has been shrunk, what should we make? It is not clear at all. + * Using SND.UNA we will fail to open window, SND.NXT is out of window. :-( + * Anything in between SND.UNA...SND.UNA+SND.WND also can be already + * invalid. OK, let's make this for now: + */ +static __inline__ __u32 tcp_acceptable_seq(struct sock *sk, struct tcp_opt *tp) +{ + if (!before(tp->snd_una+tp->snd_wnd, tp->snd_nxt)) + return tp->snd_nxt; + else + return tp->snd_una+tp->snd_wnd; } /* Calculate mss to advertise in SYN segment. @@ -79,15 +96,38 @@ return (__u16)mss; } +/* RFC2861. Reset CWND after idle period longer RTO to "restart window". + * This is the first part of cwnd validation mechanism. */ +static void tcp_cwnd_restart(struct tcp_opt *tp) +{ + s32 delta = tcp_time_stamp - tp->lsndtime; + u32 restart_cwnd = tcp_init_cwnd(tp); + u32 cwnd = tp->snd_cwnd; + + tp->snd_ssthresh = tcp_current_ssthresh(tp); + restart_cwnd = min(restart_cwnd, cwnd); + + while ((delta -= tp->rto) > 0 && cwnd > restart_cwnd) + cwnd >>= 1; + tp->snd_cwnd = max(cwnd, restart_cwnd); + tp->snd_cwnd_stamp = tcp_time_stamp; + tp->snd_cwnd_used = 0; +} + static __inline__ void tcp_event_data_sent(struct tcp_opt *tp, struct sk_buff *skb) { - /* If we had a reply for ato after last received + u32 now = tcp_time_stamp; + + if (!tp->packets_out && (s32)(now - tp->lsndtime) > tp->rto) + tcp_cwnd_restart(tp); + + tp->lsndtime = now; + + /* If it is a reply for ato after last received * packet, enter pingpong mode. */ - if ((u32)(tp->lsndtime - tp->ack.lrcvtime) < tp->ack.ato) + if ((u32)(now - tp->ack.lrcvtime) < tp->ack.ato) tp->ack.pingpong = 1; - - tp->lsndtime = tcp_time_stamp; } static __inline__ void tcp_event_ack_sent(struct sock *sk) @@ -95,11 +135,56 @@ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); tcp_dec_quickack_mode(tp); - tp->ack.pending = 0; - tp->ack.rcv_segs = 0; tcp_clear_xmit_timer(sk, TCP_TIME_DACK); } +/* Chose a new window to advertise, update state in tcp_opt for the + * socket, and return result with RFC1323 scaling applied. The return + * value can be stuffed directly into th->window for an outgoing + * frame. + */ +static __inline__ u16 tcp_select_window(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + u32 cur_win = tcp_receive_window(tp); + u32 new_win = __tcp_select_window(sk); + + /* Never shrink the offered window */ + if(new_win < cur_win) { + /* Danger Will Robinson! + * Don't update rcv_wup/rcv_wnd here or else + * we will not be able to advertise a zero + * window in time. --DaveM + * + * Relax Will Robinson. + */ + new_win = cur_win; + } + tp->rcv_wnd = new_win; + tp->rcv_wup = tp->rcv_nxt; + + /* RFC1323 scaling applied */ + new_win >>= tp->rcv_wscale; + +#ifdef TCP_FORMAL_WINDOW + if (new_win == 0) { + /* If we advertise zero window, disable fast path. */ + tp->pred_flags = 0; + } else if (cur_win == 0 && tp->pred_flags == 0 && + skb_queue_len(&tp->out_of_order_queue) == 0 && + !tp->urg_data) { + /* If we open zero window, enable fast path. + Without this it will be open by the first data packet, + it is too late to merge checksumming to copy. + */ + tcp_fast_path_on(tp); + } +#endif + + return new_win; +} + + /* This routine actually transmits TCP packets queued in by * tcp_do_sendmsg(). This is used by both the initial * transmission and possible later retransmissions. @@ -141,12 +226,12 @@ if(!(sysctl_flags & SYSCTL_FLAG_TSTAMPS)) tcp_header_size += TCPOLEN_SACKPERM_ALIGNED; } - } else if (tp->num_sacks) { + } else if (tp->eff_sacks) { /* A SACK is 2 pad bytes, a 2 byte header, plus * 2 32-bit sequence numbers for each SACK block. */ tcp_header_size += (TCPOLEN_SACK_BASE_ALIGNED + - (tp->num_sacks * TCPOLEN_SACK_PERBLOCK)); + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); } th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; @@ -155,7 +240,7 @@ /* Build TCP header and checksum it. */ th->source = sk->sport; th->dest = sk->dport; - th->seq = htonl(TCP_SKB_CB(skb)->seq); + th->seq = htonl(tcb->seq); th->ack_seq = htonl(tp->rcv_nxt); *(((__u16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | tcb->flags); if (tcb->flags & TCPCB_FLAG_SYN) { @@ -176,11 +261,13 @@ (sysctl_flags & SYSCTL_FLAG_SACK), (sysctl_flags & SYSCTL_FLAG_WSCALE), tp->rcv_wscale, - TCP_SKB_CB(skb)->when, + tcb->when, tp->ts_recent); } else { tcp_build_and_update_options((__u32 *)(th + 1), - tp, TCP_SKB_CB(skb)->when); + tp, tcb->when); + + TCP_ECN_send(sk, tp, skb, tcp_header_size); } tp->af_specific->send_check(sk, th, skb->len, skb); @@ -196,7 +283,7 @@ if (err <= 0) return err; - tcp_enter_cong_avoid(tp); + tcp_enter_cwr(tp); /* NET_XMIT_CN is special. It does not guarantee, * that this packet is lost. It tells that device @@ -212,6 +299,7 @@ #undef SYSCTL_FLAG_SACK } + /* This is the main buffer sending routine. We queue the buffer * and decide whether to queue or transmit now. * @@ -225,15 +313,15 @@ /* Advance write_seq and place onto the write_queue. */ tp->write_seq = TCP_SKB_CB(skb)->end_seq; __skb_queue_tail(&sk->write_queue, skb); + tcp_charge_skb(sk, skb); if (!force_queue && tp->send_head == NULL && tcp_snd_test(tp, skb, cur_mss, 1)) { /* Send it out now. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; if (tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)) == 0) { tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; - tcp_minshall_update(tp, cur_mss, skb->len); - tp->packets_out++; - if(!tcp_timer_is_set(sk, TCP_TIME_RETRANS)) + tcp_minshall_update(tp, cur_mss, skb); + if (tp->packets_out++ == 0) tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); return; } @@ -250,16 +338,16 @@ */ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len) { + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct sk_buff *buff; int nsize = skb->len - len; u16 flags; /* Get a new skb... force flag on. */ - buff = sock_wmalloc(sk, - (nsize + MAX_TCP_HEADER + 15), - 1, GFP_ATOMIC); + buff = tcp_alloc_skb(sk, nsize + MAX_TCP_HEADER + 15, GFP_ATOMIC); if (buff == NULL) return -ENOMEM; /* We'll just try again later. */ + tcp_charge_skb(sk, buff); /* Reserve space for headers. */ skb_reserve(buff, MAX_TCP_HEADER); @@ -286,7 +374,11 @@ if(!(flags & TCPCB_FLAG_URG)) TCP_SKB_CB(buff)->urg_ptr = 0; TCP_SKB_CB(buff)->flags = flags; - TCP_SKB_CB(buff)->sacked = 0; + TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked&(TCPCB_LOST|TCPCB_EVER_RETRANS); + if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) { + tp->lost_out++; + tp->left_out++; + } /* Copy and checksum data tail into the new buffer. */ buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), @@ -301,11 +393,6 @@ /* Looks stupid, but our code really uses when of * skbs, which it never sent before. --ANK - * - * NOTE: several days after I added this, Dave repaired - * tcp_simple_retransmit() and it should not use ->when - * of never sent skbs more. I am not sure, so that - * this line remains until more careful investigation. --ANK */ TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when; @@ -401,13 +488,6 @@ */ mss_now = tcp_current_mss(sk); - /* Anything on the transmit queue that fits the window can - * be added providing we are: - * - * a) following SWS avoidance [and Nagle algorithm] - * b) not exceeding our congestion window. - * c) not retransmitting [Nagle] - */ while((skb = tp->send_head) && tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb))) { if (skb->len > mss_now) { @@ -419,19 +499,13 @@ if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC))) break; /* Advance the send_head. This one is sent out. */ - update_send_head(sk); - tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; - tcp_minshall_update(tp, mss_now, skb->len); - tp->packets_out++; + update_send_head(sk, tp, skb); + tcp_minshall_update(tp, mss_now, skb); sent_pkts = 1; } - /* If we sent anything, make sure the retransmit - * timer is active. - */ if (sent_pkts) { - if (!tcp_timer_is_set(sk, TCP_TIME_RETRANS)) - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + tcp_cwnd_validate(sk, tp); return 0; } @@ -506,28 +580,22 @@ /* Sometimes free_space can be < 0. */ free_space = tcp_space(sk); - if (free_space > ((int) tp->window_clamp)) - free_space = tp->window_clamp; if (tp->window_clamp < mss) mss = tp->window_clamp; - if (free_space < min((int)tp->window_clamp, tcp_full_space(sk)) / 2) { - /* THIS IS _VERY_ GOOD PLACE to play window clamp. - * if free_space becomes suspiciously low - * verify ratio rmem_alloc/(rcv_nxt - copied_seq), - * and if we predict that when free_space will be lower mss, - * rmem_alloc will run out of rcvbuf*2, shrink window_clamp. - * It will eliminate most of prune events! Very simple, - * it is the next thing to do. --ANK - * - * Provided we found a way to raise it back... --ANK - */ + if (free_space < (int)min(tp->window_clamp, tcp_full_space(sk)) / 2) { tp->ack.quick = 0; + if (tcp_memory_pressure) + tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4*tp->advmss); + if (free_space < ((int) (mss/2))) return 0; } + if (free_space > tp->rcv_ssthresh) + free_space = tp->rcv_ssthresh; + /* Get the largest window that is a nice multiple of mss. * Window clamp already applied above. * If our current window offering is within 1 mss of the @@ -547,6 +615,7 @@ /* Attempt to collapse two adjacent SKB's during retransmission. */ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int mss_now) { + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct sk_buff *next_skb = skb->next; /* The first test we must make is that neither of these two @@ -564,6 +633,10 @@ if(TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_ACKED) return; + /* Next skb is out of window. */ + if (after(TCP_SKB_CB(next_skb)->end_seq, tp->snd_una+tp->snd_wnd)) + return; + /* Punt if not enough space exists in the first SKB for * the data in the second, or the total combined payload * would exceed the MSS. @@ -602,8 +675,20 @@ /* All done, get rid of second SKB and account for it so * packet counting does not break. */ - kfree_skb(next_skb); - sk->tp_pinfo.af_tcp.packets_out--; + TCP_SKB_CB(skb)->sacked |= TCP_SKB_CB(next_skb)->sacked&TCPCB_EVER_RETRANS; + if (TCP_SKB_CB(next_skb)->sacked&TCPCB_SACKED_RETRANS) + tp->retrans_out--; + if (TCP_SKB_CB(next_skb)->sacked&TCPCB_LOST) { + tp->lost_out--; + tp->left_out--; + } + if (!tp->sack_ok && tp->sacked_out) { + /* Reno case is special. Sigh... */ + tp->sacked_out--; + tp->left_out--; + } + tcp_free_skb(sk, next_skb); + tp->packets_out--; } } @@ -614,53 +699,43 @@ void tcp_simple_retransmit(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct sk_buff *skb, *old_next_skb; + struct sk_buff *skb; unsigned int mss = tcp_current_mss(sk); + int lost = 0; - /* Don't muck with the congestion window here. */ - tp->dup_acks = 0; - tp->high_seq = tp->snd_nxt; - tp->retrans_head = NULL; - - /* Input control flow will see that this was retransmitted - * and not use it for RTT calculation in the absence of - * the timestamp option. - */ - for (old_next_skb = skb = skb_peek(&sk->write_queue); - ((skb != tp->send_head) && - (skb != (struct sk_buff *)&sk->write_queue)); - skb = skb->next) { - int resend_skb = 0; - - /* Our goal is to push out the packets which we - * sent already, but are being chopped up now to - * account for the PMTU information we have. - * - * As we resend the queue, packets are fragmented - * into two pieces, and when we try to send the - * second piece it may be collapsed together with - * a subsequent packet, and so on. -DaveM - */ - if (old_next_skb != skb || skb->len > mss) - resend_skb = 1; - old_next_skb = skb->next; - if (resend_skb != 0) { - if (tcp_retransmit_skb(sk, skb)) - break; + for_retrans_queue(skb, sk, tp) { + if (skb->len > mss && + !(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) { + if (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; + tp->retrans_out--; + } + if (!(TCP_SKB_CB(skb)->sacked&TCPCB_LOST)) { + TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; + tp->lost_out++; + lost = 1; + } } } -} -static __inline__ void update_retrans_head(struct sock *sk) -{ - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - - tp->retrans_head = tp->retrans_head->next; - if((tp->retrans_head == tp->send_head) || - (tp->retrans_head == (struct sk_buff *) &sk->write_queue)) { - tp->retrans_head = NULL; - tp->rexmt_done = 1; + if (!lost) + return; + + tp->left_out = tp->sacked_out + tp->lost_out; + + /* Don't muck with the congestion window here. + * Reason is that we do not increase amount of _data_ + * in network, but units changed and effective + * cwnd/ssthresh really reduced now. + */ + if (tp->ca_state != TCP_CA_Loss) { + tp->high_seq = tp->snd_nxt; + tp->snd_ssthresh = tcp_current_ssthresh(tp); + tp->prior_ssthresh = 0; + tp->undo_marker = 0; + tp->ca_state = TCP_CA_Loss; } + tcp_xmit_retransmit_queue(sk); } /* This retransmits one SKB. Policy decisions and retransmit queue @@ -671,18 +746,13 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); unsigned int cur_mss = tcp_current_mss(sk); + int err; -#ifdef TCP_DEBUG - /* It was possible this summer, that retransmit timer - * raced with its deletion and hit socket with packets_out==0. - * I fixed it, but preserved the check in the place, - * where the fault occured. --ANK + /* Do not sent more than we queued. 1/4 is reserved for possible + * copying overhead: frgagmentation, tunneling, mangling etc. */ - if (skb == NULL) { - printk("tcp_retransmit_skb: bug, skb==NULL, caller=%p\n", NET_CALLER(sk)); - return -EFAULT; - } -#endif + if (atomic_read(&sk->wmem_alloc) > min(sk->wmem_queued+(sk->wmem_queued>>2),sk->sndbuf)) + return -EAGAIN; if(skb->len > cur_mss) { if(tcp_fragment(sk, skb, cur_mss)) @@ -715,23 +785,40 @@ skb->csum = 0; } - /* Ok, we're gonna send it out, update state. */ - TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_RETRANS; - tp->retrans_out++; - /* Make a copy, if the first transmission SKB clone we made * is still in somebody's hands, else make a clone. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; - if(skb_cloned(skb)) - skb = skb_copy(skb, GFP_ATOMIC); - else - skb = skb_clone(skb, GFP_ATOMIC); - /* Update global TCP statistics and return success. */ - TCP_INC_STATS(TcpRetransSegs); + err = tcp_transmit_skb(sk, (skb_cloned(skb) ? + skb_copy(skb, GFP_ATOMIC): + skb_clone(skb, GFP_ATOMIC))); + + if (err == 0) { + /* Update global TCP statistics. */ + TCP_INC_STATS(TcpRetransSegs); + +#if FASTRETRANS_DEBUG > 0 + if (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) { + if (net_ratelimit()) + printk(KERN_DEBUG "retrans_out leaked.\n"); + } +#endif + TCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS; + tp->retrans_out++; - return tcp_transmit_skb(sk, skb); + /* Save stamp of the first retransmit. */ + if (!tp->retrans_stamp) + tp->retrans_stamp = TCP_SKB_CB(skb)->when; + + tp->undo_retrans++; + + /* snd_nxt is stored to detect loss of retransmitted segment, + * see tcp_input.c tcp_sacktag_write_queue(). + */ + TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt; + } + return err; } /* This gets called after a retransmit timeout, and the initially @@ -746,71 +833,79 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sk_buff *skb; + int packet_cnt = tp->lost_out; - if (tp->retrans_head == NULL && - tp->rexmt_done == 0) - tp->retrans_head = skb_peek(&sk->write_queue); - if (tp->retrans_head == tp->send_head) - tp->retrans_head = NULL; - - /* Each time, advance the retrans_head if we got - * a packet out or we skipped one because it was - * SACK'd. -DaveM - */ - while ((skb = tp->retrans_head) != NULL) { - /* If it has been ack'd by a SACK block, we don't - * retransmit it. - */ - if(!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { - /* Send it out, punt if error occurred. */ - if(tcp_retransmit_skb(sk, skb)) - break; + /* First pass: retransmit lost packets. */ + if (packet_cnt) { + for_retrans_queue(skb, sk, tp) { + __u8 sacked = TCP_SKB_CB(skb)->sacked; + + if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) + return; + + if (sacked&TCPCB_LOST) { + if (!(sacked&(TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) { + if (tcp_retransmit_skb(sk, skb)) + return; + if (tp->ca_state != TCP_CA_Loss) + NET_INC_STATS_BH(TCPFastRetrans); + else + NET_INC_STATS_BH(TCPSlowStartRetrans); + + if (skb == skb_peek(&sk->write_queue)) + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + } - update_retrans_head(sk); - - /* Stop retransmitting if we've hit the congestion - * window limit. - */ - if (tp->retrans_out >= tp->snd_cwnd) - break; - } else { - update_retrans_head(sk); + if (--packet_cnt <= 0) + break; + } } } -} -/* Using FACK information, retransmit all missing frames at the receiver - * up to the forward most SACK'd packet (tp->fackets_out) if the packet - * has not been retransmitted already. - */ -void tcp_fack_retransmit(struct sock *sk) -{ - struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct sk_buff *skb = skb_peek(&sk->write_queue); - int packet_cnt = 0; + /* OK, demanded retransmission is finished. */ - while((skb != NULL) && - (skb != tp->send_head) && - (skb != (struct sk_buff *)&sk->write_queue)) { - __u8 sacked = TCP_SKB_CB(skb)->sacked; + /* Forward retransmissions are possible only during Recovery. */ + if (tp->ca_state != TCP_CA_Recovery) + return; - if(sacked & (TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS)) - goto next_packet; + /* No forward retransmissions in Reno are possible. */ + if (!tp->sack_ok) + return; - /* Ok, retransmit it. */ - if(tcp_retransmit_skb(sk, skb)) + /* Yeah, we have to make difficult choice between forward transmission + * and retransmission... Both ways have their merits... + * + * For now we do not retrnamsit anything, while we have some new + * segments to send. + */ + + if (tcp_may_send_now(sk, tp)) + return; + + packet_cnt = 0; + + for_retrans_queue(skb, sk, tp) { + if(++packet_cnt > tp->fackets_out) break; - if(tcp_packets_in_flight(tp) >= tp->snd_cwnd) + if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) break; -next_packet: - packet_cnt++; - if(packet_cnt >= tp->fackets_out) + + if(TCP_SKB_CB(skb)->sacked & TCPCB_TAGBITS) + continue; + + /* Ok, retransmit it. */ + if(tcp_retransmit_skb(sk, skb)) break; - skb = skb->next; + + if (skb == skb_peek(&sk->write_queue)) + tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + + NET_INC_STATS_BH(TCPForwardRetrans); } } + /* Send a fin. The caller locks the socket for us. This cannot be * allowed to fail queueing a FIN frame under any circumstances. */ @@ -839,30 +934,19 @@ /* Special case to avoid Nagle bogosity. If this * segment is the last segment, and it was queued * due to Nagle/SWS-avoidance, send it out now. - * - * Hmm... actually it overrides also congestion - * avoidance (OK for FIN) and retransmit phase - * (not OK? Added.). */ if(tp->send_head == skb && - !after(tp->write_seq, tp->snd_una + tp->snd_wnd) && - !tp->retransmits) { + !after(tp->write_seq, tp->snd_una + tp->snd_wnd)) { TCP_SKB_CB(skb)->when = tcp_time_stamp; - if (!tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC))) { - update_send_head(sk); - tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; - tp->packets_out++; - if(!tcp_timer_is_set(sk, TCP_TIME_RETRANS)) - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); - } else + if (!tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL))) + update_send_head(sk, tp, skb); + else tcp_check_probe_timer(sk, tp); } } else { /* Socket is locked, keep trying until memory is available. */ for (;;) { - skb = sock_wmalloc(sk, - MAX_TCP_HEADER + 15, - 1, GFP_KERNEL); + skb = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL); if (skb) break; current->policy |= SCHED_YIELD; @@ -896,8 +980,10 @@ /* NOTE: No TCP options attached and we never retransmit this. */ skb = alloc_skb(MAX_TCP_HEADER + 15, priority); - if (!skb) + if (!skb) { + NET_INC_STATS(TCPAbortFailed); return; + } /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, MAX_TCP_HEADER); @@ -907,10 +993,11 @@ TCP_SKB_CB(skb)->urg_ptr = 0; /* Send it off. */ - TCP_SKB_CB(skb)->seq = tp->snd_nxt; + TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp); TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq; TCP_SKB_CB(skb)->when = tcp_time_stamp; - tcp_transmit_skb(sk, skb); + if (tcp_transmit_skb(sk, skb)) + NET_INC_STATS(TCPAbortFailed); } /* WARNING: This routine must only be called when we have already sent @@ -920,27 +1007,29 @@ */ int tcp_send_synack(struct sock *sk) { - struct tcp_opt* tp = &(sk->tp_pinfo.af_tcp); - struct sk_buff* skb; + struct sk_buff* skb; - skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, - 1, GFP_ATOMIC); - if (skb == NULL) - return -ENOMEM; - - /* Reserve space for headers and prepare control bits. */ - skb_reserve(skb, MAX_TCP_HEADER); - skb->csum = 0; - TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_SYN); - TCP_SKB_CB(skb)->sacked = 0; - TCP_SKB_CB(skb)->urg_ptr = 0; + skb = skb_peek(&sk->write_queue); + if (skb == NULL || !(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_SYN)) { + printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n"); + return -EFAULT; + } + if (!(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_ACK)) { + if (skb_cloned(skb)) { + struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb == NULL) + return -ENOMEM; + __skb_unlink(skb, &sk->write_queue); + __skb_queue_head(&sk->write_queue, nskb); + tcp_free_skb(sk, skb); + tcp_charge_skb(sk, nskb); + skb = nskb; + } - /* SYN eats a sequence byte. */ - TCP_SKB_CB(skb)->seq = tp->snd_una; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; - __skb_queue_tail(&sk->write_queue, skb); + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ACK; + TCP_ECN_send_synack(&sk->tp_pinfo.af_tcp, skb); + } TCP_SKB_CB(skb)->when = tcp_time_stamp; - tp->packets_out++; return tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)); } @@ -974,6 +1063,7 @@ memset(th, 0, sizeof(struct tcphdr)); th->syn = 1; th->ack = 1; + TCP_ECN_make_synack(req, th); th->source = sk->sport; th->dest = req->rmt_port; TCP_SKB_CB(skb)->seq = req->snt_isn; @@ -983,7 +1073,7 @@ if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ __u8 rcv_wscale; /* Set this up on the first call only */ - req->window_clamp = tp->window_clamp ? : skb->dst->window; + req->window_clamp = tp->window_clamp ? : dst->window; /* tcp_full_space because it is guaranteed to be the first packet */ tcp_select_initial_window(tcp_full_space(sk), dst->advmss - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), @@ -1028,18 +1118,20 @@ tp->mss_clamp = tp->user_mss; tp->max_window = 0; tcp_sync_mss(sk, dst->pmtu); - tcp_initialize_rcv_mss(sk); if (!tp->window_clamp) tp->window_clamp = dst->window; tp->advmss = dst->advmss; + tcp_initialize_rcv_mss(sk); tcp_select_initial_window(tcp_full_space(sk), - tp->advmss - (tp->tcp_header_len - sizeof(struct tcphdr)), - &tp->rcv_wnd, - &tp->window_clamp, - sysctl_tcp_window_scaling, - &tp->rcv_wscale); + tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), + &tp->rcv_wnd, + &tp->window_clamp, + sysctl_tcp_window_scaling, + &tp->rcv_wscale); + + tp->rcv_ssthresh = tp->rcv_wnd; /* Socket identity change complete, no longer * in TCP_CLOSE, so enter ourselves into the @@ -1052,8 +1144,7 @@ sk->err = 0; sk->done = 0; tp->snd_wnd = 0; - tp->snd_wl1 = 0; - tp->snd_wl2 = tp->write_seq; + tcp_init_wl(tp, tp->write_seq, 0); tp->snd_una = tp->write_seq; tp->snd_sml = tp->write_seq; tp->rcv_nxt = 0; @@ -1061,23 +1152,24 @@ tp->copied_seq = 0; tp->rto = TCP_TIMEOUT_INIT; - tcp_init_xmit_timers(sk); tp->retransmits = 0; - tp->fackets_out = 0; - tp->retrans_out = 0; + tcp_clear_retrans(tp); TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; + TCP_ECN_send_syn(tp, buff); TCP_SKB_CB(buff)->sacked = 0; TCP_SKB_CB(buff)->urg_ptr = 0; buff->csum = 0; TCP_SKB_CB(buff)->seq = tp->write_seq++; TCP_SKB_CB(buff)->end_seq = tp->write_seq; tp->snd_nxt = tp->write_seq; + tp->pushed_seq = tp->write_seq; /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; - tp->syn_stamp = TCP_SKB_CB(buff)->when; + tp->retrans_stamp = TCP_SKB_CB(buff)->when; __skb_queue_tail(&sk->write_queue, buff); + tcp_charge_skb(sk, buff); tp->packets_out++; tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL)); TCP_INC_STATS(TcpActiveOpens); @@ -1099,20 +1191,27 @@ void tcp_send_delayed_ack(struct sock *sk) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - long ato = tp->ack.ato; + int ato = tp->ack.ato; unsigned long timeout; if (ato > TCP_DELACK_MIN) { - int max_ato; + int max_ato = HZ/2; + + if (tp->ack.pingpong || (tp->ack.pending&TCP_ACK_PUSHED)) + max_ato = TCP_DELACK_MAX; + + /* Slow path, intersegment interval is "high". */ /* If some rtt estimate is known, use it to bound delayed ack. * Do not use tp->rto here, use results of rtt measurements * directly. */ - if (tp->srtt) - max_ato = (tp->srtt >> 3) + tp->mdev; - else - max_ato = TCP_DELACK_MAX; + if (tp->srtt) { + int rtt = max(tp->srtt>>3, TCP_DELACK_MIN); + + if (rtt < max_ato) + max_ato = rtt; + } ato = min(ato, max_ato); } @@ -1121,20 +1220,20 @@ timeout = jiffies + ato; /* Use new timeout only if there wasn't a older one earlier. */ - if (timer_pending(&tp->delack_timer)) { - unsigned long old_timeout = tp->delack_timer.expires; - + if (tp->ack.pending&TCP_ACK_TIMER) { /* If delack timer was blocked or is about to expire, * send ACK now. */ - if (tp->ack.blocked || time_before_eq(old_timeout, jiffies+(ato>>2))) { + if (tp->ack.blocked || time_before_eq(tp->ack.timeout, jiffies+(ato>>2))) { tcp_send_ack(sk); return; } - if (!time_before(timeout, old_timeout)) - timeout = old_timeout; + if (!time_before(timeout, tp->ack.timeout)) + timeout = tp->ack.timeout; } + tp->ack.pending |= TCP_ACK_SCHED|TCP_ACK_TIMER; + tp->ack.timeout = timeout; if (!mod_timer(&tp->delack_timer, timeout)) sock_hold(sk); @@ -1170,8 +1269,8 @@ */ buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_ATOMIC); if (buff == NULL) { - tp->ack.pending = 1; - tp->ack.ato = TCP_ATO_MAX; + tcp_schedule_ack(tp); + tp->ack.ato = TCP_ATO_MIN; tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MAX); return; } @@ -1184,7 +1283,7 @@ TCP_SKB_CB(buff)->urg_ptr = 0; /* Send it off, this clears delayed acks for us. */ - TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tp->snd_nxt; + TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp); TCP_SKB_CB(buff)->when = tcp_time_stamp; tcp_transmit_skb(sk, buff); } @@ -1193,66 +1292,68 @@ /* This routine sends a packet with an out of date sequence * number. It assumes the other end will try to ack it. */ +static int tcp_xmit_probe_skb(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb; + + /* We don't queue it, tcp_transmit_skb() sets ownership. */ + skb = alloc_skb(MAX_TCP_HEADER + 15, GFP_ATOMIC); + if (skb == NULL) + return -1; + + /* Reserve space for headers and set control bits. */ + skb_reserve(skb, MAX_TCP_HEADER); + skb->csum = 0; + TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; + TCP_SKB_CB(skb)->sacked = 0; + TCP_SKB_CB(skb)->urg_ptr = 0; + + /* Use a previous sequence. This should cause the other + * end to send an ack. Don't queue or clone SKB, just + * send it. + */ + TCP_SKB_CB(skb)->seq = tp->snd_una - 1; + TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq; + TCP_SKB_CB(skb)->when = tcp_time_stamp; + return tcp_transmit_skb(sk, skb); +} + int tcp_write_wakeup(struct sock *sk) { if (sk->state != TCP_CLOSE) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sk_buff *skb; - /* Now this function is never called, while - * we have something not ACKed in queue. - */ - BUG_TRAP(tp->snd_una == tp->snd_nxt); - - if (tp->snd_wnd > (tp->snd_nxt-tp->snd_una) - && ((skb = tp->send_head) != NULL)) { + if ((skb = tp->send_head) != NULL && + before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)) { int err; - unsigned long win_size; + int mss = tcp_current_mss(sk); + int seg_size = tp->snd_una+tp->snd_wnd-TCP_SKB_CB(skb)->seq; + + if (before(tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) + tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; /* We are probing the opening of a window * but the window size is != 0 * must have been a result SWS avoidance ( sender ) */ - win_size = tp->snd_wnd - (tp->snd_nxt - tp->snd_una); - if (win_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) { - if (tcp_fragment(sk, skb, win_size)) + if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || + skb->len > mss) { + seg_size = min(seg_size, mss); + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; + if (tcp_fragment(sk, skb, seg_size)) return -1; } + TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; TCP_SKB_CB(skb)->when = tcp_time_stamp; err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)); if (!err) { - update_send_head(sk); - tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; - tp->packets_out++; - if (!tcp_timer_is_set(sk, TCP_TIME_RETRANS)) - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); + update_send_head(sk, tp, skb); } return err; } else { - /* We don't queue it, tcp_transmit_skb() sets ownership. */ - skb = alloc_skb(MAX_TCP_HEADER + 15, GFP_ATOMIC); - if (skb == NULL) - return -1; - - /* Reserve space for headers and set control bits. */ - skb_reserve(skb, MAX_TCP_HEADER); - skb->csum = 0; - TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; - TCP_SKB_CB(skb)->sacked = 0; - TCP_SKB_CB(skb)->urg_ptr = 0; - - /* Use a previous sequence. This should cause the other - * end to send an ack. Don't queue or clone SKB, just - * send it. - * - * RED-PEN: logically it should be snd_una-1. - * snd_nxt-1 will not be acked. snd_una==snd_nxt - * in this place however. Right? - */ - TCP_SKB_CB(skb)->seq = tp->snd_una - 1; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq; - TCP_SKB_CB(skb)->when = tcp_time_stamp; - return tcp_transmit_skb(sk, skb); + return tcp_xmit_probe_skb(sk); } } return -1; diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.4.0-test6/linux/net/ipv4/tcp_timer.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/tcp_timer.c Sat Aug 12 12:09:55 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.77 2000/06/30 10:18:38 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.79 2000/08/11 00:13:36 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -29,13 +29,11 @@ int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL; int sysctl_tcp_retries1 = TCP_RETR1; int sysctl_tcp_retries2 = TCP_RETR2; -int sysctl_tcp_orphan_retries = TCP_ORPHAN_RETRIES; +int sysctl_tcp_orphan_retries = 0; -static void tcp_retransmit_timer(unsigned long); +static void tcp_write_timer(unsigned long); static void tcp_delack_timer(unsigned long); -static void tcp_probe_timer(unsigned long); static void tcp_keepalive_timer (unsigned long data); -static void tcp_twkill(unsigned long); const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n"; @@ -50,73 +48,35 @@ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; init_timer(&tp->retransmit_timer); - tp->retransmit_timer.function=&tcp_retransmit_timer; + tp->retransmit_timer.function=&tcp_write_timer; tp->retransmit_timer.data = (unsigned long) sk; + tp->pending = 0; init_timer(&tp->delack_timer); tp->delack_timer.function=&tcp_delack_timer; tp->delack_timer.data = (unsigned long) sk; - - init_timer(&tp->probe_timer); - tp->probe_timer.function=&tcp_probe_timer; - tp->probe_timer.data = (unsigned long) sk; + tp->ack.pending = 0; init_timer(&sk->timer); sk->timer.function=&tcp_keepalive_timer; sk->timer.data = (unsigned long) sk; } -/* - * Reset the retransmission timer - */ - -void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when) -{ - struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - - switch (what) { - case TCP_TIME_RETRANS: - /* When seting the transmit timer the probe timer - * should not be set. - * The delayed ack timer can be set if we are changing the - * retransmit timer when removing acked frames. - */ - if (timer_pending(&tp->probe_timer) && del_timer(&tp->probe_timer)) - __sock_put(sk); - if (when > TCP_RTO_MAX) { - printk(KERN_DEBUG "reset_xmit_timer sk=%p when=0x%lx, caller=%p\n", sk, when, NET_CALLER(sk)); - when = TCP_RTO_MAX; - } - if (!mod_timer(&tp->retransmit_timer, jiffies+when)) - sock_hold(sk); - break; - - case TCP_TIME_DACK: - if (!mod_timer(&tp->delack_timer, jiffies+when)) - sock_hold(sk); - break; - - case TCP_TIME_PROBE0: - if (!mod_timer(&tp->probe_timer, jiffies+when)) - sock_hold(sk); - break; - - default: - printk(KERN_DEBUG "bug: unknown timer value\n"); - }; -} - void tcp_clear_xmit_timers(struct sock *sk) -{ +{ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - if(timer_pending(&tp->retransmit_timer) && del_timer(&tp->retransmit_timer)) - __sock_put(sk); - if(timer_pending(&tp->delack_timer) && del_timer(&tp->delack_timer)) + tp->pending = 0; + if (timer_pending(&tp->retransmit_timer) && + del_timer(&tp->retransmit_timer)) __sock_put(sk); + + tp->ack.pending = 0; tp->ack.blocked = 0; - if(timer_pending(&tp->probe_timer) && del_timer(&tp->probe_timer)) + if (timer_pending(&tp->delack_timer) && + del_timer(&tp->delack_timer)) __sock_put(sk); + if(timer_pending(&sk->timer) && del_timer(&sk->timer)) __sock_put(sk); } @@ -127,6 +87,7 @@ sk->error_report(sk); tcp_done(sk); + NET_INC_STATS_BH(TCPAbortOnTimeout); } /* Do not allow orphaned sockets to eat all our resources. @@ -138,26 +99,60 @@ * We kill the socket, if: * 1. If number of orphaned sockets exceeds an administratively configured * limit. - * 2. Under pessimistic assumption that all the orphans eat memory not - * less than this one, total consumed memory exceeds all - * the available memory. + * 2. If we have strong memory pressure. */ static int tcp_out_of_resources(struct sock *sk, int do_reset) { + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int orphans = atomic_read(&tcp_orphan_count); + /* If peer does not open window for long time, or did not transmit + * anything for long time, penalize it. */ + if ((s32)(tcp_time_stamp - tp->lsndtime) > 2*TCP_RTO_MAX || !do_reset) + orphans <<= 1; + + /* If some dubious ICMP arrived, penalize even more. */ + if (sk->err_soft) + orphans <<= 1; + if (orphans >= sysctl_tcp_max_orphans || - ((orphans*atomic_read(&sk->wmem_alloc))>>PAGE_SHIFT) >= num_physpages) { + (sk->wmem_queued > SOCK_MIN_SNDBUF && + atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])) { if (net_ratelimit()) printk(KERN_INFO "Out of socket memory\n"); + + /* Catch exceptional cases, when connection requires reset. + * 1. Last segment was sent recently. */ + if ((s32)(tcp_time_stamp - tp->lsndtime) <= TCP_TIMEWAIT_LEN || + /* 2. Window is closed. */ + (!tp->snd_wnd && !tp->packets_out)) + do_reset = 1; if (do_reset) tcp_send_active_reset(sk, GFP_ATOMIC); tcp_done(sk); + NET_INC_STATS_BH(TCPAbortOnMemory); return 1; } return 0; } +/* Calculate maximal number or retries on an orphaned socket. */ +static int tcp_orphan_retries(struct sock *sk, int alive) +{ + int retries = sysctl_tcp_orphan_retries; /* May be zero. */ + + /* We know from an ICMP that something is wrong. */ + if (sk->err_soft && !alive) + retries = 0; + + /* However, if socket sent something recently, select some safe + * number of retries. 8 corresponds to >100 seconds with minimal + * RTO of 200msec. */ + if (retries == 0 && alive) + retries = 8; + return retries; +} + /* A write timeout has occurred. Process the after effects. */ static int tcp_write_timeout(struct sock *sk) { @@ -195,10 +190,12 @@ retry_until = sysctl_tcp_retries2; if (sk->dead) { - if (tcp_out_of_resources(sk, tp->retransmits < retry_until)) - return 1; + int alive = (tp->rto < TCP_RTO_MAX); + + retry_until = tcp_orphan_retries(sk, alive); - retry_until = sysctl_tcp_orphan_retries; + if (tcp_out_of_resources(sk, alive || tp->retransmits < retry_until)) + return 1; } } @@ -220,14 +217,38 @@ /* Try again later. */ tp->ack.blocked = 1; NET_INC_STATS_BH(DelayedACKLocked); - tcp_reset_xmit_timer(sk, TCP_TIME_DACK, TCP_DELACK_MIN); + if (!mod_timer(&tp->delack_timer, jiffies + TCP_DELACK_MIN)) + sock_hold(sk); goto out_unlock; } - if (tp->ack.pending) { + tcp_mem_reclaim(sk); + + if (sk->state == TCP_CLOSE || !(tp->ack.pending&TCP_ACK_TIMER)) + goto out; + + if ((long)(tp->ack.timeout - jiffies) > 0) { + if (!mod_timer(&tp->delack_timer, tp->ack.timeout)) + sock_hold(sk); + goto out; + } + tp->ack.pending &= ~TCP_ACK_TIMER; + + if (skb_queue_len(&tp->ucopy.prequeue)) { + struct sk_buff *skb; + + net_statistics[smp_processor_id()*2].TCPSchedulerFailed += skb_queue_len(&tp->ucopy.prequeue); + + while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) + sk->backlog_rcv(sk, skb); + + tp->ucopy.memory = 0; + } + + if (tcp_ack_scheduled(tp)) { if (!tp->ack.pingpong) { /* Delayed ACK missed: inflate ATO. */ - tp->ack.ato = min(tp->ack.ato<<1, TCP_ATO_MAX); + tp->ack.ato = min(tp->ack.ato<<1, tp->rto); } else { /* Delayed ACK missed: leave pingpong mode and * deflate ATO. @@ -240,30 +261,22 @@ } TCP_CHECK_TIMER(sk); +out: + if (tcp_memory_pressure) + tcp_mem_reclaim(sk); out_unlock: bh_unlock_sock(sk); sock_put(sk); } -static void tcp_probe_timer(unsigned long data) +static void tcp_probe_timer(struct sock *sk) { - struct sock *sk = (struct sock*)data; struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; int max_probes; - bh_lock_sock(sk); - if (sk->lock.users) { - /* Try again later. */ - tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, HZ/5); - goto out_unlock; - } - - if (sk->state == TCP_CLOSE) - goto out_unlock; - if (tp->packets_out || !tp->send_head) { tp->probes_out = 0; - goto out_unlock; + return; } /* *WARNING* RFC 1122 forbids this @@ -284,10 +297,12 @@ max_probes = sysctl_tcp_retries2; if (sk->dead) { - if (tcp_out_of_resources(sk, tp->probes_out <= max_probes)) - goto out_unlock; + int alive = ((tp->rto<backoff) < TCP_RTO_MAX); + + max_probes = tcp_orphan_retries(sk, alive); - max_probes = sysctl_tcp_orphan_retries; + if (tcp_out_of_resources(sk, alive || tp->probes_out <= max_probes)) + return; } if (tp->probes_out > max_probes) { @@ -295,284 +310,47 @@ } else { /* Only send another probe if we didn't close things up. */ tcp_send_probe0(sk); - TCP_CHECK_TIMER(sk); } -out_unlock: - bh_unlock_sock(sk); - sock_put(sk); } - -/* Kill off TIME_WAIT sockets once their lifetime has expired. */ -static int tcp_tw_death_row_slot = 0; -int tcp_tw_count = 0; - -static struct tcp_tw_bucket *tcp_tw_death_row[TCP_TWKILL_SLOTS]; -static spinlock_t tw_death_lock = SPIN_LOCK_UNLOCKED; -static struct timer_list tcp_tw_timer = { function: tcp_twkill }; - -static void SMP_TIMER_NAME(tcp_twkill)(unsigned long dummy) -{ - struct tcp_tw_bucket *tw; - int killed = 0; - - /* NOTE: compare this to previous version where lock - * was released after detaching chain. It was racy, - * because tw buckets are scheduled in not serialized context - * in 2.3 (with netfilter), and with softnet it is common, because - * soft irqs are not sequenced. - */ - spin_lock(&tw_death_lock); - - if (tcp_tw_count == 0) - goto out; - - while((tw = tcp_tw_death_row[tcp_tw_death_row_slot]) != NULL) { - tcp_tw_death_row[tcp_tw_death_row_slot] = tw->next_death; - tw->pprev_death = NULL; - spin_unlock(&tw_death_lock); - - tcp_timewait_kill(tw); - tcp_tw_put(tw); - - killed++; - - spin_lock(&tw_death_lock); - } - tcp_tw_death_row_slot = - ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1)); - - if ((tcp_tw_count -= killed) != 0) - mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD); - net_statistics[smp_processor_id()*2].TimeWaited += killed; -out: - spin_unlock(&tw_death_lock); -} - -SMP_TIMER_DEFINE(tcp_twkill, tcp_twkill_task); - -/* These are always called from BH context. See callers in - * tcp_input.c to verify this. - */ - -/* This is for handling early-kills of TIME_WAIT sockets. */ -void tcp_tw_deschedule(struct tcp_tw_bucket *tw) -{ - spin_lock(&tw_death_lock); - if (tw->pprev_death) { - if(tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - *tw->pprev_death = tw->next_death; - tw->pprev_death = NULL; - tcp_tw_put(tw); - if (--tcp_tw_count == 0) - del_timer(&tcp_tw_timer); - } - spin_unlock(&tw_death_lock); -} - -/* Short-time timewait calendar */ - -static int tcp_twcal_hand = -1; -static int tcp_twcal_jiffie; -static void tcp_twcal_tick(unsigned long); -static struct timer_list tcp_twcal_timer = {function: tcp_twcal_tick}; -static struct tcp_tw_bucket *tcp_twcal_row[TCP_TW_RECYCLE_SLOTS]; - -void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo) -{ - struct tcp_tw_bucket **tpp; - int slot; - - /* timeout := RTO * 3.5 - * - * 3.5 = 1+2+0.5 to wait for two retransmits. - * - * RATIONALE: if FIN arrived and we entered TIME-WAIT state, - * our ACK acking that FIN can be lost. If N subsequent retransmitted - * FINs (or previous seqments) are lost (probability of such event - * is p^(N+1), where p is probability to lose single packet and - * time to detect the loss is about RTO*(2^N - 1) with exponential - * backoff). Normal timewait length is calculated so, that we - * waited at least for one retransmitted FIN (maximal RTO is 120sec). - * [ BTW Linux. following BSD, violates this requirement waiting - * only for 60sec, we should wait at least for 240 secs. - * Well, 240 consumes too much of resources 8) - * ] - * This interval is not reduced to catch old duplicate and - * responces to our wandering segments living for two MSLs. - * However, if we use PAWS to detect - * old duplicates, we can reduce the interval to bounds required - * by RTO, rather than MSL. So, if peer understands PAWS, we - * kill tw bucket after 3.5*RTO (it is important that this number - * is greater than TS tick!) and detect old duplicates with help - * of PAWS. - */ - slot = (timeo + (1<> TCP_TW_RECYCLE_TICK; - - spin_lock(&tw_death_lock); - - /* Unlink it, if it was scheduled */ - if (tw->pprev_death) { - if(tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - *tw->pprev_death = tw->next_death; - tw->pprev_death = NULL; - tcp_tw_count--; - } else - atomic_inc(&tw->refcnt); - - if (slot >= TCP_TW_RECYCLE_SLOTS) { - /* Schedule to slow timer */ - if (timeo >= TCP_TIMEWAIT_LEN) { - slot = TCP_TWKILL_SLOTS-1; - } else { - slot = (timeo + TCP_TWKILL_PERIOD-1) / TCP_TWKILL_PERIOD; - if (slot >= TCP_TWKILL_SLOTS) - slot = TCP_TWKILL_SLOTS-1; - } - tw->ttd = jiffies + timeo; - slot = (tcp_tw_death_row_slot + slot) & (TCP_TWKILL_SLOTS - 1); - tpp = &tcp_tw_death_row[slot]; - } else { - tw->ttd = jiffies + (slot< (slot<next_death = *tpp) != NULL) - (*tpp)->pprev_death = &tw->next_death; - *tpp = tw; - tw->pprev_death = tpp; - - if (tcp_tw_count++ == 0) - mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD); - spin_unlock(&tw_death_lock); -} - -void SMP_TIMER_NAME(tcp_twcal_tick)(unsigned long dummy) -{ - int n, slot; - unsigned long j; - unsigned long now = jiffies; - int killed = 0; - int adv = 0; - - spin_lock(&tw_death_lock); - if (tcp_twcal_hand < 0) - goto out; - - slot = tcp_twcal_hand; - j = tcp_twcal_jiffie; - - for (n=0; nnext_death; - tw->pprev_death = NULL; - - tcp_timewait_kill(tw); - tcp_tw_put(tw); - killed++; - } - } else { - if (!adv) { - adv = 1; - tcp_twcal_jiffie = j; - tcp_twcal_hand = slot; - } - - if (tcp_twcal_row[slot] != NULL) { - mod_timer(&tcp_twcal_timer, j); - goto out; - } - } - j += (1<tp_pinfo.af_tcp; - bh_lock_sock(sk); - if (sk->lock.users) { - /* Try again later */ - tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, HZ/20); - goto out_unlock; - } - - if (sk->state == TCP_CLOSE || tp->packets_out == 0) - goto out_unlock; + if (tp->packets_out == 0) + goto out; BUG_TRAP(!skb_queue_empty(&sk->write_queue)); if (tcp_write_timeout(sk)) - goto out_unlock; - - /* RFC 2018, clear all 'sacked' flags in retransmission queue, - * the sender may have dropped out of order frames and we must - * send them out should this timer fire on us. - */ - if(tp->sack_ok) { - struct sk_buff *skb = skb_peek(&sk->write_queue); + goto out; - while((skb != NULL) && - (skb != tp->send_head) && - (skb != (struct sk_buff *)&sk->write_queue)) { - TCP_SKB_CB(skb)->sacked &= - ~(TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS); - skb = skb->next; + if (tp->retransmits == 0) { + if (tp->ca_state == TCP_CA_Disorder || tp->ca_state == TCP_CA_Recovery) { + if (tp->sack_ok) { + if (tp->ca_state == TCP_CA_Recovery) + NET_INC_STATS_BH(TCPSackRecoveryFail); + else + NET_INC_STATS_BH(TCPSackFailures); + } else { + if (tp->ca_state == TCP_CA_Recovery) + NET_INC_STATS_BH(TCPRenoRecoveryFail); + else + NET_INC_STATS_BH(TCPRenoFailures); + } + } else if (tp->ca_state == TCP_CA_Loss) { + NET_INC_STATS_BH(TCPLossFailures); + } else { + NET_INC_STATS_BH(TCPTimeouts); } } - /* Retransmission. */ - tp->retrans_head = NULL; - tp->rexmt_done = 0; - tp->fackets_out = 0; - tp->retrans_out = 0; - if (tp->retransmits == 0) { - /* Remember window where we lost: - * "one half of the current window but at least 2 segments" - * - * Here "current window" means the effective one, which - * means it must be an accurate representation of our current - * sending rate _and_ the snd_wnd. - */ - tp->snd_ssthresh = tcp_recalc_ssthresh(tp); - tp->snd_cwnd_cnt = 0; - tp->snd_cwnd = 1; - } + tcp_enter_loss(sk, 0); - tp->dup_acks = 0; - tp->high_seq = tp->snd_nxt; if (tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)) > 0) { /* Retransmission failed because of local congestion, * do not backoff. @@ -581,8 +359,7 @@ tp->retransmits=1; tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, min(tp->rto, TCP_RESOURCE_PROBE_INTERVAL)); - TCP_CHECK_TIMER(sk); - goto out_unlock; + goto out; } /* Increase the timeout each time we retransmit. Note that @@ -606,8 +383,48 @@ tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); if (tp->retransmits > sysctl_tcp_retries1) __sk_dst_reset(sk); + +out: +} + +static void tcp_write_timer(unsigned long data) +{ + struct sock *sk = (struct sock*)data; + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + int event; + + bh_lock_sock(sk); + if (sk->lock.users) { + /* Try again later */ + if (!mod_timer(&tp->retransmit_timer, jiffies + (HZ/20))) + sock_hold(sk); + goto out_unlock; + } + + if (sk->state == TCP_CLOSE || !tp->pending) + goto out; + + if ((long)(tp->timeout - jiffies) > 0) { + if (!mod_timer(&tp->retransmit_timer, tp->timeout)) + sock_hold(sk); + goto out; + } + + event = tp->pending; + tp->pending = 0; + + switch (event) { + case TCP_TIME_RETRANS: + tcp_retransmit_timer(sk); + break; + case TCP_TIME_PROBE0: + tcp_probe_timer(sk); + break; + } TCP_CHECK_TIMER(sk); +out: + tcp_mem_reclaim(sk); out_unlock: bh_unlock_sock(sk); sock_put(sk); @@ -794,6 +611,7 @@ } TCP_CHECK_TIMER(sk); + tcp_mem_reclaim(sk); resched: tcp_reset_keepalive_timer (sk, elapsed); diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.4.0-test6/linux/net/ipv4/udp.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv4/udp.c Thu Aug 10 13:01:26 2000 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.84 2000/07/08 00:20:43 davem Exp $ + * Version: $Id: udp.c,v 1.85 2000/08/09 11:59:04 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -997,8 +997,8 @@ i, src, srcp, dest, destp, sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, 0, - sp->socket ? sp->socket->inode->i_ino : 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), atomic_read(&sp->refcnt), sp); } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.4.0-test6/linux/net/ipv6/raw.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv6/raw.c Thu Aug 10 13:01:26 2000 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.39 2000/07/08 00:20:43 davem Exp $ + * $Id: raw.c,v 1.40 2000/08/09 11:59:04 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -763,8 +763,8 @@ sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), sock_timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, 0, - sp->socket ? sp->socket->inode->i_ino : 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), atomic_read(&sp->refcnt), sp); } diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.4.0-test6/linux/net/ipv6/route.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv6/route.c Thu Aug 10 13:01:26 2000 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: route.c,v 1.46 2000/07/07 22:40:35 davem Exp $ + * $Id: route.c,v 1.48 2000/08/10 01:17:13 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -93,7 +93,7 @@ struct rt6_info ip6_null_entry = { {{NULL, ATOMIC_INIT(1), 1, &loopback_dev, - -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL, ip6_pkt_discard, ip6_pkt_discard, #ifdef CONFIG_NET_CLS_ROUTE diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.4.0-test6/linux/net/ipv6/tcp_ipv6.c Thu May 11 15:30:08 2000 +++ linux/net/ipv6/tcp_ipv6.c Thu Aug 10 13:01:26 2000 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.124 2000/05/03 06:37:07 davem Exp $ + * $Id: tcp_ipv6.c,v 1.125 2000/08/09 11:59:04 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -152,7 +153,9 @@ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, sk2->state != TCP_TIME_WAIT ? &sk2->net_pinfo.af_inet6.rcv_saddr : - &((struct tcp_tw_bucket*)sk)->v6_rcv_saddr)) + &((struct tcp_tw_bucket*)sk)->v6_rcv_saddr) || + (addr_type==IPV6_ADDR_MAPPED && sk2->family==AF_INET && + sk->rcv_saddr==sk2->rcv_saddr)) break; } } @@ -430,10 +433,9 @@ sk2->bound_dev_if == sk->bound_dev_if) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - if (tw->substate == TCP_TIME_WAIT && - sysctl_tcp_tw_recycle && tw->ts_recent_stamp) { + if (tw->ts_recent_stamp) { /* See comment in tcp_ipv4.c */ - if ((tp->write_seq = tw->snd_nxt + 2) == 0) + if ((tp->write_seq = tw->snd_nxt+65535+2) == 0) tp->write_seq = 1; tp->ts_recent = tw->ts_recent; tp->ts_recent_stamp = tw->ts_recent_stamp; @@ -526,6 +528,7 @@ fl.fl6_flowlabel = 0; if (np->sndflow) { fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; + IP6_ECN_flow_init(fl.fl6_flowlabel); if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { struct ip6_flowlabel *flowlabel; flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); @@ -644,6 +647,7 @@ /* set the source address */ ipv6_addr_copy(&np->rcv_saddr, saddr); ipv6_addr_copy(&np->saddr, saddr); + sk->rcv_saddr= LOOPBACK4_IPV6; tp->ext_header_len = 0; if (np->opt) @@ -651,7 +655,7 @@ tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); err = -ENOBUFS; - buff = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 0, GFP_KERNEL); + buff = alloc_skb(MAX_TCP_HEADER + 15, GFP_KERNEL); if (buff == NULL) goto failure; @@ -1072,33 +1076,30 @@ struct open_request *req, **prev; struct tcphdr *th = skb->h.th; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sock *nsk; /* Find possible connection requests. */ req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &prev); if (req) return tcp_check_req(sk, skb, req, prev); - if (tp->accept_queue) { - struct sock *nsk; - - nsk = __tcp_v6_lookup_established(&skb->nh.ipv6h->saddr, - th->source, - &skb->nh.ipv6h->daddr, - ntohs(th->dest), - tcp_v6_iif(skb)); - - if (nsk) { - if (nsk->state != TCP_TIME_WAIT) { - bh_lock_sock(nsk); - return nsk; - } - tcp_tw_put((struct tcp_tw_bucket*)sk); - return NULL; + nsk = __tcp_v6_lookup_established(&skb->nh.ipv6h->saddr, + th->source, + &skb->nh.ipv6h->daddr, + ntohs(th->dest), + tcp_v6_iif(skb)); + + if (nsk) { + if (nsk->state != TCP_TIME_WAIT) { + bh_lock_sock(nsk); + return nsk; } + tcp_tw_put((struct tcp_tw_bucket*)sk); + return NULL; } #if 0 /*def CONFIG_SYN_COOKIES*/ - if (!th->rst && (th->syn || th->ack)) + if (!th->rst && !th->syn && th->ack) sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt)); #endif return sk; @@ -1160,13 +1161,14 @@ tp.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tp.user_mss = sk->tp_pinfo.af_tcp.user_mss; - tcp_parse_options(NULL, skb->h.th, &tp, 0); + tcp_parse_options(skb, &tp); tcp_openreq_init(req, &tp, skb); req->class = &or_ipv6; ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr); ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr); + TCP_ECN_create_request(req, skb->h.th); req->af.v6_req.pktopts = NULL; if (ipv6_opt_accepted(sk, skb) || sk->net_pinfo.af_inet6.rxopt.bits.rxinfo || @@ -1344,10 +1346,8 @@ newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen; tcp_sync_mss(newsk, dst->pmtu); - tcp_initialize_rcv_mss(newsk); newtp->advmss = dst->advmss; - - tcp_init_buffer_space(newsk); + tcp_initialize_rcv_mss(newsk); newsk->daddr = LOOPBACK4_IPV6; newsk->saddr = LOOPBACK4_IPV6; @@ -1377,8 +1377,8 @@ return -1; } skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) { - if (skb->len <= 68) { + } else { + if (skb->len <= 76) { if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,csum_partial((char *)skb->h.th, skb->len, 0))) return -1; @@ -1404,7 +1404,7 @@ #ifdef CONFIG_FILTER struct sk_filter *filter; #endif - int users = 0; + struct sk_buff *opt_skb = NULL; /* Imagine: socket is IPv6. IPv4 packet arrives, goes to IPv4 receive handler and backlogged. @@ -1443,22 +1443,20 @@ by tcp. Feel free to propose better solution. --ANK (980728) */ - if (sk->net_pinfo.af_inet6.rxopt.all) { - users = atomic_read(&skb->users); - atomic_inc(&skb->users); - } + if (sk->net_pinfo.af_inet6.rxopt.all) + opt_skb = skb_clone(skb, GFP_ATOMIC); if (sk->state == TCP_ESTABLISHED) { /* Fast path */ TCP_CHECK_TIMER(sk); if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) goto reset; TCP_CHECK_TIMER(sk); - if (users) + if (opt_skb) goto ipv6_pktoptions; return 0; } - if (tcp_checksum_complete(skb)) + if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb)) goto csum_err; if (sk->state == TCP_LISTEN) { @@ -1474,8 +1472,8 @@ if(nsk != sk) { if (tcp_child_process(sk, nsk, skb)) goto reset; - if (users) - kfree_skb(skb); + if (opt_skb) + __kfree_skb(opt_skb); return 0; } } @@ -1484,15 +1482,15 @@ if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) goto reset; TCP_CHECK_TIMER(sk); - if (users) + if (opt_skb) goto ipv6_pktoptions; return 0; reset: tcp_v6_send_reset(skb); discard: - if (users) - kfree_skb(skb); + if (opt_skb) + __kfree_skb(opt_skb); kfree_skb(skb); return 0; csum_err: @@ -1508,29 +1506,23 @@ 3. socket is not in passive state. 4. Finally, it really contains options, which user wants to receive. */ - if (atomic_read(&skb->users) > users && - TCP_SKB_CB(skb)->end_seq == sk->tp_pinfo.af_tcp.rcv_nxt && + if (TCP_SKB_CB(opt_skb)->end_seq == sk->tp_pinfo.af_tcp.rcv_nxt && !((1<state)&(TCPF_CLOSE|TCPF_LISTEN))) { if (sk->net_pinfo.af_inet6.rxopt.bits.rxinfo) - sk->net_pinfo.af_inet6.mcast_oif = tcp_v6_iif(skb); + sk->net_pinfo.af_inet6.mcast_oif = tcp_v6_iif(opt_skb); if (sk->net_pinfo.af_inet6.rxopt.bits.rxhlim) - sk->net_pinfo.af_inet6.mcast_hops = skb->nh.ipv6h->hop_limit; - if (ipv6_opt_accepted(sk, skb)) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - kfree_skb(skb); - skb = NULL; - if (skb2) { - skb_set_owner_r(skb2, sk); - skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, skb2); - } + sk->net_pinfo.af_inet6.mcast_hops = opt_skb->nh.ipv6h->hop_limit; + if (ipv6_opt_accepted(sk, opt_skb)) { + skb_set_owner_r(opt_skb, sk); + opt_skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, opt_skb); } else { - kfree_skb(skb); - skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, NULL); + __kfree_skb(opt_skb); + opt_skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, NULL); } } - if (skb) - kfree_skb(skb); + if (opt_skb) + kfree_skb(opt_skb); return 0; } @@ -1559,10 +1551,9 @@ TCP_INC_STATS_BH(TcpInSegs); - if (len < sizeof(struct tcphdr)) - goto bad_packet; - - if (tcp_v6_checksum_init(skb) < 0) + if (th->doff < sizeof(struct tcphdr)/4 || + (skb->ip_summed != CHECKSUM_UNNECESSARY && + tcp_v6_checksum_init(skb) < 0)) goto bad_packet; TCP_SKB_CB(skb)->seq = ntohl(th->seq); @@ -1570,6 +1561,8 @@ len - th->doff*4); TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); TCP_SKB_CB(skb)->when = 0; + TCP_SKB_CB(skb)->flags = ip6_get_dsfield(skb->nh.ipv6h); + TCP_SKB_CB(skb)->sacked = 0; skb->used = 0; sk = __tcp_v6_lookup(saddr, th->source, daddr, ntohs(th->dest), tcp_v6_iif(skb)); @@ -1596,7 +1589,7 @@ return ret; no_tcp_socket: - if (tcp_checksum_complete(skb)) { + if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: TCP_INC_STATS_BH(TcpInErrs); } else { @@ -1617,7 +1610,7 @@ goto discard_it; do_time_wait: - if (tcp_checksum_complete(skb)) { + if (len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); sock_put(sk); goto discard_it; @@ -1698,6 +1691,7 @@ fl.fl6_dst = &np->daddr; fl.fl6_src = &np->saddr; fl.fl6_flowlabel = np->flow_label; + IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); fl.oif = sk->bound_dev_if; fl.uli_u.ports.sport = sk->sport; fl.uli_u.ports.dport = sk->dport; @@ -1816,12 +1810,19 @@ tp->snd_cwnd_clamp = ~0; tp->mss_cache = 536; + tp->reordering = sysctl_tcp_reordering; + sk->state = TCP_CLOSE; sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific; sk->write_space = tcp_write_space; + sk->sndbuf = sysctl_tcp_wmem[1]; + sk->rcvbuf = sysctl_tcp_rmem[1]; + + atomic_inc(&tcp_sockets_allocated); + return 0; } @@ -1832,7 +1833,7 @@ tcp_clear_xmit_timers(sk); /* Cleanup up the write buffer. */ - __skb_queue_purge(&sk->write_queue); + tcp_writequeue_purge(sk); /* Cleans up our, hopefuly empty, out_of_order_queue. */ __skb_queue_purge(&tp->out_of_order_queue); @@ -1844,11 +1845,13 @@ if(sk->prev != NULL) tcp_put_port(sk); + atomic_dec(&tcp_sockets_allocated); + return inet6_destroy_sock(sk); } /* Proc filesystem TCPv6 sock list dumping. */ -static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf, int i) +static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid) { struct in6_addr *dest, *src; int ttd = req->expires - jiffies; @@ -1873,7 +1876,7 @@ 1, /* timers active (only the expire timer) */ ttd, req->retrans, - sk->socket ? sk->socket->inode->i_uid : 0, + uid, 0, /* non standard timer */ 0, /* open_requests have no inode */ 0, req); @@ -1891,25 +1894,23 @@ src = &sp->net_pinfo.af_inet6.rcv_saddr; destp = ntohs(sp->dport); srcp = ntohs(sp->sport); - timer_active = 0; - timer_expires = (unsigned) -1; - if (timer_pending(&tp->retransmit_timer) && tp->retransmit_timer.expires < timer_expires) { + if (tp->pending == TCP_TIME_RETRANS) { timer_active = 1; - timer_expires = tp->retransmit_timer.expires; - } else if (timer_pending(&tp->probe_timer) && tp->probe_timer.expires < timer_expires) { + timer_expires = tp->timeout; + } else if (tp->pending == TCP_TIME_PROBE0) { timer_active = 4; - timer_expires = tp->probe_timer.expires; - } - if (timer_pending(&sp->timer) && sp->timer.expires < timer_expires) { + timer_expires = tp->timeout; + } else if (timer_pending(&sp->timer)) { timer_active = 2; timer_expires = sp->timer.expires; - } - if(timer_active == 0) + } else { + timer_active = 0; timer_expires = jiffies; + } sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p %u %u %u %u", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -1919,11 +1920,11 @@ tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, timer_active, timer_expires-jiffies, tp->retransmits, - sp->socket ? sp->socket->inode->i_uid : 0, + sock_i_uid(sp), tp->probes_out, - sp->socket ? sp->socket->inode->i_ino : 0, + sock_i_ino(sp), atomic_read(&sp->refcnt), sp, - tp->rto, tp->ack.ato, tp->ack.quick, tp->ack.pingpong + tp->rto, tp->ack.ato, tp->ack.quick, tp->ack.pingpong, sp->sndbuf ); } @@ -1984,6 +1985,7 @@ for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) { struct open_request *req; + int uid; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); if (sk->family != PF_INET6) @@ -1998,6 +2000,7 @@ } } + uid = sock_i_uid(sk); read_lock_bh(&tp->syn_wait_lock); lopt = tp->listen_opt; if (lopt && lopt->qlen != 0) { @@ -2008,7 +2011,7 @@ pos += LINE_LEN+1; if (pos < offset) continue; - get_openreq6(sk, req, tmpbuf, num); + get_openreq6(sk, req, tmpbuf, num, uid); len += sprintf(buffer+len, LINE_FMT, tmpbuf); if(len >= length) { read_unlock_bh(&tp->syn_wait_lock); diff -u --recursive --new-file v2.4.0-test6/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.4.0-test6/linux/net/ipv6/udp.c Mon Jul 10 16:47:28 2000 +++ linux/net/ipv6/udp.c Thu Aug 10 13:01:26 2000 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.55 2000/07/08 00:20:43 davem Exp $ + * $Id: udp.c,v 1.56 2000/08/09 11:59:04 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -109,7 +109,10 @@ (!sk2->rcv_saddr || addr_type == IPV6_ADDR_ANY || !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, - &sk2->net_pinfo.af_inet6.rcv_saddr)) && + &sk2->net_pinfo.af_inet6.rcv_saddr) || + (addr_type == IPV6_ADDR_MAPPED && + sk2->family == AF_INET && + sk->rcv_saddr == sk2->rcv_saddr)) && (!sk2->reuse || !sk->reuse)) goto fail; } @@ -270,7 +273,6 @@ ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000ffff), sk->saddr); - } if(ipv6_addr_any(&np->rcv_saddr)) { @@ -343,7 +345,7 @@ if(ipv6_addr_any(&np->rcv_saddr)) { ipv6_addr_copy(&np->rcv_saddr, &saddr); - sk->rcv_saddr = 0xffffffff; + sk->rcv_saddr = LOOPBACK4_IPV6; } sk->state = TCP_ESTABLISHED; } @@ -923,8 +925,8 @@ sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), sock_timer_active, timer_expires-jiffies, 0, - sp->socket->inode->i_uid, 0, - sp->socket ? sp->socket->inode->i_ino : 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), atomic_read(&sp->refcnt), sp); } diff -u --recursive --new-file v2.4.0-test6/linux/net/irda/Config.in linux/net/irda/Config.in --- v2.4.0-test6/linux/net/irda/Config.in Wed Dec 29 13:13:21 1999 +++ linux/net/irda/Config.in Sun Aug 13 10:21:20 2000 @@ -23,7 +23,6 @@ fi if [ "$CONFIG_IRDA" != "n" ]; then - source net/irda/compressors/Config.in source drivers/net/irda/Config.in fi endmenu diff -u --recursive --new-file v2.4.0-test6/linux/net/netsyms.c linux/net/netsyms.c --- v2.4.0-test6/linux/net/netsyms.c Wed Aug 9 19:19:52 2000 +++ linux/net/netsyms.c Fri Aug 18 10:26:25 2000 @@ -130,7 +130,6 @@ EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); EXPORT_SYMBOL(sock_rmalloc); -EXPORT_SYMBOL(sock_rspace); EXPORT_SYMBOL(skb_recv_datagram); EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_copy_datagram); @@ -315,7 +314,6 @@ EXPORT_SYMBOL(tcp_send_synack); EXPORT_SYMBOL(tcp_check_req); EXPORT_SYMBOL(tcp_child_process); -EXPORT_SYMBOL(tcp_reset_xmit_timer); EXPORT_SYMBOL(tcp_parse_options); EXPORT_SYMBOL(tcp_rcv_established); EXPORT_SYMBOL(tcp_init_xmit_timers); @@ -355,6 +353,13 @@ EXPORT_SYMBOL(udp_port_rover); EXPORT_SYMBOL(tcp_sync_mss); EXPORT_SYMBOL(net_statistics); +EXPORT_SYMBOL(__tcp_mem_reclaim); +EXPORT_SYMBOL(tcp_sockets_allocated); +EXPORT_SYMBOL(sysctl_tcp_reordering); +EXPORT_SYMBOL(sysctl_tcp_rmem); +EXPORT_SYMBOL(sysctl_tcp_wmem); +EXPORT_SYMBOL(sysctl_tcp_ecn); +EXPORT_SYMBOL(tcp_cwnd_application_limited); EXPORT_SYMBOL(xrlim_allow); @@ -567,51 +572,6 @@ EXPORT_SYMBOL(nf_hooks); EXPORT_SYMBOL(nf_setsockopt); EXPORT_SYMBOL(nf_getsockopt); -#endif - -#ifdef CONFIG_IP_NF_CONNTRACK -#include -#include -#include -EXPORT_SYMBOL(ip_conntrack_protocol_register); -EXPORT_SYMBOL(invert_tuplepr); -EXPORT_SYMBOL(ip_conntrack_alter_reply); -EXPORT_SYMBOL(ip_conntrack_destroyed); -EXPORT_SYMBOL(ip_conntrack_get); -EXPORT_SYMBOL(ip_conntrack_module); -EXPORT_SYMBOL(ip_conntrack_helper_register); -EXPORT_SYMBOL(ip_conntrack_helper_unregister); -EXPORT_SYMBOL(ip_ct_selective_cleanup); -EXPORT_SYMBOL(ip_ct_refresh); -EXPORT_SYMBOL(ip_conntrack_expect_related); -EXPORT_SYMBOL(ip_conntrack_tuple_taken); -EXPORT_SYMBOL(ip_ct_gather_frags); -#ifdef CONFIG_IP_NF_FTP -#include -EXPORT_SYMBOL(ip_ftp_lock); -#endif -#endif /*CONFIG_IP_NF_CONNTRACK*/ - -#ifdef CONFIG_IP_NF_NAT -#include -#include -#include -EXPORT_SYMBOL(ip_nat_setup_info); -EXPORT_SYMBOL(ip_nat_helper_register); -EXPORT_SYMBOL(ip_nat_helper_unregister); -EXPORT_SYMBOL(ip_nat_expect_register); -EXPORT_SYMBOL(ip_nat_expect_unregister); -EXPORT_SYMBOL(ip_nat_cheat_check); -#endif - -#ifdef CONFIG_IP_NF_IPTABLES -#include -EXPORT_SYMBOL(ipt_register_table); -EXPORT_SYMBOL(ipt_unregister_table); -EXPORT_SYMBOL(ipt_register_target); -EXPORT_SYMBOL(ipt_unregister_target); -EXPORT_SYMBOL(ipt_register_match); -EXPORT_SYMBOL(ipt_unregister_match); #endif EXPORT_SYMBOL(register_gifconf); diff -u --recursive --new-file v2.4.0-test6/linux/net/packet/af_packet.c linux/net/packet/af_packet.c --- v2.4.0-test6/linux/net/packet/af_packet.c Wed Aug 9 19:19:52 2000 +++ linux/net/packet/af_packet.c Thu Aug 10 13:01:26 2000 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.39 2000/08/09 08:04:45 davem Exp $ + * Version: $Id: af_packet.c,v 1.41 2000/08/10 01:21:14 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -75,11 +75,6 @@ extern int dlci_ioctl(unsigned int, void*); #endif -/* - Old SOCK_PACKET. Do exist programs, which use it? - (not counting tcpdump) - lots of them yes - AC. - - */ #define CONFIG_SOCK_PACKET 1 /* @@ -89,22 +84,10 @@ It is more expensive, but I believe, it is really correct solution: reentereble, safe and fault tolerant. - Differences: - - Changing IFF_ALLMULTI from user level is disabled. - It could only confused multicast routing daemons, not more. - - IFF_PROMISC is faked by keeping reference count and - global flag, so that real IFF_PROMISC == (gflag|(count != 0)) - I'd remove it too, but it would require recompilation tcpdump - and another applications, using promiscuous mode. - - SIOC{ADD/DEL}MULTI are moved to deprecated state, - they work, but complain. I do know who uses them. - - -*************FIXME*************** - Alexey : This doesnt cook Im afraid. We need the low level SIOCADD/DELMULTI - and also IFF_ALLMULTI for DECNET, Appletalk and other stuff as well as - BSD compatibility issues. - + IFF_PROMISC/IFF_ALLMULTI/SIOC{ADD/DEL}MULTI are faked by keeping + reference count and global flag, so that real status is + (gflag|(count != 0)), so that we can use obsolete faulty interface + not harming clever users. */ #define CONFIG_PACKET_MULTICAST 1 @@ -206,6 +189,7 @@ unsigned int frame_size; unsigned int iovmax; unsigned int head; + int copy_thresh; #endif }; @@ -537,7 +521,9 @@ struct tpacket_hdr *h; u8 * skb_head = skb->data; unsigned snaplen; - unsigned long losing; + unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER; + unsigned short macoff, netoff; + struct sk_buff *copy_skb = NULL; if (skb->pkt_type == PACKET_LOOPBACK) goto drop; @@ -572,38 +558,55 @@ snaplen = res; } #endif - spin_lock(&sk->receive_queue.lock); - h = po->iovec[po->head]; - - if (h->tp_status) - goto ring_is_full; - po->head = po->head != po->iovmax ? po->head+1 : 0; - po->stats.tp_packets++; - losing = TP_STATUS_LOSING; - if (!po->stats.tp_drops) - losing = 0; - spin_unlock(&sk->receive_queue.lock); if (sk->type == SOCK_DGRAM) { - h->tp_mac = h->tp_net = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; + macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; } else { unsigned maclen = skb->nh.raw - skb->data; - h->tp_net = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); - h->tp_mac = h->tp_net - maclen; + netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen)); + macoff = netoff - maclen; } - if (h->tp_mac + snaplen > po->frame_size) { - snaplen = po->frame_size - h->tp_mac; + if (macoff + snaplen > po->frame_size) { + if (po->copy_thresh && + atomic_read(&sk->rmem_alloc) + skb->truesize < (unsigned)sk->rcvbuf) { + if (skb_shared(skb)) { + copy_skb = skb_clone(skb, GFP_ATOMIC); + } else { + copy_skb = skb_get(skb); + skb_head = skb->data; + } + if (copy_skb) + skb_set_owner_r(copy_skb, sk); + } + snaplen = po->frame_size - macoff; if ((int)snaplen < 0) snaplen = 0; } - memcpy((u8*)h + h->tp_mac, skb->data, snaplen); + spin_lock(&sk->receive_queue.lock); + h = po->iovec[po->head]; + + if (h->tp_status) + goto ring_is_full; + po->head = po->head != po->iovmax ? po->head+1 : 0; + po->stats.tp_packets++; + if (copy_skb) { + status |= TP_STATUS_COPY; + __skb_queue_tail(&sk->receive_queue, copy_skb); + } + if (!po->stats.tp_drops) + status &= ~TP_STATUS_LOSING; + spin_unlock(&sk->receive_queue.lock); + + memcpy((u8*)h + macoff, skb->data, snaplen); - h->tp_sec = skb->stamp.tv_sec; - h->tp_usec = skb->stamp.tv_usec; h->tp_len = skb->len; h->tp_snaplen = snaplen; + h->tp_mac = macoff; + h->tp_net = netoff; + h->tp_sec = skb->stamp.tv_sec; + h->tp_usec = skb->stamp.tv_usec; sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); sll->sll_halen = 0; @@ -615,7 +618,7 @@ sll->sll_pkttype = skb->pkt_type; sll->sll_ifindex = dev->ifindex; - h->tp_status = losing|TP_STATUS_USER; + h->tp_status = status; mb(); sk->data_ready(sk, 0); @@ -634,6 +637,8 @@ spin_unlock(&sk->receive_queue.lock); sk->data_ready(sk, 0); + if (copy_skb) + kfree_skb(copy_skb); goto drop_n_restore; } @@ -1286,6 +1291,18 @@ return -EFAULT; return packet_set_ring(sk, &req, 0); } + case PACKET_COPY_THRESH: + { + int val; + + if (optlen!=sizeof(val)) + return -EINVAL; + if (copy_from_user(&val,optval,sizeof(val))) + return -EFAULT; + + sk->protinfo.af_packet->copy_thresh = val; + return 0; + } #endif default: return -ENOPROTOOPT; @@ -1814,8 +1831,8 @@ s->protinfo.af_packet->ifindex, s->protinfo.af_packet->running, atomic_read(&s->rmem_alloc), - s->socket->inode->i_uid, - s->socket->inode->i_ino + sock_i_uid(s), + sock_i_ino(s) ); buffer[len++]='\n'; diff -u --recursive --new-file v2.4.0-test6/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c --- v2.4.0-test6/linux/net/sched/cls_tcindex.c Tue Jan 11 22:31:47 2000 +++ linux/net/sched/cls_tcindex.c Fri Aug 18 10:26:25 2000 @@ -170,23 +170,17 @@ int i; struct tcindex_filter **walk = NULL; - for (i = 0; !f && i < p->hash; i++) { - for (walk = p->h+i; !f && *walk; walk = &(*walk)->next) { + for (i = 0; i < p->hash; i++) + for (walk = p->h+i; *walk; walk = &(*walk)->next) if (&(*walk)->result == r) - f = *walk; - } - } - if (!f) - return -ENOENT; -/* - @@@ OK? -- No (jhs) -Look more into it + goto found; + return -ENOENT; + +found: + f = *walk; tcf_tree_lock(tp); -*/ *walk = f->next; -/* tcf_tree_unlock(tp); -*/ } cl = __cls_set_class(&r->res.class,0); if (cl) diff -u --recursive --new-file v2.4.0-test6/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c --- v2.4.0-test6/linux/net/sched/sch_generic.c Thu May 11 15:30:08 2000 +++ linux/net/sched/sch_generic.c Fri Aug 18 10:26:25 2000 @@ -506,7 +506,7 @@ dev->qdisc = &noop_qdisc; dev->qdisc_sleeping = &noop_qdisc; qdisc_destroy(qdisc); -#ifdef CONFIG_NET_SCH_INGRESS +#if defined(CONFIG_NET_SCH_INGRESS) || defined(CONFIG_NET_SCH_INGRESS_MODULE) if ((qdisc = dev->qdisc_ingress) != NULL) { dev->qdisc_ingress = NULL; qdisc_destroy(qdisc); diff -u --recursive --new-file v2.4.0-test6/linux/net/sched/sch_gred.c linux/net/sched/sch_gred.c --- v2.4.0-test6/linux/net/sched/sch_gred.c Wed Apr 26 16:34:10 2000 +++ linux/net/sched/sch_gred.c Sat Aug 12 12:09:55 2000 @@ -67,7 +67,7 @@ u32 limit; /* HARD maximal queue length */ u32 qth_min; /* Min average length threshold: A scaled */ u32 qth_max; /* Max average length threshold: A scaled */ - u32 DP; /* the drop pramaters */ + u32 DP; /* the drop pramaters */ char Wlog; /* log(W) */ char Plog; /* random number bits */ u32 Scell_max; @@ -146,8 +146,8 @@ } - q->packetsin++; - q->bytesin+=skb->len; + q->packetsin++; + q->bytesin+=skb->len; if (t->eqp && t->grio) { qave=0; @@ -218,7 +218,7 @@ { struct gred_sched_data *q; struct gred_sched *t= (struct gred_sched *)sch->data; - q= t->tab[(skb->tc_index&0xf)]; + q= t->tab[(skb->tc_index&0xf)]; /* error checking here -- probably unnecessary */ PSCHED_SET_PASTPERFECT(q->qidlestart); @@ -308,6 +308,7 @@ while((skb=__skb_dequeue(&sch->q))!=NULL) kfree_skb(skb); + sch->stats.backlog = 0; for (i=0;iDPs;i++) { @@ -329,27 +330,27 @@ { struct gred_sched *table = (struct gred_sched *)sch->data; struct gred_sched_data *q; - struct tc_gred_qopt *ctl; - struct tc_gred_sopt *sopt; - struct rtattr *tb[TCA_GRED_STAB]; - struct rtattr *tb2[TCA_GRED_STAB]; + struct tc_gred_qopt *ctl; + struct tc_gred_sopt *sopt; + struct rtattr *tb[TCA_GRED_STAB]; + struct rtattr *tb2[TCA_GRED_STAB]; int i; - if (opt == NULL || - rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) - return -EINVAL; + if (opt == NULL || + rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) + return -EINVAL; if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 && tb[TCA_GRED_DPS-1] != 0) { rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt), RTA_PAYLOAD(opt)); - sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); - table->DPs=sopt->DPs; - table->def=sopt->def_DP; - table->grio=sopt->grio; + sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); + table->DPs=sopt->DPs; + table->def=sopt->def_DP; + table->grio=sopt->grio; table->initd=0; - /* probably need to clear all the table DP entries as well */ + /* probably need to clear all the table DP entries as well */ MOD_INC_USE_COUNT; return 0; } @@ -361,7 +362,7 @@ return -EINVAL; ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]); - if (ctl->DP > MAX_DPs-1 || ctl->DP <0) { + if (ctl->DP > MAX_DPs-1 ) { /* misbehaving is punished! Put in the default drop probability */ DPRINTK("\nGRED: DP %u not in the proper range fixed. New DP " "set to default at %d\n",ctl->DP,table->def); @@ -371,6 +372,8 @@ if (table->tab[ctl->DP] == NULL) { table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); + if (NULL == table->tab[ctl->DP]) + return -ENOMEM; memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data))); } q= table->tab[ctl->DP]; @@ -378,13 +381,13 @@ if (table->grio) { if (ctl->prio <=0) { if (table->def && table->tab[table->def]) { - DPRINTK("\nGRED: DP %u does not have a prio setting " - "default to %d\n",ctl->DP, + DPRINTK("\nGRED: DP %u does not have a prio" + "setting default to %d\n",ctl->DP, table->tab[table->def]->prio); q->prio=table->tab[table->def]->prio; } else { - DPRINTK("\nGRED: DP %u does not have a prio setting " - "default to 8\n",ctl->DP); + DPRINTK("\nGRED: DP %u does not have a prio" + " setting default to 8\n",ctl->DP); q->prio=8; } } else { @@ -392,7 +395,7 @@ } } else { q->prio=8; - } + } q->DP=ctl->DP; @@ -437,10 +440,13 @@ if (table->tab[table->def] == NULL) { table->tab[table->def]= - kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); + kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); + if (NULL == table->tab[ctl->DP]) + return -ENOMEM; + memset(table->tab[table->def], 0, (sizeof(struct gred_sched_data))); - } + } q= table->tab[table->def]; q->DP=table->def; q->Wlog = ctl->Wlog; @@ -452,45 +458,44 @@ q->qth_min = ctl->qth_min<Wlog; q->qth_max = ctl->qth_max<Wlog; - if (table->grio) + if (table->grio) q->prio=table->tab[ctl->DP]->prio; - else + else q->prio=8; q->qcount = -1; PSCHED_SET_PASTPERFECT(q->qidlestart); memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256); } - return 0; + return 0; } static int gred_init(struct Qdisc *sch, struct rtattr *opt) { struct gred_sched *table = (struct gred_sched *)sch->data; - struct tc_gred_sopt *sopt; - struct rtattr *tb[TCA_GRED_STAB]; - struct rtattr *tb2[TCA_GRED_STAB]; - - if (opt == NULL || - rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) - return -EINVAL; + struct tc_gred_sopt *sopt; + struct rtattr *tb[TCA_GRED_STAB]; + struct rtattr *tb2[TCA_GRED_STAB]; + + if (opt == NULL || + rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ) + return -EINVAL; if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 && tb[TCA_GRED_DPS-1] != 0) { - rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt), - RTA_PAYLOAD(opt)); + rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),RTA_PAYLOAD(opt)); - sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); - table->DPs=sopt->DPs; - table->def=sopt->def_DP; - table->grio=sopt->grio; + sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); + table->DPs=sopt->DPs; + table->def=sopt->def_DP; + table->grio=sopt->grio; table->initd=0; MOD_INC_USE_COUNT; return 0; } - DPRINTK("\n GRED_INIT error!\n"); + DPRINTK("\n GRED_INIT error!\n"); return -EINVAL; } diff -u --recursive --new-file v2.4.0-test6/linux/net/sched/sch_ingress.c linux/net/sched/sch_ingress.c --- v2.4.0-test6/linux/net/sched/sch_ingress.c Sun Mar 19 18:35:31 2000 +++ linux/net/sched/sch_ingress.c Fri Aug 18 10:26:25 2000 @@ -157,9 +157,7 @@ #endif }; -#ifdef CONFIG_NET_CLS_TCINDEX - skb->tc_index = TC_H_MIN(res.classid); -#endif + skb->tc_index = TC_H_MIN(res.classid); return result; } diff -u --recursive --new-file v2.4.0-test6/linux/net/sched/sch_red.c linux/net/sched/sch_red.c --- v2.4.0-test6/linux/net/sched/sch_red.c Mon Jul 10 16:47:28 2000 +++ linux/net/sched/sch_red.c Fri Aug 18 10:26:25 2000 @@ -160,7 +160,7 @@ static int red_ecn_mark(struct sk_buff *skb) { - if (skb->nh.raw + 20 < skb->tail) + if (skb->nh.raw + 20 > skb->tail) return 0; switch (skb->protocol) { diff -u --recursive --new-file v2.4.0-test6/linux/net/socket.c linux/net/socket.c --- v2.4.0-test6/linux/net/socket.c Wed Aug 9 19:19:52 2000 +++ linux/net/socket.c Mon Aug 14 08:30:12 2000 @@ -443,6 +443,7 @@ if (!inode) return NULL; + inode->i_sb = sock_mnt->mnt_sb; sock = socki_lookup(inode); inode->i_mode = S_IFSOCK|S_IRWXUGO; @@ -1711,6 +1712,9 @@ proto_init(); + register_filesystem(&sock_fs_type); + sock_mnt = kern_mount(&sock_fs_type); + /* * The netlink device handler may be needed early. */ @@ -1724,8 +1728,6 @@ #ifdef CONFIG_NETFILTER netfilter_init(); #endif - register_filesystem(&sock_fs_type); - sock_mnt = kern_mount(&sock_fs_type); } int socket_get_info(char *buffer, char **start, off_t offset, int length) diff -u --recursive --new-file v2.4.0-test6/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.4.0-test6/linux/net/sunrpc/sched.c Wed Aug 9 19:19:52 2000 +++ linux/net/sunrpc/sched.c Wed Aug 23 09:50:19 2000 @@ -369,8 +369,15 @@ spin_unlock_bh(&rpc_queue_lock); } -/* - * Wake up a single task -- must be invoked with spin lock held. +/** + * __rpc_wake_up_task - wake up a single rpc_task + * @task: task to be woken up + * + * If the task is locked, it is merely removed from the queue, and + * 'task->tk_wakeup' is set. rpc_unlock_task() will then ensure + * that it is woken up as soon as the lock count goes to zero. + * + * Caller must hold rpc_queue_lock */ static void __rpc_wake_up_task(struct rpc_task *task) @@ -395,6 +402,8 @@ return; __rpc_disable_timer(task); + if (task->tk_rpcwait != &schedq) + __rpc_remove_wait_queue(task); /* If the task has been locked, then set tk_wakeup so that * rpc_unlock_task() wakes us up... */ @@ -404,8 +413,6 @@ } else task->tk_wakeup = 0; - if (task->tk_rpcwait != &schedq) - __rpc_remove_wait_queue(task); rpc_make_runnable(task); dprintk("RPC: __rpc_wake_up_task done\n"); @@ -452,8 +459,11 @@ return task; } -/* - * Wake up all tasks on a queue +/** + * rpc_wake_up - wake up all rpc_tasks + * @queue: rpc_wait_queue on which the tasks are sleeping + * + * Grabs rpc_queue_lock */ void rpc_wake_up(struct rpc_wait_queue *queue) @@ -464,8 +474,12 @@ spin_unlock_bh(&rpc_queue_lock); } -/* - * Wake up all tasks on a queue, and set their status value. +/** + * rpc_wake_up_status - wake up all rpc_tasks and set their status value. + * @queue: rpc_wait_queue on which the tasks are sleeping + * @status: status value to set + * + * Grabs rpc_queue_lock */ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) @@ -931,20 +945,27 @@ task->tk_release(task); } -/* - * Handling of RPC child tasks - * We can't simply call wake_up(parent) here, because the - * parent task may already have gone away +/** + * rpc_find_parent - find the parent of a child task. + * @child: child task + * + * Checks that the parent task is still sleeping on the + * queue 'childq'. If so returns a pointer to the parent. + * Upon failure returns NULL. + * + * Caller must hold rpc_queue_lock */ static inline struct rpc_task * rpc_find_parent(struct rpc_task *child) { - struct rpc_task *temp, *parent; + struct rpc_task *task, *parent; parent = (struct rpc_task *) child->tk_calldata; - for (temp = childq.task; temp; temp = temp->tk_next) { - if (temp == parent) - return parent; + if ((task = childq.task) != NULL) { + do { + if (task == parent) + return parent; + } while ((task = task->tk_next) != childq.task); } return NULL; } diff -u --recursive --new-file v2.4.0-test6/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.4.0-test6/linux/net/unix/af_unix.c Wed Aug 9 19:19:52 2000 +++ linux/net/unix/af_unix.c Fri Aug 18 10:26:25 2000 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.102 2000/07/26 01:04:21 davem Exp $ + * Version: $Id: af_unix.c,v 1.105 2000/08/16 10:58:22 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. @@ -306,6 +306,27 @@ read_unlock(&sk->callback_lock); } +/* When dgram socket disconnects (or changes its peer), we clear its receive + * queue of packets arrived from previous peer. First, it allows to do + * flow control based only on wmem_alloc; second, sk connected to peer + * may receive messages only from that peer. */ +static void unix_dgram_disconnected(struct sock *sk, struct sock *other) +{ + if (skb_queue_len(&sk->receive_queue)) { + skb_queue_purge(&sk->receive_queue); + wake_up_interruptible_all(&sk->protinfo.af_unix.peer_wait); + + /* If one link of bidirectional dgram pipe is disconnected, + * we signal error. Messages are lost. Do not make this, + * when peer was not connected to us. + */ + if (!other->dead && unix_peer(other) == sk) { + other->err = ECONNRESET; + other->error_report(other); + } + } +} + static void unix_sock_destructor(struct sock *sk) { skb_queue_purge(&sk->receive_queue); @@ -572,7 +593,8 @@ int err = 0; if (sunname->sun_path[0]) { - if (path_init(sunname->sun_path, LOOKUP_POSITIVE, &nd)) + if (path_init(sunname->sun_path, + LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd)) err = path_walk(sunname->sun_path, &nd); if (err) goto fail; @@ -788,6 +810,8 @@ unix_peer(sk)=other; unix_state_wunlock(sk); + if (other != old_peer) + unix_dgram_disconnected(sk, old_peer); sock_put(old_peer); } else { unix_peer(sk)=other; @@ -1203,6 +1227,7 @@ unix_peer(sk)=NULL; unix_state_wunlock(sk); + unix_dgram_disconnected(sk, other); sock_put(other); err = -ECONNREFUSED; } else { @@ -1219,7 +1244,8 @@ if (other->shutdown&RCV_SHUTDOWN) goto out_unlock; - if (skb_queue_len(&other->receive_queue) > other->max_ack_backlog) { + if (unix_peer(other) != sk && + skb_queue_len(&other->receive_queue) > other->max_ack_backlog) { if (!timeo) { err = -EAGAIN; goto out_unlock; @@ -1640,7 +1666,6 @@ return 0; } - static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; @@ -1736,7 +1761,7 @@ s->socket ? (s->state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : (s->state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), - s->socket ? s->socket->inode->i_ino : 0); + sock_i_ino(s)); if (s->protinfo.af_unix.addr) { diff -u --recursive --new-file v2.4.0-test6/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.4.0-test6/linux/scripts/Menuconfig Thu Jul 27 17:38:02 2000 +++ linux/scripts/Menuconfig Mon Aug 21 08:57:36 2000 @@ -834,7 +834,7 @@ cat <. You may also -send a problem report to . +send a problem report to . Please indicate the kernel version you are trying to configure and which menu you were trying to enter when this error occurred. @@ -897,7 +897,7 @@ If you have verified that your ncurses install is correct, you may email the maintainer or post a message to - for additional assistance. + for additional assistance. EOM cleanup